Merge branch 'dev' into feature/mp-samplers
This commit is contained in:
commit
9210bc9198
@ -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/publish.yml
vendored
Normal file
117
.github/workflows/publish.yml
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
name: Bintray Publish
|
||||
|
||||
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 }}
|
||||
|
@ -32,9 +32,12 @@
|
||||
- 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
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
94
README.md
94
README.md
@ -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
|
||||
|
||||
@ -113,10 +110,13 @@ submit a feature request if you want something to be implemented first.
|
||||
> **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 +137,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 +155,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 +212,7 @@ One can still use generic algebras though.
|
||||
* ### [kmath-viktor](kmath-viktor)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
> **Maturity**: DEVELOPMENT
|
||||
<hr/>
|
||||
|
||||
|
||||
@ -235,11 +242,12 @@ Release artifacts are accessible from bintray with following configuration (see
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
// maven("https://dl.bintray.com/mipt-npm/dev") for dev versions
|
||||
}
|
||||
|
||||
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:0.2.0-dev-6")
|
||||
// api("kscience.kmath:kmath-core-jvm:0.2.0-dev-6") for jvm-specific version
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -4,7 +4,7 @@ plugins {
|
||||
id("ru.mipt.npm.project")
|
||||
}
|
||||
|
||||
internal val kmathVersion: String by extra("0.2.0-dev-5")
|
||||
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")
|
||||
|
||||
@ -35,10 +35,6 @@ readme {
|
||||
readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
||||
}
|
||||
|
||||
apiValidation {
|
||||
validationDisabled = true
|
||||
}
|
||||
|
||||
ksciencePublish {
|
||||
spaceRepo = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven"
|
||||
}
|
||||
|
56
docs/templates/README-TEMPLATE.md
vendored
56
docs/templates/README-TEMPLATE.md
vendored
@ -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
|
||||
|
||||
@ -106,6 +103,7 @@ Release artifacts are accessible from bintray with following configuration (see
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
// maven("https://dl.bintray.com/mipt-npm/dev") for dev versions
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -68,11 +68,12 @@ benchmark {
|
||||
targets.register("benchmarks")
|
||||
// This one matches sourceSet name above
|
||||
|
||||
configurations.register("fast") {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,3 +87,7 @@ kotlin.sourceSets.all {
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "11"
|
||||
}
|
||||
|
||||
readme{
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
}
|
||||
|
@ -3,14 +3,12 @@ package kscience.kmath.benchmarks
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kscience.kmath.commons.linear.CMMatrixContext
|
||||
import kscience.kmath.ejml.EjmlMatrixContext
|
||||
|
||||
import kscience.kmath.linear.BufferMatrixContext
|
||||
import kscience.kmath.linear.Matrix
|
||||
import kscience.kmath.linear.RealMatrixContext
|
||||
import kscience.kmath.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 kotlin.random.Random
|
||||
@ -33,38 +31,35 @@ 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
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ class LinearAlgebraBenchmark {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun kmathLUPInversion() {
|
||||
MatrixContext.real.inverseWithLUP(matrix)
|
||||
fun kmathLupInversion() {
|
||||
MatrixContext.real.inverseWithLup(matrix)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
|
@ -1,8 +1,9 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.structures.*
|
||||
import kscience.kmath.structures.Buffer
|
||||
import org.openjdk.jmh.annotations.Benchmark
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
@ -11,22 +12,16 @@ import org.openjdk.jmh.annotations.State
|
||||
internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun autoFieldAdd() {
|
||||
bufferedField {
|
||||
var res: NDBuffer<Double> = one
|
||||
autoField {
|
||||
var res: NDStructure<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
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
@ -35,16 +30,16 @@ internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun boxingFieldAdd() {
|
||||
genericField {
|
||||
var res: NDBuffer<Double> = one
|
||||
repeat(n) { res += one }
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
val specializedField: RealNDField = NDAlgebra.real(dim, dim)
|
||||
val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
||||
}
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kscience.kmath.nd.*
|
||||
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
|
||||
@ -17,15 +15,23 @@ internal class ViktorBenchmark {
|
||||
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))
|
||||
final val autoField: NDField<Double, RealField> = NDAlgebra.auto(RealField, dim, dim)
|
||||
final val realField: RealNDField = NDAlgebra.real(dim, dim)
|
||||
final val viktorField: ViktorNDField = ViktorNDField(dim, dim)
|
||||
|
||||
@Benchmark
|
||||
fun automaticFieldAddition() {
|
||||
autoField {
|
||||
var res = one
|
||||
repeat(n) { res += one }
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun realFieldAddition() {
|
||||
realField {
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +39,7 @@ internal class ViktorBenchmark {
|
||||
fun viktorFieldAddition() {
|
||||
viktorField {
|
||||
var res = one
|
||||
repeat(n) { res += one }
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,22 +49,4 @@ internal class ViktorBenchmark {
|
||||
var res = one
|
||||
repeat(n) { res = res + one }
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun realFieldLog() {
|
||||
realField {
|
||||
val fortyTwo = produce { 42.0 }
|
||||
var res = one
|
||||
repeat(n) { res = ln(fortyTwo) }
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun rawViktorLog() {
|
||||
val fortyTwo = F64Array.full(dim, dim, init = 42.0)
|
||||
var res: F64Array
|
||||
repeat(n) {
|
||||
res = fortyTwo.log()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.viktor.ViktorNDField
|
||||
import org.jetbrains.bio.viktor.F64Array
|
||||
import org.openjdk.jmh.annotations.Benchmark
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class ViktorLogBenchmark {
|
||||
final val dim: Int = 1000
|
||||
final val n: Int = 100
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
final val autoField: NDField<Double, RealField> = NDAlgebra.auto(RealField, dim, dim)
|
||||
final val realField: RealNDField = NDAlgebra.real(dim, dim)
|
||||
final val viktorField: ViktorNDField = ViktorNDField(intArrayOf(dim, dim))
|
||||
|
||||
|
||||
@Benchmark
|
||||
fun realFieldLog() {
|
||||
realField {
|
||||
val fortyTwo = produce { 42.0 }
|
||||
var res = one
|
||||
repeat(n) { res = ln(fortyTwo) }
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun viktorFieldLog() {
|
||||
viktorField {
|
||||
val fortyTwo = produce { 42.0 }
|
||||
var res = one
|
||||
repeat(n) { res = ln(fortyTwo) }
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun rawViktorLog() {
|
||||
val fortyTwo = F64Array.full(dim, dim, init = 42.0)
|
||||
var res: F64Array
|
||||
repeat(n) {
|
||||
res = fortyTwo.log()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,17 @@
|
||||
package kscience.kmath.operations
|
||||
|
||||
import kscience.kmath.structures.NDElement
|
||||
import kscience.kmath.structures.NDField
|
||||
import kscience.kmath.structures.complex
|
||||
import kscience.kmath.nd.NDAlgebra
|
||||
import kscience.kmath.nd.complex
|
||||
|
||||
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)
|
||||
|
@ -1,6 +1,9 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.linear.transpose
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.Complex
|
||||
import kscience.kmath.operations.ComplexField
|
||||
import kscience.kmath.operations.invoke
|
||||
@ -10,12 +13,12 @@ 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 +29,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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.nd4j.Nd4jArrayField
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.viktor.ViktorNDField
|
||||
import org.nd4j.linalg.factory.Nd4j
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
@ -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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.ExtendedField
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.RingWithNumbers
|
||||
import java.util.*
|
||||
import java.util.stream.IntStream
|
||||
|
||||
/**
|
||||
* A demonstration implementation of NDField over Real using Java [DoubleStream] for parallel execution
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
class StreamRealNDField(
|
||||
override val shape: IntArray,
|
||||
) : NDField<Double, RealField>,
|
||||
RingWithNumbers<NDStructure<Double>>,
|
||||
ExtendedField<NDStructure<Double>> {
|
||||
|
||||
private val strides = DefaultStrides(shape)
|
||||
override val elementContext: RealField get() = RealField
|
||||
override val zero: NDBuffer<Double> by lazy { produce { zero } }
|
||||
override val one: NDBuffer<Double> by lazy { produce { one } }
|
||||
|
||||
override fun number(value: Number): NDBuffer<Double> {
|
||||
val d = value.toDouble() // minimize conversions
|
||||
return produce { d }
|
||||
}
|
||||
|
||||
private val NDStructure<Double>.buffer: RealBuffer
|
||||
get() = when {
|
||||
!shape.contentEquals(this@StreamRealNDField.shape) -> throw ShapeMismatchException(
|
||||
this@StreamRealNDField.shape,
|
||||
shape
|
||||
)
|
||||
this is NDBuffer && this.strides == this@StreamRealNDField.strides -> this.buffer as RealBuffer
|
||||
else -> RealBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
|
||||
}
|
||||
|
||||
|
||||
override fun produce(initializer: RealField.(IntArray) -> Double): NDBuffer<Double> {
|
||||
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
|
||||
val index = strides.index(offset)
|
||||
RealField.initializer(index)
|
||||
}.toArray()
|
||||
|
||||
return NDBuffer(strides, array.asBuffer())
|
||||
}
|
||||
|
||||
override fun NDStructure<Double>.map(
|
||||
transform: RealField.(Double) -> Double,
|
||||
): NDBuffer<Double> {
|
||||
val array = Arrays.stream(buffer.array).parallel().map { RealField.transform(it) }.toArray()
|
||||
return NDBuffer(strides, array.asBuffer())
|
||||
}
|
||||
|
||||
override fun NDStructure<Double>.mapIndexed(
|
||||
transform: RealField.(index: IntArray, Double) -> Double,
|
||||
): NDBuffer<Double> {
|
||||
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
|
||||
RealField.transform(
|
||||
strides.index(offset),
|
||||
buffer.array[offset]
|
||||
)
|
||||
}.toArray()
|
||||
|
||||
return NDBuffer(strides, array.asBuffer())
|
||||
}
|
||||
|
||||
override fun combine(
|
||||
a: NDStructure<Double>,
|
||||
b: NDStructure<Double>,
|
||||
transform: RealField.(Double, Double) -> Double,
|
||||
): NDBuffer<Double> {
|
||||
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
|
||||
RealField.transform(a.buffer.array[offset], b.buffer.array[offset])
|
||||
}.toArray()
|
||||
return NDBuffer(strides, array.asBuffer())
|
||||
}
|
||||
|
||||
override fun power(arg: NDStructure<Double>, pow: Number): NDBuffer<Double> = arg.map() { power(it, pow) }
|
||||
|
||||
override fun exp(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { exp(it) }
|
||||
|
||||
override fun ln(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { ln(it) }
|
||||
|
||||
override fun sin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { sin(it) }
|
||||
override fun cos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { cos(it) }
|
||||
override fun tan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { tan(it) }
|
||||
override fun asin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { asin(it) }
|
||||
override fun acos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { acos(it) }
|
||||
override fun atan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { atan(it) }
|
||||
|
||||
override fun sinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { sinh(it) }
|
||||
override fun cosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { cosh(it) }
|
||||
override fun tanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { tanh(it) }
|
||||
override fun asinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { asinh(it) }
|
||||
override fun acosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { acosh(it) }
|
||||
override fun atanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { atanh(it) }
|
||||
}
|
||||
|
||||
fun NDAlgebra.Companion.realWithStream(vararg shape: Int): StreamRealNDField = StreamRealNDField(shape)
|
@ -1,5 +1,7 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.nd.DefaultStrides
|
||||
import kscience.kmath.nd.NDBuffer
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
fun main() {
|
||||
@ -7,7 +9,7 @@ fun main() {
|
||||
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
|
||||
|
@ -1,5 +1,7 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.nd.NDStructure
|
||||
import kscience.kmath.nd.mapToBuffer
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
fun main() {
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -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: `kscience.kmath:kmath-ast:0.2.0-dev-6`.
|
||||
>
|
||||
> 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)
|
||||
>
|
||||
@ -30,7 +30,7 @@ This subproject implements the following features:
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'kscience.kmath:kmath-ast:0.2.0-dev-4'
|
||||
> implementation 'kscience.kmath:kmath-ast:0.2.0-dev-6'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
@ -44,7 +44,7 @@ This subproject implements the following features:
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("kscience.kmath:kmath-ast:0.2.0-dev-4")
|
||||
> implementation("kscience.kmath:kmath-ast:0.2.0-dev-6")
|
||||
> }
|
||||
> ```
|
||||
|
||||
@ -61,7 +61,7 @@ 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;
|
||||
|
@ -10,3 +10,7 @@ dependencies {
|
||||
api(project(":kmath-functions"))
|
||||
api("org.apache.commons:commons-math3:3.6.1")
|
||||
}
|
||||
|
||||
readme{
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
}
|
@ -1,11 +1,8 @@
|
||||
package kscience.kmath.commons.linear
|
||||
|
||||
import kscience.kmath.linear.DiagonalFeature
|
||||
import kscience.kmath.linear.MatrixContext
|
||||
import kscience.kmath.linear.Point
|
||||
import kscience.kmath.linear.origin
|
||||
import kscience.kmath.linear.*
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.RealBuffer
|
||||
import org.apache.commons.math3.linear.*
|
||||
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)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package kscience.kmath.commons.linear
|
||||
|
||||
import kscience.kmath.linear.Matrix
|
||||
import kscience.kmath.linear.Point
|
||||
import kscience.kmath.structures.Matrix
|
||||
import org.apache.commons.math3.linear.*
|
||||
|
||||
public enum class CMDecomposition {
|
||||
|
@ -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: `kscience.kmath:kmath-core:0.2.0-dev-6`.
|
||||
>
|
||||
> 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)
|
||||
>
|
||||
@ -30,7 +33,7 @@ The core features of KMath:
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'kscience.kmath:kmath-core:0.2.0-dev-4'
|
||||
> implementation 'kscience.kmath:kmath-core:0.2.0-dev-6'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
@ -44,6 +47,6 @@ The core features of KMath:
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("kscience.kmath:kmath-core:0.2.0-dev-4")
|
||||
> implementation("kscience.kmath:kmath-core:0.2.0-dev-6")
|
||||
> }
|
||||
> ```
|
||||
|
3358
kmath-core/api/kmath-core.api
Normal file
3358
kmath-core/api/kmath-core.api
Normal file
File diff suppressed because it is too large
Load Diff
@ -16,16 +16,26 @@ readme {
|
||||
|
||||
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 +44,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"
|
||||
)
|
||||
|
||||
|
@ -3,7 +3,6 @@ package kscience.kmath.expressions
|
||||
import kscience.kmath.operations.Algebra
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* A marker interface for a symbol. A symbol mus have an identity
|
||||
@ -13,13 +12,6 @@ public interface Symbol {
|
||||
* Identity object for the symbol. Two symbols with the same identity are considered to be the same symbol.
|
||||
*/
|
||||
public val identity: String
|
||||
|
||||
public companion object : ReadOnlyProperty<Any?, Symbol> {
|
||||
//TODO deprecate and replace by top level function after fix of https://youtrack.jetbrains.com/issue/KT-40121
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): Symbol {
|
||||
return StringSymbol(property.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,9 +95,9 @@ public fun <T, E> ExpressionAlgebra<T, E>.bind(symbol: Symbol): E =
|
||||
/**
|
||||
* A delegate to create a symbol with a string identity in this scope
|
||||
*/
|
||||
public val symbol: ReadOnlyProperty<Any?, Symbol> get() = Symbol
|
||||
//TODO does not work directly on native due to https://youtrack.jetbrains.com/issue/KT-40121
|
||||
|
||||
public val symbol: ReadOnlyProperty<Any?, Symbol> = ReadOnlyProperty { thisRef, property ->
|
||||
StringSymbol(property.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a symbol by name inside the [ExpressionAlgebra]
|
||||
|
@ -1,8 +1,8 @@
|
||||
package kscience.kmath.expressions
|
||||
|
||||
import kscience.kmath.linear.Point
|
||||
import kscience.kmath.nd.Structure2D
|
||||
import kscience.kmath.structures.BufferFactory
|
||||
import kscience.kmath.structures.Structure2D
|
||||
|
||||
/**
|
||||
* An environment to easy transform indexed variables to symbols and back.
|
||||
|
@ -1,7 +1,19 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.nd.NDStructure
|
||||
import kscience.kmath.nd.Structure2D
|
||||
import kscience.kmath.operations.Ring
|
||||
import kscience.kmath.structures.*
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.BufferFactory
|
||||
import kscience.kmath.structures.asSequence
|
||||
|
||||
/**
|
||||
* Alias for [Structure2D] with more familiar name.
|
||||
*
|
||||
* @param T the type of items.
|
||||
*/
|
||||
public typealias Matrix<T> = Structure2D<T>
|
||||
|
||||
/**
|
||||
* Basic implementation of Matrix space based on [NDStructure]
|
||||
@ -17,6 +29,62 @@ public class BufferMatrixContext<T : Any, R : Ring<T>>(
|
||||
|
||||
public override fun point(size: Int, initializer: (Int) -> T): Point<T> = bufferFactory(size, initializer)
|
||||
|
||||
private fun Matrix<T>.toBufferMatrix(): BufferMatrix<T> = if (this is BufferMatrix) this else {
|
||||
produce(rowNum, colNum) { i, j -> get(i, j) }
|
||||
}
|
||||
|
||||
public fun one(rows: Int, columns: Int): Matrix<Double> = VirtualMatrix(rows, columns) { i, j ->
|
||||
if (i == j) 1.0 else 0.0
|
||||
} + DiagonalFeature
|
||||
|
||||
public override infix fun Matrix<T>.dot(other: Matrix<T>): BufferMatrix<T> {
|
||||
require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
|
||||
val bufferMatrix = toBufferMatrix()
|
||||
val otherBufferMatrix = other.toBufferMatrix()
|
||||
return elementContext {
|
||||
produce(rowNum, other.colNum) { i, j ->
|
||||
var res = one
|
||||
for (l in 0 until colNum) {
|
||||
res += bufferMatrix[i, l] * otherBufferMatrix[l, j]
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override infix fun Matrix<T>.dot(vector: Point<T>): Point<T> {
|
||||
require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" }
|
||||
val bufferMatrix = toBufferMatrix()
|
||||
return elementContext {
|
||||
bufferFactory(rowNum) { i ->
|
||||
var res = one
|
||||
for (j in 0 until colNum) {
|
||||
res += bufferMatrix[i, j] * vector[j]
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun add(a: Matrix<T>, b: Matrix<T>): BufferMatrix<T> {
|
||||
require(a.rowNum == b.rowNum) { "Row number mismatch in matrix addition. Left side: ${a.rowNum}, right side: ${b.rowNum}" }
|
||||
require(a.colNum == b.colNum) { "Column number mismatch in matrix addition. Left side: ${a.colNum}, right side: ${b.colNum}" }
|
||||
val aBufferMatrix = a.toBufferMatrix()
|
||||
val bBufferMatrix = b.toBufferMatrix()
|
||||
return elementContext {
|
||||
produce(a.rowNum, a.colNum) { i, j ->
|
||||
aBufferMatrix[i, j] + bBufferMatrix[i, j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun multiply(a: Matrix<T>, k: Number): BufferMatrix<T> {
|
||||
val aBufferMatrix = a.toBufferMatrix()
|
||||
return elementContext {
|
||||
produce(a.rowNum, a.colNum) { i, j -> aBufferMatrix[i, j] * k.toDouble() }
|
||||
}
|
||||
}
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.VirtualBuffer
|
||||
|
||||
public typealias Point<T> = Buffer<T>
|
||||
|
@ -1,6 +1,7 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.nd.getFeature
|
||||
import kscience.kmath.operations.*
|
||||
import kscience.kmath.structures.*
|
||||
|
||||
@ -151,7 +152,7 @@ public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext
|
||||
public fun MatrixContext<Double, Matrix<Double>>.lup(matrix: Matrix<Double>): LupDecomposition<Double> =
|
||||
lup(Buffer.Companion::real, RealField, matrix) { it < 1e-11 }
|
||||
|
||||
public fun <T : Any> LupDecomposition<T>.solveWithLUP(
|
||||
public fun <T : Any> LupDecomposition<T>.solveWithLup(
|
||||
factory: MutableBufferFactory<T>,
|
||||
matrix: Matrix<T>,
|
||||
): Matrix<T> {
|
||||
@ -199,14 +200,14 @@ public fun <T : Any> LupDecomposition<T>.solveWithLUP(
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun <reified T : Any> LupDecomposition<T>.solveWithLUP(matrix: Matrix<T>): Matrix<T> =
|
||||
solveWithLUP(MutableBuffer.Companion::auto, matrix)
|
||||
public inline fun <reified T : Any> LupDecomposition<T>.solveWithLup(matrix: Matrix<T>): Matrix<T> =
|
||||
solveWithLup(MutableBuffer.Companion::auto, matrix)
|
||||
|
||||
/**
|
||||
* Solve a linear equation **a*x = b** using LUP decomposition
|
||||
* Solves a system of linear equations *ax = b** using LUP decomposition.
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F, Matrix<T>>.solveWithLUP(
|
||||
public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F, Matrix<T>>.solveWithLup(
|
||||
a: Matrix<T>,
|
||||
b: Matrix<T>,
|
||||
noinline bufferFactory: MutableBufferFactory<T> = MutableBuffer.Companion::auto,
|
||||
@ -214,26 +215,26 @@ public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext
|
||||
): Matrix<T> {
|
||||
// Use existing decomposition if it is provided by matrix
|
||||
val decomposition = a.getFeature() ?: lup(bufferFactory, elementContext, a, checkSingular)
|
||||
return decomposition.solveWithLUP(bufferFactory, b)
|
||||
return decomposition.solveWithLup(bufferFactory, b)
|
||||
}
|
||||
|
||||
public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F, Matrix<T>>.inverseWithLUP(
|
||||
public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext<T, F, Matrix<T>>.inverseWithLup(
|
||||
matrix: Matrix<T>,
|
||||
noinline bufferFactory: MutableBufferFactory<T> = MutableBuffer.Companion::auto,
|
||||
noinline checkSingular: (T) -> Boolean,
|
||||
): Matrix<T> = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular)
|
||||
): Matrix<T> = solveWithLup(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular)
|
||||
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public fun RealMatrixContext.solveWithLUP(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> {
|
||||
public fun RealMatrixContext.solveWithLup(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> {
|
||||
// Use existing decomposition if it is provided by matrix
|
||||
val bufferFactory: MutableBufferFactory<Double> = MutableBuffer.Companion::real
|
||||
val decomposition: LupDecomposition<Double> = a.getFeature() ?: lup(bufferFactory, RealField, a) { it < 1e-11 }
|
||||
return decomposition.solveWithLUP(bufferFactory, b)
|
||||
return decomposition.solveWithLup(bufferFactory, b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverses a square matrix using LUP decomposition. Non square matrix will throw a error.
|
||||
*/
|
||||
public fun RealMatrixContext.inverseWithLUP(matrix: Matrix<Double>): Matrix<Double> =
|
||||
solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum))
|
||||
public fun RealMatrixContext.inverseWithLup(matrix: Matrix<Double>): Matrix<Double> =
|
||||
solveWithLup(matrix, one(matrix.rowNum, matrix.colNum))
|
@ -1,6 +1,9 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.structures.*
|
||||
import kscience.kmath.nd.Structure2D
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.BufferFactory
|
||||
import kscience.kmath.structures.asBuffer
|
||||
|
||||
public class MatrixBuilder(public val rows: Int, public val columns: Int) {
|
||||
public operator fun <T : Any> invoke(vararg elements: T): Matrix<T> {
|
||||
@ -22,7 +25,7 @@ public fun <T : Any> Structure2D.Companion.row(vararg values: T): Matrix<T> {
|
||||
public inline fun <reified T : Any> Structure2D.Companion.row(
|
||||
size: Int,
|
||||
factory: BufferFactory<T> = Buffer.Companion::auto,
|
||||
noinline builder: (Int) -> T
|
||||
noinline builder: (Int) -> T,
|
||||
): Matrix<T> {
|
||||
val buffer = factory(size, builder)
|
||||
return BufferMatrix(1, size, buffer)
|
||||
@ -36,7 +39,7 @@ public fun <T : Any> Structure2D.Companion.column(vararg values: T): Matrix<T> {
|
||||
public inline fun <reified T : Any> Structure2D.Companion.column(
|
||||
size: Int,
|
||||
factory: BufferFactory<T> = Buffer.Companion::auto,
|
||||
noinline builder: (Int) -> T
|
||||
noinline builder: (Int) -> T,
|
||||
): Matrix<T> {
|
||||
val buffer = factory(size, builder)
|
||||
return BufferMatrix(size, 1, buffer)
|
||||
|
@ -6,7 +6,6 @@ import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.operations.sum
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.BufferFactory
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.asSequence
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,5 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.structures.Matrix
|
||||
|
||||
/**
|
||||
* A marker interface representing some properties of matrices or additional transformations of them. Features are used
|
||||
* to optimize matrix operations performance in some cases or retrieve the APIs.
|
||||
@ -11,8 +9,8 @@ public interface MatrixFeature
|
||||
/**
|
||||
* Matrices with this feature are considered to have only diagonal non-null elements.
|
||||
*/
|
||||
public interface DiagonalFeature : MatrixFeature{
|
||||
public companion object: DiagonalFeature
|
||||
public interface DiagonalFeature : MatrixFeature {
|
||||
public companion object : DiagonalFeature
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,6 +37,8 @@ public interface InverseMatrixFeature<T : Any> : MatrixFeature {
|
||||
|
||||
/**
|
||||
* Matrices with this feature can compute their determinant.
|
||||
*
|
||||
* @param T the type of matrices' items.
|
||||
*/
|
||||
public interface DeterminantFeature<T : Any> : MatrixFeature {
|
||||
/**
|
||||
|
@ -1,11 +1,10 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.nd.Structure2D
|
||||
import kscience.kmath.nd.getFeature
|
||||
import kscience.kmath.operations.Ring
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.Structure2D
|
||||
import kscience.kmath.structures.asBuffer
|
||||
import kscience.kmath.structures.getFeature
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.safeCast
|
||||
@ -39,7 +38,8 @@ public class MatrixWrapper<T : Any> internal constructor(
|
||||
* Origin does not necessary store all features.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public val <T : Any> Matrix<T>.origin: Matrix<T> get() = (this as? MatrixWrapper)?.origin ?: this
|
||||
public val <T : Any> Matrix<T>.origin: Matrix<T>
|
||||
get() = (this as? MatrixWrapper)?.origin ?: this
|
||||
|
||||
/**
|
||||
* Add a single feature to a [Matrix]
|
||||
@ -60,12 +60,6 @@ public operator fun <T : Any> Matrix<T>.plus(newFeatures: Collection<MatrixFeatu
|
||||
MatrixWrapper(this, newFeatures.toSet())
|
||||
}
|
||||
|
||||
public inline fun Structure2D.Companion.real(
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
initializer: (Int, Int) -> Double,
|
||||
): BufferMatrix<Double> = MatrixContext.real.produce(rows, columns, initializer)
|
||||
|
||||
/**
|
||||
* Build a square matrix from given elements.
|
||||
*/
|
||||
|
@ -1,12 +1,10 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.RealBuffer
|
||||
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
public object RealMatrixContext : MatrixContext<Double, BufferMatrix<Double>> {
|
||||
|
||||
public override inline fun produce(
|
||||
public override fun produce(
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
initializer: (i: Int, j: Int) -> Double,
|
||||
@ -15,7 +13,7 @@ public object RealMatrixContext : MatrixContext<Double, BufferMatrix<Double>> {
|
||||
return BufferMatrix(rows, columns, buffer)
|
||||
}
|
||||
|
||||
private fun Matrix<Double>.wrap(): BufferMatrix<Double> = if (this is BufferMatrix) this else {
|
||||
public fun Matrix<Double>.toBufferMatrix(): BufferMatrix<Double> = if (this is BufferMatrix) this else {
|
||||
produce(rowNum, colNum) { i, j -> get(i, j) }
|
||||
}
|
||||
|
||||
@ -25,10 +23,12 @@ public object RealMatrixContext : MatrixContext<Double, BufferMatrix<Double>> {
|
||||
|
||||
public override infix fun Matrix<Double>.dot(other: Matrix<Double>): BufferMatrix<Double> {
|
||||
require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
|
||||
val bufferMatrix = toBufferMatrix()
|
||||
val otherBufferMatrix = other.toBufferMatrix()
|
||||
return produce(rowNum, other.colNum) { i, j ->
|
||||
var res = 0.0
|
||||
for (l in 0 until colNum) {
|
||||
res += get(i, l) * other.get(l, j)
|
||||
res += bufferMatrix[i, l] * otherBufferMatrix[l, j]
|
||||
}
|
||||
res
|
||||
}
|
||||
@ -36,10 +36,11 @@ public object RealMatrixContext : MatrixContext<Double, BufferMatrix<Double>> {
|
||||
|
||||
public override infix fun Matrix<Double>.dot(vector: Point<Double>): Point<Double> {
|
||||
require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" }
|
||||
val bufferMatrix = toBufferMatrix()
|
||||
return RealBuffer(rowNum) { i ->
|
||||
var res = 0.0
|
||||
for (j in 0 until colNum) {
|
||||
res += get(i, j) * vector[j]
|
||||
res += bufferMatrix[i, j] * vector[j]
|
||||
}
|
||||
res
|
||||
}
|
||||
@ -48,17 +49,23 @@ public object RealMatrixContext : MatrixContext<Double, BufferMatrix<Double>> {
|
||||
override fun add(a: Matrix<Double>, b: Matrix<Double>): BufferMatrix<Double> {
|
||||
require(a.rowNum == b.rowNum) { "Row number mismatch in matrix addition. Left side: ${a.rowNum}, right side: ${b.rowNum}" }
|
||||
require(a.colNum == b.colNum) { "Column number mismatch in matrix addition. Left side: ${a.colNum}, right side: ${b.colNum}" }
|
||||
val aBufferMatrix = a.toBufferMatrix()
|
||||
val bBufferMatrix = b.toBufferMatrix()
|
||||
return produce(a.rowNum, a.colNum) { i, j ->
|
||||
a[i, j] + b[i, j]
|
||||
aBufferMatrix[i, j] + bBufferMatrix[i, j]
|
||||
}
|
||||
}
|
||||
|
||||
override fun Matrix<Double>.times(value: Double): BufferMatrix<Double> =
|
||||
produce(rowNum, colNum) { i, j -> get(i, j) * value }
|
||||
override fun Matrix<Double>.times(value: Double): BufferMatrix<Double> {
|
||||
val bufferMatrix = toBufferMatrix()
|
||||
return produce(rowNum, colNum) { i, j -> bufferMatrix[i, j] * value }
|
||||
}
|
||||
|
||||
|
||||
override fun multiply(a: Matrix<Double>, k: Number): BufferMatrix<Double> =
|
||||
produce(a.rowNum, a.colNum) { i, j -> a[i, j] * k.toDouble() }
|
||||
override fun multiply(a: Matrix<Double>, k: Number): BufferMatrix<Double> {
|
||||
val aBufferMatrix = a.toBufferMatrix()
|
||||
return produce(a.rowNum, a.colNum) { i, j -> aBufferMatrix[i, j] * k.toDouble() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.structures.Matrix
|
||||
|
||||
public class VirtualMatrix<T : Any>(
|
||||
override val rowNum: Int,
|
||||
override val colNum: Int,
|
||||
|
@ -1,4 +1,4 @@
|
||||
package kscience.kmath.misc
|
||||
|
||||
@RequiresOptIn("This API is unstable and could change in future", RequiresOptIn.Level.WARNING)
|
||||
public annotation class UnstableKMathAPI
|
||||
public annotation class UnstableKMathAPI
|
||||
|
@ -0,0 +1,134 @@
|
||||
package kscience.kmath.nd
|
||||
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.*
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.BufferFactory
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
public interface BufferNDAlgebra<T, C> : NDAlgebra<T, C> {
|
||||
public val strides: Strides
|
||||
public val bufferFactory: BufferFactory<T>
|
||||
|
||||
override fun produce(initializer: C.(IntArray) -> T): NDBuffer<T> = NDBuffer(
|
||||
strides,
|
||||
bufferFactory(strides.linearSize) { offset ->
|
||||
elementContext.initializer(strides.index(offset))
|
||||
}
|
||||
)
|
||||
|
||||
public val NDStructure<T>.buffer: Buffer<T>
|
||||
get() = when {
|
||||
!shape.contentEquals(this@BufferNDAlgebra.shape) -> throw ShapeMismatchException(
|
||||
this@BufferNDAlgebra.shape,
|
||||
shape
|
||||
)
|
||||
this is NDBuffer && this.strides == this@BufferNDAlgebra.strides -> this.buffer
|
||||
else -> bufferFactory(strides.linearSize) { offset -> get(strides.index(offset)) }
|
||||
}
|
||||
|
||||
override fun NDStructure<T>.map(transform: C.(T) -> T): NDBuffer<T> {
|
||||
val buffer = bufferFactory(strides.linearSize) { offset ->
|
||||
elementContext.transform(buffer[offset])
|
||||
}
|
||||
return NDBuffer(strides, buffer)
|
||||
}
|
||||
|
||||
override fun NDStructure<T>.mapIndexed(transform: C.(index: IntArray, T) -> T): NDBuffer<T> {
|
||||
val buffer = bufferFactory(strides.linearSize) { offset ->
|
||||
elementContext.transform(
|
||||
strides.index(offset),
|
||||
buffer[offset]
|
||||
)
|
||||
}
|
||||
return NDBuffer(strides, buffer)
|
||||
}
|
||||
|
||||
override fun combine(a: NDStructure<T>, b: NDStructure<T>, transform: C.(T, T) -> T): NDBuffer<T> {
|
||||
val buffer = bufferFactory(strides.linearSize) { offset ->
|
||||
elementContext.transform(a.buffer[offset], b.buffer[offset])
|
||||
}
|
||||
return NDBuffer(strides, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
public open class BufferedNDSpace<T, R : Space<T>>(
|
||||
final override val shape: IntArray,
|
||||
final override val elementContext: R,
|
||||
final override val bufferFactory: BufferFactory<T>,
|
||||
) : NDSpace<T, R>, BufferNDAlgebra<T, R> {
|
||||
override val strides: Strides = DefaultStrides(shape)
|
||||
override val zero: NDBuffer<T> by lazy { produce { zero } }
|
||||
}
|
||||
|
||||
public open class BufferedNDRing<T, R : Ring<T>>(
|
||||
shape: IntArray,
|
||||
elementContext: R,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedNDSpace<T, R>(shape, elementContext, bufferFactory), NDRing<T, R> {
|
||||
override val one: NDBuffer<T> by lazy { produce { one } }
|
||||
}
|
||||
|
||||
public open class BufferedNDField<T, R : Field<T>>(
|
||||
shape: IntArray,
|
||||
elementContext: R,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedNDRing<T, R>(shape, elementContext, bufferFactory), NDField<T, R>
|
||||
|
||||
// space factories
|
||||
public fun <T, A : Space<T>> NDAlgebra.Companion.space(
|
||||
space: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
): BufferedNDSpace<T, A> = BufferedNDSpace(shape, space, bufferFactory)
|
||||
|
||||
public inline fun <T, A : Space<T>, R> A.ndSpace(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
action: BufferedNDSpace<T, A>.() -> R,
|
||||
): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return NDAlgebra.space(this, bufferFactory, *shape).run(action)
|
||||
}
|
||||
|
||||
//ring factories
|
||||
public fun <T, A : Ring<T>> NDAlgebra.Companion.ring(
|
||||
ring: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
): BufferedNDRing<T, A> = BufferedNDRing(shape, ring, bufferFactory)
|
||||
|
||||
public inline fun <T, A : Ring<T>, R> A.ndRing(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
action: BufferedNDRing<T, A>.() -> R,
|
||||
): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return NDAlgebra.ring(this, bufferFactory, *shape).run(action)
|
||||
}
|
||||
|
||||
//field factories
|
||||
public fun <T, A : Field<T>> NDAlgebra.Companion.field(
|
||||
field: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
): BufferedNDField<T, A> = BufferedNDField(shape, field, bufferFactory)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public inline fun <reified T : Any, A : Field<T>> NDAlgebra.Companion.auto(
|
||||
field: A,
|
||||
vararg shape: Int,
|
||||
): NDField<T, A> = when (field) {
|
||||
RealField -> RealNDField(shape) as NDField<T, A>
|
||||
else -> BufferedNDField(shape, field, Buffer.Companion::auto)
|
||||
}
|
||||
|
||||
public inline fun <T, A : Field<T>, R> A.ndField(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
action: BufferedNDField<T, A>.() -> R,
|
||||
): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return NDAlgebra.field(this, bufferFactory, *shape).run(action)
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package kscience.kmath.nd
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.operations.*
|
||||
import 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()
|
||||
}
|
262
kmath-core/src/commonMain/kotlin/kscience/kmath/nd/NDAlgebra.kt
Normal file
262
kmath-core/src/commonMain/kotlin/kscience/kmath/nd/NDAlgebra.kt
Normal file
@ -0,0 +1,262 @@
|
||||
package kscience.kmath.nd
|
||||
|
||||
import kscience.kmath.operations.Field
|
||||
import kscience.kmath.operations.Ring
|
||||
import kscience.kmath.operations.Space
|
||||
import kscience.kmath.structures.*
|
||||
|
||||
/**
|
||||
* An exception is thrown when the expected ans actual shape of NDArray differs.
|
||||
*
|
||||
* @property expected the expected shape.
|
||||
* @property actual the actual shape.
|
||||
*/
|
||||
public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) :
|
||||
RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.")
|
||||
|
||||
/**
|
||||
* The base interface for all ND-algebra implementations.
|
||||
*
|
||||
* @param T the type of ND-structure element.
|
||||
* @param C the type of the element context.
|
||||
* @param N the type of the structure.
|
||||
*/
|
||||
public interface NDAlgebra<T, C> {
|
||||
/**
|
||||
* The shape of ND-structures this algebra operates on.
|
||||
*/
|
||||
public val shape: IntArray
|
||||
|
||||
/**
|
||||
* The algebra over elements of ND structure.
|
||||
*/
|
||||
public val elementContext: C
|
||||
|
||||
/**
|
||||
* Produces a new [N] structure using given initializer function.
|
||||
*/
|
||||
public fun produce(initializer: C.(IntArray) -> T): NDStructure<T>
|
||||
|
||||
/**
|
||||
* Maps elements from one structure to another one by applying [transform] to them.
|
||||
*/
|
||||
public fun NDStructure<T>.map(transform: C.(T) -> T): NDStructure<T>
|
||||
|
||||
/**
|
||||
* Maps elements from one structure to another one by applying [transform] to them alongside with their indices.
|
||||
*/
|
||||
public fun NDStructure<T>.mapIndexed(transform: C.(index: IntArray, T) -> T): NDStructure<T>
|
||||
|
||||
/**
|
||||
* Combines two structures into one.
|
||||
*/
|
||||
public fun combine(a: NDStructure<T>, b: NDStructure<T>, transform: C.(T, T) -> T): NDStructure<T>
|
||||
|
||||
/**
|
||||
* Element-wise invocation of function working on [T] on a [NDStructure].
|
||||
*/
|
||||
public operator fun Function1<T, T>.invoke(structure: NDStructure<T>): NDStructure<T> =
|
||||
structure.map() { value -> this@invoke(value) }
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given elements are consistent with this context.
|
||||
*
|
||||
* @param structures the structures to check.
|
||||
* @return the array of valid structures.
|
||||
*/
|
||||
internal fun <T, C> NDAlgebra<T, C>.checkShape(vararg structures: NDStructure<T>): Array<out NDStructure<T>> = structures
|
||||
.map(NDStructure<T>::shape)
|
||||
.singleOrNull { !shape.contentEquals(it) }
|
||||
?.let<IntArray, Array<out NDStructure<T>>> { throw ShapeMismatchException(shape, it) }
|
||||
?: structures
|
||||
|
||||
/**
|
||||
* Checks if given element is consistent with this context.
|
||||
*
|
||||
* @param element the structure to check.
|
||||
* @return the valid structure.
|
||||
*/
|
||||
internal fun <T, C> NDAlgebra<T, C>.checkShape(element: NDStructure<T>): NDStructure<T> {
|
||||
if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape)
|
||||
return element
|
||||
}
|
||||
|
||||
/**
|
||||
* Space of [NDStructure].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param S the type of space of structure elements.
|
||||
*/
|
||||
public interface NDSpace<T, S : Space<T>> : Space<NDStructure<T>>, NDAlgebra<T, S> {
|
||||
/**
|
||||
* Element-wise addition.
|
||||
*
|
||||
* @param a the addend.
|
||||
* @param b the augend.
|
||||
* @return the sum.
|
||||
*/
|
||||
public override fun add(a: NDStructure<T>, b: NDStructure<T>): NDStructure<T> =
|
||||
combine(a, b) { aValue, bValue -> add(aValue, bValue) }
|
||||
|
||||
/**
|
||||
* Element-wise multiplication by scalar.
|
||||
*
|
||||
* @param a the multiplicand.
|
||||
* @param k the multiplier.
|
||||
* @return the product.
|
||||
*/
|
||||
public override fun multiply(a: NDStructure<T>, k: Number): NDStructure<T> = a.map() { multiply(it, k) }
|
||||
|
||||
// TODO move to extensions after KEEP-176
|
||||
|
||||
/**
|
||||
* Adds an ND structure to an element of it.
|
||||
*
|
||||
* @receiver the addend.
|
||||
* @param arg the augend.
|
||||
* @return the sum.
|
||||
*/
|
||||
public operator fun NDStructure<T>.plus(arg: T): NDStructure<T> = this.map() { value -> add(arg, value) }
|
||||
|
||||
/**
|
||||
* Subtracts an element from ND structure of it.
|
||||
*
|
||||
* @receiver the dividend.
|
||||
* @param arg the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public operator fun NDStructure<T>.minus(arg: T): NDStructure<T> = this.map() { value -> add(arg, -value) }
|
||||
|
||||
/**
|
||||
* Adds an element to ND structure of it.
|
||||
*
|
||||
* @receiver the addend.
|
||||
* @param arg the augend.
|
||||
* @return the sum.
|
||||
*/
|
||||
public operator fun T.plus(arg: NDStructure<T>): NDStructure<T> = arg.map() { value -> add(this@plus, value) }
|
||||
|
||||
/**
|
||||
* Subtracts an ND structure from an element of it.
|
||||
*
|
||||
* @receiver the dividend.
|
||||
* @param arg the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public operator fun T.minus(arg: NDStructure<T>): NDStructure<T> = arg.map() { value -> add(-this@minus, value) }
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* Ring of [NDStructure].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param R the type of ring of structure elements.
|
||||
*/
|
||||
public interface NDRing<T, R : Ring<T>> : Ring<NDStructure<T>>, NDSpace<T, R> {
|
||||
/**
|
||||
* Element-wise multiplication.
|
||||
*
|
||||
* @param a the multiplicand.
|
||||
* @param b the multiplier.
|
||||
* @return the product.
|
||||
*/
|
||||
public override fun multiply(a: NDStructure<T>, b: NDStructure<T>): NDStructure<T> =
|
||||
combine(a, b) { aValue, bValue -> multiply(aValue, bValue) }
|
||||
|
||||
//TODO move to extensions after KEEP-176
|
||||
|
||||
/**
|
||||
* Multiplies an ND structure by an element of it.
|
||||
*
|
||||
* @receiver the multiplicand.
|
||||
* @param arg the multiplier.
|
||||
* @return the product.
|
||||
*/
|
||||
public operator fun NDStructure<T>.times(arg: T): NDStructure<T> = this.map() { value -> multiply(arg, value) }
|
||||
|
||||
/**
|
||||
* Multiplies an element by a ND structure of it.
|
||||
*
|
||||
* @receiver the multiplicand.
|
||||
* @param arg the multiplier.
|
||||
* @return the product.
|
||||
*/
|
||||
public operator fun T.times(arg: NDStructure<T>): NDStructure<T> = arg.map() { value -> multiply(this@times, value) }
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* Field of [NDStructure].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param F the type field of structure elements.
|
||||
*/
|
||||
public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F> {
|
||||
/**
|
||||
* Element-wise division.
|
||||
*
|
||||
* @param a the dividend.
|
||||
* @param b the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public override fun divide(a: NDStructure<T>, b: NDStructure<T>): NDStructure<T> =
|
||||
combine(a, b) { aValue, bValue -> divide(aValue, bValue) }
|
||||
|
||||
//TODO move to extensions after KEEP-176
|
||||
/**
|
||||
* Divides an ND structure by an element of it.
|
||||
*
|
||||
* @receiver the dividend.
|
||||
* @param arg the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public operator fun NDStructure<T>.div(arg: T): NDStructure<T> = this.map() { value -> divide(arg, value) }
|
||||
|
||||
/**
|
||||
* Divides an element by an ND structure of it.
|
||||
*
|
||||
* @receiver the dividend.
|
||||
* @param arg the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public operator fun T.div(arg: NDStructure<T>): NDStructure<T> = arg.map() { divide(it, this@div) }
|
||||
|
||||
// @ThreadLocal
|
||||
// public companion object {
|
||||
// private val realNDFieldCache: MutableMap<IntArray, RealNDField> = hashMapOf()
|
||||
//
|
||||
// /**
|
||||
// * Create a nd-field for [Double] values or pull it from cache if it was created previously.
|
||||
// */
|
||||
// public fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) }
|
||||
//
|
||||
// /**
|
||||
// * Create an ND field with boxing generic buffer.
|
||||
// */
|
||||
// public fun <T : Any, F : Field<T>> boxing(
|
||||
// field: F,
|
||||
// vararg shape: Int,
|
||||
// bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
||||
// ): BufferedNDField<T, F> = BufferedNDField(shape, field, bufferFactory)
|
||||
//
|
||||
// /**
|
||||
// * Create a most suitable implementation for nd-field using reified class.
|
||||
// */
|
||||
// @Suppress("UNCHECKED_CAST")
|
||||
// public inline fun <reified T : Any, F : Field<T>> auto(field: F, vararg shape: Int): NDField<T, F> =
|
||||
// when {
|
||||
// T::class == Double::class -> real(*shape) as NDField<T, F>
|
||||
// T::class == Complex::class -> complex(*shape) as BufferedNDField<T, F>
|
||||
// else -> BoxingNDField(shape, field, Buffer.Companion::auto)
|
||||
// }
|
||||
// }
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
package kscience.kmath.structures
|
||||
package kscience.kmath.nd
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.BufferFactory
|
||||
import kscience.kmath.structures.MutableBuffer
|
||||
import kscience.kmath.structures.asSequence
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.native.concurrent.ThreadLocal
|
||||
import kotlin.reflect.KClass
|
||||
@ -74,8 +78,8 @@ public interface NDStructure<T> {
|
||||
strides: Strides,
|
||||
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
||||
initializer: (IntArray) -> T,
|
||||
): BufferNDStructure<T> =
|
||||
BufferNDStructure(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||
): NDBuffer<T> =
|
||||
NDBuffer(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||
|
||||
/**
|
||||
* Inline create NDStructure with non-boxing buffer implementation if it is possible
|
||||
@ -83,40 +87,40 @@ public interface NDStructure<T> {
|
||||
public inline fun <reified T : Any> auto(
|
||||
strides: Strides,
|
||||
crossinline initializer: (IntArray) -> T,
|
||||
): BufferNDStructure<T> =
|
||||
BufferNDStructure(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||
): NDBuffer<T> =
|
||||
NDBuffer(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||
|
||||
public inline fun <T : Any> auto(
|
||||
type: KClass<T>,
|
||||
strides: Strides,
|
||||
crossinline initializer: (IntArray) -> T,
|
||||
): BufferNDStructure<T> =
|
||||
BufferNDStructure(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||
): NDBuffer<T> =
|
||||
NDBuffer(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||
|
||||
public fun <T> build(
|
||||
shape: IntArray,
|
||||
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
||||
initializer: (IntArray) -> T,
|
||||
): BufferNDStructure<T> = build(DefaultStrides(shape), bufferFactory, initializer)
|
||||
): NDBuffer<T> = build(DefaultStrides(shape), bufferFactory, initializer)
|
||||
|
||||
public inline fun <reified T : Any> auto(
|
||||
shape: IntArray,
|
||||
crossinline initializer: (IntArray) -> T,
|
||||
): BufferNDStructure<T> =
|
||||
): NDBuffer<T> =
|
||||
auto(DefaultStrides(shape), initializer)
|
||||
|
||||
@JvmName("autoVarArg")
|
||||
public inline fun <reified T : Any> auto(
|
||||
vararg shape: Int,
|
||||
crossinline initializer: (IntArray) -> T,
|
||||
): BufferNDStructure<T> =
|
||||
): NDBuffer<T> =
|
||||
auto(DefaultStrides(shape), initializer)
|
||||
|
||||
public inline fun <T : Any> auto(
|
||||
type: KClass<T>,
|
||||
vararg shape: Int,
|
||||
crossinline initializer: (IntArray) -> T,
|
||||
): BufferNDStructure<T> =
|
||||
): NDBuffer<T> =
|
||||
auto(type, DefaultStrides(shape), initializer)
|
||||
}
|
||||
}
|
||||
@ -156,7 +160,7 @@ public inline fun <T> MutableNDStructure<T>.mapInPlace(action: (IntArray, T) ->
|
||||
*/
|
||||
public interface Strides {
|
||||
/**
|
||||
* Shape of NDstructure
|
||||
* Shape of NDStructure
|
||||
*/
|
||||
public val shape: IntArray
|
||||
|
||||
@ -185,7 +189,9 @@ public interface Strides {
|
||||
/**
|
||||
* Iterate over ND indices in a natural order
|
||||
*/
|
||||
public fun indices(): Sequence<IntArray> = (0 until linearSize).asSequence().map { index(it) }
|
||||
public fun indices(): Sequence<IntArray> = (0 until linearSize).asSequence().map {
|
||||
index(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,9 +217,7 @@ public class DefaultStrides private constructor(override val shape: IntArray) :
|
||||
}
|
||||
|
||||
override fun offset(index: IntArray): Int = index.mapIndexed { i, value ->
|
||||
if (value < 0 || value >= this.shape[i])
|
||||
throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${this.shape[i]})")
|
||||
|
||||
if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${this.shape[i]})")
|
||||
value * strides[i]
|
||||
}.sum()
|
||||
|
||||
@ -256,23 +260,29 @@ public class DefaultStrides private constructor(override val shape: IntArray) :
|
||||
* Represents [NDStructure] over [Buffer].
|
||||
*
|
||||
* @param T the type of items.
|
||||
* @param strides The strides to access elements of [Buffer] by linear indices.
|
||||
* @param buffer The underlying buffer.
|
||||
*/
|
||||
public abstract class NDBuffer<T> : NDStructure<T> {
|
||||
/**
|
||||
* The underlying buffer.
|
||||
*/
|
||||
public abstract val buffer: Buffer<T>
|
||||
public open class NDBuffer<T>(
|
||||
public val strides: Strides,
|
||||
buffer: Buffer<T>,
|
||||
) : NDStructure<T> {
|
||||
|
||||
/**
|
||||
* The strides to access elements of [Buffer] by linear indices.
|
||||
*/
|
||||
public abstract val strides: Strides
|
||||
init {
|
||||
if (strides.linearSize != buffer.size) {
|
||||
error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}")
|
||||
}
|
||||
}
|
||||
|
||||
public open val buffer: Buffer<T> = buffer
|
||||
|
||||
override operator fun get(index: IntArray): T = buffer[strides.offset(index)]
|
||||
|
||||
override val shape: IntArray get() = strides.shape
|
||||
|
||||
override fun elements(): Sequence<Pair<IntArray, T>> = strides.indices().map { it to this[it] }
|
||||
override fun elements(): Sequence<Pair<IntArray, T>> = strides.indices().map {
|
||||
it to this[it]
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return NDStructure.contentEquals(this, other as? NDStructure<*> ?: return false)
|
||||
@ -297,46 +307,30 @@ public abstract class NDBuffer<T> : NDStructure<T> {
|
||||
}
|
||||
return "NDBuffer(shape=${shape.contentToString()}, buffer=$bufferRepr)"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Boxing generic [NDStructure]
|
||||
*/
|
||||
public class BufferNDStructure<T>(
|
||||
override val strides: Strides,
|
||||
override val buffer: Buffer<T>,
|
||||
) : NDBuffer<T>() {
|
||||
init {
|
||||
if (strides.linearSize != buffer.size) {
|
||||
error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferNDStructure]
|
||||
* Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [NDBuffer]
|
||||
*/
|
||||
public inline fun <T, reified R : Any> NDStructure<T>.mapToBuffer(
|
||||
factory: BufferFactory<R> = Buffer.Companion::auto,
|
||||
crossinline transform: (T) -> R,
|
||||
): BufferNDStructure<R> {
|
||||
return if (this is BufferNDStructure<T>)
|
||||
BufferNDStructure(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) })
|
||||
): NDBuffer<R> {
|
||||
return if (this is NDBuffer<T>)
|
||||
NDBuffer(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) })
|
||||
else {
|
||||
val strides = DefaultStrides(shape)
|
||||
BufferNDStructure(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
||||
NDBuffer(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutable ND buffer based on linear [MutableBuffer].
|
||||
*/
|
||||
public class MutableBufferNDStructure<T>(
|
||||
override val strides: Strides,
|
||||
override val buffer: MutableBuffer<T>,
|
||||
) : NDBuffer<T>(), MutableNDStructure<T> {
|
||||
public class MutableNDBuffer<T>(
|
||||
strides: Strides,
|
||||
buffer: MutableBuffer<T>,
|
||||
) : NDBuffer<T>(strides, buffer), MutableNDStructure<T> {
|
||||
|
||||
init {
|
||||
require(strides.linearSize == buffer.size) {
|
||||
@ -344,6 +338,8 @@ public class MutableBufferNDStructure<T>(
|
||||
}
|
||||
}
|
||||
|
||||
override val buffer: MutableBuffer<T> = super.buffer as MutableBuffer<T>
|
||||
|
||||
override operator fun set(index: IntArray, value: T): Unit = buffer.set(strides.offset(index), value)
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
package kscience.kmath.nd
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.operations.ExtendedField
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.RingWithNumbers
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.RealBuffer
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class RealNDField(
|
||||
shape: IntArray,
|
||||
) : BufferedNDField<Double, RealField>(shape, RealField, Buffer.Companion::real),
|
||||
RingWithNumbers<NDStructure<Double>>,
|
||||
ExtendedField<NDStructure<Double>> {
|
||||
|
||||
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 }
|
||||
}
|
||||
|
||||
override val NDStructure<Double>.buffer: RealBuffer
|
||||
get() = when {
|
||||
!shape.contentEquals(this@RealNDField.shape) -> throw ShapeMismatchException(
|
||||
this@RealNDField.shape,
|
||||
shape
|
||||
)
|
||||
this is NDBuffer && this.strides == this@RealNDField.strides -> this.buffer as RealBuffer
|
||||
else -> RealBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
override inline fun NDStructure<Double>.map(
|
||||
transform: RealField.(Double) -> Double,
|
||||
): NDBuffer<Double> {
|
||||
val buffer = RealBuffer(strides.linearSize) { offset -> RealField.transform(buffer.array[offset]) }
|
||||
return NDBuffer(strides, buffer)
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
override inline fun produce(initializer: RealField.(IntArray) -> Double): NDBuffer<Double> {
|
||||
val array = DoubleArray(strides.linearSize) { offset ->
|
||||
val index = strides.index(offset)
|
||||
RealField.initializer(index)
|
||||
}
|
||||
return NDBuffer(strides, RealBuffer(array))
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
override inline fun NDStructure<Double>.mapIndexed(
|
||||
transform: RealField.(index: IntArray, Double) -> Double,
|
||||
): NDBuffer<Double> = NDBuffer(
|
||||
strides,
|
||||
buffer = RealBuffer(strides.linearSize) { offset ->
|
||||
RealField.transform(
|
||||
strides.index(offset),
|
||||
buffer.array[offset]
|
||||
)
|
||||
})
|
||||
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
override inline fun combine(
|
||||
a: NDStructure<Double>,
|
||||
b: NDStructure<Double>,
|
||||
transform: RealField.(Double, Double) -> Double,
|
||||
): NDBuffer<Double> {
|
||||
val buffer = RealBuffer(strides.linearSize) { offset ->
|
||||
RealField.transform(a.buffer.array[offset], b.buffer.array[offset])
|
||||
}
|
||||
return NDBuffer(strides, buffer)
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
|
||||
public fun NDAlgebra.Companion.real(vararg shape: Int): RealNDField = RealNDField(shape)
|
||||
|
||||
/**
|
||||
* Produce a context for n-dimensional operations inside this real field
|
||||
*/
|
||||
public inline fun <R> RealField.nd(vararg shape: Int, action: RealNDField.() -> R): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return RealNDField(shape).run(action)
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package kscience.kmath.nd
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.operations.RingWithNumbers
|
||||
import kscience.kmath.operations.ShortRing
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.ShortBuffer
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class ShortNDRing(
|
||||
shape: IntArray,
|
||||
) : BufferedNDRing<Short, ShortRing>(shape, ShortRing, Buffer.Companion::auto),
|
||||
RingWithNumbers<NDStructure<Short>> {
|
||||
|
||||
override val zero: NDBuffer<Short> by lazy { produce { zero } }
|
||||
override val one: NDBuffer<Short> by lazy { produce { one } }
|
||||
|
||||
override fun number(value: Number): NDBuffer<Short> {
|
||||
val d = value.toShort() // minimize conversions
|
||||
return produce { d }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast element production using function inlining.
|
||||
*/
|
||||
public inline fun BufferedNDRing<Short, ShortRing>.produceInline(crossinline initializer: ShortRing.(Int) -> Short): NDBuffer<Short> {
|
||||
return NDBuffer(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) }))
|
||||
}
|
||||
|
||||
public inline fun <R> ShortRing.nd(vararg shape: Int, action: ShortNDRing.() -> R): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return ShortNDRing(shape).run(action)
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
package kscience.kmath.structures
|
||||
package kscience.kmath.nd
|
||||
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.asSequence
|
||||
|
||||
/**
|
||||
* A structure that is guaranteed to be one-dimensional
|
||||
@ -34,7 +37,7 @@ private inline class Buffer1DWrapper<T>(val buffer: Buffer<T>) : Structure1D<T>
|
||||
override val size: Int get() = buffer.size
|
||||
|
||||
override fun elements(): Sequence<Pair<IntArray, T>> =
|
||||
asSequence().mapIndexed { index, value -> intArrayOf(index) to value }
|
||||
buffer.asSequence().mapIndexed { index, value -> intArrayOf(index) to value }
|
||||
|
||||
override operator fun get(index: Int): T = buffer[index]
|
||||
}
|
@ -1,4 +1,9 @@
|
||||
package kscience.kmath.structures
|
||||
package kscience.kmath.nd
|
||||
|
||||
import kscience.kmath.linear.BufferMatrix
|
||||
import kscience.kmath.linear.RealMatrixContext
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.VirtualBuffer
|
||||
|
||||
/**
|
||||
* A structure that is guaranteed to be two-dimensional.
|
||||
@ -49,7 +54,15 @@ public interface Structure2D<T> : NDStructure<T> {
|
||||
for (j in 0 until colNum) yield(intArrayOf(i, j) to get(i, j))
|
||||
}
|
||||
|
||||
public companion object
|
||||
public companion object {
|
||||
public inline fun real(
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
crossinline init: (i: Int, j: Int) -> Double,
|
||||
): BufferMatrix<Double> = RealMatrixContext.produce(rows,columns) { i, j ->
|
||||
init(i, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,10 +86,3 @@ public fun <T> NDStructure<T>.as2D(): Structure2D<T> = if (shape.size == 2)
|
||||
Structure2DWrapper(this)
|
||||
else
|
||||
error("Can't create 2d-structure from ${shape.size}d-structure")
|
||||
|
||||
/**
|
||||
* Alias for [Structure2D] with more familiar name.
|
||||
*
|
||||
* @param T the type of items.
|
||||
*/
|
||||
public typealias Matrix<T> = Structure2D<T>
|
@ -1,9 +1,12 @@
|
||||
package kscience.kmath.operations
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.nd.BufferedNDRing
|
||||
import kscience.kmath.nd.NDAlgebra
|
||||
import kscience.kmath.operations.BigInt.Companion.BASE
|
||||
import kscience.kmath.operations.BigInt.Companion.BASE_SIZE
|
||||
import kscience.kmath.structures.*
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.MutableBuffer
|
||||
import kotlin.math.log2
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
@ -463,10 +466,5 @@ public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigIn
|
||||
public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer<BigInt> =
|
||||
boxing(size, initializer)
|
||||
|
||||
public fun NDAlgebra.Companion.bigInt(vararg shape: Int): BoxingNDRing<BigInt, BigIntField> =
|
||||
BoxingNDRing(shape, BigIntField, Buffer.Companion::bigInt)
|
||||
|
||||
public fun NDElement.Companion.bigInt(
|
||||
vararg shape: Int,
|
||||
initializer: BigIntField.(IntArray) -> BigInt
|
||||
): BufferedNDRingElement<BigInt, BigIntField> = NDAlgebra.bigInt(*shape).produce(initializer)
|
||||
public fun NDAlgebra.Companion.bigInt(vararg shape: Int): BufferedNDRing<BigInt, BigIntField> =
|
||||
BufferedNDRing(shape, BigIntField, Buffer.Companion::bigInt)
|
||||
|
@ -1,81 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.operations.Field
|
||||
import kscience.kmath.operations.FieldElement
|
||||
|
||||
public class BoxingNDField<T, F : Field<T>>(
|
||||
public override val shape: IntArray,
|
||||
public override val elementContext: F,
|
||||
public val bufferFactory: BufferFactory<T>
|
||||
) : BufferedNDField<T, F> {
|
||||
public override val zero: BufferedNDFieldElement<T, F> by lazy { produce { zero } }
|
||||
public override val one: BufferedNDFieldElement<T, F> by lazy { produce { one } }
|
||||
public override val strides: Strides = DefaultStrides(shape)
|
||||
|
||||
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> =
|
||||
bufferFactory(size, initializer)
|
||||
|
||||
public override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
|
||||
require(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" }
|
||||
return elements
|
||||
}
|
||||
|
||||
public override fun produce(initializer: F.(IntArray) -> T): BufferedNDFieldElement<T, F> =
|
||||
BufferedNDFieldElement(
|
||||
this,
|
||||
buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) })
|
||||
|
||||
public override fun map(arg: NDBuffer<T>, transform: F.(T) -> T): BufferedNDFieldElement<T, F> {
|
||||
check(arg)
|
||||
|
||||
return BufferedNDFieldElement(
|
||||
this,
|
||||
buildBuffer(arg.strides.linearSize) { offset -> elementContext.transform(arg.buffer[offset]) })
|
||||
|
||||
// val buffer = arg.buffer.transform { _, value -> elementContext.transform(value) }
|
||||
// return BufferedNDFieldElement(this, buffer)
|
||||
|
||||
}
|
||||
|
||||
public override fun mapIndexed(
|
||||
arg: NDBuffer<T>,
|
||||
transform: F.(index: IntArray, T) -> T
|
||||
): BufferedNDFieldElement<T, F> {
|
||||
check(arg)
|
||||
return BufferedNDFieldElement(
|
||||
this,
|
||||
buildBuffer(arg.strides.linearSize) { offset ->
|
||||
elementContext.transform(
|
||||
arg.strides.index(offset),
|
||||
arg.buffer[offset]
|
||||
)
|
||||
})
|
||||
|
||||
// val buffer =
|
||||
// arg.buffer.transform { offset, value -> elementContext.transform(arg.strides.index(offset), value) }
|
||||
// return BufferedNDFieldElement(this, buffer)
|
||||
}
|
||||
|
||||
public override fun combine(
|
||||
a: NDBuffer<T>,
|
||||
b: NDBuffer<T>,
|
||||
transform: F.(T, T) -> T
|
||||
): BufferedNDFieldElement<T, F> {
|
||||
check(a, b)
|
||||
return BufferedNDFieldElement(
|
||||
this,
|
||||
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
|
||||
}
|
||||
|
||||
public override fun NDBuffer<T>.toElement(): FieldElement<NDBuffer<T>, *, out BufferedNDField<T, F>> =
|
||||
BufferedNDFieldElement(this@BoxingNDField, buffer)
|
||||
}
|
||||
|
||||
public inline fun <T : Any, F : Field<T>, R> F.nd(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
action: NDField<T, F, *>.() -> R
|
||||
): R {
|
||||
val ndfield = NDField.boxing(this, *shape, bufferFactory = bufferFactory)
|
||||
return ndfield.action()
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.operations.Ring
|
||||
import kscience.kmath.operations.RingElement
|
||||
|
||||
public class BoxingNDRing<T, R : Ring<T>>(
|
||||
override val shape: IntArray,
|
||||
override val elementContext: R,
|
||||
public val bufferFactory: BufferFactory<T>
|
||||
) : BufferedNDRing<T, R> {
|
||||
override val strides: Strides = DefaultStrides(shape)
|
||||
override val zero: BufferedNDRingElement<T, R> by lazy { produce { zero } }
|
||||
override val one: BufferedNDRingElement<T, R> by lazy { produce { one } }
|
||||
|
||||
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = bufferFactory(size, initializer)
|
||||
|
||||
override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
|
||||
if (!elements.all { it.strides == this.strides }) error("Element strides are not the same as context strides")
|
||||
return elements
|
||||
}
|
||||
|
||||
override fun produce(initializer: R.(IntArray) -> T): BufferedNDRingElement<T, R> =
|
||||
BufferedNDRingElement(
|
||||
this,
|
||||
buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) })
|
||||
|
||||
override fun map(arg: NDBuffer<T>, transform: R.(T) -> T): BufferedNDRingElement<T, R> {
|
||||
check(arg)
|
||||
return BufferedNDRingElement(
|
||||
this,
|
||||
buildBuffer(arg.strides.linearSize) { offset -> elementContext.transform(arg.buffer[offset]) })
|
||||
|
||||
// val buffer = arg.buffer.transform { _, value -> elementContext.transform(value) }
|
||||
// return BufferedNDFieldElement(this, buffer)
|
||||
|
||||
}
|
||||
|
||||
override fun mapIndexed(
|
||||
arg: NDBuffer<T>,
|
||||
transform: R.(index: IntArray, T) -> T
|
||||
): BufferedNDRingElement<T, R> {
|
||||
check(arg)
|
||||
return BufferedNDRingElement(
|
||||
this,
|
||||
buildBuffer(arg.strides.linearSize) { offset ->
|
||||
elementContext.transform(
|
||||
arg.strides.index(offset),
|
||||
arg.buffer[offset]
|
||||
)
|
||||
})
|
||||
|
||||
// val buffer =
|
||||
// arg.buffer.transform { offset, value -> elementContext.transform(arg.strides.index(offset), value) }
|
||||
// return BufferedNDFieldElement(this, buffer)
|
||||
}
|
||||
|
||||
override fun combine(
|
||||
a: NDBuffer<T>,
|
||||
b: NDBuffer<T>,
|
||||
transform: R.(T, T) -> T
|
||||
): BufferedNDRingElement<T, R> {
|
||||
check(a, b)
|
||||
|
||||
return BufferedNDRingElement(
|
||||
this,
|
||||
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
|
||||
}
|
||||
|
||||
override fun NDBuffer<T>.toElement(): RingElement<NDBuffer<T>, *, out BufferedNDRing<T, R>> =
|
||||
BufferedNDRingElement(this@BoxingNDRing, buffer)
|
||||
}
|
@ -1,5 +1,10 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.nd.DefaultStrides
|
||||
import kscience.kmath.nd.NDStructure
|
||||
import kscience.kmath.nd.Structure2D
|
||||
import kscience.kmath.nd.as2D
|
||||
|
||||
/**
|
||||
* A context that allows to operate on a [MutableBuffer] as on 2d array
|
||||
*/
|
||||
|
@ -1,43 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.operations.*
|
||||
|
||||
public interface BufferedNDAlgebra<T, C> : NDAlgebra<T, C, NDBuffer<T>> {
|
||||
public val strides: Strides
|
||||
|
||||
public override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
|
||||
require(elements.all { it.strides == strides }) { "Strides mismatch" }
|
||||
return elements
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert any [NDStructure] to buffered structure using strides from this context.
|
||||
* If the structure is already [NDBuffer], conversion is free. If not, it could be expensive because iteration over
|
||||
* indices.
|
||||
*
|
||||
* If the argument is [NDBuffer] with different strides structure, the new element will be produced.
|
||||
*/
|
||||
public fun NDStructure<T>.toBuffer(): NDBuffer<T> =
|
||||
if (this is NDBuffer<T> && this.strides == this@BufferedNDAlgebra.strides)
|
||||
this
|
||||
else
|
||||
produce { index -> this@toBuffer[index] }
|
||||
|
||||
/**
|
||||
* Convert a buffer to element of this algebra
|
||||
*/
|
||||
public fun NDBuffer<T>.toElement(): MathElement<out BufferedNDAlgebra<T, C>>
|
||||
}
|
||||
|
||||
|
||||
public interface BufferedNDSpace<T, S : Space<T>> : NDSpace<T, S, NDBuffer<T>>, BufferedNDAlgebra<T, S> {
|
||||
public override fun NDBuffer<T>.toElement(): SpaceElement<NDBuffer<T>, *, out BufferedNDSpace<T, S>>
|
||||
}
|
||||
|
||||
public interface BufferedNDRing<T, R : Ring<T>> : NDRing<T, R, NDBuffer<T>>, BufferedNDSpace<T, R> {
|
||||
override fun NDBuffer<T>.toElement(): RingElement<NDBuffer<T>, *, out BufferedNDRing<T, R>>
|
||||
}
|
||||
|
||||
public interface BufferedNDField<T, F : Field<T>> : NDField<T, F, NDBuffer<T>>, BufferedNDRing<T, F> {
|
||||
override fun NDBuffer<T>.toElement(): FieldElement<NDBuffer<T>, *, out BufferedNDField<T, F>>
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.operations.*
|
||||
|
||||
/**
|
||||
* Base class for an element with context, containing strides
|
||||
*/
|
||||
public abstract class BufferedNDElement<T, C> : NDBuffer<T>(), NDElement<T, C, NDBuffer<T>> {
|
||||
abstract override val context: BufferedNDAlgebra<T, C>
|
||||
|
||||
override val strides: Strides get() = context.strides
|
||||
|
||||
override val shape: IntArray get() = context.shape
|
||||
}
|
||||
|
||||
public class BufferedNDSpaceElement<T, S : Space<T>>(
|
||||
override val context: BufferedNDSpace<T, S>,
|
||||
override val buffer: Buffer<T>
|
||||
) : BufferedNDElement<T, S>(), SpaceElement<NDBuffer<T>, BufferedNDSpaceElement<T, S>, BufferedNDSpace<T, S>> {
|
||||
|
||||
override fun unwrap(): NDBuffer<T> = this
|
||||
|
||||
override fun NDBuffer<T>.wrap(): BufferedNDSpaceElement<T, S> {
|
||||
context.check(this)
|
||||
return BufferedNDSpaceElement(context, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
public class BufferedNDRingElement<T, R : Ring<T>>(
|
||||
override val context: BufferedNDRing<T, R>,
|
||||
override val buffer: Buffer<T>
|
||||
) : BufferedNDElement<T, R>(), RingElement<NDBuffer<T>, BufferedNDRingElement<T, R>, BufferedNDRing<T, R>> {
|
||||
override fun unwrap(): NDBuffer<T> = this
|
||||
|
||||
override fun NDBuffer<T>.wrap(): BufferedNDRingElement<T, R> {
|
||||
context.check(this)
|
||||
return BufferedNDRingElement(context, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
public class BufferedNDFieldElement<T, F : Field<T>>(
|
||||
override val context: BufferedNDField<T, F>,
|
||||
override val buffer: Buffer<T>
|
||||
) : BufferedNDElement<T, F>(), FieldElement<NDBuffer<T>, BufferedNDFieldElement<T, F>, BufferedNDField<T, F>> {
|
||||
override fun unwrap(): NDBuffer<T> = this
|
||||
|
||||
override fun NDBuffer<T>.wrap(): BufferedNDFieldElement<T, F> {
|
||||
context.check(this)
|
||||
return BufferedNDFieldElement(context, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Element by element application of any operation on elements to the whole array. Just like in numpy.
|
||||
*/
|
||||
public operator fun <T : Any, F : Field<T>> Function1<T, T>.invoke(ndElement: BufferedNDElement<T, F>): MathElement<out BufferedNDAlgebra<T, F>> =
|
||||
ndElement.context.run { map(ndElement) { invoke(it) }.toElement() }
|
||||
|
||||
/* plus and minus */
|
||||
|
||||
/**
|
||||
* Summation operation for [BufferedNDElement] and single element
|
||||
*/
|
||||
public operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.plus(arg: T): NDElement<T, F, NDBuffer<T>> =
|
||||
context.map(this) { it + arg }.wrap()
|
||||
|
||||
/**
|
||||
* Subtraction operation between [BufferedNDElement] and single element
|
||||
*/
|
||||
public operator fun <T : Any, F : Space<T>> BufferedNDElement<T, F>.minus(arg: T): NDElement<T, F, NDBuffer<T>> =
|
||||
context.map(this) { it - arg }.wrap()
|
||||
|
||||
/* prod and div */
|
||||
|
||||
/**
|
||||
* Product operation for [BufferedNDElement] and single element
|
||||
*/
|
||||
public operator fun <T : Any, F : Ring<T>> BufferedNDElement<T, F>.times(arg: T): NDElement<T, F, NDBuffer<T>> =
|
||||
context.map(this) { it * arg }.wrap()
|
||||
|
||||
/**
|
||||
* Division operation between [BufferedNDElement] and single element
|
||||
*/
|
||||
public operator fun <T : Any, F : Field<T>> BufferedNDElement<T, F>.div(arg: T): NDElement<T, F, NDBuffer<T>> =
|
||||
context.map(this) { it / arg }.wrap()
|
@ -1,158 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.operations.*
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
public typealias ComplexNDElement = BufferedNDFieldElement<Complex, ComplexField>
|
||||
|
||||
/**
|
||||
* An optimized nd-field for complex numbers
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class ComplexNDField(override val shape: IntArray) :
|
||||
BufferedNDField<Complex, ComplexField>,
|
||||
ExtendedNDField<Complex, ComplexField, NDBuffer<Complex>>,
|
||||
RingWithNumbers<NDBuffer<Complex>>{
|
||||
|
||||
override val strides: Strides = DefaultStrides(shape)
|
||||
override val elementContext: ComplexField get() = ComplexField
|
||||
override val zero: ComplexNDElement by lazy { produce { zero } }
|
||||
override val one: ComplexNDElement by lazy { produce { one } }
|
||||
|
||||
override fun number(value: Number): NDBuffer<Complex> {
|
||||
val c = value.toComplex()
|
||||
return produce { c }
|
||||
}
|
||||
|
||||
public inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Complex): Buffer<Complex> =
|
||||
Buffer.complex(size) { initializer(it) }
|
||||
|
||||
/**
|
||||
* Inline transform an NDStructure to another structure
|
||||
*/
|
||||
override fun map(
|
||||
arg: NDBuffer<Complex>,
|
||||
transform: ComplexField.(Complex) -> Complex,
|
||||
): ComplexNDElement {
|
||||
check(arg)
|
||||
val array = buildBuffer(arg.strides.linearSize) { offset -> ComplexField.transform(arg.buffer[offset]) }
|
||||
return BufferedNDFieldElement(this, array)
|
||||
}
|
||||
|
||||
override fun produce(initializer: ComplexField.(IntArray) -> Complex): ComplexNDElement {
|
||||
val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
||||
return BufferedNDFieldElement(this, array)
|
||||
}
|
||||
|
||||
override fun mapIndexed(
|
||||
arg: NDBuffer<Complex>,
|
||||
transform: ComplexField.(index: IntArray, Complex) -> Complex,
|
||||
): ComplexNDElement {
|
||||
check(arg)
|
||||
|
||||
return BufferedNDFieldElement(
|
||||
this,
|
||||
buildBuffer(arg.strides.linearSize) { offset ->
|
||||
elementContext.transform(
|
||||
arg.strides.index(offset),
|
||||
arg.buffer[offset]
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
override fun combine(
|
||||
a: NDBuffer<Complex>,
|
||||
b: NDBuffer<Complex>,
|
||||
transform: ComplexField.(Complex, Complex) -> Complex,
|
||||
): ComplexNDElement {
|
||||
check(a, b)
|
||||
|
||||
return BufferedNDFieldElement(
|
||||
this,
|
||||
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
|
||||
}
|
||||
|
||||
override fun NDBuffer<Complex>.toElement(): FieldElement<NDBuffer<Complex>, *, out BufferedNDField<Complex, ComplexField>> =
|
||||
BufferedNDFieldElement(this@ComplexNDField, buffer)
|
||||
|
||||
override fun power(arg: NDBuffer<Complex>, pow: Number): ComplexNDElement =
|
||||
map(arg) { power(it, pow) }
|
||||
|
||||
override fun exp(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { exp(it) }
|
||||
override fun ln(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { ln(it) }
|
||||
|
||||
override fun sin(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { sin(it) }
|
||||
override fun cos(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { cos(it) }
|
||||
override fun tan(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { tan(it) }
|
||||
override fun asin(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { asin(it) }
|
||||
override fun acos(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { acos(it) }
|
||||
override fun atan(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { atan(it) }
|
||||
|
||||
override fun sinh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { sinh(it) }
|
||||
override fun cosh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { cosh(it) }
|
||||
override fun tanh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { tanh(it) }
|
||||
override fun asinh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { asinh(it) }
|
||||
override fun acosh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { acosh(it) }
|
||||
override fun atanh(arg: NDBuffer<Complex>): ComplexNDElement = map(arg) { atanh(it) }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fast element production using function inlining
|
||||
*/
|
||||
public inline fun BufferedNDField<Complex, ComplexField>.produceInline(initializer: ComplexField.(Int) -> Complex): ComplexNDElement {
|
||||
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) }
|
||||
return BufferedNDFieldElement(this, buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Map one [ComplexNDElement] using function with indices.
|
||||
*/
|
||||
public inline fun ComplexNDElement.mapIndexed(transform: ComplexField.(index: IntArray, Complex) -> Complex): ComplexNDElement =
|
||||
context.produceInline { offset -> transform(strides.index(offset), buffer[offset]) }
|
||||
|
||||
/**
|
||||
* Map one [ComplexNDElement] using function without indices.
|
||||
*/
|
||||
public inline fun ComplexNDElement.map(transform: ComplexField.(Complex) -> Complex): ComplexNDElement {
|
||||
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.transform(buffer[offset]) }
|
||||
return BufferedNDFieldElement(context, buffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Element by element application of any operation on elements to the whole array. Just like in numpy
|
||||
*/
|
||||
public operator fun Function1<Complex, Complex>.invoke(ndElement: ComplexNDElement): ComplexNDElement =
|
||||
ndElement.map { this@invoke(it) }
|
||||
|
||||
/* plus and minus */
|
||||
|
||||
/**
|
||||
* Summation operation for [BufferedNDElement] and single element
|
||||
*/
|
||||
public operator fun ComplexNDElement.plus(arg: Complex): ComplexNDElement = map { it + arg }
|
||||
|
||||
/**
|
||||
* Subtraction operation between [BufferedNDElement] and single element
|
||||
*/
|
||||
public operator fun ComplexNDElement.minus(arg: Complex): ComplexNDElement = map { it - arg }
|
||||
|
||||
public operator fun ComplexNDElement.plus(arg: Double): ComplexNDElement = map { it + arg }
|
||||
public operator fun ComplexNDElement.minus(arg: Double): ComplexNDElement = map { it - arg }
|
||||
|
||||
public fun NDField.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape)
|
||||
|
||||
public fun NDElement.Companion.complex(
|
||||
vararg shape: Int,
|
||||
initializer: ComplexField.(IntArray) -> Complex,
|
||||
): ComplexNDElement = NDField.complex(*shape).produce(initializer)
|
||||
|
||||
/**
|
||||
* Produce a context for n-dimensional operations inside this real field
|
||||
*/
|
||||
public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return NDField.complex(*shape).action()
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.operations.ExtendedField
|
||||
|
||||
/**
|
||||
* [ExtendedField] over [NDStructure].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param F the extended field of structure elements.
|
||||
*/
|
||||
public interface ExtendedNDField<T : Any, F : ExtendedField<T>, N : NDStructure<T>> : NDField<T, F, N>, ExtendedField<N>
|
||||
|
||||
///**
|
||||
// * NDField that supports [ExtendedField] operations on its elements
|
||||
// */
|
||||
//class ExtendedNDFieldWrapper<T : Any, F : ExtendedField<T>, N : NDStructure<T>>(private val ndField: NDField<T, F, N>) :
|
||||
// ExtendedNDField<T, F, N>, NDField<T, F, N> by ndField {
|
||||
//
|
||||
// override val shape: IntArray get() = ndField.shape
|
||||
// override val elementContext: F get() = ndField.elementContext
|
||||
//
|
||||
// override fun produce(initializer: F.(IntArray) -> T) = ndField.produce(initializer)
|
||||
//
|
||||
// override fun power(arg: N, pow: Double): N {
|
||||
// return produce { with(elementContext) { power(arg[it], pow) } }
|
||||
// }
|
||||
//
|
||||
// override fun exp(arg: N): N {
|
||||
// return produce { with(elementContext) { exp(arg[it]) } }
|
||||
// }
|
||||
//
|
||||
// override fun ln(arg: N): N {
|
||||
// return produce { with(elementContext) { ln(arg[it]) } }
|
||||
// }
|
||||
//
|
||||
// override fun sin(arg: N): N {
|
||||
// return produce { with(elementContext) { sin(arg[it]) } }
|
||||
// }
|
||||
//
|
||||
// override fun cos(arg: N): N {
|
||||
// return produce { with(elementContext) { cos(arg[it]) } }
|
||||
// }
|
||||
//}
|
@ -1,259 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.operations.Complex
|
||||
import kscience.kmath.operations.Field
|
||||
import kscience.kmath.operations.Ring
|
||||
import kscience.kmath.operations.Space
|
||||
import kotlin.native.concurrent.ThreadLocal
|
||||
|
||||
/**
|
||||
* An exception is thrown when the expected ans actual shape of NDArray differs.
|
||||
*
|
||||
* @property expected the expected shape.
|
||||
* @property actual the actual shape.
|
||||
*/
|
||||
public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) :
|
||||
RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.")
|
||||
|
||||
/**
|
||||
* The base interface for all ND-algebra implementations.
|
||||
*
|
||||
* @param T the type of ND-structure element.
|
||||
* @param C the type of the element context.
|
||||
* @param N the type of the structure.
|
||||
*/
|
||||
public interface NDAlgebra<T, C, N : NDStructure<T>> {
|
||||
/**
|
||||
* The shape of ND-structures this algebra operates on.
|
||||
*/
|
||||
public val shape: IntArray
|
||||
|
||||
/**
|
||||
* The algebra over elements of ND structure.
|
||||
*/
|
||||
public val elementContext: C
|
||||
|
||||
/**
|
||||
* Produces a new [N] structure using given initializer function.
|
||||
*/
|
||||
public fun produce(initializer: C.(IntArray) -> T): N
|
||||
|
||||
/**
|
||||
* Maps elements from one structure to another one by applying [transform] to them.
|
||||
*/
|
||||
public fun map(arg: N, transform: C.(T) -> T): N
|
||||
|
||||
/**
|
||||
* Maps elements from one structure to another one by applying [transform] to them alongside with their indices.
|
||||
*/
|
||||
public fun mapIndexed(arg: N, transform: C.(index: IntArray, T) -> T): N
|
||||
|
||||
/**
|
||||
* Combines two structures into one.
|
||||
*/
|
||||
public fun combine(a: N, b: N, transform: C.(T, T) -> T): N
|
||||
|
||||
/**
|
||||
* Checks if given element is consistent with this context.
|
||||
*
|
||||
* @param element the structure to check.
|
||||
* @return the valid structure.
|
||||
*/
|
||||
public fun check(element: N): N {
|
||||
if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape)
|
||||
return element
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given elements are consistent with this context.
|
||||
*
|
||||
* @param elements the structures to check.
|
||||
* @return the array of valid structures.
|
||||
*/
|
||||
public fun check(vararg elements: N): Array<out N> = elements
|
||||
.map(NDStructure<T>::shape)
|
||||
.singleOrNull { !shape.contentEquals(it) }
|
||||
?.let<IntArray, Array<out N>> { throw ShapeMismatchException(shape, it) }
|
||||
?: elements
|
||||
|
||||
/**
|
||||
* Element-wise invocation of function working on [T] on a [NDStructure].
|
||||
*/
|
||||
public operator fun Function1<T, T>.invoke(structure: N): N = map(structure) { value -> this@invoke(value) }
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* Space of [NDStructure].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param S the type of space of structure elements.
|
||||
*/
|
||||
public interface NDSpace<T, S : Space<T>, N : NDStructure<T>> : Space<N>, NDAlgebra<T, S, N> {
|
||||
/**
|
||||
* Element-wise addition.
|
||||
*
|
||||
* @param a the addend.
|
||||
* @param b the augend.
|
||||
* @return the sum.
|
||||
*/
|
||||
public override fun add(a: N, b: N): N = combine(a, b) { aValue, bValue -> add(aValue, bValue) }
|
||||
|
||||
/**
|
||||
* Element-wise multiplication by scalar.
|
||||
*
|
||||
* @param a the multiplicand.
|
||||
* @param k the multiplier.
|
||||
* @return the product.
|
||||
*/
|
||||
public override fun multiply(a: N, k: Number): N = map(a) { multiply(it, k) }
|
||||
|
||||
// TODO move to extensions after KEEP-176
|
||||
|
||||
/**
|
||||
* Adds an ND structure to an element of it.
|
||||
*
|
||||
* @receiver the addend.
|
||||
* @param arg the augend.
|
||||
* @return the sum.
|
||||
*/
|
||||
public operator fun N.plus(arg: T): N = map(this) { value -> add(arg, value) }
|
||||
|
||||
/**
|
||||
* Subtracts an element from ND structure of it.
|
||||
*
|
||||
* @receiver the dividend.
|
||||
* @param arg the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public operator fun N.minus(arg: T): N = map(this) { value -> add(arg, -value) }
|
||||
|
||||
/**
|
||||
* Adds an element to ND structure of it.
|
||||
*
|
||||
* @receiver the addend.
|
||||
* @param arg the augend.
|
||||
* @return the sum.
|
||||
*/
|
||||
public operator fun T.plus(arg: N): N = map(arg) { value -> add(this@plus, value) }
|
||||
|
||||
/**
|
||||
* Subtracts an ND structure from an element of it.
|
||||
*
|
||||
* @receiver the dividend.
|
||||
* @param arg the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public operator fun T.minus(arg: N): N = map(arg) { value -> add(-this@minus, value) }
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* Ring of [NDStructure].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param R the type of ring of structure elements.
|
||||
*/
|
||||
public interface NDRing<T, R : Ring<T>, N : NDStructure<T>> : Ring<N>, NDSpace<T, R, N> {
|
||||
/**
|
||||
* Element-wise multiplication.
|
||||
*
|
||||
* @param a the multiplicand.
|
||||
* @param b the multiplier.
|
||||
* @return the product.
|
||||
*/
|
||||
public override fun multiply(a: N, b: N): N = combine(a, b) { aValue, bValue -> multiply(aValue, bValue) }
|
||||
|
||||
//TODO move to extensions after KEEP-176
|
||||
|
||||
/**
|
||||
* Multiplies an ND structure by an element of it.
|
||||
*
|
||||
* @receiver the multiplicand.
|
||||
* @param arg the multiplier.
|
||||
* @return the product.
|
||||
*/
|
||||
public operator fun N.times(arg: T): N = map(this) { value -> multiply(arg, value) }
|
||||
|
||||
/**
|
||||
* Multiplies an element by a ND structure of it.
|
||||
*
|
||||
* @receiver the multiplicand.
|
||||
* @param arg the multiplier.
|
||||
* @return the product.
|
||||
*/
|
||||
public operator fun T.times(arg: N): N = map(arg) { value -> multiply(this@times, value) }
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* Field of [NDStructure].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param F the type field of structure elements.
|
||||
*/
|
||||
public interface NDField<T, F : Field<T>, N : NDStructure<T>> : Field<N>, NDRing<T, F, N> {
|
||||
/**
|
||||
* Element-wise division.
|
||||
*
|
||||
* @param a the dividend.
|
||||
* @param b the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public override fun divide(a: N, b: N): N = combine(a, b) { aValue, bValue -> divide(aValue, bValue) }
|
||||
|
||||
//TODO move to extensions after KEEP-176
|
||||
/**
|
||||
* Divides an ND structure by an element of it.
|
||||
*
|
||||
* @receiver the dividend.
|
||||
* @param arg the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public operator fun N.div(arg: T): N = map(this) { value -> divide(arg, value) }
|
||||
|
||||
/**
|
||||
* Divides an element by an ND structure of it.
|
||||
*
|
||||
* @receiver the dividend.
|
||||
* @param arg the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public operator fun T.div(arg: N): N = map(arg) { divide(it, this@div) }
|
||||
|
||||
@ThreadLocal
|
||||
public companion object {
|
||||
private val realNDFieldCache: MutableMap<IntArray, RealNDField> = hashMapOf()
|
||||
|
||||
/**
|
||||
* Create a nd-field for [Double] values or pull it from cache if it was created previously.
|
||||
*/
|
||||
public fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) }
|
||||
|
||||
/**
|
||||
* Create an ND field with boxing generic buffer.
|
||||
*/
|
||||
public fun <T : Any, F : Field<T>> boxing(
|
||||
field: F,
|
||||
vararg shape: Int,
|
||||
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing
|
||||
): BoxingNDField<T, F> = BoxingNDField(shape, field, bufferFactory)
|
||||
|
||||
/**
|
||||
* Create a most suitable implementation for nd-field using reified class.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public inline fun <reified T : Any, F : Field<T>> auto(field: F, vararg shape: Int): BufferedNDField<T, F> =
|
||||
when {
|
||||
T::class == Double::class -> real(*shape) as BufferedNDField<T, F>
|
||||
T::class == Complex::class -> complex(*shape) as BufferedNDField<T, F>
|
||||
else -> BoxingNDField(shape, field, Buffer.Companion::auto)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.operations.Field
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.Ring
|
||||
import kscience.kmath.operations.Space
|
||||
|
||||
/**
|
||||
* The root for all [NDStructure] based algebra elements. Does not implement algebra element root because of problems with recursive self-types
|
||||
* @param T the type of the element of the structure
|
||||
* @param C the type of the context for the element
|
||||
* @param N the type of the underlying [NDStructure]
|
||||
*/
|
||||
public interface NDElement<T, C, N : NDStructure<T>> : NDStructure<T> {
|
||||
public val context: NDAlgebra<T, C, N>
|
||||
|
||||
public fun unwrap(): N
|
||||
|
||||
public fun N.wrap(): NDElement<T, C, N>
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* Create a optimized NDArray of doubles
|
||||
*/
|
||||
public fun real(shape: IntArray, initializer: RealField.(IntArray) -> Double = { 0.0 }): RealNDElement =
|
||||
NDField.real(*shape).produce(initializer)
|
||||
|
||||
public inline fun real1D(dim: Int, crossinline initializer: (Int) -> Double = { _ -> 0.0 }): RealNDElement =
|
||||
real(intArrayOf(dim)) { initializer(it[0]) }
|
||||
|
||||
public inline fun real2D(
|
||||
dim1: Int,
|
||||
dim2: Int,
|
||||
crossinline initializer: (Int, Int) -> Double = { _, _ -> 0.0 }
|
||||
): RealNDElement = real(intArrayOf(dim1, dim2)) { initializer(it[0], it[1]) }
|
||||
|
||||
public inline fun real3D(
|
||||
dim1: Int,
|
||||
dim2: Int,
|
||||
dim3: Int,
|
||||
crossinline initializer: (Int, Int, Int) -> Double = { _, _, _ -> 0.0 }
|
||||
): RealNDElement = real(intArrayOf(dim1, dim2, dim3)) { initializer(it[0], it[1], it[2]) }
|
||||
|
||||
|
||||
/**
|
||||
* Simple boxing NDArray
|
||||
*/
|
||||
public fun <T : Any, F : Field<T>> boxing(
|
||||
shape: IntArray,
|
||||
field: F,
|
||||
initializer: F.(IntArray) -> T
|
||||
): BufferedNDElement<T, F> {
|
||||
val ndField = BoxingNDField(shape, field, Buffer.Companion::boxing)
|
||||
return ndField.produce(initializer)
|
||||
}
|
||||
|
||||
public inline fun <reified T : Any, F : Field<T>> auto(
|
||||
shape: IntArray,
|
||||
field: F,
|
||||
noinline initializer: F.(IntArray) -> T
|
||||
): BufferedNDFieldElement<T, F> {
|
||||
val ndField = NDField.auto(field, *shape)
|
||||
return BufferedNDFieldElement(ndField, ndField.produce(initializer).buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun <T, C, N : NDStructure<T>> NDElement<T, C, N>.mapIndexed(transform: C.(index: IntArray, T) -> T): NDElement<T, C, N> =
|
||||
context.mapIndexed(unwrap(), transform).wrap()
|
||||
|
||||
public fun <T, C, N : NDStructure<T>> NDElement<T, C, N>.map(transform: C.(T) -> T): NDElement<T, C, N> =
|
||||
context.map(unwrap(), transform).wrap()
|
||||
|
||||
/**
|
||||
* Element by element application of any operation on elements to the whole [NDElement]
|
||||
*/
|
||||
public operator fun <T, C, N : NDStructure<T>> Function1<T, T>.invoke(ndElement: NDElement<T, C, N>): NDElement<T, C, N> =
|
||||
ndElement.map { value -> this@invoke(value) }
|
||||
|
||||
/* plus and minus */
|
||||
|
||||
/**
|
||||
* Summation operation for [NDElement] and single element
|
||||
*/
|
||||
public operator fun <T, S : Space<T>, N : NDStructure<T>> NDElement<T, S, N>.plus(arg: T): NDElement<T, S, N> =
|
||||
map { value -> arg + value }
|
||||
|
||||
/**
|
||||
* Subtraction operation between [NDElement] and single element
|
||||
*/
|
||||
public operator fun <T, S : Space<T>, N : NDStructure<T>> NDElement<T, S, N>.minus(arg: T): NDElement<T, S, N> =
|
||||
map { value -> arg - value }
|
||||
|
||||
/* prod and div */
|
||||
|
||||
/**
|
||||
* Product operation for [NDElement] and single element
|
||||
*/
|
||||
public operator fun <T, R : Ring<T>, N : NDStructure<T>> NDElement<T, R, N>.times(arg: T): NDElement<T, R, N> =
|
||||
map { value -> arg * value }
|
||||
|
||||
/**
|
||||
* Division operation between [NDElement] and single element
|
||||
*/
|
||||
public operator fun <T, F : Field<T>, N : NDStructure<T>> NDElement<T, F, N>.div(arg: T): NDElement<T, F, N> =
|
||||
map { value -> arg / value }
|
||||
|
||||
// /**
|
||||
// * Reverse sum operation
|
||||
// */
|
||||
// operator fun T.plus(arg: NDStructure<T>): NDElement<T, F> = produce { index ->
|
||||
// field.run { this@plus + arg[index] }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Reverse minus operation
|
||||
// */
|
||||
// operator fun T.minus(arg: NDStructure<T>): NDElement<T, F> = produce { index ->
|
||||
// field.run { this@minus - arg[index] }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Reverse product operation
|
||||
// */
|
||||
// operator fun T.times(arg: NDStructure<T>): NDElement<T, F> = produce { index ->
|
||||
// field.run { this@times * arg[index] }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Reverse division operation
|
||||
// */
|
||||
// operator fun T.div(arg: NDStructure<T>): NDElement<T, F> = produce { index ->
|
||||
// field.run { this@div / arg[index] }
|
||||
// }
|
@ -1,140 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.operations.FieldElement
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.operations.RingWithNumbers
|
||||
|
||||
public typealias RealNDElement = BufferedNDFieldElement<Double, RealField>
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class RealNDField(override val shape: IntArray) :
|
||||
BufferedNDField<Double, RealField>,
|
||||
ExtendedNDField<Double, RealField, NDBuffer<Double>>,
|
||||
RingWithNumbers<NDBuffer<Double>> {
|
||||
|
||||
override val strides: Strides = DefaultStrides(shape)
|
||||
|
||||
override val elementContext: RealField get() = RealField
|
||||
override val zero: RealNDElement by lazy { produce { zero } }
|
||||
override val one: RealNDElement by lazy { produce { one } }
|
||||
|
||||
override fun number(value: Number): NDBuffer<Double> {
|
||||
val d = value.toDouble()
|
||||
return produce { d }
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
override inline fun map(
|
||||
arg: NDBuffer<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: NDBuffer<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: NDBuffer<Double>,
|
||||
b: NDBuffer<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 NDBuffer<Double>.toElement(): FieldElement<NDBuffer<Double>, *, out BufferedNDField<Double, RealField>> =
|
||||
BufferedNDFieldElement(this@RealNDField, buffer)
|
||||
|
||||
override fun power(arg: NDBuffer<Double>, pow: Number): RealNDElement = map(arg) { power(it, pow) }
|
||||
|
||||
override fun exp(arg: NDBuffer<Double>): RealNDElement = map(arg) { exp(it) }
|
||||
|
||||
override fun ln(arg: NDBuffer<Double>): RealNDElement = map(arg) { ln(it) }
|
||||
|
||||
override fun sin(arg: NDBuffer<Double>): RealNDElement = map(arg) { sin(it) }
|
||||
override fun cos(arg: NDBuffer<Double>): RealNDElement = map(arg) { cos(it) }
|
||||
override fun tan(arg: NDBuffer<Double>): RealNDElement = map(arg) { tan(it) }
|
||||
override fun asin(arg: NDBuffer<Double>): RealNDElement = map(arg) { asin(it) }
|
||||
override fun acos(arg: NDBuffer<Double>): RealNDElement = map(arg) { acos(it) }
|
||||
override fun atan(arg: NDBuffer<Double>): RealNDElement = map(arg) { atan(it) }
|
||||
|
||||
override fun sinh(arg: NDBuffer<Double>): RealNDElement = map(arg) { sinh(it) }
|
||||
override fun cosh(arg: NDBuffer<Double>): RealNDElement = map(arg) { cosh(it) }
|
||||
override fun tanh(arg: NDBuffer<Double>): RealNDElement = map(arg) { tanh(it) }
|
||||
override fun asinh(arg: NDBuffer<Double>): RealNDElement = map(arg) { asinh(it) }
|
||||
override fun acosh(arg: NDBuffer<Double>): RealNDElement = map(arg) { acosh(it) }
|
||||
override fun atanh(arg: NDBuffer<Double>): RealNDElement = map(arg) { atanh(it) }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fast element production using function inlining
|
||||
*/
|
||||
public inline fun BufferedNDField<Double, RealField>.produceInline(crossinline initializer: RealField.(Int) -> Double): RealNDElement {
|
||||
val array = DoubleArray(strides.linearSize) { offset -> RealField.initializer(offset) }
|
||||
return BufferedNDFieldElement(this, RealBuffer(array))
|
||||
}
|
||||
|
||||
/**
|
||||
* Map one [RealNDElement] using function with indices.
|
||||
*/
|
||||
public inline fun RealNDElement.mapIndexed(crossinline transform: RealField.(index: IntArray, Double) -> Double): RealNDElement =
|
||||
context.produceInline { offset -> transform(strides.index(offset), buffer[offset]) }
|
||||
|
||||
/**
|
||||
* Map one [RealNDElement] using function without indices.
|
||||
*/
|
||||
public inline fun RealNDElement.map(crossinline transform: RealField.(Double) -> Double): RealNDElement {
|
||||
val array = DoubleArray(strides.linearSize) { offset -> RealField.transform(buffer[offset]) }
|
||||
return BufferedNDFieldElement(context, RealBuffer(array))
|
||||
}
|
||||
|
||||
/**
|
||||
* Element by element application of any operation on elements to the whole array. Just like in numpy.
|
||||
*/
|
||||
public operator fun Function1<Double, Double>.invoke(ndElement: RealNDElement): RealNDElement =
|
||||
ndElement.map { this@invoke(it) }
|
||||
|
||||
/* plus and minus */
|
||||
|
||||
/**
|
||||
* Summation operation for [BufferedNDElement] and single element
|
||||
*/
|
||||
public operator fun RealNDElement.plus(arg: Double): RealNDElement = map { it + arg }
|
||||
|
||||
/**
|
||||
* Subtraction operation between [BufferedNDElement] and single element
|
||||
*/
|
||||
public operator fun RealNDElement.minus(arg: Double): RealNDElement = map { it - arg }
|
||||
|
||||
/**
|
||||
* Produce a context for n-dimensional operations inside this real field
|
||||
*/
|
||||
public inline fun <R> RealField.nd(vararg shape: Int, action: RealNDField.() -> R): R = NDField.real(*shape).run(action)
|
@ -1,93 +0,0 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.operations.RingElement
|
||||
import kscience.kmath.operations.ShortRing
|
||||
|
||||
public typealias ShortNDElement = BufferedNDRingElement<Short, ShortRing>
|
||||
|
||||
public class ShortNDRing(override val shape: IntArray) :
|
||||
BufferedNDRing<Short, ShortRing> {
|
||||
|
||||
override val strides: Strides = DefaultStrides(shape)
|
||||
override val elementContext: ShortRing get() = ShortRing
|
||||
override val zero: ShortNDElement by lazy { produce { zero } }
|
||||
override val one: ShortNDElement by lazy { produce { one } }
|
||||
|
||||
public inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Short): Buffer<Short> =
|
||||
ShortBuffer(ShortArray(size) { initializer(it) })
|
||||
|
||||
/**
|
||||
* Inline transform an NDStructure to
|
||||
*/
|
||||
override fun map(
|
||||
arg: NDBuffer<Short>,
|
||||
transform: ShortRing.(Short) -> Short
|
||||
): ShortNDElement {
|
||||
check(arg)
|
||||
val array = buildBuffer(arg.strides.linearSize) { offset -> ShortRing.transform(arg.buffer[offset]) }
|
||||
return BufferedNDRingElement(this, array)
|
||||
}
|
||||
|
||||
override fun produce(initializer: ShortRing.(IntArray) -> Short): ShortNDElement {
|
||||
val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
||||
return BufferedNDRingElement(this, array)
|
||||
}
|
||||
|
||||
override fun mapIndexed(
|
||||
arg: NDBuffer<Short>,
|
||||
transform: ShortRing.(index: IntArray, Short) -> Short
|
||||
): ShortNDElement {
|
||||
check(arg)
|
||||
|
||||
return BufferedNDRingElement(
|
||||
this,
|
||||
buildBuffer(arg.strides.linearSize) { offset ->
|
||||
elementContext.transform(
|
||||
arg.strides.index(offset),
|
||||
arg.buffer[offset]
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
override fun combine(
|
||||
a: NDBuffer<Short>,
|
||||
b: NDBuffer<Short>,
|
||||
transform: ShortRing.(Short, Short) -> Short
|
||||
): ShortNDElement {
|
||||
check(a, b)
|
||||
return BufferedNDRingElement(
|
||||
this,
|
||||
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
|
||||
}
|
||||
|
||||
override fun NDBuffer<Short>.toElement(): RingElement<NDBuffer<Short>, *, out BufferedNDRing<Short, ShortRing>> =
|
||||
BufferedNDRingElement(this@ShortNDRing, buffer)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fast element production using function inlining.
|
||||
*/
|
||||
public inline fun BufferedNDRing<Short, ShortRing>.produceInline(crossinline initializer: ShortRing.(Int) -> Short): ShortNDElement =
|
||||
BufferedNDRingElement(this, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) }))
|
||||
|
||||
/**
|
||||
* Element by element application of any operation on elements to the whole array.
|
||||
*/
|
||||
public operator fun Function1<Short, Short>.invoke(ndElement: ShortNDElement): ShortNDElement =
|
||||
ndElement.context.produceInline { i -> invoke(ndElement.buffer[i]) }
|
||||
|
||||
|
||||
/* plus and minus */
|
||||
|
||||
/**
|
||||
* Summation operation for [ShortNDElement] and single element.
|
||||
*/
|
||||
public operator fun ShortNDElement.plus(arg: Short): ShortNDElement =
|
||||
context.produceInline { i -> (buffer[i] + arg).toShort() }
|
||||
|
||||
/**
|
||||
* Subtraction operation between [ShortNDElement] and single element.
|
||||
*/
|
||||
public operator fun ShortNDElement.minus(arg: Short): ShortNDElement =
|
||||
context.produceInline { i -> (buffer[i] - arg).toShort() }
|
@ -1,9 +1,8 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.nd.NDStructure
|
||||
import kscience.kmath.nd.as2D
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.NDStructure
|
||||
import kscience.kmath.structures.as2D
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package kscience.kmath.linear
|
||||
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -9,7 +8,7 @@ class RealLUSolverTest {
|
||||
@Test
|
||||
fun testInvertOne() {
|
||||
val matrix = MatrixContext.real.one(2, 2)
|
||||
val inverted = MatrixContext.real.inverseWithLUP(matrix)
|
||||
val inverted = MatrixContext.real.inverseWithLup(matrix)
|
||||
assertEquals(matrix, inverted)
|
||||
}
|
||||
|
||||
@ -37,7 +36,7 @@ class RealLUSolverTest {
|
||||
1.0, 3.0
|
||||
)
|
||||
|
||||
val inverted = MatrixContext.real.inverseWithLUP(matrix)
|
||||
val inverted = MatrixContext.real.inverseWithLup(matrix)
|
||||
|
||||
val expected = Matrix.square(
|
||||
0.375, -0.125,
|
||||
|
@ -1,5 +1,8 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.nd.NDAlgebra
|
||||
import kscience.kmath.nd.get
|
||||
import kscience.kmath.nd.real
|
||||
import kscience.kmath.operations.internal.FieldVerifier
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
@ -7,12 +10,12 @@ import kotlin.test.assertEquals
|
||||
internal class NDFieldTest {
|
||||
@Test
|
||||
fun verify() {
|
||||
NDField.real(12, 32).run { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) }
|
||||
NDAlgebra.real(12, 32).run { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testStrides() {
|
||||
val ndArray = NDElement.real(intArrayOf(10, 10)) { (it[0] + it[1]).toDouble() }
|
||||
val ndArray = NDAlgebra.real(10, 10).produce { (it[0] + it[1]).toDouble() }
|
||||
assertEquals(ndArray[5, 5], 10.0)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package kscience.kmath.structures
|
||||
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.Norm
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.structures.NDElement.Companion.real2D
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
import kotlin.test.Test
|
||||
@ -10,25 +10,30 @@ import kotlin.test.assertEquals
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
class NumberNDFieldTest {
|
||||
val array1: RealNDElement = real2D(3, 3) { i, j -> (i + j).toDouble() }
|
||||
val array2: RealNDElement = real2D(3, 3) { i, j -> (i - j).toDouble() }
|
||||
val algebra = NDAlgebra.real(3,3)
|
||||
val array1 = algebra.produce { (i, j) -> (i + j).toDouble() }
|
||||
val array2 = algebra.produce { (i, j) -> (i - j).toDouble() }
|
||||
|
||||
@Test
|
||||
fun testSum() {
|
||||
val sum = array1 + array2
|
||||
assertEquals(4.0, sum[2, 2])
|
||||
algebra {
|
||||
val sum = array1 + array2
|
||||
assertEquals(4.0, sum[2, 2])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProduct() {
|
||||
val product = array1 * array2
|
||||
assertEquals(0.0, product[2, 2])
|
||||
algebra {
|
||||
val product = array1 * array2
|
||||
assertEquals(0.0, product[2, 2])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGeneration() {
|
||||
|
||||
val array = real2D(3, 3) { i, j -> (i * 10 + j).toDouble() }
|
||||
val array = Structure2D.real(3, 3) { i, j -> (i * 10 + j).toDouble() }
|
||||
|
||||
for (i in 0..2)
|
||||
for (j in 0..2) {
|
||||
@ -39,16 +44,20 @@ class NumberNDFieldTest {
|
||||
|
||||
@Test
|
||||
fun testExternalFunction() {
|
||||
val function: (Double) -> Double = { x -> x.pow(2) + 2 * x + 1 }
|
||||
val result = function(array1) + 1.0
|
||||
assertEquals(10.0, result[1, 1])
|
||||
algebra {
|
||||
val function: (Double) -> Double = { x -> x.pow(2) + 2 * x + 1 }
|
||||
val result = function(array1) + 1.0
|
||||
assertEquals(10.0, result[1, 1])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLibraryFunction() {
|
||||
val abs: (Double) -> Double = ::abs
|
||||
val result = abs(array2)
|
||||
assertEquals(2.0, result[0, 2])
|
||||
algebra {
|
||||
val abs: (Double) -> Double = ::abs
|
||||
val result = abs(array2)
|
||||
assertEquals(2.0, result[0, 2])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -63,6 +72,8 @@ class NumberNDFieldTest {
|
||||
|
||||
@Test
|
||||
fun testInternalContext() {
|
||||
(NDField.real(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } }
|
||||
algebra {
|
||||
(NDAlgebra.real(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,3 +16,7 @@ kotlin.sourceSets {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readme{
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
}
|
@ -2,6 +2,8 @@ package kscience.kmath.structures
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kscience.kmath.coroutines.Math
|
||||
import kscience.kmath.nd.DefaultStrides
|
||||
import kscience.kmath.nd.NDStructure
|
||||
|
||||
public class LazyNDStructure<T>(
|
||||
public val scope: CoroutineScope,
|
||||
|
@ -1,9 +1,8 @@
|
||||
package kscience.kmath.dimensions
|
||||
|
||||
import kscience.kmath.linear.*
|
||||
import kscience.kmath.nd.Structure2D
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.Structure2D
|
||||
|
||||
/**
|
||||
* A matrix with compile-time controlled dimension
|
||||
|
@ -6,3 +6,7 @@ dependencies {
|
||||
implementation("org.ejml:ejml-simple:0.39")
|
||||
implementation(project(":kmath-core"))
|
||||
}
|
||||
|
||||
readme{
|
||||
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
|
||||
}
|
@ -2,8 +2,7 @@ package kscience.kmath.ejml
|
||||
|
||||
import kscience.kmath.linear.*
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.NDStructure
|
||||
import kscience.kmath.nd.NDStructure
|
||||
import kscience.kmath.structures.RealBuffer
|
||||
import org.ejml.dense.row.factory.DecompositionFactory_DDRM
|
||||
import org.ejml.simple.SimpleMatrix
|
||||
@ -16,21 +15,20 @@ import kotlin.reflect.cast
|
||||
* @property origin the underlying [SimpleMatrix].
|
||||
* @author Iaroslav Postovalov
|
||||
*/
|
||||
public class EjmlMatrix(
|
||||
public val origin: SimpleMatrix,
|
||||
) : Matrix<Double> {
|
||||
public class EjmlMatrix(public val origin: SimpleMatrix) : Matrix<Double> {
|
||||
public override val rowNum: Int get() = origin.numRows()
|
||||
|
||||
public override val colNum: Int get() = origin.numCols()
|
||||
|
||||
@UnstableKMathAPI
|
||||
override fun <T : Any> getFeature(type: KClass<T>): T? = when (type) {
|
||||
public override fun <T : Any> getFeature(type: KClass<T>): T? = when (type) {
|
||||
InverseMatrixFeature::class -> object : InverseMatrixFeature<Double> {
|
||||
override val inverse: Matrix<Double> by lazy { EjmlMatrix(origin.invert()) }
|
||||
}
|
||||
|
||||
DeterminantFeature::class -> object : DeterminantFeature<Double> {
|
||||
override val determinant: Double by lazy(origin::determinant)
|
||||
}
|
||||
|
||||
SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Double> {
|
||||
private val svd by lazy {
|
||||
DecompositionFactory_DDRM.svd(origin.numRows(), origin.numCols(), true, true, false)
|
||||
@ -42,14 +40,19 @@ public class EjmlMatrix(
|
||||
override val v: Matrix<Double> by lazy { EjmlMatrix(SimpleMatrix(svd.getV(null, false))) }
|
||||
override val singularValues: Point<Double> by lazy { RealBuffer(svd.singularValues) }
|
||||
}
|
||||
|
||||
QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> {
|
||||
private val qr by lazy {
|
||||
DecompositionFactory_DDRM.qr().apply { decompose(origin.ddrm.copy()) }
|
||||
}
|
||||
|
||||
override val q: Matrix<Double> by lazy { EjmlMatrix(SimpleMatrix(qr.getQ(null, false))) }
|
||||
override val r: Matrix<Double> by lazy { EjmlMatrix(SimpleMatrix(qr.getR(null, false))) }
|
||||
override val q: Matrix<Double> by lazy {
|
||||
EjmlMatrix(SimpleMatrix(qr.getQ(null, false))) + OrthogonalFeature
|
||||
}
|
||||
|
||||
override val r: Matrix<Double> by lazy { EjmlMatrix(SimpleMatrix(qr.getR(null, false))) + UFeature }
|
||||
}
|
||||
|
||||
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
|
||||
override val l: Matrix<Double> by lazy {
|
||||
val cholesky =
|
||||
@ -58,6 +61,7 @@ public class EjmlMatrix(
|
||||
EjmlMatrix(SimpleMatrix(cholesky.getT(null))) + LFeature
|
||||
}
|
||||
}
|
||||
|
||||
LupDecompositionFeature::class -> object : LupDecompositionFeature<Double> {
|
||||
private val lup by lazy {
|
||||
DecompositionFactory_DDRM.lu(origin.numRows(), origin.numCols()).apply { decompose(origin.ddrm.copy()) }
|
||||
@ -73,8 +77,9 @@ public class EjmlMatrix(
|
||||
|
||||
override val p: Matrix<Double> by lazy { EjmlMatrix(SimpleMatrix(lup.getRowPivot(null))) }
|
||||
}
|
||||
|
||||
else -> null
|
||||
}?.let { type.cast(it) }
|
||||
}?.let(type::cast)
|
||||
|
||||
public override operator fun get(i: Int, j: Int): Double = origin[i, j]
|
||||
|
||||
|
@ -1,12 +1,8 @@
|
||||
package kscience.kmath.ejml
|
||||
|
||||
import kscience.kmath.linear.InverseMatrixFeature
|
||||
import kscience.kmath.linear.MatrixContext
|
||||
import kscience.kmath.linear.Point
|
||||
import kscience.kmath.linear.origin
|
||||
import kscience.kmath.linear.*
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.getFeature
|
||||
import kscience.kmath.nd.getFeature
|
||||
import org.ejml.simple.SimpleMatrix
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,7 @@ import kscience.kmath.linear.LupDecompositionFeature
|
||||
import kscience.kmath.linear.MatrixFeature
|
||||
import kscience.kmath.linear.plus
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.structures.getFeature
|
||||
import kscience.kmath.nd.getFeature
|
||||
import org.ejml.dense.row.factory.DecompositionFactory_DDRM
|
||||
import org.ejml.simple.SimpleMatrix
|
||||
import kotlin.random.Random
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `kscience.kmath:kmath-for-real:0.2.0-dev-4`.
|
||||
> This module artifact: `kscience.kmath:kmath-for-real:0.2.0-dev-6`.
|
||||
>
|
||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-for-real/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-for-real/_latestVersion)
|
||||
>
|
||||
@ -25,7 +25,7 @@
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'kscience.kmath:kmath-for-real:0.2.0-dev-4'
|
||||
> implementation 'kscience.kmath:kmath-for-real:0.2.0-dev-6'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
@ -39,6 +39,6 @@
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("kscience.kmath:kmath-for-real:0.2.0-dev-4")
|
||||
> implementation("kscience.kmath:kmath-for-real:0.2.0-dev-6")
|
||||
> }
|
||||
> ```
|
||||
|
@ -1,12 +1,8 @@
|
||||
package kscience.kmath.real
|
||||
|
||||
import kscience.kmath.linear.MatrixContext
|
||||
import kscience.kmath.linear.VirtualMatrix
|
||||
import kscience.kmath.linear.inverseWithLUP
|
||||
import kscience.kmath.linear.real
|
||||
import kscience.kmath.linear.*
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.RealBuffer
|
||||
import kscience.kmath.structures.asIterable
|
||||
import kotlin.math.pow
|
||||
@ -144,7 +140,7 @@ public fun RealMatrix.min(): Double? = elements().map { (_, value) -> value }.mi
|
||||
public fun RealMatrix.max(): Double? = elements().map { (_, value) -> value }.maxOrNull()
|
||||
public fun RealMatrix.average(): Double = elements().map { (_, value) -> value }.average()
|
||||
|
||||
public inline fun RealMatrix.map(transform: (Double) -> Double): RealMatrix =
|
||||
public inline fun RealMatrix.map(crossinline transform: (Double) -> Double): RealMatrix =
|
||||
MatrixContext.real.produce(rowNum, colNum) { i, j ->
|
||||
transform(get(i, j))
|
||||
}
|
||||
@ -152,7 +148,7 @@ public inline fun RealMatrix.map(transform: (Double) -> Double): RealMatrix =
|
||||
/**
|
||||
* Inverse a square real matrix using LUP decomposition
|
||||
*/
|
||||
public fun RealMatrix.inverseWithLUP(): RealMatrix = MatrixContext.real.inverseWithLUP(this)
|
||||
public fun RealMatrix.inverseWithLup(): RealMatrix = MatrixContext.real.inverseWithLup(this)
|
||||
|
||||
//extended operations
|
||||
|
||||
|
@ -29,8 +29,10 @@ public inline fun RealVector.map(transform: (Double) -> Double): RealVector =
|
||||
public inline fun RealVector.mapIndexed(transform: (index: Int, value: Double) -> Double): RealVector =
|
||||
Buffer.real(size) { transform(it, get(it)) }
|
||||
|
||||
public operator fun RealVector.plus(other: RealVector): RealVector =
|
||||
mapIndexed { index, value -> value + other[index] }
|
||||
public operator fun RealVector.plus(other: RealVector): RealVector {
|
||||
require(size == other.size){"Vector size $size expected but ${other.size} found"}
|
||||
return mapIndexed { index, value -> value + other[index] }
|
||||
}
|
||||
|
||||
public operator fun RealVector.plus(number: Number): RealVector = map { it + number.toDouble() }
|
||||
|
||||
@ -38,22 +40,28 @@ public operator fun Number.plus(vector: RealVector): RealVector = vector + this
|
||||
|
||||
public operator fun RealVector.unaryMinus(): Buffer<Double> = map { -it }
|
||||
|
||||
public operator fun RealVector.minus(other: RealVector): RealVector =
|
||||
mapIndexed { index, value -> value - other[index] }
|
||||
public operator fun RealVector.minus(other: RealVector): RealVector {
|
||||
require(size == other.size){"Vector size $size expected but ${other.size} found"}
|
||||
return mapIndexed { index, value -> value - other[index] }
|
||||
}
|
||||
|
||||
public operator fun RealVector.minus(number: Number): RealVector = map { it - number.toDouble() }
|
||||
|
||||
public operator fun Number.minus(vector: RealVector): RealVector = vector.map { toDouble() - it }
|
||||
|
||||
public operator fun RealVector.times(other: RealVector): RealVector =
|
||||
mapIndexed { index, value -> value * other[index] }
|
||||
public operator fun RealVector.times(other: RealVector): RealVector {
|
||||
require(size == other.size){"Vector size $size expected but ${other.size} found"}
|
||||
return mapIndexed { index, value -> value * other[index] }
|
||||
}
|
||||
|
||||
public operator fun RealVector.times(number: Number): RealVector = map { it * number.toDouble() }
|
||||
|
||||
public operator fun Number.times(vector: RealVector): RealVector = vector * this
|
||||
|
||||
public operator fun RealVector.div(other: RealVector): RealVector =
|
||||
mapIndexed { index, value -> value / other[index] }
|
||||
public operator fun RealVector.div(other: RealVector): RealVector {
|
||||
require(size == other.size){"Vector size $size expected but ${other.size} found"}
|
||||
return mapIndexed { index, value -> value / other[index] }
|
||||
}
|
||||
|
||||
public operator fun RealVector.div(number: Number): RealVector = map { it / number.toDouble() }
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
package kscience.kmath.real
|
||||
|
||||
import kscience.kmath.nd.NDBuffer
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.structures.RealBuffer
|
||||
|
||||
/**
|
||||
* Map one [NDBuffer] using function without indices.
|
||||
*/
|
||||
public inline fun NDBuffer<Double>.mapInline(crossinline transform: RealField.(Double) -> Double): NDBuffer<Double> {
|
||||
val array = DoubleArray(strides.linearSize) { offset -> RealField.transform(buffer[offset]) }
|
||||
return NDBuffer(strides, RealBuffer(array))
|
||||
}
|
||||
|
||||
/**
|
||||
* Element by element application of any operation on elements to the whole array. Just like in numpy.
|
||||
*/
|
||||
public operator fun Function1<Double, Double>.invoke(ndElement: NDBuffer<Double>): NDBuffer<Double> =
|
||||
ndElement.mapInline { this@invoke(it) }
|
||||
|
||||
/* plus and minus */
|
||||
|
||||
/**
|
||||
* Summation operation for [NDBuffer] and single element
|
||||
*/
|
||||
public operator fun NDBuffer<Double>.plus(arg: Double): NDBuffer<Double> = mapInline { it + arg }
|
||||
|
||||
/**
|
||||
* Subtraction operation between [NDBuffer] and single element
|
||||
*/
|
||||
public operator fun NDBuffer<Double>.minus(arg: Double): NDBuffer<Double> = mapInline { it - arg }
|
@ -1,8 +1,8 @@
|
||||
package kaceince.kmath.real
|
||||
|
||||
import kscience.kmath.linear.Matrix
|
||||
import kscience.kmath.linear.build
|
||||
import kscience.kmath.real.*
|
||||
import kscience.kmath.structures.Matrix
|
||||
import kscience.kmath.structures.contentEquals
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
47
kmath-functions/README.md
Normal file
47
kmath-functions/README.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Functions (`kmath-functions`)
|
||||
|
||||
Functions and interpolations:
|
||||
|
||||
- [piecewise](Piecewise functions.) : src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt
|
||||
- [polynomials](Polynomial functions.) : src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt
|
||||
- [linear interpolation](Linear XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt
|
||||
- [spline interpolation](Cubic spline XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt
|
||||
|
||||
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `kscience.kmath:kmath-functions:0.2.0-dev-6`.
|
||||
>
|
||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-functions/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-functions/_latestVersion)
|
||||
>
|
||||
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-functions/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-functions/_latestVersion)
|
||||
>
|
||||
> **Gradle:**
|
||||
>
|
||||
> ```gradle
|
||||
> repositories {
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
|
||||
> maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
||||
> maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
>
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'kscience.kmath:kmath-functions:0.2.0-dev-6'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
>
|
||||
> ```kotlin
|
||||
> repositories {
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
> maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
> maven("https://dl.bintray.com/mipt-npm/dev")
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven")
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("kscience.kmath:kmath-functions:0.2.0-dev-6")
|
||||
> }
|
||||
> ```
|
@ -7,3 +7,14 @@ kotlin.sourceSets.commonMain {
|
||||
api(project(":kmath-core"))
|
||||
}
|
||||
}
|
||||
|
||||
readme {
|
||||
description = "Functions and interpolation"
|
||||
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
|
||||
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
|
||||
|
||||
feature("piecewise", "src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt", "Piecewise functions.")
|
||||
feature("polynomials", "src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt", "Polynomial functions.")
|
||||
feature("linear interpolation", "src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt", "Linear XY interpolator.")
|
||||
feature("spline interpolation", "src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt", "Cubic spline XY interpolator.")
|
||||
}
|
7
kmath-functions/docs/README-TEMPLATE.md
Normal file
7
kmath-functions/docs/README-TEMPLATE.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Functions (`kmath-functions`)
|
||||
|
||||
Functions and interpolations:
|
||||
|
||||
${features}
|
||||
|
||||
${artifact}
|
@ -6,8 +6,7 @@ public fun interface Piecewise<T, R> {
|
||||
public fun findPiece(arg: T): R?
|
||||
}
|
||||
|
||||
public fun interface PiecewisePolynomial<T : Any> :
|
||||
Piecewise<T, Polynomial<T>>
|
||||
public fun interface PiecewisePolynomial<T : Any> : Piecewise<T, Polynomial<T>>
|
||||
|
||||
/**
|
||||
* Ordered list of pieces in piecewise function
|
||||
|
@ -1,7 +1,7 @@
|
||||
package kscience.kmath.interpolation
|
||||
|
||||
import kscience.kmath.nd.Structure2D
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.Structure2D
|
||||
|
||||
public interface XYPointSet<X, Y> {
|
||||
public val size: Int
|
||||
|
@ -5,3 +5,7 @@ kotlin.sourceSets.commonMain {
|
||||
api(project(":kmath-core"))
|
||||
}
|
||||
}
|
||||
|
||||
readme{
|
||||
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
|
||||
}
|
||||
|
@ -1,8 +1,18 @@
|
||||
plugins { id("ru.mipt.npm.mpp") }
|
||||
|
||||
kotlin.sourceSets.commonMain {
|
||||
dependencies {
|
||||
api(project(":kmath-core"))
|
||||
api(project(":kmath-for-real"))
|
||||
kotlin.sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api(project(":kmath-core"))
|
||||
}
|
||||
}
|
||||
commonTest{
|
||||
dependencies{
|
||||
implementation(project(":kmath-for-real"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readme {
|
||||
this.maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
package kscience.kmath.histogram
|
||||
|
||||
import kscience.kmath.linear.Point
|
||||
import kscience.kmath.nd.DefaultStrides
|
||||
import kscience.kmath.nd.NDStructure
|
||||
import kscience.kmath.operations.SpaceOperations
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.structures.*
|
||||
import kotlin.math.floor
|
||||
|
||||
public data class BinDef<T : Comparable<T>>(
|
||||
public data class BinDefinition<T : Comparable<T>>(
|
||||
public val space: SpaceOperations<Point<T>>,
|
||||
public val center: Point<T>,
|
||||
public val sizes: Point<T>
|
||||
public val sizes: Point<T>,
|
||||
) {
|
||||
public fun contains(vector: Point<out T>): Boolean {
|
||||
require(vector.size == center.size) { "Dimension mismatch for input vector. Expected ${center.size}, but found ${vector.size}" }
|
||||
@ -20,14 +22,17 @@ public data class BinDef<T : Comparable<T>>(
|
||||
}
|
||||
|
||||
|
||||
public class MultivariateBin<T : Comparable<T>>(public val def: BinDef<T>, public override val value: Number) : Bin<T> {
|
||||
public class MultivariateBin<T : Comparable<T>>(
|
||||
public val definition: BinDefinition<T>,
|
||||
public override val value: Number,
|
||||
) : Bin<T> {
|
||||
public override val dimension: Int
|
||||
get() = def.center.size
|
||||
get() = definition.center.size
|
||||
|
||||
public override val center: Point<T>
|
||||
get() = def.center
|
||||
get() = definition.center
|
||||
|
||||
public override operator fun contains(point: Point<T>): Boolean = def.contains(point)
|
||||
public override operator fun contains(point: Point<T>): Boolean = definition.contains(point)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,11 +41,11 @@ public class MultivariateBin<T : Comparable<T>>(public val def: BinDef<T>, publi
|
||||
public class RealHistogram(
|
||||
private val lower: Buffer<Double>,
|
||||
private val upper: Buffer<Double>,
|
||||
private val binNums: IntArray = IntArray(lower.size) { 20 }
|
||||
private val binNums: IntArray = IntArray(lower.size) { 20 },
|
||||
) : MutableHistogram<Double, MultivariateBin<Double>> {
|
||||
private val strides = DefaultStrides(IntArray(binNums.size) { binNums[it] + 2 })
|
||||
private val values: NDStructure<LongCounter> = NDStructure.auto(strides) { LongCounter() }
|
||||
private val weights: NDStructure<DoubleCounter> = NDStructure.auto(strides) { DoubleCounter() }
|
||||
private val counts: NDStructure<LongCounter> = NDStructure.auto(strides) { LongCounter() }
|
||||
private val values: NDStructure<DoubleCounter> = NDStructure.auto(strides) { DoubleCounter() }
|
||||
public override val dimension: Int get() = lower.size
|
||||
private val binSize = RealBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] }
|
||||
|
||||
@ -63,11 +68,11 @@ public class RealHistogram(
|
||||
|
||||
private fun getIndex(point: Buffer<out Double>): IntArray = IntArray(dimension) { getIndex(it, point[it]) }
|
||||
|
||||
private fun getValue(index: IntArray): Long = values[index].sum()
|
||||
private fun getValue(index: IntArray): Long = counts[index].sum()
|
||||
|
||||
public fun getValue(point: Buffer<out Double>): Long = getValue(getIndex(point))
|
||||
|
||||
private fun getDef(index: IntArray): BinDef<Double> {
|
||||
private fun getBinDefinition(index: IntArray): BinDefinition<Double> {
|
||||
val center = index.mapIndexed { axis, i ->
|
||||
when (i) {
|
||||
0 -> Double.NEGATIVE_INFINITY
|
||||
@ -76,14 +81,14 @@ public class RealHistogram(
|
||||
}
|
||||
}.asBuffer()
|
||||
|
||||
return BinDef(RealBufferFieldOperations, center, binSize)
|
||||
return BinDefinition(RealBufferFieldOperations, center, binSize)
|
||||
}
|
||||
|
||||
public fun getDef(point: Buffer<out Double>): BinDef<Double> = getDef(getIndex(point))
|
||||
public fun getBinDefinition(point: Buffer<out Double>): BinDefinition<Double> = getBinDefinition(getIndex(point))
|
||||
|
||||
public override operator fun get(point: Buffer<out Double>): MultivariateBin<Double>? {
|
||||
val index = getIndex(point)
|
||||
return MultivariateBin(getDef(index), getValue(index))
|
||||
return MultivariateBin(getBinDefinition(index), getValue(index))
|
||||
}
|
||||
|
||||
// fun put(point: Point<out Double>){
|
||||
@ -93,23 +98,24 @@ public class RealHistogram(
|
||||
|
||||
public override fun putWithWeight(point: Buffer<out Double>, weight: Double) {
|
||||
val index = getIndex(point)
|
||||
values[index].increment()
|
||||
weights[index].add(weight)
|
||||
counts[index].increment()
|
||||
values[index].add(weight)
|
||||
}
|
||||
|
||||
public override operator fun iterator(): Iterator<MultivariateBin<Double>> =
|
||||
weights.elements().map { (index, value) -> MultivariateBin(getDef(index), value.sum()) }
|
||||
.iterator()
|
||||
values.elements().map { (index, value) ->
|
||||
MultivariateBin(getBinDefinition(index), value.sum())
|
||||
}.iterator()
|
||||
|
||||
/**
|
||||
* Convert this histogram into NDStructure containing bin values but not bin descriptions
|
||||
* NDStructure containing number of events in bins without weights
|
||||
*/
|
||||
public fun values(): NDStructure<Number> = NDStructure.auto(values.shape) { values[it].sum() }
|
||||
public fun counts(): NDStructure<Long> = NDStructure.auto(counts.shape) { counts[it].sum() }
|
||||
|
||||
/**
|
||||
* Sum of weights
|
||||
* NDStructure containing values of bins including weights
|
||||
*/
|
||||
public fun weights(): NDStructure<Double> = NDStructure.auto(weights.shape) { weights[it].sum() }
|
||||
public fun values(): NDStructure<Double> = NDStructure.auto(values.shape) { values[it].sum() }
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
|
@ -5,7 +5,6 @@ import kscience.kmath.histogram.fill
|
||||
import kscience.kmath.histogram.put
|
||||
import kscience.kmath.real.RealVector
|
||||
import kscience.kmath.real.invoke
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.*
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
package kscience.kmath.histogram
|
||||
|
||||
import kscience.kmath.real.RealVector
|
||||
import kscience.kmath.linear.Point
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.asBuffer
|
||||
import kscience.kmath.structures.asSequence
|
||||
import java.util.*
|
||||
import kotlin.math.floor
|
||||
|
||||
@ -11,28 +13,36 @@ import kotlin.math.floor
|
||||
public class UnivariateBin(
|
||||
public val position: Double,
|
||||
public val size: Double,
|
||||
public val counter: LongCounter = LongCounter()
|
||||
) : Bin<Double> {
|
||||
//TODO add weighting
|
||||
public override val value: Number get() = counter.sum()
|
||||
//internal mutation operations
|
||||
internal val counter: LongCounter = LongCounter()
|
||||
internal val weightCounter: DoubleCounter = DoubleCounter()
|
||||
|
||||
public override val center: RealVector get() = doubleArrayOf(position).asBuffer()
|
||||
/**
|
||||
* The precise number of events ignoring weighting
|
||||
*/
|
||||
public val count: Long get() = counter.sum()
|
||||
|
||||
/**
|
||||
* The value of histogram including weighting
|
||||
*/
|
||||
public override val value: Double get() = weightCounter.sum()
|
||||
|
||||
public override val center: Point<Double> get() = doubleArrayOf(position).asBuffer()
|
||||
public override val dimension: Int get() = 1
|
||||
|
||||
public operator fun contains(value: Double): Boolean = value in (position - size / 2)..(position + size / 2)
|
||||
public override fun contains(point: Buffer<Double>): Boolean = contains(point[0])
|
||||
internal operator fun inc(): UnivariateBin = this.also { counter.increment() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Univariate histogram with log(n) bin search speed
|
||||
*/
|
||||
public class UnivariateHistogram private constructor(private val factory: (Double) -> UnivariateBin) :
|
||||
MutableHistogram<Double, UnivariateBin> {
|
||||
public abstract class UnivariateHistogram(
|
||||
protected val bins: TreeMap<Double, UnivariateBin> = TreeMap(),
|
||||
) : Histogram<Double, UnivariateBin> {
|
||||
|
||||
private val bins: TreeMap<Double, UnivariateBin> = TreeMap()
|
||||
|
||||
private operator fun get(value: Double): UnivariateBin? {
|
||||
public operator fun get(value: Double): UnivariateBin? {
|
||||
// check ceiling entry and return it if it is what needed
|
||||
val ceil = bins.ceilingEntry(value)?.value
|
||||
if (ceil != null && value in ceil) return ceil
|
||||
@ -43,38 +53,38 @@ public class UnivariateHistogram private constructor(private val factory: (Doubl
|
||||
return null
|
||||
}
|
||||
|
||||
private fun createBin(value: Double): UnivariateBin = factory(value).also {
|
||||
synchronized(this) { bins[it.position] = it }
|
||||
}
|
||||
|
||||
public override operator fun get(point: Buffer<out Double>): UnivariateBin? = get(point[0])
|
||||
|
||||
public override val dimension: Int get() = 1
|
||||
|
||||
public override operator fun iterator(): Iterator<UnivariateBin> = bins.values.iterator()
|
||||
|
||||
/**
|
||||
* Thread safe put operation
|
||||
*/
|
||||
public fun put(value: Double) {
|
||||
(get(value) ?: createBin(value)).inc()
|
||||
}
|
||||
|
||||
override fun putWithWeight(point: Buffer<out Double>, weight: Double) {
|
||||
if (weight != 1.0) TODO("Implement weighting")
|
||||
put(point[0])
|
||||
}
|
||||
|
||||
public companion object {
|
||||
public fun uniform(binSize: Double, start: Double = 0.0): UnivariateHistogram = UnivariateHistogram { value ->
|
||||
val center = start + binSize * floor((value - start) / binSize + 0.5)
|
||||
UnivariateBin(center, binSize)
|
||||
}
|
||||
/**
|
||||
* Build a histogram with a uniform binning with a start at [start] and a bin size of [binSize]
|
||||
*/
|
||||
public fun uniformBuilder(binSize: Double, start: Double = 0.0): UnivariateHistogramBuilder =
|
||||
UnivariateHistogramBuilder { value ->
|
||||
val center = start + binSize * floor((value - start) / binSize + 0.5)
|
||||
UnivariateBin(center, binSize)
|
||||
}
|
||||
|
||||
public fun custom(borders: DoubleArray): UnivariateHistogram {
|
||||
/**
|
||||
* Build and fill a [UnivariateHistogram]. Returns a read-only histogram.
|
||||
*/
|
||||
public fun uniform(
|
||||
binSize: Double,
|
||||
start: Double = 0.0,
|
||||
builder: UnivariateHistogramBuilder.() -> Unit,
|
||||
): UnivariateHistogram = uniformBuilder(binSize, start).apply(builder)
|
||||
|
||||
/**
|
||||
* Create a histogram with custom cell borders
|
||||
*/
|
||||
public fun customBuilder(borders: DoubleArray): UnivariateHistogramBuilder {
|
||||
val sorted = borders.sortedArray()
|
||||
|
||||
return UnivariateHistogram { value ->
|
||||
return UnivariateHistogramBuilder { value ->
|
||||
when {
|
||||
value < sorted.first() -> UnivariateBin(
|
||||
Double.NEGATIVE_INFINITY,
|
||||
@ -95,7 +105,55 @@ public class UnivariateHistogram private constructor(private val factory: (Doubl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and fill a histogram with custom borders. Returns a read-only histogram.
|
||||
*/
|
||||
public fun custom(
|
||||
borders: DoubleArray,
|
||||
builder: UnivariateHistogramBuilder.() -> Unit,
|
||||
): UnivariateHistogram = customBuilder(borders).apply(builder)
|
||||
}
|
||||
}
|
||||
|
||||
public fun UnivariateHistogram.fill(sequence: Iterable<Double>): Unit = sequence.forEach(::put)
|
||||
public class UnivariateHistogramBuilder(
|
||||
private val factory: (Double) -> UnivariateBin,
|
||||
) : UnivariateHistogram(), MutableHistogram<Double, UnivariateBin> {
|
||||
|
||||
private fun createBin(value: Double): UnivariateBin = factory(value).also {
|
||||
synchronized(this) { bins[it.position] = it }
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread safe put operation
|
||||
*/
|
||||
public fun put(value: Double, weight: Double = 1.0) {
|
||||
(get(value) ?: createBin(value)).apply{
|
||||
counter.increment()
|
||||
weightCounter.add(weight)
|
||||
}
|
||||
}
|
||||
|
||||
override fun putWithWeight(point: Buffer<out Double>, weight: Double) {
|
||||
put(point[0], weight)
|
||||
}
|
||||
|
||||
/**
|
||||
* Put several items into a single bin
|
||||
*/
|
||||
public fun putMany(value: Double, count: Int, weight: Double = count.toDouble()){
|
||||
(get(value) ?: createBin(value)).apply{
|
||||
counter.add(count.toLong())
|
||||
weightCounter.add(weight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun UnivariateHistogramBuilder.fill(items: Iterable<Double>): Unit = items.forEach(::put)
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun UnivariateHistogramBuilder.fill(array: DoubleArray): Unit = array.forEach(::put)
|
||||
|
||||
@UnstableKMathAPI
|
||||
public fun UnivariateHistogramBuilder.fill(buffer: Buffer<Double>): Unit = buffer.asSequence().forEach(::put)
|
@ -7,3 +7,7 @@ dependencies {
|
||||
implementation("com.github.breandan:kotlingrad:0.4.0")
|
||||
api(project(":kmath-ast"))
|
||||
}
|
||||
|
||||
readme{
|
||||
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
|
||||
}
|
72
kmath-memory/api/kmath-memory.api
Normal file
72
kmath-memory/api/kmath-memory.api
Normal file
@ -0,0 +1,72 @@
|
||||
public final class kscience/kmath/memory/ByteBufferMemory : kscience/kmath/memory/Memory {
|
||||
public fun <init> (Ljava/nio/ByteBuffer;II)V
|
||||
public synthetic fun <init> (Ljava/nio/ByteBuffer;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun copy ()Lkscience/kmath/memory/Memory;
|
||||
public final fun getBuffer ()Ljava/nio/ByteBuffer;
|
||||
public fun getSize ()I
|
||||
public final fun getStartOffset ()I
|
||||
public fun reader ()Lkscience/kmath/memory/MemoryReader;
|
||||
public fun view (II)Lkscience/kmath/memory/Memory;
|
||||
public fun writer ()Lkscience/kmath/memory/MemoryWriter;
|
||||
}
|
||||
|
||||
public final class kscience/kmath/memory/ByteBufferMemoryKt {
|
||||
public static final fun allocate (Lkscience/kmath/memory/Memory$Companion;I)Lkscience/kmath/memory/Memory;
|
||||
public static final fun asMemory (Ljava/nio/ByteBuffer;II)Lkscience/kmath/memory/Memory;
|
||||
public static synthetic fun asMemory$default (Ljava/nio/ByteBuffer;IIILjava/lang/Object;)Lkscience/kmath/memory/Memory;
|
||||
public static final fun readAsMemory (Ljava/nio/file/Path;JJLkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||
public static synthetic fun readAsMemory$default (Ljava/nio/file/Path;JJLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Object;
|
||||
public static final fun wrap (Lkscience/kmath/memory/Memory$Companion;[B)Lkscience/kmath/memory/Memory;
|
||||
}
|
||||
|
||||
public abstract interface class kscience/kmath/memory/Memory {
|
||||
public static final field Companion Lkscience/kmath/memory/Memory$Companion;
|
||||
public abstract fun copy ()Lkscience/kmath/memory/Memory;
|
||||
public abstract fun getSize ()I
|
||||
public abstract fun reader ()Lkscience/kmath/memory/MemoryReader;
|
||||
public abstract fun view (II)Lkscience/kmath/memory/Memory;
|
||||
public abstract fun writer ()Lkscience/kmath/memory/MemoryWriter;
|
||||
}
|
||||
|
||||
public final class kscience/kmath/memory/Memory$Companion {
|
||||
}
|
||||
|
||||
public final class kscience/kmath/memory/MemoryKt {
|
||||
public static final fun read (Lkscience/kmath/memory/Memory;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||
public static final fun write (Lkscience/kmath/memory/Memory;Lkotlin/jvm/functions/Function1;)V
|
||||
}
|
||||
|
||||
public abstract interface class kscience/kmath/memory/MemoryReader {
|
||||
public abstract fun getMemory ()Lkscience/kmath/memory/Memory;
|
||||
public abstract fun readByte (I)B
|
||||
public abstract fun readDouble (I)D
|
||||
public abstract fun readFloat (I)F
|
||||
public abstract fun readInt (I)I
|
||||
public abstract fun readLong (I)J
|
||||
public abstract fun readShort (I)S
|
||||
public abstract fun release ()V
|
||||
}
|
||||
|
||||
public abstract interface class kscience/kmath/memory/MemorySpec {
|
||||
public abstract fun getObjectSize ()I
|
||||
public abstract fun read (Lkscience/kmath/memory/MemoryReader;I)Ljava/lang/Object;
|
||||
public abstract fun write (Lkscience/kmath/memory/MemoryWriter;ILjava/lang/Object;)V
|
||||
}
|
||||
|
||||
public final class kscience/kmath/memory/MemorySpecKt {
|
||||
public static final fun read (Lkscience/kmath/memory/MemoryReader;Lkscience/kmath/memory/MemorySpec;I)Ljava/lang/Object;
|
||||
public static final fun write (Lkscience/kmath/memory/MemoryWriter;Lkscience/kmath/memory/MemorySpec;ILjava/lang/Object;)V
|
||||
public static final fun writeArray (Lkscience/kmath/memory/MemoryWriter;Lkscience/kmath/memory/MemorySpec;I[Ljava/lang/Object;)V
|
||||
}
|
||||
|
||||
public abstract interface class kscience/kmath/memory/MemoryWriter {
|
||||
public abstract fun getMemory ()Lkscience/kmath/memory/Memory;
|
||||
public abstract fun release ()V
|
||||
public abstract fun writeByte (IB)V
|
||||
public abstract fun writeDouble (ID)V
|
||||
public abstract fun writeFloat (IF)V
|
||||
public abstract fun writeInt (II)V
|
||||
public abstract fun writeLong (IJ)V
|
||||
public abstract fun writeShort (IS)V
|
||||
}
|
||||
|
@ -2,3 +2,10 @@ plugins {
|
||||
id("ru.mipt.npm.mpp")
|
||||
id("ru.mipt.npm.native")
|
||||
}
|
||||
|
||||
readme{
|
||||
description = """
|
||||
An API and basic implementation for arranging objects in a continous memory block.
|
||||
""".trimIndent()
|
||||
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
|
||||
}
|
@ -9,7 +9,7 @@ This subproject implements the following features:
|
||||
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `kscience.kmath:kmath-nd4j:0.2.0-dev-4`.
|
||||
> This module artifact: `kscience.kmath:kmath-nd4j:0.2.0-dev-6`.
|
||||
>
|
||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-nd4j/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-nd4j/_latestVersion)
|
||||
>
|
||||
@ -27,7 +27,7 @@ This subproject implements the following features:
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'kscience.kmath:kmath-nd4j:0.2.0-dev-4'
|
||||
> implementation 'kscience.kmath:kmath-nd4j:0.2.0-dev-6'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
@ -41,7 +41,7 @@ This subproject implements the following features:
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("kscience.kmath:kmath-nd4j:0.2.0-dev-4")
|
||||
> implementation("kscience.kmath:kmath-nd4j:0.2.0-dev-6")
|
||||
> }
|
||||
> ```
|
||||
|
||||
|
@ -1,55 +1,68 @@
|
||||
package kscience.kmath.nd4j
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.*
|
||||
import kscience.kmath.structures.NDAlgebra
|
||||
import kscience.kmath.structures.NDField
|
||||
import kscience.kmath.structures.NDRing
|
||||
import kscience.kmath.structures.NDSpace
|
||||
import kscience.kmath.structures.*
|
||||
import org.nd4j.linalg.api.ndarray.INDArray
|
||||
import org.nd4j.linalg.factory.Nd4j
|
||||
|
||||
internal fun NDAlgebra<*, *>.checkShape(array: INDArray): INDArray {
|
||||
val arrayShape = array.shape().toIntArray()
|
||||
if (!shape.contentEquals(arrayShape)) throw ShapeMismatchException(shape, arrayShape)
|
||||
return array
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents [NDAlgebra] over [Nd4jArrayAlgebra].
|
||||
*
|
||||
* @param T the type of ND-structure element.
|
||||
* @param C the type of the element context.
|
||||
*/
|
||||
public interface Nd4jArrayAlgebra<T, C> : NDAlgebra<T, C, Nd4jArrayStructure<T>> {
|
||||
public interface Nd4jArrayAlgebra<T, C> : NDAlgebra<T, C> {
|
||||
/**
|
||||
* Wraps [INDArray] to [N].
|
||||
*/
|
||||
public fun INDArray.wrap(): Nd4jArrayStructure<T>
|
||||
|
||||
public val NDStructure<T>.ndArray: INDArray
|
||||
get() = when {
|
||||
!shape.contentEquals(this@Nd4jArrayAlgebra.shape) -> throw ShapeMismatchException(
|
||||
this@Nd4jArrayAlgebra.shape,
|
||||
shape
|
||||
)
|
||||
this is Nd4jArrayStructure -> ndArray //TODO check strides
|
||||
else -> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
public override fun produce(initializer: C.(IntArray) -> T): Nd4jArrayStructure<T> {
|
||||
val struct = Nd4j.create(*shape)!!.wrap()
|
||||
struct.indicesIterator().forEach { struct[it] = elementContext.initializer(it) }
|
||||
return struct
|
||||
}
|
||||
|
||||
public override fun map(arg: Nd4jArrayStructure<T>, transform: C.(T) -> T): Nd4jArrayStructure<T> {
|
||||
check(arg)
|
||||
val newStruct = arg.ndArray.dup().wrap()
|
||||
public override fun NDStructure<T>.map(transform: C.(T) -> T): Nd4jArrayStructure<T> {
|
||||
val newStruct = ndArray.dup().wrap()
|
||||
newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) }
|
||||
return newStruct
|
||||
}
|
||||
|
||||
public override fun mapIndexed(
|
||||
arg: Nd4jArrayStructure<T>,
|
||||
public override fun NDStructure<T>.mapIndexed(
|
||||
transform: C.(index: IntArray, T) -> T,
|
||||
): Nd4jArrayStructure<T> {
|
||||
check(arg)
|
||||
val new = Nd4j.create(*shape).wrap()
|
||||
new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(idx, arg[idx]) }
|
||||
val new = Nd4j.create(*this@Nd4jArrayAlgebra.shape).wrap()
|
||||
new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(idx, this[idx]) }
|
||||
return new
|
||||
}
|
||||
|
||||
public override fun combine(
|
||||
a: Nd4jArrayStructure<T>,
|
||||
b: Nd4jArrayStructure<T>,
|
||||
a: NDStructure<T>,
|
||||
b: NDStructure<T>,
|
||||
transform: C.(T, T) -> T,
|
||||
): Nd4jArrayStructure<T> {
|
||||
check(a, b)
|
||||
val new = Nd4j.create(*shape).wrap()
|
||||
new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(a[idx], b[idx]) }
|
||||
return new
|
||||
@ -62,38 +75,32 @@ public interface Nd4jArrayAlgebra<T, C> : NDAlgebra<T, C, Nd4jArrayStructure<T>>
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param S the type of space of structure elements.
|
||||
*/
|
||||
public interface Nd4jArraySpace<T, S : Space<T>> : NDSpace<T, S, Nd4jArrayStructure<T>>, Nd4jArrayAlgebra<T, S> {
|
||||
public interface Nd4jArraySpace<T, S : Space<T>> : NDSpace<T, S>, Nd4jArrayAlgebra<T, S> {
|
||||
|
||||
public override val zero: Nd4jArrayStructure<T>
|
||||
get() = Nd4j.zeros(*shape).wrap()
|
||||
|
||||
public override fun add(a: Nd4jArrayStructure<T>, b: Nd4jArrayStructure<T>): Nd4jArrayStructure<T> {
|
||||
check(a, b)
|
||||
public override fun add(a: NDStructure<T>, b: NDStructure<T>): Nd4jArrayStructure<T> {
|
||||
return a.ndArray.add(b.ndArray).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<T>.minus(b: Nd4jArrayStructure<T>): Nd4jArrayStructure<T> {
|
||||
check(this, b)
|
||||
public override operator fun NDStructure<T>.minus(b: NDStructure<T>): Nd4jArrayStructure<T> {
|
||||
return ndArray.sub(b.ndArray).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<T>.unaryMinus(): Nd4jArrayStructure<T> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<T>.unaryMinus(): Nd4jArrayStructure<T> {
|
||||
return ndArray.neg().wrap()
|
||||
}
|
||||
|
||||
public override fun multiply(a: Nd4jArrayStructure<T>, k: Number): Nd4jArrayStructure<T> {
|
||||
check(a)
|
||||
public override fun multiply(a: NDStructure<T>, k: Number): Nd4jArrayStructure<T> {
|
||||
return a.ndArray.mul(k).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<T>.div(k: Number): Nd4jArrayStructure<T> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<T>.div(k: Number): Nd4jArrayStructure<T> {
|
||||
return ndArray.div(k).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<T>.times(k: Number): Nd4jArrayStructure<T> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<T>.times(k: Number): Nd4jArrayStructure<T> {
|
||||
return ndArray.mul(k).wrap()
|
||||
}
|
||||
}
|
||||
@ -105,13 +112,12 @@ public interface Nd4jArraySpace<T, S : Space<T>> : NDSpace<T, S, Nd4jArrayStruct
|
||||
* @param R the type of ring of structure elements.
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public interface Nd4jArrayRing<T, R : Ring<T>> : NDRing<T, R, Nd4jArrayStructure<T>>, Nd4jArraySpace<T, R> {
|
||||
public interface Nd4jArrayRing<T, R : Ring<T>> : NDRing<T, R>, Nd4jArraySpace<T, R> {
|
||||
|
||||
public override val one: Nd4jArrayStructure<T>
|
||||
get() = Nd4j.ones(*shape).wrap()
|
||||
|
||||
public override fun multiply(a: Nd4jArrayStructure<T>, b: Nd4jArrayStructure<T>): Nd4jArrayStructure<T> {
|
||||
check(a, b)
|
||||
public override fun multiply(a: NDStructure<T>, b: NDStructure<T>): Nd4jArrayStructure<T> {
|
||||
return a.ndArray.mul(b.ndArray).wrap()
|
||||
}
|
||||
//
|
||||
@ -168,17 +174,12 @@ public interface Nd4jArrayRing<T, R : Ring<T>> : NDRing<T, R, Nd4jArrayStructure
|
||||
* @param N the type of ND structure.
|
||||
* @param F the type field of structure elements.
|
||||
*/
|
||||
public interface Nd4jArrayField<T, F : Field<T>> : NDField<T, F, Nd4jArrayStructure<T>>, Nd4jArrayRing<T, F> {
|
||||
public interface Nd4jArrayField<T, F : Field<T>> : NDField<T, F>, Nd4jArrayRing<T, F> {
|
||||
|
||||
public override fun divide(a: Nd4jArrayStructure<T>, b: Nd4jArrayStructure<T>): Nd4jArrayStructure<T> {
|
||||
check(a, b)
|
||||
return a.ndArray.div(b.ndArray).wrap()
|
||||
}
|
||||
public override fun divide(a: NDStructure<T>, b: NDStructure<T>): Nd4jArrayStructure<T> =
|
||||
a.ndArray.div(b.ndArray).wrap()
|
||||
|
||||
public override operator fun Number.div(b: Nd4jArrayStructure<T>): Nd4jArrayStructure<T> {
|
||||
check(b)
|
||||
return b.ndArray.rdiv(this).wrap()
|
||||
}
|
||||
public override operator fun Number.div(b: NDStructure<T>): Nd4jArrayStructure<T> = b.ndArray.rdiv(this).wrap()
|
||||
|
||||
|
||||
public companion object {
|
||||
@ -219,35 +220,29 @@ public class RealNd4jArrayField(public override val shape: IntArray) : Nd4jArray
|
||||
public override val elementContext: RealField
|
||||
get() = RealField
|
||||
|
||||
public override fun INDArray.wrap(): Nd4jArrayStructure<Double> = check(asRealStructure())
|
||||
public override fun INDArray.wrap(): Nd4jArrayStructure<Double> = checkShape(this).asRealStructure()
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Double>.div(arg: Double): Nd4jArrayStructure<Double> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Double>.div(arg: Double): Nd4jArrayStructure<Double> {
|
||||
return ndArray.div(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Double>.plus(arg: Double): Nd4jArrayStructure<Double> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Double>.plus(arg: Double): Nd4jArrayStructure<Double> {
|
||||
return ndArray.add(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Double>.minus(arg: Double): Nd4jArrayStructure<Double> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Double>.minus(arg: Double): Nd4jArrayStructure<Double> {
|
||||
return ndArray.sub(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Double>.times(arg: Double): Nd4jArrayStructure<Double> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Double>.times(arg: Double): Nd4jArrayStructure<Double> {
|
||||
return ndArray.mul(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Double.div(arg: Nd4jArrayStructure<Double>): Nd4jArrayStructure<Double> {
|
||||
check(arg)
|
||||
public override operator fun Double.div(arg: NDStructure<Double>): Nd4jArrayStructure<Double> {
|
||||
return arg.ndArray.rdiv(this).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Double.minus(arg: Nd4jArrayStructure<Double>): Nd4jArrayStructure<Double> {
|
||||
check(arg)
|
||||
public override operator fun Double.minus(arg: NDStructure<Double>): Nd4jArrayStructure<Double> {
|
||||
return arg.ndArray.rsub(this).wrap()
|
||||
}
|
||||
}
|
||||
@ -259,35 +254,29 @@ public class FloatNd4jArrayField(public override val shape: IntArray) : Nd4jArra
|
||||
public override val elementContext: FloatField
|
||||
get() = FloatField
|
||||
|
||||
public override fun INDArray.wrap(): Nd4jArrayStructure<Float> = check(asFloatStructure())
|
||||
public override fun INDArray.wrap(): Nd4jArrayStructure<Float> = checkShape(this).asFloatStructure()
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Float>.div(arg: Float): Nd4jArrayStructure<Float> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Float>.div(arg: Float): Nd4jArrayStructure<Float> {
|
||||
return ndArray.div(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Float>.plus(arg: Float): Nd4jArrayStructure<Float> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Float>.plus(arg: Float): Nd4jArrayStructure<Float> {
|
||||
return ndArray.add(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Float>.minus(arg: Float): Nd4jArrayStructure<Float> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Float>.minus(arg: Float): Nd4jArrayStructure<Float> {
|
||||
return ndArray.sub(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Float>.times(arg: Float): Nd4jArrayStructure<Float> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Float>.times(arg: Float): Nd4jArrayStructure<Float> {
|
||||
return ndArray.mul(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Float.div(arg: Nd4jArrayStructure<Float>): Nd4jArrayStructure<Float> {
|
||||
check(arg)
|
||||
public override operator fun Float.div(arg: NDStructure<Float>): Nd4jArrayStructure<Float> {
|
||||
return arg.ndArray.rdiv(this).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Float.minus(arg: Nd4jArrayStructure<Float>): Nd4jArrayStructure<Float> {
|
||||
check(arg)
|
||||
public override operator fun Float.minus(arg: NDStructure<Float>): Nd4jArrayStructure<Float> {
|
||||
return arg.ndArray.rsub(this).wrap()
|
||||
}
|
||||
}
|
||||
@ -299,25 +288,21 @@ public class IntNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayRi
|
||||
public override val elementContext: IntRing
|
||||
get() = IntRing
|
||||
|
||||
public override fun INDArray.wrap(): Nd4jArrayStructure<Int> = check(asIntStructure())
|
||||
public override fun INDArray.wrap(): Nd4jArrayStructure<Int> = checkShape(this).asIntStructure()
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Int>.plus(arg: Int): Nd4jArrayStructure<Int> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Int>.plus(arg: Int): Nd4jArrayStructure<Int> {
|
||||
return ndArray.add(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Int>.minus(arg: Int): Nd4jArrayStructure<Int> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Int>.minus(arg: Int): Nd4jArrayStructure<Int> {
|
||||
return ndArray.sub(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Int>.times(arg: Int): Nd4jArrayStructure<Int> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Int>.times(arg: Int): Nd4jArrayStructure<Int> {
|
||||
return ndArray.mul(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Int.minus(arg: Nd4jArrayStructure<Int>): Nd4jArrayStructure<Int> {
|
||||
check(arg)
|
||||
public override operator fun Int.minus(arg: NDStructure<Int>): Nd4jArrayStructure<Int> {
|
||||
return arg.ndArray.rsub(this).wrap()
|
||||
}
|
||||
}
|
||||
@ -329,25 +314,21 @@ public class LongNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayR
|
||||
public override val elementContext: LongRing
|
||||
get() = LongRing
|
||||
|
||||
public override fun INDArray.wrap(): Nd4jArrayStructure<Long> = check(asLongStructure())
|
||||
public override fun INDArray.wrap(): Nd4jArrayStructure<Long> = checkShape(this).asLongStructure()
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Long>.plus(arg: Long): Nd4jArrayStructure<Long> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Long>.plus(arg: Long): Nd4jArrayStructure<Long> {
|
||||
return ndArray.add(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Long>.minus(arg: Long): Nd4jArrayStructure<Long> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Long>.minus(arg: Long): Nd4jArrayStructure<Long> {
|
||||
return ndArray.sub(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Nd4jArrayStructure<Long>.times(arg: Long): Nd4jArrayStructure<Long> {
|
||||
check(this)
|
||||
public override operator fun NDStructure<Long>.times(arg: Long): Nd4jArrayStructure<Long> {
|
||||
return ndArray.mul(arg).wrap()
|
||||
}
|
||||
|
||||
public override operator fun Long.minus(arg: Nd4jArrayStructure<Long>): Nd4jArrayStructure<Long> {
|
||||
check(arg)
|
||||
public override operator fun Long.minus(arg: NDStructure<Long>): Nd4jArrayStructure<Long> {
|
||||
return arg.ndArray.rsub(this).wrap()
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package kscience.kmath.nd4j
|
||||
|
||||
import kscience.kmath.structures.MutableNDStructure
|
||||
import kscience.kmath.structures.NDStructure
|
||||
import kscience.kmath.nd.MutableNDStructure
|
||||
import kscience.kmath.nd.NDStructure
|
||||
import org.nd4j.linalg.api.ndarray.INDArray
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
package kscience.kmath.nd4j
|
||||
|
||||
import org.nd4j.linalg.factory.Nd4j
|
||||
import kscience.kmath.operations.invoke
|
||||
import org.nd4j.linalg.factory.Nd4j
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.fail
|
||||
@ -20,7 +20,7 @@ internal class Nd4jArrayAlgebraTest {
|
||||
|
||||
@Test
|
||||
fun testMap() {
|
||||
val res = (IntNd4jArrayRing(intArrayOf(2, 2))) { map(one) { it + it * 2 } }
|
||||
val res = (IntNd4jArrayRing(intArrayOf(2, 2))) { one.map() { it + it * 2 } }
|
||||
val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure()
|
||||
expected[intArrayOf(0, 0)] = 3
|
||||
expected[intArrayOf(0, 1)] = 3
|
||||
|
@ -1,6 +1,6 @@
|
||||
package kscience.kmath.nd4j
|
||||
|
||||
import kscience.kmath.structures.get
|
||||
import kscience.kmath.nd.get
|
||||
import org.nd4j.linalg.factory.Nd4j
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
@ -16,3 +16,7 @@ kotlin.sourceSets {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readme{
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
}
|
189
kmath-viktor/api/kmath-viktor.api
Normal file
189
kmath-viktor/api/kmath-viktor.api
Normal file
@ -0,0 +1,189 @@
|
||||
public final class kscience/kmath/viktor/ViktorBuffer : kscience/kmath/structures/MutableBuffer {
|
||||
public static final synthetic fun box-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Lkscience/kmath/viktor/ViktorBuffer;
|
||||
public static fun constructor-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Lorg/jetbrains/bio/viktor/F64FlatArray;
|
||||
public fun contentEquals (Lkscience/kmath/structures/Buffer;)Z
|
||||
public static fun contentEquals-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;Lkscience/kmath/structures/Buffer;)Z
|
||||
public fun copy ()Lkscience/kmath/structures/MutableBuffer;
|
||||
public static fun copy-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Lkscience/kmath/structures/MutableBuffer;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public static fun equals-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;Ljava/lang/Object;)Z
|
||||
public static final fun equals-impl0 (Lorg/jetbrains/bio/viktor/F64FlatArray;Lorg/jetbrains/bio/viktor/F64FlatArray;)Z
|
||||
public fun get (I)Ljava/lang/Double;
|
||||
public synthetic fun get (I)Ljava/lang/Object;
|
||||
public static fun get-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;I)Ljava/lang/Double;
|
||||
public final fun getFlatArray ()Lorg/jetbrains/bio/viktor/F64FlatArray;
|
||||
public fun getSize ()I
|
||||
public static fun getSize-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)I
|
||||
public fun hashCode ()I
|
||||
public static fun hashCode-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)I
|
||||
public fun iterator ()Ljava/util/Iterator;
|
||||
public static fun iterator-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Ljava/util/Iterator;
|
||||
public fun set (ID)V
|
||||
public synthetic fun set (ILjava/lang/Object;)V
|
||||
public static fun set-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;ID)V
|
||||
public fun toString ()Ljava/lang/String;
|
||||
public static fun toString-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Ljava/lang/String;
|
||||
public final synthetic fun unbox-impl ()Lorg/jetbrains/bio/viktor/F64FlatArray;
|
||||
}
|
||||
|
||||
public final class kscience/kmath/viktor/ViktorNDField : kscience/kmath/nd/NDField, kscience/kmath/operations/ExtendedField, kscience/kmath/operations/RingWithNumbers {
|
||||
public fun <init> ([I)V
|
||||
public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun acos-02gLDOA (Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun acosh (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public synthetic fun add (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun add-frQ_39w (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun asin-02gLDOA (Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun asinh (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun atan-02gLDOA (Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun atanh (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun binaryOperation (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun binaryOperation (Ljava/lang/String;Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
|
||||
public synthetic fun combine (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;Lkotlin/jvm/functions/Function3;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun combine-C8Lp-Ak (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;Lkotlin/jvm/functions/Function3;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun cos-02gLDOA (Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun cosh (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun div (DLkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun div (Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun div (Ljava/lang/Number;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun div (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
|
||||
public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public synthetic fun div (Ljava/lang/Object;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun div (Lkscience/kmath/nd/NDStructure;D)Lkscience/kmath/nd/NDStructure;
|
||||
public fun div (Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun div (Lkscience/kmath/nd/NDStructure;Ljava/lang/Object;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun div (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun divide (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun exp-02gLDOA (Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun getElementContext ()Ljava/lang/Object;
|
||||
public fun getElementContext ()Lkscience/kmath/operations/RealField;
|
||||
public final fun getF64Buffer (Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun getOne ()Ljava/lang/Object;
|
||||
public fun getOne-hHuhEO0 ()Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public fun getShape ()[I
|
||||
public synthetic fun getZero ()Ljava/lang/Object;
|
||||
public fun getZero-hHuhEO0 ()Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public fun invoke (Lkotlin/jvm/functions/Function1;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun leftSideNumberOperation (Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun leftSideNumberOperation (Ljava/lang/String;Ljava/lang/Number;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun leftSideNumberOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
|
||||
public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun ln-02gLDOA (Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun map (Lkscience/kmath/nd/NDStructure;Lkotlin/jvm/functions/Function2;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun map-frQ_39w (Lkscience/kmath/nd/NDStructure;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun mapIndexed (Lkscience/kmath/nd/NDStructure;Lkotlin/jvm/functions/Function3;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun mapIndexed-frQ_39w (Lkscience/kmath/nd/NDStructure;Lkotlin/jvm/functions/Function3;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public fun minus (DLkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun minus (Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun minus (Ljava/lang/Number;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
|
||||
public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public synthetic fun minus (Ljava/lang/Object;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun minus (Lkscience/kmath/nd/NDStructure;D)Lkscience/kmath/nd/NDStructure;
|
||||
public fun minus (Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun minus (Lkscience/kmath/nd/NDStructure;Ljava/lang/Object;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun minus (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun minus-frQ_39w (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
|
||||
public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public synthetic fun multiply (Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun multiply (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun multiply-frQ_39w (Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
|
||||
public fun number-02gLDOA (Ljava/lang/Number;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public fun plus (DLkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun plus (Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun plus (Ljava/lang/Number;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
|
||||
public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public synthetic fun plus (Ljava/lang/Object;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun plus (Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun plus (Lkscience/kmath/nd/NDStructure;Ljava/lang/Object;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun plus (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun plus-frQ_39w (Lkscience/kmath/nd/NDStructure;D)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public fun plus-frQ_39w (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun pow (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
|
||||
public fun pow (Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
|
||||
public fun power-frQ_39w (Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun produce (Lkotlin/jvm/functions/Function2;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun produce-02gLDOA (Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun rightSideNumberOperation (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
|
||||
public fun rightSideNumberOperation (Ljava/lang/String;Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun rightSideNumberOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
|
||||
public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun sin-02gLDOA (Lkscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun sinh (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun sqrt (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun symbol (Ljava/lang/String;)Ljava/lang/Object;
|
||||
public fun symbol (Ljava/lang/String;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun tan (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun tanh (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun times (DLkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun times (Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun times (Ljava/lang/Number;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun times (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
|
||||
public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public synthetic fun times (Ljava/lang/Object;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun times (Lkscience/kmath/nd/NDStructure;D)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun times (Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun times (Lkscience/kmath/nd/NDStructure;Ljava/lang/Object;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun times (Lkscience/kmath/nd/NDStructure;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun times-frQ_39w (Lkscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun unaryMinus (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public synthetic fun unaryOperation (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun unaryOperation (Ljava/lang/String;Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
|
||||
public synthetic fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun unaryPlus (Lkscience/kmath/nd/NDStructure;)Lkscience/kmath/nd/NDStructure;
|
||||
}
|
||||
|
||||
public final class kscience/kmath/viktor/ViktorNDStructure : kscience/kmath/nd/MutableNDStructure {
|
||||
public static final synthetic fun box-impl (Lorg/jetbrains/bio/viktor/F64Array;)Lkscience/kmath/viktor/ViktorNDStructure;
|
||||
public static fun constructor-impl (Lorg/jetbrains/bio/viktor/F64Array;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public fun elements ()Lkotlin/sequences/Sequence;
|
||||
public static fun elements-impl (Lorg/jetbrains/bio/viktor/F64Array;)Lkotlin/sequences/Sequence;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public static fun equals-impl (Lorg/jetbrains/bio/viktor/F64Array;Ljava/lang/Object;)Z
|
||||
public static final fun equals-impl0 (Lorg/jetbrains/bio/viktor/F64Array;Lorg/jetbrains/bio/viktor/F64Array;)Z
|
||||
public fun get ([I)Ljava/lang/Double;
|
||||
public synthetic fun get ([I)Ljava/lang/Object;
|
||||
public static fun get-impl (Lorg/jetbrains/bio/viktor/F64Array;[I)Ljava/lang/Double;
|
||||
public fun getDimension ()I
|
||||
public static fun getDimension-impl (Lorg/jetbrains/bio/viktor/F64Array;)I
|
||||
public final fun getF64Buffer ()Lorg/jetbrains/bio/viktor/F64Array;
|
||||
public fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object;
|
||||
public static fun getFeature-impl (Lorg/jetbrains/bio/viktor/F64Array;Lkotlin/reflect/KClass;)Ljava/lang/Object;
|
||||
public fun getShape ()[I
|
||||
public static fun getShape-impl (Lorg/jetbrains/bio/viktor/F64Array;)[I
|
||||
public fun hashCode ()I
|
||||
public static fun hashCode-impl (Lorg/jetbrains/bio/viktor/F64Array;)I
|
||||
public fun set ([ID)V
|
||||
public synthetic fun set ([ILjava/lang/Object;)V
|
||||
public static fun set-impl (Lorg/jetbrains/bio/viktor/F64Array;[ID)V
|
||||
public fun toString ()Ljava/lang/String;
|
||||
public static fun toString-impl (Lorg/jetbrains/bio/viktor/F64Array;)Ljava/lang/String;
|
||||
public final synthetic fun unbox-impl ()Lorg/jetbrains/bio/viktor/F64Array;
|
||||
}
|
||||
|
||||
public final class kscience/kmath/viktor/ViktorNDStructureKt {
|
||||
public static final fun ViktorNDField ([I)Lkscience/kmath/viktor/ViktorNDField;
|
||||
public static final fun asStructure (Lorg/jetbrains/bio/viktor/F64Array;)Lorg/jetbrains/bio/viktor/F64Array;
|
||||
}
|
||||
|
@ -8,3 +8,7 @@ dependencies {
|
||||
api(project(":kmath-core"))
|
||||
api("org.jetbrains.bio:viktor:1.0.1")
|
||||
}
|
||||
|
||||
readme{
|
||||
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package kscience.kmath.viktor
|
||||
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.nd.*
|
||||
import kscience.kmath.operations.ExtendedField
|
||||
import kscience.kmath.operations.RealField
|
||||
import kscience.kmath.structures.DefaultStrides
|
||||
import kscience.kmath.structures.MutableNDStructure
|
||||
import kscience.kmath.structures.NDField
|
||||
import kscience.kmath.structures.Strides
|
||||
import kscience.kmath.operations.RingWithNumbers
|
||||
import org.jetbrains.bio.viktor.F64Array
|
||||
|
||||
@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
|
||||
@ -23,15 +23,28 @@ public inline class ViktorNDStructure(public val f64Buffer: F64Array) : MutableN
|
||||
|
||||
public fun F64Array.asStructure(): ViktorNDStructure = ViktorNDStructure(this)
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
|
||||
public class ViktorNDField(public override val shape: IntArray) : NDField<Double, RealField, ViktorNDStructure> {
|
||||
public class ViktorNDField(public override val shape: IntArray) : NDField<Double, RealField>,
|
||||
RingWithNumbers<NDStructure<Double>>, ExtendedField<NDStructure<Double>> {
|
||||
|
||||
public val NDStructure<Double>.f64Buffer: F64Array
|
||||
get() = when {
|
||||
!shape.contentEquals(this@ViktorNDField.shape) -> throw ShapeMismatchException(
|
||||
this@ViktorNDField.shape,
|
||||
shape
|
||||
)
|
||||
this is ViktorNDStructure && this.f64Buffer.shape.contentEquals(this@ViktorNDField.shape) -> this.f64Buffer
|
||||
else -> produce { this@f64Buffer[it] }.f64Buffer
|
||||
}
|
||||
|
||||
public override val zero: ViktorNDStructure
|
||||
get() = F64Array.full(init = 0.0, shape = shape).asStructure()
|
||||
|
||||
public override val one: ViktorNDStructure
|
||||
get() = F64Array.full(init = 1.0, shape = shape).asStructure()
|
||||
|
||||
public val strides: Strides = DefaultStrides(shape)
|
||||
private val strides: Strides = DefaultStrides(shape)
|
||||
|
||||
public override val elementContext: RealField get() = RealField
|
||||
|
||||
@ -42,47 +55,67 @@ public class ViktorNDField(public override val shape: IntArray) : NDField<Double
|
||||
}
|
||||
}.asStructure()
|
||||
|
||||
public override fun map(arg: ViktorNDStructure, transform: RealField.(Double) -> Double): ViktorNDStructure =
|
||||
F64Array(*shape).apply {
|
||||
public override fun NDStructure<Double>.map(transform: RealField.(Double) -> Double): ViktorNDStructure =
|
||||
F64Array(*this@ViktorNDField.shape).apply {
|
||||
this@ViktorNDField.strides.indices().forEach { index ->
|
||||
set(value = RealField.transform(arg[index]), indices = index)
|
||||
set(value = RealField.transform(this@map[index]), indices = index)
|
||||
}
|
||||
}.asStructure()
|
||||
|
||||
public override fun mapIndexed(
|
||||
arg: ViktorNDStructure,
|
||||
transform: RealField.(index: IntArray, Double) -> Double
|
||||
): ViktorNDStructure = F64Array(*shape).apply {
|
||||
public override fun NDStructure<Double>.mapIndexed(
|
||||
transform: RealField.(index: IntArray, Double) -> Double,
|
||||
): ViktorNDStructure = F64Array(*this@ViktorNDField.shape).apply {
|
||||
this@ViktorNDField.strides.indices().forEach { index ->
|
||||
set(value = RealField.transform(index, arg[index]), indices = index)
|
||||
set(value = RealField.transform(index, this@mapIndexed[index]), indices = index)
|
||||
}
|
||||
}.asStructure()
|
||||
|
||||
public override fun combine(
|
||||
a: ViktorNDStructure,
|
||||
b: ViktorNDStructure,
|
||||
transform: RealField.(Double, Double) -> Double
|
||||
a: NDStructure<Double>,
|
||||
b: NDStructure<Double>,
|
||||
transform: RealField.(Double, Double) -> Double,
|
||||
): ViktorNDStructure = F64Array(*shape).apply {
|
||||
this@ViktorNDField.strides.indices().forEach { index ->
|
||||
set(value = RealField.transform(a[index], b[index]), indices = index)
|
||||
}
|
||||
}.asStructure()
|
||||
|
||||
public override fun add(a: ViktorNDStructure, b: ViktorNDStructure): ViktorNDStructure =
|
||||
public override fun add(a: NDStructure<Double>, b: NDStructure<Double>): ViktorNDStructure =
|
||||
(a.f64Buffer + b.f64Buffer).asStructure()
|
||||
|
||||
public override fun multiply(a: ViktorNDStructure, k: Number): ViktorNDStructure =
|
||||
public override fun multiply(a: NDStructure<Double>, k: Number): ViktorNDStructure =
|
||||
(a.f64Buffer * k.toDouble()).asStructure()
|
||||
|
||||
public override inline fun ViktorNDStructure.plus(b: ViktorNDStructure): ViktorNDStructure =
|
||||
public override inline fun NDStructure<Double>.plus(b: NDStructure<Double>): ViktorNDStructure =
|
||||
(f64Buffer + b.f64Buffer).asStructure()
|
||||
|
||||
public override inline fun ViktorNDStructure.minus(b: ViktorNDStructure): ViktorNDStructure =
|
||||
public override inline fun NDStructure<Double>.minus(b: NDStructure<Double>): ViktorNDStructure =
|
||||
(f64Buffer - b.f64Buffer).asStructure()
|
||||
|
||||
public override inline fun ViktorNDStructure.times(k: Number): ViktorNDStructure =
|
||||
public override inline fun NDStructure<Double>.times(k: Number): ViktorNDStructure =
|
||||
(f64Buffer * k.toDouble()).asStructure()
|
||||
|
||||
public override inline fun ViktorNDStructure.plus(arg: Double): ViktorNDStructure =
|
||||
public override inline fun NDStructure<Double>.plus(arg: Double): ViktorNDStructure =
|
||||
(f64Buffer.plus(arg)).asStructure()
|
||||
}
|
||||
|
||||
override fun number(value: Number): ViktorNDStructure =
|
||||
F64Array.full(init = value.toDouble(), shape = shape).asStructure()
|
||||
|
||||
override fun sin(arg: NDStructure<Double>): ViktorNDStructure = arg.map { sin(it) }
|
||||
|
||||
override fun cos(arg: NDStructure<Double>): ViktorNDStructure = arg.map { cos(it) }
|
||||
|
||||
override fun asin(arg: NDStructure<Double>): ViktorNDStructure = arg.map { asin(it) }
|
||||
|
||||
override fun acos(arg: NDStructure<Double>): ViktorNDStructure = arg.map { acos(it) }
|
||||
|
||||
override fun atan(arg: NDStructure<Double>): ViktorNDStructure = arg.map { atan(it) }
|
||||
|
||||
override fun power(arg: NDStructure<Double>, pow: Number): ViktorNDStructure = arg.map { it.pow(pow) }
|
||||
|
||||
override fun exp(arg: NDStructure<Double>): ViktorNDStructure = arg.f64Buffer.exp().asStructure()
|
||||
|
||||
override fun ln(arg: NDStructure<Double>): ViktorNDStructure = arg.f64Buffer.log().asStructure()
|
||||
}
|
||||
|
||||
public fun ViktorNDField(vararg shape: Int): ViktorNDField = ViktorNDField(shape)
|
@ -8,7 +8,7 @@ pluginManagement {
|
||||
maven("https://dl.bintray.com/kotlin/kotlinx")
|
||||
}
|
||||
|
||||
val toolsVersion = "0.7.3-1.4.30-RC"
|
||||
val toolsVersion = "0.7.4"
|
||||
val kotlinVersion = "1.4.30-RC"
|
||||
|
||||
plugins {
|
||||
|
Loading…
Reference in New Issue
Block a user