Rename API classes, update readme files

This commit is contained in:
Iaroslav Postovalov 2020-10-29 15:39:53 +07:00
parent d7cf04a98b
commit 57910f617a
No known key found for this signature in database
GPG Key ID: 46E15E4A31B3BCD7
15 changed files with 534 additions and 388 deletions

View File

@ -8,41 +8,50 @@ Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience
Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion) Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
# KMath # KMath
Could be pronounced as `key-math`.
The Kotlin MATHematics 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. Could be pronounced as `key-math`. The Kotlin MATHematics 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.
## Publications and talks ## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2) * [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
* [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814) * [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814)
* [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103) * [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103)
# Goal # Goal
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM and JS for now and Native in future).
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native).
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
* Provide bindings and wrappers with those abstractions for popular optimized platform libraries. * Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
## Non-goals ## Non-goals
* Be like Numpy. It was the idea at the beginning, but we decided that we can do better in terms of API.
* Provide best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API.
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better experience for those, who want to work with specific types. * 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
experience for those, who want to work with specific types.
## Features ## Features
Actual feature list is [here](/docs/features.md) Current feature list is [here](/docs/features.md)
* **Algebra** * **Algebra**
* Algebraic structures like rings, spaces and field (**TODO** add example to wiki) * Algebraic structures like rings, spaces and fields (**TODO** add example to wiki)
* Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. * Basic linear algebra operations (sums, products, etc.), backed by the `Space` API.
* Complex numbers backed by the `Field` API (meaning that they will be usable in any structure like vectors and N-dimensional arrays). * 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. * Advanced linear algebra operations like matrix inversion and LU decomposition.
* **Array-like structures** Full support of many-dimensional array-like structures * **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). including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).
* **Expressions** By writing a single mathematical expression * **Expressions** By writing a single mathematical expression once, users will be able to apply different types of
once, users will be able to apply different types of objects to the expression by providing a context. Expressions objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
can be used for a wide variety of purposes from high performance calculations to code generation. performance calculations to code generation.
* **Histograms** Fast multi-dimensional histograms. * **Histograms** Fast multi-dimensional histograms.
@ -50,9 +59,10 @@ can be used for a wide variety of purposes from high performance calculations to
* **Type-safe dimensions** Type-safe dimensions for matrix operations. * **Type-safe dimensions** Type-safe dimensions for matrix operations.
* **Commons-math wrapper** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/) * **Commons-math wrapper** It is planned to gradually wrap most parts of
library in Kotlin code and maybe rewrite some parts to better suit the Kotlin programming paradigm, however there is no fixed roadmap for that. Feel free [Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some
to submit a feature request if you want something to be done first. 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 ## Planned features
@ -151,6 +161,18 @@ can be used for a wide variety of purposes from high performance calculations to
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
<hr/> <hr/>
* ### [kmath-nd4j](kmath-nd4j)
> ND4J NDStructure implementation and according NDAlgebra classes
>
> **Maturity**: EXPERIMENTAL
>
> **Features:**
> - [nd4jarraystrucure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray
> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long
> - [nd4jarrayfields](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : Fields over Nd4jArrayStructure of Float and Double
<hr/>
* ### [kmath-stat](kmath-stat) * ### [kmath-stat](kmath-stat)
> >
> >
@ -166,15 +188,26 @@ can be used for a wide variety of purposes from high performance calculations to
## Multi-platform support ## Multi-platform support
KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the [common module](/kmath-core/src/commonMain). Implementation is also done in the common module wherever possible. In some cases, features are delegated to platform-specific implementations even if they could be done in the common module for performance reasons. Currently, the JVM is the main focus of development, however Kotlin/Native and Kotlin/JS contributions are also welcome. KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the
[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features
are delegated to platform-specific implementations even if they could be provided in the common module for performance
reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and
feedback are also welcome.
## Performance ## Performance
Calculation performance is one of major goals of KMath in the future, but in some cases it is not possible to achieve both performance and flexibility. We expect to focus on creating convenient universal API first and then work on increasing performance for specific cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve
both performance and flexibility.
### Dependency We expect to focus on creating convenient universal API first and then work on increasing performance for specific
cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy.
Release artifacts are accessible from bintray with following configuration (see documentation for [kotlin-multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) form more details): ### Repositories
Release artifacts are accessible from bintray with following configuration (see documentation of
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details):
```kotlin ```kotlin
repositories { repositories {
@ -182,23 +215,26 @@ repositories{
} }
dependencies { dependencies {
api("kscience.kmath:kmath-core:0.2.0-dev-2") api("kscience.kmath:kmath-core:0.2.0-dev-3")
//api("kscience.kmath:kmath-core-jvm:0.2.0-dev-2") for jvm-specific version // api("kscience.kmath:kmath-core-jvm:0.2.0-dev-3") for jvm-specific version
} }
``` ```
Gradle `6.0+` is required for multiplatform artifacts. Gradle `6.0+` is required for multiplatform artifacts.
### Development #### Development
Development builds are uploaded to the separate repository:
Development builds are accessible from the reposirtory
```kotlin ```kotlin
repositories { repositories {
maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/mipt-npm/dev")
} }
``` ```
with the same artifact names.
## Contributing ## Contributing
The project requires a lot of additional work. The most important thing we need is a feedback about what features are required the most. Feel free to open feature issues with requests. We are also welcome to code contributions, especially in issues marked as [waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero). The project requires a lot of additional work. The most important thing we need is a feedback about what features are
required the most. Feel free to create feature requests. We are also welcome to code contributions,
especially in issues marked with
[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label.

View File

@ -2,16 +2,15 @@ plugins {
id("ru.mipt.npm.project") id("ru.mipt.npm.project")
} }
val kmathVersion: String by extra("0.2.0-dev-3") internal val kmathVersion: String by extra("0.2.0-dev-3")
val bintrayRepo: String by extra("kscience") internal val bintrayRepo: String by extra("kscience")
val githubProject: String by extra("kmath") internal val githubProject: String by extra("kmath")
allprojects { allprojects {
repositories { repositories {
jcenter() jcenter()
maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/kotlin/kotlinx") maven("https://dl.bintray.com/kotlin/kotlinx")
mavenCentral()
maven("https://dl.bintray.com/hotkeytlt/maven") maven("https://dl.bintray.com/hotkeytlt/maven")
} }

View File

@ -8,41 +8,50 @@ Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience
Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion) Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
# KMath # KMath
Could be pronounced as `key-math`.
The Kotlin MATHematics 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. Could be pronounced as `key-math`. The Kotlin MATHematics 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.
## Publications and talks ## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2) * [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
* [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814) * [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814)
* [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103) * [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103)
# Goal # Goal
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM and JS for now and Native in future).
* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native).
* Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
* Provide bindings and wrappers with those abstractions for popular optimized platform libraries. * Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
## Non-goals ## Non-goals
* Be like Numpy. It was the idea at the beginning, but we decided that we can do better in terms of API.
* Provide best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API.
* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them.
* Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually.
* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like for `Double` in the core. For that we will have specialization modules like `for-real`, which will give better experience for those, who want to work with specific types. * 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
experience for those, who want to work with specific types.
## Features ## Features
Actual feature list is [here](/docs/features.md) Current feature list is [here](/docs/features.md)
* **Algebra** * **Algebra**
* Algebraic structures like rings, spaces and field (**TODO** add example to wiki) * Algebraic structures like rings, spaces and fields (**TODO** add example to wiki)
* Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. * Basic linear algebra operations (sums, products, etc.), backed by the `Space` API.
* Complex numbers backed by the `Field` API (meaning that they will be usable in any structure like vectors and N-dimensional arrays). * 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. * Advanced linear algebra operations like matrix inversion and LU decomposition.
* **Array-like structures** Full support of many-dimensional array-like structures * **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). including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking).
* **Expressions** By writing a single mathematical expression * **Expressions** By writing a single mathematical expression once, users will be able to apply different types of
once, users will be able to apply different types of objects to the expression by providing a context. Expressions objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
can be used for a wide variety of purposes from high performance calculations to code generation. performance calculations to code generation.
* **Histograms** Fast multi-dimensional histograms. * **Histograms** Fast multi-dimensional histograms.
@ -50,9 +59,10 @@ can be used for a wide variety of purposes from high performance calculations to
* **Type-safe dimensions** Type-safe dimensions for matrix operations. * **Type-safe dimensions** Type-safe dimensions for matrix operations.
* **Commons-math wrapper** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/) * **Commons-math wrapper** It is planned to gradually wrap most parts of
library in Kotlin code and maybe rewrite some parts to better suit the Kotlin programming paradigm, however there is no fixed roadmap for that. Feel free [Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some
to submit a feature request if you want something to be done first. 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 ## Planned features
@ -72,15 +82,26 @@ $modules
## Multi-platform support ## Multi-platform support
KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the [common module](/kmath-core/src/commonMain). Implementation is also done in the common module wherever possible. In some cases, features are delegated to platform-specific implementations even if they could be done in the common module for performance reasons. Currently, the JVM is the main focus of development, however Kotlin/Native and Kotlin/JS contributions are also welcome. KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the
[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features
are delegated to platform-specific implementations even if they could be provided in the common module for performance
reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and
feedback are also welcome.
## Performance ## Performance
Calculation performance is one of major goals of KMath in the future, but in some cases it is not possible to achieve both performance and flexibility. We expect to focus on creating convenient universal API first and then work on increasing performance for specific cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve
both performance and flexibility.
### Dependency We expect to focus on creating convenient universal API first and then work on increasing performance for specific
cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy.
Release artifacts are accessible from bintray with following configuration (see documentation for [kotlin-multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) form more details): ### Repositories
Release artifacts are accessible from bintray with following configuration (see documentation of
[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details):
```kotlin ```kotlin
repositories { repositories {
@ -95,16 +116,19 @@ dependencies{
Gradle `6.0+` is required for multiplatform artifacts. Gradle `6.0+` is required for multiplatform artifacts.
### Development #### Development
Development builds are uploaded to the separate repository:
Development builds are accessible from the reposirtory
```kotlin ```kotlin
repositories { repositories {
maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/mipt-npm/dev")
} }
``` ```
with the same artifact names.
## Contributing ## Contributing
The project requires a lot of additional work. The most important thing we need is a feedback about what features are required the most. Feel free to open feature issues with requests. We are also welcome to code contributions, especially in issues marked as [waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero). The project requires a lot of additional work. The most important thing we need is a feedback about what features are
required the most. Feel free to create feature requests. We are also welcome to code contributions,
especially in issues marked with
[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label.

View File

@ -12,7 +12,7 @@ The core features of KMath:
> #### Artifact: > #### Artifact:
> >
> This module artifact: `kscience.kmath:kmath-core:0.2.0-dev-2`. > This module artifact: `kscience.kmath:kmath-core:0.2.0-dev-3`.
> >
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion) > Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
> >
@ -30,7 +30,7 @@ The core features of KMath:
> } > }
> >
> dependencies { > dependencies {
> implementation 'kscience.kmath:kmath-core:0.2.0-dev-2' > implementation 'kscience.kmath:kmath-core:0.2.0-dev-3'
> } > }
> ``` > ```
> **Gradle Kotlin DSL:** > **Gradle Kotlin DSL:**
@ -44,6 +44,6 @@ The core features of KMath:
> } > }
> >
> dependencies { > dependencies {
> implementation("kscience.kmath:kmath-core:0.2.0-dev-2") > implementation("kscience.kmath:kmath-core:0.2.0-dev-3")
> } > }
> ``` > ```

View File

@ -1,3 +1,5 @@
import ru.mipt.npm.gradle.Maturity
plugins { plugins {
id("ru.mipt.npm.mpp") id("ru.mipt.npm.mpp")
id("ru.mipt.npm.native") id("ru.mipt.npm.native")
@ -11,33 +13,39 @@ kotlin.sourceSets.commonMain {
readme { readme {
description = "Core classes, algebra definitions, basic linear algebra" description = "Core classes, algebra definitions, basic linear algebra"
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT maturity = Maturity.DEVELOPMENT
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature( feature(
id = "algebras", id = "algebras",
description = "Algebraic structures: contexts and elements", description = "Algebraic structures: contexts and elements",
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt" ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
) )
feature( feature(
id = "nd", id = "nd",
description = "Many-dimensional structures", description = "Many-dimensional structures",
ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt" ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt"
) )
feature( feature(
id = "buffers", id = "buffers",
description = "One-dimensional structure", description = "One-dimensional structure",
ref = "src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt" ref = "src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt"
) )
feature( feature(
id = "expressions", id = "expressions",
description = "Functional Expressions", description = "Functional Expressions",
ref = "src/commonMain/kotlin/kscience/kmath/expressions" ref = "src/commonMain/kotlin/kscience/kmath/expressions"
) )
feature( feature(
id = "domains", id = "domains",
description = "Domains", description = "Domains",
ref = "src/commonMain/kotlin/kscience/kmath/domains" ref = "src/commonMain/kotlin/kscience/kmath/domains"
) )
feature( feature(
id = "autodif", id = "autodif",
description = "Automatic differentiation", description = "Automatic differentiation",

View File

@ -35,20 +35,27 @@ public fun interface Expression<T> {
} }
/** /**
* Invoke an expression without parameters * Calls this expression without providing any arguments.
*
* @return a value.
*/ */
public operator fun <T> Expression<T>.invoke(): T = invoke(emptyMap()) public operator fun <T> Expression<T>.invoke(): T = invoke(emptyMap())
//This method exists to avoid resolution ambiguity of vararg methods
/** /**
* Calls this expression from arguments. * Calls this expression from arguments.
* *
* @param pairs the pair of arguments' names to values. * @param pairs the pairs of arguments to values.
* @return the value. * @return a value.
*/ */
@JvmName("callBySymbol") @JvmName("callBySymbol")
public operator fun <T> Expression<T>.invoke(vararg pairs: Pair<Symbol, T>): T = invoke(mapOf(*pairs)) public operator fun <T> Expression<T>.invoke(vararg pairs: Pair<Symbol, T>): T = invoke(mapOf(*pairs))
/**
* Calls this expression from arguments.
*
* @param pairs the pairs of arguments' names to values.
* @return a value.
*/
@JvmName("callByString") @JvmName("callByString")
public operator fun <T> Expression<T>.invoke(vararg pairs: Pair<String, T>): T = public operator fun <T> Expression<T>.invoke(vararg pairs: Pair<String, T>): T =
invoke(mapOf(*pairs).mapKeys { StringSymbol(it.key) }) invoke(mapOf(*pairs).mapKeys { StringSymbol(it.key) })
@ -61,7 +68,6 @@ public operator fun <T> Expression<T>.invoke(vararg pairs: Pair<String, T>): T =
* @param E type of the actual expression state * @param E type of the actual expression state
*/ */
public interface ExpressionAlgebra<in T, E> : Algebra<E> { public interface ExpressionAlgebra<in T, E> : Algebra<E> {
/** /**
* Bind a given [Symbol] to this context variable and produce context-specific object. Return null if symbol could not be bound in current context. * Bind a given [Symbol] to this context variable and produce context-specific object. Return null if symbol could not be bound in current context.
*/ */
@ -87,7 +93,7 @@ public fun <T, E> ExpressionAlgebra<T, E>.bind(symbol: Symbol): E =
/** /**
* A delegate to create a symbol with a string identity in this scope * A delegate to create a symbol with a string identity in this scope
*/ */
public val symbol: ReadOnlyProperty<Any?, StringSymbol> = ReadOnlyProperty { thisRef, property -> public val symbol: ReadOnlyProperty<Any?, StringSymbol> = ReadOnlyProperty { _, property ->
StringSymbol(property.name) StringSymbol(property.name)
} }

View File

@ -73,7 +73,7 @@ public interface NDAlgebra<T, C, N : NDStructure<T>> {
public fun check(vararg elements: N): Array<out N> = elements public fun check(vararg elements: N): Array<out N> = elements
.map(NDStructure<T>::shape) .map(NDStructure<T>::shape)
.singleOrNull { !shape.contentEquals(it) } .singleOrNull { !shape.contentEquals(it) }
?.let { throw ShapeMismatchException(shape, it) } ?.let<IntArray, Array<out N>> { throw ShapeMismatchException(shape, it) }
?: elements ?: elements
/** /**

View File

@ -1,3 +1,5 @@
import ru.mipt.npm.gradle.Maturity
plugins { plugins {
id("ru.mipt.npm.jvm") id("ru.mipt.npm.jvm")
} }
@ -9,3 +11,27 @@ dependencies {
testImplementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") testImplementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
testImplementation("org.slf4j:slf4j-simple:1.7.30") testImplementation("org.slf4j:slf4j-simple:1.7.30")
} }
readme {
description = "ND4J NDStructure implementation and according NDAlgebra classes"
maturity = Maturity.EXPERIMENTAL
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(
id = "nd4jarraystrucure",
description = "NDStructure wrapper for INDArray",
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
)
feature(
id = "nd4jarrayrings",
description = "Rings over Nd4jArrayStructure of Int and Long",
ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt"
)
feature(
id = "nd4jarrayfields",
description = "Fields over Nd4jArrayStructure of Float and Double",
ref = "src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt"
)
}

View File

@ -0,0 +1,43 @@
# ND4J NDStructure implementation (`kmath-nd4j`)
This subproject implements the following features:
${features}
${artifact}
## Examples
NDStructure wrapper for INDArray:
```kotlin
import org.nd4j.linalg.factory.*
import scientifik.kmath.nd4j.*
import scientifik.kmath.structures.*
val array = Nd4j.ones(2, 2).asRealStructure()
println(array[0, 0]) // 1.0
array[intArrayOf(0, 0)] = 24.0
println(array[0, 0]) // 24.0
```
Fast element-wise and in-place arithmetics for INDArray:
```kotlin
import org.nd4j.linalg.factory.*
import scientifik.kmath.nd4j.*
import scientifik.kmath.operations.*
val field = RealNd4jArrayField(intArrayOf(2, 2))
val array = Nd4j.rand(2, 2).asRealStructure()
val res = field {
(25.0 / array + 20) * 4
}
println(res.ndArray)
// [[ 250.6449, 428.5840],
// [ 269.7913, 202.2077]]
```
Contributed by [Iaroslav Postovalov](https://github.com/CommanderTvis).

View File

@ -1,284 +0,0 @@
package kscience.kmath.nd4j
import org.nd4j.linalg.api.ndarray.INDArray
import org.nd4j.linalg.factory.Nd4j
import kscience.kmath.operations.*
import kscience.kmath.structures.*
/**
* Represents [NDAlgebra] over [INDArrayAlgebra].
*
* @param T the type of ND-structure element.
* @param C the type of the element context.
*/
public interface INDArrayAlgebra<T, C> : NDAlgebra<T, C, INDArrayStructure<T>> {
/**
* Wraps [INDArray] to [N].
*/
public fun INDArray.wrap(): INDArrayStructure<T>
public override fun produce(initializer: C.(IntArray) -> T): INDArrayStructure<T> {
val struct = Nd4j.create(*shape)!!.wrap()
struct.indicesIterator().forEach { struct[it] = elementContext.initializer(it) }
return struct
}
public override fun map(arg: INDArrayStructure<T>, transform: C.(T) -> T): INDArrayStructure<T> {
check(arg)
val newStruct = arg.ndArray.dup().wrap()
newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) }
return newStruct
}
public override fun mapIndexed(
arg: INDArrayStructure<T>,
transform: C.(index: IntArray, T) -> T
): INDArrayStructure<T> {
check(arg)
val new = Nd4j.create(*shape).wrap()
new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(idx, arg[idx]) }
return new
}
public override fun combine(
a: INDArrayStructure<T>,
b: INDArrayStructure<T>,
transform: C.(T, T) -> T
): INDArrayStructure<T> {
check(a, b)
val new = Nd4j.create(*shape).wrap()
new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(a[idx], b[idx]) }
return new
}
}
/**
* Represents [NDSpace] over [INDArrayStructure].
*
* @param T the type of the element contained in ND structure.
* @param S the type of space of structure elements.
*/
public interface INDArraySpace<T, S> : NDSpace<T, S, INDArrayStructure<T>>, INDArrayAlgebra<T, S> where S : Space<T> {
public override val zero: INDArrayStructure<T>
get() = Nd4j.zeros(*shape).wrap()
public override fun add(a: INDArrayStructure<T>, b: INDArrayStructure<T>): INDArrayStructure<T> {
check(a, b)
return a.ndArray.add(b.ndArray).wrap()
}
public override operator fun INDArrayStructure<T>.minus(b: INDArrayStructure<T>): INDArrayStructure<T> {
check(this, b)
return ndArray.sub(b.ndArray).wrap()
}
public override operator fun INDArrayStructure<T>.unaryMinus(): INDArrayStructure<T> {
check(this)
return ndArray.neg().wrap()
}
public override fun multiply(a: INDArrayStructure<T>, k: Number): INDArrayStructure<T> {
check(a)
return a.ndArray.mul(k).wrap()
}
public override operator fun INDArrayStructure<T>.div(k: Number): INDArrayStructure<T> {
check(this)
return ndArray.div(k).wrap()
}
public override operator fun INDArrayStructure<T>.times(k: Number): INDArrayStructure<T> {
check(this)
return ndArray.mul(k).wrap()
}
}
/**
* Represents [NDRing] over [INDArrayStructure].
*
* @param T the type of the element contained in ND structure.
* @param R the type of ring of structure elements.
*/
public interface INDArrayRing<T, R> : NDRing<T, R, INDArrayStructure<T>>, INDArraySpace<T, R> where R : Ring<T> {
public override val one: INDArrayStructure<T>
get() = Nd4j.ones(*shape).wrap()
public override fun multiply(a: INDArrayStructure<T>, b: INDArrayStructure<T>): INDArrayStructure<T> {
check(a, b)
return a.ndArray.mul(b.ndArray).wrap()
}
public override operator fun INDArrayStructure<T>.minus(b: Number): INDArrayStructure<T> {
check(this)
return ndArray.sub(b).wrap()
}
public override operator fun INDArrayStructure<T>.plus(b: Number): INDArrayStructure<T> {
check(this)
return ndArray.add(b).wrap()
}
public override operator fun Number.minus(b: INDArrayStructure<T>): INDArrayStructure<T> {
check(b)
return b.ndArray.rsub(this).wrap()
}
}
/**
* Represents [NDField] over [INDArrayStructure].
*
* @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 INDArrayField<T, F> : NDField<T, F, INDArrayStructure<T>>, INDArrayRing<T, F> where F : Field<T> {
public override fun divide(a: INDArrayStructure<T>, b: INDArrayStructure<T>): INDArrayStructure<T> {
check(a, b)
return a.ndArray.div(b.ndArray).wrap()
}
public override operator fun Number.div(b: INDArrayStructure<T>): INDArrayStructure<T> {
check(b)
return b.ndArray.rdiv(this).wrap()
}
}
/**
* Represents [NDField] over [INDArrayRealStructure].
*/
public class RealINDArrayField(public override val shape: IntArray) : INDArrayField<Double, RealField> {
public override val elementContext: RealField
get() = RealField
public override fun INDArray.wrap(): INDArrayStructure<Double> = check(asRealStructure())
public override operator fun INDArrayStructure<Double>.div(arg: Double): INDArrayStructure<Double> {
check(this)
return ndArray.div(arg).wrap()
}
public override operator fun INDArrayStructure<Double>.plus(arg: Double): INDArrayStructure<Double> {
check(this)
return ndArray.add(arg).wrap()
}
public override operator fun INDArrayStructure<Double>.minus(arg: Double): INDArrayStructure<Double> {
check(this)
return ndArray.sub(arg).wrap()
}
public override operator fun INDArrayStructure<Double>.times(arg: Double): INDArrayStructure<Double> {
check(this)
return ndArray.mul(arg).wrap()
}
public override operator fun Double.div(arg: INDArrayStructure<Double>): INDArrayStructure<Double> {
check(arg)
return arg.ndArray.rdiv(this).wrap()
}
public override operator fun Double.minus(arg: INDArrayStructure<Double>): INDArrayStructure<Double> {
check(arg)
return arg.ndArray.rsub(this).wrap()
}
}
/**
* Represents [NDField] over [INDArrayStructure] of [Float].
*/
public class FloatINDArrayField(public override val shape: IntArray) : INDArrayField<Float, FloatField> {
public override val elementContext: FloatField
get() = FloatField
public override fun INDArray.wrap(): INDArrayStructure<Float> = check(asFloatStructure())
public override operator fun INDArrayStructure<Float>.div(arg: Float): INDArrayStructure<Float> {
check(this)
return ndArray.div(arg).wrap()
}
public override operator fun INDArrayStructure<Float>.plus(arg: Float): INDArrayStructure<Float> {
check(this)
return ndArray.add(arg).wrap()
}
public override operator fun INDArrayStructure<Float>.minus(arg: Float): INDArrayStructure<Float> {
check(this)
return ndArray.sub(arg).wrap()
}
public override operator fun INDArrayStructure<Float>.times(arg: Float): INDArrayStructure<Float> {
check(this)
return ndArray.mul(arg).wrap()
}
public override operator fun Float.div(arg: INDArrayStructure<Float>): INDArrayStructure<Float> {
check(arg)
return arg.ndArray.rdiv(this).wrap()
}
public override operator fun Float.minus(arg: INDArrayStructure<Float>): INDArrayStructure<Float> {
check(arg)
return arg.ndArray.rsub(this).wrap()
}
}
/**
* Represents [NDRing] over [INDArrayIntStructure].
*/
public class IntINDArrayRing(public override val shape: IntArray) : INDArrayRing<Int, IntRing> {
public override val elementContext: IntRing
get() = IntRing
public override fun INDArray.wrap(): INDArrayStructure<Int> = check(asIntStructure())
public override operator fun INDArrayStructure<Int>.plus(arg: Int): INDArrayStructure<Int> {
check(this)
return ndArray.add(arg).wrap()
}
public override operator fun INDArrayStructure<Int>.minus(arg: Int): INDArrayStructure<Int> {
check(this)
return ndArray.sub(arg).wrap()
}
public override operator fun INDArrayStructure<Int>.times(arg: Int): INDArrayStructure<Int> {
check(this)
return ndArray.mul(arg).wrap()
}
public override operator fun Int.minus(arg: INDArrayStructure<Int>): INDArrayStructure<Int> {
check(arg)
return arg.ndArray.rsub(this).wrap()
}
}
/**
* Represents [NDRing] over [INDArrayStructure] of [Long].
*/
public class LongINDArrayRing(public override val shape: IntArray) : INDArrayRing<Long, LongRing> {
public override val elementContext: LongRing
get() = LongRing
public override fun INDArray.wrap(): INDArrayStructure<Long> = check(asLongStructure())
public override operator fun INDArrayStructure<Long>.plus(arg: Long): INDArrayStructure<Long> {
check(this)
return ndArray.add(arg).wrap()
}
public override operator fun INDArrayStructure<Long>.minus(arg: Long): INDArrayStructure<Long> {
check(this)
return ndArray.sub(arg).wrap()
}
public override operator fun INDArrayStructure<Long>.times(arg: Long): INDArrayStructure<Long> {
check(this)
return ndArray.mul(arg).wrap()
}
public override operator fun Long.minus(arg: INDArrayStructure<Long>): INDArrayStructure<Long> {
check(arg)
return arg.ndArray.rsub(this).wrap()
}
}

View File

@ -0,0 +1,288 @@
package kscience.kmath.nd4j
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 org.nd4j.linalg.api.ndarray.INDArray
import org.nd4j.linalg.factory.Nd4j
/**
* 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>> {
/**
* Wraps [INDArray] to [N].
*/
public fun INDArray.wrap(): Nd4jArrayStructure<T>
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()
newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) }
return newStruct
}
public override fun mapIndexed(
arg: Nd4jArrayStructure<T>,
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]) }
return new
}
public override fun combine(
a: Nd4jArrayStructure<T>,
b: Nd4jArrayStructure<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
}
}
/**
* Represents [NDSpace] over [Nd4jArrayStructure].
*
* @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> : NDSpace<T, S, Nd4jArrayStructure<T>>,
Nd4jArrayAlgebra<T, S> where S : Space<T> {
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)
return a.ndArray.add(b.ndArray).wrap()
}
public override operator fun Nd4jArrayStructure<T>.minus(b: Nd4jArrayStructure<T>): Nd4jArrayStructure<T> {
check(this, b)
return ndArray.sub(b.ndArray).wrap()
}
public override operator fun Nd4jArrayStructure<T>.unaryMinus(): Nd4jArrayStructure<T> {
check(this)
return ndArray.neg().wrap()
}
public override fun multiply(a: Nd4jArrayStructure<T>, k: Number): Nd4jArrayStructure<T> {
check(a)
return a.ndArray.mul(k).wrap()
}
public override operator fun Nd4jArrayStructure<T>.div(k: Number): Nd4jArrayStructure<T> {
check(this)
return ndArray.div(k).wrap()
}
public override operator fun Nd4jArrayStructure<T>.times(k: Number): Nd4jArrayStructure<T> {
check(this)
return ndArray.mul(k).wrap()
}
}
/**
* Represents [NDRing] over [Nd4jArrayStructure].
*
* @param T the type of the element contained in ND structure.
* @param R the type of ring of structure elements.
*/
public interface Nd4jArrayRing<T, R> : NDRing<T, R, Nd4jArrayStructure<T>>, Nd4jArraySpace<T, R> where R : Ring<T> {
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)
return a.ndArray.mul(b.ndArray).wrap()
}
public override operator fun Nd4jArrayStructure<T>.minus(b: Number): Nd4jArrayStructure<T> {
check(this)
return ndArray.sub(b).wrap()
}
public override operator fun Nd4jArrayStructure<T>.plus(b: Number): Nd4jArrayStructure<T> {
check(this)
return ndArray.add(b).wrap()
}
public override operator fun Number.minus(b: Nd4jArrayStructure<T>): Nd4jArrayStructure<T> {
check(b)
return b.ndArray.rsub(this).wrap()
}
}
/**
* Represents [NDField] over [Nd4jArrayStructure].
*
* @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 Nd4jArrayField<T, F> : NDField<T, F, Nd4jArrayStructure<T>>, Nd4jArrayRing<T, F> where F : Field<T> {
public override fun divide(a: Nd4jArrayStructure<T>, b: Nd4jArrayStructure<T>): Nd4jArrayStructure<T> {
check(a, b)
return 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()
}
}
/**
* Represents [NDField] over [Nd4jArrayRealStructure].
*/
public class RealNd4jArrayField(public override val shape: IntArray) : Nd4jArrayField<Double, RealField> {
public override val elementContext: RealField
get() = RealField
public override fun INDArray.wrap(): Nd4jArrayStructure<Double> = check(asRealStructure())
public override operator fun Nd4jArrayStructure<Double>.div(arg: Double): Nd4jArrayStructure<Double> {
check(this)
return ndArray.div(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Double>.plus(arg: Double): Nd4jArrayStructure<Double> {
check(this)
return ndArray.add(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Double>.minus(arg: Double): Nd4jArrayStructure<Double> {
check(this)
return ndArray.sub(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Double>.times(arg: Double): Nd4jArrayStructure<Double> {
check(this)
return ndArray.mul(arg).wrap()
}
public override operator fun Double.div(arg: Nd4jArrayStructure<Double>): Nd4jArrayStructure<Double> {
check(arg)
return arg.ndArray.rdiv(this).wrap()
}
public override operator fun Double.minus(arg: Nd4jArrayStructure<Double>): Nd4jArrayStructure<Double> {
check(arg)
return arg.ndArray.rsub(this).wrap()
}
}
/**
* Represents [NDField] over [Nd4jArrayStructure] of [Float].
*/
public class FloatNd4jArrayField(public override val shape: IntArray) : Nd4jArrayField<Float, FloatField> {
public override val elementContext: FloatField
get() = FloatField
public override fun INDArray.wrap(): Nd4jArrayStructure<Float> = check(asFloatStructure())
public override operator fun Nd4jArrayStructure<Float>.div(arg: Float): Nd4jArrayStructure<Float> {
check(this)
return ndArray.div(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Float>.plus(arg: Float): Nd4jArrayStructure<Float> {
check(this)
return ndArray.add(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Float>.minus(arg: Float): Nd4jArrayStructure<Float> {
check(this)
return ndArray.sub(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Float>.times(arg: Float): Nd4jArrayStructure<Float> {
check(this)
return ndArray.mul(arg).wrap()
}
public override operator fun Float.div(arg: Nd4jArrayStructure<Float>): Nd4jArrayStructure<Float> {
check(arg)
return arg.ndArray.rdiv(this).wrap()
}
public override operator fun Float.minus(arg: Nd4jArrayStructure<Float>): Nd4jArrayStructure<Float> {
check(arg)
return arg.ndArray.rsub(this).wrap()
}
}
/**
* Represents [NDRing] over [Nd4jArrayIntStructure].
*/
public class IntNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayRing<Int, IntRing> {
public override val elementContext: IntRing
get() = IntRing
public override fun INDArray.wrap(): Nd4jArrayStructure<Int> = check(asIntStructure())
public override operator fun Nd4jArrayStructure<Int>.plus(arg: Int): Nd4jArrayStructure<Int> {
check(this)
return ndArray.add(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Int>.minus(arg: Int): Nd4jArrayStructure<Int> {
check(this)
return ndArray.sub(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Int>.times(arg: Int): Nd4jArrayStructure<Int> {
check(this)
return ndArray.mul(arg).wrap()
}
public override operator fun Int.minus(arg: Nd4jArrayStructure<Int>): Nd4jArrayStructure<Int> {
check(arg)
return arg.ndArray.rsub(this).wrap()
}
}
/**
* Represents [NDRing] over [Nd4jArrayStructure] of [Long].
*/
public class LongNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayRing<Long, LongRing> {
public override val elementContext: LongRing
get() = LongRing
public override fun INDArray.wrap(): Nd4jArrayStructure<Long> = check(asLongStructure())
public override operator fun Nd4jArrayStructure<Long>.plus(arg: Long): Nd4jArrayStructure<Long> {
check(this)
return ndArray.add(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Long>.minus(arg: Long): Nd4jArrayStructure<Long> {
check(this)
return ndArray.sub(arg).wrap()
}
public override operator fun Nd4jArrayStructure<Long>.times(arg: Long): Nd4jArrayStructure<Long> {
check(this)
return ndArray.mul(arg).wrap()
}
public override operator fun Long.minus(arg: Nd4jArrayStructure<Long>): Nd4jArrayStructure<Long> {
check(arg)
return arg.ndArray.rsub(this).wrap()
}
}

View File

@ -3,7 +3,7 @@ package kscience.kmath.nd4j
import org.nd4j.linalg.api.ndarray.INDArray import org.nd4j.linalg.api.ndarray.INDArray
import org.nd4j.linalg.api.shape.Shape import org.nd4j.linalg.api.shape.Shape
private class INDArrayIndicesIterator(private val iterateOver: INDArray) : Iterator<IntArray> { private class Nd4jArrayIndicesIterator(private val iterateOver: INDArray) : Iterator<IntArray> {
private var i: Int = 0 private var i: Int = 0
override fun hasNext(): Boolean = i < iterateOver.length() override fun hasNext(): Boolean = i < iterateOver.length()
@ -18,9 +18,9 @@ private class INDArrayIndicesIterator(private val iterateOver: INDArray) : Itera
} }
} }
internal fun INDArray.indicesIterator(): Iterator<IntArray> = INDArrayIndicesIterator(this) internal fun INDArray.indicesIterator(): Iterator<IntArray> = Nd4jArrayIndicesIterator(this)
private sealed class INDArrayIteratorBase<T>(protected val iterateOver: INDArray) : Iterator<Pair<IntArray, T>> { private sealed class Nd4jArrayIteratorBase<T>(protected val iterateOver: INDArray) : Iterator<Pair<IntArray, T>> {
private var i: Int = 0 private var i: Int = 0
final override fun hasNext(): Boolean = i < iterateOver.length() final override fun hasNext(): Boolean = i < iterateOver.length()
@ -37,26 +37,26 @@ private sealed class INDArrayIteratorBase<T>(protected val iterateOver: INDArray
} }
} }
private class INDArrayRealIterator(iterateOver: INDArray) : INDArrayIteratorBase<Double>(iterateOver) { private class Nd4jArrayRealIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase<Double>(iterateOver) {
override fun getSingle(indices: LongArray): Double = iterateOver.getDouble(*indices) override fun getSingle(indices: LongArray): Double = iterateOver.getDouble(*indices)
} }
internal fun INDArray.realIterator(): Iterator<Pair<IntArray, Double>> = INDArrayRealIterator(this) internal fun INDArray.realIterator(): Iterator<Pair<IntArray, Double>> = Nd4jArrayRealIterator(this)
private class INDArrayLongIterator(iterateOver: INDArray) : INDArrayIteratorBase<Long>(iterateOver) { private class Nd4jArrayLongIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase<Long>(iterateOver) {
override fun getSingle(indices: LongArray) = iterateOver.getLong(*indices) override fun getSingle(indices: LongArray) = iterateOver.getLong(*indices)
} }
internal fun INDArray.longIterator(): Iterator<Pair<IntArray, Long>> = INDArrayLongIterator(this) internal fun INDArray.longIterator(): Iterator<Pair<IntArray, Long>> = Nd4jArrayLongIterator(this)
private class INDArrayIntIterator(iterateOver: INDArray) : INDArrayIteratorBase<Int>(iterateOver) { private class Nd4jArrayIntIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase<Int>(iterateOver) {
override fun getSingle(indices: LongArray) = iterateOver.getInt(*indices.toIntArray()) override fun getSingle(indices: LongArray) = iterateOver.getInt(*indices.toIntArray())
} }
internal fun INDArray.intIterator(): Iterator<Pair<IntArray, Int>> = INDArrayIntIterator(this) internal fun INDArray.intIterator(): Iterator<Pair<IntArray, Int>> = Nd4jArrayIntIterator(this)
private class INDArrayFloatIterator(iterateOver: INDArray) : INDArrayIteratorBase<Float>(iterateOver) { private class Nd4jArrayFloatIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase<Float>(iterateOver) {
override fun getSingle(indices: LongArray) = iterateOver.getFloat(*indices) override fun getSingle(indices: LongArray) = iterateOver.getFloat(*indices)
} }
internal fun INDArray.floatIterator(): Iterator<Pair<IntArray, Float>> = INDArrayFloatIterator(this) internal fun INDArray.floatIterator(): Iterator<Pair<IntArray, Float>> = Nd4jArrayFloatIterator(this)

View File

@ -1,15 +1,15 @@
package kscience.kmath.nd4j package kscience.kmath.nd4j
import org.nd4j.linalg.api.ndarray.INDArray
import kscience.kmath.structures.MutableNDStructure import kscience.kmath.structures.MutableNDStructure
import kscience.kmath.structures.NDStructure import kscience.kmath.structures.NDStructure
import org.nd4j.linalg.api.ndarray.INDArray
/** /**
* Represents a [NDStructure] wrapping an [INDArray] object. * Represents a [NDStructure] wrapping an [INDArray] object.
* *
* @param T the type of items. * @param T the type of items.
*/ */
public sealed class INDArrayStructure<T> : MutableNDStructure<T> { public sealed class Nd4jArrayStructure<T> : MutableNDStructure<T> {
/** /**
* The wrapped [INDArray]. * The wrapped [INDArray].
*/ */
@ -23,46 +23,46 @@ public sealed class INDArrayStructure<T> : MutableNDStructure<T> {
public override fun elements(): Sequence<Pair<IntArray, T>> = Sequence(::elementsIterator) public override fun elements(): Sequence<Pair<IntArray, T>> = Sequence(::elementsIterator)
} }
private data class INDArrayIntStructure(override val ndArray: INDArray) : INDArrayStructure<Int>() { private data class Nd4jArrayIntStructure(override val ndArray: INDArray) : Nd4jArrayStructure<Int>() {
override fun elementsIterator(): Iterator<Pair<IntArray, Int>> = ndArray.intIterator() override fun elementsIterator(): Iterator<Pair<IntArray, Int>> = ndArray.intIterator()
override fun get(index: IntArray): Int = ndArray.getInt(*index) override fun get(index: IntArray): Int = ndArray.getInt(*index)
override fun set(index: IntArray, value: Int): Unit = run { ndArray.putScalar(index, value) } override fun set(index: IntArray, value: Int): Unit = run { ndArray.putScalar(index, value) }
} }
/** /**
* Wraps this [INDArray] to [INDArrayStructure]. * Wraps this [INDArray] to [Nd4jArrayStructure].
*/ */
public fun INDArray.asIntStructure(): INDArrayStructure<Int> = INDArrayIntStructure(this) public fun INDArray.asIntStructure(): Nd4jArrayStructure<Int> = Nd4jArrayIntStructure(this)
private data class INDArrayLongStructure(override val ndArray: INDArray) : INDArrayStructure<Long>() { private data class Nd4jArrayLongStructure(override val ndArray: INDArray) : Nd4jArrayStructure<Long>() {
override fun elementsIterator(): Iterator<Pair<IntArray, Long>> = ndArray.longIterator() override fun elementsIterator(): Iterator<Pair<IntArray, Long>> = ndArray.longIterator()
override fun get(index: IntArray): Long = ndArray.getLong(*index.toLongArray()) override fun get(index: IntArray): Long = ndArray.getLong(*index.toLongArray())
override fun set(index: IntArray, value: Long): Unit = run { ndArray.putScalar(index, value.toDouble()) } override fun set(index: IntArray, value: Long): Unit = run { ndArray.putScalar(index, value.toDouble()) }
} }
/** /**
* Wraps this [INDArray] to [INDArrayStructure]. * Wraps this [INDArray] to [Nd4jArrayStructure].
*/ */
public fun INDArray.asLongStructure(): INDArrayStructure<Long> = INDArrayLongStructure(this) public fun INDArray.asLongStructure(): Nd4jArrayStructure<Long> = Nd4jArrayLongStructure(this)
private data class INDArrayRealStructure(override val ndArray: INDArray) : INDArrayStructure<Double>() { private data class Nd4jArrayRealStructure(override val ndArray: INDArray) : Nd4jArrayStructure<Double>() {
override fun elementsIterator(): Iterator<Pair<IntArray, Double>> = ndArray.realIterator() override fun elementsIterator(): Iterator<Pair<IntArray, Double>> = ndArray.realIterator()
override fun get(index: IntArray): Double = ndArray.getDouble(*index) override fun get(index: IntArray): Double = ndArray.getDouble(*index)
override fun set(index: IntArray, value: Double): Unit = run { ndArray.putScalar(index, value) } override fun set(index: IntArray, value: Double): Unit = run { ndArray.putScalar(index, value) }
} }
/** /**
* Wraps this [INDArray] to [INDArrayStructure]. * Wraps this [INDArray] to [Nd4jArrayStructure].
*/ */
public fun INDArray.asRealStructure(): INDArrayStructure<Double> = INDArrayRealStructure(this) public fun INDArray.asRealStructure(): Nd4jArrayStructure<Double> = Nd4jArrayRealStructure(this)
private data class INDArrayFloatStructure(override val ndArray: INDArray) : INDArrayStructure<Float>() { private data class Nd4jArrayFloatStructure(override val ndArray: INDArray) : Nd4jArrayStructure<Float>() {
override fun elementsIterator(): Iterator<Pair<IntArray, Float>> = ndArray.floatIterator() override fun elementsIterator(): Iterator<Pair<IntArray, Float>> = ndArray.floatIterator()
override fun get(index: IntArray): Float = ndArray.getFloat(*index) override fun get(index: IntArray): Float = ndArray.getFloat(*index)
override fun set(index: IntArray, value: Float): Unit = run { ndArray.putScalar(index, value) } override fun set(index: IntArray, value: Float): Unit = run { ndArray.putScalar(index, value) }
} }
/** /**
* Wraps this [INDArray] to [INDArrayStructure]. * Wraps this [INDArray] to [Nd4jArrayStructure].
*/ */
public fun INDArray.asFloatStructure(): INDArrayStructure<Float> = INDArrayFloatStructure(this) public fun INDArray.asFloatStructure(): Nd4jArrayStructure<Float> = Nd4jArrayFloatStructure(this)

View File

@ -6,10 +6,10 @@ import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.fail import kotlin.test.fail
internal class INDArrayAlgebraTest { internal class Nd4jArrayAlgebraTest {
@Test @Test
fun testProduce() { fun testProduce() {
val res = (RealINDArrayField(intArrayOf(2, 2))) { produce { it.sum().toDouble() } } val res = (RealNd4jArrayField(intArrayOf(2, 2))) { produce { it.sum().toDouble() } }
val expected = (Nd4j.create(2, 2) ?: fail()).asRealStructure() val expected = (Nd4j.create(2, 2) ?: fail()).asRealStructure()
expected[intArrayOf(0, 0)] = 0.0 expected[intArrayOf(0, 0)] = 0.0
expected[intArrayOf(0, 1)] = 1.0 expected[intArrayOf(0, 1)] = 1.0
@ -20,7 +20,7 @@ internal class INDArrayAlgebraTest {
@Test @Test
fun testMap() { fun testMap() {
val res = (IntINDArrayRing(intArrayOf(2, 2))) { map(one) { it + it * 2 } } val res = (IntNd4jArrayRing(intArrayOf(2, 2))) { map(one) { it + it * 2 } }
val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure()
expected[intArrayOf(0, 0)] = 3 expected[intArrayOf(0, 0)] = 3
expected[intArrayOf(0, 1)] = 3 expected[intArrayOf(0, 1)] = 3
@ -31,7 +31,7 @@ internal class INDArrayAlgebraTest {
@Test @Test
fun testAdd() { fun testAdd() {
val res = (IntINDArrayRing(intArrayOf(2, 2))) { one + 25 } val res = (IntNd4jArrayRing(intArrayOf(2, 2))) { one + 25 }
val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure()
expected[intArrayOf(0, 0)] = 26 expected[intArrayOf(0, 0)] = 26
expected[intArrayOf(0, 1)] = 26 expected[intArrayOf(0, 1)] = 26

View File

@ -7,7 +7,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertNotEquals import kotlin.test.assertNotEquals
import kotlin.test.fail import kotlin.test.fail
internal class INDArrayStructureTest { internal class Nd4jArrayStructureTest {
@Test @Test
fun testElements() { fun testElements() {
val nd = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!! val nd = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!!