Syncing with feature/tensor-algebra
This commit is contained in:
commit
120189fd89
@ -15,6 +15,8 @@ jobs:
|
|||||||
- name: Install build-essential
|
- name: Install build-essential
|
||||||
run: |
|
run: |
|
||||||
sudo apt install -y build-essential
|
sudo apt install -y build-essential
|
||||||
|
- name: Grant execute permission for gradlew
|
||||||
|
run: chmod +x gradlew
|
||||||
- name: Install Chrome
|
- name: Install Chrome
|
||||||
run: |
|
run: |
|
||||||
sudo apt install -y libappindicator1 fonts-liberation
|
sudo apt install -y libappindicator1 fonts-liberation
|
||||||
@ -50,6 +52,8 @@ jobs:
|
|||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
|
- name: Grant execute permission for gradlew
|
||||||
|
run: chmod +x gradlew
|
||||||
- name: Cache gradle
|
- name: Cache gradle
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
@ -80,6 +84,8 @@ jobs:
|
|||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
|
- name: Grant execute permission for gradlew
|
||||||
|
run: chmod +x gradlew
|
||||||
- name: Add msys to path
|
- name: Add msys to path
|
||||||
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
|
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
|
||||||
- name: Cache gradle
|
- name: Cache gradle
|
117
.github/workflows/release.yml
vendored
Normal file
117
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
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 }}
|
||||||
|
|
30
CHANGELOG.md
30
CHANGELOG.md
@ -2,6 +2,19 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
## [0.2.0]
|
||||||
|
### Added
|
||||||
- `fun` annotation for SAM interfaces in library
|
- `fun` annotation for SAM interfaces in library
|
||||||
- Explicit `public` visibility for all public APIs
|
- Explicit `public` visibility for all public APIs
|
||||||
- Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140)
|
- Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140)
|
||||||
@ -18,13 +31,14 @@
|
|||||||
- Some minor utilities to `kmath-for-real`
|
- Some minor utilities to `kmath-for-real`
|
||||||
- Generic operation result parameter to `MatrixContext`
|
- Generic operation result parameter to `MatrixContext`
|
||||||
- New `MatrixFeature` interfaces for matrix decompositions
|
- New `MatrixFeature` interfaces for matrix decompositions
|
||||||
|
- Basic Quaternion vector support in `kmath-complex`.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Package changed from `scientifik` to `kscience.kmath`
|
- Package changed from `scientifik` to `space.kscience`
|
||||||
- Gradle version: 6.6 -> 6.8
|
- Gradle version: 6.6 -> 6.8.2
|
||||||
- Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`)
|
- Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`)
|
||||||
- `Polynomial` secondary constructor made function
|
- `Polynomial` secondary constructor made function
|
||||||
- Kotlin version: 1.3.72 -> 1.4.21
|
- Kotlin version: 1.3.72 -> 1.4.30
|
||||||
- `kmath-ast` doesn't depend on heavy `kotlin-reflect` library
|
- `kmath-ast` doesn't depend on heavy `kotlin-reflect` library
|
||||||
- Full autodiff refactoring based on `Symbol`
|
- Full autodiff refactoring based on `Symbol`
|
||||||
- `kmath-prob` renamed to `kmath-stat`
|
- `kmath-prob` renamed to `kmath-stat`
|
||||||
@ -32,9 +46,16 @@
|
|||||||
- Use `Point<Double>` instead of specialized type in `kmath-for-real`
|
- Use `Point<Double>` instead of specialized type in `kmath-for-real`
|
||||||
- Optimized dot product for buffer matrices moved to `kmath-for-real`
|
- Optimized dot product for buffer matrices moved to `kmath-for-real`
|
||||||
- EjmlMatrix context is an object
|
- EjmlMatrix context is an object
|
||||||
- Matrix LUP `inverse` renamed to `inverseWithLUP`
|
- Matrix LUP `inverse` renamed to `inverseWithLup`
|
||||||
- `NumericAlgebra` moved outside of regular algebra chain (`Ring` no longer implements it).
|
- `NumericAlgebra` moved outside of regular algebra chain (`Ring` no longer implements it).
|
||||||
- Features moved to NDStructure and became transparent.
|
- Features moved to NDStructure and became transparent.
|
||||||
|
- Capitalization of LUP in many names changed to Lup.
|
||||||
|
- Refactored `NDStructure` algebra to be more simple, preferring under-the-hood conversion to explicit NDStructure types
|
||||||
|
- Refactor histograms. They are marked as prototype
|
||||||
|
- `Complex` and related features moved to a separate module `kmath-complex`
|
||||||
|
- Refactor AlgebraElement
|
||||||
|
- `symbol` method in `Algebra` renamed to `bindSymbol` to avoid ambiguity
|
||||||
|
- Add `out` projection to `Buffer` generic
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
@ -43,6 +64,7 @@
|
|||||||
- Support of `legacy` JS backend (we will support only IR)
|
- Support of `legacy` JS backend (we will support only IR)
|
||||||
- `toGrid` method.
|
- `toGrid` method.
|
||||||
- Public visibility of `BufferAccessor2D`
|
- Public visibility of `BufferAccessor2D`
|
||||||
|
- `Real` class
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
||||||
|
120
README.md
120
README.md
@ -9,7 +9,7 @@ Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmat
|
|||||||
|
|
||||||
# KMath
|
# KMath
|
||||||
|
|
||||||
Could be pronounced as `key-math`. The Kotlin MATHematics library was initially intended as a Kotlin-based analog to
|
Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to
|
||||||
Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture
|
Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture
|
||||||
designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could
|
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.
|
be achieved with [kmath-for-real](/kmath-for-real) extension module.
|
||||||
@ -32,49 +32,46 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module.
|
|||||||
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
|
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
|
||||||
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
|
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
|
||||||
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
|
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
|
||||||
for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better
|
for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better
|
||||||
experience for those, who want to work with specific types.
|
experience for those, who want to work with specific types.
|
||||||
|
|
||||||
## Features
|
## Features and stability
|
||||||
|
|
||||||
Current feature list is [here](/docs/features.md)
|
KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels:
|
||||||
|
|
||||||
* **Algebra**
|
* **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.
|
||||||
* Algebraic structures like rings, spaces and fields (**TODO** add example to wiki)
|
* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations.
|
||||||
* Basic linear algebra operations (sums, products, etc.), backed by the `Space` API.
|
* **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.
|
||||||
* Complex numbers backed by the `Field` API (meaning they will be usable in any structure like vectors and
|
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
|
||||||
N-dimensional arrays).
|
|
||||||
* Advanced linear algebra operations like matrix inversion and LU decomposition.
|
|
||||||
|
|
||||||
* **Array-like structures** Full support of many-dimensional array-like structures
|
<!--Current feature list is [here](/docs/features.md)-->
|
||||||
including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).
|
|
||||||
|
|
||||||
* **Expressions** By writing a single mathematical expression once, users will be able to apply different types of
|
|
||||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
|
||||||
performance calculations to code generation.
|
|
||||||
|
|
||||||
* **Histograms** Fast multi-dimensional histograms.
|
<!--* **Array-like structures** Full support of many-dimensional array-like structures -->
|
||||||
|
<!--including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).-->
|
||||||
|
|
||||||
* **Streaming** Streaming operations on mathematical objects and objects buffers.
|
<!--* **Histograms** Fast multi-dimensional histograms.-->
|
||||||
|
|
||||||
* **Type-safe dimensions** Type-safe dimensions for matrix operations.
|
<!--* **Streaming** Streaming operations on mathematical objects and objects buffers.-->
|
||||||
|
|
||||||
* **Commons-math wrapper** It is planned to gradually wrap most parts of
|
<!--* **Type-safe dimensions** Type-safe dimensions for matrix operations.-->
|
||||||
[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some
|
|
||||||
parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to
|
|
||||||
submit a feature request if you want something to be implemented first.
|
|
||||||
|
|
||||||
## Planned features
|
|
||||||
|
|
||||||
* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.
|
<!--* **Commons-math wrapper** It is planned to gradually wrap most parts of -->
|
||||||
|
<!--[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some -->
|
||||||
|
<!--parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to -->
|
||||||
|
<!--submit a feature request if you want something to be implemented first.-->
|
||||||
|
<!-- -->
|
||||||
|
<!--## Planned features-->
|
||||||
|
|
||||||
* **Array statistics**
|
<!--* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.-->
|
||||||
|
|
||||||
* **Integration** Univariate and multivariate integration framework.
|
<!--* **Array statistics** -->
|
||||||
|
|
||||||
* **Probability and distributions**
|
<!--* **Integration** Univariate and multivariate integration framework.-->
|
||||||
|
|
||||||
* **Fitting** Non-linear curve fitting facilities
|
<!--* **Probability and distributions**-->
|
||||||
|
|
||||||
|
<!--* **Fitting** Non-linear curve fitting facilities-->
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
@ -107,16 +104,30 @@ submit a feature request if you want something to be implemented first.
|
|||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
|
* ### [kmath-complex](kmath-complex)
|
||||||
|
> Complex numbers and quaternions.
|
||||||
|
>
|
||||||
|
> **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
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-core](kmath-core)
|
* ### [kmath-core](kmath-core)
|
||||||
> Core classes, algebra definitions, basic linear algebra
|
> Core classes, algebra definitions, basic linear algebra
|
||||||
>
|
>
|
||||||
> **Maturity**: DEVELOPMENT
|
> **Maturity**: DEVELOPMENT
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures: contexts and elements
|
> - [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
|
> - [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
|
> - [buffers](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||||
> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : Functional Expressions
|
> - [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
|
||||||
|
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
|
> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
||||||
> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||||
|
|
||||||
@ -137,7 +148,7 @@ submit a feature request if you want something to be implemented first.
|
|||||||
* ### [kmath-ejml](kmath-ejml)
|
* ### [kmath-ejml](kmath-ejml)
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: PROTOTYPE
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-for-real](kmath-for-real)
|
* ### [kmath-for-real](kmath-for-real)
|
||||||
@ -155,33 +166,40 @@ One can still use generic algebras though.
|
|||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-functions](kmath-functions)
|
* ### [kmath-functions](kmath-functions)
|
||||||
>
|
> Functions and interpolation
|
||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: PROTOTYPE
|
||||||
|
>
|
||||||
|
> **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
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-geometry](kmath-geometry)
|
* ### [kmath-geometry](kmath-geometry)
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: PROTOTYPE
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-histograms](kmath-histograms)
|
* ### [kmath-histograms](kmath-histograms)
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: PROTOTYPE
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-kotlingrad](kmath-kotlingrad)
|
* ### [kmath-kotlingrad](kmath-kotlingrad)
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: PROTOTYPE
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-memory](kmath-memory)
|
* ### [kmath-memory](kmath-memory)
|
||||||
>
|
> An API and basic implementation for arranging objects in a continous memory block.
|
||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: DEVELOPMENT
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-nd4j](kmath-nd4j)
|
* ### [kmath-nd4j](kmath-nd4j)
|
||||||
@ -205,7 +223,7 @@ One can still use generic algebras though.
|
|||||||
* ### [kmath-viktor](kmath-viktor)
|
* ### [kmath-viktor](kmath-viktor)
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: DEVELOPMENT
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
|
|
||||||
@ -229,32 +247,22 @@ better than SciPy.
|
|||||||
|
|
||||||
### Repositories
|
### Repositories
|
||||||
|
|
||||||
Release artifacts are accessible from bintray with following configuration (see documentation of
|
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
|
||||||
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details):
|
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
repositories {
|
repositories {
|
||||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
maven("https://repo.kotlin.link")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api("kscience.kmath:kmath-core:0.2.0-dev-4")
|
api("kscience.kmath:kmath-core:() -> kotlin.Any")
|
||||||
// api("kscience.kmath:kmath-core-jvm:0.2.0-dev-4") for jvm-specific version
|
// api("kscience.kmath:kmath-core-jvm:() -> kotlin.Any") for jvm-specific version
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Gradle `6.0+` is required for multiplatform artifacts.
|
Gradle `6.0+` is required for multiplatform artifacts.
|
||||||
|
|
||||||
#### Development
|
|
||||||
|
|
||||||
Development builds are uploaded to the separate repository:
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
repositories {
|
|
||||||
maven("https://dl.bintray.com/mipt-npm/dev")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
The project requires a lot of additional work. The most important thing we need is a feedback about what features are
|
The project requires a lot of additional work. The most important thing we need is a feedback about what features are
|
||||||
|
@ -1,13 +1,7 @@
|
|||||||
import ru.mipt.npm.gradle.KSciencePublishPlugin
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.project")
|
id("ru.mipt.npm.gradle.project")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val kmathVersion: String by extra("0.2.0-dev-5")
|
|
||||||
internal val bintrayRepo: String by extra("kscience")
|
|
||||||
internal val githubProject: String by extra("kmath")
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
@ -23,22 +17,24 @@ allprojects {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "kscience.kmath"
|
group = "space.kscience"
|
||||||
version = kmathVersion
|
version = "0.2.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
if (name.startsWith("kmath")) apply<KSciencePublishPlugin>()
|
if (name.startsWith("kmath")) apply<ru.mipt.npm.gradle.KSciencePublishingPlugin>()
|
||||||
}
|
}
|
||||||
|
|
||||||
readme {
|
readme {
|
||||||
readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
apiValidation {
|
|
||||||
validationDisabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
ksciencePublish {
|
ksciencePublish {
|
||||||
spaceRepo = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven"
|
spaceRepo = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven"
|
||||||
|
bintrayRepo = "kscience"
|
||||||
|
githubProject = "kmath"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiValidation{
|
||||||
|
nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI")
|
||||||
|
}
|
@ -5,7 +5,7 @@ operation, say `+`, one needs two objects of a type `T` and an algebra context,
|
|||||||
say `Space<T>`. Next one needs to run the actual operation in the context:
|
say `Space<T>`. Next one needs to run the actual operation in the context:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
import kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
|
|
||||||
val a: T = ...
|
val a: T = ...
|
||||||
val b: T = ...
|
val b: T = ...
|
||||||
@ -47,7 +47,7 @@ but it also holds reference to the `ComplexField` singleton, which allows perfor
|
|||||||
numbers without explicit involving the context like:
|
numbers without explicit involving the context like:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
import kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
|
|
||||||
// Using elements
|
// Using elements
|
||||||
val c1 = Complex(1.0, 1.0)
|
val c1 = Complex(1.0, 1.0)
|
||||||
@ -82,7 +82,7 @@ operations in all performance-critical places. The performance of element operat
|
|||||||
KMath submits both contexts and elements for builtin algebraic structures:
|
KMath submits both contexts and elements for builtin algebraic structures:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
import kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
|
|
||||||
val c1 = Complex(1.0, 2.0)
|
val c1 = Complex(1.0, 2.0)
|
||||||
val c2 = ComplexField.i
|
val c2 = ComplexField.i
|
||||||
@ -95,7 +95,7 @@ val c3 = ComplexField { c1 + c2 }
|
|||||||
Also, `ComplexField` features special operations to mix complex and real numbers, for example:
|
Also, `ComplexField` features special operations to mix complex and real numbers, for example:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
import kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
|
|
||||||
val c1 = Complex(1.0, 2.0)
|
val c1 = Complex(1.0, 2.0)
|
||||||
val c2 = ComplexField { c1 - 1.0 } // Returns: Complex(re=0.0, im=2.0)
|
val c2 = ComplexField { c1 - 1.0 } // Returns: Complex(re=0.0, im=2.0)
|
||||||
|
19
docs/templates/ARTIFACT-TEMPLATE.md
vendored
19
docs/templates/ARTIFACT-TEMPLATE.md
vendored
@ -10,11 +10,12 @@
|
|||||||
>
|
>
|
||||||
> ```gradle
|
> ```gradle
|
||||||
> repositories {
|
> repositories {
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
|
> maven { url 'https://repo.kotlin.link' }
|
||||||
> maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
|
||||||
> maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
> 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 {
|
> dependencies {
|
||||||
@ -25,10 +26,12 @@
|
|||||||
>
|
>
|
||||||
> ```kotlin
|
> ```kotlin
|
||||||
> repositories {
|
> repositories {
|
||||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
> maven("https://repo.kotlin.link")
|
||||||
> maven("https://dl.bintray.com/mipt-npm/kscience")
|
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> maven("https://dl.bintray.com/mipt-npm/dev")
|
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
> maven("https://dl.bintray.com/hotkeytlt/maven")
|
>// Uncomment if repo.kotlin.link is unavailable
|
||||||
|
>// maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||||
|
>// maven("https://dl.bintray.com/mipt-npm/dev")
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> dependencies {
|
> dependencies {
|
||||||
|
71
docs/templates/README-TEMPLATE.md
vendored
71
docs/templates/README-TEMPLATE.md
vendored
@ -9,7 +9,7 @@ Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmat
|
|||||||
|
|
||||||
# KMath
|
# KMath
|
||||||
|
|
||||||
Could be pronounced as `key-math`. The Kotlin MATHematics library was initially intended as a Kotlin-based analog to
|
Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to
|
||||||
Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture
|
Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture
|
||||||
designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could
|
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.
|
be achieved with [kmath-for-real](/kmath-for-real) extension module.
|
||||||
@ -32,49 +32,46 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module.
|
|||||||
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
|
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
|
||||||
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
|
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
|
||||||
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
|
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
|
||||||
for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better
|
for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better
|
||||||
experience for those, who want to work with specific types.
|
experience for those, who want to work with specific types.
|
||||||
|
|
||||||
## Features
|
## Features and stability
|
||||||
|
|
||||||
Current feature list is [here](/docs/features.md)
|
KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels:
|
||||||
|
|
||||||
* **Algebra**
|
* **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.
|
||||||
* Algebraic structures like rings, spaces and fields (**TODO** add example to wiki)
|
* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations.
|
||||||
* Basic linear algebra operations (sums, products, etc.), backed by the `Space` API.
|
* **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.
|
||||||
* Complex numbers backed by the `Field` API (meaning they will be usable in any structure like vectors and
|
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
|
||||||
N-dimensional arrays).
|
|
||||||
* Advanced linear algebra operations like matrix inversion and LU decomposition.
|
|
||||||
|
|
||||||
* **Array-like structures** Full support of many-dimensional array-like structures
|
<!--Current feature list is [here](/docs/features.md)-->
|
||||||
including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).
|
|
||||||
|
|
||||||
* **Expressions** By writing a single mathematical expression once, users will be able to apply different types of
|
|
||||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
|
||||||
performance calculations to code generation.
|
|
||||||
|
|
||||||
* **Histograms** Fast multi-dimensional histograms.
|
<!--* **Array-like structures** Full support of many-dimensional array-like structures -->
|
||||||
|
<!--including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).-->
|
||||||
|
|
||||||
* **Streaming** Streaming operations on mathematical objects and objects buffers.
|
<!--* **Histograms** Fast multi-dimensional histograms.-->
|
||||||
|
|
||||||
* **Type-safe dimensions** Type-safe dimensions for matrix operations.
|
<!--* **Streaming** Streaming operations on mathematical objects and objects buffers.-->
|
||||||
|
|
||||||
* **Commons-math wrapper** It is planned to gradually wrap most parts of
|
<!--* **Type-safe dimensions** Type-safe dimensions for matrix operations.-->
|
||||||
[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some
|
|
||||||
parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to
|
|
||||||
submit a feature request if you want something to be implemented first.
|
|
||||||
|
|
||||||
## Planned features
|
|
||||||
|
|
||||||
* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.
|
<!--* **Commons-math wrapper** It is planned to gradually wrap most parts of -->
|
||||||
|
<!--[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some -->
|
||||||
|
<!--parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to -->
|
||||||
|
<!--submit a feature request if you want something to be implemented first.-->
|
||||||
|
<!-- -->
|
||||||
|
<!--## Planned features-->
|
||||||
|
|
||||||
* **Array statistics**
|
<!--* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.-->
|
||||||
|
|
||||||
* **Integration** Univariate and multivariate integration framework.
|
<!--* **Array statistics** -->
|
||||||
|
|
||||||
* **Probability and distributions**
|
<!--* **Integration** Univariate and multivariate integration framework.-->
|
||||||
|
|
||||||
* **Fitting** Non-linear curve fitting facilities
|
<!--* **Probability and distributions**-->
|
||||||
|
|
||||||
|
<!--* **Fitting** Non-linear curve fitting facilities-->
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
@ -100,12 +97,12 @@ better than SciPy.
|
|||||||
|
|
||||||
### Repositories
|
### Repositories
|
||||||
|
|
||||||
Release artifacts are accessible from bintray with following configuration (see documentation of
|
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
|
||||||
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details):
|
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
repositories {
|
repositories {
|
||||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
maven("https://repo.kotlin.link")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -116,16 +113,6 @@ dependencies {
|
|||||||
|
|
||||||
Gradle `6.0+` is required for multiplatform artifacts.
|
Gradle `6.0+` is required for multiplatform artifacts.
|
||||||
|
|
||||||
#### Development
|
|
||||||
|
|
||||||
Development builds are uploaded to the separate repository:
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
repositories {
|
|
||||||
maven("https://dl.bintray.com/mipt-npm/dev")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
The project requires a lot of additional work. The most important thing we need is a feedback about what features are
|
The project requires a lot of additional work. The most important thing we need is a feedback about what features are
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
java
|
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
kotlin("plugin.allopen")
|
kotlin("plugin.allopen")
|
||||||
id("kotlinx.benchmark")
|
id("kotlinx.benchmark")
|
||||||
@ -12,6 +11,7 @@ sourceSets.register("benchmarks")
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
maven("https://repo.kotlin.link")
|
||||||
maven("https://clojars.org/repo")
|
maven("https://clojars.org/repo")
|
||||||
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
|
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
|
||||||
maven("https://dl.bintray.com/hotkeytlt/maven")
|
maven("https://dl.bintray.com/hotkeytlt/maven")
|
||||||
@ -30,6 +30,7 @@ dependencies {
|
|||||||
implementation(project(":kmath-core"))
|
implementation(project(":kmath-core"))
|
||||||
implementation(project(":kmath-coroutines"))
|
implementation(project(":kmath-coroutines"))
|
||||||
implementation(project(":kmath-commons"))
|
implementation(project(":kmath-commons"))
|
||||||
|
implementation(project(":kmath-complex"))
|
||||||
implementation(project(":kmath-stat"))
|
implementation(project(":kmath-stat"))
|
||||||
implementation(project(":kmath-viktor"))
|
implementation(project(":kmath-viktor"))
|
||||||
implementation(project(":kmath-dimensions"))
|
implementation(project(":kmath-dimensions"))
|
||||||
@ -68,11 +69,28 @@ benchmark {
|
|||||||
targets.register("benchmarks")
|
targets.register("benchmarks")
|
||||||
// This one matches sourceSet name above
|
// This one matches sourceSet name above
|
||||||
|
|
||||||
configurations.register("fast") {
|
configurations.register("buffer") {
|
||||||
warmups = 1 // number of warmup iterations
|
warmups = 1 // number of warmup iterations
|
||||||
iterations = 3 // number of iterations
|
iterations = 3 // number of iterations
|
||||||
iterationTime = 500 // time in seconds per iteration
|
iterationTime = 500 // time in seconds per iteration
|
||||||
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
|
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,3 +104,7 @@ kotlin.sourceSets.all {
|
|||||||
tasks.withType<KotlinCompile> {
|
tasks.withType<KotlinCompile> {
|
||||||
kotlinOptions.jvmTarget = "11"
|
kotlinOptions.jvmTarget = "11"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readme{
|
||||||
|
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||||
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
package 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..size) res += array[size - i]
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun benchmarkBufferRead() {
|
|
||||||
var res = 0
|
|
||||||
for (i in 1..size) res += arrayBuffer[size - i]
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun nativeBufferRead() {
|
|
||||||
var res = 0
|
|
||||||
for (i in 1..size) res += nativeBuffer[size - i]
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val size: Int = 1000
|
|
||||||
val array: IntArray = IntArray(size) { it }
|
|
||||||
val arrayBuffer: IntBuffer = IntBuffer.wrap(array)
|
|
||||||
val nativeBuffer: IntBuffer = IntBuffer.allocate(size).also { for (i in 0 until size) it.put(i, i) }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
package kscience.kmath.benchmarks
|
|
||||||
|
|
||||||
import kscience.kmath.operations.RealField
|
|
||||||
import kscience.kmath.operations.invoke
|
|
||||||
import kscience.kmath.structures.*
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark
|
|
||||||
import org.openjdk.jmh.annotations.Scope
|
|
||||||
import org.openjdk.jmh.annotations.State
|
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
|
||||||
internal class NDFieldBenchmark {
|
|
||||||
@Benchmark
|
|
||||||
fun autoFieldAdd() {
|
|
||||||
bufferedField {
|
|
||||||
var res: NDBuffer<Double> = one
|
|
||||||
repeat(n) { res += one }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun autoElementAdd() {
|
|
||||||
var res = genericField.one
|
|
||||||
repeat(n) { res += 1.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun specializedFieldAdd() {
|
|
||||||
specializedField {
|
|
||||||
var res: NDBuffer<Double> = one
|
|
||||||
repeat(n) { res += 1.0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun boxingFieldAdd() {
|
|
||||||
genericField {
|
|
||||||
var res: NDBuffer<Double> = one
|
|
||||||
repeat(n) { res += one }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val dim: Int = 1000
|
|
||||||
const val n: Int = 100
|
|
||||||
val bufferedField: BufferedNDField<Double, RealField> = NDField.auto(RealField, dim, dim)
|
|
||||||
val specializedField: RealNDField = NDField.real(dim, dim)
|
|
||||||
val genericField: BoxingNDField<Double, RealField> = NDField.boxing(RealField, dim, dim)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
package kscience.kmath.benchmarks
|
|
||||||
|
|
||||||
import kscience.kmath.operations.RealField
|
|
||||||
import kscience.kmath.operations.invoke
|
|
||||||
import kscience.kmath.structures.BufferedNDField
|
|
||||||
import kscience.kmath.structures.NDField
|
|
||||||
import kscience.kmath.structures.RealNDField
|
|
||||||
import kscience.kmath.viktor.ViktorNDField
|
|
||||||
import org.jetbrains.bio.viktor.F64Array
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark
|
|
||||||
import org.openjdk.jmh.annotations.Scope
|
|
||||||
import org.openjdk.jmh.annotations.State
|
|
||||||
|
|
||||||
@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: BufferedNDField<Double, RealField> = NDField.auto(RealField, dim, dim)
|
|
||||||
final val realField: RealNDField = NDField.real(dim, dim)
|
|
||||||
final val viktorField: ViktorNDField = ViktorNDField(intArrayOf(dim, dim))
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun automaticFieldAddition() {
|
|
||||||
autoField {
|
|
||||||
var res = one
|
|
||||||
repeat(n) { res += one }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun viktorFieldAddition() {
|
|
||||||
viktorField {
|
|
||||||
var res = one
|
|
||||||
repeat(n) { res += one }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun rawViktor() {
|
|
||||||
val one = F64Array.full(init = 1.0, shape = intArrayOf(dim, dim))
|
|
||||||
var res = one
|
|
||||||
repeat(n) { res = res + one }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun realFieldLog() {
|
|
||||||
realField {
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,34 @@
|
|||||||
|
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) }
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,12 @@
|
|||||||
package kscience.kmath.benchmarks
|
package space.kscience.kmath.benchmarks
|
||||||
|
|
||||||
import kscience.kmath.operations.Complex
|
|
||||||
import kscience.kmath.operations.complex
|
|
||||||
import kscience.kmath.structures.MutableBuffer
|
|
||||||
import kscience.kmath.structures.RealBuffer
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark
|
import org.openjdk.jmh.annotations.Benchmark
|
||||||
import org.openjdk.jmh.annotations.Scope
|
import org.openjdk.jmh.annotations.Scope
|
||||||
import org.openjdk.jmh.annotations.State
|
import org.openjdk.jmh.annotations.State
|
||||||
|
import space.kscience.kmath.complex.Complex
|
||||||
|
import space.kscience.kmath.complex.complex
|
||||||
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
|
import space.kscience.kmath.structures.RealBuffer
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
internal class BufferBenchmark {
|
internal class BufferBenchmark {
|
||||||
@ -31,4 +31,4 @@ internal class BufferBenchmark {
|
|||||||
companion object {
|
companion object {
|
||||||
const val size: Int = 100
|
const val size: Int = 100
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,22 +1,20 @@
|
|||||||
package kscience.kmath.benchmarks
|
package space.kscience.kmath.benchmarks
|
||||||
|
|
||||||
import kotlinx.benchmark.Benchmark
|
import kotlinx.benchmark.Benchmark
|
||||||
import kscience.kmath.commons.linear.CMMatrixContext
|
|
||||||
import kscience.kmath.ejml.EjmlMatrixContext
|
|
||||||
|
|
||||||
import kscience.kmath.linear.BufferMatrixContext
|
|
||||||
import kscience.kmath.linear.RealMatrixContext
|
|
||||||
import kscience.kmath.linear.real
|
|
||||||
import kscience.kmath.operations.RealField
|
|
||||||
import kscience.kmath.operations.invoke
|
|
||||||
import kscience.kmath.structures.Buffer
|
|
||||||
import kscience.kmath.structures.Matrix
|
|
||||||
import org.openjdk.jmh.annotations.Scope
|
import org.openjdk.jmh.annotations.Scope
|
||||||
import org.openjdk.jmh.annotations.State
|
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
|
import kotlin.random.Random
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
class DotBenchmark {
|
internal class DotBenchmark {
|
||||||
companion object {
|
companion object {
|
||||||
val random = Random(12224)
|
val random = Random(12224)
|
||||||
val dim = 1000
|
val dim = 1000
|
||||||
@ -33,40 +31,37 @@ class DotBenchmark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun commonsMathMultiplication() {
|
fun cmDot() {
|
||||||
CMMatrixContext {
|
CMMatrixContext {
|
||||||
cmMatrix1 dot cmMatrix2
|
cmMatrix1 dot cmMatrix2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun ejmlMultiplication() {
|
fun ejmlDot() {
|
||||||
EjmlMatrixContext {
|
EjmlMatrixContext {
|
||||||
ejmlMatrix1 dot ejmlMatrix2
|
ejmlMatrix1 dot ejmlMatrix2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun ejmlMultiplicationwithConversion() {
|
fun ejmlDotWithConversion() {
|
||||||
EjmlMatrixContext {
|
EjmlMatrixContext {
|
||||||
val ejmlMatrix1 = matrix1.toEjml()
|
matrix1 dot matrix2
|
||||||
val ejmlMatrix2 = matrix2.toEjml()
|
|
||||||
|
|
||||||
ejmlMatrix1 dot ejmlMatrix2
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun bufferedMultiplication() {
|
fun bufferedDot() {
|
||||||
BufferMatrixContext(RealField, Buffer.Companion::real).invoke {
|
BufferMatrixContext(RealField, Buffer.Companion::real).invoke {
|
||||||
matrix1 dot matrix2
|
matrix1 dot matrix2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun realMultiplication() {
|
fun realDot() {
|
||||||
RealMatrixContext {
|
RealMatrixContext {
|
||||||
matrix1 dot matrix2
|
matrix1 dot matrix2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,25 +1,29 @@
|
|||||||
package kscience.kmath.ast
|
package space.kscience.kmath.benchmarks
|
||||||
|
|
||||||
import kscience.kmath.asm.compile
|
|
||||||
import kscience.kmath.expressions.Expression
|
|
||||||
import kscience.kmath.expressions.expressionInField
|
|
||||||
import kscience.kmath.expressions.invoke
|
|
||||||
import kscience.kmath.expressions.symbol
|
|
||||||
import kscience.kmath.operations.Field
|
|
||||||
import kscience.kmath.operations.RealField
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark
|
import org.openjdk.jmh.annotations.Benchmark
|
||||||
import org.openjdk.jmh.annotations.Scope
|
import org.openjdk.jmh.annotations.Scope
|
||||||
import org.openjdk.jmh.annotations.State
|
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
|
import kotlin.random.Random
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
internal class ExpressionsInterpretersBenchmark {
|
internal class ExpressionsInterpretersBenchmark {
|
||||||
private val algebra: Field<Double> = RealField
|
private val algebra: Field<Double> = RealField
|
||||||
|
val x by symbol
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun functionalExpression() {
|
fun functionalExpression() {
|
||||||
val expr = algebra.expressionInField {
|
val expr = algebra.expressionInField {
|
||||||
symbol("x") * const(2.0) + const(2.0) / symbol("x") - const(16.0)
|
val x = bindSymbol(x)
|
||||||
|
x * const(2.0) + const(2.0) / x - const(16.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeAndSum(expr)
|
invokeAndSum(expr)
|
||||||
@ -28,7 +32,8 @@ internal class ExpressionsInterpretersBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun mstExpression() {
|
fun mstExpression() {
|
||||||
val expr = algebra.mstInField {
|
val expr = algebra.mstInField {
|
||||||
symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0
|
val x = bindSymbol(x)
|
||||||
|
x * 2.0 + 2.0 / x - 16.0
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeAndSum(expr)
|
invokeAndSum(expr)
|
||||||
@ -37,7 +42,8 @@ internal class ExpressionsInterpretersBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun asmExpression() {
|
fun asmExpression() {
|
||||||
val expr = algebra.mstInField {
|
val expr = algebra.mstInField {
|
||||||
symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0
|
val x = bindSymbol(x)
|
||||||
|
x * 2.0 + 2.0 / x - 16.0
|
||||||
}.compile()
|
}.compile()
|
||||||
|
|
||||||
invokeAndSum(expr)
|
invokeAndSum(expr)
|
||||||
@ -45,8 +51,10 @@ internal class ExpressionsInterpretersBenchmark {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun rawExpression() {
|
fun rawExpression() {
|
||||||
val x by symbol
|
val expr = Expression<Double> { args ->
|
||||||
val expr = Expression<Double> { args -> args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 }
|
val x = args.getValue(x)
|
||||||
|
x * 2.0 + 2.0 / x - 16.0
|
||||||
|
}
|
||||||
invokeAndSum(expr)
|
invokeAndSum(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +63,7 @@ internal class ExpressionsInterpretersBenchmark {
|
|||||||
var sum = 0.0
|
var sum = 0.0
|
||||||
|
|
||||||
repeat(1000000) {
|
repeat(1000000) {
|
||||||
sum += expr("x" to random.nextDouble())
|
sum += expr(x to random.nextDouble())
|
||||||
}
|
}
|
||||||
|
|
||||||
println(sum)
|
println(sum)
|
@ -1,20 +1,21 @@
|
|||||||
package kscience.kmath.linear
|
package space.kscience.kmath.benchmarks
|
||||||
|
|
||||||
|
|
||||||
import kotlinx.benchmark.Benchmark
|
import kotlinx.benchmark.Benchmark
|
||||||
import kscience.kmath.commons.linear.CMMatrixContext
|
|
||||||
import kscience.kmath.commons.linear.CMMatrixContext.dot
|
|
||||||
import kscience.kmath.commons.linear.inverse
|
|
||||||
import kscience.kmath.ejml.EjmlMatrixContext
|
|
||||||
import kscience.kmath.ejml.inverse
|
|
||||||
import kscience.kmath.operations.invoke
|
|
||||||
import kscience.kmath.structures.Matrix
|
|
||||||
import org.openjdk.jmh.annotations.Scope
|
import org.openjdk.jmh.annotations.Scope
|
||||||
import org.openjdk.jmh.annotations.State
|
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
|
import kotlin.random.Random
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
class LinearAlgebraBenchmark {
|
internal class LinearAlgebraBenchmark {
|
||||||
companion object {
|
companion object {
|
||||||
val random = Random(1224)
|
val random = Random(1224)
|
||||||
val dim = 100
|
val dim = 100
|
||||||
@ -26,21 +27,21 @@ class LinearAlgebraBenchmark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun kmathLUPInversion() {
|
fun kmathLupInversion() {
|
||||||
MatrixContext.real.inverseWithLUP(matrix)
|
MatrixContext.real.inverseWithLup(matrix)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun cmLUPInversion() {
|
fun cmLUPInversion() {
|
||||||
CMMatrixContext {
|
with(CMMatrixContext) {
|
||||||
inverse(matrix)
|
inverse(matrix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun ejmlInverse() {
|
fun ejmlInverse() {
|
||||||
EjmlMatrixContext {
|
with(EjmlMatrixContext) {
|
||||||
inverse(matrix)
|
inverse(matrix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
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<Double> = one
|
||||||
|
repeat(n) { res += one }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun specializedFieldAdd() {
|
||||||
|
with(specializedField) {
|
||||||
|
var res: NDStructure<Double> = one
|
||||||
|
repeat(n) { res += 1.0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun boxingFieldAdd() {
|
||||||
|
with(genericField) {
|
||||||
|
var res: NDStructure<Double> = 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)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
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<Double, RealField> = 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<Double> = one
|
||||||
|
repeat(n) { res += 1.0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun realFieldAddition() {
|
||||||
|
with(realField) {
|
||||||
|
var res: NDStructure<Double> = 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 }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
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<Double, RealField> = 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
|
import space.kscience.kmath.expressions.invoke
|
||||||
|
import space.kscience.kmath.operations.RealField
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val expr = RealField.mstInField {
|
||||||
|
val x = bindSymbol("x")
|
||||||
|
x * 2.0 + 2.0 / x - 16.0
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat(10000000){
|
||||||
|
expr.invoke("x" to 1.0)
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
package kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import kscience.kmath.asm.compile
|
import space.kscience.kmath.asm.compile
|
||||||
import kscience.kmath.expressions.derivative
|
import space.kscience.kmath.expressions.derivative
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.expressions.symbol
|
import space.kscience.kmath.expressions.symbol
|
||||||
import kscience.kmath.kotlingrad.differentiable
|
import space.kscience.kmath.kotlingrad.differentiable
|
||||||
import kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.RealField
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
|
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
|
@ -1,19 +1,19 @@
|
|||||||
package kscience.kmath.commons.fit
|
package space.kscience.kmath.commons.fit
|
||||||
|
|
||||||
import kotlinx.html.br
|
import kotlinx.html.br
|
||||||
import kotlinx.html.h3
|
import kotlinx.html.h3
|
||||||
import kscience.kmath.commons.optimization.chiSquared
|
|
||||||
import kscience.kmath.commons.optimization.minimize
|
|
||||||
import kscience.kmath.expressions.symbol
|
|
||||||
import kscience.kmath.real.RealVector
|
|
||||||
import kscience.kmath.real.map
|
|
||||||
import kscience.kmath.real.step
|
|
||||||
import kscience.kmath.stat.*
|
|
||||||
import kscience.kmath.structures.asIterable
|
|
||||||
import kscience.kmath.structures.toList
|
|
||||||
import kscience.plotly.*
|
import kscience.plotly.*
|
||||||
import kscience.plotly.models.ScatterMode
|
import kscience.plotly.models.ScatterMode
|
||||||
import kscience.plotly.models.TraceValues
|
import kscience.plotly.models.TraceValues
|
||||||
|
import space.kscience.kmath.commons.optimization.chiSquared
|
||||||
|
import space.kscience.kmath.commons.optimization.minimize
|
||||||
|
import space.kscience.kmath.expressions.symbol
|
||||||
|
import space.kscience.kmath.real.RealVector
|
||||||
|
import space.kscience.kmath.real.map
|
||||||
|
import space.kscience.kmath.real.step
|
||||||
|
import space.kscience.kmath.stat.*
|
||||||
|
import space.kscience.kmath.structures.asIterable
|
||||||
|
import space.kscience.kmath.structures.toList
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ fun main() {
|
|||||||
val a = bind(a)
|
val a = bind(a)
|
||||||
val b = bind(b)
|
val b = bind(b)
|
||||||
//Include default value for c if it is not provided as a parameter
|
//Include default value for c if it is not provided as a parameter
|
||||||
val c = bindOrNull(c) ?: one
|
val c = bindSymbolOrNull(c) ?: one
|
||||||
a * x1.pow(2) + b * x1 + c
|
a * x1.pow(2) + b * x1 + c
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val res = BigIntField { number(1) * 2 }
|
val res = BigIntField { number(1) * 2 }
|
@ -1,23 +1,24 @@
|
|||||||
package kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
import kscience.kmath.structures.NDElement
|
import space.kscience.kmath.complex.Complex
|
||||||
import kscience.kmath.structures.NDField
|
import space.kscience.kmath.complex.complex
|
||||||
import kscience.kmath.structures.complex
|
import space.kscience.kmath.nd.NDAlgebra
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
// 2d element
|
// 2d element
|
||||||
val element = NDElement.complex(2, 2) { (i,j) ->
|
val element = NDAlgebra.complex(2, 2).produce { (i, j) ->
|
||||||
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
||||||
}
|
}
|
||||||
println(element)
|
println(element)
|
||||||
|
|
||||||
// 1d element operation
|
// 1d element operation
|
||||||
val result = with(NDField.complex(8)) {
|
val result = with(NDAlgebra.complex(8)) {
|
||||||
val a = produce { (it) -> i * it - it.toDouble() }
|
val a = produce { (it) -> i * it - it.toDouble() }
|
||||||
val b = 3
|
val b = 3
|
||||||
val c = Complex(1.0, 1.0)
|
val c = Complex(1.0, 1.0)
|
||||||
|
|
||||||
(a pow b) + c
|
(a pow b) + c
|
||||||
}
|
}
|
||||||
|
|
||||||
println(result)
|
println(result)
|
||||||
}
|
}
|
@ -3,9 +3,9 @@ package kscience.kmath.commons.prob
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kscience.kmath.stat.*
|
|
||||||
import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler
|
import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler
|
||||||
import org.apache.commons.rng.simple.RandomSource
|
import org.apache.commons.rng.simple.RandomSource
|
||||||
|
import space.kscience.kmath.stat.*
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
package kscience.kmath.stat
|
package space.kscience.kmath.stat
|
||||||
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kscience.kmath.chains.Chain
|
import space.kscience.kmath.chains.Chain
|
||||||
import kscience.kmath.chains.collectWithState
|
import space.kscience.kmath.chains.collectWithState
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state of distribution averager
|
* The state of distribution averager
|
@ -1,21 +1,26 @@
|
|||||||
package kscience.kmath.structures
|
@file:Suppress("unused")
|
||||||
|
|
||||||
import kscience.kmath.linear.transpose
|
package space.kscience.kmath.structures
|
||||||
import kscience.kmath.operations.Complex
|
|
||||||
import kscience.kmath.operations.ComplexField
|
import space.kscience.kmath.complex.*
|
||||||
import kscience.kmath.operations.invoke
|
import space.kscience.kmath.linear.transpose
|
||||||
|
import space.kscience.kmath.nd.NDAlgebra
|
||||||
|
import space.kscience.kmath.nd.NDStructure
|
||||||
|
import space.kscience.kmath.nd.as2D
|
||||||
|
import space.kscience.kmath.nd.real
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val dim = 1000
|
val dim = 1000
|
||||||
val n = 1000
|
val n = 1000
|
||||||
|
|
||||||
val realField = NDField.real(dim, dim)
|
val realField = NDAlgebra.real(dim, dim)
|
||||||
val complexField: ComplexNDField = NDField.complex(dim, dim)
|
val complexField: ComplexNDField = NDAlgebra.complex(dim, dim)
|
||||||
|
|
||||||
val realTime = measureTimeMillis {
|
val realTime = measureTimeMillis {
|
||||||
realField {
|
realField {
|
||||||
var res: NDBuffer<Double> = one
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) {
|
repeat(n) {
|
||||||
res += 1.0
|
res += 1.0
|
||||||
}
|
}
|
||||||
@ -26,8 +31,10 @@ fun main() {
|
|||||||
|
|
||||||
val complexTime = measureTimeMillis {
|
val complexTime = measureTimeMillis {
|
||||||
complexField {
|
complexField {
|
||||||
var res: NDBuffer<Complex> = one
|
var res: NDStructure<Complex> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) {
|
||||||
|
res += 1.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,12 @@
|
|||||||
package kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kscience.kmath.nd4j.Nd4jArrayField
|
|
||||||
import kscience.kmath.operations.RealField
|
|
||||||
import kscience.kmath.operations.invoke
|
|
||||||
import org.nd4j.linalg.factory.Nd4j
|
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.invoke
|
||||||
|
import space.kscience.kmath.viktor.ViktorNDField
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
@ -22,42 +24,62 @@ fun main() {
|
|||||||
val n = 1000
|
val n = 1000
|
||||||
|
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
val autoField = NDField.auto(RealField, dim, dim)
|
val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||||
// specialized nd-field for Double. It works as generic Double field as well
|
// specialized nd-field for Double. It works as generic Double field as well
|
||||||
val specializedField = NDField.real(dim, dim)
|
val realField = NDAlgebra.real(dim, dim)
|
||||||
//A generic boxing field. It should be used for objects, not primitives.
|
//A generic boxing field. It should be used for objects, not primitives.
|
||||||
val genericField = NDField.boxing(RealField, dim, dim)
|
val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
||||||
// Nd4j specialized field.
|
// Nd4j specialized field.
|
||||||
val nd4jField = Nd4jArrayField.real(dim, dim)
|
val nd4jField = Nd4jArrayField.real(dim, dim)
|
||||||
|
//viktor field
|
||||||
|
val viktorField = ViktorNDField(dim,dim)
|
||||||
|
//parallel processing based on Java Streams
|
||||||
|
val parallelField = NDAlgebra.realWithStream(dim,dim)
|
||||||
|
|
||||||
measureAndPrint("Automatic field addition") {
|
measureAndPrint("Boxing addition") {
|
||||||
autoField {
|
boxingField {
|
||||||
var res: NDBuffer<Double> = one
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Element addition") {
|
|
||||||
var res = genericField.one
|
|
||||||
repeat(n) { res += 1.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
measureAndPrint("Specialized addition") {
|
measureAndPrint("Specialized addition") {
|
||||||
specializedField {
|
realField {
|
||||||
var res: NDBuffer<Double> = one
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Nd4j specialized addition") {
|
measureAndPrint("Nd4j specialized addition") {
|
||||||
nd4jField {
|
nd4jField {
|
||||||
var res = one
|
var res: NDStructure<Double> = one
|
||||||
|
repeat(n) { res += 1.0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
measureAndPrint("Viktor addition") {
|
||||||
|
viktorField {
|
||||||
|
var res: NDStructure<Double> = one
|
||||||
|
repeat(n) { res += 1.0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
measureAndPrint("Parallel stream addition") {
|
||||||
|
parallelField {
|
||||||
|
var res: NDStructure<Double> = one
|
||||||
|
repeat(n) { res += 1.0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
measureAndPrint("Automatic field addition") {
|
||||||
|
autoField {
|
||||||
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Lazy addition") {
|
measureAndPrint("Lazy addition") {
|
||||||
val res = specializedField.one.mapAsync(GlobalScope) {
|
val res = realField.one.mapAsync(GlobalScope) {
|
||||||
var c = 0.0
|
var c = 0.0
|
||||||
repeat(n) {
|
repeat(n) {
|
||||||
c += 1.0
|
c += 1.0
|
||||||
@ -67,14 +89,4 @@ fun main() {
|
|||||||
|
|
||||||
res.elements().forEach { it.second }
|
res.elements().forEach { it.second }
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Generic addition") {
|
|
||||||
//genericField.run(action)
|
|
||||||
genericField {
|
|
||||||
var res: NDBuffer<Double> = one
|
|
||||||
repeat(n) {
|
|
||||||
res += 1.0 // couldn't avoid using `one` due to resolution ambiguity }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
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<Double, RealField>,
|
||||||
|
RingWithNumbers<NDStructure<Double>>,
|
||||||
|
ExtendedField<NDStructure<Double>> {
|
||||||
|
|
||||||
|
private val strides = DefaultStrides(shape)
|
||||||
|
override val elementContext: RealField get() = RealField
|
||||||
|
override val zero: NDBuffer<Double> by lazy { produce { zero } }
|
||||||
|
override val one: NDBuffer<Double> by lazy { produce { one } }
|
||||||
|
|
||||||
|
override fun number(value: Number): NDBuffer<Double> {
|
||||||
|
val d = value.toDouble() // minimize conversions
|
||||||
|
return produce { d }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val NDStructure<Double>.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<Double> {
|
||||||
|
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<Double>.map(
|
||||||
|
transform: RealField.(Double) -> Double,
|
||||||
|
): NDBuffer<Double> {
|
||||||
|
val array = Arrays.stream(buffer.array).parallel().map { RealField.transform(it) }.toArray()
|
||||||
|
return NDBuffer(strides, array.asBuffer())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun NDStructure<Double>.mapIndexed(
|
||||||
|
transform: RealField.(index: IntArray, Double) -> Double,
|
||||||
|
): NDBuffer<Double> {
|
||||||
|
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<Double>,
|
||||||
|
b: NDStructure<Double>,
|
||||||
|
transform: RealField.(Double, Double) -> Double,
|
||||||
|
): NDBuffer<Double> {
|
||||||
|
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<Double>, pow: Number): NDBuffer<Double> = arg.map() { power(it, pow) }
|
||||||
|
|
||||||
|
override fun exp(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { exp(it) }
|
||||||
|
|
||||||
|
override fun ln(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { ln(it) }
|
||||||
|
|
||||||
|
override fun sin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { sin(it) }
|
||||||
|
override fun cos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { cos(it) }
|
||||||
|
override fun tan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { tan(it) }
|
||||||
|
override fun asin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { asin(it) }
|
||||||
|
override fun acos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { acos(it) }
|
||||||
|
override fun atan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { atan(it) }
|
||||||
|
|
||||||
|
override fun sinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { sinh(it) }
|
||||||
|
override fun cosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { cosh(it) }
|
||||||
|
override fun tanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { tanh(it) }
|
||||||
|
override fun asinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { asinh(it) }
|
||||||
|
override fun acosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { acosh(it) }
|
||||||
|
override fun atanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { atanh(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun NDAlgebra.Companion.realWithStream(vararg shape: Int): StreamRealNDField = StreamRealNDField(shape)
|
@ -1,13 +1,16 @@
|
|||||||
package kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.kmath.nd.DefaultStrides
|
||||||
|
import space.kscience.kmath.nd.NDBuffer
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
|
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||||
fun main() {
|
fun main() {
|
||||||
val n = 6000
|
val n = 6000
|
||||||
val array = DoubleArray(n * n) { 1.0 }
|
val array = DoubleArray(n * n) { 1.0 }
|
||||||
val buffer = RealBuffer(array)
|
val buffer = RealBuffer(array)
|
||||||
val strides = DefaultStrides(intArrayOf(n, n))
|
val strides = DefaultStrides(intArrayOf(n, n))
|
||||||
val structure = BufferNDStructure(strides, buffer)
|
val structure = NDBuffer(strides, buffer)
|
||||||
|
|
||||||
measureTimeMillis {
|
measureTimeMillis {
|
||||||
var res = 0.0
|
var res = 0.0
|
@ -1,7 +1,10 @@
|
|||||||
package kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.kmath.nd.NDStructure
|
||||||
|
import space.kscience.kmath.nd.mapToBuffer
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
fun main() {
|
fun main() {
|
||||||
val n = 6000
|
val n = 6000
|
||||||
val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
@ -1,9 +1,9 @@
|
|||||||
package kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import kscience.kmath.dimensions.D2
|
import space.kscience.kmath.dimensions.D2
|
||||||
import kscience.kmath.dimensions.D3
|
import space.kscience.kmath.dimensions.D3
|
||||||
import kscience.kmath.dimensions.DMatrixContext
|
import space.kscience.kmath.dimensions.DMatrixContext
|
||||||
import kscience.kmath.dimensions.Dimension
|
import space.kscience.kmath.dimensions.Dimension
|
||||||
|
|
||||||
private fun DMatrixContext<Double>.simple() {
|
private fun DMatrixContext<Double>.simple() {
|
||||||
val m1 = produce<D2, D3> { i, j -> (i + j).toDouble() }
|
val m1 = produce<D2, D3> { i, j -> (i + j).toDouble() }
|
@ -1,9 +1,8 @@
|
|||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
kotlin.parallel.tasks.in.project=true
|
|
||||||
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||||
kotlin.native.enableDependencyPropagation=false
|
|
||||||
kotlin.mpp.stability.nowarn=true
|
kotlin.mpp.stability.nowarn=true
|
||||||
|
kotlin.native.enableDependencyPropagation=false
|
||||||
|
kotlin.parallel.tasks.in.project=true
|
||||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m
|
org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
systemProp.org.gradle.internal.publish.checksums.insecure=true
|
systemProp.org.gradle.internal.publish.checksums.insecure=true
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -12,7 +12,7 @@ This subproject implements the following features:
|
|||||||
|
|
||||||
> #### Artifact:
|
> #### Artifact:
|
||||||
>
|
>
|
||||||
> This module artifact: `kscience.kmath:kmath-ast:0.2.0-dev-4`.
|
> 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 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)
|
||||||
>
|
>
|
||||||
@ -22,29 +22,32 @@ This subproject implements the following features:
|
|||||||
>
|
>
|
||||||
> ```gradle
|
> ```gradle
|
||||||
> repositories {
|
> repositories {
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
|
> maven { url 'https://repo.kotlin.link' }
|
||||||
> maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
|
||||||
> maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
> 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 {
|
> dependencies {
|
||||||
> implementation 'kscience.kmath:kmath-ast:0.2.0-dev-4'
|
> implementation 'space.kscience:kmath-ast:0.2.0'
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
> **Gradle Kotlin DSL:**
|
> **Gradle Kotlin DSL:**
|
||||||
>
|
>
|
||||||
> ```kotlin
|
> ```kotlin
|
||||||
> repositories {
|
> repositories {
|
||||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
> maven("https://repo.kotlin.link")
|
||||||
> maven("https://dl.bintray.com/mipt-npm/kscience")
|
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> maven("https://dl.bintray.com/mipt-npm/dev")
|
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
> maven("https://dl.bintray.com/hotkeytlt/maven")
|
>// Uncomment if repo.kotlin.link is unavailable
|
||||||
|
>// maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||||
|
>// maven("https://dl.bintray.com/mipt-npm/dev")
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> dependencies {
|
> dependencies {
|
||||||
> implementation("kscience.kmath:kmath-ast:0.2.0-dev-4")
|
> implementation("space.kscience:kmath-ast:0.2.0")
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
@ -61,21 +64,21 @@ For example, the following builder:
|
|||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||||
```
|
```
|
||||||
|
|
||||||
… 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
|
```java
|
||||||
package kscience.kmath.asm.generated;
|
package space.kscience.kmath.asm.generated;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import kotlin.jvm.functions.Function2;
|
import kotlin.jvm.functions.Function2;
|
||||||
import kscience.kmath.asm.internal.MapIntrinsics;
|
import space.kscience.kmath.asm.internal.MapIntrinsics;
|
||||||
import kscience.kmath.expressions.Expression;
|
import space.kscience.kmath.expressions.Expression;
|
||||||
import kscience.kmath.expressions.Symbol;
|
import space.kscience.kmath.expressions.Symbol;
|
||||||
|
|
||||||
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
||||||
private final Object[] constants;
|
private final Object[] constants;
|
||||||
|
|
||||||
public final Double invoke(Map<Symbol, Double> arguments) {
|
public final Double invoke(Map<Symbol, ? extends Double> 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import ru.mipt.npm.gradle.Maturity
|
import ru.mipt.npm.gradle.Maturity
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.mpp")
|
id("ru.mipt.npm.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin.js {
|
kotlin.js {
|
||||||
@ -25,21 +25,32 @@ kotlin.sourceSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commonTest {
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":kmath-complex"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
jsMain {
|
jsMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(npm("astring", "1.4.3"))
|
implementation(npm("astring", "1.7.0"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jvmMain {
|
jvmMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("com.github.h0tk3y.betterParse:better-parse:0.4.0")
|
api("com.github.h0tk3y.betterParse:better-parse:0.4.1")
|
||||||
implementation("org.ow2.asm:asm:9.0")
|
implementation("org.ow2.asm:asm:9.1")
|
||||||
implementation("org.ow2.asm:asm-commons:9.0")
|
implementation("org.ow2.asm:asm-commons:9.1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Workaround for https://github.com/Kotlin/dokka/issues/1455
|
||||||
|
tasks.dokkaHtml {
|
||||||
|
dependsOn(tasks.build)
|
||||||
|
}
|
||||||
|
|
||||||
readme {
|
readme {
|
||||||
maturity = Maturity.PROTOTYPE
|
maturity = Maturity.PROTOTYPE
|
||||||
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
|
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
|
||||||
|
@ -22,18 +22,18 @@ RealField.mstInField { symbol("x") + 2 }.compile()
|
|||||||
… 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
|
```java
|
||||||
package kscience.kmath.asm.generated;
|
package space.kscience.kmath.asm.generated;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import kotlin.jvm.functions.Function2;
|
import kotlin.jvm.functions.Function2;
|
||||||
import kscience.kmath.asm.internal.MapIntrinsics;
|
import space.kscience.kmath.asm.internal.MapIntrinsics;
|
||||||
import kscience.kmath.expressions.Expression;
|
import space.kscience.kmath.expressions.Expression;
|
||||||
import kscience.kmath.expressions.Symbol;
|
import space.kscience.kmath.expressions.Symbol;
|
||||||
|
|
||||||
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
||||||
private final Object[] constants;
|
private final Object[] constants;
|
||||||
|
|
||||||
public final Double invoke(Map<Symbol, Double> arguments) {
|
public final Double invoke(Map<Symbol, ? extends Double> 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import kscience.kmath.operations.Algebra
|
import space.kscience.kmath.operations.Algebra
|
||||||
import kscience.kmath.operations.NumericAlgebra
|
import space.kscience.kmath.operations.NumericAlgebra
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Mathematical Syntax Tree (MST) node for mathematical expressions.
|
* A Mathematical Syntax Tree (MST) node for mathematical expressions.
|
||||||
@ -55,7 +55,7 @@ public fun <T> Algebra<T>.evaluate(node: MST): T = when (node) {
|
|||||||
is MST.Numeric -> (this as? NumericAlgebra<T>)?.number(node.value)
|
is MST.Numeric -> (this as? NumericAlgebra<T>)?.number(node.value)
|
||||||
?: error("Numeric nodes are not supported by $this")
|
?: error("Numeric nodes are not supported by $this")
|
||||||
|
|
||||||
is MST.Symbolic -> symbol(node.value)
|
is MST.Symbolic -> bindSymbol(node.value)
|
||||||
|
|
||||||
is MST.Unary -> when {
|
is MST.Unary -> when {
|
||||||
this is NumericAlgebra && node.value is MST.Numeric -> unaryOperationFunction(node.operation)(number(node.value.value))
|
this is NumericAlgebra && node.value is MST.Numeric -> unaryOperationFunction(node.operation)(number(node.value.value))
|
@ -1,14 +1,14 @@
|
|||||||
package kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Algebra] over [MST] nodes.
|
* [Algebra] over [MST] nodes.
|
||||||
*/
|
*/
|
||||||
public object MstAlgebra : NumericAlgebra<MST> {
|
public object MstAlgebra : NumericAlgebra<MST> {
|
||||||
public override fun number(value: Number): MST.Numeric = MST.Numeric(value)
|
public override fun number(value: Number): MST.Numeric = MST.Numeric(value)
|
||||||
public override fun symbol(value: String): MST.Symbolic = MST.Symbolic(value)
|
public override fun bindSymbol(value: String): MST.Symbolic = MST.Symbolic(value)
|
||||||
|
|
||||||
public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary =
|
public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary =
|
||||||
{ arg -> MST.Unary(operation, arg) }
|
{ arg -> MST.Unary(operation, arg) }
|
||||||
@ -24,7 +24,7 @@ public object MstSpace : Space<MST>, NumericAlgebra<MST> {
|
|||||||
public override val zero: MST.Numeric by lazy { number(0.0) }
|
public override val zero: MST.Numeric by lazy { number(0.0) }
|
||||||
|
|
||||||
public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value)
|
public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value)
|
||||||
public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value)
|
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(value)
|
||||||
public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b)
|
public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b)
|
||||||
public override operator fun MST.unaryPlus(): MST.Unary =
|
public override operator fun MST.unaryPlus(): MST.Unary =
|
||||||
unaryOperationFunction(SpaceOperations.PLUS_OPERATION)(this)
|
unaryOperationFunction(SpaceOperations.PLUS_OPERATION)(this)
|
||||||
@ -56,7 +56,7 @@ public object MstRing : Ring<MST>, RingWithNumbers<MST> {
|
|||||||
public override val one: MST.Numeric by lazy { number(1.0) }
|
public override val one: MST.Numeric by lazy { number(1.0) }
|
||||||
|
|
||||||
public override fun number(value: Number): MST.Numeric = MstSpace.number(value)
|
public override fun number(value: Number): MST.Numeric = MstSpace.number(value)
|
||||||
public override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value)
|
public override fun bindSymbol(value: String): MST.Symbolic = MstSpace.bindSymbol(value)
|
||||||
public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b)
|
public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b)
|
||||||
public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k)
|
public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k)
|
||||||
public override fun multiply(a: MST, b: MST): MST.Binary =
|
public override fun multiply(a: MST, b: MST): MST.Binary =
|
||||||
@ -84,7 +84,7 @@ public object MstField : Field<MST>, RingWithNumbers<MST> {
|
|||||||
public override val one: MST.Numeric
|
public override val one: MST.Numeric
|
||||||
get() = MstRing.one
|
get() = MstRing.one
|
||||||
|
|
||||||
public override fun symbol(value: String): MST.Symbolic = MstRing.symbol(value)
|
public override fun bindSymbol(value: String): MST.Symbolic = MstRing.bindSymbol(value)
|
||||||
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
|
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
|
||||||
public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b)
|
public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b)
|
||||||
public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k)
|
public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k)
|
||||||
@ -113,7 +113,7 @@ public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
|
|||||||
public override val one: MST.Numeric
|
public override val one: MST.Numeric
|
||||||
get() = MstField.one
|
get() = MstField.one
|
||||||
|
|
||||||
public override fun symbol(value: String): MST.Symbolic = MstField.symbol(value)
|
public override fun bindSymbol(value: String): MST.Symbolic = MstField.bindSymbol(value)
|
||||||
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
|
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
|
||||||
public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg)
|
public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg)
|
||||||
public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg)
|
public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg)
|
@ -1,7 +1,7 @@
|
|||||||
package kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import kscience.kmath.expressions.*
|
import space.kscience.kmath.expressions.*
|
||||||
import kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
@ -15,14 +15,23 @@ import kotlin.contracts.contract
|
|||||||
*/
|
*/
|
||||||
public class MstExpression<T, out A : Algebra<T>>(public val algebra: A, public val mst: MST) : Expression<T> {
|
public class MstExpression<T, out A : Algebra<T>>(public val algebra: A, public val mst: MST) : Expression<T> {
|
||||||
private inner class InnerAlgebra(val arguments: Map<Symbol, T>) : NumericAlgebra<T> {
|
private inner class InnerAlgebra(val arguments: Map<Symbol, T>) : NumericAlgebra<T> {
|
||||||
override fun symbol(value: String): T = try {
|
override fun bindSymbol(value: String): T = try {
|
||||||
algebra.symbol(value)
|
algebra.bindSymbol(value)
|
||||||
} catch (ignored: IllegalStateException) {
|
} catch (ignored: IllegalStateException) {
|
||||||
null
|
null
|
||||||
} ?: arguments.getValue(StringSymbol(value))
|
} ?: arguments.getValue(StringSymbol(value))
|
||||||
|
|
||||||
override fun unaryOperationFunction(operation: String): (arg: T) -> T = algebra.unaryOperationFunction(operation)
|
override fun unaryOperation(operation: String, arg: T): T =
|
||||||
override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = algebra.binaryOperationFunction(operation)
|
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")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun number(value: Number): T = if (algebra is NumericAlgebra<*>)
|
override fun number(value: Number): T = if (algebra is NumericAlgebra<*>)
|
@ -1,3 +0,0 @@
|
|||||||
package kscience.kmath.estree.internal.astring
|
|
||||||
|
|
||||||
internal typealias Generator = Any
|
|
@ -1,7 +0,0 @@
|
|||||||
package kscience.kmath.estree.internal.stream
|
|
||||||
|
|
||||||
import kscience.kmath.estree.internal.emitter.Emitter
|
|
||||||
|
|
||||||
internal open external class Stream : Emitter {
|
|
||||||
open fun pipe(dest: Any, options: Any): Any
|
|
||||||
}
|
|
@ -1,20 +1,20 @@
|
|||||||
package kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import kscience.kmath.ast.MST
|
import space.kscience.kmath.ast.MST
|
||||||
import kscience.kmath.ast.MST.*
|
import space.kscience.kmath.ast.MST.*
|
||||||
import kscience.kmath.ast.MstExpression
|
import space.kscience.kmath.ast.MstExpression
|
||||||
import kscience.kmath.estree.internal.ESTreeBuilder
|
import space.kscience.kmath.estree.internal.ESTreeBuilder
|
||||||
import kscience.kmath.estree.internal.estree.BaseExpression
|
import space.kscience.kmath.estree.internal.estree.BaseExpression
|
||||||
import kscience.kmath.expressions.Expression
|
import space.kscience.kmath.expressions.Expression
|
||||||
import kscience.kmath.operations.Algebra
|
import space.kscience.kmath.operations.Algebra
|
||||||
import kscience.kmath.operations.NumericAlgebra
|
import space.kscience.kmath.operations.NumericAlgebra
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
|
internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
|
||||||
fun ESTreeBuilder<T>.visit(node: MST): BaseExpression = when (node) {
|
fun ESTreeBuilder<T>.visit(node: MST): BaseExpression = when (node) {
|
||||||
is Symbolic -> {
|
is Symbolic -> {
|
||||||
val symbol = try {
|
val symbol = try {
|
||||||
algebra.symbol(node.value)
|
algebra.bindSymbol(node.value)
|
||||||
} catch (ignored: IllegalStateException) {
|
} catch (ignored: IllegalStateException) {
|
||||||
null
|
null
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
package kscience.kmath.estree.internal
|
package space.kscience.kmath.estree.internal
|
||||||
|
|
||||||
import kscience.kmath.estree.internal.astring.generate
|
import space.kscience.kmath.estree.internal.astring.generate
|
||||||
import kscience.kmath.estree.internal.estree.*
|
import space.kscience.kmath.estree.internal.estree.*
|
||||||
import kscience.kmath.expressions.Expression
|
import space.kscience.kmath.expressions.Expression
|
||||||
import kscience.kmath.expressions.Symbol
|
import space.kscience.kmath.expressions.Symbol
|
||||||
|
|
||||||
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {
|
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {
|
||||||
private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> {
|
private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> {
|
@ -1,9 +1,9 @@
|
|||||||
@file:JsModule("astring")
|
@file:JsModule("astring")
|
||||||
@file:JsNonModule
|
@file:JsNonModule
|
||||||
|
|
||||||
package kscience.kmath.estree.internal.astring
|
package space.kscience.kmath.estree.internal.astring
|
||||||
|
|
||||||
import kscience.kmath.estree.internal.estree.BaseNode
|
import space.kscience.kmath.estree.internal.estree.BaseNode
|
||||||
|
|
||||||
internal external interface Options {
|
internal external interface Options {
|
||||||
var indent: String?
|
var indent: String?
|
@ -0,0 +1,3 @@
|
|||||||
|
package space.kscience.kmath.estree.internal.astring
|
||||||
|
|
||||||
|
internal typealias Generator = Any
|
@ -1,4 +1,4 @@
|
|||||||
package kscience.kmath.estree.internal.emitter
|
package space.kscience.kmath.estree.internal.emitter
|
||||||
|
|
||||||
internal open external class Emitter {
|
internal open external class Emitter {
|
||||||
constructor(obj: Any)
|
constructor(obj: Any)
|
@ -1,4 +1,4 @@
|
|||||||
package kscience.kmath.estree.internal.estree
|
package space.kscience.kmath.estree.internal.estree
|
||||||
|
|
||||||
internal fun Program(sourceType: String, vararg body: dynamic) = object : Program {
|
internal fun Program(sourceType: String, vararg body: dynamic) = object : Program {
|
||||||
override var type = "Program"
|
override var type = "Program"
|
@ -1,4 +1,4 @@
|
|||||||
package kscience.kmath.estree.internal.estree
|
package space.kscience.kmath.estree.internal.estree
|
||||||
|
|
||||||
import kotlin.js.RegExp
|
import kotlin.js.RegExp
|
||||||
|
|
@ -0,0 +1,7 @@
|
|||||||
|
package space.kscience.kmath.estree.internal.stream
|
||||||
|
|
||||||
|
import space.kscience.kmath.estree.internal.emitter.Emitter
|
||||||
|
|
||||||
|
internal open external class Stream : Emitter {
|
||||||
|
open fun pipe(dest: Any, options: Any): Any
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package kscience.kmath.estree.internal.tsstdlib
|
package space.kscience.kmath.estree.internal.tsstdlib
|
||||||
|
|
||||||
internal external interface IteratorYieldResult<TYield> {
|
internal external interface IteratorYieldResult<TYield> {
|
||||||
var done: Boolean?
|
var done: Boolean?
|
@ -1,6 +1,6 @@
|
|||||||
@file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION")
|
@file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION")
|
||||||
|
|
||||||
package kscience.kmath.estree.internal.tsstdlib
|
package space.kscience.kmath.estree.internal.tsstdlib
|
||||||
|
|
||||||
import kotlin.js.RegExp
|
import kotlin.js.RegExp
|
||||||
|
|
@ -1,11 +1,11 @@
|
|||||||
package kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import kscience.kmath.ast.*
|
import space.kscience.kmath.ast.*
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.complex.ComplexField
|
||||||
import kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.complex.toComplex
|
||||||
import kscience.kmath.operations.ComplexField
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.ByteRing
|
||||||
import kscience.kmath.operations.toComplex
|
import space.kscience.kmath.operations.RealField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
),
|
),
|
||||||
|
|
||||||
number(1)
|
number(1)
|
||||||
) + symbol("x") + zero
|
) + bindSymbol("x") + zero
|
||||||
}("x" to MST.Numeric(2))
|
}("x" to MST.Numeric(2))
|
||||||
|
|
||||||
val res2 = MstSpace.mstInSpace {
|
val res2 = MstSpace.mstInSpace {
|
||||||
@ -35,7 +35,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
),
|
),
|
||||||
|
|
||||||
number(1)
|
number(1)
|
||||||
) + symbol("x") + zero
|
) + bindSymbol("x") + zero
|
||||||
}.compile()("x" to MST.Numeric(2))
|
}.compile()("x" to MST.Numeric(2))
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
assertEquals(res1, res2)
|
||||||
@ -46,7 +46,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
val res1 = ByteRing.mstInRing {
|
val res1 = ByteRing.mstInRing {
|
||||||
binaryOperationFunction("+")(
|
binaryOperationFunction("+")(
|
||||||
unaryOperationFunction("+")(
|
unaryOperationFunction("+")(
|
||||||
(symbol("x") - (2.toByte() + (multiply(
|
(bindSymbol("x") - (2.toByte() + (multiply(
|
||||||
add(number(1), number(1)),
|
add(number(1), number(1)),
|
||||||
2
|
2
|
||||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
) + 1.toByte()))) * 3.0 - 1.toByte()
|
||||||
@ -59,7 +59,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
val res2 = ByteRing.mstInRing {
|
val res2 = ByteRing.mstInRing {
|
||||||
binaryOperationFunction("+")(
|
binaryOperationFunction("+")(
|
||||||
unaryOperationFunction("+")(
|
unaryOperationFunction("+")(
|
||||||
(symbol("x") - (2.toByte() + (multiply(
|
(bindSymbol("x") - (2.toByte() + (multiply(
|
||||||
add(number(1), number(1)),
|
add(number(1), number(1)),
|
||||||
2
|
2
|
||||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
) + 1.toByte()))) * 3.0 - 1.toByte()
|
||||||
@ -75,7 +75,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
fun realField() {
|
fun realField() {
|
||||||
val res1 = RealField.mstInField {
|
val res1 = RealField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
@ -83,7 +83,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
|
|
||||||
val res2 = RealField.mstInField {
|
val res2 = RealField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
@ -96,7 +96,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
fun complexField() {
|
fun complexField() {
|
||||||
val res1 = ComplexField.mstInField {
|
val res1 = ComplexField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
@ -104,7 +104,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
|
|
||||||
val res2 = ComplexField.mstInField {
|
val res2 = ComplexField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
@ -1,10 +1,10 @@
|
|||||||
package kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import kscience.kmath.ast.mstInExtendedField
|
import space.kscience.kmath.ast.mstInExtendedField
|
||||||
import kscience.kmath.ast.mstInField
|
import space.kscience.kmath.ast.mstInField
|
||||||
import kscience.kmath.ast.mstInSpace
|
import space.kscience.kmath.ast.mstInSpace
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.RealField
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -12,27 +12,27 @@ import kotlin.test.assertEquals
|
|||||||
internal class TestESTreeOperationsSupport {
|
internal class TestESTreeOperationsSupport {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryOperationInvocation() {
|
fun testUnaryOperationInvocation() {
|
||||||
val expression = RealField.mstInSpace { -symbol("x") }.compile()
|
val expression = RealField.mstInSpace { -bindSymbol("x") }.compile()
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-2.0, res)
|
assertEquals(-2.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBinaryOperationInvocation() {
|
fun testBinaryOperationInvocation() {
|
||||||
val expression = RealField.mstInSpace { -symbol("x") + number(1.0) }.compile()
|
val expression = RealField.mstInSpace { -bindSymbol("x") + number(1.0) }.compile()
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-1.0, res)
|
assertEquals(-1.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testConstProductInvocation() {
|
fun testConstProductInvocation() {
|
||||||
val res = RealField.mstInField { symbol("x") * 2 }("x" to 2.0)
|
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
||||||
assertEquals(4.0, res)
|
assertEquals(4.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMultipleCalls() {
|
fun testMultipleCalls() {
|
||||||
val e = RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile()
|
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile()
|
||||||
val r = Random(0)
|
val r = Random(0)
|
||||||
var s = 0.0
|
var s = 0.0
|
||||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
@ -1,52 +1,52 @@
|
|||||||
package kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import kscience.kmath.ast.mstInField
|
import space.kscience.kmath.ast.mstInField
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.RealField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class TestESTreeSpecialization {
|
internal class TestESTreeSpecialization {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryPlus() {
|
fun testUnaryPlus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("+")(symbol("x")) }.compile()
|
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(2.0, expr("x" to 2.0))
|
assertEquals(2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryMinus() {
|
fun testUnaryMinus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile()
|
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(-2.0, expr("x" to 2.0))
|
assertEquals(-2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAdd() {
|
fun testAdd() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile()
|
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSine() {
|
fun testSine() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile()
|
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(0.0, expr("x" to 0.0))
|
assertEquals(0.0, expr("x" to 0.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMinus() {
|
fun testMinus() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile()
|
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(0.0, expr("x" to 2.0))
|
assertEquals(0.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDivide() {
|
fun testDivide() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile()
|
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(1.0, expr("x" to 2.0))
|
assertEquals(1.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPower() {
|
fun testPower() {
|
||||||
val expr = RealField
|
val expr = RealField
|
||||||
.mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) }
|
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||||
.compile()
|
.compile()
|
||||||
|
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
@ -1,8 +1,8 @@
|
|||||||
package kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import kscience.kmath.ast.mstInRing
|
import space.kscience.kmath.ast.mstInRing
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.operations.ByteRing
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
@ -10,13 +10,13 @@ import kotlin.test.assertFailsWith
|
|||||||
internal class TestESTreeVariables {
|
internal class TestESTreeVariables {
|
||||||
@Test
|
@Test
|
||||||
fun testVariable() {
|
fun testVariable() {
|
||||||
val expr = ByteRing.mstInRing { symbol("x") }.compile()
|
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||||
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUndefinedVariableFails() {
|
fun testUndefinedVariableFails() {
|
||||||
val expr = ByteRing.mstInRing { symbol("x") }.compile()
|
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||||
assertFailsWith<NoSuchElementException> { expr() }
|
assertFailsWith<NoSuchElementException> { expr() }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,13 +1,13 @@
|
|||||||
package kscience.kmath.asm
|
package space.kscience.kmath.asm
|
||||||
|
|
||||||
import kscience.kmath.asm.internal.AsmBuilder
|
import space.kscience.kmath.asm.internal.AsmBuilder
|
||||||
import kscience.kmath.asm.internal.buildName
|
import space.kscience.kmath.asm.internal.buildName
|
||||||
import kscience.kmath.ast.MST
|
import space.kscience.kmath.ast.MST
|
||||||
import kscience.kmath.ast.MST.*
|
import space.kscience.kmath.ast.MST.*
|
||||||
import kscience.kmath.ast.MstExpression
|
import space.kscience.kmath.ast.MstExpression
|
||||||
import kscience.kmath.expressions.Expression
|
import space.kscience.kmath.expressions.Expression
|
||||||
import kscience.kmath.operations.Algebra
|
import space.kscience.kmath.operations.Algebra
|
||||||
import kscience.kmath.operations.NumericAlgebra
|
import space.kscience.kmath.operations.NumericAlgebra
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles given MST to an Expression using AST compiler.
|
* Compiles given MST to an Expression using AST compiler.
|
||||||
@ -22,7 +22,7 @@ internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Exp
|
|||||||
fun AsmBuilder<T>.visit(node: MST): Unit = when (node) {
|
fun AsmBuilder<T>.visit(node: MST): Unit = when (node) {
|
||||||
is Symbolic -> {
|
is Symbolic -> {
|
||||||
val symbol = try {
|
val symbol = try {
|
||||||
algebra.symbol(node.value)
|
algebra.bindSymbol(node.value)
|
||||||
} catch (ignored: IllegalStateException) {
|
} catch (ignored: IllegalStateException) {
|
||||||
null
|
null
|
||||||
}
|
}
|
@ -1,15 +1,14 @@
|
|||||||
package kscience.kmath.asm.internal
|
package space.kscience.kmath.asm.internal
|
||||||
|
|
||||||
import kscience.kmath.asm.internal.AsmBuilder.ClassLoader
|
|
||||||
import kscience.kmath.ast.MST
|
|
||||||
import kscience.kmath.expressions.Expression
|
|
||||||
import org.objectweb.asm.*
|
import org.objectweb.asm.*
|
||||||
import org.objectweb.asm.Opcodes.*
|
import org.objectweb.asm.Opcodes.*
|
||||||
import org.objectweb.asm.Type.*
|
import org.objectweb.asm.Type.*
|
||||||
import org.objectweb.asm.commons.InstructionAdapter
|
import org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader
|
||||||
|
import space.kscience.kmath.ast.MST
|
||||||
|
import space.kscience.kmath.expressions.Expression
|
||||||
import java.lang.invoke.MethodHandles
|
import java.lang.invoke.MethodHandles
|
||||||
import java.lang.invoke.MethodType
|
import java.lang.invoke.MethodType
|
||||||
import java.lang.reflect.Modifier
|
|
||||||
import java.util.stream.Collectors.toMap
|
import java.util.stream.Collectors.toMap
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
@ -83,7 +82,7 @@ internal class AsmBuilder<T>(
|
|||||||
ACC_PUBLIC or ACC_FINAL,
|
ACC_PUBLIC or ACC_FINAL,
|
||||||
"invoke",
|
"invoke",
|
||||||
getMethodDescriptor(tType, MAP_TYPE),
|
getMethodDescriptor(tType, MAP_TYPE),
|
||||||
"(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}${if (Modifier.isFinal(classOfT.modifiers)) "" else "+"}${tType.descriptor}>;)${tType.descriptor}",
|
"(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}",
|
||||||
null,
|
null,
|
||||||
).instructionAdapter {
|
).instructionAdapter {
|
||||||
invokeMethodVisitor = this
|
invokeMethodVisitor = this
|
||||||
@ -310,7 +309,7 @@ internal class AsmBuilder<T>(
|
|||||||
/**
|
/**
|
||||||
* ASM type for [Expression].
|
* ASM type for [Expression].
|
||||||
*/
|
*/
|
||||||
val EXPRESSION_TYPE: Type by lazy { getObjectType("kscience/kmath/expressions/Expression") }
|
val EXPRESSION_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Expression") }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ASM type for [java.util.Map].
|
* ASM type for [java.util.Map].
|
||||||
@ -335,11 +334,11 @@ internal class AsmBuilder<T>(
|
|||||||
/**
|
/**
|
||||||
* ASM type for MapIntrinsics.
|
* ASM type for MapIntrinsics.
|
||||||
*/
|
*/
|
||||||
val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("kscience/kmath/asm/internal/MapIntrinsics") }
|
val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ASM Type for [kscience.kmath.expressions.Symbol].
|
* ASM Type for [kscience.kmath.expressions.Symbol].
|
||||||
*/
|
*/
|
||||||
val SYMBOL_TYPE: Type by lazy { getObjectType("kscience/kmath/expressions/Symbol") }
|
val SYMBOL_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Symbol") }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
package kscience.kmath.asm.internal
|
package space.kscience.kmath.asm.internal
|
||||||
|
|
||||||
import kscience.kmath.ast.MST
|
|
||||||
import kscience.kmath.expressions.Expression
|
|
||||||
import org.objectweb.asm.*
|
import org.objectweb.asm.*
|
||||||
import org.objectweb.asm.commons.InstructionAdapter
|
import org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
import space.kscience.kmath.ast.MST
|
||||||
|
import space.kscience.kmath.expressions.Expression
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
@ -1,9 +1,9 @@
|
|||||||
@file:JvmName("MapIntrinsics")
|
@file:JvmName("MapIntrinsics")
|
||||||
|
|
||||||
package kscience.kmath.asm.internal
|
package space.kscience.kmath.asm.internal
|
||||||
|
|
||||||
import kscience.kmath.expressions.StringSymbol
|
import space.kscience.kmath.expressions.StringSymbol
|
||||||
import kscience.kmath.expressions.Symbol
|
import space.kscience.kmath.expressions.Symbol
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets value with given [key] or throws [NoSuchElementException] whenever it is not present.
|
* Gets value with given [key] or throws [NoSuchElementException] whenever it is not present.
|
@ -1,6 +1,6 @@
|
|||||||
// TODO move to common when https://github.com/h0tk3y/better-parse/pull/33 is merged
|
// TODO move to common when https://github.com/h0tk3y/better-parse/pull/37 is merged
|
||||||
|
|
||||||
package kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import com.github.h0tk3y.betterParse.combinators.*
|
import com.github.h0tk3y.betterParse.combinators.*
|
||||||
import com.github.h0tk3y.betterParse.grammar.Grammar
|
import com.github.h0tk3y.betterParse.grammar.Grammar
|
||||||
@ -13,10 +13,10 @@ import com.github.h0tk3y.betterParse.lexer.literalToken
|
|||||||
import com.github.h0tk3y.betterParse.lexer.regexToken
|
import com.github.h0tk3y.betterParse.lexer.regexToken
|
||||||
import com.github.h0tk3y.betterParse.parser.ParseResult
|
import com.github.h0tk3y.betterParse.parser.ParseResult
|
||||||
import com.github.h0tk3y.betterParse.parser.Parser
|
import com.github.h0tk3y.betterParse.parser.Parser
|
||||||
import kscience.kmath.operations.FieldOperations
|
import space.kscience.kmath.operations.FieldOperations
|
||||||
import kscience.kmath.operations.PowerOperations
|
import space.kscience.kmath.operations.PowerOperations
|
||||||
import kscience.kmath.operations.RingOperations
|
import space.kscience.kmath.operations.RingOperations
|
||||||
import kscience.kmath.operations.SpaceOperations
|
import space.kscience.kmath.operations.SpaceOperations
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4.
|
* better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4.
|
||||||
@ -25,8 +25,8 @@ import kscience.kmath.operations.SpaceOperations
|
|||||||
*/
|
*/
|
||||||
public object ArithmeticsEvaluator : Grammar<MST>() {
|
public object ArithmeticsEvaluator : Grammar<MST>() {
|
||||||
// TODO replace with "...".toRegex() when better-parse 0.4.1 is released
|
// TODO replace with "...".toRegex() when better-parse 0.4.1 is released
|
||||||
private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?")
|
private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?".toRegex())
|
||||||
private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*")
|
private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*".toRegex())
|
||||||
private val lpar: Token by literalToken("(")
|
private val lpar: Token by literalToken("(")
|
||||||
private val rpar: Token by literalToken(")")
|
private val rpar: Token by literalToken(")")
|
||||||
private val comma: Token by literalToken(",")
|
private val comma: Token by literalToken(",")
|
||||||
@ -35,7 +35,7 @@ public object ArithmeticsEvaluator : Grammar<MST>() {
|
|||||||
private val div: Token by literalToken("/")
|
private val div: Token by literalToken("/")
|
||||||
private val minus: Token by literalToken("-")
|
private val minus: Token by literalToken("-")
|
||||||
private val plus: Token by literalToken("+")
|
private val plus: Token by literalToken("+")
|
||||||
private val ws: Token by regexToken("\\s+", ignore = true)
|
private val ws: Token by regexToken("\\s+".toRegex(), ignore = true)
|
||||||
|
|
||||||
private val number: Parser<MST> by num use { MST.Numeric(text.toDouble()) }
|
private val number: Parser<MST> by num use { MST.Numeric(text.toDouble()) }
|
||||||
private val singular: Parser<MST> by id use { MST.Symbolic(text) }
|
private val singular: Parser<MST> by id use { MST.Symbolic(text) }
|
@ -1,11 +1,11 @@
|
|||||||
package kscience.kmath.asm
|
package space.kscience.kmath.asm
|
||||||
|
|
||||||
import kscience.kmath.ast.*
|
import space.kscience.kmath.ast.*
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.complex.ComplexField
|
||||||
import kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.complex.toComplex
|
||||||
import kscience.kmath.operations.ComplexField
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.ByteRing
|
||||||
import kscience.kmath.operations.toComplex
|
import space.kscience.kmath.operations.RealField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
),
|
),
|
||||||
|
|
||||||
number(1)
|
number(1)
|
||||||
) + symbol("x") + zero
|
) + bindSymbol("x") + zero
|
||||||
}("x" to MST.Numeric(2))
|
}("x" to MST.Numeric(2))
|
||||||
|
|
||||||
val res2 = MstSpace.mstInSpace {
|
val res2 = MstSpace.mstInSpace {
|
||||||
@ -35,7 +35,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
),
|
),
|
||||||
|
|
||||||
number(1)
|
number(1)
|
||||||
) + symbol("x") + zero
|
) + bindSymbol("x") + zero
|
||||||
}.compile()("x" to MST.Numeric(2))
|
}.compile()("x" to MST.Numeric(2))
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
assertEquals(res1, res2)
|
||||||
@ -46,7 +46,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
val res1 = ByteRing.mstInRing {
|
val res1 = ByteRing.mstInRing {
|
||||||
binaryOperationFunction("+")(
|
binaryOperationFunction("+")(
|
||||||
unaryOperationFunction("+")(
|
unaryOperationFunction("+")(
|
||||||
(symbol("x") - (2.toByte() + (multiply(
|
(bindSymbol("x") - (2.toByte() + (multiply(
|
||||||
add(number(1), number(1)),
|
add(number(1), number(1)),
|
||||||
2
|
2
|
||||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
) + 1.toByte()))) * 3.0 - 1.toByte()
|
||||||
@ -59,7 +59,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
val res2 = ByteRing.mstInRing {
|
val res2 = ByteRing.mstInRing {
|
||||||
binaryOperationFunction("+")(
|
binaryOperationFunction("+")(
|
||||||
unaryOperationFunction("+")(
|
unaryOperationFunction("+")(
|
||||||
(symbol("x") - (2.toByte() + (multiply(
|
(bindSymbol("x") - (2.toByte() + (multiply(
|
||||||
add(number(1), number(1)),
|
add(number(1), number(1)),
|
||||||
2
|
2
|
||||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
) + 1.toByte()))) * 3.0 - 1.toByte()
|
||||||
@ -75,7 +75,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
fun realField() {
|
fun realField() {
|
||||||
val res1 = RealField.mstInField {
|
val res1 = RealField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
@ -83,7 +83,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
|
|
||||||
val res2 = RealField.mstInField {
|
val res2 = RealField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
@ -96,7 +96,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
fun complexField() {
|
fun complexField() {
|
||||||
val res1 = ComplexField.mstInField {
|
val res1 = ComplexField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
@ -104,7 +104,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
|
|
||||||
val res2 = ComplexField.mstInField {
|
val res2 = ComplexField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
@ -1,10 +1,10 @@
|
|||||||
package kscience.kmath.asm
|
package space.kscience.kmath.asm
|
||||||
|
|
||||||
import kscience.kmath.ast.mstInExtendedField
|
import space.kscience.kmath.ast.mstInExtendedField
|
||||||
import kscience.kmath.ast.mstInField
|
import space.kscience.kmath.ast.mstInField
|
||||||
import kscience.kmath.ast.mstInSpace
|
import space.kscience.kmath.ast.mstInSpace
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.RealField
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -12,27 +12,27 @@ import kotlin.test.assertEquals
|
|||||||
internal class TestAsmOperationsSupport {
|
internal class TestAsmOperationsSupport {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryOperationInvocation() {
|
fun testUnaryOperationInvocation() {
|
||||||
val expression = RealField.mstInSpace { -symbol("x") }.compile()
|
val expression = RealField.mstInSpace { -bindSymbol("x") }.compile()
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-2.0, res)
|
assertEquals(-2.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBinaryOperationInvocation() {
|
fun testBinaryOperationInvocation() {
|
||||||
val expression = RealField.mstInSpace { -symbol("x") + number(1.0) }.compile()
|
val expression = RealField.mstInSpace { -bindSymbol("x") + number(1.0) }.compile()
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-1.0, res)
|
assertEquals(-1.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testConstProductInvocation() {
|
fun testConstProductInvocation() {
|
||||||
val res = RealField.mstInField { symbol("x") * 2 }("x" to 2.0)
|
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
||||||
assertEquals(4.0, res)
|
assertEquals(4.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMultipleCalls() {
|
fun testMultipleCalls() {
|
||||||
val e = RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile()
|
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile()
|
||||||
val r = Random(0)
|
val r = Random(0)
|
||||||
var s = 0.0
|
var s = 0.0
|
||||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
@ -1,52 +1,52 @@
|
|||||||
package kscience.kmath.asm
|
package space.kscience.kmath.asm
|
||||||
|
|
||||||
import kscience.kmath.ast.mstInField
|
import space.kscience.kmath.ast.mstInField
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.RealField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class TestAsmSpecialization {
|
internal class TestAsmSpecialization {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryPlus() {
|
fun testUnaryPlus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("+")(symbol("x")) }.compile()
|
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(2.0, expr("x" to 2.0))
|
assertEquals(2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryMinus() {
|
fun testUnaryMinus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile()
|
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(-2.0, expr("x" to 2.0))
|
assertEquals(-2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAdd() {
|
fun testAdd() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile()
|
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSine() {
|
fun testSine() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile()
|
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(0.0, expr("x" to 0.0))
|
assertEquals(0.0, expr("x" to 0.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMinus() {
|
fun testMinus() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile()
|
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(0.0, expr("x" to 2.0))
|
assertEquals(0.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDivide() {
|
fun testDivide() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile()
|
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(1.0, expr("x" to 2.0))
|
assertEquals(1.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPower() {
|
fun testPower() {
|
||||||
val expr = RealField
|
val expr = RealField
|
||||||
.mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) }
|
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||||
.compile()
|
.compile()
|
||||||
|
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
@ -1,8 +1,8 @@
|
|||||||
package kscience.kmath.asm
|
package space.kscience.kmath.asm
|
||||||
|
|
||||||
import kscience.kmath.ast.mstInRing
|
import space.kscience.kmath.ast.mstInRing
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.operations.ByteRing
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
@ -10,13 +10,13 @@ import kotlin.test.assertFailsWith
|
|||||||
internal class TestAsmVariables {
|
internal class TestAsmVariables {
|
||||||
@Test
|
@Test
|
||||||
fun testVariable() {
|
fun testVariable() {
|
||||||
val expr = ByteRing.mstInRing { symbol("x") }.compile()
|
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||||
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUndefinedVariableFails() {
|
fun testUndefinedVariableFails() {
|
||||||
val expr = ByteRing.mstInRing { symbol("x") }.compile()
|
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||||
assertFailsWith<NoSuchElementException> { expr() }
|
assertFailsWith<NoSuchElementException> { expr() }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import kscience.kmath.operations.Field
|
import space.kscience.kmath.operations.Field
|
||||||
import kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.RealField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
@ -1,10 +1,10 @@
|
|||||||
package kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import kscience.kmath.expressions.invoke
|
import space.kscience.kmath.complex.Complex
|
||||||
import kscience.kmath.operations.Algebra
|
import space.kscience.kmath.complex.ComplexField
|
||||||
import kscience.kmath.operations.Complex
|
import space.kscience.kmath.expressions.invoke
|
||||||
import kscience.kmath.operations.ComplexField
|
import space.kscience.kmath.operations.Algebra
|
||||||
import kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.RealField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ internal class ParserTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `evaluate MST with binary function`() {
|
fun `evaluate MST with binary function`() {
|
||||||
val magicalAlgebra = object : Algebra<String> {
|
val magicalAlgebra = object : Algebra<String> {
|
||||||
override fun symbol(value: String): String = value
|
override fun bindSymbol(value: String): String = value
|
||||||
|
|
||||||
override fun unaryOperationFunction(operation: String): (arg: String) -> String {
|
override fun unaryOperationFunction(operation: String): (arg: String) -> String {
|
||||||
throw NotImplementedError()
|
throw NotImplementedError()
|
@ -1,12 +1,17 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.jvm")
|
id("ru.mipt.npm.gradle.jvm")
|
||||||
}
|
}
|
||||||
description = "Commons math binding for kmath"
|
description = "Commons math binding for kmath"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":kmath-core"))
|
api(project(":kmath-core"))
|
||||||
|
api(project(":kmath-complex"))
|
||||||
api(project(":kmath-coroutines"))
|
api(project(":kmath-coroutines"))
|
||||||
api(project(":kmath-stat"))
|
api(project(":kmath-stat"))
|
||||||
api(project(":kmath-functions"))
|
api(project(":kmath-functions"))
|
||||||
api("org.apache.commons:commons-math3:3.6.1")
|
api("org.apache.commons:commons-math3:3.6.1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readme{
|
||||||
|
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
package kscience.kmath.commons.expressions
|
package space.kscience.kmath.commons.expressions
|
||||||
|
|
||||||
import kscience.kmath.expressions.*
|
|
||||||
import kscience.kmath.misc.UnstableKMathAPI
|
|
||||||
import kscience.kmath.operations.ExtendedField
|
|
||||||
import kscience.kmath.operations.RingWithNumbers
|
|
||||||
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
||||||
|
import space.kscience.kmath.expressions.*
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.operations.ExtendedField
|
||||||
|
import space.kscience.kmath.operations.RingWithNumbers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A field over commons-math [DerivativeStructure].
|
* A field over commons-math [DerivativeStructure].
|
||||||
@ -48,11 +48,11 @@ public class DerivativeStructureField(
|
|||||||
|
|
||||||
override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value)
|
override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value)
|
||||||
|
|
||||||
public override fun bindOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity]
|
public override fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity]
|
||||||
|
|
||||||
public fun bind(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity)
|
public fun bind(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity)
|
||||||
|
|
||||||
override fun symbol(value: String): DerivativeStructureSymbol = bind(StringSymbol(value))
|
override fun bindSymbol(value: String): DerivativeStructureSymbol = bind(StringSymbol(value))
|
||||||
|
|
||||||
public fun DerivativeStructure.derivative(symbols: List<Symbol>): Double {
|
public fun DerivativeStructure.derivative(symbols: List<Symbol>): Double {
|
||||||
require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" }
|
require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" }
|
@ -1,12 +1,9 @@
|
|||||||
package kscience.kmath.commons.linear
|
package space.kscience.kmath.commons.linear
|
||||||
|
|
||||||
import kscience.kmath.linear.DiagonalFeature
|
|
||||||
import kscience.kmath.linear.MatrixContext
|
|
||||||
import kscience.kmath.linear.Point
|
|
||||||
import kscience.kmath.linear.origin
|
|
||||||
import kscience.kmath.misc.UnstableKMathAPI
|
|
||||||
import kscience.kmath.structures.Matrix
|
|
||||||
import org.apache.commons.math3.linear.*
|
import org.apache.commons.math3.linear.*
|
||||||
|
import space.kscience.kmath.linear.*
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.structures.RealBuffer
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.cast
|
import kotlin.reflect.cast
|
||||||
|
|
||||||
@ -17,8 +14,40 @@ public inline class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
|
|||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
override fun <T : Any> getFeature(type: KClass<T>): T? = when (type) {
|
override fun <T : Any> getFeature(type: KClass<T>): T? = when (type) {
|
||||||
DiagonalFeature::class -> if (origin is DiagonalMatrix) DiagonalFeature else null
|
DiagonalFeature::class -> if (origin is DiagonalMatrix) DiagonalFeature else null
|
||||||
|
|
||||||
|
DeterminantFeature::class, LupDecompositionFeature::class -> object :
|
||||||
|
DeterminantFeature<Double>,
|
||||||
|
LupDecompositionFeature<Double> {
|
||||||
|
private val lup by lazy { LUDecomposition(origin) }
|
||||||
|
override val determinant: Double by lazy { lup.determinant }
|
||||||
|
override val l: Matrix<Double> by lazy { CMMatrix(lup.l) + LFeature }
|
||||||
|
override val u: Matrix<Double> by lazy { CMMatrix(lup.u) + UFeature }
|
||||||
|
override val p: Matrix<Double> by lazy { CMMatrix(lup.p) }
|
||||||
|
}
|
||||||
|
|
||||||
|
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
|
||||||
|
override val l: Matrix<Double> by lazy {
|
||||||
|
val cholesky = CholeskyDecomposition(origin)
|
||||||
|
CMMatrix(cholesky.l) + LFeature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> {
|
||||||
|
private val qr by lazy { QRDecomposition(origin) }
|
||||||
|
override val q: Matrix<Double> by lazy { CMMatrix(qr.q) + OrthogonalFeature }
|
||||||
|
override val r: Matrix<Double> by lazy { CMMatrix(qr.r) + UFeature }
|
||||||
|
}
|
||||||
|
|
||||||
|
SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Double> {
|
||||||
|
private val sv by lazy { SingularValueDecomposition(origin) }
|
||||||
|
override val u: Matrix<Double> by lazy { CMMatrix(sv.u) }
|
||||||
|
override val s: Matrix<Double> by lazy { CMMatrix(sv.s) }
|
||||||
|
override val v: Matrix<Double> by lazy { CMMatrix(sv.v) }
|
||||||
|
override val singularValues: Point<Double> by lazy { RealBuffer(sv.singularValues) }
|
||||||
|
}
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
}?.let { type.cast(it) }
|
}?.let(type::cast)
|
||||||
|
|
||||||
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
|
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package kscience.kmath.commons.linear
|
package space.kscience.kmath.commons.linear
|
||||||
|
|
||||||
import kscience.kmath.linear.Point
|
|
||||||
import kscience.kmath.structures.Matrix
|
|
||||||
import org.apache.commons.math3.linear.*
|
import org.apache.commons.math3.linear.*
|
||||||
|
import space.kscience.kmath.linear.Matrix
|
||||||
|
import space.kscience.kmath.linear.Point
|
||||||
|
|
||||||
public enum class CMDecomposition {
|
public enum class CMDecomposition {
|
||||||
LUP,
|
LUP,
|
@ -1,10 +1,5 @@
|
|||||||
package kscience.kmath.commons.optimization
|
package space.kscience.kmath.commons.optimization
|
||||||
|
|
||||||
import kscience.kmath.expressions.*
|
|
||||||
import kscience.kmath.stat.OptimizationFeature
|
|
||||||
import kscience.kmath.stat.OptimizationProblem
|
|
||||||
import kscience.kmath.stat.OptimizationProblemFactory
|
|
||||||
import kscience.kmath.stat.OptimizationResult
|
|
||||||
import org.apache.commons.math3.optim.*
|
import org.apache.commons.math3.optim.*
|
||||||
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType
|
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType
|
||||||
import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer
|
import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer
|
||||||
@ -14,6 +9,11 @@ import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjuga
|
|||||||
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex
|
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex
|
||||||
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex
|
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex
|
||||||
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
|
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
|
||||||
|
import space.kscience.kmath.expressions.*
|
||||||
|
import space.kscience.kmath.stat.OptimizationFeature
|
||||||
|
import space.kscience.kmath.stat.OptimizationProblem
|
||||||
|
import space.kscience.kmath.stat.OptimizationProblemFactory
|
||||||
|
import space.kscience.kmath.stat.OptimizationResult
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
public operator fun PointValuePair.component1(): DoubleArray = point
|
public operator fun PointValuePair.component1(): DoubleArray = point
|
@ -1,16 +1,16 @@
|
|||||||
package kscience.kmath.commons.optimization
|
package space.kscience.kmath.commons.optimization
|
||||||
|
|
||||||
import kscience.kmath.commons.expressions.DerivativeStructureField
|
|
||||||
import kscience.kmath.expressions.DifferentiableExpression
|
|
||||||
import kscience.kmath.expressions.Expression
|
|
||||||
import kscience.kmath.expressions.Symbol
|
|
||||||
import kscience.kmath.stat.Fitting
|
|
||||||
import kscience.kmath.stat.OptimizationResult
|
|
||||||
import kscience.kmath.stat.optimizeWith
|
|
||||||
import kscience.kmath.structures.Buffer
|
|
||||||
import kscience.kmath.structures.asBuffer
|
|
||||||
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
||||||
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType
|
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType
|
||||||
|
import space.kscience.kmath.commons.expressions.DerivativeStructureField
|
||||||
|
import space.kscience.kmath.expressions.DifferentiableExpression
|
||||||
|
import space.kscience.kmath.expressions.Expression
|
||||||
|
import space.kscience.kmath.expressions.Symbol
|
||||||
|
import space.kscience.kmath.stat.Fitting
|
||||||
|
import space.kscience.kmath.stat.OptimizationResult
|
||||||
|
import space.kscience.kmath.stat.optimizeWith
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.asBuffer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
|
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
|
@ -1,6 +1,6 @@
|
|||||||
package kscience.kmath.commons.random
|
package space.kscience.kmath.commons.random
|
||||||
|
|
||||||
import kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
|
|
||||||
public class CMRandomGeneratorWrapper(
|
public class CMRandomGeneratorWrapper(
|
||||||
public val factory: (IntArray) -> RandomGenerator,
|
public val factory: (IntArray) -> RandomGenerator,
|
@ -1,13 +1,13 @@
|
|||||||
package kscience.kmath.commons.transform
|
package space.kscience.kmath.commons.transform
|
||||||
|
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kscience.kmath.operations.Complex
|
|
||||||
import kscience.kmath.streaming.chunked
|
|
||||||
import kscience.kmath.streaming.spread
|
|
||||||
import kscience.kmath.structures.*
|
|
||||||
import org.apache.commons.math3.transform.*
|
import org.apache.commons.math3.transform.*
|
||||||
|
import space.kscience.kmath.complex.Complex
|
||||||
|
import space.kscience.kmath.streaming.chunked
|
||||||
|
import space.kscience.kmath.streaming.spread
|
||||||
|
import space.kscience.kmath.structures.*
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
@ -1,6 +1,6 @@
|
|||||||
package kscience.kmath.commons.expressions
|
package space.kscience.kmath.commons.expressions
|
||||||
|
|
||||||
import kscience.kmath.expressions.*
|
import space.kscience.kmath.expressions.*
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@ -24,7 +24,7 @@ internal class AutoDiffTest {
|
|||||||
fun derivativeStructureFieldTest() {
|
fun derivativeStructureFieldTest() {
|
||||||
diff(2, x to 1.0, y to 1.0) {
|
diff(2, x to 1.0, y to 1.0) {
|
||||||
val x = bind(x)//by binding()
|
val x = bind(x)//by binding()
|
||||||
val y = symbol("y")
|
val y = bindSymbol("y")
|
||||||
val z = x * (-sin(x * y) + y) + 2.0
|
val z = x * (-sin(x * y) + y) + 2.0
|
||||||
println(z.derivative(x))
|
println(z.derivative(x))
|
||||||
println(z.derivative(y,x))
|
println(z.derivative(y,x))
|
@ -1,12 +1,12 @@
|
|||||||
package kscience.kmath.commons.optimization
|
package space.kscience.kmath.commons.optimization
|
||||||
|
|
||||||
import kscience.kmath.commons.expressions.DerivativeStructureExpression
|
|
||||||
import kscience.kmath.expressions.symbol
|
|
||||||
import kscience.kmath.stat.Distribution
|
|
||||||
import kscience.kmath.stat.Fitting
|
|
||||||
import kscience.kmath.stat.RandomGenerator
|
|
||||||
import kscience.kmath.stat.normal
|
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import space.kscience.kmath.commons.expressions.DerivativeStructureExpression
|
||||||
|
import space.kscience.kmath.expressions.symbol
|
||||||
|
import space.kscience.kmath.stat.Distribution
|
||||||
|
import space.kscience.kmath.stat.Fitting
|
||||||
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
|
import space.kscience.kmath.stat.normal
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
internal class OptimizeTest {
|
internal class OptimizeTest {
|
||||||
@ -56,7 +56,7 @@ internal class OptimizeTest {
|
|||||||
val yErr = List(x.size) { sigma }
|
val yErr = List(x.size) { sigma }
|
||||||
|
|
||||||
val chi2 = Fitting.chiSquared(x, y, yErr) { x1 ->
|
val chi2 = Fitting.chiSquared(x, y, yErr) { x1 ->
|
||||||
val cWithDefault = bindOrNull(c) ?: one
|
val cWithDefault = bindSymbolOrNull(c) ?: one
|
||||||
bind(a) * x1.pow(2) + bind(b) * x1 + cWithDefault
|
bind(a) * x1.pow(2) + bind(b) * x1 + cWithDefault
|
||||||
}
|
}
|
||||||
|
|
48
kmath-complex/README.md
Normal file
48
kmath-complex/README.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# The Core Module (`kmath-core`)
|
||||||
|
|
||||||
|
Complex and hypercomplex number systems in KMath:
|
||||||
|
|
||||||
|
- [complex](src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||||
|
- [quaternion](src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||||
|
|
||||||
|
|
||||||
|
> #### Artifact:
|
||||||
|
>
|
||||||
|
> This module artifact: `space.kscience:kmath-complex:0.2.0`.
|
||||||
|
>
|
||||||
|
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-complex/_latestVersion)
|
||||||
|
>
|
||||||
|
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-complex/_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-complex: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-complex:0.2.0")
|
||||||
|
> }
|
||||||
|
> ```
|
36
kmath-complex/build.gradle.kts
Normal file
36
kmath-complex/build.gradle.kts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import ru.mipt.npm.gradle.Maturity
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("ru.mipt.npm.gradle.mpp")
|
||||||
|
id("ru.mipt.npm.gradle.native")
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin.sourceSets {
|
||||||
|
all {
|
||||||
|
languageSettings.useExperimentalAnnotation("kscience.kmath.misc.UnstableKMathAPI")
|
||||||
|
}
|
||||||
|
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api(project(":kmath-core"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readme {
|
||||||
|
description = "Complex numbers and quaternions."
|
||||||
|
maturity = Maturity.PROTOTYPE
|
||||||
|
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
|
||||||
|
|
||||||
|
feature(
|
||||||
|
id = "complex",
|
||||||
|
description = "Complex Numbers",
|
||||||
|
ref = "src/commonMain/kotlin/kscience/kmath/complex/Complex.kt"
|
||||||
|
)
|
||||||
|
|
||||||
|
feature(
|
||||||
|
id = "quaternion",
|
||||||
|
description = "Quaternions",
|
||||||
|
ref = "src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt"
|
||||||
|
)
|
||||||
|
}
|
7
kmath-complex/docs/README-TEMPLATE.md
Normal file
7
kmath-complex/docs/README-TEMPLATE.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# The Core Module (`kmath-core`)
|
||||||
|
|
||||||
|
Complex and hypercomplex number systems in KMath:
|
||||||
|
|
||||||
|
${features}
|
||||||
|
|
||||||
|
${artifact}
|
@ -1,13 +1,17 @@
|
|||||||
package kscience.kmath.operations
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
import kscience.kmath.memory.MemoryReader
|
import space.kscience.kmath.memory.MemoryReader
|
||||||
import kscience.kmath.memory.MemorySpec
|
import space.kscience.kmath.memory.MemorySpec
|
||||||
import kscience.kmath.memory.MemoryWriter
|
import space.kscience.kmath.memory.MemoryWriter
|
||||||
import kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import kscience.kmath.structures.Buffer
|
import space.kscience.kmath.operations.ExtendedField
|
||||||
import kscience.kmath.structures.MemoryBuffer
|
import space.kscience.kmath.operations.FieldElement
|
||||||
import kscience.kmath.structures.MutableBuffer
|
import space.kscience.kmath.operations.Norm
|
||||||
import kscience.kmath.structures.MutableMemoryBuffer
|
import space.kscience.kmath.operations.RingWithNumbers
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.MemoryBuffer
|
||||||
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
|
import space.kscience.kmath.structures.MutableMemoryBuffer
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,72 +48,69 @@ private val PI_DIV_2 = Complex(PI / 2, 0)
|
|||||||
*/
|
*/
|
||||||
@OptIn(UnstableKMathAPI::class)
|
@OptIn(UnstableKMathAPI::class)
|
||||||
public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, RingWithNumbers<Complex> {
|
public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, RingWithNumbers<Complex> {
|
||||||
override val zero: Complex = 0.0.toComplex()
|
public override val zero: Complex = 0.0.toComplex()
|
||||||
override val one: Complex = 1.0.toComplex()
|
public override val one: Complex = 1.0.toComplex()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The imaginary unit.
|
* The imaginary unit.
|
||||||
*/
|
*/
|
||||||
public val i: Complex = Complex(0.0, 1.0)
|
public val i: Complex by lazy { Complex(0.0, 1.0) }
|
||||||
|
|
||||||
override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im)
|
public override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im)
|
||||||
|
public override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble())
|
||||||
|
|
||||||
override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble())
|
public override fun multiply(a: Complex, b: Complex): Complex =
|
||||||
|
|
||||||
override fun multiply(a: Complex, b: Complex): Complex =
|
|
||||||
Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re)
|
Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re)
|
||||||
|
|
||||||
override fun divide(a: Complex, b: Complex): Complex = when {
|
public override fun divide(a: Complex, b: Complex): Complex = when {
|
||||||
b.re.isNaN() || b.im.isNaN() -> Complex(Double.NaN, Double.NaN)
|
abs(b.im) < abs(b.re) -> {
|
||||||
|
|
||||||
(if (b.im < 0) -b.im else +b.im) < (if (b.re < 0) -b.re else +b.re) -> {
|
|
||||||
val wr = b.im / b.re
|
val wr = b.im / b.re
|
||||||
val wd = b.re + wr * b.im
|
val wd = b.re + wr * b.im
|
||||||
|
|
||||||
if (wd.isNaN() || wd == 0.0)
|
if (wd.isNaN() || wd == 0.0)
|
||||||
Complex(Double.NaN, Double.NaN)
|
throw ArithmeticException("Division by zero or infinity")
|
||||||
else
|
else
|
||||||
Complex((a.re + a.im * wr) / wd, (a.im - a.re * wr) / wd)
|
Complex((a.re + a.im * wr) / wd, (a.im - a.re * wr) / wd)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.im == 0.0 -> Complex(Double.NaN, Double.NaN)
|
b.im == 0.0 -> throw ArithmeticException("Division by zero")
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val wr = b.re / b.im
|
val wr = b.re / b.im
|
||||||
val wd = b.im + wr * b.re
|
val wd = b.im + wr * b.re
|
||||||
|
|
||||||
if (wd.isNaN() || wd == 0.0)
|
if (wd.isNaN() || wd == 0.0)
|
||||||
Complex(Double.NaN, Double.NaN)
|
throw ArithmeticException("Division by zero or infinity")
|
||||||
else
|
else
|
||||||
Complex((a.re * wr + a.im) / wd, (a.im * wr - a.re) / wd)
|
Complex((a.re * wr + a.im) / wd, (a.im * wr - a.re) / wd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2
|
public override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2
|
||||||
override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2
|
public override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2
|
||||||
|
|
||||||
override fun tan(arg: Complex): Complex {
|
public override fun tan(arg: Complex): Complex {
|
||||||
val e1 = exp(-i * arg)
|
val e1 = exp(-i * arg)
|
||||||
val e2 = exp(i * arg)
|
val e2 = exp(i * arg)
|
||||||
return i * (e1 - e2) / (e1 + e2)
|
return i * (e1 - e2) / (e1 + e2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg)
|
public override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg)
|
||||||
override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg)
|
public override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg)
|
||||||
|
|
||||||
override fun atan(arg: Complex): Complex {
|
public override fun atan(arg: Complex): Complex {
|
||||||
val iArg = i * arg
|
val iArg = i * arg
|
||||||
return i * (ln(1 - iArg) - ln(1 + iArg)) / 2
|
return i * (ln(1 - iArg) - ln(1 + iArg)) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0)
|
public override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0)
|
||||||
arg.re.pow(pow.toDouble()).toComplex()
|
arg.re.pow(pow.toDouble()).toComplex()
|
||||||
else
|
else
|
||||||
exp(pow * ln(arg))
|
exp(pow * ln(arg))
|
||||||
|
|
||||||
override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im))
|
public override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im))
|
||||||
|
|
||||||
override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re)
|
public override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds complex number to real one.
|
* Adds complex number to real one.
|
||||||
@ -156,9 +157,9 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Rin
|
|||||||
*/
|
*/
|
||||||
public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this)
|
public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this)
|
||||||
|
|
||||||
override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
|
public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
|
||||||
|
|
||||||
override fun symbol(value: String): Complex = if (value == "i") i else super<ExtendedField>.symbol(value)
|
public override fun bindSymbol(value: String): Complex = if (value == "i") i else super<ExtendedField>.bindSymbol(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,30 +168,22 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Rin
|
|||||||
* @property re The real part.
|
* @property re The real part.
|
||||||
* @property im The imaginary part.
|
* @property im The imaginary part.
|
||||||
*/
|
*/
|
||||||
public data class Complex(val re: Double, val im: Double) : FieldElement<Complex, Complex, ComplexField>,
|
@OptIn(UnstableKMathAPI::class)
|
||||||
Comparable<Complex> {
|
public data class Complex(val re: Double, val im: Double) : FieldElement<Complex, ComplexField> {
|
||||||
public constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble())
|
public constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble())
|
||||||
|
public constructor(re: Number) : this(re.toDouble(), 0.0)
|
||||||
|
|
||||||
override val context: ComplexField get() = ComplexField
|
public override val context: ComplexField get() = ComplexField
|
||||||
|
|
||||||
override fun unwrap(): Complex = this
|
|
||||||
|
|
||||||
override fun Complex.wrap(): Complex = this
|
|
||||||
|
|
||||||
override fun compareTo(other: Complex): Int = r.compareTo(other.r)
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "($re + i*$im)"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public override fun toString(): String = "($re + i*$im)"
|
||||||
|
|
||||||
public companion object : MemorySpec<Complex> {
|
public companion object : MemorySpec<Complex> {
|
||||||
override val objectSize: Int
|
public override val objectSize: Int
|
||||||
get() = 16
|
get() = 16
|
||||||
|
|
||||||
override fun MemoryReader.read(offset: Int): Complex = Complex(readDouble(offset), readDouble(offset + 8))
|
public override fun MemoryReader.read(offset: Int): Complex = Complex(readDouble(offset), readDouble(offset + 8))
|
||||||
|
|
||||||
override fun MemoryWriter.write(offset: Int, value: Complex) {
|
public override fun MemoryWriter.write(offset: Int, value: Complex) {
|
||||||
writeDouble(offset, value.re)
|
writeDouble(offset, value.re)
|
||||||
writeDouble(offset + 8, value.im)
|
writeDouble(offset + 8, value.im)
|
||||||
}
|
}
|
||||||
@ -204,7 +197,7 @@ public data class Complex(val re: Double, val im: Double) : FieldElement<Complex
|
|||||||
* @receiver the real part.
|
* @receiver the real part.
|
||||||
* @return the new complex number.
|
* @return the new complex number.
|
||||||
*/
|
*/
|
||||||
public fun Number.toComplex(): Complex = Complex(this, 0.0)
|
public fun Number.toComplex(): Complex = Complex(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new buffer of complex numbers with the specified [size], where each element is calculated by calling the
|
* Creates a new buffer of complex numbers with the specified [size], where each element is calculated by calling the
|
@ -0,0 +1,118 @@
|
|||||||
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.nd.BufferedNDField
|
||||||
|
import space.kscience.kmath.nd.NDAlgebra
|
||||||
|
import space.kscience.kmath.nd.NDBuffer
|
||||||
|
import space.kscience.kmath.nd.NDStructure
|
||||||
|
import space.kscience.kmath.operations.ExtendedField
|
||||||
|
import space.kscience.kmath.operations.RingWithNumbers
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optimized nd-field for complex numbers
|
||||||
|
*/
|
||||||
|
@OptIn(UnstableKMathAPI::class)
|
||||||
|
public class ComplexNDField(
|
||||||
|
shape: IntArray,
|
||||||
|
) : BufferedNDField<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
|
||||||
|
RingWithNumbers<NDStructure<Complex>>,
|
||||||
|
ExtendedField<NDStructure<Complex>> {
|
||||||
|
|
||||||
|
override val zero: NDBuffer<Complex> by lazy { produce { zero } }
|
||||||
|
override val one: NDBuffer<Complex> by lazy { produce { one } }
|
||||||
|
|
||||||
|
override fun number(value: Number): NDBuffer<Complex> {
|
||||||
|
val d = value.toComplex() // minimize conversions
|
||||||
|
return produce { d }
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
// override inline fun map(
|
||||||
|
// arg: AbstractNDBuffer<Double>,
|
||||||
|
// transform: RealField.(Double) -> Double,
|
||||||
|
// ): RealNDElement {
|
||||||
|
// check(arg)
|
||||||
|
// val array = RealBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) }
|
||||||
|
// return BufferedNDFieldElement(this, array)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
// override inline fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement {
|
||||||
|
// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
||||||
|
// return BufferedNDFieldElement(this, array)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
// override inline fun mapIndexed(
|
||||||
|
// arg: AbstractNDBuffer<Double>,
|
||||||
|
// transform: RealField.(index: IntArray, Double) -> Double,
|
||||||
|
// ): RealNDElement {
|
||||||
|
// check(arg)
|
||||||
|
// return BufferedNDFieldElement(
|
||||||
|
// this,
|
||||||
|
// RealBuffer(arg.strides.linearSize) { offset ->
|
||||||
|
// elementContext.transform(
|
||||||
|
// arg.strides.index(offset),
|
||||||
|
// arg.buffer[offset]
|
||||||
|
// )
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
// override inline fun combine(
|
||||||
|
// a: AbstractNDBuffer<Double>,
|
||||||
|
// b: AbstractNDBuffer<Double>,
|
||||||
|
// transform: RealField.(Double, Double) -> Double,
|
||||||
|
// ): RealNDElement {
|
||||||
|
// check(a, b)
|
||||||
|
// val buffer = RealBuffer(strides.linearSize) { offset ->
|
||||||
|
// elementContext.transform(a.buffer[offset], b.buffer[offset])
|
||||||
|
// }
|
||||||
|
// return BufferedNDFieldElement(this, buffer)
|
||||||
|
// }
|
||||||
|
|
||||||
|
override fun power(arg: NDStructure<Complex>, pow: Number): NDBuffer<Complex> = arg.map() { power(it, pow) }
|
||||||
|
|
||||||
|
override fun exp(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { exp(it) }
|
||||||
|
|
||||||
|
override fun ln(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { ln(it) }
|
||||||
|
|
||||||
|
override fun sin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { sin(it) }
|
||||||
|
override fun cos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { cos(it) }
|
||||||
|
override fun tan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { tan(it) }
|
||||||
|
override fun asin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { asin(it) }
|
||||||
|
override fun acos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { acos(it) }
|
||||||
|
override fun atan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { atan(it) }
|
||||||
|
|
||||||
|
override fun sinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { sinh(it) }
|
||||||
|
override fun cosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { cosh(it) }
|
||||||
|
override fun tanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { tanh(it) }
|
||||||
|
override fun asinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { asinh(it) }
|
||||||
|
override fun acosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { acosh(it) }
|
||||||
|
override fun atanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { atanh(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fast element production using function inlining
|
||||||
|
*/
|
||||||
|
public inline fun BufferedNDField<Complex, ComplexField>.produceInline(initializer: ComplexField.(Int) -> Complex): NDBuffer<Complex> {
|
||||||
|
contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) }
|
||||||
|
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) }
|
||||||
|
return NDBuffer(strides, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public fun NDAlgebra.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce a context for n-dimensional operations inside this real field
|
||||||
|
*/
|
||||||
|
public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R {
|
||||||
|
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||||
|
return ComplexNDField(shape).action()
|
||||||
|
}
|
@ -0,0 +1,263 @@
|
|||||||
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
|
import space.kscience.kmath.memory.MemoryReader
|
||||||
|
import space.kscience.kmath.memory.MemorySpec
|
||||||
|
import space.kscience.kmath.memory.MemoryWriter
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.operations.*
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.MemoryBuffer
|
||||||
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
|
import space.kscience.kmath.structures.MutableMemoryBuffer
|
||||||
|
import kotlin.math.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This quaternion's conjugate.
|
||||||
|
*/
|
||||||
|
public val Quaternion.conjugate: Quaternion
|
||||||
|
get() = QuaternionField { z - x * i - y * j - z * k }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This quaternion's reciprocal.
|
||||||
|
*/
|
||||||
|
public val Quaternion.reciprocal: Quaternion
|
||||||
|
get() {
|
||||||
|
val n = QuaternionField { norm(this@reciprocal) }
|
||||||
|
return conjugate / (n * n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Absolute value of the quaternion.
|
||||||
|
*/
|
||||||
|
public val Quaternion.r: Double
|
||||||
|
get() = sqrt(w * w + x * x + y * y + z * z)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A field of [Quaternion].
|
||||||
|
*/
|
||||||
|
@OptIn(UnstableKMathAPI::class)
|
||||||
|
public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Quaternion>, PowerOperations<Quaternion>,
|
||||||
|
ExponentialOperations<Quaternion>, RingWithNumbers<Quaternion> {
|
||||||
|
override val zero: Quaternion = 0.toQuaternion()
|
||||||
|
override val one: Quaternion = 1.toQuaternion()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `i` quaternion unit.
|
||||||
|
*/
|
||||||
|
public val i: Quaternion = Quaternion(0, 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `j` quaternion unit.
|
||||||
|
*/
|
||||||
|
public val j: Quaternion = Quaternion(0, 0, 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `k` quaternion unit.
|
||||||
|
*/
|
||||||
|
public val k: Quaternion = Quaternion(0, 0, 0, 1)
|
||||||
|
|
||||||
|
public override fun add(a: Quaternion, b: Quaternion): Quaternion =
|
||||||
|
Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z)
|
||||||
|
|
||||||
|
public override fun multiply(a: Quaternion, k: Number): Quaternion {
|
||||||
|
val d = k.toDouble()
|
||||||
|
return Quaternion(a.w * d, a.x * d, a.y * d, a.z * d)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion(
|
||||||
|
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
|
||||||
|
a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
||||||
|
a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
||||||
|
a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
|
||||||
|
)
|
||||||
|
|
||||||
|
public override fun divide(a: Quaternion, b: Quaternion): Quaternion {
|
||||||
|
val s = b.w * b.w + b.x * b.x + b.y * b.y + b.z * b.z
|
||||||
|
|
||||||
|
return Quaternion(
|
||||||
|
(b.w * a.w + b.x * a.x + b.y * a.y + b.z * a.z) / s,
|
||||||
|
(b.w * a.x - b.x * a.w - b.y * a.z + b.z * a.y) / s,
|
||||||
|
(b.w * a.y + b.x * a.z - b.y * a.w - b.z * a.x) / s,
|
||||||
|
(b.w * a.z - b.x * a.y + b.y * a.x - b.z * a.w) / s,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun power(arg: Quaternion, pow: Number): Quaternion {
|
||||||
|
if (pow is Int) return pwr(arg, pow)
|
||||||
|
if (floor(pow.toDouble()) == pow.toDouble()) return pwr(arg, pow.toInt())
|
||||||
|
return exp(pow * ln(arg))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pwr(x: Quaternion, a: Int): Quaternion = when {
|
||||||
|
a < 0 -> -(pwr(x, -a))
|
||||||
|
a == 0 -> one
|
||||||
|
a == 1 -> x
|
||||||
|
a == 2 -> pwr2(x)
|
||||||
|
a == 3 -> pwr3(x)
|
||||||
|
a == 4 -> pwr4(x)
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val x4 = pwr4(x)
|
||||||
|
var y = x4
|
||||||
|
repeat((1 until a / 4).count()) { y *= x4 }
|
||||||
|
if (a % 4 == 3) y *= pwr3(x)
|
||||||
|
if (a % 4 == 2) y *= pwr2(x)
|
||||||
|
if (a % 4 == 1) y *= x
|
||||||
|
y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pwr2(x: Quaternion): Quaternion {
|
||||||
|
val aa = 2 * x.w
|
||||||
|
return Quaternion(x.w * x.w - (x.x * x.x + x.y * x.y + x.z * x.z), aa * x.x, aa * x.y, aa * x.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pwr3(x: Quaternion): Quaternion {
|
||||||
|
val a2 = x.w * x.w
|
||||||
|
val n1 = x.x * x.x + x.y * x.y + x.z * x.z
|
||||||
|
val n2 = 3.0 * a2 - n1
|
||||||
|
return Quaternion(x.w * (a2 - 3 * n1), x.x * n2, x.y * n2, x.z * n2)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pwr4(x: Quaternion): Quaternion {
|
||||||
|
val a2 = x.w * x.w
|
||||||
|
val n1 = x.x * x.x + x.y * x.y + x.z * x.z
|
||||||
|
val n2 = 4 * x.w * (a2 - n1)
|
||||||
|
return Quaternion(a2 * a2 - 6 * a2 * n1 + n1 * n1, x.x * n2, x.y * n2, x.z * n2)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun exp(arg: Quaternion): Quaternion {
|
||||||
|
val un = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z
|
||||||
|
if (un == 0.0) return exp(arg.w).toQuaternion()
|
||||||
|
val n1 = sqrt(un)
|
||||||
|
val ea = exp(arg.w)
|
||||||
|
val n2 = ea * sin(n1) / n1
|
||||||
|
return Quaternion(ea * cos(n1), n2 * arg.x, n2 * arg.y, n2 * arg.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun ln(arg: Quaternion): Quaternion {
|
||||||
|
val nu2 = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z
|
||||||
|
|
||||||
|
if (nu2 == 0.0)
|
||||||
|
return if (arg.w > 0)
|
||||||
|
Quaternion(ln(arg.w), 0, 0, 0)
|
||||||
|
else {
|
||||||
|
val l = ComplexField { ComplexField.ln(arg.w.toComplex()) }
|
||||||
|
Quaternion(l.re, l.im, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val a = arg.w
|
||||||
|
check(nu2 > 0)
|
||||||
|
val n = sqrt(a * a + nu2)
|
||||||
|
val th = acos(a / n) / sqrt(nu2)
|
||||||
|
return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z)
|
||||||
|
|
||||||
|
public override operator fun Number.minus(b: Quaternion): Quaternion =
|
||||||
|
Quaternion(toDouble() - b.w, -b.x, -b.y, -b.z)
|
||||||
|
|
||||||
|
public override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z)
|
||||||
|
public override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.toDouble(), x, y, z)
|
||||||
|
|
||||||
|
public override operator fun Number.times(b: Quaternion): Quaternion =
|
||||||
|
Quaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z)
|
||||||
|
|
||||||
|
public override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z)
|
||||||
|
public override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg)
|
||||||
|
|
||||||
|
public override fun bindSymbol(value: String): Quaternion = when (value) {
|
||||||
|
"i" -> i
|
||||||
|
"j" -> j
|
||||||
|
"k" -> k
|
||||||
|
else -> super<Field>.bindSymbol(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents `double`-based quaternion.
|
||||||
|
*
|
||||||
|
* @property w The first component.
|
||||||
|
* @property x The second component.
|
||||||
|
* @property y The third component.
|
||||||
|
* @property z The fourth component.
|
||||||
|
*/
|
||||||
|
@OptIn(UnstableKMathAPI::class)
|
||||||
|
public data class Quaternion(
|
||||||
|
val w: Double, val x: Double, val y: Double, val z: Double,
|
||||||
|
) : FieldElement<Quaternion, QuaternionField> {
|
||||||
|
public constructor(w: Number, x: Number, y: Number, z: Number) : this(
|
||||||
|
w.toDouble(),
|
||||||
|
x.toDouble(),
|
||||||
|
y.toDouble(),
|
||||||
|
z.toDouble(),
|
||||||
|
)
|
||||||
|
|
||||||
|
public constructor(w: Number, x: Number, y: Number) : this(w.toDouble(), x.toDouble(), y.toDouble(), 0.0)
|
||||||
|
public constructor(w: Number, x: Number) : this(w.toDouble(), x.toDouble(), 0.0, 0.0)
|
||||||
|
public constructor(w: Number) : this(w.toDouble(), 0.0, 0.0, 0.0)
|
||||||
|
public constructor(wx: Complex, yz: Complex) : this(wx.re, wx.im, yz.re, yz.im)
|
||||||
|
public constructor(wx: Complex) : this(wx.re, wx.im, 0, 0)
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(!w.isNaN()) { "w-component of quaternion is not-a-number" }
|
||||||
|
require(!x.isNaN()) { "x-component of quaternion is not-a-number" }
|
||||||
|
require(!y.isNaN()) { "x-component of quaternion is not-a-number" }
|
||||||
|
require(!z.isNaN()) { "x-component of quaternion is not-a-number" }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override val context: QuaternionField
|
||||||
|
get() = QuaternionField
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of this quaternion.
|
||||||
|
*/
|
||||||
|
public override fun toString(): String = "($w + $x * i + $y * j + $z * k)"
|
||||||
|
|
||||||
|
public companion object : MemorySpec<Quaternion> {
|
||||||
|
public override val objectSize: Int
|
||||||
|
get() = 32
|
||||||
|
|
||||||
|
public override fun MemoryReader.read(offset: Int): Quaternion =
|
||||||
|
Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24))
|
||||||
|
|
||||||
|
public override fun MemoryWriter.write(offset: Int, value: Quaternion) {
|
||||||
|
writeDouble(offset, value.w)
|
||||||
|
writeDouble(offset + 8, value.x)
|
||||||
|
writeDouble(offset + 16, value.y)
|
||||||
|
writeDouble(offset + 24, value.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a quaternion with real part equal to this real.
|
||||||
|
*
|
||||||
|
* @receiver the real part.
|
||||||
|
* @return a new quaternion.
|
||||||
|
*/
|
||||||
|
public fun Number.toQuaternion(): Quaternion = Quaternion(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a quaternion with `w`-component equal to `re`-component of given complex and `x`-component equal to
|
||||||
|
* `im`-component of given complex.
|
||||||
|
*
|
||||||
|
* @receiver the complex number.
|
||||||
|
* @return a new quaternion.
|
||||||
|
*/
|
||||||
|
public fun Complex.toQuaternion(): Quaternion = Quaternion(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the
|
||||||
|
* specified [init] function.
|
||||||
|
*/
|
||||||
|
public inline fun Buffer.Companion.quaternion(size: Int, init: (Int) -> Quaternion): Buffer<Quaternion> =
|
||||||
|
MemoryBuffer.create(Quaternion, size, init)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the
|
||||||
|
* specified [init] function.
|
||||||
|
*/
|
||||||
|
public inline fun MutableBuffer.Companion.quaternion(size: Int, init: (Int) -> Quaternion): MutableBuffer<Quaternion> =
|
||||||
|
MutableMemoryBuffer.create(Quaternion, size, init)
|
@ -1,7 +1,6 @@
|
|||||||
package kscience.kmath.structures
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
import kscience.kmath.operations.Complex
|
import space.kscience.kmath.structures.Buffer
|
||||||
import kscience.kmath.operations.complex
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -11,4 +10,4 @@ class ComplexBufferSpecTest {
|
|||||||
val buffer = Buffer.complex(20) { Complex(it.toDouble(), -it.toDouble()) }
|
val buffer = Buffer.complex(20) { Complex(it.toDouble(), -it.toDouble()) }
|
||||||
assertEquals(Complex(5.0, -5.0), buffer[5])
|
assertEquals(Complex(5.0, -5.0), buffer[5])
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package kscience.kmath.operations
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
import kscience.kmath.operations.internal.FieldVerifier
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@ -8,8 +8,9 @@ import kotlin.test.assertEquals
|
|||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
internal class ComplexFieldTest {
|
internal class ComplexFieldTest {
|
||||||
@Test
|
// TODO make verifier classes available in this source set
|
||||||
fun verify() = ComplexField { FieldVerifier(this, 42.0 * i, 66.0 + 28 * i, 2.0 + 0 * i, 5).verify() }
|
// @Test
|
||||||
|
// fun verify() = ComplexField { FieldVerifier(this, 42.0 * i, 66.0 + 28 * i, 2.0 + 0 * i, 5).verify() }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAddition() {
|
fun testAddition() {
|
||||||
@ -37,8 +38,6 @@ internal class ComplexFieldTest {
|
|||||||
assertEquals(Complex(42, 42), ComplexField { Complex(0, 168) / Complex(2, 2) })
|
assertEquals(Complex(42, 42), ComplexField { Complex(0, 168) / Complex(2, 2) })
|
||||||
assertEquals(Complex(42, 56), ComplexField { Complex(86, 56) - 44 })
|
assertEquals(Complex(42, 56), ComplexField { Complex(86, 56) - 44 })
|
||||||
assertEquals(Complex(42, 56), ComplexField { 86 - Complex(44, -56) })
|
assertEquals(Complex(42, 56), ComplexField { 86 - Complex(44, -56) })
|
||||||
assertEquals(Complex(Double.NaN, Double.NaN), ComplexField { Complex(1, 1) / Complex(Double.NaN, Double.NaN) })
|
|
||||||
assertEquals(Complex(Double.NaN, Double.NaN), ComplexField { Complex(1, 1) / Complex(0, 0) })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
@ -0,0 +1,31 @@
|
|||||||
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
internal class ComplexTest {
|
||||||
|
@Test
|
||||||
|
fun conjugate() = ComplexField { assertEquals(Complex(0, 42), Complex(0, -42).conjugate) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun reciprocal() = ComplexField { assertTrue((Complex(0.5, -0.0) - 2.toComplex().reciprocal).r < 1e-10) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun r() = ComplexField { assertEquals(sqrt(2.0), (i + 1.0.toComplex()).r) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun theta() = assertEquals(0.0, 1.toComplex().theta)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toComplex() {
|
||||||
|
assertEquals(Complex(42), 42.toComplex())
|
||||||
|
assertEquals(Complex(42.0), 42.0.toComplex())
|
||||||
|
assertEquals(Complex(42f), 42f.toComplex())
|
||||||
|
assertEquals(Complex(42.0), 42.0.toComplex())
|
||||||
|
assertEquals(Complex(42.toByte()), 42.toByte().toComplex())
|
||||||
|
assertEquals(Complex(42.toShort()), 42.toShort().toComplex())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
|
import space.kscience.kmath.expressions.FunctionalExpressionField
|
||||||
|
import space.kscience.kmath.expressions.bindSymbol
|
||||||
|
import space.kscience.kmath.expressions.invoke
|
||||||
|
import space.kscience.kmath.expressions.symbol
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
internal class ExpressionFieldForComplexTest {
|
||||||
|
val x by symbol
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testComplex() {
|
||||||
|
val context = FunctionalExpressionField(ComplexField)
|
||||||
|
|
||||||
|
val expression = context {
|
||||||
|
val x = bindSymbol(x)
|
||||||
|
x * x + 2 * x + one
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(expression(x to Complex(1.0, 0.0)), Complex(4.0, 0.0))
|
||||||
|
//assertEquals(expression(), Complex(9.0, 0.0))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
internal class QuaternionFieldTest {
|
||||||
|
@Test
|
||||||
|
fun testAddition() {
|
||||||
|
assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(16, 16) + Quaternion(26, 26) })
|
||||||
|
assertEquals(Quaternion(42, 16), QuaternionField { Quaternion(16, 16) + 26 })
|
||||||
|
assertEquals(Quaternion(42, 16), QuaternionField { 26 + Quaternion(16, 16) })
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// fun testSubtraction() {
|
||||||
|
// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(86, 55) - Quaternion(44, 13) })
|
||||||
|
// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 })
|
||||||
|
// assertEquals(Quaternion(42, 56), QuaternionField { 86 - Quaternion(44, -56) })
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiplication() {
|
||||||
|
assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(4.2, 0) * Quaternion(10, 10) })
|
||||||
|
assertEquals(Quaternion(42, 21), QuaternionField { Quaternion(4.2, 2.1) * 10 })
|
||||||
|
assertEquals(Quaternion(42, 21), QuaternionField { 10 * Quaternion(4.2, 2.1) })
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// fun testDivision() {
|
||||||
|
// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(0, 168) / Quaternion(2, 2) })
|
||||||
|
// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 })
|
||||||
|
// assertEquals(Quaternion(42, 56) , QuaternionField { 86 - Quaternion(44, -56) })
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPower() {
|
||||||
|
assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
|
||||||
|
assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
QuaternionField { i * 8 }.let { it.x.toInt() to it.w.toInt() },
|
||||||
|
QuaternionField { Quaternion(2, 2) pow 2 }.let { it.x.toInt() to it.w.toInt() })
|
||||||
|
}
|
||||||
|
}
|
@ -2,17 +2,20 @@
|
|||||||
|
|
||||||
The core features of KMath:
|
The core features of KMath:
|
||||||
|
|
||||||
- [algebras](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures: contexts and elements
|
- [algebras](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||||
- [nd](src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures
|
- [nd](src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
|
||||||
|
- [linear](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](src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
- [buffers](src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||||
- [expressions](src/commonMain/kotlin/kscience/kmath/expressions) : Functional Expressions
|
- [expressions](src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||||
|
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||||
|
performance calculations to code generation.
|
||||||
- [domains](src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
- [domains](src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
||||||
- [autodif](src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
- [autodif](src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||||
|
|
||||||
|
|
||||||
> #### Artifact:
|
> #### Artifact:
|
||||||
>
|
>
|
||||||
> This module artifact: `kscience.kmath:kmath-core:0.2.0-dev-4`.
|
> This module artifact: `space.kscience:kmath-core:0.2.0`.
|
||||||
>
|
>
|
||||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
||||||
>
|
>
|
||||||
@ -22,28 +25,31 @@ The core features of KMath:
|
|||||||
>
|
>
|
||||||
> ```gradle
|
> ```gradle
|
||||||
> repositories {
|
> repositories {
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
|
> maven { url 'https://repo.kotlin.link' }
|
||||||
> maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
|
||||||
> maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
> 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 {
|
> dependencies {
|
||||||
> implementation 'kscience.kmath:kmath-core:0.2.0-dev-4'
|
> implementation 'space.kscience:kmath-core:0.2.0'
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
> **Gradle Kotlin DSL:**
|
> **Gradle Kotlin DSL:**
|
||||||
>
|
>
|
||||||
> ```kotlin
|
> ```kotlin
|
||||||
> repositories {
|
> repositories {
|
||||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
> maven("https://repo.kotlin.link")
|
||||||
> maven("https://dl.bintray.com/mipt-npm/kscience")
|
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> maven("https://dl.bintray.com/mipt-npm/dev")
|
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
> maven("https://dl.bintray.com/hotkeytlt/maven")
|
>// Uncomment if repo.kotlin.link is unavailable
|
||||||
|
>// maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||||
|
>// maven("https://dl.bintray.com/mipt-npm/dev")
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> dependencies {
|
> dependencies {
|
||||||
> implementation("kscience.kmath:kmath-core:0.2.0-dev-4")
|
> implementation("space.kscience:kmath-core:0.2.0")
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
|
2974
kmath-core/api/kmath-core.api
Normal file
2974
kmath-core/api/kmath-core.api
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,31 +1,45 @@
|
|||||||
|
import ru.mipt.npm.gradle.Maturity
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.mpp")
|
id("ru.mipt.npm.gradle.mpp")
|
||||||
id("ru.mipt.npm.native")
|
id("ru.mipt.npm.gradle.native")
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin.sourceSets.commonMain {
|
kotlin.sourceSets {
|
||||||
dependencies {
|
commonMain {
|
||||||
api(project(":kmath-memory"))
|
dependencies {
|
||||||
|
api(project(":kmath-memory"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readme {
|
readme {
|
||||||
description = "Core classes, algebra definitions, basic linear algebra"
|
description = "Core classes, algebra definitions, basic linear algebra"
|
||||||
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
|
maturity = Maturity.DEVELOPMENT
|
||||||
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
|
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "algebras",
|
id = "algebras",
|
||||||
description = "Algebraic structures: contexts and elements",
|
description = """
|
||||||
|
Algebraic structures like rings, spaces and fields.
|
||||||
|
""".trimIndent(),
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "nd",
|
id = "nd",
|
||||||
description = "Many-dimensional structures",
|
description = "Many-dimensional structures and operations on them.",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt"
|
ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
feature(
|
||||||
|
id = "linear",
|
||||||
|
description = """
|
||||||
|
Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||||
|
""".trimIndent(),
|
||||||
|
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
||||||
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "buffers",
|
id = "buffers",
|
||||||
description = "One-dimensional structure",
|
description = "One-dimensional structure",
|
||||||
@ -34,7 +48,11 @@ readme {
|
|||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "expressions",
|
id = "expressions",
|
||||||
description = "Functional Expressions",
|
description = """
|
||||||
|
By writing a single mathematical expression once, users will be able to apply different types of
|
||||||
|
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||||
|
performance calculations to code generation.
|
||||||
|
""".trimIndent(),
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/expressions"
|
ref = "src/commonMain/kotlin/kscience/kmath/expressions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
package kscience.kmath.linear
|
|
||||||
|
|
||||||
import kscience.kmath.operations.Ring
|
|
||||||
import kscience.kmath.structures.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic implementation of Matrix space based on [NDStructure]
|
|
||||||
*/
|
|
||||||
public class BufferMatrixContext<T : Any, R : Ring<T>>(
|
|
||||||
public override val elementContext: R,
|
|
||||||
private val bufferFactory: BufferFactory<T>,
|
|
||||||
) : GenericMatrixContext<T, R, BufferMatrix<T>> {
|
|
||||||
public override fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): BufferMatrix<T> {
|
|
||||||
val buffer = bufferFactory(rows * columns) { offset -> initializer(offset / columns, offset % columns) }
|
|
||||||
return BufferMatrix(rows, columns, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun point(size: Int, initializer: (Int) -> T): Point<T> = bufferFactory(size, initializer)
|
|
||||||
|
|
||||||
public companion object
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BufferMatrix<T : Any>(
|
|
||||||
public override val rowNum: Int,
|
|
||||||
public override val colNum: Int,
|
|
||||||
public val buffer: Buffer<out T>,
|
|
||||||
) : Matrix<T> {
|
|
||||||
|
|
||||||
init {
|
|
||||||
require(buffer.size == rowNum * colNum) { "Dimension mismatch for matrix structure" }
|
|
||||||
}
|
|
||||||
|
|
||||||
override val shape: IntArray get() = intArrayOf(rowNum, colNum)
|
|
||||||
|
|
||||||
public override operator fun get(index: IntArray): T = get(index[0], index[1])
|
|
||||||
public override operator fun get(i: Int, j: Int): T = buffer[i * colNum + j]
|
|
||||||
|
|
||||||
public override fun elements(): Sequence<Pair<IntArray, T>> = sequence {
|
|
||||||
for (i in 0 until rowNum) for (j in 0 until colNum) yield(intArrayOf(i, j) to get(i, j))
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
|
|
||||||
return when (other) {
|
|
||||||
is NDStructure<*> -> NDStructure.contentEquals(this, other)
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = rowNum
|
|
||||||
result = 31 * result + colNum
|
|
||||||
result = 31 * result + buffer.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun toString(): String {
|
|
||||||
return if (rowNum <= 5 && colNum <= 5)
|
|
||||||
"Matrix(rowsNum = $rowNum, colNum = $colNum)\n" +
|
|
||||||
rows.asSequence().joinToString(prefix = "(", postfix = ")", separator = "\n ") { buffer ->
|
|
||||||
buffer.asSequence().joinToString(separator = "\t") { it.toString() }
|
|
||||||
}
|
|
||||||
else "Matrix(rowsNum = $rowNum, colNum = $colNum)"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
package kscience.kmath.operations
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The generic mathematics elements which is able to store its context
|
|
||||||
*
|
|
||||||
* @param C the type of mathematical context for this element.
|
|
||||||
*/
|
|
||||||
public interface MathElement<C> {
|
|
||||||
/**
|
|
||||||
* The context this element belongs to.
|
|
||||||
*/
|
|
||||||
public val context: C
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents element that can be wrapped to its "primitive" value.
|
|
||||||
*
|
|
||||||
* @param T the type wrapped by this wrapper.
|
|
||||||
* @param I the type of this wrapper.
|
|
||||||
*/
|
|
||||||
public interface MathWrapper<T, I> {
|
|
||||||
/**
|
|
||||||
* Unwraps [I] to [T].
|
|
||||||
*/
|
|
||||||
public fun unwrap(): T
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wraps [T] to [I].
|
|
||||||
*/
|
|
||||||
public fun T.wrap(): I
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The element of [Space].
|
|
||||||
*
|
|
||||||
* @param T the type of space operation results.
|
|
||||||
* @param I self type of the element. Needed for static type checking.
|
|
||||||
* @param S the type of space.
|
|
||||||
*/
|
|
||||||
public interface SpaceElement<T, I : SpaceElement<T, I, S>, S : Space<T>> : MathElement<S>, MathWrapper<T, I> {
|
|
||||||
/**
|
|
||||||
* Adds element to this one.
|
|
||||||
*
|
|
||||||
* @param b the augend.
|
|
||||||
* @return the sum.
|
|
||||||
*/
|
|
||||||
public operator fun plus(b: T): I = context.add(unwrap(), b).wrap()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtracts element from this one.
|
|
||||||
*
|
|
||||||
* @param b the subtrahend.
|
|
||||||
* @return the difference.
|
|
||||||
*/
|
|
||||||
public operator fun minus(b: T): I = context.add(unwrap(), context.multiply(b, -1.0)).wrap()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Multiplies this element by number.
|
|
||||||
*
|
|
||||||
* @param k the multiplicand.
|
|
||||||
* @return the product.
|
|
||||||
*/
|
|
||||||
public operator fun times(k: Number): I = context.multiply(unwrap(), k.toDouble()).wrap()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Divides this element by number.
|
|
||||||
*
|
|
||||||
* @param k the divisor.
|
|
||||||
* @return the quotient.
|
|
||||||
*/
|
|
||||||
public operator fun div(k: Number): I = context.multiply(unwrap(), 1.0 / k.toDouble()).wrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The element of [Ring].
|
|
||||||
*
|
|
||||||
* @param T the type of ring operation results.
|
|
||||||
* @param I self type of the element. Needed for static type checking.
|
|
||||||
* @param R the type of ring.
|
|
||||||
*/
|
|
||||||
public interface RingElement<T, I : RingElement<T, I, R>, R : Ring<T>> : SpaceElement<T, I, R> {
|
|
||||||
/**
|
|
||||||
* Multiplies this element by another one.
|
|
||||||
*
|
|
||||||
* @param b the multiplicand.
|
|
||||||
* @return the product.
|
|
||||||
*/
|
|
||||||
public operator fun times(b: T): I = context.multiply(unwrap(), b).wrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The element of [Field].
|
|
||||||
*
|
|
||||||
* @param T the type of field operation results.
|
|
||||||
* @param I self type of the element. Needed for static type checking.
|
|
||||||
* @param F the type of field.
|
|
||||||
*/
|
|
||||||
public interface FieldElement<T, I : FieldElement<T, I, F>, F : Field<T>> : RingElement<T, I, F> {
|
|
||||||
override val context: F
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Divides this element by another one.
|
|
||||||
*
|
|
||||||
* @param b the divisor.
|
|
||||||
* @return the quotient.
|
|
||||||
*/
|
|
||||||
public operator fun div(b: T): I = context.divide(unwrap(), b).wrap()
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
package kscience.kmath.structures
|
|
||||||
|
|
||||||
import kscience.kmath.operations.Field
|
|
||||||
import kscience.kmath.operations.FieldElement
|
|
||||||
|
|
||||||
public class BoxingNDField<T, F : Field<T>>(
|
|
||||||
public override val shape: IntArray,
|
|
||||||
public override val elementContext: F,
|
|
||||||
public val bufferFactory: BufferFactory<T>
|
|
||||||
) : BufferedNDField<T, F> {
|
|
||||||
public override val zero: BufferedNDFieldElement<T, F> by lazy { produce { zero } }
|
|
||||||
public override val one: BufferedNDFieldElement<T, F> by lazy { produce { one } }
|
|
||||||
public override val strides: Strides = DefaultStrides(shape)
|
|
||||||
|
|
||||||
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> =
|
|
||||||
bufferFactory(size, initializer)
|
|
||||||
|
|
||||||
public override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
|
|
||||||
require(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" }
|
|
||||||
return elements
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun produce(initializer: F.(IntArray) -> T): BufferedNDFieldElement<T, F> =
|
|
||||||
BufferedNDFieldElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) })
|
|
||||||
|
|
||||||
public override fun map(arg: NDBuffer<T>, transform: F.(T) -> T): BufferedNDFieldElement<T, F> {
|
|
||||||
check(arg)
|
|
||||||
|
|
||||||
return BufferedNDFieldElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(arg.strides.linearSize) { offset -> elementContext.transform(arg.buffer[offset]) })
|
|
||||||
|
|
||||||
// val buffer = arg.buffer.transform { _, value -> elementContext.transform(value) }
|
|
||||||
// return BufferedNDFieldElement(this, buffer)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun mapIndexed(
|
|
||||||
arg: NDBuffer<T>,
|
|
||||||
transform: F.(index: IntArray, T) -> T
|
|
||||||
): BufferedNDFieldElement<T, F> {
|
|
||||||
check(arg)
|
|
||||||
return BufferedNDFieldElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(arg.strides.linearSize) { offset ->
|
|
||||||
elementContext.transform(
|
|
||||||
arg.strides.index(offset),
|
|
||||||
arg.buffer[offset]
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// val buffer =
|
|
||||||
// arg.buffer.transform { offset, value -> elementContext.transform(arg.strides.index(offset), value) }
|
|
||||||
// return BufferedNDFieldElement(this, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun combine(
|
|
||||||
a: NDBuffer<T>,
|
|
||||||
b: NDBuffer<T>,
|
|
||||||
transform: F.(T, T) -> T
|
|
||||||
): BufferedNDFieldElement<T, F> {
|
|
||||||
check(a, b)
|
|
||||||
return BufferedNDFieldElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun NDBuffer<T>.toElement(): FieldElement<NDBuffer<T>, *, out BufferedNDField<T, F>> =
|
|
||||||
BufferedNDFieldElement(this@BoxingNDField, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
public inline fun <T : Any, F : Field<T>, R> F.nd(
|
|
||||||
noinline bufferFactory: BufferFactory<T>,
|
|
||||||
vararg shape: Int,
|
|
||||||
action: NDField<T, F, *>.() -> R
|
|
||||||
): R {
|
|
||||||
val ndfield = NDField.boxing(this, *shape, bufferFactory = bufferFactory)
|
|
||||||
return ndfield.action()
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
package kscience.kmath.structures
|
|
||||||
|
|
||||||
import kscience.kmath.operations.Ring
|
|
||||||
import kscience.kmath.operations.RingElement
|
|
||||||
|
|
||||||
public class BoxingNDRing<T, R : Ring<T>>(
|
|
||||||
override val shape: IntArray,
|
|
||||||
override val elementContext: R,
|
|
||||||
public val bufferFactory: BufferFactory<T>
|
|
||||||
) : BufferedNDRing<T, R> {
|
|
||||||
override val strides: Strides = DefaultStrides(shape)
|
|
||||||
override val zero: BufferedNDRingElement<T, R> by lazy { produce { zero } }
|
|
||||||
override val one: BufferedNDRingElement<T, R> by lazy { produce { one } }
|
|
||||||
|
|
||||||
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = bufferFactory(size, initializer)
|
|
||||||
|
|
||||||
override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
|
|
||||||
if (!elements.all { it.strides == this.strides }) error("Element strides are not the same as context strides")
|
|
||||||
return elements
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun produce(initializer: R.(IntArray) -> T): BufferedNDRingElement<T, R> =
|
|
||||||
BufferedNDRingElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) })
|
|
||||||
|
|
||||||
override fun map(arg: NDBuffer<T>, transform: R.(T) -> T): BufferedNDRingElement<T, R> {
|
|
||||||
check(arg)
|
|
||||||
return BufferedNDRingElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(arg.strides.linearSize) { offset -> elementContext.transform(arg.buffer[offset]) })
|
|
||||||
|
|
||||||
// val buffer = arg.buffer.transform { _, value -> elementContext.transform(value) }
|
|
||||||
// return BufferedNDFieldElement(this, buffer)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mapIndexed(
|
|
||||||
arg: NDBuffer<T>,
|
|
||||||
transform: R.(index: IntArray, T) -> T
|
|
||||||
): BufferedNDRingElement<T, R> {
|
|
||||||
check(arg)
|
|
||||||
return BufferedNDRingElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(arg.strides.linearSize) { offset ->
|
|
||||||
elementContext.transform(
|
|
||||||
arg.strides.index(offset),
|
|
||||||
arg.buffer[offset]
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// val buffer =
|
|
||||||
// arg.buffer.transform { offset, value -> elementContext.transform(arg.strides.index(offset), value) }
|
|
||||||
// return BufferedNDFieldElement(this, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun combine(
|
|
||||||
a: NDBuffer<T>,
|
|
||||||
b: NDBuffer<T>,
|
|
||||||
transform: R.(T, T) -> T
|
|
||||||
): BufferedNDRingElement<T, R> {
|
|
||||||
check(a, b)
|
|
||||||
|
|
||||||
return BufferedNDRingElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun NDBuffer<T>.toElement(): RingElement<NDBuffer<T>, *, out BufferedNDRing<T, R>> =
|
|
||||||
BufferedNDRingElement(this@BoxingNDRing, buffer)
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package kscience.kmath.structures
|
|
||||||
|
|
||||||
import kscience.kmath.operations.*
|
|
||||||
|
|
||||||
public interface BufferedNDAlgebra<T, C> : NDAlgebra<T, C, NDBuffer<T>> {
|
|
||||||
public val strides: Strides
|
|
||||||
|
|
||||||
public override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
|
|
||||||
require(elements.all { it.strides == strides }) { "Strides mismatch" }
|
|
||||||
return elements
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert any [NDStructure] to buffered structure using strides from this context.
|
|
||||||
* If the structure is already [NDBuffer], conversion is free. If not, it could be expensive because iteration over
|
|
||||||
* indices.
|
|
||||||
*
|
|
||||||
* If the argument is [NDBuffer] with different strides structure, the new element will be produced.
|
|
||||||
*/
|
|
||||||
public fun NDStructure<T>.toBuffer(): NDBuffer<T> =
|
|
||||||
if (this is NDBuffer<T> && this.strides == this@BufferedNDAlgebra.strides)
|
|
||||||
this
|
|
||||||
else
|
|
||||||
produce { index -> this@toBuffer[index] }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a buffer to element of this algebra
|
|
||||||
*/
|
|
||||||
public fun NDBuffer<T>.toElement(): MathElement<out BufferedNDAlgebra<T, C>>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public interface BufferedNDSpace<T, S : Space<T>> : NDSpace<T, S, NDBuffer<T>>, BufferedNDAlgebra<T, S> {
|
|
||||||
public override fun NDBuffer<T>.toElement(): SpaceElement<NDBuffer<T>, *, out BufferedNDSpace<T, S>>
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface BufferedNDRing<T, R : Ring<T>> : NDRing<T, R, NDBuffer<T>>, BufferedNDSpace<T, R> {
|
|
||||||
override fun NDBuffer<T>.toElement(): RingElement<NDBuffer<T>, *, out BufferedNDRing<T, R>>
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface BufferedNDField<T, F : Field<T>> : NDField<T, F, NDBuffer<T>>, BufferedNDRing<T, F> {
|
|
||||||
override fun NDBuffer<T>.toElement(): FieldElement<NDBuffer<T>, *, out BufferedNDField<T, F>>
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
package kscience.kmath.structures
|
|
||||||
|
|
||||||
import kscience.kmath.operations.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for an element with context, containing strides
|
|
||||||
*/
|
|
||||||
public abstract class BufferedNDElement<T, C> : NDBuffer<T>(), NDElement<T, C, NDBuffer<T>> {
|
|
||||||
abstract override val context: BufferedNDAlgebra<T, C>
|
|
||||||
|
|
||||||
override val strides: Strides get() = context.strides
|
|
||||||
|
|
||||||
override val shape: IntArray get() = context.shape
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BufferedNDSpaceElement<T, S : Space<T>>(
|
|
||||||
override val context: BufferedNDSpace<T, S>,
|
|
||||||
override val buffer: Buffer<T>
|
|
||||||
) : BufferedNDElement<T, S>(), SpaceElement<NDBuffer<T>, BufferedNDSpaceElement<T, S>, BufferedNDSpace<T, S>> {
|
|
||||||
|
|
||||||
override fun unwrap(): NDBuffer<T> = this
|
|
||||||
|
|
||||||
override fun NDBuffer<T>.wrap(): BufferedNDSpaceElement<T, S> {
|
|
||||||
context.check(this)
|
|
||||||
return BufferedNDSpaceElement(context, buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BufferedNDRingElement<T, R : Ring<T>>(
|
|
||||||
override val context: BufferedNDRing<T, R>,
|
|
||||||
override val buffer: Buffer<T>
|
|
||||||
) : BufferedNDElement<T, R>(), RingElement<NDBuffer<T>, BufferedNDRingElement<T, R>, BufferedNDRing<T, R>> {
|
|
||||||
override fun unwrap(): NDBuffer<T> = this
|
|
||||||
|
|
||||||
override fun NDBuffer<T>.wrap(): BufferedNDRingElement<T, R> {
|
|
||||||
context.check(this)
|
|
||||||
return BufferedNDRingElement(context, buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BufferedNDFieldElement<T, F : Field<T>>(
|
|
||||||
override val context: BufferedNDField<T, F>,
|
|
||||||
override val buffer: Buffer<T>
|
|
||||||
) : BufferedNDElement<T, F>(), FieldElement<NDBuffer<T>, BufferedNDFieldElement<T, F>, BufferedNDField<T, F>> {
|
|
||||||
override fun unwrap(): NDBuffer<T> = this
|
|
||||||
|
|
||||||
override fun NDBuffer<T>.wrap(): BufferedNDFieldElement<T, F> {
|
|
||||||
context.check(this)
|
|
||||||
return BufferedNDFieldElement(context, buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Element by element application of any operation on elements to the whole array. Just like in numpy.
|
|
||||||
*/
|
|
||||||
public operator fun <T : Any, F : Field<T>> Function1<T, T>.invoke(ndElement: BufferedNDElement<T, F>): MathElement<out BufferedNDAlgebra<T, F>> =
|
|
||||||
ndElement.context.run { map(ndElement) { invoke(it) }.toElement() }
|
|
||||||
|
|
||||||
/* plus and minus */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Summation operation for [BufferedNDElement] and single element
|
|
||||||
*/
|
|
||||||
public operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.plus(arg: T): NDElement<T, F, NDBuffer<T>> =
|
|
||||||
context.map(this) { it + arg }.wrap()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtraction operation between [BufferedNDElement] and single element
|
|
||||||
*/
|
|
||||||
public operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.minus(arg: T): NDElement<T, F, NDBuffer<T>> =
|
|
||||||
context.map(this) { it - arg }.wrap()
|
|
||||||
|
|
||||||
/* prod and div */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Product operation for [BufferedNDElement] and single element
|
|
||||||
*/
|
|
||||||
public operator fun <T : Any, F : Ring<T>> BufferedNDElement<T, F>.times(arg: T): NDElement<T, F, NDBuffer<T>> =
|
|
||||||
context.map(this) { it * arg }.wrap()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Division operation between [BufferedNDElement] and single element
|
|
||||||
*/
|
|
||||||
public operator fun <T : Any, F : Field<T>> BufferedNDElement<T, F>.div(arg: T): NDElement<T, F, NDBuffer<T>> =
|
|
||||||
context.map(this) { it / arg }.wrap()
|
|
@ -1,158 +0,0 @@
|
|||||||
package kscience.kmath.structures
|
|
||||||
|
|
||||||
import kscience.kmath.misc.UnstableKMathAPI
|
|
||||||
import kscience.kmath.operations.*
|
|
||||||
import kotlin.contracts.InvocationKind
|
|
||||||
import kotlin.contracts.contract
|
|
||||||
|
|
||||||
public typealias ComplexNDElement = BufferedNDFieldElement<Complex, ComplexField>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An optimized nd-field for complex numbers
|
|
||||||
*/
|
|
||||||
@OptIn(UnstableKMathAPI::class)
|
|
||||||
public class ComplexNDField(override val shape: IntArray) :
|
|
||||||
BufferedNDField<Complex, ComplexField>,
|
|
||||||
ExtendedNDField<Complex, ComplexField, NDBuffer<Complex>>,
|
|
||||||
RingWithNumbers<NDBuffer<Complex>>{
|
|
||||||
|
|
||||||
override val strides: Strides = DefaultStrides(shape)
|
|
||||||
override val elementContext: ComplexField get() = ComplexField
|
|
||||||
override val zero: ComplexNDElement by lazy { produce { zero } }
|
|
||||||
override val one: ComplexNDElement by lazy { produce { one } }
|
|
||||||
|
|
||||||
override fun number(value: Number): NDBuffer<Complex> {
|
|
||||||
val c = value.toComplex()
|
|
||||||
return produce { c }
|
|
||||||
}
|
|
||||||
|
|
||||||
public inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Complex): Buffer<Complex> =
|
|
||||||
Buffer.complex(size) { initializer(it) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inline transform an NDStructure to another structure
|
|
||||||
*/
|
|
||||||
override fun map(
|
|
||||||
arg: NDBuffer<Complex>,
|
|
||||||
transform: ComplexField.(Complex) -> Complex,
|
|
||||||
): ComplexNDElement {
|
|
||||||
check(arg)
|
|
||||||
val array = buildBuffer(arg.strides.linearSize) { offset -> ComplexField.transform(arg.buffer[offset]) }
|
|
||||||
return BufferedNDFieldElement(this, array)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun produce(initializer: ComplexField.(IntArray) -> Complex): ComplexNDElement {
|
|
||||||
val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
|
||||||
return BufferedNDFieldElement(this, array)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mapIndexed(
|
|
||||||
arg: NDBuffer<Complex>,
|
|
||||||
transform: ComplexField.(index: IntArray, Complex) -> Complex,
|
|
||||||
): ComplexNDElement {
|
|
||||||
check(arg)
|
|
||||||
|
|
||||||
return BufferedNDFieldElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(arg.strides.linearSize) { offset ->
|
|
||||||
elementContext.transform(
|
|
||||||
arg.strides.index(offset),
|
|
||||||
arg.buffer[offset]
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun combine(
|
|
||||||
a: NDBuffer<Complex>,
|
|
||||||
b: NDBuffer<Complex>,
|
|
||||||
transform: ComplexField.(Complex, Complex) -> Complex,
|
|
||||||
): ComplexNDElement {
|
|
||||||
check(a, b)
|
|
||||||
|
|
||||||
return BufferedNDFieldElement(
|
|
||||||
this,
|
|
||||||
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun NDBuffer<Complex>.toElement(): FieldElement<NDBuffer<Complex>, *, out BufferedNDField<Complex, ComplexField>> =
|
|
||||||
BufferedNDFieldElement(this@ComplexNDField, buffer)
|
|
||||||
|
|
||||||
override fun power(arg: NDBuffer<Complex>, pow: Number): ComplexNDElement =
|
|
||||||
map(arg) { power(it, pow) }
|
|
||||||
|
|
||||||
override fun exp(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { exp(it) }
|
|
||||||
override fun ln(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { ln(it) }
|
|
||||||
|
|
||||||
override fun sin(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { sin(it) }
|
|
||||||
override fun cos(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { cos(it) }
|
|
||||||
override fun tan(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { tan(it) }
|
|
||||||
override fun asin(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { asin(it) }
|
|
||||||
override fun acos(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { acos(it) }
|
|
||||||
override fun atan(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { atan(it) }
|
|
||||||
|
|
||||||
override fun sinh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { sinh(it) }
|
|
||||||
override fun cosh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { cosh(it) }
|
|
||||||
override fun tanh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { tanh(it) }
|
|
||||||
override fun asinh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { asinh(it) }
|
|
||||||
override fun acosh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { acosh(it) }
|
|
||||||
override fun atanh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { atanh(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fast element production using function inlining
|
|
||||||
*/
|
|
||||||
public inline fun BufferedNDField<Complex, ComplexField>.produceInline(initializer: ComplexField.(Int) -> Complex): ComplexNDElement {
|
|
||||||
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) }
|
|
||||||
return BufferedNDFieldElement(this, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map one [ComplexNDElement] using function with indices.
|
|
||||||
*/
|
|
||||||
public inline fun ComplexNDElement.mapIndexed(transform: ComplexField.(index: IntArray, Complex) -> Complex): ComplexNDElement =
|
|
||||||
context.produceInline { offset -> transform(strides.index(offset), buffer[offset]) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map one [ComplexNDElement] using function without indices.
|
|
||||||
*/
|
|
||||||
public inline fun ComplexNDElement.map(transform: ComplexField.(Complex) -> Complex): ComplexNDElement {
|
|
||||||
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.transform(buffer[offset]) }
|
|
||||||
return BufferedNDFieldElement(context, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Element by element application of any operation on elements to the whole array. Just like in numpy
|
|
||||||
*/
|
|
||||||
public operator fun Function1<Complex, Complex>.invoke(ndElement: ComplexNDElement): ComplexNDElement =
|
|
||||||
ndElement.map { this@invoke(it) }
|
|
||||||
|
|
||||||
/* plus and minus */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Summation operation for [BufferedNDElement] and single element
|
|
||||||
*/
|
|
||||||
public operator fun ComplexNDElement.plus(arg: Complex): ComplexNDElement = map { it + arg }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtraction operation between [BufferedNDElement] and single element
|
|
||||||
*/
|
|
||||||
public operator fun ComplexNDElement.minus(arg: Complex): ComplexNDElement = map { it - arg }
|
|
||||||
|
|
||||||
public operator fun ComplexNDElement.plus(arg: Double): ComplexNDElement = map { it + arg }
|
|
||||||
public operator fun ComplexNDElement.minus(arg: Double): ComplexNDElement = map { it - arg }
|
|
||||||
|
|
||||||
public fun NDField.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape)
|
|
||||||
|
|
||||||
public fun NDElement.Companion.complex(
|
|
||||||
vararg shape: Int,
|
|
||||||
initializer: ComplexField.(IntArray) -> Complex,
|
|
||||||
): ComplexNDElement = NDField.complex(*shape).produce(initializer)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Produce a context for n-dimensional operations inside this real field
|
|
||||||
*/
|
|
||||||
public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R {
|
|
||||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return NDField.complex(*shape).action()
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package kscience.kmath.structures
|
|
||||||
|
|
||||||
import kscience.kmath.operations.ExtendedField
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [ExtendedField] over [NDStructure].
|
|
||||||
*
|
|
||||||
* @param T the type of the element contained in ND structure.
|
|
||||||
* @param N the type of ND structure.
|
|
||||||
* @param F the extended field of structure elements.
|
|
||||||
*/
|
|
||||||
public interface ExtendedNDField<T : Any, F : ExtendedField<T>, N : NDStructure<T>> : NDField<T, F, N>, ExtendedField<N>
|
|
||||||
|
|
||||||
///**
|
|
||||||
// * NDField that supports [ExtendedField] operations on its elements
|
|
||||||
// */
|
|
||||||
//class ExtendedNDFieldWrapper<T : Any, F : ExtendedField<T>, N : NDStructure<T>>(private val ndField: NDField<T, F, N>) :
|
|
||||||
// ExtendedNDField<T, F, N>, NDField<T, F, N> by ndField {
|
|
||||||
//
|
|
||||||
// override val shape: IntArray get() = ndField.shape
|
|
||||||
// override val elementContext: F get() = ndField.elementContext
|
|
||||||
//
|
|
||||||
// override fun produce(initializer: F.(IntArray) -> T) = ndField.produce(initializer)
|
|
||||||
//
|
|
||||||
// override fun power(arg: N, pow: Double): N {
|
|
||||||
// return produce { with(elementContext) { power(arg[it], pow) } }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun exp(arg: N): N {
|
|
||||||
// return produce { with(elementContext) { exp(arg[it]) } }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun ln(arg: N): N {
|
|
||||||
// return produce { with(elementContext) { ln(arg[it]) } }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun sin(arg: N): N {
|
|
||||||
// return produce { with(elementContext) { sin(arg[it]) } }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun cos(arg: N): N {
|
|
||||||
// return produce { with(elementContext) { cos(arg[it]) } }
|
|
||||||
// }
|
|
||||||
//}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user