Merging dev

This commit is contained in:
Roland Grinis 2021-03-01 12:47:20 +00:00
commit 2ea6d0bfdd
285 changed files with 7637 additions and 3522 deletions

View File

@ -12,6 +12,8 @@ jobs:
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
@ -47,6 +49,8 @@ jobs:
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:
@ -77,6 +81,8 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 11
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Add msys to path
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
- name: Cache gradle

117
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,117 @@
name: Gradle release
on:
release:
types:
- created
jobs:
build-ubuntu:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Install Chrome
run: |
sudo apt install -y libappindicator1 fonts-liberation
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome*.deb
- name: Cache gradle
uses: actions/cache@v2
with:
path: |
.gradle
build
~/.gradle
key: gradle
restore-keys: gradle
- name: Cache konan
uses: actions/cache@v2
with:
path: |
~/.konan/dependencies
~/.konan/kotlin-native-prebuilt-linux-*
key: ${{ runner.os }}-konan
restore-keys: ${{ runner.os }}-konan
- name: Build with Gradle
run: ./gradlew -Dorg.gradle.daemon=false --build-cache build
- name: Run release task
run: ./gradlew release -PbintrayUser=${{ secrets.BINTRAY_USER }} -PbintrayApiKey=${{ secrets.BINTRAY_KEY }}
build-osx:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Cache gradle
uses: actions/cache@v2
with:
path: |
.gradle
build
~/.gradle
key: gradle
restore-keys: gradle
- name: Cache konan
uses: actions/cache@v2
with:
path: |
~/.konan/dependencies
~/.konan/kotlin-native-prebuilt-macos-*
key: ${{ runner.os }}-konan
restore-keys: ${{ runner.os }}-konan
- name: Build with Gradle
run: sudo ./gradlew -Dorg.gradle.daemon=false --build-cache build
- name: Run release task
run: ./gradlew release -PbintrayUser=${{ secrets.BINTRAY_USER }} -PbintrayApiKey=${{ secrets.BINTRAY_KEY }}
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Add msys to path
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
- name: Cache gradle
uses: actions/cache@v2
with:
path: |
.gradle
build
~/.gradle
key: ${{ runner.os }}-gradle
restore-keys: ${{ runner.os }}-gradle
- name: Cache konan
uses: actions/cache@v2
with:
path: |
~/.konan/dependencies
~/.konan/kotlin-native-prebuilt-mingw-*
key: ${{ runner.os }}-konan
restore-keys: ${{ runner.os }}-konan
- name: Build with Gradle
run: ./gradlew --build-cache build
- name: Run release task
run: ./gradlew release -PbintrayUser=${{ secrets.BINTRAY_USER }} -PbintrayApiKey=${{ secrets.BINTRAY_KEY }}

View File

@ -2,6 +2,19 @@
## [Unreleased]
### Added
### Changed
### Deprecated
### Removed
### 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)
@ -18,13 +31,14 @@
- Some minor utilities to `kmath-for-real`
- Generic operation result parameter to `MatrixContext`
- New `MatrixFeature` interfaces for matrix decompositions
- Basic Quaternion vector support in `kmath-complex`.
### Changed
- Package changed from `scientifik` to `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`
@ -32,9 +46,16 @@
- Use `Point<Double>` instead of specialized type in `kmath-for-real`
- Optimized dot product for buffer matrices moved to `kmath-for-real`
- EjmlMatrix context is an object
- Matrix LUP `inverse` renamed to `inverseWithLUP`
- Matrix LUP `inverse` renamed to `inverseWithLup`
- `NumericAlgebra` moved outside of regular algebra chain (`Ring` no longer implements it).
- Features moved to NDStructure and became transparent.
- Capitalization of LUP in many names changed to Lup.
- Refactored `NDStructure` algebra to be more simple, preferring under-the-hood conversion to explicit NDStructure types
- Refactor histograms. They are marked as prototype
- `Complex` and related features moved to a separate module `kmath-complex`
- Refactor AlgebraElement
- `symbol` method in `Algebra` renamed to `bindSymbol` to avoid ambiguity
- Add `out` projection to `Buffer` generic
### Deprecated
@ -43,6 +64,7 @@
- Support of `legacy` JS backend (we will support only IR)
- `toGrid` method.
- Public visibility of `BufferAccessor2D`
- `Real` class
### Fixed
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)

120
README.md
View File

