Merge branch 'dev' into feature/mp-samplers
# Conflicts: # examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt # examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt # examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt # kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt # kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt # kmath-coroutines/src/commonMain/kotlin/kscience/kmath/chains/BlockingRealChain.kt # kmath-stat/src/commonMain/kotlin/kscience/kmath/stat/SamplerAlgebra.kt # kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Distribution.kt # kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt # kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/distributions.kt
107
.github/workflows/build.yml
vendored
@ -3,105 +3,34 @@ name: Gradle build
|
||||
on: [ push ]
|
||||
|
||||
jobs:
|
||||
build-ubuntu:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macOS-latest, windows-latest ]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout the repo
|
||||
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
|
||||
|
||||
build-osx:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
- name: Cache gradle
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
.gradle
|
||||
build
|
||||
~/.gradle
|
||||
key: gradle
|
||||
restore-keys: gradle
|
||||
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.konan/dependencies
|
||||
~/.konan/kotlin-native-prebuilt-macos-*
|
||||
key: ${{ runner.os }}-konan
|
||||
restore-keys: ${{ runner.os }}-konan
|
||||
- name: Build with Gradle
|
||||
run: sudo ./gradlew -Dorg.gradle.daemon=false --build-cache build
|
||||
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
- name: Add msys to path
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
|
||||
- name: Cache gradle
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
.gradle
|
||||
build
|
||||
~/.gradle
|
||||
key: ${{ runner.os }}-gradle
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.konan/dependencies
|
||||
~/.konan/kotlin-native-prebuilt-mingw-*
|
||||
key: ${{ runner.os }}-konan
|
||||
restore-keys: ${{ runner.os }}-konan
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew --build-cache build
|
||||
path: ~/.konan
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Build
|
||||
run: ./gradlew build --no-daemon --stacktrace
|
||||
|
40
.github/workflows/pages.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
name: Dokka publication
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Cache gradle
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ubuntu-20.04-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
ubuntu-20.04-gradle-
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.konan
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Build
|
||||
run: |
|
||||
./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace
|
||||
mv build/dokka/htmlMultiModule/-modules.html build/dokka/htmlMultiModule/index.html
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.0
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: build/dokka/htmlMultiModule
|
136
.github/workflows/publish.yml
vendored
@ -1,117 +1,59 @@
|
||||
name: Bintray Publish
|
||||
name: Gradle publish
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
build-ubuntu:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
publish:
|
||||
environment:
|
||||
name: publish
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macOS-latest, windows-latest ]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout the repo
|
||||
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
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
|
||||
- name: Cache gradle
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
.gradle
|
||||
build
|
||||
~/.gradle
|
||||
key: ${{ runner.os }}-gradle
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.konan/dependencies
|
||||
~/.konan/kotlin-native-prebuilt-mingw-*
|
||||
key: ${{ runner.os }}-konan
|
||||
restore-keys: ${{ runner.os }}-konan
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew --build-cache build
|
||||
- name: Run release task
|
||||
run: ./gradlew release -PbintrayUser=${{ secrets.BINTRAY_USER }} -PbintrayApiKey=${{ secrets.BINTRAY_KEY }}
|
||||
|
||||
path: ~/.konan
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Publish Windows Artifacts
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: >
|
||||
./gradlew release --no-daemon
|
||||
-Ppublishing.enabled=true
|
||||
-Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }}
|
||||
-Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }}
|
||||
-Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }}
|
||||
-Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }}
|
||||
- name: Publish Mac Artifacts
|
||||
if: matrix.os == 'macOS-latest'
|
||||
run: >
|
||||
./gradlew release --no-daemon
|
||||
-Ppublishing.enabled=true
|
||||
-Ppublishing.platform=macosX64
|
||||
-Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }}
|
||||
-Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }}
|
||||
-Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }}
|
||||
-Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }}
|
||||
|
5
.gitignore
vendored
@ -2,9 +2,14 @@
|
||||
build/
|
||||
out/
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
# Generated by javac -h and runtime
|
||||
*.class
|
||||
*.log
|
||||
|
35
CHANGELOG.md
@ -2,6 +2,32 @@
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- ScaleOperations interface
|
||||
- Field extends ScaleOperations
|
||||
- Basic integration API
|
||||
|
||||
### Changed
|
||||
- Exponential operations merged with hyperbolic functions
|
||||
- Space is replaced by Group. Space is reserved for vector spaces.
|
||||
- VectorSpace is now a vector space
|
||||
- Buffer factories for primitives moved to MutableBuffer.Companion
|
||||
- NDStructure and NDAlgebra to StructureND and AlgebraND respectively
|
||||
- Real -> Double
|
||||
- DataSets are moved from functions to core
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
- Nearest in Domain. To be implemented in geometry package.
|
||||
- Number multiplication and division in main Algebra chain
|
||||
- `contentEquals` from Buffer. It moved to the companion.
|
||||
|
||||
### Fixed
|
||||
|
||||
### Security
|
||||
|
||||
## [0.2.0]
|
||||
### Added
|
||||
- `fun` annotation for SAM interfaces in library
|
||||
- Explicit `public` visibility for all public APIs
|
||||
- Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140)
|
||||
@ -21,11 +47,11 @@
|
||||
- Basic Quaternion vector support in `kmath-complex`.
|
||||
|
||||
### Changed
|
||||
- Package changed from `scientifik` to `kscience.kmath`
|
||||
- Gradle version: 6.6 -> 6.8
|
||||
- Package changed from `scientifik` to `space.kscience`
|
||||
- Gradle version: 6.6 -> 6.8.2
|
||||
- Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`)
|
||||
- `Polynomial` secondary constructor made function
|
||||
- Kotlin version: 1.3.72 -> 1.4.21
|
||||
- Kotlin version: 1.3.72 -> 1.4.30
|
||||
- `kmath-ast` doesn't depend on heavy `kotlin-reflect` library
|
||||
- Full autodiff refactoring based on `Symbol`
|
||||
- `kmath-prob` renamed to `kmath-stat`
|
||||
@ -41,6 +67,8 @@
|
||||
- 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
|
||||
|
||||
@ -50,6 +78,7 @@
|
||||
- `toGrid` method.
|
||||
- Public visibility of `BufferAccessor2D`
|
||||
- `Real` class
|
||||
- StructureND identity and equals
|
||||
|
||||
### Fixed
|
||||
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
||||
|
84
README.md
@ -1,11 +1,8 @@
|
||||
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
|
||||
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
|
||||
|
||||
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
||||
|
||||
Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
||||
|
||||
Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
|
||||
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22)
|
||||
[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
|
||||
|
||||
# KMath
|
||||
|
||||
@ -89,12 +86,12 @@ KMath is a modular library. Different modules provide different features with di
|
||||
> **Maturity**: PROTOTYPE
|
||||
>
|
||||
> **Features:**
|
||||
> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -110,8 +107,8 @@ KMath is a modular library. Different modules provide different features with di
|
||||
> **Maturity**: PROTOTYPE
|
||||
>
|
||||
> **Features:**
|
||||
> - [complex](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||
> - [quaternion](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||
> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -121,15 +118,15 @@ KMath is a modular library. Different modules provide different features with di
|
||||
> **Maturity**: DEVELOPMENT
|
||||
>
|
||||
> **Features:**
|
||||
> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||
> - [nd](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
|
||||
> - [linear](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
> - [buffers](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||
> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||
> - [algebras](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||
> - [nd](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
|
||||
> - [linear](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
> - [buffers](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||
> - [expressions](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||
performance calculations to code generation.
|
||||
> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
||||
> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||
> - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
|
||||
> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -149,6 +146,12 @@ performance calculations to code generation.
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
>
|
||||
> **Features:**
|
||||
> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : The Point implementation using SimpleMatrix.
|
||||
> - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : The Matrix implementation using SimpleMatrix.
|
||||
> - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : The LinearSpace implementation using SimpleMatrix.
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-for-real](kmath-for-real)
|
||||
@ -159,9 +162,9 @@ One can still use generic algebras though.
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
>
|
||||
> **Features:**
|
||||
> - [RealVector](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealVector.kt) : Numpy-like operations for Buffers/Points
|
||||
> - [RealMatrix](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt) : Numpy-like operations for 2d real structures
|
||||
> - [grids](kmath-for-real/src/commonMain/kotlin/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
||||
> - [DoubleVector](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points
|
||||
> - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures
|
||||
> - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -171,10 +174,10 @@ One can still use generic algebras though.
|
||||
> **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
|
||||
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt
|
||||
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt
|
||||
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt
|
||||
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -208,9 +211,9 @@ One can still use generic algebras though.
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
>
|
||||
> **Features:**
|
||||
> - [nd4jarraystructure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray
|
||||
> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long
|
||||
> - [nd4jarrayfields](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : Fields over Nd4jArrayStructure of Float and Double
|
||||
> - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
|
||||
> - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long
|
||||
> - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -247,33 +250,22 @@ better than SciPy.
|
||||
|
||||
### Repositories
|
||||
|
||||
Release artifacts are accessible from bintray with following configuration (see documentation of
|
||||
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details):
|
||||
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
|
||||
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy:
|
||||
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
// maven("https://dl.bintray.com/mipt-npm/dev") for dev versions
|
||||
maven("https://repo.kotlin.link")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api("kscience.kmath:kmath-core:0.2.0-dev-7")
|
||||
// api("kscience.kmath:kmath-core-jvm:0.2.0-dev-7") for jvm-specific version
|
||||
api("space.kscience:kmath-core:0.3.0-dev-3")
|
||||
// api("kscience.kmath:kmath-core-jvm:0.3.0-dev-3") for jvm-specific version
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
The project requires a lot of additional work. The most important thing we need is a feedback about what features are
|
||||
|
@ -1,34 +1,49 @@
|
||||
import ru.mipt.npm.gradle.KSciencePublishPlugin
|
||||
import org.jetbrains.dokka.gradle.DokkaTask
|
||||
import ru.mipt.npm.gradle.KSciencePublishingPlugin
|
||||
import java.net.URL
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.project")
|
||||
id("ru.mipt.npm.gradle.project")
|
||||
}
|
||||
|
||||
internal val kmathVersion: String by extra("0.2.0-dev-7")
|
||||
internal val bintrayRepo: String by extra("kscience")
|
||||
internal val githubProject: String by extra("kmath")
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven("https://clojars.org/repo")
|
||||
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
|
||||
maven("https://dl.bintray.com/hotkeytlt/maven")
|
||||
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
maven("https://dl.bintray.com/kotlin/kotlinx")
|
||||
maven("https://dl.bintray.com/mipt-npm/dev")
|
||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
maven("https://jitpack.io")
|
||||
maven("http://logicrunch.research.it.uu.se/maven/")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
group = "kscience.kmath"
|
||||
version = kmathVersion
|
||||
group = "space.kscience"
|
||||
version = "0.3.0-dev-4"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
if (name.startsWith("kmath")) apply<KSciencePublishPlugin>()
|
||||
if (name.startsWith("kmath")) apply<KSciencePublishingPlugin>()
|
||||
|
||||
afterEvaluate {
|
||||
tasks.withType<DokkaTask> {
|
||||
dokkaSourceSets.all {
|
||||
val readmeFile = File(this@subprojects.projectDir, "./README.md")
|
||||
if (readmeFile.exists())
|
||||
includes.setFrom(includes + readmeFile.absolutePath)
|
||||
|
||||
arrayOf(
|
||||
"http://ejml.org/javadoc/",
|
||||
"https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/",
|
||||
"https://deeplearning4j.org/api/latest/"
|
||||
).map { URL("${it}package-list") to URL(it) }.forEach { (a, b) ->
|
||||
externalDocumentationLink {
|
||||
packageListUrl.set(a)
|
||||
url.set(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readme {
|
||||
@ -36,5 +51,11 @@ readme {
|
||||
}
|
||||
|
||||
ksciencePublish {
|
||||
spaceRepo = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven"
|
||||
github("kmath")
|
||||
space()
|
||||
sonatype()
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
```kotlin
|
||||
import kscience.kmath.operations.*
|
||||
import space.kscience.kmath.operations.*
|
||||
|
||||
val a: T = ...
|
||||
val b: T = ...
|
||||
@ -31,7 +31,7 @@ multiplication;
|
||||
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
|
||||
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
|
||||
|
||||
A typical implementation of `Field<T>` is the `RealField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
||||
A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
||||
|
||||
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
|
||||
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot`
|
||||
@ -47,7 +47,7 @@ but it also holds reference to the `ComplexField` singleton, which allows perfor
|
||||
numbers without explicit involving the context like:
|
||||
|
||||
```kotlin
|
||||
import kscience.kmath.operations.*
|
||||
import space.kscience.kmath.operations.*
|
||||
|
||||
// Using elements
|
||||
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:
|
||||
|
||||
```kotlin
|
||||
import kscience.kmath.operations.*
|
||||
import space.kscience.kmath.operations.*
|
||||
|
||||
val c1 = Complex(1.0, 2.0)
|
||||
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:
|
||||
|
||||
```kotlin
|
||||
import kscience.kmath.operations.*
|
||||
import space.kscience.kmath.operations.*
|
||||
|
||||
val c1 = Complex(1.0, 2.0)
|
||||
val c2 = ComplexField { c1 - 1.0 } // Returns: Complex(re=0.0, im=2.0)
|
||||
|
@ -13,16 +13,19 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath24"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path22"
|
||||
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath><clipPath
|
||||
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path34"
|
||||
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs><g
|
||||
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 248 KiB |
@ -13,12 +13,14 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath32"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path30"
|
||||
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs><g
|
||||
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@ -13,24 +13,29 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath24"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path22"
|
||||
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath><clipPath
|
||||
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path34"
|
||||
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath><clipPath
|
||||
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath48"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path46"
|
||||
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath><clipPath
|
||||
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath60"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path58"
|
||||
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs><g
|
||||
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
|
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 278 KiB |
@ -13,88 +13,109 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath40"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path38"
|
||||
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
||||
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath52"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path50"
|
||||
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath><clipPath
|
||||
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath64"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path62"
|
||||
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath><clipPath
|
||||
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath76"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path74"
|
||||
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath><clipPath
|
||||
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath88"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path86"
|
||||
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath><clipPath
|
||||
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath100"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path98"
|
||||
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath><clipPath
|
||||
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath112"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path110"
|
||||
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath><clipPath
|
||||
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath124"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path122"
|
||||
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath><clipPath
|
||||
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath136"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path134"
|
||||
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath><clipPath
|
||||
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath148"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path146"
|
||||
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath><clipPath
|
||||
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath160"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path158"
|
||||
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath><clipPath
|
||||
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath172"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path170"
|
||||
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
||||
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath184"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path182"
|
||||
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath><clipPath
|
||||
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath196"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path194"
|
||||
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
||||
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath208"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path206"
|
||||
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
||||
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath220"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path218"
|
||||
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
||||
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath232"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path230"
|
||||
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath><clipPath
|
||||
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath244"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path242"
|
||||
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
||||
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath256"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path254"
|
||||
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath><clipPath
|
||||
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath268"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path266"
|
||||
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs><g
|
||||
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
@ -10,11 +10,11 @@ structures. In `kmath` performance depends on which particular context was used
|
||||
Let us consider following contexts:
|
||||
```kotlin
|
||||
// automatically build context most suited for given type.
|
||||
val autoField = NDField.auto(RealField, dim, dim)
|
||||
val autoField = NDField.auto(DoubleField, dim, dim)
|
||||
// specialized nd-field for Double. It works as generic Double field as well
|
||||
val specializedField = NDField.real(dim, dim)
|
||||
//A generic boxing field. It should be used for objects, not primitives.
|
||||
val genericField = NDField.buffered(RealField, dim, dim)
|
||||
val genericField = NDField.buffered(DoubleField, dim, dim)
|
||||
```
|
||||
Now let us perform several tests and see which implementation is best suited for each case:
|
||||
|
||||
|
65
docs/templates/ARTIFACT-TEMPLATE.md
vendored
@ -1,37 +1,28 @@
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `${group}:${name}:${version}`.
|
||||
>
|
||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/${name}/images/download.svg) ](https://bintray.com/mipt-npm/kscience/${name}/_latestVersion)
|
||||
>
|
||||
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/${name}/images/download.svg) ](https://bintray.com/mipt-npm/dev/${name}/_latestVersion)
|
||||
>
|
||||
> **Gradle:**
|
||||
>
|
||||
> ```gradle
|
||||
> repositories {
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
|
||||
> 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' }
|
||||
>
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation '${group}:${name}:${version}'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
>
|
||||
> ```kotlin
|
||||
> repositories {
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
> maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
> maven("https://dl.bintray.com/mipt-npm/dev")
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven")
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("${group}:${name}:${version}")
|
||||
> }
|
||||
> ```
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `${group}:${name}:${version}`.
|
||||
|
||||
**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
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation '${group}:${name}:${version}'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("${group}:${name}:${version}")
|
||||
}
|
||||
```
|
26
docs/templates/README-TEMPLATE.md
vendored
@ -1,11 +1,8 @@
|
||||
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
|
||||
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
|
||||
|
||||
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
||||
|
||||
Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
||||
|
||||
Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
|
||||
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22)
|
||||
[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
|
||||
|
||||
# KMath
|
||||
|
||||
@ -97,33 +94,22 @@ better than SciPy.
|
||||
|
||||
### Repositories
|
||||
|
||||
Release artifacts are accessible from bintray with following configuration (see documentation of
|
||||
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details):
|
||||
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
|
||||
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy:
|
||||
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
// maven("https://dl.bintray.com/mipt-npm/dev") for dev versions
|
||||
maven("https://repo.kotlin.link")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api("kscience.kmath:kmath-core:$version")
|
||||
api("${group}:kmath-core:$version")
|
||||
// api("kscience.kmath:kmath-core-jvm:$version") for jvm-specific version
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
plugins {
|
||||
java
|
||||
kotlin("jvm")
|
||||
kotlin("plugin.allopen")
|
||||
id("kotlinx.benchmark")
|
||||
@ -12,6 +11,7 @@ sourceSets.register("benchmarks")
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
maven("https://repo.kotlin.link")
|
||||
maven("https://clojars.org/repo")
|
||||
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
|
||||
maven("https://dl.bintray.com/hotkeytlt/maven")
|
||||
@ -69,6 +69,14 @@ benchmark {
|
||||
targets.register("benchmarks")
|
||||
// This one matches sourceSet name above
|
||||
|
||||
configurations.register("buffer") {
|
||||
warmups = 1 // number of warmup iterations
|
||||
iterations = 3 // number of iterations
|
||||
iterationTime = 500 // time in seconds per iteration
|
||||
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
|
||||
include("BufferBenchmark")
|
||||
}
|
||||
|
||||
configurations.register("dot") {
|
||||
warmups = 1 // number of warmup iterations
|
||||
iterations = 3 // number of iterations
|
||||
@ -76,6 +84,22 @@ benchmark {
|
||||
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")
|
||||
}
|
||||
|
||||
configurations.register("matrixInverse") {
|
||||
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("MatrixInverseBenchmark")
|
||||
}
|
||||
}
|
||||
|
||||
kotlin.sourceSets.all {
|
||||
|
@ -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,34 +0,0 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kscience.kmath.complex.Complex
|
||||
import kscience.kmath.complex.complex
|
||||
import kscience.kmath.structures.MutableBuffer
|
||||
import kscience.kmath.structures.RealBuffer
|
||||
import org.openjdk.jmh.annotations.Benchmark
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class BufferBenchmark {
|
||||
@Benchmark
|
||||
fun genericRealBufferReadWrite() {
|
||||
val buffer = RealBuffer(size) { it.toDouble() }
|
||||
|
||||
(0 until size).forEach {
|
||||
buffer[it]
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun complexBufferReadWrite() {
|
||||
val buffer = MutableBuffer.complex(size / 2) { Complex(it.toDouble(), -it.toDouble()) }
|
||||
|
||||
(0 until size / 2).forEach {
|
||||
buffer[it]
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val size: Int = 100
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kscience.kmath.commons.linear.CMMatrixContext
|
||||
import kscience.kmath.ejml.EjmlMatrixContext
|
||||
import kscience.kmath.linear.BufferMatrixContext
|
||||
import kscience.kmath.linear.Matrix
|
||||
import kscience.kmath.linear.RealMatrixContext
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.structures.Buffer
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class DotBenchmark {
|
||||
companion object {
|
||||
val random = Random(12224)
|
||||
val dim = 1000
|
||||
|
||||
//creating invertible matrix
|
||||
val matrix1 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val matrix2 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
|
||||
val cmMatrix1 = CMMatrixContext { matrix1.toCM() }
|
||||
val cmMatrix2 = CMMatrixContext { matrix2.toCM() }
|
||||
|
||||
val ejmlMatrix1 = EjmlMatrixContext { matrix1.toEjml() }
|
||||
val ejmlMatrix2 = EjmlMatrixContext { matrix2.toEjml() }
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun cmDot() {
|
||||
CMMatrixContext {
|
||||
cmMatrix1 dot cmMatrix2
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun ejmlDot() {
|
||||
EjmlMatrixContext {
|
||||
ejmlMatrix1 dot ejmlMatrix2
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun ejmlDotWithConversion() {
|
||||
EjmlMatrixContext {
|
||||
matrix1 dot matrix2
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun bufferedDot() {
|
||||
BufferMatrixContext(RealField, Buffer.Companion::real).invoke {
|
||||
matrix1 dot matrix2
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun realDot() {
|
||||
RealMatrixContext {
|
||||
matrix1 dot matrix2
|
||||
}
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kscience.kmath.asm.compile
|
||||
import kscience.kmath.ast.MstField
|
||||
import kscience.kmath.ast.mstInField
|
||||
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.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class ExpressionsInterpretersBenchmark {
|
||||
private val algebra: Field<Double> = RealField
|
||||
|
||||
@Benchmark
|
||||
fun functionalExpression() {
|
||||
val expr = algebra.expressionInField {
|
||||
symbol("x") * const(2.0) + const(2.0) / symbol("x") - const(16.0)
|
||||
}
|
||||
|
||||
invokeAndSum(expr)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun mstExpression() {
|
||||
val expr = algebra.mstInField {
|
||||
symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0
|
||||
}
|
||||
|
||||
invokeAndSum(expr)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun asmExpression() {
|
||||
val expr = algebra.mstInField {
|
||||
MstField.symbol("x") * 2.0 + 2.0 / MstField.symbol("x") - 16.0
|
||||
}.compile()
|
||||
|
||||
invokeAndSum(expr)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun rawExpression() {
|
||||
val x by symbol
|
||||
val expr = Expression<Double> { args -> args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 }
|
||||
invokeAndSum(expr)
|
||||
}
|
||||
|
||||
private fun invokeAndSum(expr: Expression<Double>) {
|
||||
val random = Random(0)
|
||||
var sum = 0.0
|
||||
|
||||
repeat(1000000) {
|
||||
sum += expr("x" to random.nextDouble())
|
||||
}
|
||||
|
||||
println(sum)
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
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.linear.Matrix
|
||||
import kscience.kmath.linear.MatrixContext
|
||||
import kscience.kmath.linear.inverseWithLup
|
||||
import kscience.kmath.linear.real
|
||||
import kscience.kmath.operations.invoke
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class LinearAlgebraBenchmark {
|
||||
companion object {
|
||||
val random = Random(1224)
|
||||
val dim = 100
|
||||
|
||||
//creating invertible matrix
|
||||
val u = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val l = Matrix.real(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
|
||||
val matrix = l dot u
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun kmathLupInversion() {
|
||||
MatrixContext.real.inverseWithLup(matrix)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun cmLUPInversion() {
|
||||
CMMatrixContext {
|
||||
inverse(matrix)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun ejmlInverse() {
|
||||
EjmlMatrixContext {
|
||||
inverse(matrix)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.structures.Buffer
|
||||
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() {
|
||||
autoField {
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += one }
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun specializedFieldAdd() {
|
||||
specializedField {
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Benchmark
|
||||
fun boxingFieldAdd() {
|
||||
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)
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.invoke
|
||||
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: 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() {
|
||||
autoField {
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun realFieldAddition() {
|
||||
realField {
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun viktorFieldAddition() {
|
||||
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 }
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.invoke
|
||||
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 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() {
|
||||
realField {
|
||||
val fortyTwo = produce { 42.0 }
|
||||
var res = one
|
||||
repeat(n) { res = ln(fortyTwo) }
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun viktorFieldLog() {
|
||||
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,38 @@
|
||||
package space.kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import java.nio.IntBuffer
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class ArrayBenchmark {
|
||||
@Benchmark
|
||||
fun benchmarkArrayRead(blackhole: Blackhole) {
|
||||
var res = 0
|
||||
for (i in 1..size) res += array[size - i]
|
||||
blackhole.consume(res)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun benchmarkBufferRead(blackhole: Blackhole) {
|
||||
var res = 0
|
||||
for (i in 1..size) res += arrayBuffer[size - i]
|
||||
blackhole.consume(res)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun nativeBufferRead(blackhole: Blackhole) {
|
||||
var res = 0
|
||||
for (i in 1..size) res += nativeBuffer[size - i]
|
||||
blackhole.consume(res)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val size = 1000
|
||||
private val array = IntArray(size) { it }
|
||||
private val arrayBuffer = IntBuffer.wrap(array)
|
||||
private val nativeBuffer = IntBuffer.allocate(size).also { for (i in 0 until size) it.put(i, i) }
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package space.kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.complex.Complex
|
||||
import space.kscience.kmath.complex.complex
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class BufferBenchmark {
|
||||
@Benchmark
|
||||
fun genericDoubleBufferReadWrite() {
|
||||
val buffer = DoubleBuffer(size) { it.toDouble() }
|
||||
|
||||
(0 until size).forEach {
|
||||
buffer[it]
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun complexBufferReadWrite() {
|
||||
val buffer = MutableBuffer.complex(size / 2) { Complex(it.toDouble(), -it.toDouble()) }
|
||||
|
||||
(0 until size / 2).forEach {
|
||||
buffer[it]
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val size = 100
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package space.kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.commons.linear.CMLinearSpace
|
||||
import space.kscience.kmath.ejml.EjmlLinearSpace
|
||||
import space.kscience.kmath.linear.LinearSpace
|
||||
import space.kscience.kmath.linear.invoke
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class DotBenchmark {
|
||||
companion object {
|
||||
val random = Random(12224)
|
||||
const val dim = 1000
|
||||
|
||||
//creating invertible matrix
|
||||
val matrix1 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val matrix2 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
|
||||
val cmMatrix1 = CMLinearSpace { matrix1.toCM() }
|
||||
val cmMatrix2 = CMLinearSpace { matrix2.toCM() }
|
||||
|
||||
val ejmlMatrix1 = EjmlLinearSpace { matrix1.toEjml() }
|
||||
val ejmlMatrix2 = EjmlLinearSpace { matrix2.toEjml() }
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun cmDot(blackhole: Blackhole) {
|
||||
CMLinearSpace.run {
|
||||
blackhole.consume(cmMatrix1 dot cmMatrix2)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun ejmlDot(blackhole: Blackhole) {
|
||||
EjmlLinearSpace {
|
||||
blackhole.consume(ejmlMatrix1 dot ejmlMatrix2)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun ejmlDotWithConversion(blackhole: Blackhole) {
|
||||
EjmlLinearSpace {
|
||||
blackhole.consume(matrix1 dot matrix2)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun bufferedDot(blackhole: Blackhole) {
|
||||
LinearSpace.auto(DoubleField).invoke {
|
||||
blackhole.consume(matrix1 dot matrix2)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun realDot(blackhole: Blackhole) {
|
||||
LinearSpace.real {
|
||||
blackhole.consume(matrix1 dot matrix2)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package space.kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.asm.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.misc.symbol
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.bindSymbol
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class ExpressionsInterpretersBenchmark {
|
||||
@Benchmark
|
||||
fun functionalExpression(blackhole: Blackhole) {
|
||||
val expr = algebra.expressionInField {
|
||||
val x = bindSymbol(x)
|
||||
x * const(2.0) + const(2.0) / x - const(16.0)
|
||||
}
|
||||
|
||||
invokeAndSum(expr, blackhole)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun mstExpression(blackhole: Blackhole) {
|
||||
val expr = algebra.mstInField {
|
||||
val x = bindSymbol(x)
|
||||
x * 2.0 + number(2.0) / x - 16.0
|
||||
}
|
||||
|
||||
invokeAndSum(expr, blackhole)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun asmExpression(blackhole: Blackhole) {
|
||||
val expr = algebra.mstInField {
|
||||
val x = bindSymbol(x)
|
||||
x * 2.0 + number(2.0) / x - 16.0
|
||||
}.compile()
|
||||
|
||||
invokeAndSum(expr, blackhole)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun rawExpression(blackhole: Blackhole) {
|
||||
val expr = Expression<Double> { args ->
|
||||
val x = args.getValue(x)
|
||||
x * 2.0 + 2.0 / x - 16.0
|
||||
}
|
||||
|
||||
invokeAndSum(expr, blackhole)
|
||||
}
|
||||
|
||||
private fun invokeAndSum(expr: Expression<Double>, blackhole: Blackhole) {
|
||||
val random = Random(0)
|
||||
var sum = 0.0
|
||||
|
||||
repeat(1000000) {
|
||||
sum += expr(x to random.nextDouble())
|
||||
}
|
||||
|
||||
blackhole.consume(sum)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private val algebra = DoubleField
|
||||
private val x by symbol
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package space.kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.commons.linear.CMLinearSpace
|
||||
import space.kscience.kmath.commons.linear.inverse
|
||||
import space.kscience.kmath.ejml.EjmlLinearSpace
|
||||
import space.kscience.kmath.ejml.inverse
|
||||
import space.kscience.kmath.linear.LinearSpace
|
||||
import space.kscience.kmath.linear.inverseWithLup
|
||||
import space.kscience.kmath.linear.invoke
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class MatrixInverseBenchmark {
|
||||
companion object {
|
||||
val random = Random(1224)
|
||||
const val dim = 100
|
||||
|
||||
private val space = LinearSpace.real
|
||||
|
||||
//creating invertible matrix
|
||||
val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
|
||||
val matrix = space { l dot u }
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun kmathLupInversion(blackhole: Blackhole) {
|
||||
blackhole.consume(LinearSpace.real.inverseWithLup(matrix))
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun cmLUPInversion(blackhole: Blackhole) {
|
||||
with(CMLinearSpace) {
|
||||
blackhole.consume(inverse(matrix))
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun ejmlInverse(blackhole: Blackhole) {
|
||||
with(EjmlLinearSpace) {
|
||||
blackhole.consume(inverse(matrix))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package space.kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.nd.*
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun autoFieldAdd(blackhole: Blackhole) {
|
||||
with(autoField) {
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += one }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun specializedFieldAdd(blackhole: Blackhole) {
|
||||
with(specializedField) {
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Benchmark
|
||||
fun boxingFieldAdd(blackhole: Blackhole) {
|
||||
with(genericField) {
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val dim = 1000
|
||||
private const val n = 100
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val specializedField = AlgebraND.real(dim, dim)
|
||||
private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package space.kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import org.jetbrains.bio.viktor.F64Array
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.auto
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.viktor.ViktorNDField
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class ViktorBenchmark {
|
||||
@Benchmark
|
||||
fun automaticFieldAddition(blackhole: Blackhole) {
|
||||
with(autoField) {
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun realFieldAddition(blackhole: Blackhole) {
|
||||
with(realField) {
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun viktorFieldAddition(blackhole: Blackhole) {
|
||||
with(viktorField) {
|
||||
var res = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun rawViktor(blackhole: Blackhole) {
|
||||
val one = F64Array.full(init = 1.0, shape = intArrayOf(dim, dim))
|
||||
var res = one
|
||||
repeat(n) { res = res + one }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val dim = 1000
|
||||
private const val n = 100
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val realField = AlgebraND.real(dim, dim)
|
||||
private val viktorField = ViktorNDField(dim, dim)
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package space.kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import org.jetbrains.bio.viktor.F64Array
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.auto
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.viktor.ViktorFieldND
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class ViktorLogBenchmark {
|
||||
@Benchmark
|
||||
fun realFieldLog(blackhole: Blackhole) {
|
||||
with(realNdField) {
|
||||
val fortyTwo = produce { 42.0 }
|
||||
var res = one
|
||||
repeat(n) { res = ln(fortyTwo) }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun viktorFieldLog(blackhole: Blackhole) {
|
||||
with(viktorField) {
|
||||
val fortyTwo = produce { 42.0 }
|
||||
var res = one
|
||||
repeat(n) { res = ln(fortyTwo) }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun rawViktorLog(blackhole: Blackhole) {
|
||||
val fortyTwo = F64Array.full(dim, dim, init = 42.0)
|
||||
lateinit var res: F64Array
|
||||
repeat(n) { res = fortyTwo.log() }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val dim = 1000
|
||||
private const val n = 100
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val realNdField = AlgebraND.real(dim, dim)
|
||||
private val viktorField = ViktorFieldND(intArrayOf(dim, dim))
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package kscience.kmath.ast
|
||||
|
||||
import kscience.kmath.asm.compile
|
||||
import kscience.kmath.expressions.derivative
|
||||
import kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.expressions.symbol
|
||||
import kscience.kmath.kotlingrad.differentiable
|
||||
import kscience.kmath.operations.RealField
|
||||
|
||||
/**
|
||||
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
|
||||
* valid derivative.
|
||||
*/
|
||||
fun main() {
|
||||
val x by symbol
|
||||
|
||||
val actualDerivative = MstExpression(RealField, "x^2-4*x-44".parseMath())
|
||||
.differentiable()
|
||||
.derivative(x)
|
||||
.compile()
|
||||
|
||||
val expectedDerivative = MstExpression(RealField, "2*x-4".parseMath()).compile()
|
||||
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.ExtendedField
|
||||
import kscience.kmath.operations.RealField
|
||||
import 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)
|
@ -0,0 +1,15 @@
|
||||
package space.kscience.kmath.ast
|
||||
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
|
||||
fun main() {
|
||||
val expr = DoubleField.mstInField {
|
||||
val x = bindSymbol("x")
|
||||
x * 2.0 + number(2.0) / x - 16.0
|
||||
}
|
||||
|
||||
repeat(10000000) {
|
||||
expr.invoke("x" to 1.0)
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package space.kscience.kmath.ast
|
||||
|
||||
import space.kscience.kmath.asm.compile
|
||||
import space.kscience.kmath.expressions.derivative
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.kotlingrad.differentiable
|
||||
import space.kscience.kmath.misc.symbol
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
|
||||
/**
|
||||
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
|
||||
* valid derivative.
|
||||
*/
|
||||
fun main() {
|
||||
val x by symbol
|
||||
|
||||
val actualDerivative = MstExpression(DoubleField, "x^2-4*x-44".parseMath())
|
||||
.differentiable()
|
||||
.derivative(x)
|
||||
.compile()
|
||||
|
||||
val expectedDerivative = MstExpression(DoubleField, "2*x-4".parseMath()).compile()
|
||||
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package space.kscience.kmath.linear
|
||||
|
||||
import space.kscience.kmath.real.*
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
|
||||
fun main() {
|
||||
val x0 = DoubleVector(0.0, 0.0, 0.0)
|
||||
val sigma = DoubleVector(1.0, 1.0, 1.0)
|
||||
|
||||
val gaussian: (Point<Double>) -> Double = { x ->
|
||||
require(x.size == x0.size)
|
||||
kotlin.math.exp(-((x - x0) / sigma).square().sum())
|
||||
}
|
||||
|
||||
fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> {
|
||||
require(x.size == x0.size)
|
||||
return DoubleBuffer(x.size) { i ->
|
||||
val h = sigma[i] / 5
|
||||
val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
|
||||
val f1 = invoke(x + dVector / 2)
|
||||
val f0 = invoke(x - dVector / 2)
|
||||
(f1 - f0) / h
|
||||
}
|
||||
}
|
||||
|
||||
println(gaussian.grad(x0))
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package kscience.kmath.operations
|
||||
package space.kscience.kmath.operations
|
||||
|
||||
fun main() {
|
||||
val res = BigIntField { number(1) * 2 }
|
@ -1,18 +1,18 @@
|
||||
package kscience.kmath.operations
|
||||
package space.kscience.kmath.operations
|
||||
|
||||
import kscience.kmath.complex.Complex
|
||||
import kscience.kmath.complex.complex
|
||||
import kscience.kmath.nd.NDAlgebra
|
||||
import space.kscience.kmath.complex.Complex
|
||||
import space.kscience.kmath.complex.complex
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
|
||||
fun main() {
|
||||
// 2d element
|
||||
val element = NDAlgebra.complex(2, 2).produce { (i, j) ->
|
||||
val element = AlgebraND.complex(2, 2).produce { (i, j) ->
|
||||
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
||||
}
|
||||
println(element)
|
||||
|
||||
// 1d element operation
|
||||
val result = with(NDAlgebra.complex(8)) {
|
||||
val result = with(AlgebraND.complex(8)) {
|
||||
val a = produce { (it) -> i * it - it.toDouble() }
|
||||
val b = 3
|
||||
val c = Complex(1.0, 1.0)
|
@ -1,26 +1,26 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package kscience.kmath.structures
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.complex.*
|
||||
import kscience.kmath.linear.transpose
|
||||
import kscience.kmath.nd.NDAlgebra
|
||||
import kscience.kmath.nd.NDStructure
|
||||
import kscience.kmath.nd.as2D
|
||||
import kscience.kmath.nd.real
|
||||
import kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.complex.*
|
||||
import space.kscience.kmath.linear.transpose
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.as2D
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
fun main() {
|
||||
val dim = 1000
|
||||
val n = 1000
|
||||
|
||||
val realField = NDAlgebra.real(dim, dim)
|
||||
val complexField: ComplexNDField = NDAlgebra.complex(dim, dim)
|
||||
val realField = AlgebraND.real(dim, dim)
|
||||
val complexField: ComplexFieldND = AlgebraND.complex(dim, dim)
|
||||
|
||||
val realTime = measureTimeMillis {
|
||||
realField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) {
|
||||
res += 1.0
|
||||
}
|
||||
@ -31,7 +31,7 @@ fun main() {
|
||||
|
||||
val complexTime = measureTimeMillis {
|
||||
complexField {
|
||||
var res: NDStructure<Complex> = one
|
||||
var res: StructureND<Complex> = one
|
||||
repeat(n) {
|
||||
res += 1.0
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
package kscience.kmath.structures
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.nd4j.Nd4jArrayField
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.viktor.ViktorNDField
|
||||
import org.nd4j.linalg.factory.Nd4j
|
||||
import space.kscience.kmath.nd.*
|
||||
import space.kscience.kmath.nd4j.Nd4jArrayField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.viktor.ViktorNDField
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.system.measureTimeMillis
|
||||
@ -24,56 +24,56 @@ fun main() {
|
||||
val n = 1000
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
// specialized nd-field for Double. It works as generic Double field as well
|
||||
val realField = NDAlgebra.real(dim, dim)
|
||||
val realField = AlgebraND.real(dim, dim)
|
||||
//A generic boxing field. It should be used for objects, not primitives.
|
||||
val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
||||
val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||
// Nd4j specialized field.
|
||||
val nd4jField = Nd4jArrayField.real(dim, dim)
|
||||
//viktor field
|
||||
val viktorField = ViktorNDField(dim, dim)
|
||||
//parallel processing based on Java Streams
|
||||
val parallelField = NDAlgebra.realWithStream(dim,dim)
|
||||
val parallelField = AlgebraND.realWithStream(dim, dim)
|
||||
|
||||
measureAndPrint("Boxing addition") {
|
||||
boxingField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Specialized addition") {
|
||||
realField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Nd4j specialized addition") {
|
||||
nd4jField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Viktor addition") {
|
||||
viktorField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Parallel stream addition") {
|
||||
parallelField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Automatic field addition") {
|
||||
autoField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.*
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.ExtendedField
|
||||
import space.kscience.kmath.operations.NumbersAddOperations
|
||||
import java.util.*
|
||||
import java.util.stream.IntStream
|
||||
|
||||
/**
|
||||
* A demonstration implementation of NDField over Real using Java [DoubleStream] for parallel execution
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
class StreamDoubleFieldND(
|
||||
override val shape: IntArray,
|
||||
) : FieldND<Double, DoubleField>,
|
||||
NumbersAddOperations<StructureND<Double>>,
|
||||
ExtendedField<StructureND<Double>> {
|
||||
|
||||
private val strides = DefaultStrides(shape)
|
||||
override val elementContext: DoubleField get() = DoubleField
|
||||
override val zero: BufferND<Double> by lazy { produce { zero } }
|
||||
override val one: BufferND<Double> by lazy { produce { one } }
|
||||
|
||||
override fun number(value: Number): BufferND<Double> {
|
||||
val d = value.toDouble() // minimize conversions
|
||||
return produce { d }
|
||||
}
|
||||
|
||||
private val StructureND<Double>.buffer: DoubleBuffer
|
||||
get() = when {
|
||||
!shape.contentEquals(this@StreamDoubleFieldND.shape) -> throw ShapeMismatchException(
|
||||
this@StreamDoubleFieldND.shape,
|
||||
shape
|
||||
)
|
||||
this is BufferND && this.strides == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer
|
||||
else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
|
||||
}
|
||||
|
||||
|
||||
override fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND<Double> {
|
||||
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
|
||||
val index = strides.index(offset)
|
||||
DoubleField.initializer(index)
|
||||
}.toArray()
|
||||
|
||||
return BufferND(strides, array.asBuffer())
|
||||
}
|
||||
|
||||
override fun StructureND<Double>.map(
|
||||
transform: DoubleField.(Double) -> Double,
|
||||
): BufferND<Double> {
|
||||
val array = Arrays.stream(buffer.array).parallel().map { DoubleField.transform(it) }.toArray()
|
||||
return BufferND(strides, array.asBuffer())
|
||||
}
|
||||
|
||||
override fun StructureND<Double>.mapIndexed(
|
||||
transform: DoubleField.(index: IntArray, Double) -> Double,
|
||||
): BufferND<Double> {
|
||||
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
|
||||
DoubleField.transform(
|
||||
strides.index(offset),
|
||||
buffer.array[offset]
|
||||
)
|
||||
}.toArray()
|
||||
|
||||
return BufferND(strides, array.asBuffer())
|
||||
}
|
||||
|
||||
override fun combine(
|
||||
a: StructureND<Double>,
|
||||
b: StructureND<Double>,
|
||||
transform: DoubleField.(Double, Double) -> Double,
|
||||
): BufferND<Double> {
|
||||
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
|
||||
DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset])
|
||||
}.toArray()
|
||||
return BufferND(strides, array.asBuffer())
|
||||
}
|
||||
|
||||
override fun StructureND<Double>.unaryMinus(): StructureND<Double> = map { -it }
|
||||
|
||||
override fun scale(a: StructureND<Double>, value: Double): StructureND<Double> = a.map { it * value }
|
||||
|
||||
override fun power(arg: StructureND<Double>, pow: Number): BufferND<Double> = arg.map { power(it, pow) }
|
||||
|
||||
override fun exp(arg: StructureND<Double>): BufferND<Double> = arg.map { exp(it) }
|
||||
|
||||
override fun ln(arg: StructureND<Double>): BufferND<Double> = arg.map { ln(it) }
|
||||
|
||||
override fun sin(arg: StructureND<Double>): BufferND<Double> = arg.map { sin(it) }
|
||||
override fun cos(arg: StructureND<Double>): BufferND<Double> = arg.map { cos(it) }
|
||||
override fun tan(arg: StructureND<Double>): BufferND<Double> = arg.map { tan(it) }
|
||||
override fun asin(arg: StructureND<Double>): BufferND<Double> = arg.map { asin(it) }
|
||||
override fun acos(arg: StructureND<Double>): BufferND<Double> = arg.map { acos(it) }
|
||||
override fun atan(arg: StructureND<Double>): BufferND<Double> = arg.map { atan(it) }
|
||||
|
||||
override fun sinh(arg: StructureND<Double>): BufferND<Double> = arg.map { sinh(it) }
|
||||
override fun cosh(arg: StructureND<Double>): BufferND<Double> = arg.map { cosh(it) }
|
||||
override fun tanh(arg: StructureND<Double>): BufferND<Double> = arg.map { tanh(it) }
|
||||
override fun asinh(arg: StructureND<Double>): BufferND<Double> = arg.map { asinh(it) }
|
||||
override fun acosh(arg: StructureND<Double>): BufferND<Double> = arg.map { acosh(it) }
|
||||
override fun atanh(arg: StructureND<Double>): BufferND<Double> = arg.map { atanh(it) }
|
||||
}
|
||||
|
||||
fun AlgebraND.Companion.realWithStream(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(shape)
|
@ -1,15 +1,16 @@
|
||||
package kscience.kmath.structures
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.nd.DefaultStrides
|
||||
import kscience.kmath.nd.NDBuffer
|
||||
import space.kscience.kmath.nd.BufferND
|
||||
import space.kscience.kmath.nd.DefaultStrides
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||
fun main() {
|
||||
val n = 6000
|
||||
val array = DoubleArray(n * n) { 1.0 }
|
||||
val buffer = RealBuffer(array)
|
||||
val buffer = DoubleBuffer(array)
|
||||
val strides = DefaultStrides(intArrayOf(n, n))
|
||||
val structure = NDBuffer(strides, buffer)
|
||||
val structure = BufferND(strides, buffer)
|
||||
|
||||
measureTimeMillis {
|
||||
var res = 0.0
|
@ -1,12 +1,13 @@
|
||||
package kscience.kmath.structures
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.nd.NDStructure
|
||||
import kscience.kmath.nd.mapToBuffer
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.mapToBuffer
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
fun main() {
|
||||
val n = 6000
|
||||
val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
||||
val structure = StructureND.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
||||
structure.mapToBuffer { it + 1 } // warm-up
|
||||
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
|
||||
println("Structure mapping finished in $time1 millis")
|
||||
@ -19,10 +20,10 @@ fun main() {
|
||||
|
||||
println("Array mapping finished in $time2 millis")
|
||||
|
||||
val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
|
||||
val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 })
|
||||
|
||||
val time3 = measureTimeMillis {
|
||||
val target = RealBuffer(DoubleArray(n * n))
|
||||
val target = DoubleBuffer(DoubleArray(n * n))
|
||||
val res = array.forEachIndexed { index, value ->
|
||||
target[index] = value + 1
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package kscience.kmath.structures
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.dimensions.D2
|
||||
import kscience.kmath.dimensions.D3
|
||||
import kscience.kmath.dimensions.DMatrixContext
|
||||
import kscience.kmath.dimensions.Dimension
|
||||
import space.kscience.kmath.dimensions.D2
|
||||
import space.kscience.kmath.dimensions.D3
|
||||
import space.kscience.kmath.dimensions.DMatrixContext
|
||||
import space.kscience.kmath.dimensions.Dimension
|
||||
|
||||
private fun DMatrixContext<Double>.simple() {
|
||||
private fun DMatrixContext<Double, *>.simple() {
|
||||
val m1 = produce<D2, D3> { i, j -> (i + j).toDouble() }
|
||||
val m2 = produce<D3, D2> { i, j -> (i + j).toDouble() }
|
||||
|
||||
@ -17,7 +17,7 @@ private object D5 : Dimension {
|
||||
override val dim: UInt = 5u
|
||||
}
|
||||
|
||||
private fun DMatrixContext<Double>.custom() {
|
||||
private fun DMatrixContext<Double, *>.custom() {
|
||||
val m1 = produce<D2, D5> { i, j -> (i + j).toDouble() }
|
||||
val m2 = produce<D5, D2> { i, j -> (i - j).toDouble() }
|
||||
val m3 = produce<D2, D2> { i, j -> (i - j).toDouble() }
|
@ -3,6 +3,6 @@ kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||
kotlin.mpp.stability.nowarn=true
|
||||
kotlin.native.enableDependencyPropagation=false
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=9G
|
||||
org.gradle.parallel=true
|
||||
systemProp.org.gradle.internal.publish.checksums.insecure=true
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -1,52 +1,43 @@
|
||||
# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`)
|
||||
# Module kmath-ast
|
||||
|
||||
This subproject implements the following features:
|
||||
Abstract syntax tree expression representation and related optimizations.
|
||||
|
||||
- [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
- [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
- [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
- [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
- [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
- [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
- [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
- [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
- [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
- [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
- [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
- [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
|
||||
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `kscience.kmath:kmath-ast:0.2.0-dev-7`.
|
||||
>
|
||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
|
||||
>
|
||||
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-ast/_latestVersion)
|
||||
>
|
||||
> **Gradle:**
|
||||
>
|
||||
> ```gradle
|
||||
> repositories {
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
|
||||
> 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' }
|
||||
>
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'kscience.kmath:kmath-ast:0.2.0-dev-7'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
>
|
||||
> ```kotlin
|
||||
> repositories {
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
> maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
> maven("https://dl.bintray.com/mipt-npm/dev")
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven")
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("kscience.kmath:kmath-ast:0.2.0-dev-7")
|
||||
> }
|
||||
> ```
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-3`.
|
||||
|
||||
**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
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-ast:0.3.0-dev-3'
|
||||
}
|
||||
```
|
||||
**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
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-ast:0.3.0-dev-3")
|
||||
}
|
||||
```
|
||||
|
||||
## Dynamic expression code generation
|
||||
|
||||
@ -58,19 +49,19 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
|
||||
For example, the following builder:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||
|
||||
```java
|
||||
package kscience.kmath.asm.generated;
|
||||
package space.kscience.kmath.asm.generated;
|
||||
|
||||
import java.util.Map;
|
||||
import kotlin.jvm.functions.Function2;
|
||||
import kscience.kmath.asm.internal.MapIntrinsics;
|
||||
import kscience.kmath.expressions.Expression;
|
||||
import kscience.kmath.expressions.Symbol;
|
||||
import space.kscience.kmath.asm.internal.MapIntrinsics;
|
||||
import space.kscience.kmath.expressions.Expression;
|
||||
import space.kscience.kmath.expressions.Symbol;
|
||||
|
||||
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
||||
private final Object[] constants;
|
||||
@ -91,8 +82,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
||||
This API extends MST and MstExpression, so you may optimize as both of them:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
RealField.expression("x+2".parseMath())
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.expression("x+2".parseMath())
|
||||
```
|
||||
|
||||
#### Known issues
|
||||
@ -106,7 +97,7 @@ RealField.expression("x+2".parseMath())
|
||||
A similar feature is also available on JS.
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
The code above returns expression implemented with such a JS function:
|
||||
|
@ -1,7 +1,7 @@
|
||||
import ru.mipt.npm.gradle.Maturity
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.mpp")
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
}
|
||||
|
||||
kotlin.js {
|
||||
@ -33,19 +33,24 @@ kotlin.sourceSets {
|
||||
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation(npm("astring", "1.4.3"))
|
||||
implementation(npm("astring", "1.7.0"))
|
||||
}
|
||||
}
|
||||
|
||||
jvmMain {
|
||||
dependencies {
|
||||
api("com.github.h0tk3y.betterParse:better-parse:0.4.0")
|
||||
implementation("org.ow2.asm:asm:9.0")
|
||||
implementation("org.ow2.asm:asm-commons:9.0")
|
||||
api("com.github.h0tk3y.betterParse:better-parse:0.4.1")
|
||||
implementation("org.ow2.asm:asm:9.1")
|
||||
implementation("org.ow2.asm:asm-commons:9.1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Workaround for https://github.com/Kotlin/dokka/issues/1455
|
||||
tasks.dokkaHtml {
|
||||
dependsOn(tasks.build)
|
||||
}
|
||||
|
||||
readme {
|
||||
maturity = Maturity.PROTOTYPE
|
||||
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
|
||||
@ -53,36 +58,36 @@ readme {
|
||||
feature(
|
||||
id = "expression-language",
|
||||
description = "Expression language and its parser",
|
||||
ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt"
|
||||
ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst",
|
||||
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-building",
|
||||
description = "MST building algebraic structure",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-interpreter",
|
||||
description = "MST interpreter",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-jvm-codegen",
|
||||
description = "Dynamic MST to JVM bytecode compiler",
|
||||
ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt"
|
||||
ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-js-codegen",
|
||||
description = "Dynamic MST to JS compiler",
|
||||
ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt"
|
||||
ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt"
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`)
|
||||
# Module kmath-ast
|
||||
|
||||
This subproject implements the following features:
|
||||
Abstract syntax tree expression representation and related optimizations.
|
||||
|
||||
${features}
|
||||
|
||||
@ -16,19 +16,19 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
|
||||
For example, the following builder:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||
|
||||
```java
|
||||
package kscience.kmath.asm.generated;
|
||||
package space.kscience.kmath.asm.generated;
|
||||
|
||||
import java.util.Map;
|
||||
import kotlin.jvm.functions.Function2;
|
||||
import kscience.kmath.asm.internal.MapIntrinsics;
|
||||
import kscience.kmath.expressions.Expression;
|
||||
import kscience.kmath.expressions.Symbol;
|
||||
import space.kscience.kmath.asm.internal.MapIntrinsics;
|
||||
import space.kscience.kmath.expressions.Expression;
|
||||
import space.kscience.kmath.expressions.Symbol;
|
||||
|
||||
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
||||
private final Object[] constants;
|
||||
@ -49,8 +49,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
||||
This API extends MST and MstExpression, so you may optimize as both of them:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
RealField.expression("x+2".parseMath())
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.expression("x+2".parseMath())
|
||||
```
|
||||
|
||||
#### Known issues
|
||||
@ -64,7 +64,7 @@ RealField.expression("x+2".parseMath())
|
||||
A similar feature is also available on JS.
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
The code above returns expression implemented with such a JS function:
|
||||
|
@ -1,7 +1,7 @@
|
||||
package kscience.kmath.ast
|
||||
package space.kscience.kmath.ast
|
||||
|
||||
import kscience.kmath.operations.Algebra
|
||||
import kscience.kmath.operations.NumericAlgebra
|
||||
import space.kscience.kmath.operations.Algebra
|
||||
import space.kscience.kmath.operations.NumericAlgebra
|
||||
|
||||
/**
|
||||
* 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)
|
||||
?: error("Numeric nodes are not supported by $this")
|
||||
|
||||
is MST.Symbolic -> symbol(node.value)
|
||||
is MST.Symbolic -> bindSymbol(node.value)
|
||||
|
||||
is MST.Unary -> when {
|
||||
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 kscience.kmath.operations.*
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.*
|
||||
|
||||
/**
|
||||
* [Algebra] over [MST] nodes.
|
||||
*/
|
||||
public object MstAlgebra : NumericAlgebra<MST> {
|
||||
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 =
|
||||
{ arg -> MST.Unary(operation, arg) }
|
||||
@ -18,25 +18,25 @@ public object MstAlgebra : NumericAlgebra<MST> {
|
||||
}
|
||||
|
||||
/**
|
||||
* [Space] over [MST] nodes.
|
||||
* [Group] over [MST] nodes.
|
||||
*/
|
||||
public object MstSpace : Space<MST>, NumericAlgebra<MST> {
|
||||
public override val zero: MST.Numeric by lazy { number(0.0) }
|
||||
public object MstGroup : Group<MST>, NumericAlgebra<MST>, ScaleOperations<MST> {
|
||||
public override val zero: MST.Numeric = number(0.0)
|
||||
|
||||
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 add(a: MST, b: MST): MST.Binary = binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b)
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(value)
|
||||
public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOperations.PLUS_OPERATION)(a, b)
|
||||
public override operator fun MST.unaryPlus(): MST.Unary =
|
||||
unaryOperationFunction(SpaceOperations.PLUS_OPERATION)(this)
|
||||
unaryOperationFunction(GroupOperations.PLUS_OPERATION)(this)
|
||||
|
||||
public override operator fun MST.unaryMinus(): MST.Unary =
|
||||
unaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this)
|
||||
unaryOperationFunction(GroupOperations.MINUS_OPERATION)(this)
|
||||
|
||||
public override operator fun MST.minus(b: MST): MST.Binary =
|
||||
binaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this, b)
|
||||
binaryOperationFunction(GroupOperations.MINUS_OPERATION)(this, b)
|
||||
|
||||
public override fun multiply(a: MST, k: Number): MST.Binary =
|
||||
binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(k))
|
||||
public override fun scale(a: MST, value: Double): MST.Binary =
|
||||
binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(value))
|
||||
|
||||
public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary =
|
||||
MstAlgebra.binaryOperationFunction(operation)
|
||||
@ -49,25 +49,26 @@ public object MstSpace : Space<MST>, NumericAlgebra<MST> {
|
||||
* [Ring] over [MST] nodes.
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public object MstRing : Ring<MST>, RingWithNumbers<MST> {
|
||||
public override val zero: MST.Numeric
|
||||
get() = MstSpace.zero
|
||||
public object MstRing : Ring<MST>, NumbersAddOperations<MST>, ScaleOperations<MST> {
|
||||
public override val zero: MST.Numeric get() = MstGroup.zero
|
||||
public override val one: MST.Numeric = number(1.0)
|
||||
|
||||
public override val one: MST.Numeric by lazy { number(1.0) }
|
||||
public override fun number(value: Number): MST.Numeric = MstGroup.number(value)
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(value)
|
||||
public override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b)
|
||||
|
||||
public override fun scale(a: MST, value: Double): MST.Binary =
|
||||
MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.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 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, b: MST): MST.Binary =
|
||||
binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b)
|
||||
|
||||
public override operator fun MST.unaryPlus(): MST.Unary = MstSpace { +this@unaryPlus }
|
||||
public override operator fun MST.unaryMinus(): MST.Unary = MstSpace { -this@unaryMinus }
|
||||
public override operator fun MST.minus(b: MST): MST.Binary = MstSpace { this@minus - b }
|
||||
public override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus }
|
||||
public override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus }
|
||||
public override operator fun MST.minus(b: MST): MST.Binary = MstGroup { this@minus - b }
|
||||
|
||||
public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary =
|
||||
MstSpace.binaryOperationFunction(operation)
|
||||
MstGroup.binaryOperationFunction(operation)
|
||||
|
||||
public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary =
|
||||
MstAlgebra.unaryOperationFunction(operation)
|
||||
@ -77,17 +78,18 @@ public object MstRing : Ring<MST>, RingWithNumbers<MST> {
|
||||
* [Field] over [MST] nodes.
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public object MstField : Field<MST>, RingWithNumbers<MST> {
|
||||
public override val zero: MST.Numeric
|
||||
get() = MstRing.zero
|
||||
public object MstField : Field<MST>, NumbersAddOperations<MST>, ScaleOperations<MST> {
|
||||
public override val zero: MST.Numeric get() = MstRing.zero
|
||||
|
||||
public override val one: MST.Numeric
|
||||
get() = MstRing.one
|
||||
public override val one: MST.Numeric get() = MstRing.one
|
||||
|
||||
public override fun symbol(value: String): MST.Symbolic = MstRing.symbol(value)
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(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 multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k)
|
||||
|
||||
public override fun scale(a: MST, value: Double): MST.Binary =
|
||||
MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value))
|
||||
|
||||
public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b)
|
||||
public override fun divide(a: MST, b: MST): MST.Binary =
|
||||
binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b)
|
||||
@ -107,13 +109,10 @@ public object MstField : Field<MST>, RingWithNumbers<MST> {
|
||||
* [ExtendedField] over [MST] nodes.
|
||||
*/
|
||||
public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
|
||||
public override val zero: MST.Numeric
|
||||
get() = MstField.zero
|
||||
public override val zero: MST.Numeric get() = MstField.zero
|
||||
public override val one: MST.Numeric get() = MstField.one
|
||||
|
||||
public override val one: MST.Numeric
|
||||
get() = MstField.one
|
||||
|
||||
public override fun symbol(value: String): MST.Symbolic = MstField.symbol(value)
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(value)
|
||||
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
|
||||
public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg)
|
||||
public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg)
|
||||
@ -121,14 +120,17 @@ public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
|
||||
public override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg)
|
||||
public override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg)
|
||||
public override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg)
|
||||
public override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.SINH_OPERATION)(arg)
|
||||
public override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.COSH_OPERATION)(arg)
|
||||
public override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.TANH_OPERATION)(arg)
|
||||
public override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ASINH_OPERATION)(arg)
|
||||
public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ACOSH_OPERATION)(arg)
|
||||
public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ATANH_OPERATION)(arg)
|
||||
public override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.SINH_OPERATION)(arg)
|
||||
public override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.COSH_OPERATION)(arg)
|
||||
public override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.TANH_OPERATION)(arg)
|
||||
public override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ASINH_OPERATION)(arg)
|
||||
public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg)
|
||||
public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg)
|
||||
public override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b)
|
||||
public override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k)
|
||||
|
||||
public override fun scale(a: MST, value: Double): MST =
|
||||
binaryOperation(GroupOperations.PLUS_OPERATION, a, number(value))
|
||||
|
||||
public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b)
|
||||
public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b)
|
||||
public override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus }
|
@ -1,7 +1,9 @@
|
||||
package kscience.kmath.ast
|
||||
package space.kscience.kmath.ast
|
||||
|
||||
import kscience.kmath.expressions.*
|
||||
import kscience.kmath.operations.*
|
||||
import space.kscience.kmath.expressions.*
|
||||
import space.kscience.kmath.misc.StringSymbol
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
import space.kscience.kmath.operations.*
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@ -15,14 +17,23 @@ import kotlin.contracts.contract
|
||||
*/
|
||||
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> {
|
||||
override fun symbol(value: String): T = try {
|
||||
algebra.symbol(value)
|
||||
override fun bindSymbol(value: String): T = try {
|
||||
algebra.bindSymbol(value)
|
||||
} catch (ignored: IllegalStateException) {
|
||||
null
|
||||
} ?: arguments.getValue(StringSymbol(value))
|
||||
|
||||
override fun unaryOperationFunction(operation: String): (arg: T) -> T = algebra.unaryOperationFunction(operation)
|
||||
override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = algebra.binaryOperationFunction(operation)
|
||||
override fun unaryOperation(operation: String, arg: T): T =
|
||||
algebra.unaryOperation(operation, arg)
|
||||
|
||||
override fun binaryOperation(operation: String, left: T, right: T): T =
|
||||
algebra.binaryOperation(operation, left, right)
|
||||
|
||||
override fun unaryOperationFunction(operation: String): (arg: T) -> T =
|
||||
algebra.unaryOperationFunction(operation)
|
||||
|
||||
override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T =
|
||||
algebra.binaryOperationFunction(operation)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun number(value: Number): T = if (algebra is NumericAlgebra<*>)
|
||||
@ -45,13 +56,13 @@ public inline fun <reified T : Any, A : Algebra<T>, E : Algebra<MST>> A.mst(
|
||||
): MstExpression<T, A> = MstExpression(this, mstAlgebra.block())
|
||||
|
||||
/**
|
||||
* Builds [MstExpression] over [Space].
|
||||
* Builds [MstExpression] over [Group].
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public inline fun <reified T : Any, A : Space<T>> A.mstInSpace(block: MstSpace.() -> MST): MstExpression<T, A> {
|
||||
public inline fun <reified T : Any, A : Group<T>> A.mstInGroup(block: MstGroup.() -> MST): MstExpression<T, A> {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return MstExpression(this, MstSpace.block())
|
||||
return MstExpression(this, MstGroup.block())
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,13 +96,13 @@ public inline fun <reified T : Any, A : ExtendedField<T>> A.mstInExtendedField(b
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds [MstExpression] over [FunctionalExpressionSpace].
|
||||
* Builds [MstExpression] over [FunctionalExpressionGroup].
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public inline fun <reified T : Any, A : Space<T>> FunctionalExpressionSpace<T, A>.mstInSpace(block: MstSpace.() -> MST): MstExpression<T, A> {
|
||||
public inline fun <reified T : Any, A : Group<T>> FunctionalExpressionGroup<T, A>.mstInGroup(block: MstGroup.() -> MST): MstExpression<T, A> {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return algebra.mstInSpace(block)
|
||||
return algebra.mstInGroup(block)
|
||||
}
|
||||
|
||||
/**
|
@ -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 kscience.kmath.ast.MST.*
|
||||
import kscience.kmath.ast.MstExpression
|
||||
import kscience.kmath.estree.internal.ESTreeBuilder
|
||||
import kscience.kmath.estree.internal.estree.BaseExpression
|
||||
import kscience.kmath.expressions.Expression
|
||||
import kscience.kmath.operations.Algebra
|
||||
import kscience.kmath.operations.NumericAlgebra
|
||||
import space.kscience.kmath.ast.MST
|
||||
import space.kscience.kmath.ast.MST.*
|
||||
import space.kscience.kmath.ast.MstExpression
|
||||
import space.kscience.kmath.estree.internal.ESTreeBuilder
|
||||
import space.kscience.kmath.estree.internal.estree.BaseExpression
|
||||
import space.kscience.kmath.expressions.Expression
|
||||
import space.kscience.kmath.operations.Algebra
|
||||
import space.kscience.kmath.operations.NumericAlgebra
|
||||
|
||||
@PublishedApi
|
||||
internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
|
||||
fun ESTreeBuilder<T>.visit(node: MST): BaseExpression = when (node) {
|
||||
is Symbolic -> {
|
||||
val symbol = try {
|
||||
algebra.symbol(node.value)
|
||||
algebra.bindSymbol(node.value)
|
||||
} catch (ignored: IllegalStateException) {
|
||||
null
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package kscience.kmath.estree.internal
|
||||
package space.kscience.kmath.estree.internal
|
||||
|
||||
import kscience.kmath.estree.internal.astring.generate
|
||||
import kscience.kmath.estree.internal.estree.*
|
||||
import kscience.kmath.expressions.Expression
|
||||
import kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.estree.internal.astring.generate
|
||||
import space.kscience.kmath.estree.internal.estree.*
|
||||
import space.kscience.kmath.expressions.Expression
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
|
||||
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {
|
||||
private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> {
|
@ -1,9 +1,9 @@
|
||||
@file:JsModule("astring")
|
||||
@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 {
|
||||
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 {
|
||||
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 {
|
||||
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
|
||||
|
@ -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> {
|
||||
var done: Boolean?
|
@ -1,6 +1,6 @@
|
||||
@file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION")
|
||||
|
||||
package kscience.kmath.estree.internal.tsstdlib
|
||||
package space.kscience.kmath.estree.internal.tsstdlib
|
||||
|
||||
import kotlin.js.RegExp
|
||||
|
@ -1,41 +0,0 @@
|
||||
package kscience.kmath.estree
|
||||
|
||||
import kscience.kmath.ast.mstInExtendedField
|
||||
import kscience.kmath.ast.mstInField
|
||||
import kscience.kmath.ast.mstInSpace
|
||||
import kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.RealField
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestESTreeOperationsSupport {
|
||||
@Test
|
||||
fun testUnaryOperationInvocation() {
|
||||
val expression = RealField.mstInSpace { -symbol("x") }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-2.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBinaryOperationInvocation() {
|
||||
val expression = RealField.mstInSpace { -symbol("x") + number(1.0) }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-1.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConstProductInvocation() {
|
||||
val res = RealField.mstInField { symbol("x") * 2 }("x" to 2.0)
|
||||
assertEquals(4.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultipleCalls() {
|
||||
val e = RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile()
|
||||
val r = Random(0)
|
||||
var s = 0.0
|
||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||
println(s)
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package kscience.kmath.estree
|
||||
|
||||
import kscience.kmath.ast.mstInField
|
||||
import kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.RealField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestESTreeSpecialization {
|
||||
@Test
|
||||
fun testUnaryPlus() {
|
||||
val expr = RealField.mstInField { unaryOperationFunction("+")(symbol("x")) }.compile()
|
||||
assertEquals(2.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnaryMinus() {
|
||||
val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile()
|
||||
assertEquals(-2.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAdd() {
|
||||
val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile()
|
||||
assertEquals(4.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSine() {
|
||||
val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile()
|
||||
assertEquals(0.0, expr("x" to 0.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMinus() {
|
||||
val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile()
|
||||
assertEquals(0.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDivide() {
|
||||
val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile()
|
||||
assertEquals(1.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
val expr = RealField
|
||||
.mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) }
|
||||
.compile()
|
||||
|
||||
assertEquals(4.0, expr("x" to 2.0))
|
||||
}
|
||||
}
|
@ -1,41 +1,41 @@
|
||||
package kscience.kmath.estree
|
||||
package space.kscience.kmath.estree
|
||||
|
||||
import kscience.kmath.ast.*
|
||||
import kscience.kmath.complex.ComplexField
|
||||
import kscience.kmath.complex.toComplex
|
||||
import kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.ByteRing
|
||||
import kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.ast.*
|
||||
import space.kscience.kmath.complex.ComplexField
|
||||
import space.kscience.kmath.complex.toComplex
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.ByteRing
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestESTreeConsistencyWithInterpreter {
|
||||
@Test
|
||||
fun mstSpace() {
|
||||
val res1 = MstSpace.mstInSpace {
|
||||
val res1 = MstGroup.mstInGroup {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
number(3.toByte()) - (number(2.toByte()) + (multiply(
|
||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
||||
add(number(1), number(1)),
|
||||
2
|
||||
2.0
|
||||
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
|
||||
),
|
||||
|
||||
number(1)
|
||||
) + symbol("x") + zero
|
||||
) + bindSymbol("x") + zero
|
||||
}("x" to MST.Numeric(2))
|
||||
|
||||
val res2 = MstSpace.mstInSpace {
|
||||
val res2 = MstGroup.mstInGroup {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
number(3.toByte()) - (number(2.toByte()) + (multiply(
|
||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
||||
add(number(1), number(1)),
|
||||
2
|
||||
2.0
|
||||
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
|
||||
),
|
||||
|
||||
number(1)
|
||||
) + symbol("x") + zero
|
||||
) + bindSymbol("x") + zero
|
||||
}.compile()("x" to MST.Numeric(2))
|
||||
|
||||
assertEquals(res1, res2)
|
||||
@ -46,9 +46,9 @@ internal class TestESTreeConsistencyWithInterpreter {
|
||||
val res1 = ByteRing.mstInRing {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
(symbol("x") - (2.toByte() + (multiply(
|
||||
(bindSymbol("x") - (2.toByte() + (scale(
|
||||
add(number(1), number(1)),
|
||||
2
|
||||
2.0
|
||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
||||
),
|
||||
|
||||
@ -59,9 +59,9 @@ internal class TestESTreeConsistencyWithInterpreter {
|
||||
val res2 = ByteRing.mstInRing {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
(symbol("x") - (2.toByte() + (multiply(
|
||||
(bindSymbol("x") - (2.toByte() + (scale(
|
||||
add(number(1), number(1)),
|
||||
2
|
||||
2.0
|
||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
||||
),
|
||||
number(1)
|
||||
@ -73,17 +73,17 @@ internal class TestESTreeConsistencyWithInterpreter {
|
||||
|
||||
@Test
|
||||
fun realField() {
|
||||
val res1 = RealField.mstInField {
|
||||
val res1 = DoubleField.mstInField {
|
||||
+(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") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}("x" to 2.0)
|
||||
|
||||
val res2 = RealField.mstInField {
|
||||
val res2 = DoubleField.mstInField {
|
||||
+(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") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
@ -96,7 +96,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
||||
fun complexField() {
|
||||
val res1 = ComplexField.mstInField {
|
||||
+(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") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
@ -104,7 +104,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
||||
|
||||
val res2 = ComplexField.mstInField {
|
||||
+(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") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
@ -0,0 +1,43 @@
|
||||
package space.kscience.kmath.estree
|
||||
|
||||
import space.kscience.kmath.ast.mstInExtendedField
|
||||
import space.kscience.kmath.ast.mstInField
|
||||
import space.kscience.kmath.ast.mstInGroup
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestESTreeOperationsSupport {
|
||||
@Test
|
||||
fun testUnaryOperationInvocation() {
|
||||
val expression = DoubleField.mstInGroup { -bindSymbol("x") }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-2.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBinaryOperationInvocation() {
|
||||
val expression = DoubleField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-1.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConstProductInvocation() {
|
||||
val res = DoubleField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
||||
assertEquals(4.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultipleCalls() {
|
||||
val e =
|
||||
DoubleField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
|
||||
.compile()
|
||||
val r = Random(0)
|
||||
var s = 0.0
|
||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||
println(s)
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package space.kscience.kmath.estree
|
||||
|
||||
import space.kscience.kmath.ast.mstInField
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestESTreeSpecialization {
|
||||
@Test
|
||||
fun testUnaryPlus() {
|
||||
val expr = DoubleField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
||||
assertEquals(2.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnaryMinus() {
|
||||
val expr = DoubleField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
||||
assertEquals(-2.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAdd() {
|
||||
val expr = DoubleField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||
assertEquals(4.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSine() {
|
||||
val expr = DoubleField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
||||
assertEquals(0.0, expr("x" to 0.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMinus() {
|
||||
val expr = DoubleField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||
assertEquals(0.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDivide() {
|
||||
val expr = DoubleField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||
assertEquals(1.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
val expr = DoubleField
|
||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||
.compile()
|
||||
|
||||
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 kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.ByteRing
|
||||
import space.kscience.kmath.ast.mstInRing
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.ByteRing
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
@ -10,13 +10,13 @@ import kotlin.test.assertFailsWith
|
||||
internal class TestESTreeVariables {
|
||||
@Test
|
||||
fun testVariable() {
|
||||
val expr = ByteRing.mstInRing { symbol("x") }.compile()
|
||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUndefinedVariableFails() {
|
||||
val expr = ByteRing.mstInRing { symbol("x") }.compile()
|
||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||
assertFailsWith<NoSuchElementException> { expr() }
|
||||
}
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
package kscience.kmath.asm
|
||||
package space.kscience.kmath.asm
|
||||
|
||||
import kscience.kmath.asm.internal.AsmBuilder
|
||||
import kscience.kmath.asm.internal.buildName
|
||||
import kscience.kmath.ast.MST
|
||||
import kscience.kmath.ast.MST.*
|
||||
import kscience.kmath.ast.MstExpression
|
||||
import kscience.kmath.expressions.Expression
|
||||
import kscience.kmath.operations.Algebra
|
||||
import kscience.kmath.operations.NumericAlgebra
|
||||
import space.kscience.kmath.asm.internal.AsmBuilder
|
||||
import space.kscience.kmath.asm.internal.buildName
|
||||
import space.kscience.kmath.ast.MST
|
||||
import space.kscience.kmath.ast.MST.*
|
||||
import space.kscience.kmath.ast.MstExpression
|
||||
import space.kscience.kmath.expressions.Expression
|
||||
import space.kscience.kmath.operations.Algebra
|
||||
import space.kscience.kmath.operations.NumericAlgebra
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
is Symbolic -> {
|
||||
val symbol = try {
|
||||
algebra.symbol(node.value)
|
||||
algebra.bindSymbol(node.value)
|
||||
} catch (ignored: IllegalStateException) {
|
||||
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.Opcodes.*
|
||||
import org.objectweb.asm.Type.*
|
||||
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.MethodType
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.stream.Collectors.toMap
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
@ -310,7 +309,7 @@ internal class AsmBuilder<T>(
|
||||
/**
|
||||
* 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].
|
||||
@ -335,11 +334,11 @@ internal class AsmBuilder<T>(
|
||||
/**
|
||||
* 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].
|
||||
*/
|
||||
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.commons.InstructionAdapter
|
||||
import space.kscience.kmath.ast.MST
|
||||
import space.kscience.kmath.expressions.Expression
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@ -86,7 +86,7 @@ internal inline fun ClassWriter.visitField(
|
||||
descriptor: String,
|
||||
signature: String?,
|
||||
value: Any?,
|
||||
block: FieldVisitor.() -> Unit
|
||||
block: FieldVisitor.() -> Unit,
|
||||
): FieldVisitor {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return visitField(access, name, descriptor, signature, value).apply(block)
|
@ -1,9 +1,9 @@
|
||||
@file:JvmName("MapIntrinsics")
|
||||
|
||||
package kscience.kmath.asm.internal
|
||||
package space.kscience.kmath.asm.internal
|
||||
|
||||
import kscience.kmath.expressions.StringSymbol
|
||||
import kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.StringSymbol
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
|
||||
/**
|
||||
* 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.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.parser.ParseResult
|
||||
import com.github.h0tk3y.betterParse.parser.Parser
|
||||
import kscience.kmath.operations.FieldOperations
|
||||
import kscience.kmath.operations.PowerOperations
|
||||
import kscience.kmath.operations.RingOperations
|
||||
import kscience.kmath.operations.SpaceOperations
|
||||
import space.kscience.kmath.operations.FieldOperations
|
||||
import space.kscience.kmath.operations.GroupOperations
|
||||
import space.kscience.kmath.operations.PowerOperations
|
||||
import space.kscience.kmath.operations.RingOperations
|
||||
|
||||
/**
|
||||
* better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4.
|
||||
@ -25,8 +25,8 @@ import kscience.kmath.operations.SpaceOperations
|
||||
*/
|
||||
public object ArithmeticsEvaluator : Grammar<MST>() {
|
||||
// TODO replace with "...".toRegex() when better-parse 0.4.1 is released
|
||||
private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?")
|
||||
private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*")
|
||||
private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?".toRegex())
|
||||
private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*".toRegex())
|
||||
private val lpar: Token by literalToken("(")
|
||||
private val rpar: Token by literalToken(")")
|
||||
private val comma: Token by literalToken(",")
|
||||
@ -35,7 +35,7 @@ public object ArithmeticsEvaluator : Grammar<MST>() {
|
||||
private val div: Token by literalToken("/")
|
||||
private val minus: Token by literalToken("-")
|
||||
private val plus: Token by literalToken("+")
|
||||
private val ws: Token by regexToken("\\s+", 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 singular: Parser<MST> by id use { MST.Symbolic(text) }
|
||||
@ -55,7 +55,7 @@ public object ArithmeticsEvaluator : Grammar<MST>() {
|
||||
.or(binaryFunction)
|
||||
.or(unaryFunction)
|
||||
.or(singular)
|
||||
.or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(SpaceOperations.MINUS_OPERATION, it) })
|
||||
.or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(GroupOperations.MINUS_OPERATION, it) })
|
||||
.or(-lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar)
|
||||
|
||||
private val powChain: Parser<MST> by leftAssociative(term = term, operator = pow) { a, _, b ->
|
||||
@ -77,9 +77,9 @@ public object ArithmeticsEvaluator : Grammar<MST>() {
|
||||
operator = plus or minus use TokenMatch::type
|
||||
) { a, op, b ->
|
||||
if (op == plus)
|
||||
MST.Binary(SpaceOperations.PLUS_OPERATION, a, b)
|
||||
MST.Binary(GroupOperations.PLUS_OPERATION, a, b)
|
||||
else
|
||||
MST.Binary(SpaceOperations.MINUS_OPERATION, a, b)
|
||||
MST.Binary(GroupOperations.MINUS_OPERATION, a, b)
|
||||
}
|
||||
|
||||
override val rootParser: Parser<MST> by subSumChain
|
@ -1,41 +0,0 @@
|
||||
package kscience.kmath.asm
|
||||
|
||||
import kscience.kmath.ast.mstInExtendedField
|
||||
import kscience.kmath.ast.mstInField
|
||||
import kscience.kmath.ast.mstInSpace
|
||||
import kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.RealField
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestAsmOperationsSupport {
|
||||
@Test
|
||||
fun testUnaryOperationInvocation() {
|
||||
val expression = RealField.mstInSpace { -symbol("x") }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-2.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBinaryOperationInvocation() {
|
||||
val expression = RealField.mstInSpace { -symbol("x") + number(1.0) }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-1.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConstProductInvocation() {
|
||||
val res = RealField.mstInField { symbol("x") * 2 }("x" to 2.0)
|
||||
assertEquals(4.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultipleCalls() {
|
||||
val e = RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile()
|
||||
val r = Random(0)
|
||||
var s = 0.0
|
||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||
println(s)
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package kscience.kmath.asm
|
||||
|
||||
import kscience.kmath.ast.mstInField
|
||||
import kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.RealField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestAsmSpecialization {
|
||||
@Test
|
||||
fun testUnaryPlus() {
|
||||
val expr = RealField.mstInField { unaryOperationFunction("+")(symbol("x")) }.compile()
|
||||
assertEquals(2.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnaryMinus() {
|
||||
val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile()
|
||||
assertEquals(-2.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAdd() {
|
||||
val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile()
|
||||
assertEquals(4.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSine() {
|
||||
val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile()
|
||||
assertEquals(0.0, expr("x" to 0.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMinus() {
|
||||
val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile()
|
||||
assertEquals(0.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDivide() {
|
||||
val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile()
|
||||
assertEquals(1.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
val expr = RealField
|
||||
.mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) }
|
||||
.compile()
|
||||
|
||||
assertEquals(4.0, expr("x" to 2.0))
|
||||
}
|
||||
}
|
@ -1,40 +1,41 @@
|
||||
package kscience.kmath.asm
|
||||
package space.kscience.kmath.asm
|
||||
|
||||
import kscience.kmath.ast.*
|
||||
import kscience.kmath.complex.*
|
||||
import kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.ByteRing
|
||||
import kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.ast.*
|
||||
import space.kscience.kmath.complex.ComplexField
|
||||
import space.kscience.kmath.complex.toComplex
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.ByteRing
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestAsmConsistencyWithInterpreter {
|
||||
@Test
|
||||
fun mstSpace() {
|
||||
val res1 = MstSpace.mstInSpace {
|
||||
val res1 = MstGroup.mstInGroup {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
number(3.toByte()) - (number(2.toByte()) + (multiply(
|
||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
||||
add(number(1), number(1)),
|
||||
2
|
||||
2.0
|
||||
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
|
||||
),
|
||||
|
||||
number(1)
|
||||
) + symbol("x") + zero
|
||||
) + bindSymbol("x") + zero
|
||||
}("x" to MST.Numeric(2))
|
||||
|
||||
val res2 = MstSpace.mstInSpace {
|
||||
val res2 = MstGroup.mstInGroup {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
number(3.toByte()) - (number(2.toByte()) + (multiply(
|
||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
||||
add(number(1), number(1)),
|
||||
2
|
||||
2.0
|
||||
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
|
||||
),
|
||||
|
||||
number(1)
|
||||
) + symbol("x") + zero
|
||||
) + bindSymbol("x") + zero
|
||||
}.compile()("x" to MST.Numeric(2))
|
||||
|
||||
assertEquals(res1, res2)
|
||||
@ -45,9 +46,9 @@ internal class TestAsmConsistencyWithInterpreter {
|
||||
val res1 = ByteRing.mstInRing {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
(symbol("x") - (2.toByte() + (multiply(
|
||||
(bindSymbol("x") - (2.toByte() + (scale(
|
||||
add(number(1), number(1)),
|
||||
2
|
||||
2.0
|
||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
||||
),
|
||||
|
||||
@ -58,9 +59,9 @@ internal class TestAsmConsistencyWithInterpreter {
|
||||
val res2 = ByteRing.mstInRing {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
(symbol("x") - (2.toByte() + (multiply(
|
||||
(bindSymbol("x") - (2.toByte() + (scale(
|
||||
add(number(1), number(1)),
|
||||
2
|
||||
2.0
|
||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
||||
),
|
||||
number(1)
|
||||
@ -72,17 +73,17 @@ internal class TestAsmConsistencyWithInterpreter {
|
||||
|
||||
@Test
|
||||
fun realField() {
|
||||
val res1 = RealField.mstInField {
|
||||
val res1 = DoubleField.mstInField {
|
||||
+(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") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}("x" to 2.0)
|
||||
|
||||
val res2 = RealField.mstInField {
|
||||
val res2 = DoubleField.mstInField {
|
||||
+(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") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
@ -95,7 +96,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
||||
fun complexField() {
|
||||
val res1 = ComplexField.mstInField {
|
||||
+(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") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
@ -103,7 +104,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
||||
|
||||
val res2 = ComplexField.mstInField {
|
||||
+(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") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
@ -0,0 +1,43 @@
|
||||
package space.kscience.kmath.asm
|
||||
|
||||
import space.kscience.kmath.ast.mstInExtendedField
|
||||
import space.kscience.kmath.ast.mstInField
|
||||
import space.kscience.kmath.ast.mstInGroup
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestAsmOperationsSupport {
|
||||
@Test
|
||||
fun testUnaryOperationInvocation() {
|
||||
val expression = DoubleField.mstInGroup { -bindSymbol("x") }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-2.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBinaryOperationInvocation() {
|
||||
val expression = DoubleField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-1.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConstProductInvocation() {
|
||||
val res = DoubleField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
||||
assertEquals(4.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultipleCalls() {
|
||||
val e =
|
||||
DoubleField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
|
||||
.compile()
|
||||
val r = Random(0)
|
||||
var s = 0.0
|
||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||
println(s)
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package space.kscience.kmath.asm
|
||||
|
||||
import space.kscience.kmath.ast.mstInField
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestAsmSpecialization {
|
||||
@Test
|
||||
fun testUnaryPlus() {
|
||||
val expr = DoubleField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
||||
assertEquals(2.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnaryMinus() {
|
||||
val expr = DoubleField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
||||
assertEquals(-2.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAdd() {
|
||||
val expr = DoubleField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||
assertEquals(4.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSine() {
|
||||
val expr = DoubleField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
||||
assertEquals(0.0, expr("x" to 0.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMinus() {
|
||||
val expr = DoubleField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||
assertEquals(0.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDivide() {
|
||||
val expr = DoubleField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||
assertEquals(1.0, expr("x" to 2.0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
val expr = DoubleField
|
||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||
.compile()
|
||||
|
||||
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 kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.ByteRing
|
||||
import space.kscience.kmath.ast.mstInRing
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.ByteRing
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
@ -10,13 +10,13 @@ import kotlin.test.assertFailsWith
|
||||
internal class TestAsmVariables {
|
||||
@Test
|
||||
fun testVariable() {
|
||||
val expr = ByteRing.mstInRing { symbol("x") }.compile()
|
||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUndefinedVariableFails() {
|
||||
val expr = ByteRing.mstInRing { symbol("x") }.compile()
|
||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||
assertFailsWith<NoSuchElementException> { expr() }
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
package kscience.kmath.ast
|
||||
package space.kscience.kmath.ast
|
||||
|
||||
import kscience.kmath.operations.Field
|
||||
import kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.Field
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class ParserPrecedenceTest {
|
||||
private val f: Field<Double> = RealField
|
||||
private val f: Field<Double> = DoubleField
|
||||
|
||||
@Test
|
||||
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
|
@ -1,10 +1,10 @@
|
||||
package kscience.kmath.ast
|
||||
package space.kscience.kmath.ast
|
||||
|
||||
import kscience.kmath.complex.Complex
|
||||
import kscience.kmath.complex.ComplexField
|
||||
import kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.Algebra
|
||||
import kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.complex.Complex
|
||||
import space.kscience.kmath.complex.ComplexField
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.Algebra
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -33,14 +33,14 @@ internal class ParserTest {
|
||||
@Test
|
||||
fun `evaluate MST with unary function`() {
|
||||
val mst = "sin(0)".parseMath()
|
||||
val res = RealField.evaluate(mst)
|
||||
val res = DoubleField.evaluate(mst)
|
||||
assertEquals(0.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `evaluate MST with binary function`() {
|
||||
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 {
|
||||
throw NotImplementedError()
|
@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.jvm")
|
||||
id("ru.mipt.npm.gradle.jvm")
|
||||
}
|
||||
description = "Commons math binding for kmath"
|
||||
|
||||
|
@ -1,118 +0,0 @@
|
||||
package kscience.kmath.commons.linear
|
||||
|
||||
import kscience.kmath.linear.*
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.structures.RealBuffer
|
||||
import org.apache.commons.math3.linear.*
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.cast
|
||||
|
||||
public inline class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
|
||||
public override val rowNum: Int get() = origin.rowDimension
|
||||
public override val colNum: Int get() = origin.columnDimension
|
||||
|
||||
@UnstableKMathAPI
|
||||
override fun <T : Any> getFeature(type: KClass<T>): T? = when (type) {
|
||||
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
|
||||
}?.let(type::cast)
|
||||
|
||||
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
|
||||
}
|
||||
|
||||
|
||||
public fun RealMatrix.asMatrix(): CMMatrix = CMMatrix(this)
|
||||
|
||||
public class CMVector(public val origin: RealVector) : Point<Double> {
|
||||
public override val size: Int get() = origin.dimension
|
||||
|
||||
public override operator fun get(index: Int): Double = origin.getEntry(index)
|
||||
|
||||
public override operator fun iterator(): Iterator<Double> = origin.toArray().iterator()
|
||||
}
|
||||
|
||||
public fun Point<Double>.toCM(): CMVector = if (this is CMVector) this else {
|
||||
val array = DoubleArray(size) { this[it] }
|
||||
CMVector(ArrayRealVector(array))
|
||||
}
|
||||
|
||||
public fun RealVector.toPoint(): CMVector = CMVector(this)
|
||||
|
||||
public object CMMatrixContext : MatrixContext<Double, CMMatrix> {
|
||||
public override fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> Double): CMMatrix {
|
||||
val array = Array(rows) { i -> DoubleArray(columns) { j -> initializer(i, j) } }
|
||||
return CMMatrix(Array2DRowRealMatrix(array))
|
||||
}
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public fun Matrix<Double>.toCM(): CMMatrix = when (val matrix = origin) {
|
||||
is CMMatrix -> matrix
|
||||
else -> {
|
||||
//TODO add feature analysis
|
||||
val array = Array(rowNum) { i -> DoubleArray(colNum) { j -> get(i, j) } }
|
||||
CMMatrix(Array2DRowRealMatrix(array))
|
||||
}
|
||||
}
|
||||
|
||||
public override fun Matrix<Double>.dot(other: Matrix<Double>): CMMatrix =
|
||||
CMMatrix(toCM().origin.multiply(other.toCM().origin))
|
||||
|
||||
public override fun Matrix<Double>.dot(vector: Point<Double>): CMVector =
|
||||
CMVector(toCM().origin.preMultiply(vector.toCM().origin))
|
||||
|
||||
public override operator fun Matrix<Double>.unaryMinus(): CMMatrix =
|
||||
produce(rowNum, colNum) { i, j -> -get(i, j) }
|
||||
|
||||
public override fun add(a: Matrix<Double>, b: Matrix<Double>): CMMatrix =
|
||||
CMMatrix(a.toCM().origin.multiply(b.toCM().origin))
|
||||
|
||||
public override operator fun Matrix<Double>.minus(b: Matrix<Double>): CMMatrix =
|
||||
CMMatrix(toCM().origin.subtract(b.toCM().origin))
|
||||
|
||||
public override fun multiply(a: Matrix<Double>, k: Number): CMMatrix =
|
||||
CMMatrix(a.toCM().origin.scalarMultiply(k.toDouble()))
|
||||
|
||||
public override operator fun Matrix<Double>.times(value: Double): CMMatrix =
|
||||
produce(rowNum, colNum) { i, j -> get(i, j) * value }
|
||||
}
|
||||
|
||||
public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix =
|
||||
CMMatrix(origin.add(other.origin))
|
||||
|
||||
public operator fun CMMatrix.minus(other: CMMatrix): CMMatrix =
|
||||
CMMatrix(origin.subtract(other.origin))
|
||||
|
||||
public infix fun CMMatrix.dot(other: CMMatrix): CMMatrix =
|
||||
CMMatrix(origin.multiply(other.origin))
|
@ -1,10 +1,12 @@
|
||||
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 space.kscience.kmath.expressions.*
|
||||
import space.kscience.kmath.misc.StringSymbol
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.ExtendedField
|
||||
import space.kscience.kmath.operations.NumbersAddOperations
|
||||
|
||||
/**
|
||||
* A field over commons-math [DerivativeStructure].
|
||||
@ -16,7 +18,8 @@ import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
||||
public class DerivativeStructureField(
|
||||
public val order: Int,
|
||||
bindings: Map<Symbol, Double>,
|
||||
) : ExtendedField<DerivativeStructure>, ExpressionAlgebra<Double, DerivativeStructure>, RingWithNumbers<DerivativeStructure> {
|
||||
) : ExtendedField<DerivativeStructure>, ExpressionAlgebra<Double, DerivativeStructure>,
|
||||
NumbersAddOperations<DerivativeStructure> {
|
||||
public val numberOfVariables: Int = bindings.size
|
||||
|
||||
public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) }
|
||||
@ -48,11 +51,11 @@ public class DerivativeStructureField(
|
||||
|
||||
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)
|
||||
|
||||
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 {
|
||||
require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" }
|
||||
@ -62,13 +65,11 @@ public class DerivativeStructureField(
|
||||
|
||||
public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList())
|
||||
|
||||
override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate()
|
||||
|
||||
public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b)
|
||||
|
||||
public override fun multiply(a: DerivativeStructure, k: Number): DerivativeStructure = when (k) {
|
||||
is Double -> a.multiply(k)
|
||||
is Int -> a.multiply(k)
|
||||
else -> a.multiply(k.toDouble())
|
||||
}
|
||||
public override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value)
|
||||
|
||||
public override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b)
|
||||
public override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b)
|
@ -0,0 +1,92 @@
|
||||
package space.kscience.kmath.commons.integration
|
||||
|
||||
import org.apache.commons.math3.analysis.integration.IterativeLegendreGaussIntegrator
|
||||
import org.apache.commons.math3.analysis.integration.SimpsonIntegrator
|
||||
import space.kscience.kmath.integration.*
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
|
||||
/**
|
||||
* Integration wrapper for Common-maths UnivariateIntegrator
|
||||
*/
|
||||
public class CMIntegrator(
|
||||
private val defaultMaxCalls: Int = 200,
|
||||
public val integratorBuilder: (Integrand) -> org.apache.commons.math3.analysis.integration.UnivariateIntegrator,
|
||||
) : UnivariateIntegrator<Double> {
|
||||
|
||||
public class TargetRelativeAccuracy(public val value: Double) : IntegrandFeature
|
||||
public class TargetAbsoluteAccuracy(public val value: Double) : IntegrandFeature
|
||||
|
||||
public class MinIterations(public val value: Int) : IntegrandFeature
|
||||
public class MaxIterations(public val value: Int) : IntegrandFeature
|
||||
|
||||
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
|
||||
val integrator = integratorBuilder(integrand)
|
||||
val maxCalls = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: defaultMaxCalls
|
||||
val remainingCalls = maxCalls - integrand.calls
|
||||
val range = integrand.getFeature<IntegrationRange<Double>>()?.range
|
||||
?: error("Integration range is not provided")
|
||||
val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive)
|
||||
|
||||
return integrand +
|
||||
IntegrandValue(res) +
|
||||
IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy) +
|
||||
IntegrandRelativeAccuracy(integrator.relativeAccuracy) +
|
||||
IntegrandCalls(integrator.evaluations + integrand.calls)
|
||||
}
|
||||
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* Create a Simpson integrator based on [SimpsonIntegrator]
|
||||
*/
|
||||
public fun simpson(defaultMaxCalls: Int = 200): CMIntegrator = CMIntegrator(defaultMaxCalls) { integrand ->
|
||||
val absoluteAccuracy = integrand.getFeature<TargetAbsoluteAccuracy>()?.value
|
||||
?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY
|
||||
val relativeAccuracy = integrand.getFeature<TargetRelativeAccuracy>()?.value
|
||||
?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY
|
||||
val minIterations = integrand.getFeature<MinIterations>()?.value
|
||||
?: SimpsonIntegrator.DEFAULT_MIN_ITERATIONS_COUNT
|
||||
val maxIterations = integrand.getFeature<MaxIterations>()?.value
|
||||
?: SimpsonIntegrator.SIMPSON_MAX_ITERATIONS_COUNT
|
||||
|
||||
SimpsonIntegrator(relativeAccuracy, absoluteAccuracy, minIterations, maxIterations)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Gauss-Legandre integrator based on [IterativeLegendreGaussIntegrator]
|
||||
*/
|
||||
public fun legandre(numPoints: Int, defaultMaxCalls: Int = numPoints * 5): CMIntegrator =
|
||||
CMIntegrator(defaultMaxCalls) { integrand ->
|
||||
val absoluteAccuracy = integrand.getFeature<TargetAbsoluteAccuracy>()?.value
|
||||
?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY
|
||||
val relativeAccuracy = integrand.getFeature<TargetRelativeAccuracy>()?.value
|
||||
?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY
|
||||
val minIterations = integrand.getFeature<MinIterations>()?.value
|
||||
?: IterativeLegendreGaussIntegrator.DEFAULT_MIN_ITERATIONS_COUNT
|
||||
val maxIterations = integrand.getFeature<MaxIterations>()?.value
|
||||
?: IterativeLegendreGaussIntegrator.DEFAULT_MAX_ITERATIONS_COUNT
|
||||
|
||||
IterativeLegendreGaussIntegrator(
|
||||
numPoints,
|
||||
relativeAccuracy,
|
||||
absoluteAccuracy,
|
||||
minIterations,
|
||||
maxIterations
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableKMathAPI
|
||||
public var MutableList<IntegrandFeature>.targetAbsoluteAccuracy: Double?
|
||||
get() = filterIsInstance<CMIntegrator.TargetAbsoluteAccuracy>().lastOrNull()?.value
|
||||
set(value) {
|
||||
value?.let { add(CMIntegrator.TargetAbsoluteAccuracy(value)) }
|
||||
}
|
||||
|
||||
@UnstableKMathAPI
|
||||
public var MutableList<IntegrandFeature>.targetRelativeAccuracy: Double?
|
||||
get() = filterIsInstance<CMIntegrator.TargetRelativeAccuracy>().lastOrNull()?.value
|
||||
set(value) {
|
||||
value?.let { add(CMIntegrator.TargetRelativeAccuracy(value)) }
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2015 Alexander Nozik.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package space.kscience.kmath.commons.integration
|
||||
|
||||
import org.apache.commons.math3.analysis.integration.gauss.GaussIntegrator
|
||||
import org.apache.commons.math3.analysis.integration.gauss.GaussIntegratorFactory
|
||||
import space.kscience.kmath.integration.*
|
||||
|
||||
/**
|
||||
* A simple one-pass integrator based on Gauss rule
|
||||
*/
|
||||
public class GaussRuleIntegrator(
|
||||
private val numpoints: Int,
|
||||
private var type: GaussRule = GaussRule.LEGANDRE,
|
||||
) : UnivariateIntegrator<Double> {
|
||||
|
||||
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
|
||||
val range = integrand.getFeature<IntegrationRange<Double>>()?.range
|
||||
?: error("Integration range is not provided")
|
||||
val integrator: GaussIntegrator = getIntegrator(range)
|
||||
//TODO check performance
|
||||
val res: Double = integrator.integrate(integrand.function)
|
||||
return integrand + IntegrandValue(res) + IntegrandCalls(integrand.calls + numpoints)
|
||||
}
|
||||
|
||||
private fun getIntegrator(range: ClosedRange<Double>): GaussIntegrator {
|
||||
return when (type) {
|
||||
GaussRule.LEGANDRE -> factory.legendre(
|
||||
numpoints,
|
||||
range.start,
|
||||
range.endInclusive
|
||||
)
|
||||
GaussRule.LEGANDREHP -> factory.legendreHighPrecision(
|
||||
numpoints,
|
||||
range.start,
|
||||
range.endInclusive
|
||||
)
|
||||
GaussRule.UNIFORM -> GaussIntegrator(
|
||||
getUniformRule(
|
||||
range.start,
|
||||
range.endInclusive,
|
||||
numpoints
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUniformRule(
|
||||
min: Double,
|
||||
max: Double,
|
||||
numPoints: Int,
|
||||
): org.apache.commons.math3.util.Pair<DoubleArray, DoubleArray> {
|
||||
assert(numPoints > 2)
|
||||
val points = DoubleArray(numPoints)
|
||||
val weights = DoubleArray(numPoints)
|
||||
val step = (max - min) / (numPoints - 1)
|
||||
points[0] = min
|
||||
for (i in 1 until numPoints) {
|
||||
points[i] = points[i - 1] + step
|
||||
weights[i] = step
|
||||
}
|
||||
return org.apache.commons.math3.util.Pair<DoubleArray, DoubleArray>(points, weights)
|
||||
}
|
||||
|
||||
public enum class GaussRule {
|
||||
UNIFORM, LEGANDRE, LEGANDREHP
|
||||
}
|
||||
|
||||
public companion object {
|
||||
private val factory: GaussIntegratorFactory = GaussIntegratorFactory()
|
||||
|
||||
public fun integrate(
|
||||
range: ClosedRange<Double>,
|
||||
numPoints: Int = 100,
|
||||
type: GaussRule = GaussRule.LEGANDRE,
|
||||
function: (Double) -> Double,
|
||||
): Double = GaussRuleIntegrator(numPoints, type).integrate(
|
||||
UnivariateIntegrand(function, IntegrationRange(range))
|
||||
).value!!
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
package space.kscience.kmath.commons.linear
|
||||
|
||||
import org.apache.commons.math3.linear.*
|
||||
import space.kscience.kmath.linear.*
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.StructureFeature
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.cast
|
||||
|
||||
public inline class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
|
||||
public override val rowNum: Int get() = origin.rowDimension
|
||||
public override val colNum: Int get() = origin.columnDimension
|
||||
|
||||
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
|
||||
}
|
||||
|
||||
public inline class CMVector(public val origin: RealVector) : Point<Double> {
|
||||
public override val size: Int get() = origin.dimension
|
||||
|
||||
public override operator fun get(index: Int): Double = origin.getEntry(index)
|
||||
|
||||
public override operator fun iterator(): Iterator<Double> = origin.toArray().iterator()
|
||||
}
|
||||
|
||||
public fun RealVector.toPoint(): CMVector = CMVector(this)
|
||||
|
||||
public object CMLinearSpace : LinearSpace<Double, DoubleField> {
|
||||
override val elementAlgebra: DoubleField get() = DoubleField
|
||||
|
||||
public override fun buildMatrix(
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
initializer: DoubleField.(i: Int, j: Int) -> Double,
|
||||
): CMMatrix {
|
||||
val array = Array(rows) { i -> DoubleArray(columns) { j -> DoubleField.initializer(i, j) } }
|
||||
return CMMatrix(Array2DRowRealMatrix(array))
|
||||
}
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public fun Matrix<Double>.toCM(): CMMatrix = when (val matrix = origin) {
|
||||
is CMMatrix -> matrix
|
||||
else -> {
|
||||
//TODO add feature analysis
|
||||
val array = Array(rowNum) { i -> DoubleArray(colNum) { j -> get(i, j) } }
|
||||
Array2DRowRealMatrix(array).wrap()
|
||||
}
|
||||
}
|
||||
|
||||
public fun Point<Double>.toCM(): CMVector = if (this is CMVector) this else {
|
||||
val array = DoubleArray(size) { this[it] }
|
||||
ArrayRealVector(array).wrap()
|
||||
}
|
||||
|
||||
internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this)
|
||||
internal fun RealVector.wrap(): CMVector = CMVector(this)
|
||||
|
||||
override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): Point<Double> =
|
||||
ArrayRealVector(DoubleArray(size) { DoubleField.initializer(it) }).wrap()
|
||||
|
||||
override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix =
|
||||
toCM().origin.add(other.toCM().origin).wrap()
|
||||
|
||||
override fun Point<Double>.plus(other: Point<Double>): CMVector =
|
||||
toCM().origin.add(other.toCM().origin).wrap()
|
||||
|
||||
override fun Point<Double>.minus(other: Point<Double>): CMVector =
|
||||
toCM().origin.subtract(other.toCM().origin).wrap()
|
||||
|
||||
public override fun Matrix<Double>.dot(other: Matrix<Double>): CMMatrix =
|
||||
toCM().origin.multiply(other.toCM().origin).wrap()
|
||||
|
||||
public override fun Matrix<Double>.dot(vector: Point<Double>): CMVector =
|
||||
toCM().origin.preMultiply(vector.toCM().origin).wrap()
|
||||
|
||||
public override operator fun Matrix<Double>.minus(other: Matrix<Double>): CMMatrix =
|
||||
toCM().origin.subtract(other.toCM().origin).wrap()
|
||||
|
||||
public override operator fun Matrix<Double>.times(value: Double): CMMatrix =
|
||||
toCM().origin.scalarMultiply(value).wrap()
|
||||
|
||||
override fun Double.times(m: Matrix<Double>): CMMatrix =
|
||||
m * this
|
||||
|
||||
override fun Point<Double>.times(value: Double): CMVector =
|
||||
toCM().origin.mapMultiply(value).wrap()
|
||||
|
||||
override fun Double.times(v: Point<Double>): CMVector =
|
||||
v * this
|
||||
|
||||
@UnstableKMathAPI
|
||||
override fun <F : StructureFeature> getFeature(structure: Matrix<Double>, type: KClass<out F>): F? {
|
||||
//Return the feature if it is intrinsic to the structure
|
||||
structure.getFeature(type)?.let { return it }
|
||||
|
||||
val origin = structure.toCM().origin
|
||||
|
||||
return when (type) {
|
||||
DiagonalFeature::class -> if (origin is DiagonalMatrix) DiagonalFeature else null
|
||||
|
||||
DeterminantFeature::class, LupDecompositionFeature::class -> object :
|
||||
DeterminantFeature<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 { DoubleBuffer(sv.singularValues) }
|
||||
}
|
||||
else -> null
|
||||
}?.let(type::cast)
|
||||
}
|
||||
}
|
||||
|
||||
public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix = CMMatrix(origin.add(other.origin))
|
||||
|
||||
public operator fun CMMatrix.minus(other: CMMatrix): CMMatrix = CMMatrix(origin.subtract(other.origin))
|
||||
|
||||
public infix fun CMMatrix.dot(other: CMMatrix): CMMatrix = CMMatrix(origin.multiply(other.origin))
|
@ -1,8 +1,8 @@
|
||||
package kscience.kmath.commons.linear
|
||||
package space.kscience.kmath.commons.linear
|
||||
|
||||
import kscience.kmath.linear.Matrix
|
||||
import kscience.kmath.linear.Point
|
||||
import org.apache.commons.math3.linear.*
|
||||
import space.kscience.kmath.linear.Matrix
|
||||
import space.kscience.kmath.linear.Point
|
||||
|
||||
public enum class CMDecomposition {
|
||||
LUP,
|
||||
@ -12,9 +12,9 @@ public enum class CMDecomposition {
|
||||
CHOLESKY
|
||||
}
|
||||
|
||||
public fun CMMatrixContext.solver(
|
||||
public fun CMLinearSpace.solver(
|
||||
a: Matrix<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): DecompositionSolver = when (decomposition) {
|
||||
CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver
|
||||
CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver
|
||||
@ -23,19 +23,19 @@ public fun CMMatrixContext.solver(
|
||||
CMDecomposition.CHOLESKY -> CholeskyDecomposition(a.toCM().origin).solver
|
||||
}
|
||||
|
||||
public fun CMMatrixContext.solve(
|
||||
public fun CMLinearSpace.solve(
|
||||
a: Matrix<Double>,
|
||||
b: Matrix<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).asMatrix()
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap()
|
||||
|
||||
public fun CMMatrixContext.solve(
|
||||
public fun CMLinearSpace.solve(
|
||||
a: Matrix<Double>,
|
||||
b: Point<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint()
|
||||
|
||||
public fun CMMatrixContext.inverse(
|
||||
public fun CMLinearSpace.inverse(
|
||||
a: Matrix<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
): CMMatrix = solver(a, decomposition).inverse.asMatrix()
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): CMMatrix = solver(a, decomposition).inverse.wrap()
|
@ -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.nonlinear.scalar.GoalType
|
||||
import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer
|
||||
@ -14,17 +9,36 @@ 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.NelderMeadSimplex
|
||||
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
|
||||
import space.kscience.kmath.expressions.DifferentiableExpression
|
||||
import space.kscience.kmath.expressions.Expression
|
||||
import space.kscience.kmath.expressions.SymbolIndexer
|
||||
import space.kscience.kmath.expressions.derivative
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.optimization.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
public operator fun PointValuePair.component1(): DoubleArray = point
|
||||
public operator fun PointValuePair.component2(): Double = value
|
||||
|
||||
public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
OptimizationProblem<Double>, SymbolIndexer, OptimizationFeature {
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class CMOptimization(
|
||||
override val symbols: List<Symbol>,
|
||||
) : FunctionOptimization<Double>, NoDerivFunctionOptimization<Double>, SymbolIndexer, OptimizationFeature {
|
||||
|
||||
private val optimizationData: HashMap<KClass<out OptimizationData>, OptimizationData> = HashMap()
|
||||
private var optimizatorBuilder: (() -> MultivariateOptimizer)? = null
|
||||
public var convergenceChecker: ConvergenceChecker<PointValuePair> = SimpleValueChecker(DEFAULT_RELATIVE_TOLERANCE,
|
||||
DEFAULT_ABSOLUTE_TOLERANCE, DEFAULT_MAX_ITER)
|
||||
private var optimizerBuilder: (() -> MultivariateOptimizer)? = null
|
||||
public var convergenceChecker: ConvergenceChecker<PointValuePair> = SimpleValueChecker(
|
||||
DEFAULT_RELATIVE_TOLERANCE,
|
||||
DEFAULT_ABSOLUTE_TOLERANCE,
|
||||
DEFAULT_MAX_ITER
|
||||
)
|
||||
|
||||
override var maximize: Boolean
|
||||
get() = optimizationData[GoalType::class] == GoalType.MAXIMIZE
|
||||
set(value) {
|
||||
optimizationData[GoalType::class] = if (value) GoalType.MAXIMIZE else GoalType.MINIMIZE
|
||||
}
|
||||
|
||||
public fun addOptimizationData(data: OptimizationData) {
|
||||
optimizationData[data::class] = data
|
||||
@ -40,7 +54,7 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
addOptimizationData(InitialGuess(map.toDoubleArray()))
|
||||
}
|
||||
|
||||
public override fun expression(expression: Expression<Double>): Unit {
|
||||
public override fun function(expression: Expression<Double>): Unit {
|
||||
val objectiveFunction = ObjectiveFunction {
|
||||
val args = it.toMap()
|
||||
expression(args)
|
||||
@ -48,8 +62,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
addOptimizationData(objectiveFunction)
|
||||
}
|
||||
|
||||
public override fun diffExpression(expression: DifferentiableExpression<Double, Expression<Double>>) {
|
||||
expression(expression)
|
||||
public override fun diffFunction(expression: DifferentiableExpression<Double, Expression<Double>>) {
|
||||
function(expression)
|
||||
val gradientFunction = ObjectiveFunctionGradient {
|
||||
val args = it.toMap()
|
||||
DoubleArray(symbols.size) { index ->
|
||||
@ -57,8 +71,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
}
|
||||
}
|
||||
addOptimizationData(gradientFunction)
|
||||
if (optimizatorBuilder == null) {
|
||||
optimizatorBuilder = {
|
||||
if (optimizerBuilder == null) {
|
||||
optimizerBuilder = {
|
||||
NonLinearConjugateGradientOptimizer(
|
||||
NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES,
|
||||
convergenceChecker
|
||||
@ -70,8 +84,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
public fun simplex(simplex: AbstractSimplex) {
|
||||
addOptimizationData(simplex)
|
||||
//Set optimization builder to simplex if it is not present
|
||||
if (optimizatorBuilder == null) {
|
||||
optimizatorBuilder = { SimplexOptimizer(convergenceChecker) }
|
||||
if (optimizerBuilder == null) {
|
||||
optimizerBuilder = { SimplexOptimizer(convergenceChecker) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +98,7 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
}
|
||||
|
||||
public fun optimizer(block: () -> MultivariateOptimizer) {
|
||||
optimizatorBuilder = block
|
||||
optimizerBuilder = block
|
||||
}
|
||||
|
||||
override fun update(result: OptimizationResult<Double>) {
|
||||
@ -92,19 +106,19 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
}
|
||||
|
||||
override fun optimize(): OptimizationResult<Double> {
|
||||
val optimizer = optimizatorBuilder?.invoke() ?: error("Optimizer not defined")
|
||||
val optimizer = optimizerBuilder?.invoke() ?: error("Optimizer not defined")
|
||||
val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray())
|
||||
return OptimizationResult(point.toMap(), value, setOf(this))
|
||||
}
|
||||
|
||||
public companion object : OptimizationProblemFactory<Double, CMOptimizationProblem> {
|
||||
public companion object : OptimizationProblemFactory<Double, CMOptimization> {
|
||||
public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4
|
||||
public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4
|
||||
public const val DEFAULT_MAX_ITER: Int = 1000
|
||||
|
||||
override fun build(symbols: List<Symbol>): CMOptimizationProblem = CMOptimizationProblem(symbols)
|
||||
override fun build(symbols: List<Symbol>): CMOptimization = CMOptimization(symbols)
|
||||
}
|
||||
}
|
||||
|
||||
public fun CMOptimizationProblem.initialGuess(vararg pairs: Pair<Symbol, Double>): Unit = initialGuess(pairs.toMap())
|
||||
public fun CMOptimizationProblem.simplexSteps(vararg pairs: Pair<Symbol, Double>): Unit = simplexSteps(pairs.toMap())
|
||||
public fun CMOptimization.initialGuess(vararg pairs: Pair<Symbol, Double>): Unit = initialGuess(pairs.toMap())
|
||||
public fun CMOptimization.simplexSteps(vararg pairs: Pair<Symbol, Double>): Unit = simplexSteps(pairs.toMap())
|
@ -1,21 +1,21 @@
|
||||
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.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.misc.Symbol
|
||||
import space.kscience.kmath.optimization.FunctionOptimization
|
||||
import space.kscience.kmath.optimization.OptimizationResult
|
||||
import space.kscience.kmath.optimization.noDerivOptimizeWith
|
||||
import space.kscience.kmath.optimization.optimizeWith
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.asBuffer
|
||||
|
||||
/**
|
||||
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
|
||||
*/
|
||||
public fun Fitting.chiSquared(
|
||||
public fun FunctionOptimization.Companion.chiSquared(
|
||||
x: Buffer<Double>,
|
||||
y: Buffer<Double>,
|
||||
yErr: Buffer<Double>,
|
||||
@ -25,7 +25,7 @@ public fun Fitting.chiSquared(
|
||||
/**
|
||||
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
|
||||
*/
|
||||
public fun Fitting.chiSquared(
|
||||
public fun FunctionOptimization.Companion.chiSquared(
|
||||
x: Iterable<Double>,
|
||||
y: Iterable<Double>,
|
||||
yErr: Iterable<Double>,
|
||||
@ -43,25 +43,26 @@ public fun Fitting.chiSquared(
|
||||
*/
|
||||
public fun Expression<Double>.optimize(
|
||||
vararg symbols: Symbol,
|
||||
configuration: CMOptimizationProblem.() -> Unit,
|
||||
): OptimizationResult<Double> = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration)
|
||||
configuration: CMOptimization.() -> Unit,
|
||||
): OptimizationResult<Double> = noDerivOptimizeWith(CMOptimization, symbols = symbols, configuration)
|
||||
|
||||
/**
|
||||
* Optimize differentiable expression
|
||||
*/
|
||||
public fun DifferentiableExpression<Double, Expression<Double>>.optimize(
|
||||
vararg symbols: Symbol,
|
||||
configuration: CMOptimizationProblem.() -> Unit,
|
||||
): OptimizationResult<Double> = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration)
|
||||
configuration: CMOptimization.() -> Unit,
|
||||
): OptimizationResult<Double> = optimizeWith(CMOptimization, symbols = symbols, configuration)
|
||||
|
||||
public fun DifferentiableExpression<Double, Expression<Double>>.minimize(
|
||||
vararg startPoint: Pair<Symbol, Double>,
|
||||
configuration: CMOptimizationProblem.() -> Unit = {},
|
||||
configuration: CMOptimization.() -> Unit = {},
|
||||
): OptimizationResult<Double> {
|
||||
require(startPoint.isNotEmpty()) { "Must provide a list of symbols for optimization" }
|
||||
val problem = CMOptimizationProblem(startPoint.map { it.first }).apply(configuration)
|
||||
problem.diffExpression(this)
|
||||
problem.initialGuess(startPoint.toMap())
|
||||
problem.goal(GoalType.MINIMIZE)
|
||||
return problem.optimize()
|
||||
val symbols = startPoint.map { it.first }.toTypedArray()
|
||||
return optimize(*symbols){
|
||||
maximize = false
|
||||
initialGuess(startPoint.toMap())
|
||||
diffFunction(this@minimize)
|
||||
configuration()
|
||||
}
|
||||
}
|
@ -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 val factory: (IntArray) -> RandomGenerator,
|
@ -1,13 +1,14 @@
|
||||
package kscience.kmath.commons.transform
|
||||
package space.kscience.kmath.commons.transform
|
||||
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kscience.kmath.complex.*
|
||||
import kscience.kmath.streaming.chunked
|
||||
import kscience.kmath.streaming.spread
|
||||
import kscience.kmath.structures.*
|
||||
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.*
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@ -17,7 +18,7 @@ public object Transformations {
|
||||
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
|
||||
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
|
||||
|
||||
private fun Buffer<Double>.asArray() = if (this is RealBuffer) {
|
||||
private fun Buffer<Double>.asArray() = if (this is DoubleBuffer) {
|
||||
array
|
||||
} else {
|
||||
DoubleArray(size) { i -> get(i) }
|
||||
@ -33,34 +34,34 @@ public object Transformations {
|
||||
|
||||
public fun fourier(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Complex, Complex> = {
|
||||
FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun realFourier(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Complex> = {
|
||||
FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun sine(
|
||||
normalization: DstNormalization = DstNormalization.STANDARD_DST_I,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Double> = {
|
||||
FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun cosine(
|
||||
normalization: DctNormalization = DctNormalization.STANDARD_DCT_I,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Double> = {
|
||||
FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun hadamard(
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Double> = {
|
||||
FastHadamardTransformer().transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
@ -72,7 +73,7 @@ public object Transformations {
|
||||
@FlowPreview
|
||||
public fun Flow<Buffer<Complex>>.FFT(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Buffer<Complex>> {
|
||||
val transform = Transformations.fourier(normalization, direction)
|
||||
return map { transform(it) }
|
||||
@ -82,7 +83,7 @@ public fun Flow<Buffer<Complex>>.FFT(
|
||||
@JvmName("realFFT")
|
||||
public fun Flow<Buffer<Double>>.FFT(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Buffer<Complex>> {
|
||||
val transform = Transformations.realFourier(normalization, direction)
|
||||
return map(transform)
|
||||
@ -96,7 +97,7 @@ public fun Flow<Buffer<Double>>.FFT(
|
||||
public fun Flow<Double>.FFT(
|
||||
bufferSize: Int = Int.MAX_VALUE,
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread()
|
||||
|
||||
/**
|
@ -1,6 +1,10 @@
|
||||
package kscience.kmath.commons.expressions
|
||||
package space.kscience.kmath.commons.expressions
|
||||
|
||||
import kscience.kmath.expressions.*
|
||||
import space.kscience.kmath.expressions.binding
|
||||
import space.kscience.kmath.expressions.derivative
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
import space.kscience.kmath.misc.symbol
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.test.Test
|
||||
@ -24,7 +28,7 @@ internal class AutoDiffTest {
|
||||
fun derivativeStructureFieldTest() {
|
||||
diff(2, x to 1.0, y to 1.0) {
|
||||
val x = bind(x)//by binding()
|
||||
val y = symbol("y")
|
||||
val y = bindSymbol("y")
|
||||
val z = x * (-sin(x * y) + y) + 2.0
|
||||
println(z.derivative(x))
|
||||
println(z.derivative(y, x))
|
@ -0,0 +1,30 @@
|
||||
package space.kscience.kmath.commons.integration
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import space.kscience.kmath.integration.integrate
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.DoubleField.sin
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.abs
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@UnstableKMathAPI
|
||||
internal class IntegrationTest {
|
||||
private val function: (Double) -> Double = { sin(it) }
|
||||
|
||||
@Test
|
||||
fun simpson() {
|
||||
val res = CMIntegrator.simpson().integrate(0.0..2 * PI, function)
|
||||
assertTrue { abs(res) < 1e-3 }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun customSimpson() {
|
||||
val res = CMIntegrator.simpson().integrate(0.0..PI, function) {
|
||||
targetRelativeAccuracy = 1e-4
|
||||
targetAbsoluteAccuracy = 1e-4
|
||||
}
|
||||
assertTrue { abs(res - 2) < 1e-3 }
|
||||
assertTrue { abs(res - 2) > 1e-12 }
|
||||
}
|
||||
}
|