@ -9,7 +9,7 @@ Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmat
# KMath
Could be pronounced as `key-math`. The Kotlin MATHematics library was initially intended as a Kotlin-based analog to
Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to
Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture
designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could
be achieved with [kmath-for-real](/kmath-for-real) extension module.
@ -32,49 +32,46 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module.
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better
for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better
experience for those, who want to work with specific types.
## Features
## Features and stability
Current feature list is [here](/docs/features.md)
KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels:
* **Algebra**
* Algebraic structures like rings, spaces and fields (**TODO** add example to wiki)
* Basic linear algebra operations (sums, products, etc.), backed by the `Space` API.
* Complex numbers backed by the `Field` API (meaning they will be usable in any structure like vectors and
N-dimensional arrays).
* Advanced linear algebra operations like matrix inversion and LU decomposition.
* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version.
* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations.
* **DEVELOPMENT**. API breaking genrally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool.
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
* **Array-like structures** Full support of many-dimensional array-like structures
including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).
<!--Current feature list is [here](/docs/features.md)-->
* **Expressions** By writing a single mathematical expression once, users will be able to apply different types of
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation.
* **Histograms** Fast multi-dimensional histograms.
<!--* **Array-like structures** Full support of many-dimensional array-like structures -->
<!--including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).-->
* **Streaming** Streaming operations on mathematical objects and objects buffers.
<!--* **Histograms** Fast multi-dimensional histograms.-->
* **Type-safe dimensions** Type-safe dimensions for matrix operations.
<!--* **Streaming** Streaming operations on mathematical objects and objects buffers.-->
* **Commons-math wrapper** It is planned to gradually wrap most parts of
[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some
parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to
submit a feature request if you want something to be implemented first.
## Planned features
<!--* **Type-safe dimensions** Type-safe dimensions for matrix operations.-->
* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.
<!--* **Commons-math wrapper** It is planned to gradually wrap most parts of -->
<!--[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some -->
<!--parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to -->
<!--submit a feature request if you want something to be implemented first.-->
<!-- -->
<!--## Planned features-->
* **Array statistics**
<!--* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.-->
* **Integration** Univariate and multivariate integration framework.
<!--* **Array statistics** -->
* **Probability and distributions**
<!--* **Integration** Univariate and multivariate integration framework.-->
* **Fitting** Non-linear curve fitting facilities
<!--* **Probability and distributions**-->
<!--* **Fitting** Non-linear curve fitting facilities-->
## Modules
@ -107,16 +104,30 @@ submit a feature request if you want something to be implemented first.
> **Maturity**: EXPERIMENTAL
<hr/>
* ### [kmath-complex](kmath-complex)
> Complex numbers and quaternions.
>
> **Maturity**: PROTOTYPE
>
> **Features:**
> - [complex](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
> - [quaternion](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
<hr/>
* ### [kmath-core](kmath-core)
> Core classes, algebra definitions, basic linear algebra
>
> **Maturity**: DEVELOPMENT
>
> **Features:**
> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures: contexts and elements
> - [nd](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures
> - [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) : Functional Expressions
> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation.
> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains
> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
@ -137,7 +148,7 @@ submit a feature request if you want something to be implemented first.
* ### [kmath-ejml](kmath-ejml)
>
>
> **Maturity**: EXPERIMENTAL
> **Maturity**: PROTOTYPE
<hr/>
* ### [kmath-for-real](kmath-for-real)
@ -155,33 +166,40 @@ One can still use generic algebras though.
<hr/>
* ### [kmath-functions](kmath-functions)
>
> Functions and interpolation
>
> **Maturity**: EXPERIMENTAL
> **Maturity**: PROTOTYPE
>
> **Features:**
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt
<hr/>
* ### [kmath-geometry](kmath-geometry)
>
>
> **Maturity**: EXPERIMENTAL
> **Maturity**: PROTOTYPE
<hr/>
* ### [kmath-histograms](kmath-histograms)
>
>
> **Maturity**: EXPERIMENTAL
> **Maturity**: PROTOTYPE
<hr/>
* ### [kmath-kotlingrad](kmath-kotlingrad)
>
>
> **Maturity**: EXPERIMENTAL
> **Maturity**: PROTOTYPE
<hr/>
* ### [kmath-memory](kmath-memory)
>
> An API and basic implementation for arranging objects in a continous memory block.
>
> **Maturity**: EXPERIMENTAL
> **Maturity**: DEVELOPMENT
<hr/>
* ### [kmath-nd4j](kmath-nd4j)
@ -205,7 +223,7 @@ One can still use generic algebras though.
* ### [kmath-viktor](kmath-viktor)
>
>
> **Maturity**: EXPERIMENTAL
> **Maturity**: DEVELOPMENT
<hr/>
@ -229,32 +247,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://repo.kotlin.link")
}
dependencies {
api("kscience.kmath:kmath-core:0.2.0-dev-4")
// api("kscience.kmath:kmath-core-jvm:0.2.0-dev-4") for jvm-specific version
api("kscience.kmath:kmath-core:() -> kotlin.Any")
// api("kscience.kmath:kmath-core-jvm:() -> kotlin.Any") 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

View File

@ -1,13 +1,7 @@
import ru.mipt.npm.gradle.KSciencePublishPlugin
plugins {
id("ru.mipt.npm.project")
id("ru.mipt.npm.gradle.project")
}
internal val kmathVersion: String by extra("0.2.0-dev-6")
internal val bintrayRepo: String by extra("kscience")
internal val githubProject: String by extra("kmath")
allprojects {
repositories {
jcenter()
@ -23,22 +17,24 @@ allprojects {
mavenCentral()
}
group = "kscience.kmath"
version = kmathVersion
group = "space.kscience"
version = "0.2.0"
}
subprojects {
if (name.startsWith("kmath")) apply<KSciencePublishPlugin>()
if (name.startsWith("kmath")) apply<ru.mipt.npm.gradle.KSciencePublishingPlugin>()
}
readme {
readmeTemplate = file("docs/templates/README-TEMPLATE.md")
}
apiValidation {
validationDisabled = true
}
ksciencePublish {
spaceRepo = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven"
bintrayRepo = "kscience"
githubProject = "kmath"
}
apiValidation{
nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI")
}

View File

@ -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 = ...
@ -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)

View File

@ -10,11 +10,12 @@
>
> ```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://repo.kotlin.link' }
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
>
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
>// Uncomment if repo.kotlin.link is unavailable
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
> }
>
> dependencies {
@ -25,10 +26,12 @@
>
> ```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")
> maven("https://repo.kotlin.link")
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
>// Uncomment if repo.kotlin.link is unavailable
>// maven("https://dl.bintray.com/mipt-npm/kscience")
>// maven("https://dl.bintray.com/mipt-npm/dev")
> }
>
> dependencies {

View File

@ -9,7 +9,7 @@ Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmat
# KMath
Could be pronounced as `key-math`. The Kotlin MATHematics library was initially intended as a Kotlin-based analog to
Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to
Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture
designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could
be achieved with [kmath-for-real](/kmath-for-real) extension module.
@ -32,49 +32,46 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module.
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like
for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better
for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better
experience for those, who want to work with specific types.
## Features
## Features and stability
Current feature list is [here](/docs/features.md)
KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels:
* **Algebra**
* Algebraic structures like rings, spaces and fields (**TODO** add example to wiki)
* Basic linear algebra operations (sums, products, etc.), backed by the `Space` API.
* Complex numbers backed by the `Field` API (meaning they will be usable in any structure like vectors and
N-dimensional arrays).
* Advanced linear algebra operations like matrix inversion and LU decomposition.
* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version.
* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations.
* **DEVELOPMENT**. API breaking genrally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool.
* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases.
* **Array-like structures** Full support of many-dimensional array-like structures
including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).
<!--Current feature list is [here](/docs/features.md)-->
* **Expressions** By writing a single mathematical expression once, users will be able to apply different types of
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation.
* **Histograms** Fast multi-dimensional histograms.
<!--* **Array-like structures** Full support of many-dimensional array-like structures -->
<!--including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).-->
* **Streaming** Streaming operations on mathematical objects and objects buffers.
<!--* **Histograms** Fast multi-dimensional histograms.-->
* **Type-safe dimensions** Type-safe dimensions for matrix operations.
<!--* **Streaming** Streaming operations on mathematical objects and objects buffers.-->
* **Commons-math wrapper** It is planned to gradually wrap most parts of
[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some
parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to
submit a feature request if you want something to be implemented first.
## Planned features
<!--* **Type-safe dimensions** Type-safe dimensions for matrix operations.-->
* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.
<!--* **Commons-math wrapper** It is planned to gradually wrap most parts of -->
<!--[Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some -->
<!--parts to better suit the Kotlin programming paradigm, however there is no established roadmap for that. Feel free to -->
<!--submit a feature request if you want something to be implemented first.-->
<!-- -->
<!--## Planned features-->
* **Array statistics**
<!--* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.-->
* **Integration** Univariate and multivariate integration framework.
<!--* **Array statistics** -->
* **Probability and distributions**
<!--* **Integration** Univariate and multivariate integration framework.-->
* **Fitting** Non-linear curve fitting facilities
<!--* **Probability and distributions**-->
<!--* **Fitting** Non-linear curve fitting facilities-->
## Modules
@ -100,12 +97,12 @@ 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://repo.kotlin.link")
}
dependencies {
@ -116,16 +113,6 @@ dependencies {
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

View File

@ -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")
@ -30,6 +30,7 @@ dependencies {
implementation(project(":kmath-core"))
implementation(project(":kmath-coroutines"))
implementation(project(":kmath-commons"))
implementation(project(":kmath-complex"))
implementation(project(":kmath-stat"))
implementation(project(":kmath-viktor"))
implementation(project(":kmath-dimensions"))
@ -68,11 +69,28 @@ benchmark {
targets.register("benchmarks")
// This one matches sourceSet name above
configurations.register("fast") {
configurations.register("buffer") {
warmups = 1 // number of warmup iterations
iterations = 3 // number of iterations
iterationTime = 500 // time in seconds per iteration
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
include("BufferBenchmark")
}
configurations.register("dot") {
warmups = 1 // number of warmup iterations
iterations = 3 // number of iterations
iterationTime = 500 // time in seconds per iteration
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
include("DotBenchmark")
}
configurations.register("expressions") {
warmups = 1 // number of warmup iterations
iterations = 3 // number of iterations
iterationTime = 500 // time in seconds per iteration
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
include("ExpressionsInterpretersBenchmark")
}
}
@ -86,3 +104,7 @@ kotlin.sourceSets.all {
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -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) }
}
}

View File

@ -1,50 +0,0 @@
package kscience.kmath.benchmarks
import kscience.kmath.operations.RealField
import kscience.kmath.operations.invoke
import kscience.kmath.structures.*
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
@State(Scope.Benchmark)
internal class NDFieldBenchmark {
@Benchmark
fun autoFieldAdd() {
bufferedField {
var res: NDBuffer<Double> = one
repeat(n) { res += one }
}
}
@Benchmark
fun autoElementAdd() {
var res = genericField.one
repeat(n) { res += 1.0 }
}
@Benchmark
fun specializedFieldAdd() {
specializedField {
var res: NDBuffer<Double> = one
repeat(n) { res += 1.0 }
}
}
@Benchmark
fun boxingFieldAdd() {
genericField {
var res: NDBuffer<Double> = one
repeat(n) { res += one }
}
}
companion object {
const val dim: Int = 1000
const val n: Int = 100
val bufferedField: BufferedNDField<Double, RealField> = NDField.auto(RealField, dim, dim)
val specializedField: RealNDField = NDField.real(dim, dim)
val genericField: BoxingNDField<Double, RealField> = NDField.boxing(RealField, dim, dim)
}
}

View File

@ -1,64 +0,0 @@
package kscience.kmath.benchmarks
import kscience.kmath.operations.RealField
import kscience.kmath.operations.invoke
import kscience.kmath.structures.BufferedNDField
import kscience.kmath.structures.NDField
import kscience.kmath.structures.RealNDField
import kscience.kmath.viktor.ViktorNDField
import org.jetbrains.bio.viktor.F64Array
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
@State(Scope.Benchmark)
internal class ViktorBenchmark {
final val dim: Int = 1000
final val n: Int = 100
// automatically build context most suited for given type.
final val autoField: BufferedNDField<Double, RealField> = NDField.auto(RealField, dim, dim)
final val realField: RealNDField = NDField.real(dim, dim)
final val viktorField: ViktorNDField = ViktorNDField(intArrayOf(dim, dim))
@Benchmark
fun automaticFieldAddition() {
autoField {
var res = one
repeat(n) { res += one }
}
}
@Benchmark
fun viktorFieldAddition() {
viktorField {
var res = one
repeat(n) { res += one }
}
}
@Benchmark
fun rawViktor() {
val one = F64Array.full(init = 1.0, shape = intArrayOf(dim, dim))
var res = one
repeat(n) { res = res + one }
}
@Benchmark
fun realFieldLog() {
realField {
val fortyTwo = produce { 42.0 }
var res = one
repeat(n) { res = ln(fortyTwo) }
}
}
@Benchmark
fun rawViktorLog() {
val fortyTwo = F64Array.full(dim, dim, init = 42.0)
var res: F64Array
repeat(n) {
res = fortyTwo.log()
}
}
}

View File

@ -0,0 +1,34 @@
package space.kscience.kmath.benchmarks
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import java.nio.IntBuffer
@State(Scope.Benchmark)
internal class ArrayBenchmark {
@Benchmark
fun benchmarkArrayRead() {
var res = 0
for (i in 1..space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) res += space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.array[space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size - i]
}
@Benchmark
fun benchmarkBufferRead() {
var res = 0
for (i in 1..space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) res += space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.arrayBuffer[space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size - i]
}
@Benchmark
fun nativeBufferRead() {
var res = 0
for (i in 1..space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) res += space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.nativeBuffer[space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size - i]
}
companion object {
const val size: Int = 1000
val array: IntArray = IntArray(space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) { it }
val arrayBuffer: IntBuffer = IntBuffer.wrap(space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.array)
val nativeBuffer: IntBuffer = IntBuffer.allocate(space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size).also { for (i in 0 until space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) it.put(i, i) }
}
}

View File

@ -1,12 +1,12 @@
package kscience.kmath.benchmarks
package space.kscience.kmath.benchmarks
import kscience.kmath.operations.Complex
import kscience.kmath.operations.complex
import kscience.kmath.structures.MutableBuffer
import kscience.kmath.structures.RealBuffer
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.complex
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.RealBuffer
@State(Scope.Benchmark)
internal class BufferBenchmark {
@ -31,4 +31,4 @@ internal class BufferBenchmark {
companion object {
const val size: Int = 100
}
}
}

View File

@ -1,22 +1,20 @@
package kscience.kmath.benchmarks
package space.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.RealMatrixContext
import kscience.kmath.linear.real
import kscience.kmath.operations.RealField
import kscience.kmath.operations.invoke
import kscience.kmath.structures.Buffer
import kscience.kmath.structures.Matrix
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import space.kscience.kmath.commons.linear.CMMatrixContext
import space.kscience.kmath.ejml.EjmlMatrixContext
import space.kscience.kmath.linear.BufferMatrixContext
import space.kscience.kmath.linear.Matrix
import space.kscience.kmath.linear.RealMatrixContext
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer
import kotlin.random.Random
@State(Scope.Benchmark)
class DotBenchmark {
internal class DotBenchmark {
companion object {
val random = Random(12224)
val dim = 1000
@ -33,40 +31,37 @@ class DotBenchmark {
}
@Benchmark
fun commonsMathMultiplication() {
fun cmDot() {
CMMatrixContext {
cmMatrix1 dot cmMatrix2
}
}
@Benchmark
fun ejmlMultiplication() {
fun ejmlDot() {
EjmlMatrixContext {
ejmlMatrix1 dot ejmlMatrix2
}
}
@Benchmark
fun ejmlMultiplicationwithConversion() {
fun ejmlDotWithConversion() {
EjmlMatrixContext {
val ejmlMatrix1 = matrix1.toEjml()
val ejmlMatrix2 = matrix2.toEjml()
ejmlMatrix1 dot ejmlMatrix2
matrix1 dot matrix2
}
}
@Benchmark
fun bufferedMultiplication() {
fun bufferedDot() {
BufferMatrixContext(RealField, Buffer.Companion::real).invoke {
matrix1 dot matrix2
}
}
@Benchmark
fun realMultiplication() {
fun realDot() {
RealMatrixContext {
matrix1 dot matrix2
}
}
}
}

View File

@ -1,25 +1,29 @@
package kscience.kmath.ast
package space.kscience.kmath.benchmarks
import kscience.kmath.asm.compile
import kscience.kmath.expressions.Expression
import kscience.kmath.expressions.expressionInField
import kscience.kmath.expressions.invoke
import kscience.kmath.expressions.symbol
import kscience.kmath.operations.Field
import kscience.kmath.operations.RealField
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import space.kscience.kmath.asm.compile
import space.kscience.kmath.ast.mstInField
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.expressionInField
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.bindSymbol
import kotlin.random.Random
@State(Scope.Benchmark)
internal class ExpressionsInterpretersBenchmark {
private val algebra: Field<Double> = RealField
val x by symbol
@Benchmark
fun functionalExpression() {
val expr = algebra.expressionInField {
symbol("x") * const(2.0) + const(2.0) / symbol("x") - const(16.0)
val x = bindSymbol(x)
x * const(2.0) + const(2.0) / x - const(16.0)
}
invokeAndSum(expr)
@ -28,7 +32,8 @@ internal class ExpressionsInterpretersBenchmark {
@Benchmark
fun mstExpression() {
val expr = algebra.mstInField {
symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0
val x = bindSymbol(x)
x * 2.0 + 2.0 / x - 16.0
}
invokeAndSum(expr)
@ -37,7 +42,8 @@ internal class ExpressionsInterpretersBenchmark {
@Benchmark
fun asmExpression() {
val expr = algebra.mstInField {
symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0
val x = bindSymbol(x)
x * 2.0 + 2.0 / x - 16.0
}.compile()
invokeAndSum(expr)
@ -45,8 +51,10 @@ internal class ExpressionsInterpretersBenchmark {
@Benchmark
fun rawExpression() {
val x by symbol
val expr = Expression<Double> { args -> args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 }
val expr = Expression<Double> { args ->
val x = args.getValue(x)
x * 2.0 + 2.0 / x - 16.0
}
invokeAndSum(expr)
}
@ -55,7 +63,7 @@ internal class ExpressionsInterpretersBenchmark {
var sum = 0.0
repeat(1000000) {
sum += expr("x" to random.nextDouble())
sum += expr(x to random.nextDouble())
}
println(sum)

View File

@ -1,20 +1,21 @@
package kscience.kmath.linear
package space.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.operations.invoke
import kscience.kmath.structures.Matrix
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import space.kscience.kmath.commons.linear.CMMatrixContext
import space.kscience.kmath.commons.linear.CMMatrixContext.dot
import space.kscience.kmath.commons.linear.inverse
import space.kscience.kmath.ejml.EjmlMatrixContext
import space.kscience.kmath.ejml.inverse
import space.kscience.kmath.linear.Matrix
import space.kscience.kmath.linear.MatrixContext
import space.kscience.kmath.linear.inverseWithLup
import space.kscience.kmath.linear.real
import kotlin.random.Random
@State(Scope.Benchmark)
class LinearAlgebraBenchmark {
internal class LinearAlgebraBenchmark {
companion object {
val random = Random(1224)
val dim = 100
@ -26,21 +27,21 @@ class LinearAlgebraBenchmark {
}
@Benchmark
fun kmathLUPInversion() {
MatrixContext.real.inverseWithLUP(matrix)
fun kmathLupInversion() {
MatrixContext.real.inverseWithLup(matrix)
}
@Benchmark
fun cmLUPInversion() {
CMMatrixContext {
with(CMMatrixContext) {
inverse(matrix)
}
}
@Benchmark
fun ejmlInverse() {
EjmlMatrixContext {
with(EjmlMatrixContext) {
inverse(matrix)
}
}
}
}

View File

@ -0,0 +1,44 @@
package space.kscience.kmath.benchmarks
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.structures.Buffer
@State(Scope.Benchmark)
internal class NDFieldBenchmark {
@Benchmark
fun autoFieldAdd() {
with(autoField) {
var res: NDStructure<Double> = one
repeat(n) { res += one }
}
}
@Benchmark
fun specializedFieldAdd() {
with(specializedField) {
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
@Benchmark
fun boxingFieldAdd() {
with(genericField) {
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
companion object {
const val dim: Int = 1000
const val n: Int = 100
val autoField = NDAlgebra.auto(RealField, dim, dim)
val specializedField: RealNDField = NDAlgebra.real(dim, dim)
val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
}
}

View File

@ -0,0 +1,51 @@
package space.kscience.kmath.benchmarks
import org.jetbrains.bio.viktor.F64Array
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.viktor.ViktorNDField
@State(Scope.Benchmark)
internal class ViktorBenchmark {
final val dim: Int = 1000
final val n: Int = 100
// automatically build context most suited for given type.
final val autoField: NDField<Double, RealField> = NDAlgebra.auto(RealField, dim, dim)
final val realField: RealNDField = NDAlgebra.real(dim, dim)
final val viktorField: ViktorNDField = ViktorNDField(dim, dim)
@Benchmark
fun automaticFieldAddition() {
with(autoField) {
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
@Benchmark
fun realFieldAddition() {
with(realField) {
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
@Benchmark
fun viktorFieldAddition() {
with(viktorField) {
var res = one
repeat(n) { res += 1.0 }
}
}
@Benchmark
fun rawViktor() {
val one = F64Array.full(init = 1.0, shape = intArrayOf(dim, dim))
var res = one
repeat(n) { res = res + one }
}
}

View File

@ -0,0 +1,48 @@
package space.kscience.kmath.benchmarks
import org.jetbrains.bio.viktor.F64Array
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.viktor.ViktorNDField
@State(Scope.Benchmark)
internal class ViktorLogBenchmark {
final val dim: Int = 1000
final val n: Int = 100
// automatically build context most suited for given type.
final val autoField: NDField<Double, RealField> = NDAlgebra.auto(RealField, dim, dim)
final val realField: RealNDField = NDAlgebra.real(dim, dim)
final val viktorField: ViktorNDField = ViktorNDField(intArrayOf(dim, dim))
@Benchmark
fun realFieldLog() {
with(realField) {
val fortyTwo = produce { 42.0 }
var res = one
repeat(n) { res = ln(fortyTwo) }
}
}
@Benchmark
fun viktorFieldLog() {
with(viktorField) {
val fortyTwo = produce { 42.0 }
var res = one
repeat(n) { res = ln(fortyTwo) }
}
}
@Benchmark
fun rawViktorLog() {
val fortyTwo = F64Array.full(dim, dim, init = 42.0)
var res: F64Array
repeat(n) {
res = fortyTwo.log()
}
}
}

View File

@ -0,0 +1,15 @@
package space.kscience.kmath.ast
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.RealField
fun main() {
val expr = RealField.mstInField {
val x = bindSymbol("x")
x * 2.0 + 2.0 / x - 16.0
}
repeat(10000000){
expr.invoke("x" to 1.0)
}
}

View File

@ -1,11 +1,11 @@
package kscience.kmath.ast
package space.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
import space.kscience.kmath.asm.compile
import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.kotlingrad.differentiable
import space.kscience.kmath.operations.RealField
/**
* In this example, x^2-4*x-44 function is differentiated with Kotlin, and the autodiff result is compared with

View File

@ -1,19 +1,19 @@
package kscience.kmath.commons.fit
package space.kscience.kmath.commons.fit
import kotlinx.html.br
import kotlinx.html.h3
import kscience.kmath.commons.optimization.chiSquared
import kscience.kmath.commons.optimization.minimize
import kscience.kmath.expressions.symbol
import kscience.kmath.real.RealVector
import kscience.kmath.real.map
import kscience.kmath.real.step
import kscience.kmath.stat.*
import kscience.kmath.structures.asIterable
import kscience.kmath.structures.toList
import kscience.plotly.*
import kscience.plotly.models.ScatterMode
import kscience.plotly.models.TraceValues
import space.kscience.kmath.commons.optimization.chiSquared
import space.kscience.kmath.commons.optimization.minimize
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.real.RealVector
import space.kscience.kmath.real.map
import space.kscience.kmath.real.step
import space.kscience.kmath.stat.*
import space.kscience.kmath.structures.asIterable
import space.kscience.kmath.structures.toList
import kotlin.math.pow
import kotlin.math.sqrt
@ -63,7 +63,7 @@ fun main() {
val a = bind(a)
val b = bind(b)
//Include default value for c if it is not provided as a parameter
val c = bindOrNull(c) ?: one
val c = bindSymbolOrNull(c) ?: one
a * x1.pow(2) + b * x1 + c
}

View File

@ -1,4 +1,4 @@
package kscience.kmath.operations
package space.kscience.kmath.operations
fun main() {
val res = BigIntField { number(1) * 2 }

View File

@ -1,23 +1,24 @@
package kscience.kmath.operations
package space.kscience.kmath.operations
import kscience.kmath.structures.NDElement
import kscience.kmath.structures.NDField
import kscience.kmath.structures.complex
import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.complex
import space.kscience.kmath.nd.NDAlgebra
fun main() {
// 2d element
val element = NDElement.complex(2, 2) { (i,j) ->
val element = NDAlgebra.complex(2, 2).produce { (i, j) ->
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
}
println(element)
// 1d element operation
val result = with(NDField.complex(8)) {
val result = with(NDAlgebra.complex(8)) {
val a = produce { (it) -> i * it - it.toDouble() }
val b = 3
val c = Complex(1.0, 1.0)
(a pow b) + c
}
println(result)
}

View File

@ -3,9 +3,9 @@ package kscience.kmath.commons.prob
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import kscience.kmath.stat.*
import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler
import org.apache.commons.rng.simple.RandomSource
import space.kscience.kmath.stat.*
import java.time.Duration
import java.time.Instant

View File

@ -1,8 +1,8 @@
package kscience.kmath.stat
package space.kscience.kmath.stat
import kotlinx.coroutines.runBlocking
import kscience.kmath.chains.Chain
import kscience.kmath.chains.collectWithState
import space.kscience.kmath.chains.Chain
import space.kscience.kmath.chains.collectWithState
/**
* The state of distribution averager

View File

@ -1,21 +1,26 @@
package kscience.kmath.structures
@file:Suppress("unused")
import kscience.kmath.linear.transpose
import kscience.kmath.operations.Complex
import kscience.kmath.operations.ComplexField
import kscience.kmath.operations.invoke
package space.kscience.kmath.structures
import space.kscience.kmath.complex.*
import space.kscience.kmath.linear.transpose
import space.kscience.kmath.nd.NDAlgebra
import space.kscience.kmath.nd.NDStructure
import space.kscience.kmath.nd.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 = NDField.real(dim, dim)
val complexField: ComplexNDField = NDField.complex(dim, dim)
val realField = NDAlgebra.real(dim, dim)
val complexField: ComplexNDField = NDAlgebra.complex(dim, dim)
val realTime = measureTimeMillis {
realField {
var res: NDBuffer<Double> = one
var res: NDStructure<Double> = one
repeat(n) {
res += 1.0
}
@ -26,8 +31,10 @@ fun main() {
val complexTime = measureTimeMillis {
complexField {
var res: NDBuffer<Complex> = one
repeat(n) { res += 1.0 }
var res: NDStructure<Complex> = one
repeat(n) {
res += 1.0
}
}
}

View File

@ -1,10 +1,12 @@
package kscience.kmath.structures
package space.kscience.kmath.structures
import kotlinx.coroutines.GlobalScope
import kscience.kmath.nd4j.Nd4jArrayField
import kscience.kmath.operations.RealField
import kscience.kmath.operations.invoke
import org.nd4j.linalg.factory.Nd4j
import space.kscience.kmath.nd.*
import space.kscience.kmath.nd4j.Nd4jArrayField
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.viktor.ViktorNDField
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.system.measureTimeMillis
@ -22,42 +24,62 @@ fun main() {
val n = 1000
// automatically build context most suited for given type.
val autoField = NDField.auto(RealField, dim, dim)
val autoField = NDAlgebra.auto(RealField, dim, dim)
// specialized nd-field for Double. It works as generic Double field as well
val specializedField = NDField.real(dim, dim)
val realField = NDAlgebra.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives.
val genericField = NDField.boxing(RealField, dim, dim)
val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
// Nd4j specialized field.
val nd4jField = Nd4jArrayField.real(dim, dim)
//viktor field
val viktorField = ViktorNDField(dim,dim)
//parallel processing based on Java Streams
val parallelField = NDAlgebra.realWithStream(dim,dim)
measureAndPrint("Automatic field addition") {
autoField {
var res: NDBuffer<Double> = one
measureAndPrint("Boxing addition") {
boxingField {
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Element addition") {
var res = genericField.one
repeat(n) { res += 1.0 }
}
measureAndPrint("Specialized addition") {
specializedField {
var res: NDBuffer<Double> = one
realField {
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Nd4j specialized addition") {
nd4jField {
var res = one
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Viktor addition") {
viktorField {
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Parallel stream addition") {
parallelField {
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Automatic field addition") {
autoField {
var res: NDStructure<Double> = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Lazy addition") {
val res = specializedField.one.mapAsync(GlobalScope) {
val res = realField.one.mapAsync(GlobalScope) {
var c = 0.0
repeat(n) {
c += 1.0
@ -67,14 +89,4 @@ fun main() {
res.elements().forEach { it.second }
}
measureAndPrint("Generic addition") {
//genericField.run(action)
genericField {
var res: NDBuffer<Double> = one
repeat(n) {
res += 1.0 // couldn't avoid using `one` due to resolution ambiguity }
}
}
}
}

View File

@ -0,0 +1,103 @@
package space.kscience.kmath.structures
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.RingWithNumbers
import java.util.*
import java.util.stream.IntStream
/**
* A demonstration implementation of NDField over Real using Java [DoubleStream] for parallel execution
*/
@OptIn(UnstableKMathAPI::class)
class StreamRealNDField(
override val shape: IntArray,
) : NDField<Double, RealField>,
RingWithNumbers<NDStructure<Double>>,
ExtendedField<NDStructure<Double>> {
private val strides = DefaultStrides(shape)
override val elementContext: RealField get() = RealField
override val zero: NDBuffer<Double> by lazy { produce { zero } }
override val one: NDBuffer<Double> by lazy { produce { one } }
override fun number(value: Number): NDBuffer<Double> {
val d = value.toDouble() // minimize conversions
return produce { d }
}
private val NDStructure<Double>.buffer: RealBuffer
get() = when {
!shape.contentEquals(this@StreamRealNDField.shape) -> throw ShapeMismatchException(
this@StreamRealNDField.shape,
shape
)
this is NDBuffer && this.strides == this@StreamRealNDField.strides -> this.buffer as RealBuffer
else -> RealBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
}
override fun produce(initializer: RealField.(IntArray) -> Double): NDBuffer<Double> {
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
val index = strides.index(offset)
RealField.initializer(index)
}.toArray()
return NDBuffer(strides, array.asBuffer())
}
override fun NDStructure<Double>.map(
transform: RealField.(Double) -> Double,
): NDBuffer<Double> {
val array = Arrays.stream(buffer.array).parallel().map { RealField.transform(it) }.toArray()
return NDBuffer(strides, array.asBuffer())
}
override fun NDStructure<Double>.mapIndexed(
transform: RealField.(index: IntArray, Double) -> Double,
): NDBuffer<Double> {
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
RealField.transform(
strides.index(offset),
buffer.array[offset]
)
}.toArray()
return NDBuffer(strides, array.asBuffer())
}
override fun combine(
a: NDStructure<Double>,
b: NDStructure<Double>,
transform: RealField.(Double, Double) -> Double,
): NDBuffer<Double> {
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
RealField.transform(a.buffer.array[offset], b.buffer.array[offset])
}.toArray()
return NDBuffer(strides, array.asBuffer())
}
override fun power(arg: NDStructure<Double>, pow: Number): NDBuffer<Double> = arg.map() { power(it, pow) }
override fun exp(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { exp(it) }
override fun ln(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { ln(it) }
override fun sin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { sin(it) }
override fun cos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { cos(it) }
override fun tan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { tan(it) }
override fun asin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { asin(it) }
override fun acos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { acos(it) }
override fun atan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { atan(it) }
override fun sinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { sinh(it) }
override fun cosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { cosh(it) }
override fun tanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { tanh(it) }
override fun asinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { asinh(it) }
override fun acosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { acosh(it) }
override fun atanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { atanh(it) }
}
fun NDAlgebra.Companion.realWithStream(vararg shape: Int): StreamRealNDField = StreamRealNDField(shape)

View File

@ -1,13 +1,16 @@
package kscience.kmath.structures
package space.kscience.kmath.structures
import space.kscience.kmath.nd.DefaultStrides
import space.kscience.kmath.nd.NDBuffer
import kotlin.system.measureTimeMillis
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
fun main() {
val n = 6000
val array = DoubleArray(n * n) { 1.0 }
val buffer = RealBuffer(array)
val strides = DefaultStrides(intArrayOf(n, n))
val structure = BufferNDStructure(strides, buffer)
val structure = NDBuffer(strides, buffer)
measureTimeMillis {
var res = 0.0

View File

@ -1,7 +1,10 @@
package kscience.kmath.structures
package space.kscience.kmath.structures
import space.kscience.kmath.nd.NDStructure
import space.kscience.kmath.nd.mapToBuffer
import kotlin.system.measureTimeMillis
@Suppress("UNUSED_VARIABLE")
fun main() {
val n = 6000
val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }

View File

@ -1,9 +1,9 @@
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() {
val m1 = produce<D2, D3> { i, j -> (i + j).toDouble() }

View File

@ -1,9 +1,8 @@
kotlin.code.style=official
kotlin.parallel.tasks.in.project=true
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false
kotlin.mpp.stability.nowarn=true
kotlin.native.enableDependencyPropagation=false
kotlin.parallel.tasks.in.project=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m
org.gradle.parallel=true
systemProp.org.gradle.internal.publish.checksums.insecure=true
systemProp.org.gradle.internal.publish.checksums.insecure=true

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -12,7 +12,7 @@ This subproject implements the following features:
> #### Artifact:
>
> This module artifact: `kscience.kmath:kmath-ast:0.2.0-dev-4`.
> This module artifact: `space.kscience:kmath-ast:0.2.0`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
>
@ -22,29 +22,32 @@ This subproject implements the following features:
>
> ```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://repo.kotlin.link' }
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
>
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
>// Uncomment if repo.kotlin.link is unavailable
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
> }
>
> dependencies {
> implementation 'kscience.kmath:kmath-ast:0.2.0-dev-4'
> implementation 'space.kscience:kmath-ast:0.2.0'
> }
> ```
> **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")
> maven("https://repo.kotlin.link")
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
>// Uncomment if repo.kotlin.link is unavailable
>// maven("https://dl.bintray.com/mipt-npm/kscience")
>// maven("https://dl.bintray.com/mipt-npm/dev")
> }
>
> dependencies {
> implementation("kscience.kmath:kmath-ast:0.2.0-dev-4")
> implementation("space.kscience:kmath-ast:0.2.0")
> }
> ```
@ -61,21 +64,21 @@ For example, the following builder:
RealField.mstInField { symbol("x") + 2 }.compile()
```
leads to generation of bytecode, which can be decompiled to the following Java class:
… leads to generation of bytecode, which can be decompiled to the following Java class:
```java
package 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;
public final Double invoke(Map<Symbol, Double> arguments) {
public final Double invoke(Map<Symbol, ? extends Double> arguments) {
return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2);
}

View File

@ -1,7 +1,7 @@
import ru.mipt.npm.gradle.Maturity
plugins {
id("ru.mipt.npm.mpp")
id("ru.mipt.npm.gradle.mpp")
}
kotlin.js {
@ -25,21 +25,32 @@ kotlin.sourceSets {
}
}
commonTest {
dependencies {
implementation(project(":kmath-complex"))
}
}
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"))

View File

@ -22,18 +22,18 @@ RealField.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;
public final Double invoke(Map<Symbol, Double> arguments) {
public final Double invoke(Map<Symbol, ? extends Double> arguments) {
return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2);
}

View File

@ -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))

View File

@ -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) }
@ -24,7 +24,7 @@ public object MstSpace : Space<MST>, NumericAlgebra<MST> {
public override val zero: MST.Numeric by lazy { number(0.0) }
public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value)
public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value)
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(value)
public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b)
public override operator fun MST.unaryPlus(): MST.Unary =
unaryOperationFunction(SpaceOperations.PLUS_OPERATION)(this)
@ -56,7 +56,7 @@ public object MstRing : Ring<MST>, RingWithNumbers<MST> {
public override val one: MST.Numeric by lazy { number(1.0) }
public override fun number(value: Number): MST.Numeric = MstSpace.number(value)
public override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value)
public override fun bindSymbol(value: String): MST.Symbolic = MstSpace.bindSymbol(value)
public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b)
public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k)
public override fun multiply(a: MST, b: MST): MST.Binary =
@ -84,7 +84,7 @@ public object MstField : Field<MST>, RingWithNumbers<MST> {
public override val one: MST.Numeric
get() = MstRing.one
public override fun symbol(value: String): MST.Symbolic = MstRing.symbol(value)
public override fun bindSymbol(value: String): MST.Symbolic = MstRing.bindSymbol(value)
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
public override fun 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)
@ -113,7 +113,7 @@ public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
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 = MstField.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)

View File

@ -1,7 +1,7 @@
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.operations.*
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
@ -15,14 +15,23 @@ import kotlin.contracts.contract
*/
public class MstExpression<T, out A : Algebra<T>>(public val algebra: A, public val mst: MST) : Expression<T> {
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<*>)

View File

@ -1,3 +0,0 @@
package kscience.kmath.estree.internal.astring
internal typealias Generator = Any

View File

@ -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
}

View File

@ -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
}

View File

@ -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.expressions.Symbol
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {
private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> {

View File

@ -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?

View File

@ -0,0 +1,3 @@
package space.kscience.kmath.estree.internal.astring
internal typealias Generator = Any

View File

@ -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)

View File

@ -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"

View File

@ -1,4 +1,4 @@
package kscience.kmath.estree.internal.estree
package space.kscience.kmath.estree.internal.estree
import kotlin.js.RegExp

View File

@ -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
}

View File

@ -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?

View File

@ -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

View File

@ -1,11 +1,11 @@
package kscience.kmath.estree
package space.kscience.kmath.estree
import kscience.kmath.ast.*
import kscience.kmath.expressions.invoke
import kscience.kmath.operations.ByteRing
import kscience.kmath.operations.ComplexField
import kscience.kmath.operations.RealField
import kscience.kmath.operations.toComplex
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.RealField
import kotlin.test.Test
import kotlin.test.assertEquals
@ -22,7 +22,7 @@ internal class TestESTreeConsistencyWithInterpreter {
),
number(1)
) + symbol("x") + zero
) + bindSymbol("x") + zero
}("x" to MST.Numeric(2))
val res2 = MstSpace.mstInSpace {
@ -35,7 +35,7 @@ internal class TestESTreeConsistencyWithInterpreter {
),
number(1)
) + symbol("x") + zero
) + bindSymbol("x") + zero
}.compile()("x" to MST.Numeric(2))
assertEquals(res1, res2)
@ -46,7 +46,7 @@ internal class TestESTreeConsistencyWithInterpreter {
val res1 = ByteRing.mstInRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(symbol("x") - (2.toByte() + (multiply(
(bindSymbol("x") - (2.toByte() + (multiply(
add(number(1), number(1)),
2
) + 1.toByte()))) * 3.0 - 1.toByte()
@ -59,7 +59,7 @@ internal class TestESTreeConsistencyWithInterpreter {
val res2 = ByteRing.mstInRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(symbol("x") - (2.toByte() + (multiply(
(bindSymbol("x") - (2.toByte() + (multiply(
add(number(1), number(1)),
2
) + 1.toByte()))) * 3.0 - 1.toByte()
@ -75,7 +75,7 @@ internal class TestESTreeConsistencyWithInterpreter {
fun realField() {
val res1 = RealField.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") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -83,7 +83,7 @@ internal class TestESTreeConsistencyWithInterpreter {
val res2 = RealField.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") + (multiply(add(number(1.0), number(1.0)), 2) + 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") + (multiply(add(number(1.0), number(1.0)), 2) + 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") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero

View File

@ -1,10 +1,10 @@
package kscience.kmath.estree
package space.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 space.kscience.kmath.ast.mstInExtendedField
import space.kscience.kmath.ast.mstInField
import space.kscience.kmath.ast.mstInSpace
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.RealField
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
@ -12,27 +12,27 @@ import kotlin.test.assertEquals
internal class TestESTreeOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
val expression = RealField.mstInSpace { -symbol("x") }.compile()
val expression = RealField.mstInSpace { -bindSymbol("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 expression = RealField.mstInSpace { -bindSymbol("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)
val res = RealField.mstInField { bindSymbol("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 e = RealField.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()) }

View File

@ -1,52 +1,52 @@
package kscience.kmath.estree
package space.kscience.kmath.estree
import kscience.kmath.ast.mstInField
import kscience.kmath.expressions.invoke
import kscience.kmath.operations.RealField
import space.kscience.kmath.ast.mstInField
import space.kscience.kmath.expressions.invoke
import space.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()
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
assertEquals(2.0, expr("x" to 2.0))
}
@Test
fun testUnaryMinus() {
val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile()
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
assertEquals(-2.0, expr("x" to 2.0))
}
@Test
fun testAdd() {
val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile()
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
assertEquals(4.0, expr("x" to 2.0))
}
@Test
fun testSine() {
val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile()
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
assertEquals(0.0, expr("x" to 0.0))
}
@Test
fun testMinus() {
val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile()
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
assertEquals(0.0, expr("x" to 2.0))
}
@Test
fun testDivide() {
val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile()
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
assertEquals(1.0, expr("x" to 2.0))
}
@Test
fun testPower() {
val expr = RealField
.mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) }
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
.compile()
assertEquals(4.0, expr("x" to 2.0))

View File

@ -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() }
}
}

View File

@ -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
}

View File

@ -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
@ -83,7 +82,7 @@ internal class AsmBuilder<T>(
ACC_PUBLIC or ACC_FINAL,
"invoke",
getMethodDescriptor(tType, MAP_TYPE),
"(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}${if (Modifier.isFinal(classOfT.modifiers)) "" else "+"}${tType.descriptor}>;)${tType.descriptor}",
"(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}",
null,
).instructionAdapter {
invokeMethodVisitor = this
@ -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") }
}
}

View File

@ -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

View File

@ -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.expressions.StringSymbol
import space.kscience.kmath.expressions.Symbol
/**
* Gets value with given [key] or throws [NoSuchElementException] whenever it is not present.

View File

@ -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.PowerOperations
import space.kscience.kmath.operations.RingOperations
import space.kscience.kmath.operations.SpaceOperations
/**
* 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) }

View File

@ -1,11 +1,11 @@
package kscience.kmath.asm
package space.kscience.kmath.asm
import kscience.kmath.ast.*
import kscience.kmath.expressions.invoke
import kscience.kmath.operations.ByteRing
import kscience.kmath.operations.ComplexField
import kscience.kmath.operations.RealField
import kscience.kmath.operations.toComplex
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.RealField
import kotlin.test.Test
import kotlin.test.assertEquals
@ -22,7 +22,7 @@ internal class TestAsmConsistencyWithInterpreter {
),
number(1)
) + symbol("x") + zero
) + bindSymbol("x") + zero
}("x" to MST.Numeric(2))
val res2 = MstSpace.mstInSpace {
@ -35,7 +35,7 @@ internal class TestAsmConsistencyWithInterpreter {
),
number(1)
) + symbol("x") + zero
) + bindSymbol("x") + zero
}.compile()("x" to MST.Numeric(2))
assertEquals(res1, res2)
@ -46,7 +46,7 @@ internal class TestAsmConsistencyWithInterpreter {
val res1 = ByteRing.mstInRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(symbol("x") - (2.toByte() + (multiply(
(bindSymbol("x") - (2.toByte() + (multiply(
add(number(1), number(1)),
2
) + 1.toByte()))) * 3.0 - 1.toByte()
@ -59,7 +59,7 @@ internal class TestAsmConsistencyWithInterpreter {
val res2 = ByteRing.mstInRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(symbol("x") - (2.toByte() + (multiply(
(bindSymbol("x") - (2.toByte() + (multiply(
add(number(1), number(1)),
2
) + 1.toByte()))) * 3.0 - 1.toByte()
@ -75,7 +75,7 @@ internal class TestAsmConsistencyWithInterpreter {
fun realField() {
val res1 = RealField.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") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -83,7 +83,7 @@ internal class TestAsmConsistencyWithInterpreter {
val res2 = RealField.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") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -96,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") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -104,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") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero

View File

@ -1,10 +1,10 @@
package kscience.kmath.asm
package space.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 space.kscience.kmath.ast.mstInExtendedField
import space.kscience.kmath.ast.mstInField
import space.kscience.kmath.ast.mstInSpace
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.RealField
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
@ -12,27 +12,27 @@ import kotlin.test.assertEquals
internal class TestAsmOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
val expression = RealField.mstInSpace { -symbol("x") }.compile()
val expression = RealField.mstInSpace { -bindSymbol("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 expression = RealField.mstInSpace { -bindSymbol("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)
val res = RealField.mstInField { bindSymbol("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 e = RealField.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()) }

View File

@ -1,52 +1,52 @@
package kscience.kmath.asm
package space.kscience.kmath.asm
import kscience.kmath.ast.mstInField
import kscience.kmath.expressions.invoke
import kscience.kmath.operations.RealField
import space.kscience.kmath.ast.mstInField
import space.kscience.kmath.expressions.invoke
import space.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()
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
assertEquals(2.0, expr("x" to 2.0))
}
@Test
fun testUnaryMinus() {
val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile()
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
assertEquals(-2.0, expr("x" to 2.0))
}
@Test
fun testAdd() {
val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile()
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
assertEquals(4.0, expr("x" to 2.0))
}
@Test
fun testSine() {
val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile()
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
assertEquals(0.0, expr("x" to 0.0))
}
@Test
fun testMinus() {
val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile()
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
assertEquals(0.0, expr("x" to 2.0))
}
@Test
fun testDivide() {
val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile()
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
assertEquals(1.0, expr("x" to 2.0))
}
@Test
fun testPower() {
val expr = RealField
.mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) }
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
.compile()
assertEquals(4.0, expr("x" to 2.0))

View File

@ -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() }
}
}

View File

@ -1,7 +1,7 @@
package kscience.kmath.ast
package space.kscience.kmath.ast
import kscience.kmath.operations.Field
import kscience.kmath.operations.RealField
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.RealField
import kotlin.test.Test
import kotlin.test.assertEquals

View File

@ -1,10 +1,10 @@
package kscience.kmath.ast
package space.kscience.kmath.ast
import kscience.kmath.expressions.invoke
import kscience.kmath.operations.Algebra
import kscience.kmath.operations.Complex
import kscience.kmath.operations.ComplexField
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.RealField
import kotlin.test.Test
import kotlin.test.assertEquals
@ -40,7 +40,7 @@ internal class ParserTest {
@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()

View File

@ -1,12 +1,17 @@
plugins {
id("ru.mipt.npm.jvm")
id("ru.mipt.npm.gradle.jvm")
}
description = "Commons math binding for kmath"
dependencies {
api(project(":kmath-core"))
api(project(":kmath-complex"))
api(project(":kmath-coroutines"))
api(project(":kmath-stat"))
api(project(":kmath-functions"))
api("org.apache.commons:commons-math3:3.6.1")
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -1,10 +1,10 @@
package kscience.kmath.commons.expressions
package space.kscience.kmath.commons.expressions
import kscience.kmath.expressions.*
import kscience.kmath.misc.UnstableKMathAPI
import kscience.kmath.operations.ExtendedField
import kscience.kmath.operations.RingWithNumbers
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.RingWithNumbers
/**
* A field over commons-math [DerivativeStructure].
@ -48,11 +48,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" }

View File

@ -1,12 +1,9 @@
package kscience.kmath.commons.linear
package space.kscience.kmath.commons.linear
import kscience.kmath.linear.DiagonalFeature
import kscience.kmath.linear.MatrixContext
import kscience.kmath.linear.MatrixWrapper
import kscience.kmath.linear.Point
import kscience.kmath.misc.UnstableKMathAPI
import kscience.kmath.structures.Matrix
import org.apache.commons.math3.linear.*
import space.kscience.kmath.linear.*
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.structures.RealBuffer
import kotlin.reflect.KClass
import kotlin.reflect.cast
@ -17,8 +14,40 @@ public inline class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
@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(it) }
}?.let(type::cast)
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
}
@ -47,9 +76,9 @@ public object CMMatrixContext : MatrixContext<Double, CMMatrix> {
return CMMatrix(Array2DRowRealMatrix(array))
}
public fun Matrix<Double>.toCM(): CMMatrix = when {
this is CMMatrix -> this
this is MatrixWrapper && matrix is CMMatrix -> matrix as CMMatrix
@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) } }

View File

@ -1,8 +1,8 @@
package kscience.kmath.commons.linear
package space.kscience.kmath.commons.linear
import kscience.kmath.linear.Point
import kscience.kmath.structures.Matrix
import org.apache.commons.math3.linear.*
import space.kscience.kmath.linear.Matrix
import space.kscience.kmath.linear.Point
public enum class CMDecomposition {
LUP,

View File

@ -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,6 +9,11 @@ import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjuga
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
import space.kscience.kmath.expressions.*
import space.kscience.kmath.stat.OptimizationFeature
import space.kscience.kmath.stat.OptimizationProblem
import space.kscience.kmath.stat.OptimizationProblemFactory
import space.kscience.kmath.stat.OptimizationResult
import kotlin.reflect.KClass
public operator fun PointValuePair.component1(): DoubleArray = point

View File

@ -1,16 +1,16 @@
package kscience.kmath.commons.optimization
package space.kscience.kmath.commons.optimization
import kscience.kmath.commons.expressions.DerivativeStructureField
import kscience.kmath.expressions.DifferentiableExpression
import kscience.kmath.expressions.Expression
import kscience.kmath.expressions.Symbol
import kscience.kmath.stat.Fitting
import kscience.kmath.stat.OptimizationResult
import kscience.kmath.stat.optimizeWith
import kscience.kmath.structures.Buffer
import kscience.kmath.structures.asBuffer
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType
import space.kscience.kmath.commons.expressions.DerivativeStructureField
import space.kscience.kmath.expressions.DifferentiableExpression
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.stat.Fitting
import space.kscience.kmath.stat.OptimizationResult
import space.kscience.kmath.stat.optimizeWith
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.asBuffer
/**
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation

View File

@ -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,

View File

@ -1,13 +1,13 @@
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.operations.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.*
/**

View File

@ -1,6 +1,6 @@
package kscience.kmath.commons.expressions
package space.kscience.kmath.commons.expressions
import kscience.kmath.expressions.*
import space.kscience.kmath.expressions.*
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.test.Test
@ -24,7 +24,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))

View File

@ -1,12 +1,12 @@
package kscience.kmath.commons.optimization
package space.kscience.kmath.commons.optimization
import kscience.kmath.commons.expressions.DerivativeStructureExpression
import kscience.kmath.expressions.symbol
import kscience.kmath.stat.Distribution
import kscience.kmath.stat.Fitting
import kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.normal
import org.junit.jupiter.api.Test
import space.kscience.kmath.commons.expressions.DerivativeStructureExpression
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.stat.Distribution
import space.kscience.kmath.stat.Fitting
import space.kscience.kmath.stat.RandomGenerator
import space.kscience.kmath.stat.normal
import kotlin.math.pow
internal class OptimizeTest {
@ -56,7 +56,7 @@ internal class OptimizeTest {
val yErr = List(x.size) { sigma }
val chi2 = Fitting.chiSquared(x, y, yErr) { x1 ->
val cWithDefault = bindOrNull(c) ?: one
val cWithDefault = bindSymbolOrNull(c) ?: one
bind(a) * x1.pow(2) + bind(b) * x1 + cWithDefault
}

48
kmath-complex/README.md Normal file
View File

@ -0,0 +1,48 @@
# The Core Module (`kmath-core`)
Complex and hypercomplex number systems in KMath:
- [complex](src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
- [quaternion](src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
> #### Artifact:
>
> This module artifact: `space.kscience:kmath-complex:0.2.0`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-complex/_latestVersion)
>
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-complex/_latestVersion)
>
> **Gradle:**
>
> ```gradle
> repositories {
> maven { url 'https://repo.kotlin.link' }
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
>// Uncomment if repo.kotlin.link is unavailable
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
> }
>
> dependencies {
> implementation 'space.kscience:kmath-complex:0.2.0'
> }
> ```
> **Gradle Kotlin DSL:**
>
> ```kotlin
> repositories {
> maven("https://repo.kotlin.link")
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
>// Uncomment if repo.kotlin.link is unavailable
>// maven("https://dl.bintray.com/mipt-npm/kscience")
>// maven("https://dl.bintray.com/mipt-npm/dev")
> }
>
> dependencies {
> implementation("space.kscience:kmath-complex:0.2.0")
> }
> ```

View File

@ -0,0 +1,36 @@
import ru.mipt.npm.gradle.Maturity
plugins {
id("ru.mipt.npm.gradle.mpp")
id("ru.mipt.npm.gradle.native")
}
kotlin.sourceSets {
all {
languageSettings.useExperimentalAnnotation("kscience.kmath.misc.UnstableKMathAPI")
}
commonMain {
dependencies {
api(project(":kmath-core"))
}
}
}
readme {
description = "Complex numbers and quaternions."
maturity = Maturity.PROTOTYPE
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(
id = "complex",
description = "Complex Numbers",
ref = "src/commonMain/kotlin/kscience/kmath/complex/Complex.kt"
)
feature(
id = "quaternion",
description = "Quaternions",
ref = "src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt"
)
}

View File

@ -0,0 +1,7 @@
# The Core Module (`kmath-core`)
Complex and hypercomplex number systems in KMath:
${features}
${artifact}

View File

@ -1,13 +1,17 @@
package kscience.kmath.operations
package space.kscience.kmath.complex
import kscience.kmath.memory.MemoryReader
import kscience.kmath.memory.MemorySpec
import kscience.kmath.memory.MemoryWriter
import kscience.kmath.misc.UnstableKMathAPI
import kscience.kmath.structures.Buffer
import kscience.kmath.structures.MemoryBuffer
import kscience.kmath.structures.MutableBuffer
import kscience.kmath.structures.MutableMemoryBuffer
import space.kscience.kmath.memory.MemoryReader
import space.kscience.kmath.memory.MemorySpec
import space.kscience.kmath.memory.MemoryWriter
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.FieldElement
import space.kscience.kmath.operations.Norm
import space.kscience.kmath.operations.RingWithNumbers
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MemoryBuffer
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableMemoryBuffer
import kotlin.math.*
/**
@ -44,72 +48,69 @@ private val PI_DIV_2 = Complex(PI / 2, 0)
*/
@OptIn(UnstableKMathAPI::class)
public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, RingWithNumbers<Complex> {
override val zero: Complex = 0.0.toComplex()
override val one: Complex = 1.0.toComplex()
public override val zero: Complex = 0.0.toComplex()
public override val one: Complex = 1.0.toComplex()
/**
* The imaginary unit.
*/
public val i: Complex = Complex(0.0, 1.0)
public val i: Complex by lazy { Complex(0.0, 1.0) }
override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im)
public override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im)
public override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble())
override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble())
override fun multiply(a: Complex, b: Complex): Complex =
public override fun multiply(a: Complex, b: Complex): Complex =
Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re)
override fun divide(a: Complex, b: Complex): Complex = when {
b.re.isNaN() || b.im.isNaN() -> Complex(Double.NaN, Double.NaN)
(if (b.im < 0) -b.im else +b.im) < (if (b.re < 0) -b.re else +b.re) -> {
public override fun divide(a: Complex, b: Complex): Complex = when {
abs(b.im) < abs(b.re) -> {
val wr = b.im / b.re
val wd = b.re + wr * b.im
if (wd.isNaN() || wd == 0.0)
Complex(Double.NaN, Double.NaN)
throw ArithmeticException("Division by zero or infinity")
else
Complex((a.re + a.im * wr) / wd, (a.im - a.re * wr) / wd)
}
b.im == 0.0 -> Complex(Double.NaN, Double.NaN)
b.im == 0.0 -> throw ArithmeticException("Division by zero")
else -> {
val wr = b.re / b.im
val wd = b.im + wr * b.re
if (wd.isNaN() || wd == 0.0)
Complex(Double.NaN, Double.NaN)
throw ArithmeticException("Division by zero or infinity")
else
Complex((a.re * wr + a.im) / wd, (a.im * wr - a.re) / wd)
}
}
override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2
override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2
public override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2
public override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2
override fun tan(arg: Complex): Complex {
public override fun tan(arg: Complex): Complex {
val e1 = exp(-i * arg)
val e2 = exp(i * arg)
return i * (e1 - e2) / (e1 + e2)
}
override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg)
override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg)
public override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg)
public override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg)
override fun atan(arg: Complex): Complex {
public override fun atan(arg: Complex): Complex {
val iArg = i * arg
return i * (ln(1 - iArg) - ln(1 + iArg)) / 2
}
override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0)
public override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0)
arg.re.pow(pow.toDouble()).toComplex()
else
exp(pow * ln(arg))
override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im))
public override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im))
override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re)
public override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re)
/**
* Adds complex number to real one.
@ -156,9 +157,9 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Rin
*/
public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this)
override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
override fun symbol(value: String): Complex = if (value == "i") i else super<ExtendedField>.symbol(value)
public override fun bindSymbol(value: String): Complex = if (value == "i") i else super<ExtendedField>.bindSymbol(value)
}
/**
@ -167,30 +168,22 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Rin
* @property re The real part.
* @property im The imaginary part.
*/
public data class Complex(val re: Double, val im: Double) : FieldElement<Complex, Complex, ComplexField>,
Comparable<Complex> {
@OptIn(UnstableKMathAPI::class)
public data class Complex(val re: Double, val im: Double) : FieldElement<Complex, ComplexField> {
public constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble())
public constructor(re: Number) : this(re.toDouble(), 0.0)
override val context: ComplexField get() = ComplexField
override fun unwrap(): Complex = this
override fun Complex.wrap(): Complex = this
override fun compareTo(other: Complex): Int = r.compareTo(other.r)
override fun toString(): String {
return "($re + i*$im)"
}
public override val context: ComplexField get() = ComplexField
public override fun toString(): String = "($re + i*$im)"
public companion object : MemorySpec<Complex> {
override val objectSize: Int
public override val objectSize: Int
get() = 16
override fun MemoryReader.read(offset: Int): Complex = Complex(readDouble(offset), readDouble(offset + 8))
public override fun MemoryReader.read(offset: Int): Complex = Complex(readDouble(offset), readDouble(offset + 8))
override fun MemoryWriter.write(offset: Int, value: Complex) {
public override fun MemoryWriter.write(offset: Int, value: Complex) {
writeDouble(offset, value.re)
writeDouble(offset + 8, value.im)
}
@ -204,7 +197,7 @@ public data class Complex(val re: Double, val im: Double) : FieldElement<Complex
* @receiver the real part.
* @return the new complex number.
*/
public fun Number.toComplex(): Complex = Complex(this, 0.0)
public fun Number.toComplex(): Complex = Complex(this)
/**
* Creates a new buffer of complex numbers with the specified [size], where each element is calculated by calling the

View File

@ -0,0 +1,118 @@
package space.kscience.kmath.complex
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.BufferedNDField
import space.kscience.kmath.nd.NDAlgebra
import space.kscience.kmath.nd.NDBuffer
import space.kscience.kmath.nd.NDStructure
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.RingWithNumbers
import space.kscience.kmath.structures.Buffer
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
/**
* An optimized nd-field for complex numbers
*/
@OptIn(UnstableKMathAPI::class)
public class ComplexNDField(
shape: IntArray,
) : BufferedNDField<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
RingWithNumbers<NDStructure<Complex>>,
ExtendedField<NDStructure<Complex>> {
override val zero: NDBuffer<Complex> by lazy { produce { zero } }
override val one: NDBuffer<Complex> by lazy { produce { one } }
override fun number(value: Number): NDBuffer<Complex> {
val d = value.toComplex() // minimize conversions
return produce { d }
}
//
// @Suppress("OVERRIDE_BY_INLINE")
// override inline fun map(
// arg: AbstractNDBuffer<Double>,
// transform: RealField.(Double) -> Double,
// ): RealNDElement {
// check(arg)
// val array = RealBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) }
// return BufferedNDFieldElement(this, array)
// }
//
// @Suppress("OVERRIDE_BY_INLINE")
// override inline fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement {
// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
// return BufferedNDFieldElement(this, array)
// }
//
// @Suppress("OVERRIDE_BY_INLINE")
// override inline fun mapIndexed(
// arg: AbstractNDBuffer<Double>,
// transform: RealField.(index: IntArray, Double) -> Double,
// ): RealNDElement {
// check(arg)
// return BufferedNDFieldElement(
// this,
// RealBuffer(arg.strides.linearSize) { offset ->
// elementContext.transform(
// arg.strides.index(offset),
// arg.buffer[offset]
// )
// })
// }
//
// @Suppress("OVERRIDE_BY_INLINE")
// override inline fun combine(
// a: AbstractNDBuffer<Double>,
// b: AbstractNDBuffer<Double>,
// transform: RealField.(Double, Double) -> Double,
// ): RealNDElement {
// check(a, b)
// val buffer = RealBuffer(strides.linearSize) { offset ->
// elementContext.transform(a.buffer[offset], b.buffer[offset])
// }
// return BufferedNDFieldElement(this, buffer)
// }
override fun power(arg: NDStructure<Complex>, pow: Number): NDBuffer<Complex> = arg.map() { power(it, pow) }
override fun exp(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { exp(it) }
override fun ln(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { ln(it) }
override fun sin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { sin(it) }
override fun cos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { cos(it) }
override fun tan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { tan(it) }
override fun asin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { asin(it) }
override fun acos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { acos(it) }
override fun atan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { atan(it) }
override fun sinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { sinh(it) }
override fun cosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { cosh(it) }
override fun tanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { tanh(it) }
override fun asinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { asinh(it) }
override fun acosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { acosh(it) }
override fun atanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { atanh(it) }
}
/**
* Fast element production using function inlining
*/
public inline fun BufferedNDField<Complex, ComplexField>.produceInline(initializer: ComplexField.(Int) -> Complex): NDBuffer<Complex> {
contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) }
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) }
return NDBuffer(strides, buffer)
}
public fun NDAlgebra.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape)
/**
* Produce a context for n-dimensional operations inside this real field
*/
public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R {
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
return ComplexNDField(shape).action()
}

View File

@ -0,0 +1,263 @@
package space.kscience.kmath.complex
import space.kscience.kmath.memory.MemoryReader
import space.kscience.kmath.memory.MemorySpec
import space.kscience.kmath.memory.MemoryWriter
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MemoryBuffer
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableMemoryBuffer
import kotlin.math.*
/**
* This quaternion's conjugate.
*/
public val Quaternion.conjugate: Quaternion
get() = QuaternionField { z - x * i - y * j - z * k }
/**
* This quaternion's reciprocal.
*/
public val Quaternion.reciprocal: Quaternion
get() {
val n = QuaternionField { norm(this@reciprocal) }
return conjugate / (n * n)
}
/**
* Absolute value of the quaternion.
*/
public val Quaternion.r: Double
get() = sqrt(w * w + x * x + y * y + z * z)
/**
* A field of [Quaternion].
*/
@OptIn(UnstableKMathAPI::class)
public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Quaternion>, PowerOperations<Quaternion>,
ExponentialOperations<Quaternion>, RingWithNumbers<Quaternion> {
override val zero: Quaternion = 0.toQuaternion()
override val one: Quaternion = 1.toQuaternion()
/**
* The `i` quaternion unit.
*/
public val i: Quaternion = Quaternion(0, 1)
/**
* The `j` quaternion unit.
*/
public val j: Quaternion = Quaternion(0, 0, 1)
/**
* The `k` quaternion unit.
*/
public val k: Quaternion = Quaternion(0, 0, 0, 1)
public override fun add(a: Quaternion, b: Quaternion): Quaternion =
Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z)
public override fun multiply(a: Quaternion, k: Number): Quaternion {
val d = k.toDouble()
return Quaternion(a.w * d, a.x * d, a.y * d, a.z * d)
}
public override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion(
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
)
public override fun divide(a: Quaternion, b: Quaternion): Quaternion {
val s = b.w * b.w + b.x * b.x + b.y * b.y + b.z * b.z
return Quaternion(
(b.w * a.w + b.x * a.x + b.y * a.y + b.z * a.z) / s,
(b.w * a.x - b.x * a.w - b.y * a.z + b.z * a.y) / s,
(b.w * a.y + b.x * a.z - b.y * a.w - b.z * a.x) / s,
(b.w * a.z - b.x * a.y + b.y * a.x - b.z * a.w) / s,
)
}
public override fun power(arg: Quaternion, pow: Number): Quaternion {
if (pow is Int) return pwr(arg, pow)
if (floor(pow.toDouble()) == pow.toDouble()) return pwr(arg, pow.toInt())
return exp(pow * ln(arg))
}
private fun pwr(x: Quaternion, a: Int): Quaternion = when {
a < 0 -> -(pwr(x, -a))
a == 0 -> one
a == 1 -> x
a == 2 -> pwr2(x)
a == 3 -> pwr3(x)
a == 4 -> pwr4(x)
else -> {
val x4 = pwr4(x)
var y = x4
repeat((1 until a / 4).count()) { y *= x4 }
if (a % 4 == 3) y *= pwr3(x)
if (a % 4 == 2) y *= pwr2(x)
if (a % 4 == 1) y *= x
y
}
}
private fun pwr2(x: Quaternion): Quaternion {
val aa = 2 * x.w
return Quaternion(x.w * x.w - (x.x * x.x + x.y * x.y + x.z * x.z), aa * x.x, aa * x.y, aa * x.z)
}
private fun pwr3(x: Quaternion): Quaternion {
val a2 = x.w * x.w
val n1 = x.x * x.x + x.y * x.y + x.z * x.z
val n2 = 3.0 * a2 - n1
return Quaternion(x.w * (a2 - 3 * n1), x.x * n2, x.y * n2, x.z * n2)
}
private fun pwr4(x: Quaternion): Quaternion {
val a2 = x.w * x.w
val n1 = x.x * x.x + x.y * x.y + x.z * x.z
val n2 = 4 * x.w * (a2 - n1)
return Quaternion(a2 * a2 - 6 * a2 * n1 + n1 * n1, x.x * n2, x.y * n2, x.z * n2)
}
public override fun exp(arg: Quaternion): Quaternion {
val un = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z
if (un == 0.0) return exp(arg.w).toQuaternion()
val n1 = sqrt(un)
val ea = exp(arg.w)
val n2 = ea * sin(n1) / n1
return Quaternion(ea * cos(n1), n2 * arg.x, n2 * arg.y, n2 * arg.z)
}
public override fun ln(arg: Quaternion): Quaternion {
val nu2 = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z
if (nu2 == 0.0)
return if (arg.w > 0)
Quaternion(ln(arg.w), 0, 0, 0)
else {
val l = ComplexField { ComplexField.ln(arg.w.toComplex()) }
Quaternion(l.re, l.im, 0, 0)
}
val a = arg.w
check(nu2 > 0)
val n = sqrt(a * a + nu2)
val th = acos(a / n) / sqrt(nu2)
return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z)
}
public override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z)
public override operator fun Number.minus(b: Quaternion): Quaternion =
Quaternion(toDouble() - b.w, -b.x, -b.y, -b.z)
public override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z)
public override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.toDouble(), x, y, z)
public override operator fun Number.times(b: Quaternion): Quaternion =
Quaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z)
public override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z)
public override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg)
public override fun bindSymbol(value: String): Quaternion = when (value) {
"i" -> i
"j" -> j
"k" -> k
else -> super<Field>.bindSymbol(value)
}
}
/**
* Represents `double`-based quaternion.
*
* @property w The first component.
* @property x The second component.
* @property y The third component.
* @property z The fourth component.
*/
@OptIn(UnstableKMathAPI::class)
public data class Quaternion(
val w: Double, val x: Double, val y: Double, val z: Double,
) : FieldElement<Quaternion, QuaternionField> {
public constructor(w: Number, x: Number, y: Number, z: Number) : this(
w.toDouble(),
x.toDouble(),
y.toDouble(),
z.toDouble(),
)
public constructor(w: Number, x: Number, y: Number) : this(w.toDouble(), x.toDouble(), y.toDouble(), 0.0)
public constructor(w: Number, x: Number) : this(w.toDouble(), x.toDouble(), 0.0, 0.0)
public constructor(w: Number) : this(w.toDouble(), 0.0, 0.0, 0.0)
public constructor(wx: Complex, yz: Complex) : this(wx.re, wx.im, yz.re, yz.im)
public constructor(wx: Complex) : this(wx.re, wx.im, 0, 0)
init {
require(!w.isNaN()) { "w-component of quaternion is not-a-number" }
require(!x.isNaN()) { "x-component of quaternion is not-a-number" }
require(!y.isNaN()) { "x-component of quaternion is not-a-number" }
require(!z.isNaN()) { "x-component of quaternion is not-a-number" }
}
public override val context: QuaternionField
get() = QuaternionField
/**
* Returns a string representation of this quaternion.
*/
public override fun toString(): String = "($w + $x * i + $y * j + $z * k)"
public companion object : MemorySpec<Quaternion> {
public override val objectSize: Int
get() = 32
public override fun MemoryReader.read(offset: Int): Quaternion =
Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24))
public override fun MemoryWriter.write(offset: Int, value: Quaternion) {
writeDouble(offset, value.w)
writeDouble(offset + 8, value.x)
writeDouble(offset + 16, value.y)
writeDouble(offset + 24, value.z)
}
}
}
/**
* Creates a quaternion with real part equal to this real.
*
* @receiver the real part.
* @return a new quaternion.
*/
public fun Number.toQuaternion(): Quaternion = Quaternion(this)
/**
* Creates a quaternion with `w`-component equal to `re`-component of given complex and `x`-component equal to
* `im`-component of given complex.
*
* @receiver the complex number.
* @return a new quaternion.
*/
public fun Complex.toQuaternion(): Quaternion = Quaternion(this)
/**
* Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the
* specified [init] function.
*/
public inline fun Buffer.Companion.quaternion(size: Int, init: (Int) -> Quaternion): Buffer<Quaternion> =
MemoryBuffer.create(Quaternion, size, init)
/**
* Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the
* specified [init] function.
*/
public inline fun MutableBuffer.Companion.quaternion(size: Int, init: (Int) -> Quaternion): MutableBuffer<Quaternion> =
MutableMemoryBuffer.create(Quaternion, size, init)

View File

@ -1,7 +1,6 @@
package kscience.kmath.structures
package space.kscience.kmath.complex
import kscience.kmath.operations.Complex
import kscience.kmath.operations.complex
import space.kscience.kmath.structures.Buffer
import kotlin.test.Test
import kotlin.test.assertEquals
@ -11,4 +10,4 @@ class ComplexBufferSpecTest {
val buffer = Buffer.complex(20) { Complex(it.toDouble(), -it.toDouble()) }
assertEquals(Complex(5.0, -5.0), buffer[5])
}
}
}

View File

@ -1,6 +1,6 @@
package kscience.kmath.operations
package space.kscience.kmath.complex
import kscience.kmath.operations.internal.FieldVerifier
import space.kscience.kmath.operations.invoke
import kotlin.math.PI
import kotlin.math.abs
import kotlin.test.Test
@ -8,8 +8,9 @@ import kotlin.test.assertEquals
import kotlin.test.assertTrue
internal class ComplexFieldTest {
@Test
fun verify() = ComplexField { FieldVerifier(this, 42.0 * i, 66.0 + 28 * i, 2.0 + 0 * i, 5).verify() }
// TODO make verifier classes available in this source set
// @Test
// fun verify() = ComplexField { FieldVerifier(this, 42.0 * i, 66.0 + 28 * i, 2.0 + 0 * i, 5).verify() }
@Test
fun testAddition() {
@ -37,8 +38,6 @@ internal class ComplexFieldTest {
assertEquals(Complex(42, 42), ComplexField { Complex(0, 168) / Complex(2, 2) })
assertEquals(Complex(42, 56), ComplexField { Complex(86, 56) - 44 })
assertEquals(Complex(42, 56), ComplexField { 86 - Complex(44, -56) })
assertEquals(Complex(Double.NaN, Double.NaN), ComplexField { Complex(1, 1) / Complex(Double.NaN, Double.NaN) })
assertEquals(Complex(Double.NaN, Double.NaN), ComplexField { Complex(1, 1) / Complex(0, 0) })
}
@Test

View File

@ -0,0 +1,31 @@
package space.kscience.kmath.complex
import space.kscience.kmath.operations.invoke
import kotlin.math.sqrt
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
internal class ComplexTest {
@Test
fun conjugate() = ComplexField { assertEquals(Complex(0, 42), Complex(0, -42).conjugate) }
@Test
fun reciprocal() = ComplexField { assertTrue((Complex(0.5, -0.0) - 2.toComplex().reciprocal).r < 1e-10) }
@Test
fun r() = ComplexField { assertEquals(sqrt(2.0), (i + 1.0.toComplex()).r) }
@Test
fun theta() = assertEquals(0.0, 1.toComplex().theta)
@Test
fun toComplex() {
assertEquals(Complex(42), 42.toComplex())
assertEquals(Complex(42.0), 42.0.toComplex())
assertEquals(Complex(42f), 42f.toComplex())
assertEquals(Complex(42.0), 42.0.toComplex())
assertEquals(Complex(42.toByte()), 42.toByte().toComplex())
assertEquals(Complex(42.toShort()), 42.toShort().toComplex())
}
}

View File

@ -0,0 +1,26 @@
package space.kscience.kmath.complex
import space.kscience.kmath.expressions.FunctionalExpressionField
import space.kscience.kmath.expressions.bindSymbol
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class ExpressionFieldForComplexTest {
val x by symbol
@Test
fun testComplex() {
val context = FunctionalExpressionField(ComplexField)
val expression = context {
val x = bindSymbol(x)
x * x + 2 * x + one
}
assertEquals(expression(x to Complex(1.0, 0.0)), Complex(4.0, 0.0))
//assertEquals(expression(), Complex(9.0, 0.0))
}
}

View File

@ -0,0 +1,45 @@
package space.kscience.kmath.complex
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class QuaternionFieldTest {
@Test
fun testAddition() {
assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(16, 16) + Quaternion(26, 26) })
assertEquals(Quaternion(42, 16), QuaternionField { Quaternion(16, 16) + 26 })
assertEquals(Quaternion(42, 16), QuaternionField { 26 + Quaternion(16, 16) })
}
// @Test
// fun testSubtraction() {
// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(86, 55) - Quaternion(44, 13) })
// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 })
// assertEquals(Quaternion(42, 56), QuaternionField { 86 - Quaternion(44, -56) })
// }
@Test
fun testMultiplication() {
assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(4.2, 0) * Quaternion(10, 10) })
assertEquals(Quaternion(42, 21), QuaternionField { Quaternion(4.2, 2.1) * 10 })
assertEquals(Quaternion(42, 21), QuaternionField { 10 * Quaternion(4.2, 2.1) })
}
// @Test
// fun testDivision() {
// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(0, 168) / Quaternion(2, 2) })
// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 })
// assertEquals(Quaternion(42, 56) , QuaternionField { 86 - Quaternion(44, -56) })
// }
@Test
fun testPower() {
assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
assertEquals(
QuaternionField { i * 8 }.let { it.x.toInt() to it.w.toInt() },
QuaternionField { Quaternion(2, 2) pow 2 }.let { it.x.toInt() to it.w.toInt() })
}
}

View File

@ -2,17 +2,20 @@
The core features of KMath:
- [algebras](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures: contexts and elements
- [nd](src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures
- [algebras](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
- [nd](src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
- [linear](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
- [buffers](src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
- [expressions](src/commonMain/kotlin/kscience/kmath/expressions) : Functional Expressions
- [expressions](src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation.
- [domains](src/commonMain/kotlin/kscience/kmath/domains) : Domains
- [autodif](src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
> #### Artifact:
>
> This module artifact: `kscience.kmath:kmath-core:0.2.0-dev-4`.
> This module artifact: `space.kscience:kmath-core:0.2.0`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
>
@ -22,28 +25,31 @@ The core features of KMath:
>
> ```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://repo.kotlin.link' }
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
>
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
>// Uncomment if repo.kotlin.link is unavailable
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
> }
>
> dependencies {
> implementation 'kscience.kmath:kmath-core:0.2.0-dev-4'
> implementation 'space.kscience:kmath-core:0.2.0'
> }
> ```
> **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")
> maven("https://repo.kotlin.link")
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
>// Uncomment if repo.kotlin.link is unavailable
>// maven("https://dl.bintray.com/mipt-npm/kscience")
>// maven("https://dl.bintray.com/mipt-npm/dev")
> }
>
> dependencies {
> implementation("kscience.kmath:kmath-core:0.2.0-dev-4")
> implementation("space.kscience:kmath-core:0.2.0")
> }
> ```

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +1,45 @@
import ru.mipt.npm.gradle.Maturity
plugins {
id("ru.mipt.npm.mpp")
id("ru.mipt.npm.native")
id("ru.mipt.npm.gradle.mpp")
id("ru.mipt.npm.gradle.native")
}
kotlin.sourceSets.commonMain {
dependencies {
api(project(":kmath-memory"))
kotlin.sourceSets {
commonMain {
dependencies {
api(project(":kmath-memory"))
}
}
}
readme {
description = "Core classes, algebra definitions, basic linear algebra"
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
maturity = Maturity.DEVELOPMENT
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(
id = "algebras",
description = "Algebraic structures: contexts and elements",
description = """
Algebraic structures like rings, spaces and fields.
""".trimIndent(),
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
)
feature(
id = "nd",
description = "Many-dimensional structures",
description = "Many-dimensional structures and operations on them.",
ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt"
)
feature(
id = "linear",
description = """
Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
""".trimIndent(),
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
)
feature(
id = "buffers",
description = "One-dimensional structure",
@ -34,7 +48,11 @@ readme {
feature(
id = "expressions",
description = "Functional Expressions",
description = """
By writing a single mathematical expression once, users will be able to apply different types of
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation.
""".trimIndent(),
ref = "src/commonMain/kotlin/kscience/kmath/expressions"
)

View File

@ -1,68 +0,0 @@
package kscience.kmath.linear
import kscience.kmath.operations.Ring
import kscience.kmath.structures.*
/**
* Basic implementation of Matrix space based on [NDStructure]
*/
public class BufferMatrixContext<T : Any, R : Ring<T>>(
public override val elementContext: R,
private val bufferFactory: BufferFactory<T>,
) : GenericMatrixContext<T, R, BufferMatrix<T>> {
public override fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): BufferMatrix<T> {
val buffer = bufferFactory(rows * columns) { offset -> initializer(offset / columns, offset % columns) }
return BufferMatrix(rows, columns, buffer)
}
public override fun point(size: Int, initializer: (Int) -> T): Point<T> = bufferFactory(size, initializer)
public companion object
}
public class BufferMatrix<T : Any>(
public override val rowNum: Int,
public override val colNum: Int,
public val buffer: Buffer<out T>,
) : Matrix<T> {
init {
require(buffer.size == rowNum * colNum) { "Dimension mismatch for matrix structure" }
}
override val shape: IntArray get() = intArrayOf(rowNum, colNum)
public override operator fun get(index: IntArray): T = get(index[0], index[1])
public override operator fun get(i: Int, j: Int): T = buffer[i * colNum + j]
public override fun elements(): Sequence<Pair<IntArray, T>> = sequence {
for (i in 0 until rowNum) for (j in 0 until colNum) yield(intArrayOf(i, j) to get(i, j))
}
public override fun equals(other: Any?): Boolean {
if (this === other) return true
return when (other) {
is NDStructure<*> -> NDStructure.contentEquals(this, other)
else -> false
}
}
override fun hashCode(): Int {
var result = rowNum
result = 31 * result + colNum
result = 31 * result + buffer.hashCode()
return result
}
public override fun toString(): String {
return if (rowNum <= 5 && colNum <= 5)
"Matrix(rowsNum = $rowNum, colNum = $colNum)\n" +
rows.asSequence().joinToString(prefix = "(", postfix = ")", separator = "\n ") { buffer ->
buffer.asSequence().joinToString(separator = "\t") { it.toString() }
}
else "Matrix(rowsNum = $rowNum, colNum = $colNum)"
}
}

View File

@ -1,108 +0,0 @@
package kscience.kmath.operations
/**
* The generic mathematics elements which is able to store its context
*
* @param C the type of mathematical context for this element.
*/
public interface MathElement<C> {
/**
* The context this element belongs to.
*/
public val context: C
}
/**
* Represents element that can be wrapped to its "primitive" value.
*
* @param T the type wrapped by this wrapper.
* @param I the type of this wrapper.
*/
public interface MathWrapper<T, I> {
/**
* Unwraps [I] to [T].
*/
public fun unwrap(): T
/**
* Wraps [T] to [I].
*/
public fun T.wrap(): I
}
/**
* The element of [Space].
*
* @param T the type of space operation results.
* @param I self type of the element. Needed for static type checking.
* @param S the type of space.
*/
public interface SpaceElement<T, I : SpaceElement<T, I, S>, S : Space<T>> : MathElement<S>, MathWrapper<T, I> {
/**
* Adds element to this one.
*
* @param b the augend.
* @return the sum.
*/
public operator fun plus(b: T): I = context.add(unwrap(), b).wrap()
/**
* Subtracts element from this one.
*
* @param b the subtrahend.
* @return the difference.
*/
public operator fun minus(b: T): I = context.add(unwrap(), context.multiply(b, -1.0)).wrap()
/**
* Multiplies this element by number.
*
* @param k the multiplicand.
* @return the product.
*/
public operator fun times(k: Number): I = context.multiply(unwrap(), k.toDouble()).wrap()
/**
* Divides this element by number.
*
* @param k the divisor.
* @return the quotient.
*/
public operator fun div(k: Number): I = context.multiply(unwrap(), 1.0 / k.toDouble()).wrap()
}
/**
* The element of [Ring].
*
* @param T the type of ring operation results.
* @param I self type of the element. Needed for static type checking.
* @param R the type of ring.
*/
public interface RingElement<T, I : RingElement<T, I, R>, R : Ring<T>> : SpaceElement<T, I, R> {
/**
* Multiplies this element by another one.
*
* @param b the multiplicand.
* @return the product.
*/
public operator fun times(b: T): I = context.multiply(unwrap(), b).wrap()
}
/**
* The element of [Field].
*
* @param T the type of field operation results.
* @param I self type of the element. Needed for static type checking.
* @param F the type of field.
*/
public interface FieldElement<T, I : FieldElement<T, I, F>, F : Field<T>> : RingElement<T, I, F> {
override val context: F
/**
* Divides this element by another one.
*
* @param b the divisor.
* @return the quotient.
*/
public operator fun div(b: T): I = context.divide(unwrap(), b).wrap()
}

View File

@ -1,81 +0,0 @@
package kscience.kmath.structures
import kscience.kmath.operations.Field
import kscience.kmath.operations.FieldElement
public class BoxingNDField<T, F : Field<T>>(
public override val shape: IntArray,
public override val elementContext: F,
public val bufferFactory: BufferFactory<T>
) : BufferedNDField<T, F> {
public override val zero: BufferedNDFieldElement<T, F> by lazy { produce { zero } }
public override val one: BufferedNDFieldElement<T, F> by lazy { produce { one } }
public override val strides: Strides = DefaultStrides(shape)
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> =
bufferFactory(size, initializer)
public override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
require(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" }
return elements
}
public override fun produce(initializer: F.(IntArray) -> T): BufferedNDFieldElement<T, F> =
BufferedNDFieldElement(
this,
buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) })
public override fun map(arg: NDBuffer<T>, transform: F.(T) -> T): BufferedNDFieldElement<T, F> {
check(arg)
return BufferedNDFieldElement(
this,
buildBuffer(arg.strides.linearSize) { offset -> elementContext.transform(arg.buffer[offset]) })
// val buffer = arg.buffer.transform { _, value -> elementContext.transform(value) }
// return BufferedNDFieldElement(this, buffer)
}
public override fun mapIndexed(
arg: NDBuffer<T>,
transform: F.(index: IntArray, T) -> T
): BufferedNDFieldElement<T, F> {
check(arg)
return BufferedNDFieldElement(
this,
buildBuffer(arg.strides.linearSize) { offset ->
elementContext.transform(
arg.strides.index(offset),
arg.buffer[offset]
)
})
// val buffer =
// arg.buffer.transform { offset, value -> elementContext.transform(arg.strides.index(offset), value) }
// return BufferedNDFieldElement(this, buffer)
}
public override fun combine(
a: NDBuffer<T>,
b: NDBuffer<T>,
transform: F.(T, T) -> T
): BufferedNDFieldElement<T, F> {
check(a, b)
return BufferedNDFieldElement(
this,
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
}
public override fun NDBuffer<T>.toElement(): FieldElement<NDBuffer<T>, *, out BufferedNDField<T, F>> =
BufferedNDFieldElement(this@BoxingNDField, buffer)
}
public inline fun <T : Any, F : Field<T>, R> F.nd(
noinline bufferFactory: BufferFactory<T>,
vararg shape: Int,
action: NDField<T, F, *>.() -> R
): R {
val ndfield = NDField.boxing(this, *shape, bufferFactory = bufferFactory)
return ndfield.action()
}

View File

@ -1,71 +0,0 @@
package kscience.kmath.structures
import kscience.kmath.operations.Ring
import kscience.kmath.operations.RingElement
public class BoxingNDRing<T, R : Ring<T>>(
override val shape: IntArray,
override val elementContext: R,
public val bufferFactory: BufferFactory<T>
) : BufferedNDRing<T, R> {
override val strides: Strides = DefaultStrides(shape)
override val zero: BufferedNDRingElement<T, R> by lazy { produce { zero } }
override val one: BufferedNDRingElement<T, R> by lazy { produce { one } }
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = bufferFactory(size, initializer)
override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
if (!elements.all { it.strides == this.strides }) error("Element strides are not the same as context strides")
return elements
}
override fun produce(initializer: R.(IntArray) -> T): BufferedNDRingElement<T, R> =
BufferedNDRingElement(
this,
buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) })
override fun map(arg: NDBuffer<T>, transform: R.(T) -> T): BufferedNDRingElement<T, R> {
check(arg)
return BufferedNDRingElement(
this,
buildBuffer(arg.strides.linearSize) { offset -> elementContext.transform(arg.buffer[offset]) })
// val buffer = arg.buffer.transform { _, value -> elementContext.transform(value) }
// return BufferedNDFieldElement(this, buffer)
}
override fun mapIndexed(
arg: NDBuffer<T>,
transform: R.(index: IntArray, T) -> T
): BufferedNDRingElement<T, R> {
check(arg)
return BufferedNDRingElement(
this,
buildBuffer(arg.strides.linearSize) { offset ->
elementContext.transform(
arg.strides.index(offset),
arg.buffer[offset]
)
})
// val buffer =
// arg.buffer.transform { offset, value -> elementContext.transform(arg.strides.index(offset), value) }
// return BufferedNDFieldElement(this, buffer)
}
override fun combine(
a: NDBuffer<T>,
b: NDBuffer<T>,
transform: R.(T, T) -> T
): BufferedNDRingElement<T, R> {
check(a, b)
return BufferedNDRingElement(
this,
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
}
override fun NDBuffer<T>.toElement(): RingElement<NDBuffer<T>, *, out BufferedNDRing<T, R>> =
BufferedNDRingElement(this@BoxingNDRing, buffer)
}

View File

@ -1,43 +0,0 @@
package kscience.kmath.structures
import kscience.kmath.operations.*
public interface BufferedNDAlgebra<T, C> : NDAlgebra<T, C, NDBuffer<T>> {
public val strides: Strides
public override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
require(elements.all { it.strides == strides }) { "Strides mismatch" }
return elements
}
/**
* Convert any [NDStructure] to buffered structure using strides from this context.
* If the structure is already [NDBuffer], conversion is free. If not, it could be expensive because iteration over
* indices.
*
* If the argument is [NDBuffer] with different strides structure, the new element will be produced.
*/
public fun NDStructure<T>.toBuffer(): NDBuffer<T> =
if (this is NDBuffer<T> && this.strides == this@BufferedNDAlgebra.strides)
this
else
produce { index -> this@toBuffer[index] }
/**
* Convert a buffer to element of this algebra
*/
public fun NDBuffer<T>.toElement(): MathElement<out BufferedNDAlgebra<T, C>>
}
public interface BufferedNDSpace<T, S : Space<T>> : NDSpace<T, S, NDBuffer<T>>, BufferedNDAlgebra<T, S> {
public override fun NDBuffer<T>.toElement(): SpaceElement<NDBuffer<T>, *, out BufferedNDSpace<T, S>>
}
public interface BufferedNDRing<T, R : Ring<T>> : NDRing<T, R, NDBuffer<T>>, BufferedNDSpace<T, R> {
override fun NDBuffer<T>.toElement(): RingElement<NDBuffer<T>, *, out BufferedNDRing<T, R>>
}
public interface BufferedNDField<T, F : Field<T>> : NDField<T, F, NDBuffer<T>>, BufferedNDRing<T, F> {
override fun NDBuffer<T>.toElement(): FieldElement<NDBuffer<T>, *, out BufferedNDField<T, F>>
}

View File

@ -1,86 +0,0 @@
package kscience.kmath.structures
import kscience.kmath.operations.*
/**
* Base class for an element with context, containing strides
*/
public abstract class BufferedNDElement<T, C> : NDBuffer<T>(), NDElement<T, C, NDBuffer<T>> {
abstract override val context: BufferedNDAlgebra<T, C>
override val strides: Strides get() = context.strides
override val shape: IntArray get() = context.shape
}
public class BufferedNDSpaceElement<T, S : Space<T>>(
override val context: BufferedNDSpace<T, S>,
override val buffer: Buffer<T>
) : BufferedNDElement<T, S>(), SpaceElement<NDBuffer<T>, BufferedNDSpaceElement<T, S>, BufferedNDSpace<T, S>> {
override fun unwrap(): NDBuffer<T> = this
override fun NDBuffer<T>.wrap(): BufferedNDSpaceElement<T, S> {
context.check(this)
return BufferedNDSpaceElement(context, buffer)
}
}
public class BufferedNDRingElement<T, R : Ring<T>>(
override val context: BufferedNDRing<T, R>,
override val buffer: Buffer<T>
) : BufferedNDElement<T, R>(), RingElement<NDBuffer<T>, BufferedNDRingElement<T, R>, BufferedNDRing<T, R>> {
override fun unwrap(): NDBuffer<T> = this
override fun NDBuffer<T>.wrap(): BufferedNDRingElement<T, R> {
context.check(this)
return BufferedNDRingElement(context, buffer)
}
}
public class BufferedNDFieldElement<T, F : Field<T>>(
override val context: BufferedNDField<T, F>,
override val buffer: Buffer<T>
) : BufferedNDElement<T, F>(), FieldElement<NDBuffer<T>, BufferedNDFieldElement<T, F>, BufferedNDField<T, F>> {
override fun unwrap(): NDBuffer<T> = this
override fun NDBuffer<T>.wrap(): BufferedNDFieldElement<T, F> {
context.check(this)
return BufferedNDFieldElement(context, buffer)
}
}
/**
* Element by element application of any operation on elements to the whole array. Just like in numpy.
*/
public operator fun <T : Any, F : Field<T>> Function1<T, T>.invoke(ndElement: BufferedNDElement<T, F>): MathElement<out BufferedNDAlgebra<T, F>> =
ndElement.context.run { map(ndElement) { invoke(it) }.toElement() }
/* plus and minus */
/**
* Summation operation for [BufferedNDElement] and single element
*/
public operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.plus(arg: T): NDElement<T, F, NDBuffer<T>> =
context.map(this) { it + arg }.wrap()
/**
* Subtraction operation between [BufferedNDElement] and single element
*/
public operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.minus(arg: T): NDElement<T, F, NDBuffer<T>> =
context.map(this) { it - arg }.wrap()
/* prod and div */
/**
* Product operation for [BufferedNDElement] and single element
*/
public operator fun <T : Any, F : Ring<T>> BufferedNDElement<T, F>.times(arg: T): NDElement<T, F, NDBuffer<T>> =
context.map(this) { it * arg }.wrap()
/**
* Division operation between [BufferedNDElement] and single element
*/
public operator fun <T : Any, F : Field<T>> BufferedNDElement<T, F>.div(arg: T): NDElement<T, F, NDBuffer<T>> =
context.map(this) { it / arg }.wrap()

View File

@ -1,158 +0,0 @@
package kscience.kmath.structures
import kscience.kmath.misc.UnstableKMathAPI
import kscience.kmath.operations.*
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
public typealias ComplexNDElement = BufferedNDFieldElement<Complex, ComplexField>
/**
* An optimized nd-field for complex numbers
*/
@OptIn(UnstableKMathAPI::class)
public class ComplexNDField(override val shape: IntArray) :
BufferedNDField<Complex, ComplexField>,
ExtendedNDField<Complex, ComplexField, NDBuffer<Complex>>,
RingWithNumbers<NDBuffer<Complex>>{
override val strides: Strides = DefaultStrides(shape)
override val elementContext: ComplexField get() = ComplexField
override val zero: ComplexNDElement by lazy { produce { zero } }
override val one: ComplexNDElement by lazy { produce { one } }
override fun number(value: Number): NDBuffer<Complex> {
val c = value.toComplex()
return produce { c }
}
public inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Complex): Buffer<Complex> =
Buffer.complex(size) { initializer(it) }
/**
* Inline transform an NDStructure to another structure
*/
override fun map(
arg: NDBuffer<Complex>,
transform: ComplexField.(Complex) -> Complex,
): ComplexNDElement {
check(arg)
val array = buildBuffer(arg.strides.linearSize) { offset -> ComplexField.transform(arg.buffer[offset]) }
return BufferedNDFieldElement(this, array)
}
override fun produce(initializer: ComplexField.(IntArray) -> Complex): ComplexNDElement {
val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
return BufferedNDFieldElement(this, array)
}
override fun mapIndexed(
arg: NDBuffer<Complex>,
transform: ComplexField.(index: IntArray, Complex) -> Complex,
): ComplexNDElement {
check(arg)
return BufferedNDFieldElement(
this,
buildBuffer(arg.strides.linearSize) { offset ->
elementContext.transform(
arg.strides.index(offset),
arg.buffer[offset]
)
})
}
override fun combine(
a: NDBuffer<Complex>,
b: NDBuffer<Complex>,
transform: ComplexField.(Complex, Complex) -> Complex,
): ComplexNDElement {
check(a, b)
return BufferedNDFieldElement(
this,
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
}
override fun NDBuffer<Complex>.toElement(): FieldElement<NDBuffer<Complex>, *, out BufferedNDField<Complex, ComplexField>> =
BufferedNDFieldElement(this@ComplexNDField, buffer)
override fun power(arg: NDBuffer<Complex>, pow: Number): ComplexNDElement =
map(arg) { power(it, pow) }
override fun exp(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { exp(it) }
override fun ln(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { ln(it) }
override fun sin(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { sin(it) }
override fun cos(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { cos(it) }
override fun tan(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { tan(it) }
override fun asin(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { asin(it) }
override fun acos(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { acos(it) }
override fun atan(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { atan(it) }
override fun sinh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { sinh(it) }
override fun cosh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { cosh(it) }
override fun tanh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { tanh(it) }
override fun asinh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { asinh(it) }
override fun acosh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { acosh(it) }
override fun atanh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { atanh(it) }
}
/**
* Fast element production using function inlining
*/
public inline fun BufferedNDField<Complex, ComplexField>.produceInline(initializer: ComplexField.(Int) -> Complex): ComplexNDElement {
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) }
return BufferedNDFieldElement(this, buffer)
}
/**
* Map one [ComplexNDElement] using function with indices.
*/
public inline fun ComplexNDElement.mapIndexed(transform: ComplexField.(index: IntArray, Complex) -> Complex): ComplexNDElement =
context.produceInline { offset -> transform(strides.index(offset), buffer[offset]) }
/**
* Map one [ComplexNDElement] using function without indices.
*/
public inline fun ComplexNDElement.map(transform: ComplexField.(Complex) -> Complex): ComplexNDElement {
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.transform(buffer[offset]) }
return BufferedNDFieldElement(context, buffer)
}
/**
* Element by element application of any operation on elements to the whole array. Just like in numpy
*/
public operator fun Function1<Complex, Complex>.invoke(ndElement: ComplexNDElement): ComplexNDElement =
ndElement.map { this@invoke(it) }
/* plus and minus */
/**
* Summation operation for [BufferedNDElement] and single element
*/
public operator fun ComplexNDElement.plus(arg: Complex): ComplexNDElement = map { it + arg }
/**
* Subtraction operation between [BufferedNDElement] and single element
*/
public operator fun ComplexNDElement.minus(arg: Complex): ComplexNDElement = map { it - arg }
public operator fun ComplexNDElement.plus(arg: Double): ComplexNDElement = map { it + arg }
public operator fun ComplexNDElement.minus(arg: Double): ComplexNDElement = map { it - arg }
public fun NDField.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape)
public fun NDElement.Companion.complex(
vararg shape: Int,
initializer: ComplexField.(IntArray) -> Complex,
): ComplexNDElement = NDField.complex(*shape).produce(initializer)
/**
* Produce a context for n-dimensional operations inside this real field
*/
public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R {
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
return NDField.complex(*shape).action()
}

View File

@ -1,44 +0,0 @@
package kscience.kmath.structures
import kscience.kmath.operations.ExtendedField
/**
* [ExtendedField] over [NDStructure].
*
* @param T the type of the element contained in ND structure.
* @param N the type of ND structure.
* @param F the extended field of structure elements.
*/
public interface ExtendedNDField<T : Any, F : ExtendedField<T>, N : NDStructure<T>> : NDField<T, F, N>, ExtendedField<N>
///**
// * NDField that supports [ExtendedField] operations on its elements
// */
//class ExtendedNDFieldWrapper<T : Any, F : ExtendedField<T>, N : NDStructure<T>>(private val ndField: NDField<T, F, N>) :
// ExtendedNDField<T, F, N>, NDField<T, F, N> by ndField {
//
// override val shape: IntArray get() = ndField.shape
// override val elementContext: F get() = ndField.elementContext
//
// override fun produce(initializer: F.(IntArray) -> T) = ndField.produce(initializer)
//
// override fun power(arg: N, pow: Double): N {
// return produce { with(elementContext) { power(arg[it], pow) } }
// }
//
// override fun exp(arg: N): N {
// return produce { with(elementContext) { exp(arg[it]) } }
// }
//
// override fun ln(arg: N): N {
// return produce { with(elementContext) { ln(arg[it]) } }
// }
//
// override fun sin(arg: N): N {
// return produce { with(elementContext) { sin(arg[it]) } }
// }
//
// override fun cos(arg: N): N {
// return produce { with(elementContext) { cos(arg[it]) } }
// }
//}

Some files were not shown because too many files have changed in this diff Show More