Merge dev, API check failed
11
.github/workflows/pages.yml
vendored
@ -22,8 +22,17 @@ jobs:
|
|||||||
key: ubuntu-20.04-gradle-${{ hashFiles('*.gradle.kts') }}
|
key: ubuntu-20.04-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
ubuntu-20.04-gradle-
|
ubuntu-20.04-gradle-
|
||||||
|
- name: Cache konan
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.konan
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gradle-
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./gradlew build --no-daemon --stacktrace
|
run: |
|
||||||
|
./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace
|
||||||
|
mv build/dokka/htmlMultiModule/-modules.html build/dokka/htmlMultiModule/index.html
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
uses: JamesIves/github-pages-deploy-action@4.1.0
|
uses: JamesIves/github-pages-deploy-action@4.1.0
|
||||||
with:
|
with:
|
||||||
|
@ -4,18 +4,22 @@
|
|||||||
### Added
|
### Added
|
||||||
- ScaleOperations interface
|
- ScaleOperations interface
|
||||||
- Field extends ScaleOperations
|
- Field extends ScaleOperations
|
||||||
|
- Basic integration API
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Exponential operations merged with hyperbolic functions
|
- Exponential operations merged with hyperbolic functions
|
||||||
- Space is replaced by Group. Space is reserved for vector spaces.
|
- Space is replaced by Group. Space is reserved for vector spaces.
|
||||||
- VectorSpace is now a vector space
|
- VectorSpace is now a vector space
|
||||||
-
|
- Buffer factories for primitives moved to MutableBuffer.Companion
|
||||||
|
- NDStructure and NDAlgebra to StructureND and AlgebraND respectively
|
||||||
|
- Real -> Double
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Nearest in Domain. To be implemented in geometry package.
|
- Nearest in Domain. To be implemented in geometry package.
|
||||||
- Number multiplication and division in main Algebra chain
|
- Number multiplication and division in main Algebra chain
|
||||||
|
- `contentEquals` from Buffer. It moved to the companion.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@ -73,6 +77,7 @@
|
|||||||
- `toGrid` method.
|
- `toGrid` method.
|
||||||
- Public visibility of `BufferAccessor2D`
|
- Public visibility of `BufferAccessor2D`
|
||||||
- `Real` class
|
- `Real` class
|
||||||
|
- StructureND identity and equals
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
||||||
|
58
README.md
@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
||||||
|
|
||||||
Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22kmath-core%22)
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@ -89,12 +87,12 @@ KMath is a modular library. Different modules provide different features with di
|
|||||||
> **Maturity**: PROTOTYPE
|
> **Maturity**: PROTOTYPE
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||||
> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||||
> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||||
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||||
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||||
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -110,8 +108,8 @@ KMath is a modular library. Different modules provide different features with di
|
|||||||
> **Maturity**: PROTOTYPE
|
> **Maturity**: PROTOTYPE
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [complex](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||||
> - [quaternion](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -121,15 +119,15 @@ KMath is a modular library. Different modules provide different features with di
|
|||||||
> **Maturity**: DEVELOPMENT
|
> **Maturity**: DEVELOPMENT
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
> - [algebras](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||||
> - [nd](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
|
> - [nd](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
|
||||||
> - [linear](kmath-core/src/commonMain/kotlin/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.
|
> - [linear](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||||
> - [buffers](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
> - [buffers](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||||
> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
> - [expressions](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
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.
|
performance calculations to code generation.
|
||||||
> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
> - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
|
||||||
> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -159,9 +157,9 @@ One can still use generic algebras though.
|
|||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [RealVector](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealVector.kt) : Numpy-like operations for Buffers/Points
|
> - [DoubleVector](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points
|
||||||
> - [RealMatrix](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt) : Numpy-like operations for 2d real structures
|
> - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures
|
||||||
> - [grids](kmath-for-real/src/commonMain/kotlin/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
> - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -171,10 +169,10 @@ One can still use generic algebras though.
|
|||||||
> **Maturity**: PROTOTYPE
|
> **Maturity**: PROTOTYPE
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt
|
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt
|
||||||
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt
|
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt
|
||||||
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt
|
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt
|
||||||
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt
|
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -208,9 +206,9 @@ One can still use generic algebras though.
|
|||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [nd4jarraystructure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray
|
> - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
|
||||||
> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long
|
> - [nd4jarrayrings](kmath-nd4j/#) : 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
|
> - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -256,8 +254,8 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api("kscience.kmath:kmath-core:() -> kotlin.Any")
|
api("space.kscience:kmath-core:0.3.0-dev-3")
|
||||||
// api("kscience.kmath:kmath-core-jvm:() -> kotlin.Any") for jvm-specific version
|
// api("kscience.kmath:kmath-core-jvm:0.3.0-dev-3") for jvm-specific version
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "space.kscience"
|
group = "space.kscience"
|
||||||
version = "0.3.0"
|
version = "0.3.0-dev-3"
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
|
@ -31,7 +31,7 @@ multiplication;
|
|||||||
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
|
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
|
||||||
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
|
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
|
||||||
|
|
||||||
A typical implementation of `Field<T>` is the `RealField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
||||||
|
|
||||||
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
|
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
|
||||||
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot`
|
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot`
|
||||||
|
@ -13,16 +13,19 @@
|
|||||||
version="1.1"><metadata
|
version="1.1"><metadata
|
||||||
id="metadata8"><rdf:RDF><cc:Work
|
id="metadata8"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||||
|
<defs
|
||||||
id="defs6"><clipPath
|
id="defs6"><clipPath
|
||||||
id="clipPath24"
|
id="clipPath24"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path22"
|
id="path22"
|
||||||
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath><clipPath
|
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath36"
|
id="clipPath36"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path34"
|
id="path34"
|
||||||
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs><g
|
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs>
|
||||||
|
<g
|
||||||
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
|
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
|
||||||
id="g10"><g
|
id="g10"><g
|
||||||
transform="scale(0.1)"
|
transform="scale(0.1)"
|
||||||
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 248 KiB |
@ -13,12 +13,14 @@
|
|||||||
version="1.1"><metadata
|
version="1.1"><metadata
|
||||||
id="metadata8"><rdf:RDF><cc:Work
|
id="metadata8"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||||
|
<defs
|
||||||
id="defs6"><clipPath
|
id="defs6"><clipPath
|
||||||
id="clipPath32"
|
id="clipPath32"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path30"
|
id="path30"
|
||||||
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs><g
|
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs>
|
||||||
|
<g
|
||||||
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
|
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
|
||||||
id="g10"><g
|
id="g10"><g
|
||||||
transform="scale(0.1)"
|
transform="scale(0.1)"
|
||||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@ -13,24 +13,29 @@
|
|||||||
version="1.1"><metadata
|
version="1.1"><metadata
|
||||||
id="metadata8"><rdf:RDF><cc:Work
|
id="metadata8"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||||
|
<defs
|
||||||
id="defs6"><clipPath
|
id="defs6"><clipPath
|
||||||
id="clipPath24"
|
id="clipPath24"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path22"
|
id="path22"
|
||||||
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath><clipPath
|
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath36"
|
id="clipPath36"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path34"
|
id="path34"
|
||||||
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath><clipPath
|
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath48"
|
id="clipPath48"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path46"
|
id="path46"
|
||||||
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath><clipPath
|
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath60"
|
id="clipPath60"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path58"
|
id="path58"
|
||||||
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs><g
|
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs>
|
||||||
|
<g
|
||||||
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
|
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
|
||||||
id="g10"><g
|
id="g10"><g
|
||||||
transform="scale(0.1)"
|
transform="scale(0.1)"
|
||||||
|
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 278 KiB |
@ -13,88 +13,109 @@
|
|||||||
version="1.1"><metadata
|
version="1.1"><metadata
|
||||||
id="metadata8"><rdf:RDF><cc:Work
|
id="metadata8"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||||
|
<defs
|
||||||
id="defs6"><clipPath
|
id="defs6"><clipPath
|
||||||
id="clipPath40"
|
id="clipPath40"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path38"
|
id="path38"
|
||||||
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath52"
|
id="clipPath52"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path50"
|
id="path50"
|
||||||
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath><clipPath
|
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath64"
|
id="clipPath64"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path62"
|
id="path62"
|
||||||
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath><clipPath
|
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath76"
|
id="clipPath76"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path74"
|
id="path74"
|
||||||
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath88"
|
id="clipPath88"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path86"
|
id="path86"
|
||||||
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath><clipPath
|
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath100"
|
id="clipPath100"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path98"
|
id="path98"
|
||||||
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath><clipPath
|
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath112"
|
id="clipPath112"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path110"
|
id="path110"
|
||||||
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath124"
|
id="clipPath124"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path122"
|
id="path122"
|
||||||
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath><clipPath
|
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath136"
|
id="clipPath136"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path134"
|
id="path134"
|
||||||
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath><clipPath
|
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath148"
|
id="clipPath148"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path146"
|
id="path146"
|
||||||
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath><clipPath
|
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath160"
|
id="clipPath160"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path158"
|
id="path158"
|
||||||
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath172"
|
id="clipPath172"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path170"
|
id="path170"
|
||||||
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath184"
|
id="clipPath184"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path182"
|
id="path182"
|
||||||
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath><clipPath
|
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath196"
|
id="clipPath196"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path194"
|
id="path194"
|
||||||
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath208"
|
id="clipPath208"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path206"
|
id="path206"
|
||||||
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath220"
|
id="clipPath220"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path218"
|
id="path218"
|
||||||
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath232"
|
id="clipPath232"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path230"
|
id="path230"
|
||||||
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath><clipPath
|
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath244"
|
id="clipPath244"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path242"
|
id="path242"
|
||||||
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath256"
|
id="clipPath256"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path254"
|
id="path254"
|
||||||
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath><clipPath
|
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath268"
|
id="clipPath268"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path266"
|
id="path266"
|
||||||
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs><g
|
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs>
|
||||||
|
<g
|
||||||
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
|
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
|
||||||
id="g10"><g
|
id="g10"><g
|
||||||
transform="scale(0.1)"
|
transform="scale(0.1)"
|
||||||
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
@ -10,11 +10,11 @@ structures. In `kmath` performance depends on which particular context was used
|
|||||||
Let us consider following contexts:
|
Let us consider following contexts:
|
||||||
```kotlin
|
```kotlin
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
val autoField = NDField.auto(RealField, dim, dim)
|
val autoField = NDField.auto(DoubleField, dim, dim)
|
||||||
// specialized nd-field for Double. It works as generic Double field as well
|
// specialized nd-field for Double. It works as generic Double field as well
|
||||||
val specializedField = NDField.real(dim, dim)
|
val specializedField = NDField.real(dim, dim)
|
||||||
//A generic boxing field. It should be used for objects, not primitives.
|
//A generic boxing field. It should be used for objects, not primitives.
|
||||||
val genericField = NDField.buffered(RealField, dim, dim)
|
val genericField = NDField.buffered(DoubleField, dim, dim)
|
||||||
```
|
```
|
||||||
Now let us perform several tests and see which implementation is best suited for each case:
|
Now let us perform several tests and see which implementation is best suited for each case:
|
||||||
|
|
||||||
|
6
docs/templates/ARTIFACT-TEMPLATE.md
vendored
@ -13,9 +13,6 @@
|
|||||||
> maven { url 'https://repo.kotlin.link' }
|
> maven { url 'https://repo.kotlin.link' }
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||||
>// Uncomment if repo.kotlin.link is unavailable
|
|
||||||
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
|
||||||
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> dependencies {
|
> dependencies {
|
||||||
@ -29,9 +26,6 @@
|
|||||||
> maven("https://repo.kotlin.link")
|
> maven("https://repo.kotlin.link")
|
||||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
>// Uncomment if repo.kotlin.link is unavailable
|
|
||||||
>// maven("https://dl.bintray.com/mipt-npm/kscience")
|
|
||||||
>// maven("https://dl.bintray.com/mipt-npm/dev")
|
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> dependencies {
|
> dependencies {
|
||||||
|
6
docs/templates/README-TEMPLATE.md
vendored
@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
||||||
|
|
||||||
Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22kmath-core%22)
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@ -106,7 +104,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api("kscience.kmath:kmath-core:$version")
|
api("${group}:kmath-core:$version")
|
||||||
// api("kscience.kmath:kmath-core-jvm:$version") for jvm-specific version
|
// api("kscience.kmath:kmath-core-jvm:$version") for jvm-specific version
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -5,14 +5,14 @@ import kotlinx.benchmark.Scope
|
|||||||
import kotlinx.benchmark.State
|
import kotlinx.benchmark.State
|
||||||
import space.kscience.kmath.complex.Complex
|
import space.kscience.kmath.complex.Complex
|
||||||
import space.kscience.kmath.complex.complex
|
import space.kscience.kmath.complex.complex
|
||||||
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import space.kscience.kmath.structures.MutableBuffer
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
import space.kscience.kmath.structures.RealBuffer
|
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
internal class BufferBenchmark {
|
internal class BufferBenchmark {
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun genericRealBufferReadWrite() {
|
fun genericDoubleBufferReadWrite() {
|
||||||
val buffer = RealBuffer(size) { it.toDouble() }
|
val buffer = DoubleBuffer(size) { it.toDouble() }
|
||||||
|
|
||||||
(0 until size).forEach {
|
(0 until size).forEach {
|
||||||
buffer[it]
|
buffer[it]
|
||||||
|
@ -8,7 +8,7 @@ import space.kscience.kmath.commons.linear.CMLinearSpace
|
|||||||
import space.kscience.kmath.ejml.EjmlLinearSpace
|
import space.kscience.kmath.ejml.EjmlLinearSpace
|
||||||
import space.kscience.kmath.linear.LinearSpace
|
import space.kscience.kmath.linear.LinearSpace
|
||||||
import space.kscience.kmath.linear.invoke
|
import space.kscience.kmath.linear.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
@ -51,7 +51,7 @@ internal class DotBenchmark {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun bufferedDot(blackhole: Blackhole) {
|
fun bufferedDot(blackhole: Blackhole) {
|
||||||
LinearSpace.auto(RealField).invoke {
|
LinearSpace.auto(DoubleField).invoke {
|
||||||
blackhole.consume(matrix1 dot matrix2)
|
blackhole.consume(matrix1 dot matrix2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import space.kscience.kmath.expressions.Expression
|
|||||||
import space.kscience.kmath.expressions.expressionInField
|
import space.kscience.kmath.expressions.expressionInField
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.expressions.symbol
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.operations.bindSymbol
|
import space.kscience.kmath.operations.bindSymbol
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ internal class ExpressionsInterpretersBenchmark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private val algebra = RealField
|
private val algebra = DoubleField
|
||||||
private val x by symbol
|
private val x by symbol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import kotlinx.benchmark.Blackhole
|
|||||||
import kotlinx.benchmark.Scope
|
import kotlinx.benchmark.Scope
|
||||||
import kotlinx.benchmark.State
|
import kotlinx.benchmark.State
|
||||||
import space.kscience.kmath.nd.*
|
import space.kscience.kmath.nd.*
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
@ -13,7 +13,7 @@ internal class NDFieldBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun autoFieldAdd(blackhole: Blackhole) {
|
fun autoFieldAdd(blackhole: Blackhole) {
|
||||||
with(autoField) {
|
with(autoField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += one }
|
repeat(n) { res += one }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ internal class NDFieldBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun specializedFieldAdd(blackhole: Blackhole) {
|
fun specializedFieldAdd(blackhole: Blackhole) {
|
||||||
with(specializedField) {
|
with(specializedField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ internal class NDFieldBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun boxingFieldAdd(blackhole: Blackhole) {
|
fun boxingFieldAdd(blackhole: Blackhole) {
|
||||||
with(genericField) {
|
with(genericField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -41,8 +41,8 @@ internal class NDFieldBenchmark {
|
|||||||
private companion object {
|
private companion object {
|
||||||
private const val dim = 1000
|
private const val dim = 1000
|
||||||
private const val n = 100
|
private const val n = 100
|
||||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||||
private val specializedField = NDAlgebra.real(dim, dim)
|
private val specializedField = AlgebraND.real(dim, dim)
|
||||||
private val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@ import kotlinx.benchmark.Blackhole
|
|||||||
import kotlinx.benchmark.Scope
|
import kotlinx.benchmark.Scope
|
||||||
import kotlinx.benchmark.State
|
import kotlinx.benchmark.State
|
||||||
import org.jetbrains.bio.viktor.F64Array
|
import org.jetbrains.bio.viktor.F64Array
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.nd.auto
|
import space.kscience.kmath.nd.auto
|
||||||
import space.kscience.kmath.nd.real
|
import space.kscience.kmath.nd.real
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.viktor.ViktorNDField
|
import space.kscience.kmath.viktor.ViktorNDField
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
@ -17,7 +17,7 @@ internal class ViktorBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun automaticFieldAddition(blackhole: Blackhole) {
|
fun automaticFieldAddition(blackhole: Blackhole) {
|
||||||
with(autoField) {
|
with(autoField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ internal class ViktorBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun realFieldAddition(blackhole: Blackhole) {
|
fun realFieldAddition(blackhole: Blackhole) {
|
||||||
with(realField) {
|
with(realField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -54,8 +54,8 @@ internal class ViktorBenchmark {
|
|||||||
private const val n = 100
|
private const val n = 100
|
||||||
|
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||||
private val realField = NDAlgebra.real(dim, dim)
|
private val realField = AlgebraND.real(dim, dim)
|
||||||
private val viktorField = ViktorNDField(dim, dim)
|
private val viktorField = ViktorNDField(dim, dim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@ import kotlinx.benchmark.Blackhole
|
|||||||
import kotlinx.benchmark.Scope
|
import kotlinx.benchmark.Scope
|
||||||
import kotlinx.benchmark.State
|
import kotlinx.benchmark.State
|
||||||
import org.jetbrains.bio.viktor.F64Array
|
import org.jetbrains.bio.viktor.F64Array
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
import space.kscience.kmath.nd.auto
|
import space.kscience.kmath.nd.auto
|
||||||
import space.kscience.kmath.nd.real
|
import space.kscience.kmath.nd.real
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.viktor.ViktorNDField
|
import space.kscience.kmath.viktor.ViktorFieldND
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
internal class ViktorLogBenchmark {
|
internal class ViktorLogBenchmark {
|
||||||
@ -46,8 +46,8 @@ internal class ViktorLogBenchmark {
|
|||||||
private const val n = 100
|
private const val n = 100
|
||||||
|
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||||
private val realNdField = NDAlgebra.real(dim, dim)
|
private val realNdField = AlgebraND.real(dim, dim)
|
||||||
private val viktorField = ViktorNDField(intArrayOf(dim, dim))
|
private val viktorField = ViktorFieldND(intArrayOf(dim, dim))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package space.kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val expr = RealField.mstInField {
|
val expr = DoubleField.mstInField {
|
||||||
val x = bindSymbol("x")
|
val x = bindSymbol("x")
|
||||||
x * 2.0 + number(2.0) / x - 16.0
|
x * 2.0 + number(2.0) / x - 16.0
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import space.kscience.kmath.expressions.derivative
|
|||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.expressions.symbol
|
||||||
import space.kscience.kmath.kotlingrad.differentiable
|
import space.kscience.kmath.kotlingrad.differentiable
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
|
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
|
||||||
@ -14,11 +14,11 @@ import space.kscience.kmath.operations.RealField
|
|||||||
fun main() {
|
fun main() {
|
||||||
val x by symbol
|
val x by symbol
|
||||||
|
|
||||||
val actualDerivative = MstExpression(RealField, "x^2-4*x-44".parseMath())
|
val actualDerivative = MstExpression(DoubleField, "x^2-4*x-44".parseMath())
|
||||||
.differentiable()
|
.differentiable()
|
||||||
.derivative(x)
|
.derivative(x)
|
||||||
.compile()
|
.compile()
|
||||||
|
|
||||||
val expectedDerivative = MstExpression(RealField, "2*x-4".parseMath()).compile()
|
val expectedDerivative = MstExpression(DoubleField, "2*x-4".parseMath()).compile()
|
||||||
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
|
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import kscience.plotly.models.TraceValues
|
|||||||
import space.kscience.kmath.commons.optimization.chiSquared
|
import space.kscience.kmath.commons.optimization.chiSquared
|
||||||
import space.kscience.kmath.commons.optimization.minimize
|
import space.kscience.kmath.commons.optimization.minimize
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.expressions.symbol
|
||||||
import space.kscience.kmath.real.RealVector
|
import space.kscience.kmath.real.DoubleVector
|
||||||
import space.kscience.kmath.real.map
|
import space.kscience.kmath.real.map
|
||||||
import space.kscience.kmath.real.step
|
import space.kscience.kmath.real.step
|
||||||
import space.kscience.kmath.stat.*
|
import space.kscience.kmath.stat.*
|
||||||
@ -26,7 +26,7 @@ private val c by symbol
|
|||||||
/**
|
/**
|
||||||
* Shortcut to use buffers in plotly
|
* Shortcut to use buffers in plotly
|
||||||
*/
|
*/
|
||||||
operator fun TraceValues.invoke(vector: RealVector) {
|
operator fun TraceValues.invoke(vector: DoubleVector) {
|
||||||
numbers = vector.asIterable()
|
numbers = vector.asIterable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package space.kscience.kmath.linear
|
package space.kscience.kmath.linear
|
||||||
|
|
||||||
import space.kscience.kmath.real.*
|
import space.kscience.kmath.real.*
|
||||||
import space.kscience.kmath.structures.RealBuffer
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val x0 = Point(0.0, 0.0, 0.0)
|
val x0 = DoubleVector(0.0, 0.0, 0.0)
|
||||||
val sigma = Point(1.0, 1.0, 1.0)
|
val sigma = DoubleVector(1.0, 1.0, 1.0)
|
||||||
|
|
||||||
val gaussian: (Point<Double>) -> Double = { x ->
|
val gaussian: (Point<Double>) -> Double = { x ->
|
||||||
require(x.size == x0.size)
|
require(x.size == x0.size)
|
||||||
@ -14,9 +14,9 @@ fun main() {
|
|||||||
|
|
||||||
fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> {
|
fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> {
|
||||||
require(x.size == x0.size)
|
require(x.size == x0.size)
|
||||||
return RealBuffer(x.size) { i ->
|
return DoubleBuffer(x.size) { i ->
|
||||||
val h = sigma[i] / 5
|
val h = sigma[i] / 5
|
||||||
val dVector = RealBuffer(x.size) { if (it == i) h else 0.0 }
|
val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
|
||||||
val f1 = invoke(x + dVector / 2)
|
val f1 = invoke(x + dVector / 2)
|
||||||
val f0 = invoke(x - dVector / 2)
|
val f0 = invoke(x - dVector / 2)
|
||||||
(f1 - f0) / h
|
(f1 - f0) / h
|
||||||
|
@ -2,17 +2,17 @@ package space.kscience.kmath.operations
|
|||||||
|
|
||||||
import space.kscience.kmath.complex.Complex
|
import space.kscience.kmath.complex.Complex
|
||||||
import space.kscience.kmath.complex.complex
|
import space.kscience.kmath.complex.complex
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
// 2d element
|
// 2d element
|
||||||
val element = NDAlgebra.complex(2, 2).produce { (i, j) ->
|
val element = AlgebraND.complex(2, 2).produce { (i, j) ->
|
||||||
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
||||||
}
|
}
|
||||||
println(element)
|
println(element)
|
||||||
|
|
||||||
// 1d element operation
|
// 1d element operation
|
||||||
val result = with(NDAlgebra.complex(8)) {
|
val result = with(AlgebraND.complex(8)) {
|
||||||
val a = produce { (it) -> i * it - it.toDouble() }
|
val a = produce { (it) -> i * it - it.toDouble() }
|
||||||
val b = 3
|
val b = 3
|
||||||
val c = Complex(1.0, 1.0)
|
val c = Complex(1.0, 1.0)
|
||||||
|
@ -4,8 +4,8 @@ package space.kscience.kmath.structures
|
|||||||
|
|
||||||
import space.kscience.kmath.complex.*
|
import space.kscience.kmath.complex.*
|
||||||
import space.kscience.kmath.linear.transpose
|
import space.kscience.kmath.linear.transpose
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.nd.as2D
|
import space.kscience.kmath.nd.as2D
|
||||||
import space.kscience.kmath.nd.real
|
import space.kscience.kmath.nd.real
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
@ -15,12 +15,12 @@ fun main() {
|
|||||||
val dim = 1000
|
val dim = 1000
|
||||||
val n = 1000
|
val n = 1000
|
||||||
|
|
||||||
val realField = NDAlgebra.real(dim, dim)
|
val realField = AlgebraND.real(dim, dim)
|
||||||
val complexField: ComplexNDField = NDAlgebra.complex(dim, dim)
|
val complexField: ComplexFieldND = AlgebraND.complex(dim, dim)
|
||||||
|
|
||||||
val realTime = measureTimeMillis {
|
val realTime = measureTimeMillis {
|
||||||
realField {
|
realField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) {
|
repeat(n) {
|
||||||
res += 1.0
|
res += 1.0
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ fun main() {
|
|||||||
|
|
||||||
val complexTime = measureTimeMillis {
|
val complexTime = measureTimeMillis {
|
||||||
complexField {
|
complexField {
|
||||||
var res: NDStructure<Complex> = one
|
var res: StructureND<Complex> = one
|
||||||
repeat(n) {
|
repeat(n) {
|
||||||
res += 1.0
|
res += 1.0
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import kotlinx.coroutines.GlobalScope
|
|||||||
import org.nd4j.linalg.factory.Nd4j
|
import org.nd4j.linalg.factory.Nd4j
|
||||||
import space.kscience.kmath.nd.*
|
import space.kscience.kmath.nd.*
|
||||||
import space.kscience.kmath.nd4j.Nd4jArrayField
|
import space.kscience.kmath.nd4j.Nd4jArrayField
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import space.kscience.kmath.viktor.ViktorNDField
|
import space.kscience.kmath.viktor.ViktorNDField
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
@ -24,56 +24,56 @@ fun main() {
|
|||||||
val n = 1000
|
val n = 1000
|
||||||
|
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
val autoField = NDAlgebra.auto(RealField, dim, dim)
|
val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||||
// specialized nd-field for Double. It works as generic Double field as well
|
// specialized nd-field for Double. It works as generic Double field as well
|
||||||
val realField = NDAlgebra.real(dim, dim)
|
val realField = AlgebraND.real(dim, dim)
|
||||||
//A generic boxing field. It should be used for objects, not primitives.
|
//A generic boxing field. It should be used for objects, not primitives.
|
||||||
val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||||
// Nd4j specialized field.
|
// Nd4j specialized field.
|
||||||
val nd4jField = Nd4jArrayField.real(dim, dim)
|
val nd4jField = Nd4jArrayField.real(dim, dim)
|
||||||
//viktor field
|
//viktor field
|
||||||
val viktorField = ViktorNDField(dim, dim)
|
val viktorField = ViktorNDField(dim, dim)
|
||||||
//parallel processing based on Java Streams
|
//parallel processing based on Java Streams
|
||||||
val parallelField = NDAlgebra.realWithStream(dim,dim)
|
val parallelField = AlgebraND.realWithStream(dim, dim)
|
||||||
|
|
||||||
measureAndPrint("Boxing addition") {
|
measureAndPrint("Boxing addition") {
|
||||||
boxingField {
|
boxingField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Specialized addition") {
|
measureAndPrint("Specialized addition") {
|
||||||
realField {
|
realField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Nd4j specialized addition") {
|
measureAndPrint("Nd4j specialized addition") {
|
||||||
nd4jField {
|
nd4jField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Viktor addition") {
|
measureAndPrint("Viktor addition") {
|
||||||
viktorField {
|
viktorField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Parallel stream addition") {
|
measureAndPrint("Parallel stream addition") {
|
||||||
parallelField {
|
parallelField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Automatic field addition") {
|
measureAndPrint("Automatic field addition") {
|
||||||
autoField {
|
autoField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,107 +0,0 @@
|
|||||||
package space.kscience.kmath.structures
|
|
||||||
|
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
|
||||||
import space.kscience.kmath.nd.*
|
|
||||||
import space.kscience.kmath.operations.ExtendedField
|
|
||||||
import space.kscience.kmath.operations.NumbersAddOperations
|
|
||||||
import space.kscience.kmath.operations.RealField
|
|
||||||
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>,
|
|
||||||
NumbersAddOperations<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 NDStructure<Double>.unaryMinus(): NDStructure<Double> = map { -it }
|
|
||||||
|
|
||||||
override fun scale(a: NDStructure<Double>, value: Double): NDStructure<Double> = a.map { it * value }
|
|
||||||
|
|
||||||
override fun power(arg: NDStructure<Double>, pow: Number): NDBuffer<Double> = arg.map { power(it, pow) }
|
|
||||||
|
|
||||||
override fun exp(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { exp(it) }
|
|
||||||
|
|
||||||
override fun ln(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { ln(it) }
|
|
||||||
|
|
||||||
override fun sin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { sin(it) }
|
|
||||||
override fun cos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { cos(it) }
|
|
||||||
override fun tan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { tan(it) }
|
|
||||||
override fun asin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { asin(it) }
|
|
||||||
override fun acos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { acos(it) }
|
|
||||||
override fun atan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { atan(it) }
|
|
||||||
|
|
||||||
override fun sinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { sinh(it) }
|
|
||||||
override fun cosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { cosh(it) }
|
|
||||||
override fun tanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { tanh(it) }
|
|
||||||
override fun asinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { asinh(it) }
|
|
||||||
override fun acosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { acosh(it) }
|
|
||||||
override fun atanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { atanh(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun NDAlgebra.Companion.realWithStream(vararg shape: Int): StreamRealNDField = StreamRealNDField(shape)
|
|
@ -0,0 +1,107 @@
|
|||||||
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.nd.*
|
||||||
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.ExtendedField
|
||||||
|
import space.kscience.kmath.operations.NumbersAddOperations
|
||||||
|
import java.util.*
|
||||||
|
import java.util.stream.IntStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A demonstration implementation of NDField over Real using Java [DoubleStream] for parallel execution
|
||||||
|
*/
|
||||||
|
@OptIn(UnstableKMathAPI::class)
|
||||||
|
class StreamDoubleFieldND(
|
||||||
|
override val shape: IntArray,
|
||||||
|
) : FieldND<Double, DoubleField>,
|
||||||
|
NumbersAddOperations<StructureND<Double>>,
|
||||||
|
ExtendedField<StructureND<Double>> {
|
||||||
|
|
||||||
|
private val strides = DefaultStrides(shape)
|
||||||
|
override val elementContext: DoubleField get() = DoubleField
|
||||||
|
override val zero: BufferND<Double> by lazy { produce { zero } }
|
||||||
|
override val one: BufferND<Double> by lazy { produce { one } }
|
||||||
|
|
||||||
|
override fun number(value: Number): BufferND<Double> {
|
||||||
|
val d = value.toDouble() // minimize conversions
|
||||||
|
return produce { d }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val StructureND<Double>.buffer: DoubleBuffer
|
||||||
|
get() = when {
|
||||||
|
!shape.contentEquals(this@StreamDoubleFieldND.shape) -> throw ShapeMismatchException(
|
||||||
|
this@StreamDoubleFieldND.shape,
|
||||||
|
shape
|
||||||
|
)
|
||||||
|
this is BufferND && this.strides == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer
|
||||||
|
else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND<Double> {
|
||||||
|
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
|
||||||
|
val index = strides.index(offset)
|
||||||
|
DoubleField.initializer(index)
|
||||||
|
}.toArray()
|
||||||
|
|
||||||
|
return BufferND(strides, array.asBuffer())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun StructureND<Double>.map(
|
||||||
|
transform: DoubleField.(Double) -> Double,
|
||||||
|
): BufferND<Double> {
|
||||||
|
val array = Arrays.stream(buffer.array).parallel().map { DoubleField.transform(it) }.toArray()
|
||||||
|
return BufferND(strides, array.asBuffer())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun StructureND<Double>.mapIndexed(
|
||||||
|
transform: DoubleField.(index: IntArray, Double) -> Double,
|
||||||
|
): BufferND<Double> {
|
||||||
|
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
|
||||||
|
DoubleField.transform(
|
||||||
|
strides.index(offset),
|
||||||
|
buffer.array[offset]
|
||||||
|
)
|
||||||
|
}.toArray()
|
||||||
|
|
||||||
|
return BufferND(strides, array.asBuffer())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun combine(
|
||||||
|
a: StructureND<Double>,
|
||||||
|
b: StructureND<Double>,
|
||||||
|
transform: DoubleField.(Double, Double) -> Double,
|
||||||
|
): BufferND<Double> {
|
||||||
|
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
|
||||||
|
DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset])
|
||||||
|
}.toArray()
|
||||||
|
return BufferND(strides, array.asBuffer())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun StructureND<Double>.unaryMinus(): StructureND<Double> = map { -it }
|
||||||
|
|
||||||
|
override fun scale(a: StructureND<Double>, value: Double): StructureND<Double> = a.map { it * value }
|
||||||
|
|
||||||
|
override fun power(arg: StructureND<Double>, pow: Number): BufferND<Double> = arg.map { power(it, pow) }
|
||||||
|
|
||||||
|
override fun exp(arg: StructureND<Double>): BufferND<Double> = arg.map { exp(it) }
|
||||||
|
|
||||||
|
override fun ln(arg: StructureND<Double>): BufferND<Double> = arg.map { ln(it) }
|
||||||
|
|
||||||
|
override fun sin(arg: StructureND<Double>): BufferND<Double> = arg.map { sin(it) }
|
||||||
|
override fun cos(arg: StructureND<Double>): BufferND<Double> = arg.map { cos(it) }
|
||||||
|
override fun tan(arg: StructureND<Double>): BufferND<Double> = arg.map { tan(it) }
|
||||||
|
override fun asin(arg: StructureND<Double>): BufferND<Double> = arg.map { asin(it) }
|
||||||
|
override fun acos(arg: StructureND<Double>): BufferND<Double> = arg.map { acos(it) }
|
||||||
|
override fun atan(arg: StructureND<Double>): BufferND<Double> = arg.map { atan(it) }
|
||||||
|
|
||||||
|
override fun sinh(arg: StructureND<Double>): BufferND<Double> = arg.map { sinh(it) }
|
||||||
|
override fun cosh(arg: StructureND<Double>): BufferND<Double> = arg.map { cosh(it) }
|
||||||
|
override fun tanh(arg: StructureND<Double>): BufferND<Double> = arg.map { tanh(it) }
|
||||||
|
override fun asinh(arg: StructureND<Double>): BufferND<Double> = arg.map { asinh(it) }
|
||||||
|
override fun acosh(arg: StructureND<Double>): BufferND<Double> = arg.map { acosh(it) }
|
||||||
|
override fun atanh(arg: StructureND<Double>): BufferND<Double> = arg.map { atanh(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AlgebraND.Companion.realWithStream(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(shape)
|
@ -1,16 +1,16 @@
|
|||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.kmath.nd.BufferND
|
||||||
import space.kscience.kmath.nd.DefaultStrides
|
import space.kscience.kmath.nd.DefaultStrides
|
||||||
import space.kscience.kmath.nd.NDBuffer
|
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||||
fun main() {
|
fun main() {
|
||||||
val n = 6000
|
val n = 6000
|
||||||
val array = DoubleArray(n * n) { 1.0 }
|
val array = DoubleArray(n * n) { 1.0 }
|
||||||
val buffer = RealBuffer(array)
|
val buffer = DoubleBuffer(array)
|
||||||
val strides = DefaultStrides(intArrayOf(n, n))
|
val strides = DefaultStrides(intArrayOf(n, n))
|
||||||
val structure = NDBuffer(strides, buffer)
|
val structure = BufferND(strides, buffer)
|
||||||
|
|
||||||
measureTimeMillis {
|
measureTimeMillis {
|
||||||
var res = 0.0
|
var res = 0.0
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.nd.mapToBuffer
|
import space.kscience.kmath.nd.mapToBuffer
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
@Suppress("UNUSED_VARIABLE")
|
@Suppress("UNUSED_VARIABLE")
|
||||||
fun main() {
|
fun main() {
|
||||||
val n = 6000
|
val n = 6000
|
||||||
val structure = NDStructure.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
val structure = StructureND.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
||||||
structure.mapToBuffer { it + 1 } // warm-up
|
structure.mapToBuffer { it + 1 } // warm-up
|
||||||
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
|
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
|
||||||
println("Structure mapping finished in $time1 millis")
|
println("Structure mapping finished in $time1 millis")
|
||||||
@ -20,10 +20,10 @@ fun main() {
|
|||||||
|
|
||||||
println("Array mapping finished in $time2 millis")
|
println("Array mapping finished in $time2 millis")
|
||||||
|
|
||||||
val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
|
val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 })
|
||||||
|
|
||||||
val time3 = measureTimeMillis {
|
val time3 = measureTimeMillis {
|
||||||
val target = RealBuffer(DoubleArray(n * n))
|
val target = DoubleBuffer(DoubleArray(n * n))
|
||||||
val res = array.forEachIndexed { index, value ->
|
val res = array.forEachIndexed { index, value ->
|
||||||
target[index] = value + 1
|
target[index] = value + 1
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
|
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||||
kotlin.mpp.stability.nowarn=true
|
kotlin.mpp.stability.nowarn=true
|
||||||
|
kotlin.native.enableDependencyPropagation=false
|
||||||
kotlin.parallel.tasks.in.project=true
|
kotlin.parallel.tasks.in.project=true
|
||||||
org.gradle.configureondemand=true
|
org.gradle.configureondemand=true
|
||||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
|
org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
|
||||||
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
|
||||||
kotlin.native.enableDependencyPropagation=false
|
|
||||||
|
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
This subproject implements the following features:
|
This subproject implements the following features:
|
||||||
|
|
||||||
- [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
- [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||||
- [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
- [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||||
- [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
- [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||||
- [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
- [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||||
- [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
- [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||||
- [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
- [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||||
|
|
||||||
|
|
||||||
> #### Artifact:
|
> #### Artifact:
|
||||||
>
|
>
|
||||||
> This module artifact: `space.kscience:kmath-ast:0.2.0`.
|
> This module artifact: `space.kscience:kmath-ast:0.3.0-dev-3`.
|
||||||
>
|
>
|
||||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
|
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
|
||||||
>
|
>
|
||||||
@ -25,13 +25,10 @@ This subproject implements the following features:
|
|||||||
> maven { url 'https://repo.kotlin.link' }
|
> maven { url 'https://repo.kotlin.link' }
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||||
>// Uncomment if repo.kotlin.link is unavailable
|
|
||||||
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
|
||||||
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> dependencies {
|
> dependencies {
|
||||||
> implementation 'space.kscience:kmath-ast:0.2.0'
|
> implementation 'space.kscience:kmath-ast:0.3.0-dev-3'
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
> **Gradle Kotlin DSL:**
|
> **Gradle Kotlin DSL:**
|
||||||
@ -41,13 +38,10 @@ This subproject implements the following features:
|
|||||||
> maven("https://repo.kotlin.link")
|
> maven("https://repo.kotlin.link")
|
||||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
>// Uncomment if repo.kotlin.link is unavailable
|
|
||||||
>// maven("https://dl.bintray.com/mipt-npm/kscience")
|
|
||||||
>// maven("https://dl.bintray.com/mipt-npm/dev")
|
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> dependencies {
|
> dependencies {
|
||||||
> implementation("space.kscience:kmath-ast:0.2.0")
|
> implementation("space.kscience:kmath-ast:0.3.0-dev-3")
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
@ -61,10 +55,10 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
|
|||||||
For example, the following builder:
|
For example, the following builder:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
```
|
```
|
||||||
|
|
||||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
package space.kscience.kmath.asm.generated;
|
package space.kscience.kmath.asm.generated;
|
||||||
@ -94,8 +88,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
|||||||
This API extends MST and MstExpression, so you may optimize as both of them:
|
This API extends MST and MstExpression, so you may optimize as both of them:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
RealField.expression("x+2".parseMath())
|
DoubleField.expression("x+2".parseMath())
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Known issues
|
#### Known issues
|
||||||
@ -109,7 +103,7 @@ RealField.expression("x+2".parseMath())
|
|||||||
A similar feature is also available on JS.
|
A similar feature is also available on JS.
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
```
|
```
|
||||||
|
|
||||||
The code above returns expression implemented with such a JS function:
|
The code above returns expression implemented with such a JS function:
|
||||||
|
@ -58,36 +58,36 @@ readme {
|
|||||||
feature(
|
feature(
|
||||||
id = "expression-language",
|
id = "expression-language",
|
||||||
description = "Expression language and its parser",
|
description = "Expression language and its parser",
|
||||||
ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt"
|
ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst",
|
id = "mst",
|
||||||
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
|
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst-building",
|
id = "mst-building",
|
||||||
description = "MST building algebraic structure",
|
description = "MST building algebraic structure",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst-interpreter",
|
id = "mst-interpreter",
|
||||||
description = "MST interpreter",
|
description = "MST interpreter",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst-jvm-codegen",
|
id = "mst-jvm-codegen",
|
||||||
description = "Dynamic MST to JVM bytecode compiler",
|
description = "Dynamic MST to JVM bytecode compiler",
|
||||||
ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt"
|
ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst-js-codegen",
|
id = "mst-js-codegen",
|
||||||
description = "Dynamic MST to JS compiler",
|
description = "Dynamic MST to JS compiler",
|
||||||
ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt"
|
ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
|
|||||||
For example, the following builder:
|
For example, the following builder:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
```
|
```
|
||||||
|
|
||||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||||
@ -49,8 +49,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
|||||||
This API extends MST and MstExpression, so you may optimize as both of them:
|
This API extends MST and MstExpression, so you may optimize as both of them:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
RealField.expression("x+2".parseMath())
|
DoubleField.expression("x+2".parseMath())
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Known issues
|
#### Known issues
|
||||||
@ -64,7 +64,7 @@ RealField.expression("x+2".parseMath())
|
|||||||
A similar feature is also available on JS.
|
A similar feature is also available on JS.
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
```
|
```
|
||||||
|
|
||||||
The code above returns expression implemented with such a JS function:
|
The code above returns expression implemented with such a JS function:
|
||||||
|
@ -5,7 +5,7 @@ import space.kscience.kmath.complex.ComplexField
|
|||||||
import space.kscience.kmath.complex.toComplex
|
import space.kscience.kmath.complex.toComplex
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.operations.ByteRing
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun realField() {
|
fun realField() {
|
||||||
val res1 = RealField.mstInField {
|
val res1 = DoubleField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
@ -81,7 +81,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
) + zero
|
) + zero
|
||||||
}("x" to 2.0)
|
}("x" to 2.0)
|
||||||
|
|
||||||
val res2 = RealField.mstInField {
|
val res2 = DoubleField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
|
@ -4,7 +4,7 @@ import space.kscience.kmath.ast.mstInExtendedField
|
|||||||
import space.kscience.kmath.ast.mstInField
|
import space.kscience.kmath.ast.mstInField
|
||||||
import space.kscience.kmath.ast.mstInGroup
|
import space.kscience.kmath.ast.mstInGroup
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -12,27 +12,29 @@ import kotlin.test.assertEquals
|
|||||||
internal class TestESTreeOperationsSupport {
|
internal class TestESTreeOperationsSupport {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryOperationInvocation() {
|
fun testUnaryOperationInvocation() {
|
||||||
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile()
|
val expression = DoubleField.mstInGroup { -bindSymbol("x") }.compile()
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-2.0, res)
|
assertEquals(-2.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBinaryOperationInvocation() {
|
fun testBinaryOperationInvocation() {
|
||||||
val expression = RealField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
val expression = DoubleField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-1.0, res)
|
assertEquals(-1.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testConstProductInvocation() {
|
fun testConstProductInvocation() {
|
||||||
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
val res = DoubleField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
||||||
assertEquals(4.0, res)
|
assertEquals(4.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMultipleCalls() {
|
fun testMultipleCalls() {
|
||||||
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile()
|
val e =
|
||||||
|
DoubleField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
|
||||||
|
.compile()
|
||||||
val r = Random(0)
|
val r = Random(0)
|
||||||
var s = 0.0
|
var s = 0.0
|
||||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||||
|
@ -2,50 +2,50 @@ package space.kscience.kmath.estree
|
|||||||
|
|
||||||
import space.kscience.kmath.ast.mstInField
|
import space.kscience.kmath.ast.mstInField
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class TestESTreeSpecialization {
|
internal class TestESTreeSpecialization {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryPlus() {
|
fun testUnaryPlus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(2.0, expr("x" to 2.0))
|
assertEquals(2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryMinus() {
|
fun testUnaryMinus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(-2.0, expr("x" to 2.0))
|
assertEquals(-2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAdd() {
|
fun testAdd() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSine() {
|
fun testSine() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(0.0, expr("x" to 0.0))
|
assertEquals(0.0, expr("x" to 0.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMinus() {
|
fun testMinus() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(0.0, expr("x" to 2.0))
|
assertEquals(0.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDivide() {
|
fun testDivide() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(1.0, expr("x" to 2.0))
|
assertEquals(1.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPower() {
|
fun testPower() {
|
||||||
val expr = RealField
|
val expr = DoubleField
|
||||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||||
.compile()
|
.compile()
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ internal inline fun ClassWriter.visitField(
|
|||||||
descriptor: String,
|
descriptor: String,
|
||||||
signature: String?,
|
signature: String?,
|
||||||
value: Any?,
|
value: Any?,
|
||||||
block: FieldVisitor.() -> Unit
|
block: FieldVisitor.() -> Unit,
|
||||||
): FieldVisitor {
|
): FieldVisitor {
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||||
return visitField(access, name, descriptor, signature, value).apply(block)
|
return visitField(access, name, descriptor, signature, value).apply(block)
|
||||||
|
@ -5,7 +5,7 @@ import space.kscience.kmath.complex.ComplexField
|
|||||||
import space.kscience.kmath.complex.toComplex
|
import space.kscience.kmath.complex.toComplex
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.operations.ByteRing
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun realField() {
|
fun realField() {
|
||||||
val res1 = RealField.mstInField {
|
val res1 = DoubleField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
@ -81,7 +81,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
) + zero
|
) + zero
|
||||||
}("x" to 2.0)
|
}("x" to 2.0)
|
||||||
|
|
||||||
val res2 = RealField.mstInField {
|
val res2 = DoubleField.mstInField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
|
@ -4,7 +4,7 @@ import space.kscience.kmath.ast.mstInExtendedField
|
|||||||
import space.kscience.kmath.ast.mstInField
|
import space.kscience.kmath.ast.mstInField
|
||||||
import space.kscience.kmath.ast.mstInGroup
|
import space.kscience.kmath.ast.mstInGroup
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -12,27 +12,29 @@ import kotlin.test.assertEquals
|
|||||||
internal class TestAsmOperationsSupport {
|
internal class TestAsmOperationsSupport {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryOperationInvocation() {
|
fun testUnaryOperationInvocation() {
|
||||||
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile()
|
val expression = DoubleField.mstInGroup { -bindSymbol("x") }.compile()
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-2.0, res)
|
assertEquals(-2.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBinaryOperationInvocation() {
|
fun testBinaryOperationInvocation() {
|
||||||
val expression = RealField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
val expression = DoubleField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-1.0, res)
|
assertEquals(-1.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testConstProductInvocation() {
|
fun testConstProductInvocation() {
|
||||||
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
val res = DoubleField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
||||||
assertEquals(4.0, res)
|
assertEquals(4.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMultipleCalls() {
|
fun testMultipleCalls() {
|
||||||
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile()
|
val e =
|
||||||
|
DoubleField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
|
||||||
|
.compile()
|
||||||
val r = Random(0)
|
val r = Random(0)
|
||||||
var s = 0.0
|
var s = 0.0
|
||||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||||
|
@ -2,50 +2,50 @@ package space.kscience.kmath.asm
|
|||||||
|
|
||||||
import space.kscience.kmath.ast.mstInField
|
import space.kscience.kmath.ast.mstInField
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class TestAsmSpecialization {
|
internal class TestAsmSpecialization {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryPlus() {
|
fun testUnaryPlus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(2.0, expr("x" to 2.0))
|
assertEquals(2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryMinus() {
|
fun testUnaryMinus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(-2.0, expr("x" to 2.0))
|
assertEquals(-2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAdd() {
|
fun testAdd() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSine() {
|
fun testSine() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
||||||
assertEquals(0.0, expr("x" to 0.0))
|
assertEquals(0.0, expr("x" to 0.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMinus() {
|
fun testMinus() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(0.0, expr("x" to 2.0))
|
assertEquals(0.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDivide() {
|
fun testDivide() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = DoubleField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
||||||
assertEquals(1.0, expr("x" to 2.0))
|
assertEquals(1.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPower() {
|
fun testPower() {
|
||||||
val expr = RealField
|
val expr = DoubleField
|
||||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||||
.compile()
|
.compile()
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package space.kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.operations.Field
|
import space.kscience.kmath.operations.Field
|
||||||
import space.kscience.kmath.operations.RealField
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class ParserPrecedenceTest {
|
internal class ParserPrecedenceTest {
|
||||||
private val f: Field<Double> = RealField
|
private val f: Field<Double> = DoubleField
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
|
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
|
||||||
|
@ -4,7 +4,7 @@ import space.kscience.kmath.complex.Complex
|
|||||||
import space.kscience.kmath.complex.ComplexField
|
import space.kscience.kmath.complex.ComplexField
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.Algebra
|
import space.kscience.kmath.operations.Algebra
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ internal class ParserTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `evaluate MST with unary function`() {
|
fun `evaluate MST with unary function`() {
|
||||||
val mst = "sin(0)".parseMath()
|
val mst = "sin(0)".parseMath()
|
||||||
val res = RealField.evaluate(mst)
|
val res = DoubleField.evaluate(mst)
|
||||||
assertEquals(0.0, res)
|
assertEquals(0.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
package space.kscience.kmath.commons.integration
|
||||||
|
|
||||||
|
import org.apache.commons.math3.analysis.integration.IterativeLegendreGaussIntegrator
|
||||||
|
import org.apache.commons.math3.analysis.integration.SimpsonIntegrator
|
||||||
|
import space.kscience.kmath.integration.*
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration wrapper for Common-maths UnivariateIntegrator
|
||||||
|
*/
|
||||||
|
public class CMIntegrator(
|
||||||
|
private val defaultMaxCalls: Int = 200,
|
||||||
|
public val integratorBuilder: (Integrand) -> org.apache.commons.math3.analysis.integration.UnivariateIntegrator,
|
||||||
|
) : UnivariateIntegrator<Double> {
|
||||||
|
|
||||||
|
public class TargetRelativeAccuracy(public val value: Double) : IntegrandFeature
|
||||||
|
public class TargetAbsoluteAccuracy(public val value: Double) : IntegrandFeature
|
||||||
|
|
||||||
|
public class MinIterations(public val value: Int) : IntegrandFeature
|
||||||
|
public class MaxIterations(public val value: Int) : IntegrandFeature
|
||||||
|
|
||||||
|
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
|
||||||
|
val integrator = integratorBuilder(integrand)
|
||||||
|
val maxCalls = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: defaultMaxCalls
|
||||||
|
val remainingCalls = maxCalls - integrand.calls
|
||||||
|
val range = integrand.getFeature<IntegrationRange<Double>>()?.range
|
||||||
|
?: error("Integration range is not provided")
|
||||||
|
val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive)
|
||||||
|
|
||||||
|
return integrand +
|
||||||
|
IntegrandValue(res) +
|
||||||
|
IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy) +
|
||||||
|
IntegrandRelativeAccuracy(integrator.relativeAccuracy) +
|
||||||
|
IntegrandCalls(integrator.evaluations + integrand.calls)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
/**
|
||||||
|
* Create a Simpson integrator based on [SimpsonIntegrator]
|
||||||
|
*/
|
||||||
|
public fun simpson(defaultMaxCalls: Int = 200): CMIntegrator = CMIntegrator(defaultMaxCalls) { integrand ->
|
||||||
|
val absoluteAccuracy = integrand.getFeature<TargetAbsoluteAccuracy>()?.value
|
||||||
|
?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY
|
||||||
|
val relativeAccuracy = integrand.getFeature<TargetRelativeAccuracy>()?.value
|
||||||
|
?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY
|
||||||
|
val minIterations = integrand.getFeature<MinIterations>()?.value
|
||||||
|
?: SimpsonIntegrator.DEFAULT_MIN_ITERATIONS_COUNT
|
||||||
|
val maxIterations = integrand.getFeature<MaxIterations>()?.value
|
||||||
|
?: SimpsonIntegrator.SIMPSON_MAX_ITERATIONS_COUNT
|
||||||
|
|
||||||
|
SimpsonIntegrator(relativeAccuracy, absoluteAccuracy, minIterations, maxIterations)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Gauss-Legandre integrator based on [IterativeLegendreGaussIntegrator]
|
||||||
|
*/
|
||||||
|
public fun legandre(numPoints: Int, defaultMaxCalls: Int = numPoints * 5): CMIntegrator =
|
||||||
|
CMIntegrator(defaultMaxCalls) { integrand ->
|
||||||
|
val absoluteAccuracy = integrand.getFeature<TargetAbsoluteAccuracy>()?.value
|
||||||
|
?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY
|
||||||
|
val relativeAccuracy = integrand.getFeature<TargetRelativeAccuracy>()?.value
|
||||||
|
?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY
|
||||||
|
val minIterations = integrand.getFeature<MinIterations>()?.value
|
||||||
|
?: IterativeLegendreGaussIntegrator.DEFAULT_MIN_ITERATIONS_COUNT
|
||||||
|
val maxIterations = integrand.getFeature<MaxIterations>()?.value
|
||||||
|
?: IterativeLegendreGaussIntegrator.DEFAULT_MAX_ITERATIONS_COUNT
|
||||||
|
|
||||||
|
IterativeLegendreGaussIntegrator(
|
||||||
|
numPoints,
|
||||||
|
relativeAccuracy,
|
||||||
|
absoluteAccuracy,
|
||||||
|
minIterations,
|
||||||
|
maxIterations
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public var MutableList<IntegrandFeature>.targetAbsoluteAccuracy: Double?
|
||||||
|
get() = filterIsInstance<CMIntegrator.TargetAbsoluteAccuracy>().lastOrNull()?.value
|
||||||
|
set(value) {
|
||||||
|
value?.let { add(CMIntegrator.TargetAbsoluteAccuracy(value)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public var MutableList<IntegrandFeature>.targetRelativeAccuracy: Double?
|
||||||
|
get() = filterIsInstance<CMIntegrator.TargetRelativeAccuracy>().lastOrNull()?.value
|
||||||
|
set(value) {
|
||||||
|
value?.let { add(CMIntegrator.TargetRelativeAccuracy(value)) }
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Alexander Nozik.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package space.kscience.kmath.commons.integration
|
||||||
|
|
||||||
|
import org.apache.commons.math3.analysis.integration.gauss.GaussIntegrator
|
||||||
|
import org.apache.commons.math3.analysis.integration.gauss.GaussIntegratorFactory
|
||||||
|
import space.kscience.kmath.integration.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple one-pass integrator based on Gauss rule
|
||||||
|
*/
|
||||||
|
public class GaussRuleIntegrator(
|
||||||
|
private val numpoints: Int,
|
||||||
|
private var type: GaussRule = GaussRule.LEGANDRE,
|
||||||
|
) : UnivariateIntegrator<Double> {
|
||||||
|
|
||||||
|
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
|
||||||
|
val range = integrand.getFeature<IntegrationRange<Double>>()?.range
|
||||||
|
?: error("Integration range is not provided")
|
||||||
|
val integrator: GaussIntegrator = getIntegrator(range)
|
||||||
|
//TODO check performance
|
||||||
|
val res: Double = integrator.integrate(integrand.function)
|
||||||
|
return integrand + IntegrandValue(res) + IntegrandCalls(integrand.calls + numpoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getIntegrator(range: ClosedRange<Double>): GaussIntegrator {
|
||||||
|
return when (type) {
|
||||||
|
GaussRule.LEGANDRE -> factory.legendre(
|
||||||
|
numpoints,
|
||||||
|
range.start,
|
||||||
|
range.endInclusive
|
||||||
|
)
|
||||||
|
GaussRule.LEGANDREHP -> factory.legendreHighPrecision(
|
||||||
|
numpoints,
|
||||||
|
range.start,
|
||||||
|
range.endInclusive
|
||||||
|
)
|
||||||
|
GaussRule.UNIFORM -> GaussIntegrator(
|
||||||
|
getUniformRule(
|
||||||
|
range.start,
|
||||||
|
range.endInclusive,
|
||||||
|
numpoints
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getUniformRule(
|
||||||
|
min: Double,
|
||||||
|
max: Double,
|
||||||
|
numPoints: Int,
|
||||||
|
): org.apache.commons.math3.util.Pair<DoubleArray, DoubleArray> {
|
||||||
|
assert(numPoints > 2)
|
||||||
|
val points = DoubleArray(numPoints)
|
||||||
|
val weights = DoubleArray(numPoints)
|
||||||
|
val step = (max - min) / (numPoints - 1)
|
||||||
|
points[0] = min
|
||||||
|
for (i in 1 until numPoints) {
|
||||||
|
points[i] = points[i - 1] + step
|
||||||
|
weights[i] = step
|
||||||
|
}
|
||||||
|
return org.apache.commons.math3.util.Pair<DoubleArray, DoubleArray>(points, weights)
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum class GaussRule {
|
||||||
|
UNIFORM, LEGANDRE, LEGANDREHP
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
private val factory: GaussIntegratorFactory = GaussIntegratorFactory()
|
||||||
|
|
||||||
|
public fun integrate(
|
||||||
|
range: ClosedRange<Double>,
|
||||||
|
numPoints: Int = 100,
|
||||||
|
type: GaussRule = GaussRule.LEGANDRE,
|
||||||
|
function: (Double) -> Double,
|
||||||
|
): Double = GaussRuleIntegrator(numPoints, type).integrate(
|
||||||
|
UnivariateIntegrand(function, IntegrationRange(range))
|
||||||
|
).value!!
|
||||||
|
}
|
||||||
|
}
|
@ -3,63 +3,16 @@ package space.kscience.kmath.commons.linear
|
|||||||
import org.apache.commons.math3.linear.*
|
import org.apache.commons.math3.linear.*
|
||||||
import space.kscience.kmath.linear.*
|
import space.kscience.kmath.linear.*
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import space.kscience.kmath.structures.RealBuffer
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.cast
|
import kotlin.reflect.cast
|
||||||
|
|
||||||
public class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
|
public inline class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
|
||||||
public override val rowNum: Int get() = origin.rowDimension
|
public override val rowNum: Int get() = origin.rowDimension
|
||||||
public override val colNum: Int get() = origin.columnDimension
|
public override val colNum: Int get() = origin.columnDimension
|
||||||
|
|
||||||
@UnstableKMathAPI
|
|
||||||
override fun <T : Any> getFeature(type: KClass<T>): T? = when (type) {
|
|
||||||
DiagonalFeature::class -> if (origin is DiagonalMatrix) DiagonalFeature else null
|
|
||||||
|
|
||||||
DeterminantFeature::class, LupDecompositionFeature::class -> object :
|
|
||||||
DeterminantFeature<Double>,
|
|
||||||
LupDecompositionFeature<Double> {
|
|
||||||
private val lup by lazy { LUDecomposition(origin) }
|
|
||||||
override val determinant: Double by lazy { lup.determinant }
|
|
||||||
override val l: Matrix<Double> by lazy { CMMatrix(lup.l) + LFeature }
|
|
||||||
override val u: Matrix<Double> by lazy { CMMatrix(lup.u) + UFeature }
|
|
||||||
override val p: Matrix<Double> by lazy { CMMatrix(lup.p) }
|
|
||||||
}
|
|
||||||
|
|
||||||
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
|
|
||||||
override val l: Matrix<Double> by lazy {
|
|
||||||
val cholesky = CholeskyDecomposition(origin)
|
|
||||||
CMMatrix(cholesky.l) + LFeature
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> {
|
|
||||||
private val qr by lazy { QRDecomposition(origin) }
|
|
||||||
override val q: Matrix<Double> by lazy { CMMatrix(qr.q) + OrthogonalFeature }
|
|
||||||
override val r: Matrix<Double> by lazy { CMMatrix(qr.r) + UFeature }
|
|
||||||
}
|
|
||||||
|
|
||||||
SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Double> {
|
|
||||||
private val sv by lazy { SingularValueDecomposition(origin) }
|
|
||||||
override val u: Matrix<Double> by lazy { CMMatrix(sv.u) }
|
|
||||||
override val s: Matrix<Double> by lazy { CMMatrix(sv.s) }
|
|
||||||
override val v: Matrix<Double> by lazy { CMMatrix(sv.v) }
|
|
||||||
override val singularValues: Point<Double> by lazy { RealBuffer(sv.singularValues) }
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> null
|
|
||||||
}?.let(type::cast)
|
|
||||||
|
|
||||||
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
|
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other !is NDStructure<*>) return false
|
|
||||||
return NDStructure.contentEquals(this, other)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int = origin.hashCode()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline class CMVector(public val origin: RealVector) : Point<Double> {
|
public inline class CMVector(public val origin: RealVector) : Point<Double> {
|
||||||
@ -72,15 +25,15 @@ public inline class CMVector(public val origin: RealVector) : Point<Double> {
|
|||||||
|
|
||||||
public fun RealVector.toPoint(): CMVector = CMVector(this)
|
public fun RealVector.toPoint(): CMVector = CMVector(this)
|
||||||
|
|
||||||
public object CMLinearSpace : LinearSpace<Double, RealField> {
|
public object CMLinearSpace : LinearSpace<Double, DoubleField> {
|
||||||
override val elementAlgebra: RealField get() = RealField
|
override val elementAlgebra: DoubleField get() = DoubleField
|
||||||
|
|
||||||
public override fun buildMatrix(
|
public override fun buildMatrix(
|
||||||
rows: Int,
|
rows: Int,
|
||||||
columns: Int,
|
columns: Int,
|
||||||
initializer: RealField.(i: Int, j: Int) -> Double,
|
initializer: DoubleField.(i: Int, j: Int) -> Double,
|
||||||
): CMMatrix {
|
): CMMatrix {
|
||||||
val array = Array(rows) { i -> DoubleArray(columns) { j -> RealField.initializer(i, j) } }
|
val array = Array(rows) { i -> DoubleArray(columns) { j -> DoubleField.initializer(i, j) } }
|
||||||
return CMMatrix(Array2DRowRealMatrix(array))
|
return CMMatrix(Array2DRowRealMatrix(array))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,8 +55,8 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
|
|||||||
internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this)
|
internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this)
|
||||||
internal fun RealVector.wrap(): CMVector = CMVector(this)
|
internal fun RealVector.wrap(): CMVector = CMVector(this)
|
||||||
|
|
||||||
override fun buildVector(size: Int, initializer: RealField.(Int) -> Double): Point<Double> =
|
override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): Point<Double> =
|
||||||
ArrayRealVector(DoubleArray(size) { RealField.initializer(it) }).wrap()
|
ArrayRealVector(DoubleArray(size) { DoubleField.initializer(it) }).wrap()
|
||||||
|
|
||||||
override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix =
|
override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix =
|
||||||
toCM().origin.add(other.toCM().origin).wrap()
|
toCM().origin.add(other.toCM().origin).wrap()
|
||||||
@ -134,13 +87,54 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
|
|||||||
|
|
||||||
override fun Double.times(v: Point<Double>): CMVector =
|
override fun Double.times(v: Point<Double>): CMVector =
|
||||||
v * this
|
v * this
|
||||||
|
|
||||||
|
@UnstableKMathAPI
|
||||||
|
override fun <F : Any> getFeature(structure: Matrix<Double>, type: KClass<F>): F? {
|
||||||
|
//Return the feature if it is intrinsic to the structure
|
||||||
|
structure.getFeature(type)?.let { return it }
|
||||||
|
|
||||||
|
val origin = structure.toCM().origin
|
||||||
|
|
||||||
|
return when (type) {
|
||||||
|
DiagonalFeature::class -> if (origin is DiagonalMatrix) DiagonalFeature else null
|
||||||
|
|
||||||
|
DeterminantFeature::class, LupDecompositionFeature::class -> object :
|
||||||
|
DeterminantFeature<Double>,
|
||||||
|
LupDecompositionFeature<Double> {
|
||||||
|
private val lup by lazy { LUDecomposition(origin) }
|
||||||
|
override val determinant: Double by lazy { lup.determinant }
|
||||||
|
override val l: Matrix<Double> by lazy { CMMatrix(lup.l) + LFeature }
|
||||||
|
override val u: Matrix<Double> by lazy { CMMatrix(lup.u) + UFeature }
|
||||||
|
override val p: Matrix<Double> by lazy { CMMatrix(lup.p) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix =
|
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
|
||||||
CMMatrix(origin.add(other.origin))
|
override val l: Matrix<Double> by lazy {
|
||||||
|
val cholesky = CholeskyDecomposition(origin)
|
||||||
|
CMMatrix(cholesky.l) + LFeature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public operator fun CMMatrix.minus(other: CMMatrix): CMMatrix =
|
QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> {
|
||||||
CMMatrix(origin.subtract(other.origin))
|
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 }
|
||||||
|
}
|
||||||
|
|
||||||
public infix fun CMMatrix.dot(other: CMMatrix): CMMatrix =
|
SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Double> {
|
||||||
CMMatrix(origin.multiply(other.origin))
|
private val sv by lazy { SingularValueDecomposition(origin) }
|
||||||
|
override val u: Matrix<Double> by lazy { CMMatrix(sv.u) }
|
||||||
|
override val s: Matrix<Double> by lazy { CMMatrix(sv.s) }
|
||||||
|
override val v: Matrix<Double> by lazy { CMMatrix(sv.v) }
|
||||||
|
override val singularValues: Point<Double> by lazy { DoubleBuffer(sv.singularValues) }
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}?.let(type::cast)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix = CMMatrix(origin.add(other.origin))
|
||||||
|
|
||||||
|
public operator fun CMMatrix.minus(other: CMMatrix): CMMatrix = CMMatrix(origin.subtract(other.origin))
|
||||||
|
|
||||||
|
public infix fun CMMatrix.dot(other: CMMatrix): CMMatrix = CMMatrix(origin.multiply(other.origin))
|
||||||
|
@ -14,7 +14,7 @@ public enum class CMDecomposition {
|
|||||||
|
|
||||||
public fun CMLinearSpace.solver(
|
public fun CMLinearSpace.solver(
|
||||||
a: Matrix<Double>,
|
a: Matrix<Double>,
|
||||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||||
): DecompositionSolver = when (decomposition) {
|
): DecompositionSolver = when (decomposition) {
|
||||||
CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver
|
CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver
|
||||||
CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver
|
CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver
|
||||||
@ -26,16 +26,16 @@ public fun CMLinearSpace.solver(
|
|||||||
public fun CMLinearSpace.solve(
|
public fun CMLinearSpace.solve(
|
||||||
a: Matrix<Double>,
|
a: Matrix<Double>,
|
||||||
b: Matrix<Double>,
|
b: Matrix<Double>,
|
||||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||||
): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap()
|
): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap()
|
||||||
|
|
||||||
public fun CMLinearSpace.solve(
|
public fun CMLinearSpace.solve(
|
||||||
a: Matrix<Double>,
|
a: Matrix<Double>,
|
||||||
b: Point<Double>,
|
b: Point<Double>,
|
||||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||||
): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint()
|
): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint()
|
||||||
|
|
||||||
public fun CMLinearSpace.inverse(
|
public fun CMLinearSpace.inverse(
|
||||||
a: Matrix<Double>,
|
a: Matrix<Double>,
|
||||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||||
): CMMatrix = solver(a, decomposition).inverse.wrap()
|
): CMMatrix = solver(a, decomposition).inverse.wrap()
|
||||||
|
@ -19,7 +19,7 @@ import kotlin.reflect.KClass
|
|||||||
public operator fun PointValuePair.component1(): DoubleArray = point
|
public operator fun PointValuePair.component1(): DoubleArray = point
|
||||||
public operator fun PointValuePair.component2(): Double = value
|
public operator fun PointValuePair.component2(): Double = value
|
||||||
|
|
||||||
public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
public class CMOptimizationProblem(override val symbols: List<Symbol>) :
|
||||||
OptimizationProblem<Double>, SymbolIndexer, OptimizationFeature {
|
OptimizationProblem<Double>, SymbolIndexer, OptimizationFeature {
|
||||||
private val optimizationData: HashMap<KClass<out OptimizationData>, OptimizationData> = HashMap()
|
private val optimizationData: HashMap<KClass<out OptimizationData>, OptimizationData> = HashMap()
|
||||||
private var optimizatorBuilder: (() -> MultivariateOptimizer)? = null
|
private var optimizatorBuilder: (() -> MultivariateOptimizer)? = null
|
||||||
|
@ -10,6 +10,7 @@ import space.kscience.kmath.streaming.spread
|
|||||||
import space.kscience.kmath.structures.*
|
import space.kscience.kmath.structures.*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Streaming and buffer transformations
|
* Streaming and buffer transformations
|
||||||
*/
|
*/
|
||||||
@ -17,7 +18,7 @@ public object Transformations {
|
|||||||
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
|
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
|
||||||
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
|
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
|
||||||
|
|
||||||
private fun Buffer<Double>.asArray() = if (this is RealBuffer) {
|
private fun Buffer<Double>.asArray() = if (this is DoubleBuffer) {
|
||||||
array
|
array
|
||||||
} else {
|
} else {
|
||||||
DoubleArray(size) { i -> get(i) }
|
DoubleArray(size) { i -> get(i) }
|
||||||
@ -33,34 +34,34 @@ public object Transformations {
|
|||||||
|
|
||||||
public fun fourier(
|
public fun fourier(
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Complex, Complex> = {
|
): SuspendBufferTransform<Complex, Complex> = {
|
||||||
FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer()
|
FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun realFourier(
|
public fun realFourier(
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Double, Complex> = {
|
): SuspendBufferTransform<Double, Complex> = {
|
||||||
FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun sine(
|
public fun sine(
|
||||||
normalization: DstNormalization = DstNormalization.STANDARD_DST_I,
|
normalization: DstNormalization = DstNormalization.STANDARD_DST_I,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Double, Double> = {
|
): SuspendBufferTransform<Double, Double> = {
|
||||||
FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun cosine(
|
public fun cosine(
|
||||||
normalization: DctNormalization = DctNormalization.STANDARD_DCT_I,
|
normalization: DctNormalization = DctNormalization.STANDARD_DCT_I,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Double, Double> = {
|
): SuspendBufferTransform<Double, Double> = {
|
||||||
FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun hadamard(
|
public fun hadamard(
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Double, Double> = {
|
): SuspendBufferTransform<Double, Double> = {
|
||||||
FastHadamardTransformer().transform(it.asArray(), direction).asBuffer()
|
FastHadamardTransformer().transform(it.asArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
@ -72,7 +73,7 @@ public object Transformations {
|
|||||||
@FlowPreview
|
@FlowPreview
|
||||||
public fun Flow<Buffer<Complex>>.FFT(
|
public fun Flow<Buffer<Complex>>.FFT(
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): Flow<Buffer<Complex>> {
|
): Flow<Buffer<Complex>> {
|
||||||
val transform = Transformations.fourier(normalization, direction)
|
val transform = Transformations.fourier(normalization, direction)
|
||||||
return map { transform(it) }
|
return map { transform(it) }
|
||||||
@ -82,7 +83,7 @@ public fun Flow<Buffer<Complex>>.FFT(
|
|||||||
@JvmName("realFFT")
|
@JvmName("realFFT")
|
||||||
public fun Flow<Buffer<Double>>.FFT(
|
public fun Flow<Buffer<Double>>.FFT(
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): Flow<Buffer<Complex>> {
|
): Flow<Buffer<Complex>> {
|
||||||
val transform = Transformations.realFourier(normalization, direction)
|
val transform = Transformations.realFourier(normalization, direction)
|
||||||
return map(transform)
|
return map(transform)
|
||||||
@ -96,7 +97,7 @@ public fun Flow<Buffer<Double>>.FFT(
|
|||||||
public fun Flow<Double>.FFT(
|
public fun Flow<Double>.FFT(
|
||||||
bufferSize: Int = Int.MAX_VALUE,
|
bufferSize: Int = Int.MAX_VALUE,
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread()
|
): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package space.kscience.kmath.commons.integration
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import space.kscience.kmath.integration.integrate
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.operations.DoubleField.sin
|
||||||
|
import kotlin.math.PI
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
@UnstableKMathAPI
|
||||||
|
internal class IntegrationTest {
|
||||||
|
private val function: (Double) -> Double = { sin(it) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simpson() {
|
||||||
|
val res = CMIntegrator.simpson().integrate(0.0..2 * PI, function)
|
||||||
|
assertTrue { abs(res) < 1e-3 }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun customSimpson() {
|
||||||
|
val res = CMIntegrator.simpson().integrate(0.0..PI, function) {
|
||||||
|
targetRelativeAccuracy = 1e-4
|
||||||
|
targetAbsoluteAccuracy = 1e-4
|
||||||
|
}
|
||||||
|
assertTrue { abs(res - 2) < 1e-3 }
|
||||||
|
assertTrue { abs(res - 2) > 1e-12 }
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
Complex and hypercomplex number systems in KMath:
|
Complex and hypercomplex number systems in KMath:
|
||||||
|
|
||||||
- [complex](src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
- [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||||
- [quaternion](src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
- [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||||
|
|
||||||
|
|
||||||
> #### Artifact:
|
> #### Artifact:
|
||||||
>
|
>
|
||||||
> This module artifact: `space.kscience:kmath-complex:0.2.0`.
|
> This module artifact: `space.kscience:kmath-complex:0.3.0-dev-3`.
|
||||||
>
|
>
|
||||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-complex/_latestVersion)
|
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-complex/_latestVersion)
|
||||||
>
|
>
|
||||||
@ -21,13 +21,10 @@ Complex and hypercomplex number systems in KMath:
|
|||||||
> maven { url 'https://repo.kotlin.link' }
|
> maven { url 'https://repo.kotlin.link' }
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||||
>// Uncomment if repo.kotlin.link is unavailable
|
|
||||||
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
|
||||||
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> dependencies {
|
> dependencies {
|
||||||
> implementation 'space.kscience:kmath-complex:0.2.0'
|
> implementation 'space.kscience:kmath-complex:0.3.0-dev-3'
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
> **Gradle Kotlin DSL:**
|
> **Gradle Kotlin DSL:**
|
||||||
@ -37,12 +34,9 @@ Complex and hypercomplex number systems in KMath:
|
|||||||
> maven("https://repo.kotlin.link")
|
> maven("https://repo.kotlin.link")
|
||||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
>// Uncomment if repo.kotlin.link is unavailable
|
|
||||||
>// maven("https://dl.bintray.com/mipt-npm/kscience")
|
|
||||||
>// maven("https://dl.bintray.com/mipt-npm/dev")
|
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> dependencies {
|
> dependencies {
|
||||||
> implementation("space.kscience:kmath-complex:0.2.0")
|
> implementation("space.kscience:kmath-complex:0.3.0-dev-3")
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
|
@ -25,12 +25,12 @@ readme {
|
|||||||
feature(
|
feature(
|
||||||
id = "complex",
|
id = "complex",
|
||||||
description = "Complex Numbers",
|
description = "Complex Numbers",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/complex/Complex.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "quaternion",
|
id = "quaternion",
|
||||||
description = "Quaternions",
|
description = "Quaternions",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package space.kscience.kmath.complex
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.BufferedNDField
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.BufferND
|
||||||
import space.kscience.kmath.nd.NDBuffer
|
import space.kscience.kmath.nd.BufferedFieldND
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.operations.ExtendedField
|
import space.kscience.kmath.operations.ExtendedField
|
||||||
import space.kscience.kmath.operations.NumbersAddOperations
|
import space.kscience.kmath.operations.NumbersAddOperations
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
@ -16,16 +16,16 @@ import kotlin.contracts.contract
|
|||||||
* An optimized nd-field for complex numbers
|
* An optimized nd-field for complex numbers
|
||||||
*/
|
*/
|
||||||
@OptIn(UnstableKMathAPI::class)
|
@OptIn(UnstableKMathAPI::class)
|
||||||
public class ComplexNDField(
|
public class ComplexFieldND(
|
||||||
shape: IntArray,
|
shape: IntArray,
|
||||||
) : BufferedNDField<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
|
) : BufferedFieldND<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
|
||||||
NumbersAddOperations<NDStructure<Complex>>,
|
NumbersAddOperations<StructureND<Complex>>,
|
||||||
ExtendedField<NDStructure<Complex>> {
|
ExtendedField<StructureND<Complex>> {
|
||||||
|
|
||||||
override val zero: NDBuffer<Complex> by lazy { produce { zero } }
|
override val zero: BufferND<Complex> by lazy { produce { zero } }
|
||||||
override val one: NDBuffer<Complex> by lazy { produce { one } }
|
override val one: BufferND<Complex> by lazy { produce { one } }
|
||||||
|
|
||||||
override fun number(value: Number): NDBuffer<Complex> {
|
override fun number(value: Number): BufferND<Complex> {
|
||||||
val d = value.toComplex() // minimize conversions
|
val d = value.toComplex() // minimize conversions
|
||||||
return produce { d }
|
return produce { d }
|
||||||
}
|
}
|
||||||
@ -34,15 +34,15 @@ public class ComplexNDField(
|
|||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
// override inline fun map(
|
// override inline fun map(
|
||||||
// arg: AbstractNDBuffer<Double>,
|
// arg: AbstractNDBuffer<Double>,
|
||||||
// transform: RealField.(Double) -> Double,
|
// transform: DoubleField.(Double) -> Double,
|
||||||
// ): RealNDElement {
|
// ): RealNDElement {
|
||||||
// check(arg)
|
// check(arg)
|
||||||
// val array = RealBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) }
|
// val array = RealBuffer(arg.strides.linearSize) { offset -> DoubleField.transform(arg.buffer[offset]) }
|
||||||
// return BufferedNDFieldElement(this, array)
|
// return BufferedNDFieldElement(this, array)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
// override inline fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement {
|
// override inline fun produce(initializer: DoubleField.(IntArray) -> Double): RealNDElement {
|
||||||
// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
||||||
// return BufferedNDFieldElement(this, array)
|
// return BufferedNDFieldElement(this, array)
|
||||||
// }
|
// }
|
||||||
@ -50,7 +50,7 @@ public class ComplexNDField(
|
|||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
// override inline fun mapIndexed(
|
// override inline fun mapIndexed(
|
||||||
// arg: AbstractNDBuffer<Double>,
|
// arg: AbstractNDBuffer<Double>,
|
||||||
// transform: RealField.(index: IntArray, Double) -> Double,
|
// transform: DoubleField.(index: IntArray, Double) -> Double,
|
||||||
// ): RealNDElement {
|
// ): RealNDElement {
|
||||||
// check(arg)
|
// check(arg)
|
||||||
// return BufferedNDFieldElement(
|
// return BufferedNDFieldElement(
|
||||||
@ -67,7 +67,7 @@ public class ComplexNDField(
|
|||||||
// override inline fun combine(
|
// override inline fun combine(
|
||||||
// a: AbstractNDBuffer<Double>,
|
// a: AbstractNDBuffer<Double>,
|
||||||
// b: AbstractNDBuffer<Double>,
|
// b: AbstractNDBuffer<Double>,
|
||||||
// transform: RealField.(Double, Double) -> Double,
|
// transform: DoubleField.(Double, Double) -> Double,
|
||||||
// ): RealNDElement {
|
// ): RealNDElement {
|
||||||
// check(a, b)
|
// check(a, b)
|
||||||
// val buffer = RealBuffer(strides.linearSize) { offset ->
|
// val buffer = RealBuffer(strides.linearSize) { offset ->
|
||||||
@ -76,44 +76,44 @@ public class ComplexNDField(
|
|||||||
// return BufferedNDFieldElement(this, buffer)
|
// return BufferedNDFieldElement(this, buffer)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
override fun power(arg: NDStructure<Complex>, pow: Number): NDBuffer<Complex> = arg.map { power(it, pow) }
|
override fun power(arg: StructureND<Complex>, pow: Number): BufferND<Complex> = arg.map { power(it, pow) }
|
||||||
|
|
||||||
override fun exp(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { exp(it) }
|
override fun exp(arg: StructureND<Complex>): BufferND<Complex> = arg.map { exp(it) }
|
||||||
|
|
||||||
override fun ln(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { ln(it) }
|
override fun ln(arg: StructureND<Complex>): BufferND<Complex> = arg.map { ln(it) }
|
||||||
|
|
||||||
override fun sin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { sin(it) }
|
override fun sin(arg: StructureND<Complex>): BufferND<Complex> = arg.map { sin(it) }
|
||||||
override fun cos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { cos(it) }
|
override fun cos(arg: StructureND<Complex>): BufferND<Complex> = arg.map { cos(it) }
|
||||||
override fun tan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { tan(it) }
|
override fun tan(arg: StructureND<Complex>): BufferND<Complex> = arg.map { tan(it) }
|
||||||
override fun asin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { asin(it) }
|
override fun asin(arg: StructureND<Complex>): BufferND<Complex> = arg.map { asin(it) }
|
||||||
override fun acos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { acos(it) }
|
override fun acos(arg: StructureND<Complex>): BufferND<Complex> = arg.map { acos(it) }
|
||||||
override fun atan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { atan(it) }
|
override fun atan(arg: StructureND<Complex>): BufferND<Complex> = arg.map { atan(it) }
|
||||||
|
|
||||||
override fun sinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { sinh(it) }
|
override fun sinh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { sinh(it) }
|
||||||
override fun cosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { cosh(it) }
|
override fun cosh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { cosh(it) }
|
||||||
override fun tanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { tanh(it) }
|
override fun tanh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { tanh(it) }
|
||||||
override fun asinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { asinh(it) }
|
override fun asinh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { asinh(it) }
|
||||||
override fun acosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { acosh(it) }
|
override fun acosh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { acosh(it) }
|
||||||
override fun atanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { atanh(it) }
|
override fun atanh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { atanh(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fast element production using function inlining
|
* Fast element production using function inlining
|
||||||
*/
|
*/
|
||||||
public inline fun BufferedNDField<Complex, ComplexField>.produceInline(initializer: ComplexField.(Int) -> Complex): NDBuffer<Complex> {
|
public inline fun BufferedFieldND<Complex, ComplexField>.produceInline(initializer: ComplexField.(Int) -> Complex): BufferND<Complex> {
|
||||||
contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) }
|
||||||
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) }
|
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) }
|
||||||
return NDBuffer(strides, buffer)
|
return BufferND(strides, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public fun NDAlgebra.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape)
|
public fun AlgebraND.Companion.complex(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produce a context for n-dimensional operations inside this real field
|
* Produce a context for n-dimensional operations inside this real field
|
||||||
*/
|
*/
|
||||||
public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R {
|
public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexFieldND.() -> R): R {
|
||||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||||
return ComplexNDField(shape).action()
|
return ComplexFieldND(shape).action()
|
||||||
}
|
}
|
49
kmath-core/README.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# The Core Module (`kmath-core`)
|
||||||
|
|
||||||
|
The core features of KMath:
|
||||||
|
|
||||||
|
- [algebras](src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||||
|
- [nd](src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
|
||||||
|
- [linear](src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||||
|
- [buffers](src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||||
|
- [expressions](src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||||
|
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||||
|
performance calculations to code generation.
|
||||||
|
- [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
|
||||||
|
- [autodif](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||||
|
|
||||||
|
|
||||||
|
> #### Artifact:
|
||||||
|
>
|
||||||
|
> This module artifact: `space.kscience:kmath-core:0.3.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 development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
|
||||||
|
>
|
||||||
|
> **Gradle:**
|
||||||
|
>
|
||||||
|
> ```gradle
|
||||||
|
> repositories {
|
||||||
|
> maven { url 'https://repo.kotlin.link' }
|
||||||
|
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||||
|
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> dependencies {
|
||||||
|
> implementation 'space.kscience:kmath-core:0.3.0-dev-3'
|
||||||
|
> }
|
||||||
|
> ```
|
||||||
|
> **Gradle Kotlin DSL:**
|
||||||
|
>
|
||||||
|
> ```kotlin
|
||||||
|
> repositories {
|
||||||
|
> maven("https://repo.kotlin.link")
|
||||||
|
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
|
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> dependencies {
|
||||||
|
> implementation("space.kscience:kmath-core:0.3.0-dev-3")
|
||||||
|
> }
|
||||||
|
> ```
|
@ -23,13 +23,13 @@ readme {
|
|||||||
description = """
|
description = """
|
||||||
Algebraic structures like rings, spaces and fields.
|
Algebraic structures like rings, spaces and fields.
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "nd",
|
id = "nd",
|
||||||
description = "Many-dimensional structures and operations on them.",
|
description = "Many-dimensional structures and operations on them.",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
@ -37,13 +37,13 @@ readme {
|
|||||||
description = """
|
description = """
|
||||||
Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.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/space/kscience/kmath/structures/Buffers.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
@ -53,18 +53,18 @@ readme {
|
|||||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
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.
|
performance calculations to code generation.
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/expressions"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/expressions"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "domains",
|
id = "domains",
|
||||||
description = "Domains",
|
description = "Domains",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/domains"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/domains"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "autodif",
|
id = "autodif",
|
||||||
description = "Automatic differentiation",
|
description = "Automatic differentiation",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI
|
|||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public interface RealDomain : Domain<Double> {
|
public interface DoubleDomain : Domain<Double> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global lower edge
|
* Global lower edge
|
@ -27,7 +27,7 @@ import space.kscience.kmath.structures.indices
|
|||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public class HyperSquareDomain(private val lower: Buffer<Double>, private val upper: Buffer<Double>) : RealDomain {
|
public class HyperSquareDomain(private val lower: Buffer<Double>, private val upper: Buffer<Double>) : DoubleDomain {
|
||||||
public override val dimension: Int get() = lower.size
|
public override val dimension: Int get() = lower.size
|
||||||
|
|
||||||
public override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i ->
|
public override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i ->
|
||||||
|
@ -19,7 +19,7 @@ import space.kscience.kmath.linear.Point
|
|||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public class UnconstrainedDomain(public override val dimension: Int) : RealDomain {
|
public class UnconstrainedDomain(public override val dimension: Int) : DoubleDomain {
|
||||||
public override operator fun contains(point: Point<Double>): Boolean = true
|
public override operator fun contains(point: Point<Double>): Boolean = true
|
||||||
|
|
||||||
public override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY
|
public override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY
|
||||||
|
@ -4,7 +4,7 @@ import space.kscience.kmath.linear.Point
|
|||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public inline class UnivariateDomain(public val range: ClosedFloatingPointRange<Double>) : RealDomain {
|
public inline class UnivariateDomain(public val range: ClosedFloatingPointRange<Double>) : DoubleDomain {
|
||||||
public override val dimension: Int get() = 1
|
public override val dimension: Int get() = 1
|
||||||
|
|
||||||
public operator fun contains(d: Double): Boolean = range.contains(d)
|
public operator fun contains(d: Double): Boolean = range.contains(d)
|
||||||
|
@ -198,7 +198,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
|
|||||||
* Example:
|
* Example:
|
||||||
* ```
|
* ```
|
||||||
* val x by symbol // define variable(s) and their values
|
* val x by symbol // define variable(s) and their values
|
||||||
* val y = RealField.withAutoDiff() { sqr(x) + 5 * x + 3 } // write formulate in deriv context
|
* val y = DoubleField.withAutoDiff() { sqr(x) + 5 * x + 3 } // write formulate in deriv context
|
||||||
* assertEquals(17.0, y.x) // the value of result (y)
|
* assertEquals(17.0, y.x) // the value of result (y)
|
||||||
* assertEquals(9.0, x.d) // dy/dx
|
* assertEquals(9.0, x.d) // dy/dx
|
||||||
* ```
|
* ```
|
||||||
|
@ -9,7 +9,7 @@ import space.kscience.kmath.structures.VirtualBuffer
|
|||||||
import space.kscience.kmath.structures.indices
|
import space.kscience.kmath.structures.indices
|
||||||
|
|
||||||
|
|
||||||
public class BufferLinearSpace<T : Any, A : Ring<T>>(
|
public class BufferedLinearSpace<T : Any, A : Ring<T>>(
|
||||||
override val elementAlgebra: A,
|
override val elementAlgebra: A,
|
||||||
private val bufferFactory: BufferFactory<T>,
|
private val bufferFactory: BufferFactory<T>,
|
||||||
) : LinearSpace<T, A> {
|
) : LinearSpace<T, A> {
|
||||||
@ -17,7 +17,7 @@ public class BufferLinearSpace<T : Any, A : Ring<T>>(
|
|||||||
private fun ndRing(
|
private fun ndRing(
|
||||||
rows: Int,
|
rows: Int,
|
||||||
cols: Int,
|
cols: Int,
|
||||||
): BufferedNDRing<T, A> = NDAlgebra.ring(elementAlgebra, bufferFactory, rows, cols)
|
): BufferedRingND<T, A> = AlgebraND.ring(elementAlgebra, bufferFactory, rows, cols)
|
||||||
|
|
||||||
override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix<T> =
|
override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix<T> =
|
||||||
ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D()
|
ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D()
|
@ -6,9 +6,20 @@ import space.kscience.kmath.nd.as1D
|
|||||||
* A group of methods to resolve equation A dot X = B, where A and B are matrices or vectors
|
* A group of methods to resolve equation A dot X = B, where A and B are matrices or vectors
|
||||||
*/
|
*/
|
||||||
public interface LinearSolver<T : Any> {
|
public interface LinearSolver<T : Any> {
|
||||||
|
/**
|
||||||
|
* Solve a dot x = b matrix equation and return x
|
||||||
|
*/
|
||||||
public fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T>
|
public fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solve a dot x = b vector equation and return b
|
||||||
|
*/
|
||||||
public fun solve(a: Matrix<T>, b: Point<T>): Point<T> = solve(a, b.asMatrix()).asVector()
|
public fun solve(a: Matrix<T>, b: Point<T>): Point<T> = solve(a, b.asMatrix()).asVector()
|
||||||
public fun inverse(a: Matrix<T>): Matrix<T>
|
|
||||||
|
/**
|
||||||
|
* Get inverse of a matrix
|
||||||
|
*/
|
||||||
|
public fun inverse(matrix: Matrix<T>): Matrix<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,6 +5,7 @@ import space.kscience.kmath.nd.*
|
|||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.BufferFactory
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,16 +156,15 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
|
|||||||
public operator fun T.times(v: Point<T>): Point<T> = v * this
|
public operator fun T.times(v: Point<T>): Point<T> = v * this
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a feature from the matrix. This function may return some additional features to
|
* Get a feature of the structure in this scope. Structure features take precedence other context features
|
||||||
* [space.kscience.kmath.nd.NDStructure.getFeature].
|
|
||||||
*
|
*
|
||||||
* @param F the type of feature.
|
* @param F the type of feature.
|
||||||
* @param m the matrix.
|
* @param structure the structure.
|
||||||
* @param type the [KClass] instance of [F].
|
* @param type the [KClass] instance of [F].
|
||||||
* @return a feature object or `null` if it isn't present.
|
* @return a feature object or `null` if it isn't present.
|
||||||
*/
|
*/
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public fun <F : Any> getFeature(m: Matrix<T>, type: KClass<F>): F? = m.getFeature(type)
|
public fun <F : Any> getFeature(structure: Matrix<T>, type: KClass<F>): F? = structure.getFeature(type)
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
|
||||||
@ -174,9 +174,9 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
|
|||||||
public fun <T : Any, A : Ring<T>> buffered(
|
public fun <T : Any, A : Ring<T>> buffered(
|
||||||
algebra: A,
|
algebra: A,
|
||||||
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
||||||
): LinearSpace<T, A> = BufferLinearSpace(algebra,bufferFactory)
|
): LinearSpace<T, A> = BufferedLinearSpace(algebra, bufferFactory)
|
||||||
|
|
||||||
public val real: LinearSpace<Double, RealField> = buffered(RealField, Buffer.Companion::real)
|
public val real: LinearSpace<Double, DoubleField> = buffered(DoubleField, ::DoubleBuffer)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatic buffered matrix, unboxed if it is possible
|
* Automatic buffered matrix, unboxed if it is possible
|
||||||
@ -186,19 +186,17 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public operator fun <LS : LinearSpace<*, *>, R> LS.invoke(block: LS.() -> R): R = run(block)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a feature from the matrix. This function may return some additional features to
|
* Get a feature of the structure in this scope. Structure features take precedence other context features
|
||||||
* [space.kscience.kmath.nd.NDStructure.getFeature].
|
|
||||||
*
|
*
|
||||||
* @param T the type of items in the matrices.
|
* @param T the type of items in the matrices.
|
||||||
* @param M the type of operated matrices.
|
|
||||||
* @param F the type of feature.
|
* @param F the type of feature.
|
||||||
* @receiver the [LinearSpace] of [T].
|
|
||||||
* @param m the matrix.
|
|
||||||
* @return a feature object or `null` if it isn't present.
|
* @return a feature object or `null` if it isn't present.
|
||||||
*/
|
*/
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public inline fun <T : Any, reified F : Any> LinearSpace<T, *>.getFeature(m: Matrix<T>): F? = getFeature(m, F::class)
|
public inline fun <T : Any, reified F : Any> LinearSpace<T, *>.getFeature(structure: Matrix<T>): F? =
|
||||||
|
getFeature(structure, F::class)
|
||||||
|
|
||||||
|
|
||||||
|
public operator fun <LS : LinearSpace<*, *>, R> LS.invoke(block: LS.() -> R): R = run(block)
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ package space.kscience.kmath.linear
|
|||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.getFeature
|
import space.kscience.kmath.nd.getFeature
|
||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
import space.kscience.kmath.structures.Buffer
|
|
||||||
import space.kscience.kmath.structures.BufferAccessor2D
|
import space.kscience.kmath.structures.BufferAccessor2D
|
||||||
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import space.kscience.kmath.structures.MutableBuffer
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
import space.kscience.kmath.structures.MutableBufferFactory
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
|
|
||||||
@ -151,8 +151,8 @@ public inline fun <reified T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
|
|||||||
noinline checkSingular: (T) -> Boolean,
|
noinline checkSingular: (T) -> Boolean,
|
||||||
): LupDecomposition<T> = lup(MutableBuffer.Companion::auto, matrix, checkSingular)
|
): LupDecomposition<T> = lup(MutableBuffer.Companion::auto, matrix, checkSingular)
|
||||||
|
|
||||||
public fun LinearSpace<Double, RealField>.lup(matrix: Matrix<Double>): LupDecomposition<Double> =
|
public fun LinearSpace<Double, DoubleField>.lup(matrix: Matrix<Double>): LupDecomposition<Double> =
|
||||||
lup(Buffer.Companion::real, matrix) { it < 1e-11 }
|
lup(::DoubleBuffer, matrix) { it < 1e-11 }
|
||||||
|
|
||||||
public fun <T : Any> LupDecomposition<T>.solveWithLup(
|
public fun <T : Any> LupDecomposition<T>.solveWithLup(
|
||||||
factory: MutableBufferFactory<T>,
|
factory: MutableBufferFactory<T>,
|
||||||
@ -228,9 +228,9 @@ public inline fun <reified T : Comparable<T>> LinearSpace<T, Field<T>>.inverseWi
|
|||||||
|
|
||||||
|
|
||||||
@OptIn(UnstableKMathAPI::class)
|
@OptIn(UnstableKMathAPI::class)
|
||||||
public fun LinearSpace<Double, RealField>.solveWithLup(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> {
|
public fun LinearSpace<Double, DoubleField>.solveWithLup(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> {
|
||||||
// Use existing decomposition if it is provided by matrix
|
// Use existing decomposition if it is provided by matrix
|
||||||
val bufferFactory: MutableBufferFactory<Double> = MutableBuffer.Companion::real
|
val bufferFactory: MutableBufferFactory<Double> = ::DoubleBuffer
|
||||||
val decomposition: LupDecomposition<Double> = a.getFeature() ?: lup(bufferFactory, a) { it < 1e-11 }
|
val decomposition: LupDecomposition<Double> = a.getFeature() ?: lup(bufferFactory, a) { it < 1e-11 }
|
||||||
return decomposition.solveWithLup(bufferFactory, b)
|
return decomposition.solveWithLup(bufferFactory, b)
|
||||||
}
|
}
|
||||||
@ -238,5 +238,5 @@ public fun LinearSpace<Double, RealField>.solveWithLup(a: Matrix<Double>, b: Mat
|
|||||||
/**
|
/**
|
||||||
* Inverses a square matrix using LUP decomposition. Non square matrix will throw a error.
|
* Inverses a square matrix using LUP decomposition. Non square matrix will throw a error.
|
||||||
*/
|
*/
|
||||||
public fun LinearSpace<Double, RealField>.inverseWithLup(matrix: Matrix<Double>): Matrix<Double> =
|
public fun LinearSpace<Double, DoubleField>.inverseWithLup(matrix: Matrix<Double>): Matrix<Double> =
|
||||||
solveWithLup(matrix, one(matrix.rowNum, matrix.colNum))
|
solveWithLup(matrix, one(matrix.rowNum, matrix.colNum))
|
@ -23,8 +23,6 @@ public class MatrixWrapper<T : Any> internal constructor(
|
|||||||
override fun <T : Any> getFeature(type: KClass<T>): T? = features.singleOrNull { type.isInstance(it) } as? T
|
override fun <T : Any> getFeature(type: KClass<T>): T? = features.singleOrNull { type.isInstance(it) } as? T
|
||||||
?: origin.getFeature(type)
|
?: origin.getFeature(type)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean = origin == other
|
|
||||||
override fun hashCode(): Int = origin.hashCode()
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "MatrixWrapper(matrix=$origin, features=$features)"
|
return "MatrixWrapper(matrix=$origin, features=$features)"
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package space.kscience.kmath.linear
|
package space.kscience.kmath.linear
|
||||||
|
|
||||||
import space.kscience.kmath.nd.NDStructure
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The matrix where each element is evaluated each time when is being accessed.
|
* The matrix where each element is evaluated each time when is being accessed.
|
||||||
*
|
*
|
||||||
@ -10,23 +8,10 @@ import space.kscience.kmath.nd.NDStructure
|
|||||||
public class VirtualMatrix<T : Any>(
|
public class VirtualMatrix<T : Any>(
|
||||||
override val rowNum: Int,
|
override val rowNum: Int,
|
||||||
override val colNum: Int,
|
override val colNum: Int,
|
||||||
public val generator: (i: Int, j: Int) -> T
|
public val generator: (i: Int, j: Int) -> T,
|
||||||
) : Matrix<T> {
|
) : Matrix<T> {
|
||||||
|
|
||||||
override val shape: IntArray get() = intArrayOf(rowNum, colNum)
|
override val shape: IntArray get() = intArrayOf(rowNum, colNum)
|
||||||
|
|
||||||
override operator fun get(i: Int, j: Int): T = generator(i, j)
|
override operator fun get(i: Int, j: Int): T = generator(i, j)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other !is NDStructure<*>) return false
|
|
||||||
return NDStructure.contentEquals(this, other)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = rowNum
|
|
||||||
result = 31 * result + colNum
|
|
||||||
result = 31 * result + generator.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ public fun <T, R> List<T>.cumulative(initial: R, operation: (R, T) -> R): List<R
|
|||||||
/**
|
/**
|
||||||
* Cumulative sum with custom space
|
* Cumulative sum with custom space
|
||||||
*/
|
*/
|
||||||
public fun <T> Iterable<T>.cumulativeSum(space: Group<T>): Iterable<T> =
|
public fun <T> Iterable<T>.cumulativeSum(group: Group<T>): Iterable<T> =
|
||||||
space { cumulative(zero) { element: T, sum: T -> sum + element } }
|
group { cumulative(zero) { element: T, sum: T -> sum + element } }
|
||||||
|
|
||||||
@JvmName("cumulativeSumOfDouble")
|
@JvmName("cumulativeSumOfDouble")
|
||||||
public fun Iterable<Double>.cumulativeSum(): Iterable<Double> = cumulative(0.0) { element, sum -> sum + element }
|
public fun Iterable<Double>.cumulativeSum(): Iterable<Double> = cumulative(0.0) { element, sum -> sum + element }
|
||||||
@ -49,8 +49,8 @@ public fun Iterable<Int>.cumulativeSum(): Iterable<Int> = cumulative(0) { elemen
|
|||||||
@JvmName("cumulativeSumOfLong")
|
@JvmName("cumulativeSumOfLong")
|
||||||
public fun Iterable<Long>.cumulativeSum(): Iterable<Long> = cumulative(0L) { element, sum -> sum + element }
|
public fun Iterable<Long>.cumulativeSum(): Iterable<Long> = cumulative(0L) { element, sum -> sum + element }
|
||||||
|
|
||||||
public fun <T> Sequence<T>.cumulativeSum(space: Group<T>): Sequence<T> =
|
public fun <T> Sequence<T>.cumulativeSum(group: Group<T>): Sequence<T> =
|
||||||
space { cumulative(zero) { element: T, sum: T -> sum + element } }
|
group { cumulative(zero) { element: T, sum: T -> sum + element } }
|
||||||
|
|
||||||
@JvmName("cumulativeSumOfDouble")
|
@JvmName("cumulativeSumOfDouble")
|
||||||
public fun Sequence<Double>.cumulativeSum(): Sequence<Double> = cumulative(0.0) { element, sum -> sum + element }
|
public fun Sequence<Double>.cumulativeSum(): Sequence<Double> = cumulative(0.0) { element, sum -> sum + element }
|
||||||
@ -61,8 +61,8 @@ public fun Sequence<Int>.cumulativeSum(): Sequence<Int> = cumulative(0) { elemen
|
|||||||
@JvmName("cumulativeSumOfLong")
|
@JvmName("cumulativeSumOfLong")
|
||||||
public fun Sequence<Long>.cumulativeSum(): Sequence<Long> = cumulative(0L) { element, sum -> sum + element }
|
public fun Sequence<Long>.cumulativeSum(): Sequence<Long> = cumulative(0L) { element, sum -> sum + element }
|
||||||
|
|
||||||
public fun <T> List<T>.cumulativeSum(space: Group<T>): List<T> =
|
public fun <T> List<T>.cumulativeSum(group: Group<T>): List<T> =
|
||||||
space { cumulative(zero) { element: T, sum: T -> sum + element } }
|
group { cumulative(zero) { element: T, sum: T -> sum + element } }
|
||||||
|
|
||||||
@JvmName("cumulativeSumOfDouble")
|
@JvmName("cumulativeSumOfDouble")
|
||||||
public fun List<Double>.cumulativeSum(): List<Double> = cumulative(0.0) { element, sum -> sum + element }
|
public fun List<Double>.cumulativeSum(): List<Double> = cumulative(0.0) { element, sum -> sum + element }
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package space.kscience.kmath.nd
|
package space.kscience.kmath.nd
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
import space.kscience.kmath.structures.*
|
import space.kscience.kmath.structures.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An exception is thrown when the expected ans actual shape of NDArray differs.
|
* An exception is thrown when the expected ans actual shape of NDArray differs.
|
||||||
@ -19,7 +21,7 @@ public class ShapeMismatchException(public val expected: IntArray, public val ac
|
|||||||
* @param C the type of the element context.
|
* @param C the type of the element context.
|
||||||
* @param N the type of the structure.
|
* @param N the type of the structure.
|
||||||
*/
|
*/
|
||||||
public interface NDAlgebra<T, C: Algebra<T>> {
|
public interface AlgebraND<T, C : Algebra<T>> {
|
||||||
/**
|
/**
|
||||||
* The shape of ND-structures this algebra operates on.
|
* The shape of ND-structures this algebra operates on.
|
||||||
*/
|
*/
|
||||||
@ -33,42 +35,66 @@ public interface NDAlgebra<T, C: Algebra<T>> {
|
|||||||
/**
|
/**
|
||||||
* Produces a new NDStructure using given initializer function.
|
* Produces a new NDStructure using given initializer function.
|
||||||
*/
|
*/
|
||||||
public fun produce(initializer: C.(IntArray) -> T): NDStructure<T>
|
public fun produce(initializer: C.(IntArray) -> T): StructureND<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps elements from one structure to another one by applying [transform] to them.
|
* Maps elements from one structure to another one by applying [transform] to them.
|
||||||
*/
|
*/
|
||||||
public fun NDStructure<T>.map(transform: C.(T) -> T): NDStructure<T>
|
public fun StructureND<T>.map(transform: C.(T) -> T): StructureND<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps elements from one structure to another one by applying [transform] to them alongside with their indices.
|
* 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>
|
public fun StructureND<T>.mapIndexed(transform: C.(index: IntArray, T) -> T): StructureND<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combines two structures into one.
|
* Combines two structures into one.
|
||||||
*/
|
*/
|
||||||
public fun combine(a: NDStructure<T>, b: NDStructure<T>, transform: C.(T, T) -> T): NDStructure<T>
|
public fun combine(a: StructureND<T>, b: StructureND<T>, transform: C.(T, T) -> T): StructureND<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Element-wise invocation of function working on [T] on a [NDStructure].
|
* Element-wise invocation of function working on [T] on a [StructureND].
|
||||||
*/
|
*/
|
||||||
public operator fun Function1<T, T>.invoke(structure: NDStructure<T>): NDStructure<T> =
|
public operator fun Function1<T, T>.invoke(structure: StructureND<T>): StructureND<T> =
|
||||||
structure.map { value -> this@invoke(value) }
|
structure.map { value -> this@invoke(value) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a feature of the structure in this scope. Structure features take precedence other context features
|
||||||
|
*
|
||||||
|
* @param F the type of feature.
|
||||||
|
* @param structure the structure.
|
||||||
|
* @param type the [KClass] instance of [F].
|
||||||
|
* @return a feature object or `null` if it isn't present.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <F : Any> getFeature(structure: StructureND<T>, type: KClass<F>): F? = structure.getFeature(type)
|
||||||
|
|
||||||
public companion object
|
public companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a feature of the structure in this scope. Structure features take precedence other context features
|
||||||
|
*
|
||||||
|
* @param T the type of items in the matrices.
|
||||||
|
* @param F the type of feature.
|
||||||
|
* @return a feature object or `null` if it isn't present.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public inline fun <T : Any, reified F : Any> AlgebraND<T, *>.getFeature(structure: StructureND<T>): F? =
|
||||||
|
getFeature(structure, F::class)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if given elements are consistent with this context.
|
* Checks if given elements are consistent with this context.
|
||||||
*
|
*
|
||||||
* @param structures the structures to check.
|
* @param structures the structures to check.
|
||||||
* @return the array of valid structures.
|
* @return the array of valid structures.
|
||||||
*/
|
*/
|
||||||
internal fun <T, C: Algebra<T>> NDAlgebra<T, C>.checkShape(vararg structures: NDStructure<T>): Array<out NDStructure<T>> = structures
|
internal fun <T, C : Algebra<T>> AlgebraND<T, C>.checkShape(vararg structures: StructureND<T>): Array<out StructureND<T>> =
|
||||||
.map(NDStructure<T>::shape)
|
structures
|
||||||
|
.map(StructureND<T>::shape)
|
||||||
.singleOrNull { !shape.contentEquals(it) }
|
.singleOrNull { !shape.contentEquals(it) }
|
||||||
?.let<IntArray, Array<out NDStructure<T>>> { throw ShapeMismatchException(shape, it) }
|
?.let<IntArray, Array<out StructureND<T>>> { throw ShapeMismatchException(shape, it) }
|
||||||
?: structures
|
?: structures
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,19 +103,19 @@ internal fun <T, C: Algebra<T>> NDAlgebra<T, C>.checkShape(vararg structures: ND
|
|||||||
* @param element the structure to check.
|
* @param element the structure to check.
|
||||||
* @return the valid structure.
|
* @return the valid structure.
|
||||||
*/
|
*/
|
||||||
internal fun <T, C: Algebra<T>> NDAlgebra<T, C>.checkShape(element: NDStructure<T>): NDStructure<T> {
|
internal fun <T, C : Algebra<T>> AlgebraND<T, C>.checkShape(element: StructureND<T>): StructureND<T> {
|
||||||
if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape)
|
if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape)
|
||||||
return element
|
return element
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Space of [NDStructure].
|
* Space of [StructureND].
|
||||||
*
|
*
|
||||||
* @param T the type of the element contained in ND structure.
|
* @param T the type of the element contained in ND structure.
|
||||||
* @param N the type of ND structure.
|
* @param N the type of ND structure.
|
||||||
* @param S the type of space of structure elements.
|
* @param S the type of space of structure elements.
|
||||||
*/
|
*/
|
||||||
public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T, S> {
|
public interface GroupND<T, S : Group<T>> : Group<StructureND<T>>, AlgebraND<T, S> {
|
||||||
/**
|
/**
|
||||||
* Element-wise addition.
|
* Element-wise addition.
|
||||||
*
|
*
|
||||||
@ -97,7 +123,7 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
|||||||
* @param b the augend.
|
* @param b the augend.
|
||||||
* @return the sum.
|
* @return the sum.
|
||||||
*/
|
*/
|
||||||
public override fun add(a: NDStructure<T>, b: NDStructure<T>): NDStructure<T> =
|
public override fun add(a: StructureND<T>, b: StructureND<T>): StructureND<T> =
|
||||||
combine(a, b) { aValue, bValue -> add(aValue, bValue) }
|
combine(a, b) { aValue, bValue -> add(aValue, bValue) }
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
@ -118,7 +144,7 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
|||||||
* @param arg the augend.
|
* @param arg the augend.
|
||||||
* @return the sum.
|
* @return the sum.
|
||||||
*/
|
*/
|
||||||
public operator fun NDStructure<T>.plus(arg: T): NDStructure<T> = this.map { value -> add(arg, value) }
|
public operator fun StructureND<T>.plus(arg: T): StructureND<T> = this.map { value -> add(arg, value) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subtracts an element from ND structure of it.
|
* Subtracts an element from ND structure of it.
|
||||||
@ -127,7 +153,7 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
|||||||
* @param arg the divisor.
|
* @param arg the divisor.
|
||||||
* @return the quotient.
|
* @return the quotient.
|
||||||
*/
|
*/
|
||||||
public operator fun NDStructure<T>.minus(arg: T): NDStructure<T> = this.map { value -> add(arg, -value) }
|
public operator fun StructureND<T>.minus(arg: T): StructureND<T> = this.map { value -> add(arg, -value) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an element to ND structure of it.
|
* Adds an element to ND structure of it.
|
||||||
@ -136,7 +162,7 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
|||||||
* @param arg the augend.
|
* @param arg the augend.
|
||||||
* @return the sum.
|
* @return the sum.
|
||||||
*/
|
*/
|
||||||
public operator fun T.plus(arg: NDStructure<T>): NDStructure<T> = arg.map { value -> add(this@plus, value) }
|
public operator fun T.plus(arg: StructureND<T>): StructureND<T> = arg.map { value -> add(this@plus, value) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subtracts an ND structure from an element of it.
|
* Subtracts an ND structure from an element of it.
|
||||||
@ -145,19 +171,19 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
|||||||
* @param arg the divisor.
|
* @param arg the divisor.
|
||||||
* @return the quotient.
|
* @return the quotient.
|
||||||
*/
|
*/
|
||||||
public operator fun T.minus(arg: NDStructure<T>): NDStructure<T> = arg.map { value -> add(-this@minus, value) }
|
public operator fun T.minus(arg: StructureND<T>): StructureND<T> = arg.map { value -> add(-this@minus, value) }
|
||||||
|
|
||||||
public companion object
|
public companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ring of [NDStructure].
|
* Ring of [StructureND].
|
||||||
*
|
*
|
||||||
* @param T the type of the element contained in ND structure.
|
* @param T the type of the element contained in ND structure.
|
||||||
* @param N the type of ND structure.
|
* @param N the type of ND structure.
|
||||||
* @param R the type of ring of structure elements.
|
* @param R the type of ring of structure elements.
|
||||||
*/
|
*/
|
||||||
public interface NDRing<T, R : Ring<T>> : Ring<NDStructure<T>>, NDGroup<T, R> {
|
public interface RingND<T, R : Ring<T>> : Ring<StructureND<T>>, GroupND<T, R> {
|
||||||
/**
|
/**
|
||||||
* Element-wise multiplication.
|
* Element-wise multiplication.
|
||||||
*
|
*
|
||||||
@ -165,7 +191,7 @@ public interface NDRing<T, R : Ring<T>> : Ring<NDStructure<T>>, NDGroup<T, R> {
|
|||||||
* @param b the multiplier.
|
* @param b the multiplier.
|
||||||
* @return the product.
|
* @return the product.
|
||||||
*/
|
*/
|
||||||
public override fun multiply(a: NDStructure<T>, b: NDStructure<T>): NDStructure<T> =
|
public override fun multiply(a: StructureND<T>, b: StructureND<T>): StructureND<T> =
|
||||||
combine(a, b) { aValue, bValue -> multiply(aValue, bValue) }
|
combine(a, b) { aValue, bValue -> multiply(aValue, bValue) }
|
||||||
|
|
||||||
//TODO move to extensions after KEEP-176
|
//TODO move to extensions after KEEP-176
|
||||||
@ -177,7 +203,7 @@ public interface NDRing<T, R : Ring<T>> : Ring<NDStructure<T>>, NDGroup<T, R> {
|
|||||||
* @param arg the multiplier.
|
* @param arg the multiplier.
|
||||||
* @return the product.
|
* @return the product.
|
||||||
*/
|
*/
|
||||||
public operator fun NDStructure<T>.times(arg: T): NDStructure<T> = this.map { value -> multiply(arg, value) }
|
public operator fun StructureND<T>.times(arg: T): StructureND<T> = this.map { value -> multiply(arg, value) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiplies an element by a ND structure of it.
|
* Multiplies an element by a ND structure of it.
|
||||||
@ -186,19 +212,19 @@ public interface NDRing<T, R : Ring<T>> : Ring<NDStructure<T>>, NDGroup<T, R> {
|
|||||||
* @param arg the multiplier.
|
* @param arg the multiplier.
|
||||||
* @return the product.
|
* @return the product.
|
||||||
*/
|
*/
|
||||||
public operator fun T.times(arg: NDStructure<T>): NDStructure<T> = arg.map { value -> multiply(this@times, value) }
|
public operator fun T.times(arg: StructureND<T>): StructureND<T> = arg.map { value -> multiply(this@times, value) }
|
||||||
|
|
||||||
public companion object
|
public companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field of [NDStructure].
|
* Field of [StructureND].
|
||||||
*
|
*
|
||||||
* @param T the type of the element contained in ND structure.
|
* @param T the type of the element contained in ND structure.
|
||||||
* @param N the type of ND structure.
|
* @param N the type of ND structure.
|
||||||
* @param F the type field of structure elements.
|
* @param F the type field of structure elements.
|
||||||
*/
|
*/
|
||||||
public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F>, ScaleOperations<NDStructure<T>> {
|
public interface FieldND<T, F : Field<T>> : Field<StructureND<T>>, RingND<T, F>, ScaleOperations<StructureND<T>> {
|
||||||
/**
|
/**
|
||||||
* Element-wise division.
|
* Element-wise division.
|
||||||
*
|
*
|
||||||
@ -206,7 +232,7 @@ public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F>,
|
|||||||
* @param b the divisor.
|
* @param b the divisor.
|
||||||
* @return the quotient.
|
* @return the quotient.
|
||||||
*/
|
*/
|
||||||
public override fun divide(a: NDStructure<T>, b: NDStructure<T>): NDStructure<T> =
|
public override fun divide(a: StructureND<T>, b: StructureND<T>): StructureND<T> =
|
||||||
combine(a, b) { aValue, bValue -> divide(aValue, bValue) }
|
combine(a, b) { aValue, bValue -> divide(aValue, bValue) }
|
||||||
|
|
||||||
//TODO move to extensions after KEEP-176
|
//TODO move to extensions after KEEP-176
|
||||||
@ -217,7 +243,7 @@ public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F>,
|
|||||||
* @param arg the divisor.
|
* @param arg the divisor.
|
||||||
* @return the quotient.
|
* @return the quotient.
|
||||||
*/
|
*/
|
||||||
public operator fun NDStructure<T>.div(arg: T): NDStructure<T> = this.map { value -> divide(arg, value) }
|
public operator fun StructureND<T>.div(arg: T): StructureND<T> = this.map { value -> divide(arg, value) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Divides an element by an ND structure of it.
|
* Divides an element by an ND structure of it.
|
||||||
@ -226,7 +252,7 @@ public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F>,
|
|||||||
* @param arg the divisor.
|
* @param arg the divisor.
|
||||||
* @return the quotient.
|
* @return the quotient.
|
||||||
*/
|
*/
|
||||||
public operator fun T.div(arg: NDStructure<T>): NDStructure<T> = arg.map { divide(it, this@div) }
|
public operator fun T.div(arg: StructureND<T>): StructureND<T> = arg.map { divide(it, this@div) }
|
||||||
|
|
||||||
// @ThreadLocal
|
// @ThreadLocal
|
||||||
// public companion object {
|
// public companion object {
|
@ -6,132 +6,132 @@ import space.kscience.kmath.structures.BufferFactory
|
|||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
public interface BufferNDAlgebra<T, A : Algebra<T>> : NDAlgebra<T, A> {
|
public interface BufferAlgebraND<T, A : Algebra<T>> : AlgebraND<T, A> {
|
||||||
public val strides: Strides
|
public val strides: Strides
|
||||||
public val bufferFactory: BufferFactory<T>
|
public val bufferFactory: BufferFactory<T>
|
||||||
|
|
||||||
override fun produce(initializer: A.(IntArray) -> T): NDBuffer<T> = NDBuffer(
|
override fun produce(initializer: A.(IntArray) -> T): BufferND<T> = BufferND(
|
||||||
strides,
|
strides,
|
||||||
bufferFactory(strides.linearSize) { offset ->
|
bufferFactory(strides.linearSize) { offset ->
|
||||||
elementContext.initializer(strides.index(offset))
|
elementContext.initializer(strides.index(offset))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
public val NDStructure<T>.buffer: Buffer<T>
|
public val StructureND<T>.buffer: Buffer<T>
|
||||||
get() = when {
|
get() = when {
|
||||||
!shape.contentEquals(this@BufferNDAlgebra.shape) -> throw ShapeMismatchException(
|
!shape.contentEquals(this@BufferAlgebraND.shape) -> throw ShapeMismatchException(
|
||||||
this@BufferNDAlgebra.shape,
|
this@BufferAlgebraND.shape,
|
||||||
shape
|
shape
|
||||||
)
|
)
|
||||||
this is NDBuffer && this.strides == this@BufferNDAlgebra.strides -> this.buffer
|
this is BufferND && this.strides == this@BufferAlgebraND.strides -> this.buffer
|
||||||
else -> bufferFactory(strides.linearSize) { offset -> get(strides.index(offset)) }
|
else -> bufferFactory(strides.linearSize) { offset -> get(strides.index(offset)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun NDStructure<T>.map(transform: A.(T) -> T): NDBuffer<T> {
|
override fun StructureND<T>.map(transform: A.(T) -> T): BufferND<T> {
|
||||||
val buffer = bufferFactory(strides.linearSize) { offset ->
|
val buffer = bufferFactory(strides.linearSize) { offset ->
|
||||||
elementContext.transform(buffer[offset])
|
elementContext.transform(buffer[offset])
|
||||||
}
|
}
|
||||||
return NDBuffer(strides, buffer)
|
return BufferND(strides, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun NDStructure<T>.mapIndexed(transform: A.(index: IntArray, T) -> T): NDBuffer<T> {
|
override fun StructureND<T>.mapIndexed(transform: A.(index: IntArray, T) -> T): BufferND<T> {
|
||||||
val buffer = bufferFactory(strides.linearSize) { offset ->
|
val buffer = bufferFactory(strides.linearSize) { offset ->
|
||||||
elementContext.transform(
|
elementContext.transform(
|
||||||
strides.index(offset),
|
strides.index(offset),
|
||||||
buffer[offset]
|
buffer[offset]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return NDBuffer(strides, buffer)
|
return BufferND(strides, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun combine(a: NDStructure<T>, b: NDStructure<T>, transform: A.(T, T) -> T): NDBuffer<T> {
|
override fun combine(a: StructureND<T>, b: StructureND<T>, transform: A.(T, T) -> T): BufferND<T> {
|
||||||
val buffer = bufferFactory(strides.linearSize) { offset ->
|
val buffer = bufferFactory(strides.linearSize) { offset ->
|
||||||
elementContext.transform(a.buffer[offset], b.buffer[offset])
|
elementContext.transform(a.buffer[offset], b.buffer[offset])
|
||||||
}
|
}
|
||||||
return NDBuffer(strides, buffer)
|
return BufferND(strides, buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public open class BufferedNDGroup<T, A : Group<T>>(
|
public open class BufferedGroupND<T, A : Group<T>>(
|
||||||
final override val shape: IntArray,
|
final override val shape: IntArray,
|
||||||
final override val elementContext: A,
|
final override val elementContext: A,
|
||||||
final override val bufferFactory: BufferFactory<T>,
|
final override val bufferFactory: BufferFactory<T>,
|
||||||
) : NDGroup<T, A>, BufferNDAlgebra<T, A> {
|
) : GroupND<T, A>, BufferAlgebraND<T, A> {
|
||||||
override val strides: Strides = DefaultStrides(shape)
|
override val strides: Strides = DefaultStrides(shape)
|
||||||
override val zero: NDBuffer<T> by lazy { produce { zero } }
|
override val zero: BufferND<T> by lazy { produce { zero } }
|
||||||
override fun NDStructure<T>.unaryMinus(): NDStructure<T> = produce { -get(it) }
|
override fun StructureND<T>.unaryMinus(): StructureND<T> = produce { -get(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public open class BufferedNDRing<T, R : Ring<T>>(
|
public open class BufferedRingND<T, R : Ring<T>>(
|
||||||
shape: IntArray,
|
shape: IntArray,
|
||||||
elementContext: R,
|
elementContext: R,
|
||||||
bufferFactory: BufferFactory<T>,
|
bufferFactory: BufferFactory<T>,
|
||||||
) : BufferedNDGroup<T, R>(shape, elementContext, bufferFactory), NDRing<T, R> {
|
) : BufferedGroupND<T, R>(shape, elementContext, bufferFactory), RingND<T, R> {
|
||||||
override val one: NDBuffer<T> by lazy { produce { one } }
|
override val one: BufferND<T> by lazy { produce { one } }
|
||||||
}
|
}
|
||||||
|
|
||||||
public open class BufferedNDField<T, R : Field<T>>(
|
public open class BufferedFieldND<T, R : Field<T>>(
|
||||||
shape: IntArray,
|
shape: IntArray,
|
||||||
elementContext: R,
|
elementContext: R,
|
||||||
bufferFactory: BufferFactory<T>,
|
bufferFactory: BufferFactory<T>,
|
||||||
) : BufferedNDRing<T, R>(shape, elementContext, bufferFactory), NDField<T, R> {
|
) : BufferedRingND<T, R>(shape, elementContext, bufferFactory), FieldND<T, R> {
|
||||||
|
|
||||||
override fun scale(a: NDStructure<T>, value: Double): NDStructure<T> = a.map { it * value }
|
override fun scale(a: StructureND<T>, value: Double): StructureND<T> = a.map { it * value }
|
||||||
}
|
}
|
||||||
|
|
||||||
// group factories
|
// group factories
|
||||||
public fun <T, A : Group<T>> NDAlgebra.Companion.group(
|
public fun <T, A : Group<T>> AlgebraND.Companion.group(
|
||||||
space: A,
|
space: A,
|
||||||
bufferFactory: BufferFactory<T>,
|
bufferFactory: BufferFactory<T>,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
): BufferedNDGroup<T, A> = BufferedNDGroup(shape, space, bufferFactory)
|
): BufferedGroupND<T, A> = BufferedGroupND(shape, space, bufferFactory)
|
||||||
|
|
||||||
public inline fun <T, A : Group<T>, R> A.ndGroup(
|
public inline fun <T, A : Group<T>, R> A.ndGroup(
|
||||||
noinline bufferFactory: BufferFactory<T>,
|
noinline bufferFactory: BufferFactory<T>,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
action: BufferedNDGroup<T, A>.() -> R,
|
action: BufferedGroupND<T, A>.() -> R,
|
||||||
): R {
|
): R {
|
||||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||||
return NDAlgebra.group(this, bufferFactory, *shape).run(action)
|
return AlgebraND.group(this, bufferFactory, *shape).run(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ring factories
|
//ring factories
|
||||||
public fun <T, A : Ring<T>> NDAlgebra.Companion.ring(
|
public fun <T, A : Ring<T>> AlgebraND.Companion.ring(
|
||||||
ring: A,
|
ring: A,
|
||||||
bufferFactory: BufferFactory<T>,
|
bufferFactory: BufferFactory<T>,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
): BufferedNDRing<T, A> = BufferedNDRing(shape, ring, bufferFactory)
|
): BufferedRingND<T, A> = BufferedRingND(shape, ring, bufferFactory)
|
||||||
|
|
||||||
public inline fun <T, A : Ring<T>, R> A.ndRing(
|
public inline fun <T, A : Ring<T>, R> A.ndRing(
|
||||||
noinline bufferFactory: BufferFactory<T>,
|
noinline bufferFactory: BufferFactory<T>,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
action: BufferedNDRing<T, A>.() -> R,
|
action: BufferedRingND<T, A>.() -> R,
|
||||||
): R {
|
): R {
|
||||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||||
return NDAlgebra.ring(this, bufferFactory, *shape).run(action)
|
return AlgebraND.ring(this, bufferFactory, *shape).run(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
//field factories
|
//field factories
|
||||||
public fun <T, A : Field<T>> NDAlgebra.Companion.field(
|
public fun <T, A : Field<T>> AlgebraND.Companion.field(
|
||||||
field: A,
|
field: A,
|
||||||
bufferFactory: BufferFactory<T>,
|
bufferFactory: BufferFactory<T>,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
): BufferedNDField<T, A> = BufferedNDField(shape, field, bufferFactory)
|
): BufferedFieldND<T, A> = BufferedFieldND(shape, field, bufferFactory)
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public inline fun <reified T : Any, A : Field<T>> NDAlgebra.Companion.auto(
|
public inline fun <reified T : Any, A : Field<T>> AlgebraND.Companion.auto(
|
||||||
field: A,
|
field: A,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
): NDField<T, A> = when (field) {
|
): FieldND<T, A> = when (field) {
|
||||||
RealField -> RealNDField(shape) as NDField<T, A>
|
DoubleField -> DoubleFieldND(shape) as FieldND<T, A>
|
||||||
else -> BufferedNDField(shape, field, Buffer.Companion::auto)
|
else -> BufferedFieldND(shape, field, Buffer.Companion::auto)
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline fun <T, A : Field<T>, R> A.ndField(
|
public inline fun <T, A : Field<T>, R> A.ndField(
|
||||||
noinline bufferFactory: BufferFactory<T>,
|
noinline bufferFactory: BufferFactory<T>,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
action: BufferedNDField<T, A>.() -> R,
|
action: BufferedFieldND<T, A>.() -> R,
|
||||||
): R {
|
): R {
|
||||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||||
return NDAlgebra.field(this, bufferFactory, *shape).run(action)
|
return AlgebraND.field(this, bufferFactory, *shape).run(action)
|
||||||
}
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package space.kscience.kmath.nd
|
||||||
|
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents [StructureND] 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 class BufferND<T>(
|
||||||
|
public val strides: Strides,
|
||||||
|
public val buffer: Buffer<T>,
|
||||||
|
) : StructureND<T> {
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (strides.linearSize != buffer.size) {
|
||||||
|
error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 toString(): String = StructureND.toString(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferND]
|
||||||
|
*/
|
||||||
|
public inline fun <T, reified R : Any> StructureND<T>.mapToBuffer(
|
||||||
|
factory: BufferFactory<R> = Buffer.Companion::auto,
|
||||||
|
crossinline transform: (T) -> R,
|
||||||
|
): BufferND<R> {
|
||||||
|
return if (this is BufferND<T>)
|
||||||
|
BufferND(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) })
|
||||||
|
else {
|
||||||
|
val strides = DefaultStrides(shape)
|
||||||
|
BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
package space.kscience.kmath.nd
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.ExtendedField
|
||||||
|
import space.kscience.kmath.operations.NumbersAddOperations
|
||||||
|
import space.kscience.kmath.operations.ScaleOperations
|
||||||
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
|
@OptIn(UnstableKMathAPI::class)
|
||||||
|
public class DoubleFieldND(
|
||||||
|
shape: IntArray,
|
||||||
|
) : BufferedFieldND<Double, DoubleField>(shape, DoubleField, ::DoubleBuffer),
|
||||||
|
NumbersAddOperations<StructureND<Double>>,
|
||||||
|
ScaleOperations<StructureND<Double>>,
|
||||||
|
ExtendedField<StructureND<Double>> {
|
||||||
|
|
||||||
|
override val zero: BufferND<Double> by lazy { produce { zero } }
|
||||||
|
override val one: BufferND<Double> by lazy { produce { one } }
|
||||||
|
|
||||||
|
override fun number(value: Number): BufferND<Double> {
|
||||||
|
val d = value.toDouble() // minimize conversions
|
||||||
|
return produce { d }
|
||||||
|
}
|
||||||
|
|
||||||
|
override val StructureND<Double>.buffer: DoubleBuffer
|
||||||
|
get() = when {
|
||||||
|
!shape.contentEquals(this@DoubleFieldND.shape) -> throw ShapeMismatchException(
|
||||||
|
this@DoubleFieldND.shape,
|
||||||
|
shape
|
||||||
|
)
|
||||||
|
this is BufferND && this.strides == this@DoubleFieldND.strides -> this.buffer as DoubleBuffer
|
||||||
|
else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
override inline fun StructureND<Double>.map(
|
||||||
|
transform: DoubleField.(Double) -> Double,
|
||||||
|
): BufferND<Double> {
|
||||||
|
val buffer = DoubleBuffer(strides.linearSize) { offset -> DoubleField.transform(buffer.array[offset]) }
|
||||||
|
return BufferND(strides, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
override inline fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND<Double> {
|
||||||
|
val array = DoubleArray(strides.linearSize) { offset ->
|
||||||
|
val index = strides.index(offset)
|
||||||
|
DoubleField.initializer(index)
|
||||||
|
}
|
||||||
|
return BufferND(strides, DoubleBuffer(array))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
override inline fun StructureND<Double>.mapIndexed(
|
||||||
|
transform: DoubleField.(index: IntArray, Double) -> Double,
|
||||||
|
): BufferND<Double> = BufferND(
|
||||||
|
strides,
|
||||||
|
buffer = DoubleBuffer(strides.linearSize) { offset ->
|
||||||
|
DoubleField.transform(
|
||||||
|
strides.index(offset),
|
||||||
|
buffer.array[offset]
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
override inline fun combine(
|
||||||
|
a: StructureND<Double>,
|
||||||
|
b: StructureND<Double>,
|
||||||
|
transform: DoubleField.(Double, Double) -> Double,
|
||||||
|
): BufferND<Double> {
|
||||||
|
val buffer = DoubleBuffer(strides.linearSize) { offset ->
|
||||||
|
DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset])
|
||||||
|
}
|
||||||
|
return BufferND(strides, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun scale(a: StructureND<Double>, value: Double): StructureND<Double> = a.map { it * value }
|
||||||
|
|
||||||
|
override fun power(arg: StructureND<Double>, pow: Number): BufferND<Double> = arg.map { power(it, pow) }
|
||||||
|
|
||||||
|
override fun exp(arg: StructureND<Double>): BufferND<Double> = arg.map { exp(it) }
|
||||||
|
|
||||||
|
override fun ln(arg: StructureND<Double>): BufferND<Double> = arg.map { ln(it) }
|
||||||
|
|
||||||
|
override fun sin(arg: StructureND<Double>): BufferND<Double> = arg.map { sin(it) }
|
||||||
|
override fun cos(arg: StructureND<Double>): BufferND<Double> = arg.map { cos(it) }
|
||||||
|
override fun tan(arg: StructureND<Double>): BufferND<Double> = arg.map { tan(it) }
|
||||||
|
override fun asin(arg: StructureND<Double>): BufferND<Double> = arg.map { asin(it) }
|
||||||
|
override fun acos(arg: StructureND<Double>): BufferND<Double> = arg.map { acos(it) }
|
||||||
|
override fun atan(arg: StructureND<Double>): BufferND<Double> = arg.map { atan(it) }
|
||||||
|
|
||||||
|
override fun sinh(arg: StructureND<Double>): BufferND<Double> = arg.map { sinh(it) }
|
||||||
|
override fun cosh(arg: StructureND<Double>): BufferND<Double> = arg.map { cosh(it) }
|
||||||
|
override fun tanh(arg: StructureND<Double>): BufferND<Double> = arg.map { tanh(it) }
|
||||||
|
override fun asinh(arg: StructureND<Double>): BufferND<Double> = arg.map { asinh(it) }
|
||||||
|
override fun acosh(arg: StructureND<Double>): BufferND<Double> = arg.map { acosh(it) }
|
||||||
|
override fun atanh(arg: StructureND<Double>): BufferND<Double> = arg.map { atanh(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun AlgebraND.Companion.real(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce a context for n-dimensional operations inside this real field
|
||||||
|
*/
|
||||||
|
public inline fun <R> DoubleField.nd(vararg shape: Int, action: DoubleFieldND.() -> R): R {
|
||||||
|
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||||
|
return DoubleFieldND(shape).run(action)
|
||||||
|
}
|
@ -1,111 +0,0 @@
|
|||||||
package space.kscience.kmath.nd
|
|
||||||
|
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
|
||||||
import space.kscience.kmath.operations.ExtendedField
|
|
||||||
import space.kscience.kmath.operations.NumbersAddOperations
|
|
||||||
import space.kscience.kmath.operations.RealField
|
|
||||||
import space.kscience.kmath.operations.ScaleOperations
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
|
||||||
import space.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),
|
|
||||||
NumbersAddOperations<NDStructure<Double>>,
|
|
||||||
ScaleOperations<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 scale(a: NDStructure<Double>, value: Double): NDStructure<Double> = a.map { it * value }
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
@ -9,15 +9,15 @@ import kotlin.contracts.InvocationKind
|
|||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
@OptIn(UnstableKMathAPI::class)
|
@OptIn(UnstableKMathAPI::class)
|
||||||
public class ShortNDRing(
|
public class ShortRingND(
|
||||||
shape: IntArray,
|
shape: IntArray,
|
||||||
) : BufferedNDRing<Short, ShortRing>(shape, ShortRing, Buffer.Companion::auto),
|
) : BufferedRingND<Short, ShortRing>(shape, ShortRing, Buffer.Companion::auto),
|
||||||
NumbersAddOperations<NDStructure<Short>> {
|
NumbersAddOperations<StructureND<Short>> {
|
||||||
|
|
||||||
override val zero: NDBuffer<Short> by lazy { produce { zero } }
|
override val zero: BufferND<Short> by lazy { produce { zero } }
|
||||||
override val one: NDBuffer<Short> by lazy { produce { one } }
|
override val one: BufferND<Short> by lazy { produce { one } }
|
||||||
|
|
||||||
override fun number(value: Number): NDBuffer<Short> {
|
override fun number(value: Number): BufferND<Short> {
|
||||||
val d = value.toShort() // minimize conversions
|
val d = value.toShort() // minimize conversions
|
||||||
return produce { d }
|
return produce { d }
|
||||||
}
|
}
|
||||||
@ -26,11 +26,11 @@ public class ShortNDRing(
|
|||||||
/**
|
/**
|
||||||
* Fast element production using function inlining.
|
* Fast element production using function inlining.
|
||||||
*/
|
*/
|
||||||
public inline fun BufferedNDRing<Short, ShortRing>.produceInline(crossinline initializer: ShortRing.(Int) -> Short): NDBuffer<Short> {
|
public inline fun BufferedRingND<Short, ShortRing>.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND<Short> {
|
||||||
return NDBuffer(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) }))
|
return BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) }))
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline fun <R> ShortRing.nd(vararg shape: Int, action: ShortNDRing.() -> R): R {
|
public inline fun <R> ShortRing.nd(vararg shape: Int, action: ShortRingND.() -> R): R {
|
||||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||||
return ShortNDRing(shape).run(action)
|
return ShortRingND(shape).run(action)
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ import space.kscience.kmath.structures.asSequence
|
|||||||
/**
|
/**
|
||||||
* A structure that is guaranteed to be one-dimensional
|
* A structure that is guaranteed to be one-dimensional
|
||||||
*/
|
*/
|
||||||
public interface Structure1D<T> : NDStructure<T>, Buffer<T> {
|
public interface Structure1D<T> : StructureND<T>, Buffer<T> {
|
||||||
public override val dimension: Int get() = 1
|
public override val dimension: Int get() = 1
|
||||||
|
|
||||||
public override operator fun get(index: IntArray): T {
|
public override operator fun get(index: IntArray): T {
|
||||||
@ -22,7 +22,7 @@ public interface Structure1D<T> : NDStructure<T>, Buffer<T> {
|
|||||||
/**
|
/**
|
||||||
* A mutable structure that is guaranteed to be one-dimensional
|
* A mutable structure that is guaranteed to be one-dimensional
|
||||||
*/
|
*/
|
||||||
public interface MutableStructure1D<T> : Structure1D<T>, MutableNDStructure<T>, MutableBuffer<T> {
|
public interface MutableStructure1D<T> : Structure1D<T>, MutableStructureND<T>, MutableBuffer<T> {
|
||||||
public override operator fun set(index: IntArray, value: T) {
|
public override operator fun set(index: IntArray, value: T) {
|
||||||
require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" }
|
require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" }
|
||||||
set(index[0], value)
|
set(index[0], value)
|
||||||
@ -32,7 +32,7 @@ public interface MutableStructure1D<T> : Structure1D<T>, MutableNDStructure<T>,
|
|||||||
/**
|
/**
|
||||||
* A 1D wrapper for nd-structure
|
* A 1D wrapper for nd-structure
|
||||||
*/
|
*/
|
||||||
private inline class Structure1DWrapper<T>(val structure: NDStructure<T>) : Structure1D<T> {
|
private inline class Structure1DWrapper<T>(val structure: StructureND<T>) : Structure1D<T> {
|
||||||
override val shape: IntArray get() = structure.shape
|
override val shape: IntArray get() = structure.shape
|
||||||
override val size: Int get() = structure.shape[0]
|
override val size: Int get() = structure.shape[0]
|
||||||
|
|
||||||
@ -43,12 +43,10 @@ private inline class Structure1DWrapper<T>(val structure: NDStructure<T>) : Stru
|
|||||||
/**
|
/**
|
||||||
* A 1D wrapper for a mutable nd-structure
|
* A 1D wrapper for a mutable nd-structure
|
||||||
*/
|
*/
|
||||||
private inline class MutableStructure1DWrapper<T>(val structure: MutableNDStructure<T>) : MutableStructure1D<T> {
|
private inline class MutableStructure1DWrapper<T>(val structure: MutableStructureND<T>) : MutableStructure1D<T> {
|
||||||
override val shape: IntArray get() = structure.shape
|
override val shape: IntArray get() = structure.shape
|
||||||
override val size: Int get() = structure.shape[0]
|
override val size: Int get() = structure.shape[0]
|
||||||
override fun elements(): Sequence<Pair<IntArray, T>> {
|
override fun elements(): Sequence<Pair<IntArray, T>> = structure.elements()
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun get(index: Int): T = structure[index]
|
override fun get(index: Int): T = structure[index]
|
||||||
override fun set(index: Int, value: T) {
|
override fun set(index: Int, value: T) {
|
||||||
@ -73,37 +71,19 @@ private inline class Buffer1DWrapper<T>(val buffer: Buffer<T>) : Structure1D<T>
|
|||||||
override operator fun get(index: Int): T = buffer[index]
|
override operator fun get(index: Int): T = buffer[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline class MutableBuffer1DWrapper<T>(val buffer: MutableBuffer<T>) : MutableStructure1D<T> {
|
|
||||||
override val shape: IntArray get() = intArrayOf(buffer.size)
|
|
||||||
override val size: Int get() = buffer.size
|
|
||||||
|
|
||||||
override fun elements(): Sequence<Pair<IntArray, T>> =
|
|
||||||
buffer.asSequence().mapIndexed { index, value -> intArrayOf(index) to value }
|
|
||||||
|
|
||||||
override operator fun get(index: Int): T = buffer[index]
|
|
||||||
override fun set(index: Int, value: T) {
|
|
||||||
buffer[index] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun copy(): MutableBuffer<T> = buffer.copy()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch
|
* Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch
|
||||||
*/
|
*/
|
||||||
public fun <T> NDStructure<T>.as1D(): Structure1D<T> = this as? Structure1D<T> ?: if (shape.size == 1) {
|
public fun <T> StructureND<T>.as1D(): Structure1D<T> = this as? Structure1D<T> ?: if (shape.size == 1) {
|
||||||
when (this) {
|
when (this) {
|
||||||
is NDBuffer -> Buffer1DWrapper(this.buffer)
|
is BufferND -> Buffer1DWrapper(this.buffer)
|
||||||
else -> Structure1DWrapper(this)
|
else -> Structure1DWrapper(this)
|
||||||
}
|
}
|
||||||
} else error("Can't create 1d-structure from ${shape.size}d-structure")
|
} else error("Can't create 1d-structure from ${shape.size}d-structure")
|
||||||
|
|
||||||
public fun <T> MutableNDStructure<T>.as1D(): MutableStructure1D<T> =
|
public fun <T> MutableStructureND<T>.as1D(): MutableStructure1D<T> =
|
||||||
this as? MutableStructure1D<T> ?: if (shape.size == 1) {
|
this as? MutableStructure1D<T> ?: if (shape.size == 1) {
|
||||||
when (this) {
|
MutableStructure1DWrapper(this)
|
||||||
is MutableNDBuffer -> MutableBuffer1DWrapper(this.buffer)
|
|
||||||
else -> MutableStructure1DWrapper(this)
|
|
||||||
}
|
|
||||||
} else error("Can't create 1d-structure from ${shape.size}d-structure")
|
} else error("Can't create 1d-structure from ${shape.size}d-structure")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,4 +91,12 @@ public fun <T> MutableNDStructure<T>.as1D(): MutableStructure1D<T> =
|
|||||||
*/
|
*/
|
||||||
public fun <T> Buffer<T>.asND(): Structure1D<T> = Buffer1DWrapper(this)
|
public fun <T> Buffer<T>.asND(): Structure1D<T> = Buffer1DWrapper(this)
|
||||||
|
|
||||||
public fun <T> MutableBuffer<T>.asND(): MutableStructure1D<T> = MutableBuffer1DWrapper(this)
|
/**
|
||||||
|
* Expose inner buffer of this [Structure1D] if possible
|
||||||
|
*/
|
||||||
|
internal fun <T : Any> Structure1D<T>.unwrap(): Buffer<T> = when {
|
||||||
|
this is Buffer1DWrapper<T> -> buffer
|
||||||
|
this is Structure1DWrapper && structure is BufferND<T> -> structure.buffer
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import kotlin.reflect.KClass
|
|||||||
*
|
*
|
||||||
* @param T the type of items.
|
* @param T the type of items.
|
||||||
*/
|
*/
|
||||||
public interface Structure2D<T> : NDStructure<T> {
|
public interface Structure2D<T> : StructureND<T> {
|
||||||
/**
|
/**
|
||||||
* The number of rows in this structure.
|
* The number of rows in this structure.
|
||||||
*/
|
*/
|
||||||
@ -60,7 +60,7 @@ public interface Structure2D<T> : NDStructure<T> {
|
|||||||
/**
|
/**
|
||||||
* Represents mutable [Structure2D].
|
* Represents mutable [Structure2D].
|
||||||
*/
|
*/
|
||||||
public interface MutableStructure2D<T> : Structure2D<T>, MutableNDStructure<T> {
|
public interface MutableStructure2D<T> : Structure2D<T>, MutableStructureND<T> {
|
||||||
/**
|
/**
|
||||||
* Inserts an item at the specified indices.
|
* Inserts an item at the specified indices.
|
||||||
*
|
*
|
||||||
@ -74,7 +74,7 @@ public interface MutableStructure2D<T> : Structure2D<T>, MutableNDStructure<T> {
|
|||||||
/**
|
/**
|
||||||
* A 2D wrapper for nd-structure
|
* A 2D wrapper for nd-structure
|
||||||
*/
|
*/
|
||||||
private class Structure2DWrapper<T>(val structure: NDStructure<T>) : Structure2D<T> {
|
private inline class Structure2DWrapper<T>(val structure: StructureND<T>) : Structure2D<T> {
|
||||||
override val shape: IntArray get() = structure.shape
|
override val shape: IntArray get() = structure.shape
|
||||||
|
|
||||||
override val rowNum: Int get() = shape[0]
|
override val rowNum: Int get() = shape[0]
|
||||||
@ -86,16 +86,12 @@ private class Structure2DWrapper<T>(val structure: NDStructure<T>) : Structure2D
|
|||||||
override fun <F : Any> getFeature(type: KClass<F>): F? = structure.getFeature(type)
|
override fun <F : Any> getFeature(type: KClass<F>): F? = structure.getFeature(type)
|
||||||
|
|
||||||
override fun elements(): Sequence<Pair<IntArray, T>> = structure.elements()
|
override fun elements(): Sequence<Pair<IntArray, T>> = structure.elements()
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean = structure == other
|
|
||||||
|
|
||||||
override fun hashCode(): Int = structure.hashCode()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A 2D wrapper for a mutable nd-structure
|
* A 2D wrapper for a mutable nd-structure
|
||||||
*/
|
*/
|
||||||
private class MutableStructure2DWrapper<T>(val structure: MutableNDStructure<T>): MutableStructure2D<T>
|
private class MutableStructure2DWrapper<T>(val structure: MutableStructureND<T>): MutableStructure2D<T>
|
||||||
{
|
{
|
||||||
override val shape: IntArray get() = structure.shape
|
override val shape: IntArray get() = structure.shape
|
||||||
|
|
||||||
@ -120,19 +116,25 @@ private class MutableStructure2DWrapper<T>(val structure: MutableNDStructure<T>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represent a [NDStructure] as [Structure2D]. Throw error in case of dimension mismatch
|
* Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch
|
||||||
*/
|
*/
|
||||||
public fun <T> NDStructure<T>.as2D(): Structure2D<T> = this as? Structure2D<T> ?: when (shape.size) {
|
public fun <T> StructureND<T>.as2D(): Structure2D<T> = this as? Structure2D<T> ?: when (shape.size) {
|
||||||
2 -> Structure2DWrapper(this)
|
2 -> Structure2DWrapper(this)
|
||||||
else -> error("Can't create 2d-structure from ${shape.size}d-structure")
|
else -> error("Can't create 2d-structure from ${shape.size}d-structure")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <T> Structure2D<T>.unwrap(): NDStructure<T> = if (this is Structure2DWrapper) structure else this
|
public fun <T> MutableStructureND<T>.as2D(): MutableStructure2D<T> = this as? MutableStructure2D<T> ?: when (shape.size) {
|
||||||
|
|
||||||
public fun <T> MutableNDStructure<T>.as2D(): MutableStructure2D<T> = this as? MutableStructure2D<T> ?: when (shape.size) {
|
|
||||||
2 -> MutableStructure2DWrapper(this)
|
2 -> MutableStructure2DWrapper(this)
|
||||||
else -> error("Can't create 2d-structure from ${shape.size}d-structure")
|
else -> error("Can't create 2d-structure from ${shape.size}d-structure")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <T> MutableStructure2D<T>.unwrap(): MutableNDStructure<T> =
|
/**
|
||||||
|
* Expose inner [StructureND] if possible
|
||||||
|
*/
|
||||||
|
internal fun <T> Structure2D<T>.unwrap(): StructureND<T> =
|
||||||
|
if (this is Structure2DWrapper) structure
|
||||||
|
else this
|
||||||
|
|
||||||
|
internal fun <T> MutableStructure2D<T>.unwrap(): MutableStructureND<T> =
|
||||||
if (this is MutableStructure2DWrapper) structure else this
|
if (this is MutableStructure2DWrapper) structure else this
|
||||||
|
|
||||||
|
@ -3,8 +3,6 @@ package space.kscience.kmath.nd
|
|||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.BufferFactory
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
import space.kscience.kmath.structures.MutableBuffer
|
|
||||||
import space.kscience.kmath.structures.asSequence
|
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
import kotlin.native.concurrent.ThreadLocal
|
import kotlin.native.concurrent.ThreadLocal
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -14,9 +12,11 @@ import kotlin.reflect.KClass
|
|||||||
* of dimensions and items in an array is defined by its shape, which is a sequence of non-negative integers that
|
* of dimensions and items in an array is defined by its shape, which is a sequence of non-negative integers that
|
||||||
* specify the sizes of each dimension.
|
* specify the sizes of each dimension.
|
||||||
*
|
*
|
||||||
|
* StructureND is in general identity-free. [StructureND.contentEquals] should be used in tests to compare contents.
|
||||||
|
*
|
||||||
* @param T the type of items.
|
* @param T the type of items.
|
||||||
*/
|
*/
|
||||||
public interface NDStructure<T> {
|
public interface StructureND<T> {
|
||||||
/**
|
/**
|
||||||
* The shape of structure, i.e. non-empty sequence of non-negative integers that specify sizes of dimensions of
|
* The shape of structure, i.e. non-empty sequence of non-negative integers that specify sizes of dimensions of
|
||||||
* this structure.
|
* this structure.
|
||||||
@ -43,32 +43,47 @@ public interface NDStructure<T> {
|
|||||||
*/
|
*/
|
||||||
public fun elements(): Sequence<Pair<IntArray, T>>
|
public fun elements(): Sequence<Pair<IntArray, T>>
|
||||||
|
|
||||||
//force override equality and hash code
|
|
||||||
public override fun equals(other: Any?): Boolean
|
|
||||||
public override fun hashCode(): Int
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Feature is additional property or hint that does not directly affect the structure, but could in some cases help
|
* Feature is some additional strucure information which allows to access it special properties or hints.
|
||||||
* optimize operations and performance. If the feature is not present, null is defined.
|
* If the feature is not present, null is returned.
|
||||||
*/
|
*/
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public fun <F : Any> getFeature(type: KClass<F>): F? = null
|
public fun <F : Any> getFeature(type: KClass<F>): F? = null
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
/**
|
/**
|
||||||
* Indicates whether some [NDStructure] is equal to another one.
|
* Indicates whether some [StructureND] is equal to another one.
|
||||||
*/
|
*/
|
||||||
public fun contentEquals(st1: NDStructure<*>, st2: NDStructure<*>): Boolean {
|
public fun <T : Any> contentEquals(st1: StructureND<T>, st2: StructureND<T>): Boolean {
|
||||||
if (st1 === st2) return true
|
if (st1 === st2) return true
|
||||||
|
|
||||||
// fast comparison of buffers if possible
|
// fast comparison of buffers if possible
|
||||||
if (st1 is NDBuffer && st2 is NDBuffer && st1.strides == st2.strides)
|
if (st1 is BufferND && st2 is BufferND && st1.strides == st2.strides)
|
||||||
return st1.buffer.contentEquals(st2.buffer)
|
return Buffer.contentEquals(st1.buffer, st2.buffer)
|
||||||
|
|
||||||
//element by element comparison if it could not be avoided
|
//element by element comparison if it could not be avoided
|
||||||
return st1.elements().all { (index, value) -> value == st2[index] }
|
return st1.elements().all { (index, value) -> value == st2[index] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug output to string
|
||||||
|
*/
|
||||||
|
public fun toString(structure: StructureND<*>): String {
|
||||||
|
val bufferRepr: String = when (structure.shape.size) {
|
||||||
|
1 -> (0 until structure.shape[0]).map { structure[it] }
|
||||||
|
.joinToString(prefix = "[", postfix = "]", separator = ", ")
|
||||||
|
2 -> (0 until structure.shape[0]).joinToString(prefix = "[", postfix = "]", separator = ", ") { i ->
|
||||||
|
(0 until structure.shape[1]).joinToString(prefix = "[", postfix = "]", separator = ", ") { j ->
|
||||||
|
structure[i, j].toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> "..."
|
||||||
|
}
|
||||||
|
val className = structure::class.simpleName ?: "StructureND"
|
||||||
|
|
||||||
|
return "$className(shape=${structure.shape.contentToString()}, buffer=$bufferRepr)"
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a NDStructure with explicit buffer factory.
|
* Creates a NDStructure with explicit buffer factory.
|
||||||
*
|
*
|
||||||
@ -78,7 +93,7 @@ public interface NDStructure<T> {
|
|||||||
strides: Strides,
|
strides: Strides,
|
||||||
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
||||||
initializer: (IntArray) -> T,
|
initializer: (IntArray) -> T,
|
||||||
): NDBuffer<T> = NDBuffer(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) })
|
): BufferND<T> = BufferND(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inline create NDStructure with non-boxing buffer implementation if it is possible
|
* Inline create NDStructure with non-boxing buffer implementation if it is possible
|
||||||
@ -86,37 +101,37 @@ public interface NDStructure<T> {
|
|||||||
public inline fun <reified T : Any> auto(
|
public inline fun <reified T : Any> auto(
|
||||||
strides: Strides,
|
strides: Strides,
|
||||||
crossinline initializer: (IntArray) -> T,
|
crossinline initializer: (IntArray) -> T,
|
||||||
): NDBuffer<T> = NDBuffer(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) })
|
): BufferND<T> = BufferND(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||||
|
|
||||||
public inline fun <T : Any> auto(
|
public inline fun <T : Any> auto(
|
||||||
type: KClass<T>,
|
type: KClass<T>,
|
||||||
strides: Strides,
|
strides: Strides,
|
||||||
crossinline initializer: (IntArray) -> T,
|
crossinline initializer: (IntArray) -> T,
|
||||||
): NDBuffer<T> = NDBuffer(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) })
|
): BufferND<T> = BufferND(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||||
|
|
||||||
public fun <T> buffered(
|
public fun <T> buffered(
|
||||||
shape: IntArray,
|
shape: IntArray,
|
||||||
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
||||||
initializer: (IntArray) -> T,
|
initializer: (IntArray) -> T,
|
||||||
): NDBuffer<T> = buffered(DefaultStrides(shape), bufferFactory, initializer)
|
): BufferND<T> = buffered(DefaultStrides(shape), bufferFactory, initializer)
|
||||||
|
|
||||||
public inline fun <reified T : Any> auto(
|
public inline fun <reified T : Any> auto(
|
||||||
shape: IntArray,
|
shape: IntArray,
|
||||||
crossinline initializer: (IntArray) -> T,
|
crossinline initializer: (IntArray) -> T,
|
||||||
): NDBuffer<T> = auto(DefaultStrides(shape), initializer)
|
): BufferND<T> = auto(DefaultStrides(shape), initializer)
|
||||||
|
|
||||||
@JvmName("autoVarArg")
|
@JvmName("autoVarArg")
|
||||||
public inline fun <reified T : Any> auto(
|
public inline fun <reified T : Any> auto(
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
crossinline initializer: (IntArray) -> T,
|
crossinline initializer: (IntArray) -> T,
|
||||||
): NDBuffer<T> =
|
): BufferND<T> =
|
||||||
auto(DefaultStrides(shape), initializer)
|
auto(DefaultStrides(shape), initializer)
|
||||||
|
|
||||||
public inline fun <T : Any> auto(
|
public inline fun <T : Any> auto(
|
||||||
type: KClass<T>,
|
type: KClass<T>,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
crossinline initializer: (IntArray) -> T,
|
crossinline initializer: (IntArray) -> T,
|
||||||
): NDBuffer<T> = auto(type, DefaultStrides(shape), initializer)
|
): BufferND<T> = auto(type, DefaultStrides(shape), initializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,15 +141,15 @@ public interface NDStructure<T> {
|
|||||||
* @param index the indices.
|
* @param index the indices.
|
||||||
* @return the value.
|
* @return the value.
|
||||||
*/
|
*/
|
||||||
public operator fun <T> NDStructure<T>.get(vararg index: Int): T = get(index)
|
public operator fun <T> StructureND<T>.get(vararg index: Int): T = get(index)
|
||||||
|
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public inline fun <reified T : Any> NDStructure<*>.getFeature(): T? = getFeature(T::class)
|
public inline fun <reified T : Any> StructureND<*>.getFeature(): T? = getFeature(T::class)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents mutable [NDStructure].
|
* Represents mutable [StructureND].
|
||||||
*/
|
*/
|
||||||
public interface MutableNDStructure<T> : NDStructure<T> {
|
public interface MutableStructureND<T> : StructureND<T> {
|
||||||
/**
|
/**
|
||||||
* Inserts an item at the specified indices.
|
* Inserts an item at the specified indices.
|
||||||
*
|
*
|
||||||
@ -147,7 +162,7 @@ public interface MutableNDStructure<T> : NDStructure<T> {
|
|||||||
/**
|
/**
|
||||||
* Transform a structure element-by element in place.
|
* Transform a structure element-by element in place.
|
||||||
*/
|
*/
|
||||||
public inline fun <T> MutableNDStructure<T>.mapInPlace(action: (IntArray, T) -> T): Unit =
|
public inline fun <T> MutableStructureND<T>.mapInPlace(action: (IntArray, T) -> T): Unit =
|
||||||
elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) }
|
elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -194,7 +209,8 @@ public interface Strides {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal inline fun offsetFromIndex(index: IntArray, shape: IntArray, strides: IntArray): Int = index.mapIndexed { i, value ->
|
internal inline fun offsetFromIndex(index: IntArray, shape: IntArray, strides: IntArray): Int =
|
||||||
|
index.mapIndexed { i, value ->
|
||||||
if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${shape[i]})")
|
if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${shape[i]})")
|
||||||
value * strides[i]
|
value * strides[i]
|
||||||
}.sum()
|
}.sum()
|
||||||
@ -262,97 +278,11 @@ 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 open class NDBuffer<T>(
|
|
||||||
public val strides: Strides,
|
|
||||||
buffer: Buffer<T>,
|
|
||||||
) : NDStructure<T> {
|
|
||||||
|
|
||||||
init {
|
public inline fun <reified T : Any> StructureND<T>.combine(
|
||||||
if (strides.linearSize != buffer.size) {
|
struct: StructureND<T>,
|
||||||
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 equals(other: Any?): Boolean {
|
|
||||||
return NDStructure.contentEquals(this, other as? NDStructure<*> ?: return false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = strides.hashCode()
|
|
||||||
result = 31 * result + buffer.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
val bufferRepr: String = when (shape.size) {
|
|
||||||
1 -> buffer.asSequence().joinToString(prefix = "[", postfix = "]", separator = ", ")
|
|
||||||
2 -> (0 until shape[0]).joinToString(prefix = "[", postfix = "]", separator = ", ") { i ->
|
|
||||||
(0 until shape[1]).joinToString(prefix = "[", postfix = "]", separator = ", ") { j ->
|
|
||||||
val offset = strides.offset(intArrayOf(i, j))
|
|
||||||
buffer[offset].toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> "..."
|
|
||||||
}
|
|
||||||
return "NDBuffer(shape=${shape.contentToString()}, buffer=$bufferRepr)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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,
|
|
||||||
): NDBuffer<R> {
|
|
||||||
return if (this is NDBuffer<T>)
|
|
||||||
NDBuffer(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) })
|
|
||||||
else {
|
|
||||||
val strides = DefaultStrides(shape)
|
|
||||||
NDBuffer(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mutable ND buffer based on linear [MutableBuffer].
|
|
||||||
*/
|
|
||||||
public open class MutableNDBuffer<T>(
|
|
||||||
strides: Strides,
|
|
||||||
buffer: MutableBuffer<T>,
|
|
||||||
) : NDBuffer<T>(strides, buffer), MutableNDStructure<T> {
|
|
||||||
|
|
||||||
init {
|
|
||||||
require(strides.linearSize == buffer.size) {
|
|
||||||
"Expected buffer side of ${strides.linearSize}, but found ${buffer.size}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
public inline fun <reified T : Any> NDStructure<T>.combine(
|
|
||||||
struct: NDStructure<T>,
|
|
||||||
crossinline block: (T, T) -> T,
|
crossinline block: (T, T) -> T,
|
||||||
): NDStructure<T> {
|
): StructureND<T> {
|
||||||
require(shape.contentEquals(struct.shape)) { "Shape mismatch in structure combination" }
|
require(shape.contentEquals(struct.shape)) { "Shape mismatch in structure combination" }
|
||||||
return NDStructure.auto(shape) { block(this[it], struct[it]) }
|
return StructureND.auto(shape) { block(this[it], struct[it]) }
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package space.kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.BufferedNDRing
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.BufferedRingND
|
||||||
import space.kscience.kmath.operations.BigInt.Companion.BASE
|
import space.kscience.kmath.operations.BigInt.Companion.BASE
|
||||||
import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE
|
import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
@ -464,5 +464,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> =
|
public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer<BigInt> =
|
||||||
boxing(size, initializer)
|
boxing(size, initializer)
|
||||||
|
|
||||||
public fun NDAlgebra.Companion.bigInt(vararg shape: Int): BufferedNDRing<BigInt, BigIntField> =
|
public fun AlgebraND.Companion.bigInt(vararg shape: Int): BufferedRingND<BigInt, BigIntField> =
|
||||||
BufferedNDRing(shape, BigIntField, Buffer.Companion::bigInt)
|
BufferedRingND(shape, BigIntField, Buffer.Companion::bigInt)
|
||||||
|
@ -49,19 +49,19 @@ public fun <T : Comparable<T>> Group<T>.abs(value: T): T = if (value > zero) val
|
|||||||
* Returns the sum of all elements in the iterable in provided space.
|
* Returns the sum of all elements in the iterable in provided space.
|
||||||
*
|
*
|
||||||
* @receiver the collection to sum up.
|
* @receiver the collection to sum up.
|
||||||
* @param space the algebra that provides addition.
|
* @param group the algebra that provides addition.
|
||||||
* @return the sum.
|
* @return the sum.
|
||||||
*/
|
*/
|
||||||
public fun <T> Iterable<T>.sumWith(space: Group<T>): T = space.sum(this)
|
public fun <T> Iterable<T>.sumWith(group: Group<T>): T = group.sum(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the sum of all elements in the sequence in provided space.
|
* Returns the sum of all elements in the sequence in provided space.
|
||||||
*
|
*
|
||||||
* @receiver the collection to sum up.
|
* @receiver the collection to sum up.
|
||||||
* @param space the algebra that provides addition.
|
* @param group the algebra that provides addition.
|
||||||
* @return the sum.
|
* @return the sum.
|
||||||
*/
|
*/
|
||||||
public fun <T> Sequence<T>.sumWith(space: Group<T>): T = space.sum(this)
|
public fun <T> Sequence<T>.sumWith(group: Group<T>): T = group.sum(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an average value of elements in the iterable in this [Group].
|
* Returns an average value of elements in the iterable in this [Group].
|
||||||
|
@ -55,7 +55,7 @@ public interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T>, Numeri
|
|||||||
* A field for [Double] without boxing. Does not produce appropriate field element.
|
* A field for [Double] without boxing. Does not produce appropriate field element.
|
||||||
*/
|
*/
|
||||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
|
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
|
||||||
public object RealField : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> {
|
public object DoubleField : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> {
|
||||||
public override val zero: Double = 0.0
|
public override val zero: Double = 0.0
|
||||||
public override val one: Double = 1.0
|
public override val one: Double = 1.0
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@ public typealias BufferFactory<T> = (Int, (Int) -> T) -> Buffer<T>
|
|||||||
public typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T>
|
public typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A generic immutable random-access structure for both primitives and objects.
|
* A generic read-only random-access structure for both primitives and objects.
|
||||||
|
*
|
||||||
|
* [Buffer] is in general identity-free. [Buffer.contentEquals] should be used for content equality checks.
|
||||||
*
|
*
|
||||||
* @param T the type of elements contained in the buffer.
|
* @param T the type of elements contained in the buffer.
|
||||||
*/
|
*/
|
||||||
@ -37,49 +39,46 @@ public interface Buffer<out T> {
|
|||||||
*/
|
*/
|
||||||
public operator fun iterator(): Iterator<T>
|
public operator fun iterator(): Iterator<T>
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks content equality with another buffer.
|
|
||||||
*/
|
|
||||||
public fun contentEquals(other: Buffer<*>): Boolean =
|
|
||||||
asSequence().mapIndexed { index, value -> value == other[index] }.all { it }
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
|
* Check the element-by-element match of content of two buffers.
|
||||||
* [initializer] function.
|
|
||||||
*/
|
*/
|
||||||
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
|
public fun <T: Any> contentEquals(first: Buffer<T>, second: Buffer<T>): Boolean{
|
||||||
RealBuffer(size) { initializer(it) }
|
if (first.size != second.size) return false
|
||||||
|
for (i in first.indices) {
|
||||||
|
if (first[i] != second[i]) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the
|
* Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the
|
||||||
* specified [initializer] function.
|
* specified [initializer] function.
|
||||||
*/
|
*/
|
||||||
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> =
|
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> =
|
||||||
ListBuffer(List(size, initializer))
|
List(size, initializer).asBuffer()
|
||||||
|
|
||||||
// TODO add resolution based on Annotation or companion resolution
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer],
|
* Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer],
|
||||||
* [RealBuffer], etc.), [ListBuffer] is returned otherwise.
|
* [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
|
||||||
*
|
*
|
||||||
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public inline fun <T : Any> auto(type: KClass<T>, size: Int, initializer: (Int) -> T): Buffer<T> =
|
public inline fun <T : Any> auto(type: KClass<T>, size: Int, initializer: (Int) -> T): Buffer<T> =
|
||||||
when (type) {
|
when (type) {
|
||||||
Double::class -> RealBuffer(size) { initializer(it) as Double } as Buffer<T>
|
Double::class -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer<T>
|
||||||
Short::class -> ShortBuffer(size) { initializer(it) as Short } as Buffer<T>
|
Short::class -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
|
||||||
Int::class -> IntBuffer(size) { initializer(it) as Int } as Buffer<T>
|
Int::class -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
|
||||||
Long::class -> LongBuffer(size) { initializer(it) as Long } as Buffer<T>
|
Long::class -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
|
||||||
Float::class -> FloatBuffer(size) { initializer(it) as Float } as Buffer<T>
|
Float::class -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
|
||||||
else -> boxing(size, initializer)
|
else -> boxing(size, initializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([IntBuffer],
|
* Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([IntBuffer],
|
||||||
* [RealBuffer], etc.), [ListBuffer] is returned otherwise.
|
* [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
|
||||||
*
|
*
|
||||||
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
||||||
*/
|
*/
|
||||||
@ -89,41 +88,6 @@ public interface Buffer<out T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a sequence that returns all elements from this [Buffer].
|
|
||||||
*/
|
|
||||||
public fun <T> Buffer<T>.asSequence(): Sequence<T> = Sequence(::iterator)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an iterable that returns all elements from this [Buffer].
|
|
||||||
*/
|
|
||||||
public fun <T> Buffer<T>.asIterable(): Iterable<T> = Iterable(::iterator)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [List] containing all elements of this buffer.
|
|
||||||
*/
|
|
||||||
public fun <T> Buffer<T>.toList(): List<T> = when (this) {
|
|
||||||
is ArrayBuffer<T> -> array.toList()
|
|
||||||
is ListBuffer<T> -> list.toList()
|
|
||||||
is MutableListBuffer<T> -> list.toList()
|
|
||||||
else -> asSequence().toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [MutableList] filled with all elements of this buffer.
|
|
||||||
*/
|
|
||||||
public fun <T> Buffer<T>.toMutableList(): MutableList<T> = when (this) {
|
|
||||||
is ArrayBuffer<T> -> array.toMutableList()
|
|
||||||
is ListBuffer<T> -> list.toMutableList()
|
|
||||||
is MutableListBuffer<T> -> list.toMutableList()
|
|
||||||
else -> asSequence().toMutableList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [Array] containing all elements of this buffer.
|
|
||||||
*/
|
|
||||||
public inline fun <reified T> Buffer<T>.toTypedArray(): Array<T> = asSequence().toList().toTypedArray()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an [IntRange] of the valid indices for this [Buffer].
|
* Returns an [IntRange] of the valid indices for this [Buffer].
|
||||||
*/
|
*/
|
||||||
@ -146,6 +110,44 @@ public interface MutableBuffer<T> : Buffer<T> {
|
|||||||
public fun copy(): MutableBuffer<T>
|
public fun copy(): MutableBuffer<T>
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified
|
||||||
|
* [initializer] function.
|
||||||
|
*/
|
||||||
|
public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer =
|
||||||
|
DoubleBuffer(size, initializer)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified
|
||||||
|
* [initializer] function.
|
||||||
|
*/
|
||||||
|
public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer =
|
||||||
|
ShortBuffer(size, initializer)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified
|
||||||
|
* [initializer] function.
|
||||||
|
*/
|
||||||
|
public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer =
|
||||||
|
IntBuffer(size, initializer)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified
|
||||||
|
* [initializer] function.
|
||||||
|
*/
|
||||||
|
public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer =
|
||||||
|
LongBuffer(size, initializer)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified
|
||||||
|
* [initializer] function.
|
||||||
|
*/
|
||||||
|
public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer =
|
||||||
|
FloatBuffer(size, initializer)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a boxing mutable buffer of given type
|
* Create a boxing mutable buffer of given type
|
||||||
*/
|
*/
|
||||||
@ -154,37 +156,30 @@ public interface MutableBuffer<T> : Buffer<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used
|
* Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used
|
||||||
* ([IntBuffer], [RealBuffer], etc.), [ListBuffer] is returned otherwise.
|
* ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
|
||||||
*
|
*
|
||||||
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
||||||
when (type) {
|
when (type) {
|
||||||
Double::class -> RealBuffer(size) { initializer(it) as Double } as MutableBuffer<T>
|
Double::class -> double(size) { initializer(it) as Double } as MutableBuffer<T>
|
||||||
Short::class -> ShortBuffer(size) { initializer(it) as Short } as MutableBuffer<T>
|
Short::class -> short(size) { initializer(it) as Short } as MutableBuffer<T>
|
||||||
Int::class -> IntBuffer(size) { initializer(it) as Int } as MutableBuffer<T>
|
Int::class -> int(size) { initializer(it) as Int } as MutableBuffer<T>
|
||||||
Float::class -> FloatBuffer(size) { initializer(it) as Float } as MutableBuffer<T>
|
Float::class -> float(size) { initializer(it) as Float } as MutableBuffer<T>
|
||||||
Long::class -> LongBuffer(size) { initializer(it) as Long } as MutableBuffer<T>
|
Long::class -> long(size) { initializer(it) as Long } as MutableBuffer<T>
|
||||||
else -> boxing(size, initializer)
|
else -> boxing(size, initializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
|
* Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
|
||||||
* ([IntBuffer], [RealBuffer], etc.), [ListBuffer] is returned otherwise.
|
* ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
|
||||||
*
|
*
|
||||||
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
||||||
auto(T::class, size, initializer)
|
auto(T::class, size, initializer)
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
|
|
||||||
* [initializer] function.
|
|
||||||
*/
|
|
||||||
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
|
|
||||||
RealBuffer(size) { initializer(it) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,15 +202,6 @@ public inline class ListBuffer<T>(public val list: List<T>) : Buffer<T> {
|
|||||||
*/
|
*/
|
||||||
public fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this)
|
public fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this)
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new [ListBuffer] with the specified [size], where each element is calculated by calling the specified
|
|
||||||
* [init] function.
|
|
||||||
*
|
|
||||||
* The function [init] is called for each array element sequentially starting from the first one.
|
|
||||||
* It should return the value for an array element given its index.
|
|
||||||
*/
|
|
||||||
public inline fun <T> ListBuffer(size: Int, init: (Int) -> T): ListBuffer<T> = List(size, init).asBuffer()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [MutableBuffer] implementation over [MutableList].
|
* [MutableBuffer] implementation over [MutableList].
|
||||||
*
|
*
|
||||||
@ -237,7 +223,11 @@ public inline class MutableListBuffer<T>(public val list: MutableList<T>) : Muta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
<<<<<<< HEAD
|
||||||
* Returns an [MutableListBuffer] that wraps the original list.
|
* Returns an [MutableListBuffer] that wraps the original list.
|
||||||
|
=======
|
||||||
|
* Returns an [ListBuffer] that wraps the original list.
|
||||||
|
>>>>>>> dev
|
||||||
*/
|
*/
|
||||||
public fun <T> MutableList<T>.asMutableBuffer(): MutableListBuffer<T> = MutableListBuffer(this)
|
public fun <T> MutableList<T>.asMutableBuffer(): MutableListBuffer<T> = MutableListBuffer(this)
|
||||||
|
|
||||||
@ -249,8 +239,7 @@ public fun <T> MutableList<T>.asMutableBuffer(): MutableListBuffer<T> = MutableL
|
|||||||
*/
|
*/
|
||||||
public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
|
public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
|
||||||
// Can't inline because array is invariant
|
// Can't inline because array is invariant
|
||||||
override val size: Int
|
override val size: Int get() = array.size
|
||||||
get() = array.size
|
|
||||||
|
|
||||||
override operator fun get(index: Int): T = array[index]
|
override operator fun get(index: Int): T = array[index]
|
||||||
|
|
||||||
@ -268,16 +257,6 @@ public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
|
|||||||
*/
|
*/
|
||||||
public fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
|
public fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new [ArrayBuffer] with the specified [size], where each element is calculated by calling the specified
|
|
||||||
* [init] function.
|
|
||||||
*
|
|
||||||
* The function [init] is called for each array element sequentially starting from the first one.
|
|
||||||
* It should return the value for an array element given its index.
|
|
||||||
*/
|
|
||||||
public inline fun <reified T> ArrayBuffer(size: Int, init: (Int) -> T): ArrayBuffer<T> =
|
|
||||||
Array(size) { i -> init(i) }.asBuffer()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immutable wrapper for [MutableBuffer].
|
* Immutable wrapper for [MutableBuffer].
|
||||||
*
|
*
|
||||||
@ -305,27 +284,9 @@ public class VirtualBuffer<T>(override val size: Int, private val generator: (In
|
|||||||
}
|
}
|
||||||
|
|
||||||
override operator fun iterator(): Iterator<T> = (0 until size).asSequence().map(generator).iterator()
|
override operator fun iterator(): Iterator<T> = (0 until size).asSequence().map(generator).iterator()
|
||||||
|
|
||||||
override fun contentEquals(other: Buffer<*>): Boolean {
|
|
||||||
return if (other is VirtualBuffer) {
|
|
||||||
this.size == other.size && this.generator == other.generator
|
|
||||||
} else {
|
|
||||||
super.contentEquals(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert this buffer to read-only buffer.
|
* Convert this buffer to read-only buffer.
|
||||||
*/
|
*/
|
||||||
public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this
|
public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this
|
||||||
|
|
||||||
/**
|
|
||||||
* Typealias for buffer transformations.
|
|
||||||
*/
|
|
||||||
public typealias BufferTransform<T, R> = (Buffer<T>) -> Buffer<R>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Typealias for buffer transformations with suspend function.
|
|
||||||
*/
|
|
||||||
public typealias SuspendBufferTransform<T, R> = suspend (Buffer<T>) -> Buffer<R>
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import space.kscience.kmath.nd.DefaultStrides
|
import space.kscience.kmath.nd.DefaultStrides
|
||||||
import space.kscience.kmath.nd.NDStructure
|
|
||||||
import space.kscience.kmath.nd.Structure2D
|
import space.kscience.kmath.nd.Structure2D
|
||||||
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.nd.as2D
|
import space.kscience.kmath.nd.as2D
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,7 +25,7 @@ internal class BufferAccessor2D<T : Any>(
|
|||||||
public fun create(mat: Structure2D<T>): MutableBuffer<T> = create { i, j -> mat[i, j] }
|
public fun create(mat: Structure2D<T>): MutableBuffer<T> = create { i, j -> mat[i, j] }
|
||||||
|
|
||||||
//TODO optimize wrapper
|
//TODO optimize wrapper
|
||||||
public fun MutableBuffer<T>.collect(): Structure2D<T> = NDStructure.buffered(
|
public fun MutableBuffer<T>.collect(): Structure2D<T> = StructureND.buffered(
|
||||||
DefaultStrides(intArrayOf(rowNum, colNum)),
|
DefaultStrides(intArrayOf(rowNum, colNum)),
|
||||||
factory
|
factory
|
||||||
) { (i, j) ->
|
) { (i, j) ->
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialized [MutableBuffer] implementation over [DoubleArray].
|
||||||
|
*
|
||||||
|
* @property array the underlying array.
|
||||||
|
*/
|
||||||
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
public inline class DoubleBuffer(public val array: DoubleArray) : MutableBuffer<Double> {
|
||||||
|
override val size: Int get() = array.size
|
||||||
|
|
||||||
|
override operator fun get(index: Int): Double = array[index]
|
||||||
|
|
||||||
|
override operator fun set(index: Int, value: Double) {
|
||||||
|
array[index] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun iterator(): DoubleIterator = array.iterator()
|
||||||
|
|
||||||
|
override fun copy(): DoubleBuffer = DoubleBuffer(array.copyOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified
|
||||||
|
* [init] function.
|
||||||
|
*
|
||||||
|
* The function [init] is called for each array element sequentially starting from the first one.
|
||||||
|
* It should return the value for an buffer element given its index.
|
||||||
|
*/
|
||||||
|
public inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = DoubleBuffer(DoubleArray(size) { init(it) })
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new [DoubleBuffer] of given elements.
|
||||||
|
*/
|
||||||
|
public fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(doubles)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplified [DoubleBuffer] to array comparison
|
||||||
|
*/
|
||||||
|
public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new [DoubleArray] containing all of the elements of this [Buffer].
|
||||||
|
*/
|
||||||
|
public fun Buffer<Double>.toDoubleArray(): DoubleArray = when (this) {
|
||||||
|
is DoubleBuffer -> array.copyOf()
|
||||||
|
else -> DoubleArray(size, ::get)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [DoubleBuffer] over this array.
|
||||||
|
*
|
||||||
|
* @receiver the array.
|
||||||
|
* @return the new buffer.
|
||||||
|
*/
|
||||||
|
public fun DoubleArray.asBuffer(): DoubleBuffer = DoubleBuffer(this)
|
@ -0,0 +1,272 @@
|
|||||||
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.ExtendedField
|
||||||
|
import space.kscience.kmath.operations.ExtendedFieldOperations
|
||||||
|
import kotlin.math.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [ExtendedFieldOperations] over [DoubleBuffer].
|
||||||
|
*/
|
||||||
|
public object DoubleBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
|
||||||
|
override fun Buffer<Double>.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) {
|
||||||
|
DoubleBuffer(size) { -array[it] }
|
||||||
|
} else {
|
||||||
|
DoubleBuffer(size) { -get(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun add(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(b.size == a.size) {
|
||||||
|
"The size of the first buffer ${a.size} should be the same as for second one: ${b.size} "
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (a is DoubleBuffer && b is DoubleBuffer) {
|
||||||
|
val aArray = a.array
|
||||||
|
val bArray = b.array
|
||||||
|
DoubleBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] })
|
||||||
|
} else DoubleBuffer(DoubleArray(a.size) { a[it] + b[it] })
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// public override fun multiply(a: Buffer<Double>, k: Number): RealBuffer {
|
||||||
|
// val kValue = k.toDouble()
|
||||||
|
//
|
||||||
|
// return if (a is RealBuffer) {
|
||||||
|
// val aArray = a.array
|
||||||
|
// RealBuffer(DoubleArray(a.size) { aArray[it] * kValue })
|
||||||
|
// } else RealBuffer(DoubleArray(a.size) { a[it] * kValue })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public override fun divide(a: Buffer<Double>, k: Number): RealBuffer {
|
||||||
|
// val kValue = k.toDouble()
|
||||||
|
//
|
||||||
|
// return if (a is RealBuffer) {
|
||||||
|
// val aArray = a.array
|
||||||
|
// RealBuffer(DoubleArray(a.size) { aArray[it] / kValue })
|
||||||
|
// } else RealBuffer(DoubleArray(a.size) { a[it] / kValue })
|
||||||
|
// }
|
||||||
|
|
||||||
|
public override fun multiply(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(b.size == a.size) {
|
||||||
|
"The size of the first buffer ${a.size} should be the same as for second one: ${b.size} "
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (a is DoubleBuffer && b is DoubleBuffer) {
|
||||||
|
val aArray = a.array
|
||||||
|
val bArray = b.array
|
||||||
|
DoubleBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(a.size) { a[it] * b[it] })
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun divide(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(b.size == a.size) {
|
||||||
|
"The size of the first buffer ${a.size} should be the same as for second one: ${b.size} "
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (a is DoubleBuffer && b is DoubleBuffer) {
|
||||||
|
val aArray = a.array
|
||||||
|
val bArray = b.array
|
||||||
|
DoubleBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] })
|
||||||
|
} else DoubleBuffer(DoubleArray(a.size) { a[it] / b[it] })
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun sin(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) })
|
||||||
|
} else DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) })
|
||||||
|
|
||||||
|
public override fun cos(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) })
|
||||||
|
} else DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) })
|
||||||
|
|
||||||
|
public override fun tan(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { tan(array[it]) })
|
||||||
|
} else DoubleBuffer(DoubleArray(arg.size) { tan(arg[it]) })
|
||||||
|
|
||||||
|
public override fun asin(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { asin(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { asin(arg[it]) })
|
||||||
|
|
||||||
|
public override fun acos(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { acos(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { acos(arg[it]) })
|
||||||
|
|
||||||
|
public override fun atan(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { atan(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { atan(arg[it]) })
|
||||||
|
|
||||||
|
public override fun sinh(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { sinh(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { sinh(arg[it]) })
|
||||||
|
|
||||||
|
public override fun cosh(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { cosh(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { cosh(arg[it]) })
|
||||||
|
|
||||||
|
public override fun tanh(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { tanh(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { tanh(arg[it]) })
|
||||||
|
|
||||||
|
public override fun asinh(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { asinh(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { asinh(arg[it]) })
|
||||||
|
|
||||||
|
public override fun acosh(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { acosh(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { acosh(arg[it]) })
|
||||||
|
|
||||||
|
public override fun atanh(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { atanh(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { atanh(arg[it]) })
|
||||||
|
|
||||||
|
public override fun power(arg: Buffer<Double>, pow: Number): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) })
|
||||||
|
|
||||||
|
public override fun exp(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) })
|
||||||
|
} else DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) })
|
||||||
|
|
||||||
|
public override fun ln(arg: Buffer<Double>): DoubleBuffer = if (arg is DoubleBuffer) {
|
||||||
|
val array = arg.array
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) })
|
||||||
|
} else
|
||||||
|
DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [ExtendedField] over [DoubleBuffer].
|
||||||
|
*
|
||||||
|
* @property size the size of buffers to operate on.
|
||||||
|
*/
|
||||||
|
public class DoubleBufferField(public val size: Int) : ExtendedField<Buffer<Double>> {
|
||||||
|
public override val zero: Buffer<Double> by lazy { DoubleBuffer(size) { 0.0 } }
|
||||||
|
public override val one: Buffer<Double> by lazy { DoubleBuffer(size) { 1.0 } }
|
||||||
|
|
||||||
|
override fun number(value: Number): Buffer<Double> = DoubleBuffer(size) { value.toDouble() }
|
||||||
|
|
||||||
|
override fun Buffer<Double>.unaryMinus(): Buffer<Double> = DoubleBufferFieldOperations.run {
|
||||||
|
-this@unaryMinus
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun add(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.add(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun scale(a: Buffer<Double>, value: Double): DoubleBuffer {
|
||||||
|
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
|
||||||
|
|
||||||
|
return if (a is DoubleBuffer) {
|
||||||
|
val aArray = a.array
|
||||||
|
DoubleBuffer(DoubleArray(a.size) { aArray[it] * value })
|
||||||
|
} else DoubleBuffer(DoubleArray(a.size) { a[it] * value })
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun multiply(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.multiply(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun divide(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.divide(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun sin(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.sin(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun cos(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.cos(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun tan(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.tan(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun asin(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.asin(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun acos(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.acos(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun atan(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.atan(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun sinh(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.sinh(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun cosh(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.cosh(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun tanh(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.tanh(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun asinh(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.asinh(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun acosh(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.acosh(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun atanh(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.atanh(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun power(arg: Buffer<Double>, pow: Number): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.power(arg, pow)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun exp(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.exp(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun ln(arg: Buffer<Double>): DoubleBuffer {
|
||||||
|
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
||||||
|
return DoubleBufferFieldOperations.ln(arg)
|
||||||
|
}
|
||||||
|
}
|
@ -48,7 +48,7 @@ public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, Valu
|
|||||||
/**
|
/**
|
||||||
* A real buffer which supports flags for each value like NaN or Missing
|
* A real buffer which supports flags for each value like NaN or Missing
|
||||||
*/
|
*/
|
||||||
public class FlaggedRealBuffer(public val values: DoubleArray, public val flags: ByteArray) : FlaggedBuffer<Double?>,
|
public class FlaggedDoubleBuffer(public val values: DoubleArray, public val flags: ByteArray) : FlaggedBuffer<Double?>,
|
||||||
Buffer<Double?> {
|
Buffer<Double?> {
|
||||||
init {
|
init {
|
||||||
require(values.size == flags.size) { "Values and flags must have the same dimensions" }
|
require(values.size == flags.size) { "Values and flags must have the same dimensions" }
|
||||||
@ -65,7 +65,7 @@ public class FlaggedRealBuffer(public val values: DoubleArray, public val flags:
|
|||||||
}.iterator()
|
}.iterator()
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline fun FlaggedRealBuffer.forEachValid(block: (Double) -> Unit) {
|
public inline fun FlaggedDoubleBuffer.forEachValid(block: (Double) -> Unit) {
|
||||||
indices
|
indices
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter(::isValid)
|
.filter(::isValid)
|
||||||
|
@ -24,7 +24,7 @@ public open class MemoryBuffer<T : Any>(protected val memory: Memory, protected
|
|||||||
public inline fun <T : Any> create(
|
public inline fun <T : Any> create(
|
||||||
spec: MemorySpec<T>,
|
spec: MemorySpec<T>,
|
||||||
size: Int,
|
size: Int,
|
||||||
initializer: (Int) -> T
|
initializer: (Int) -> T,
|
||||||
): MemoryBuffer<T> = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
): MemoryBuffer<T> = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
||||||
(0 until size).forEach { buffer[it] = initializer(it) }
|
(0 until size).forEach { buffer[it] = initializer(it) }
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ public class MutableMemoryBuffer<T : Any>(memory: Memory, spec: MemorySpec<T>) :
|
|||||||
public inline fun <T : Any> create(
|
public inline fun <T : Any> create(
|
||||||
spec: MemorySpec<T>,
|
spec: MemorySpec<T>,
|
||||||
size: Int,
|
size: Int,
|
||||||
initializer: (Int) -> T
|
initializer: (Int) -> T,
|
||||||
): MutableMemoryBuffer<T> = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
): MutableMemoryBuffer<T> = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
||||||
(0 until size).forEach { buffer[it] = initializer(it) }
|
(0 until size).forEach { buffer[it] = initializer(it) }
|
||||||
}
|
}
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
package space.kscience.kmath.structures
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specialized [MutableBuffer] implementation over [DoubleArray].
|
|
||||||
*
|
|
||||||
* @property array the underlying array.
|
|
||||||
*/
|
|
||||||
@Suppress("OVERRIDE_BY_INLINE")
|
|
||||||
public inline class RealBuffer(public val array: DoubleArray) : MutableBuffer<Double> {
|
|
||||||
override val size: Int get() = array.size
|
|
||||||
|
|
||||||
override operator fun get(index: Int): Double = array[index]
|
|
||||||
|
|
||||||
override operator fun set(index: Int, value: Double) {
|
|
||||||
array[index] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun iterator(): DoubleIterator = array.iterator()
|
|
||||||
|
|
||||||
override fun copy(): RealBuffer = RealBuffer(array.copyOf())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new [RealBuffer] with the specified [size], where each element is calculated by calling the specified
|
|
||||||
* [init] function.
|
|
||||||
*
|
|
||||||
* The function [init] is called for each array element sequentially starting from the first one.
|
|
||||||
* It should return the value for an buffer element given its index.
|
|
||||||
*/
|
|
||||||
public inline fun RealBuffer(size: Int, init: (Int) -> Double): RealBuffer = RealBuffer(DoubleArray(size) { init(it) })
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [RealBuffer] of given elements.
|
|
||||||
*/
|
|
||||||
public fun RealBuffer(vararg doubles: Double): RealBuffer = RealBuffer(doubles)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simplified [RealBuffer] to array comparison
|
|
||||||
*/
|
|
||||||
public fun RealBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [DoubleArray] containing all of the elements of this [Buffer].
|
|
||||||
*/
|
|
||||||
public fun Buffer<Double>.toDoubleArray(): DoubleArray = when(this) {
|
|
||||||
is RealBuffer -> array.copyOf()
|
|
||||||
else -> DoubleArray(size, ::get)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns [RealBuffer] over this array.
|
|
||||||
*
|
|
||||||
* @receiver the array.
|
|
||||||
* @return the new buffer.
|
|
||||||
*/
|
|
||||||
public fun DoubleArray.asBuffer(): RealBuffer = RealBuffer(this)
|
|
@ -1,272 +0,0 @@
|
|||||||
package space.kscience.kmath.structures
|
|
||||||
|
|
||||||
import space.kscience.kmath.operations.ExtendedField
|
|
||||||
import space.kscience.kmath.operations.ExtendedFieldOperations
|
|
||||||
import kotlin.math.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [ExtendedFieldOperations] over [RealBuffer].
|
|
||||||
*/
|
|
||||||
public object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
|
|
||||||
override fun Buffer<Double>.unaryMinus(): RealBuffer = if (this is RealBuffer) {
|
|
||||||
RealBuffer(size) { -array[it] }
|
|
||||||
} else {
|
|
||||||
RealBuffer(size) { -get(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
|
|
||||||
require(b.size == a.size) {
|
|
||||||
"The size of the first buffer ${a.size} should be the same as for second one: ${b.size} "
|
|
||||||
}
|
|
||||||
|
|
||||||
return if (a is RealBuffer && b is RealBuffer) {
|
|
||||||
val aArray = a.array
|
|
||||||
val bArray = b.array
|
|
||||||
RealBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] })
|
|
||||||
} else RealBuffer(DoubleArray(a.size) { a[it] + b[it] })
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// public override fun multiply(a: Buffer<Double>, k: Number): RealBuffer {
|
|
||||||
// val kValue = k.toDouble()
|
|
||||||
//
|
|
||||||
// return if (a is RealBuffer) {
|
|
||||||
// val aArray = a.array
|
|
||||||
// RealBuffer(DoubleArray(a.size) { aArray[it] * kValue })
|
|
||||||
// } else RealBuffer(DoubleArray(a.size) { a[it] * kValue })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public override fun divide(a: Buffer<Double>, k: Number): RealBuffer {
|
|
||||||
// val kValue = k.toDouble()
|
|
||||||
//
|
|
||||||
// return if (a is RealBuffer) {
|
|
||||||
// val aArray = a.array
|
|
||||||
// RealBuffer(DoubleArray(a.size) { aArray[it] / kValue })
|
|
||||||
// } else RealBuffer(DoubleArray(a.size) { a[it] / kValue })
|
|
||||||
// }
|
|
||||||
|
|
||||||
public override fun multiply(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
|
|
||||||
require(b.size == a.size) {
|
|
||||||
"The size of the first buffer ${a.size} should be the same as for second one: ${b.size} "
|
|
||||||
}
|
|
||||||
|
|
||||||
return if (a is RealBuffer && b is RealBuffer) {
|
|
||||||
val aArray = a.array
|
|
||||||
val bArray = b.array
|
|
||||||
RealBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(a.size) { a[it] * b[it] })
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun divide(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
|
|
||||||
require(b.size == a.size) {
|
|
||||||
"The size of the first buffer ${a.size} should be the same as for second one: ${b.size} "
|
|
||||||
}
|
|
||||||
|
|
||||||
return if (a is RealBuffer && b is RealBuffer) {
|
|
||||||
val aArray = a.array
|
|
||||||
val bArray = b.array
|
|
||||||
RealBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] })
|
|
||||||
} else RealBuffer(DoubleArray(a.size) { a[it] / b[it] })
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun sin(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { sin(array[it]) })
|
|
||||||
} else RealBuffer(DoubleArray(arg.size) { sin(arg[it]) })
|
|
||||||
|
|
||||||
public override fun cos(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { cos(array[it]) })
|
|
||||||
} else RealBuffer(DoubleArray(arg.size) { cos(arg[it]) })
|
|
||||||
|
|
||||||
public override fun tan(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { tan(array[it]) })
|
|
||||||
} else RealBuffer(DoubleArray(arg.size) { tan(arg[it]) })
|
|
||||||
|
|
||||||
public override fun asin(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { asin(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { asin(arg[it]) })
|
|
||||||
|
|
||||||
public override fun acos(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { acos(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { acos(arg[it]) })
|
|
||||||
|
|
||||||
public override fun atan(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { atan(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { atan(arg[it]) })
|
|
||||||
|
|
||||||
public override fun sinh(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { sinh(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { sinh(arg[it]) })
|
|
||||||
|
|
||||||
public override fun cosh(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { cosh(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { cosh(arg[it]) })
|
|
||||||
|
|
||||||
public override fun tanh(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { tanh(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { tanh(arg[it]) })
|
|
||||||
|
|
||||||
public override fun asinh(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { asinh(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { asinh(arg[it]) })
|
|
||||||
|
|
||||||
public override fun acosh(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { acosh(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { acosh(arg[it]) })
|
|
||||||
|
|
||||||
public override fun atanh(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { atanh(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { atanh(arg[it]) })
|
|
||||||
|
|
||||||
public override fun power(arg: Buffer<Double>, pow: Number): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) })
|
|
||||||
|
|
||||||
public override fun exp(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { exp(array[it]) })
|
|
||||||
} else RealBuffer(DoubleArray(arg.size) { exp(arg[it]) })
|
|
||||||
|
|
||||||
public override fun ln(arg: Buffer<Double>): RealBuffer = if (arg is RealBuffer) {
|
|
||||||
val array = arg.array
|
|
||||||
RealBuffer(DoubleArray(arg.size) { ln(array[it]) })
|
|
||||||
} else
|
|
||||||
RealBuffer(DoubleArray(arg.size) { ln(arg[it]) })
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [ExtendedField] over [RealBuffer].
|
|
||||||
*
|
|
||||||
* @property size the size of buffers to operate on.
|
|
||||||
*/
|
|
||||||
public class RealBufferField(public val size: Int) : ExtendedField<Buffer<Double>> {
|
|
||||||
public override val zero: Buffer<Double> by lazy { RealBuffer(size) { 0.0 } }
|
|
||||||
public override val one: Buffer<Double> by lazy { RealBuffer(size) { 1.0 } }
|
|
||||||
|
|
||||||
override fun number(value: Number): Buffer<Double> = RealBuffer(size) { value.toDouble() }
|
|
||||||
|
|
||||||
override fun Buffer<Double>.unaryMinus(): Buffer<Double> = RealBufferFieldOperations.run {
|
|
||||||
-this@unaryMinus
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
|
|
||||||
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.add(a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun scale(a: Buffer<Double>, value: Double): RealBuffer {
|
|
||||||
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
|
|
||||||
|
|
||||||
return if (a is RealBuffer) {
|
|
||||||
val aArray = a.array
|
|
||||||
RealBuffer(DoubleArray(a.size) { aArray[it] * value })
|
|
||||||
} else RealBuffer(DoubleArray(a.size) { a[it] * value })
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun multiply(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
|
|
||||||
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.multiply(a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun divide(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
|
|
||||||
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.divide(a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun sin(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.sin(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun cos(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.cos(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun tan(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.tan(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun asin(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.asin(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun acos(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.acos(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun atan(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.atan(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun sinh(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.sinh(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun cosh(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.cosh(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun tanh(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.tanh(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun asinh(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.asinh(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun acosh(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.acosh(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun atanh(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.atanh(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun power(arg: Buffer<Double>, pow: Number): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.power(arg, pow)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun exp(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.exp(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun ln(arg: Buffer<Double>): RealBuffer {
|
|
||||||
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
|
|
||||||
return RealBufferFieldOperations.ln(arg)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,84 @@
|
|||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typealias for buffer transformations.
|
||||||
|
*/
|
||||||
|
public typealias BufferTransform<T, R> = (Buffer<T>) -> Buffer<R>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typealias for buffer transformations with suspend function.
|
||||||
|
*/
|
||||||
|
public typealias SuspendBufferTransform<T, R> = suspend (Buffer<T>) -> Buffer<R>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a sequence that returns all elements from this [Buffer].
|
||||||
|
*/
|
||||||
|
public fun <T> Buffer<T>.asSequence(): Sequence<T> = Sequence(::iterator)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an iterable that returns all elements from this [Buffer].
|
||||||
|
*/
|
||||||
|
public fun <T> Buffer<T>.asIterable(): Iterable<T> = Iterable(::iterator)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new [List] containing all elements of this buffer.
|
||||||
|
*/
|
||||||
|
public fun <T> Buffer<T>.toList(): List<T> = when (this) {
|
||||||
|
is ArrayBuffer<T> -> array.toList()
|
||||||
|
is ListBuffer<T> -> list.toList()
|
||||||
|
is MutableListBuffer<T> -> list.toList()
|
||||||
|
else -> asSequence().toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new [MutableList] filled with all elements of this buffer.
|
||||||
|
* **NOTE:** this method uses a protective copy, so it should not be used in performance-critical code.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <T> Buffer<T>.toMutableList(): MutableList<T> = when (this) {
|
||||||
|
is ArrayBuffer<T> -> array.toMutableList()
|
||||||
|
is ListBuffer<T> -> list.toMutableList()
|
||||||
|
is MutableListBuffer<T> -> list.toMutableList()
|
||||||
|
else -> MutableList(size, ::get)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new [Array] containing all elements of this buffer.
|
||||||
|
* **NOTE:** this method uses a protective copy, so it should not be used in performance-critical code.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public inline fun <reified T> Buffer<T>.toTypedArray(): Array<T> = Array(size, ::get)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new buffer from this one with the given mapping function.
|
||||||
|
* Provided [BufferFactory] is used to construct the new buffer.
|
||||||
|
*/
|
||||||
public inline fun <T : Any, reified R : Any> Buffer<T>.map(
|
public inline fun <T : Any, reified R : Any> Buffer<T>.map(
|
||||||
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
|
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
|
||||||
crossinline block: (T) -> R,
|
crossinline block: (T) -> R,
|
||||||
): Buffer<R> = bufferFactory(size) { block(get(it)) }
|
): Buffer<R> = bufferFactory(size) { block(get(it)) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new buffer from this one with the given indexed mapping function.
|
||||||
|
* Provided [BufferFactory] is used to construct the new buffer.
|
||||||
|
*/
|
||||||
|
public inline fun <T : Any, reified R : Any> Buffer<T>.mapIndexed(
|
||||||
|
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
|
||||||
|
crossinline block: (index: Int, value: T) -> R,
|
||||||
|
): Buffer<R> = bufferFactory(size) { block(it, get(it)) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zip two buffers using given [transform].
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public inline fun <T1 : Any, T2 : Any, reified R : Any> Buffer<T1>.zip(
|
||||||
|
other: Buffer<T2>,
|
||||||
|
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
|
||||||
|
crossinline transform: (T1, T2) -> R,
|
||||||
|
): Buffer<R> {
|
||||||
|
require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" }
|
||||||
|
return bufferFactory(size) { transform(get(it), other[it]) }
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
package space.kscience.kmath.tensors
|
package space.kscience.kmath.tensors
|
||||||
|
|
||||||
import space.kscience.kmath.nd.MutableNDStructure
|
import space.kscience.kmath.nd.MutableStructureND
|
||||||
|
|
||||||
public typealias TensorStructure<T> = MutableNDStructure<T>
|
public typealias TensorStructure<T> = MutableStructureND<T>
|
||||||
|
@ -90,4 +90,4 @@ public class DoubleTensor internal constructor(
|
|||||||
shape: IntArray,
|
shape: IntArray,
|
||||||
buffer: DoubleArray,
|
buffer: DoubleArray,
|
||||||
offset: Int = 0
|
offset: Int = 0
|
||||||
) : BufferedTensor<Double>(shape, RealBuffer(buffer), offset)
|
) : BufferedTensor<Double>(shape, DoubleBuffer(buffer), offset)
|
@ -31,6 +31,6 @@ internal fun Buffer<Float>.array(): FloatArray = when (this) {
|
|||||||
* Returns a reference to [DoubleArray] containing all of the elements of this [Buffer].
|
* Returns a reference to [DoubleArray] containing all of the elements of this [Buffer].
|
||||||
*/
|
*/
|
||||||
internal fun Buffer<Double>.array(): DoubleArray = when (this) {
|
internal fun Buffer<Double>.array(): DoubleArray = when (this) {
|
||||||
is RealBuffer -> array
|
is DoubleBuffer -> array
|
||||||
else -> throw RuntimeException("Failed to cast Buffer to DoubleArray")
|
else -> throw RuntimeException("Failed to cast Buffer to DoubleArray")
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package space.kscience.kmath.expressions
|
package space.kscience.kmath.expressions
|
||||||
|
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -11,7 +11,7 @@ class ExpressionFieldTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testExpression() {
|
fun testExpression() {
|
||||||
val expression = FunctionalExpressionField(RealField).invoke {
|
val expression = FunctionalExpressionField(DoubleField).invoke {
|
||||||
val x by binding()
|
val x by binding()
|
||||||
x * x + 2 * x + one
|
x * x + 2 * x + one
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ class ExpressionFieldTest {
|
|||||||
return x * x + 2 * x + one
|
return x * x + 2 * x + one
|
||||||
}
|
}
|
||||||
|
|
||||||
val expression = FunctionalExpressionField(RealField).expression()
|
val expression = FunctionalExpressionField(DoubleField).expression()
|
||||||
assertEquals(expression(x to 1.0), 4.0)
|
assertEquals(expression(x to 1.0), 4.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ class ExpressionFieldTest {
|
|||||||
x * x + 2 * x + one
|
x * x + 2 * x + one
|
||||||
}
|
}
|
||||||
|
|
||||||
val expression = FunctionalExpressionField(RealField).expressionBuilder()
|
val expression = FunctionalExpressionField(DoubleField).expressionBuilder()
|
||||||
assertEquals(expression(x to 1.0), 4.0)
|
assertEquals(expression(x to 1.0), 4.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package space.kscience.kmath.expressions
|
package space.kscience.kmath.expressions
|
||||||
|
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.asBuffer
|
import space.kscience.kmath.structures.asBuffer
|
||||||
import kotlin.math.E
|
import kotlin.math.E
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
@ -14,19 +15,19 @@ class SimpleAutoDiffTest {
|
|||||||
|
|
||||||
fun dx(
|
fun dx(
|
||||||
xBinding: Pair<Symbol, Double>,
|
xBinding: Pair<Symbol, Double>,
|
||||||
body: SimpleAutoDiffField<Double, RealField>.(x: AutoDiffValue<Double>) -> AutoDiffValue<Double>,
|
body: SimpleAutoDiffField<Double, DoubleField>.(x: AutoDiffValue<Double>) -> AutoDiffValue<Double>,
|
||||||
): DerivationResult<Double> = RealField.simpleAutoDiff(xBinding) { body(bindSymbol(xBinding.first)) }
|
): DerivationResult<Double> = DoubleField.simpleAutoDiff(xBinding) { body(bindSymbol(xBinding.first)) }
|
||||||
|
|
||||||
fun dxy(
|
fun dxy(
|
||||||
xBinding: Pair<Symbol, Double>,
|
xBinding: Pair<Symbol, Double>,
|
||||||
yBinding: Pair<Symbol, Double>,
|
yBinding: Pair<Symbol, Double>,
|
||||||
body: SimpleAutoDiffField<Double, RealField>.(x: AutoDiffValue<Double>, y: AutoDiffValue<Double>) -> AutoDiffValue<Double>,
|
body: SimpleAutoDiffField<Double, DoubleField>.(x: AutoDiffValue<Double>, y: AutoDiffValue<Double>) -> AutoDiffValue<Double>,
|
||||||
): DerivationResult<Double> = RealField.simpleAutoDiff(xBinding, yBinding) {
|
): DerivationResult<Double> = DoubleField.simpleAutoDiff(xBinding, yBinding) {
|
||||||
body(bindSymbol(xBinding.first), bindSymbol(yBinding.first))
|
body(bindSymbol(xBinding.first), bindSymbol(yBinding.first))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun diff(block: SimpleAutoDiffField<Double, RealField>.() -> AutoDiffValue<Double>): SimpleAutoDiffExpression<Double, RealField> {
|
fun diff(block: SimpleAutoDiffField<Double, DoubleField>.() -> AutoDiffValue<Double>): SimpleAutoDiffExpression<Double, DoubleField> {
|
||||||
return SimpleAutoDiffExpression(RealField, block)
|
return SimpleAutoDiffExpression(DoubleField, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
val x by symbol
|
val x by symbol
|
||||||
@ -35,7 +36,7 @@ class SimpleAutoDiffTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPlusX2() {
|
fun testPlusX2() {
|
||||||
val y = RealField.simpleAutoDiff(x to 3.0) {
|
val y = DoubleField.simpleAutoDiff(x to 3.0) {
|
||||||
// diff w.r.t this x at 3
|
// diff w.r.t this x at 3
|
||||||
val x = bindSymbol(x)
|
val x = bindSymbol(x)
|
||||||
x + x
|
x + x
|
||||||
@ -58,7 +59,7 @@ class SimpleAutoDiffTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testPlus() {
|
fun testPlus() {
|
||||||
// two variables
|
// two variables
|
||||||
val z = RealField.simpleAutoDiff(x to 2.0, y to 3.0) {
|
val z = DoubleField.simpleAutoDiff(x to 2.0, y to 3.0) {
|
||||||
val x = bindSymbol(x)
|
val x = bindSymbol(x)
|
||||||
val y = bindSymbol(y)
|
val y = bindSymbol(y)
|
||||||
x + y
|
x + y
|
||||||
@ -71,7 +72,7 @@ class SimpleAutoDiffTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testMinus() {
|
fun testMinus() {
|
||||||
// two variables
|
// two variables
|
||||||
val z = RealField.simpleAutoDiff(x to 7.0, y to 3.0) {
|
val z = DoubleField.simpleAutoDiff(x to 7.0, y to 3.0) {
|
||||||
val x = bindSymbol(x)
|
val x = bindSymbol(x)
|
||||||
val y = bindSymbol(y)
|
val y = bindSymbol(y)
|
||||||
|
|
||||||
@ -276,7 +277,7 @@ class SimpleAutoDiffTest {
|
|||||||
fun testDivGrad() {
|
fun testDivGrad() {
|
||||||
val res = dxy(x to 1.0, y to 2.0) { x, y -> x * x + y * y }
|
val res = dxy(x to 1.0, y to 2.0) { x, y -> x * x + y * y }
|
||||||
assertEquals(6.0, res.div())
|
assertEquals(6.0, res.div())
|
||||||
assertTrue(res.grad(x, y).contentEquals(doubleArrayOf(2.0, 4.0).asBuffer()))
|
assertTrue(Buffer.contentEquals(res.grad(x, y), doubleArrayOf(2.0, 4.0).asBuffer()))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertApprox(a: Double, b: Double) {
|
private fun assertApprox(a: Double, b: Double) {
|
||||||
|
@ -1,17 +1,23 @@
|
|||||||
package space.kscience.kmath.linear
|
package space.kscience.kmath.linear
|
||||||
|
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.nd.StructureND
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
fun <T : Any> assertMatrixEquals(expected: StructureND<T>, actual: StructureND<T>) {
|
||||||
|
assertTrue { StructureND.contentEquals(expected, actual) }
|
||||||
|
}
|
||||||
|
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
class RealLUSolverTest {
|
class DoubleLUSolverTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testInvertOne() {
|
fun testInvertOne() {
|
||||||
val matrix = LinearSpace.real.one(2, 2)
|
val matrix = LinearSpace.real.one(2, 2)
|
||||||
val inverted = LinearSpace.real.inverseWithLup(matrix)
|
val inverted = LinearSpace.real.inverseWithLup(matrix)
|
||||||
assertEquals(matrix, inverted)
|
assertMatrixEquals(matrix, inverted)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -27,7 +33,7 @@ class RealLUSolverTest {
|
|||||||
//Check determinant
|
//Check determinant
|
||||||
assertEquals(7.0, lup.determinant)
|
assertEquals(7.0, lup.determinant)
|
||||||
|
|
||||||
assertEquals(lup.p dot matrix, lup.l dot lup.u)
|
assertMatrixEquals(lup.p dot matrix, lup.l dot lup.u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +51,6 @@ class RealLUSolverTest {
|
|||||||
-0.125, 0.375
|
-0.125, 0.375
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(expected, inverted)
|
assertMatrixEquals(expected, inverted)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,11 @@
|
|||||||
package space.kscience.kmath.linear
|
package space.kscience.kmath.linear
|
||||||
|
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.nd.as2D
|
import space.kscience.kmath.nd.as2D
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
@Suppress("UNUSED_VARIABLE")
|
@Suppress("UNUSED_VARIABLE")
|
||||||
@ -13,7 +14,7 @@ class MatrixTest {
|
|||||||
fun testTranspose() {
|
fun testTranspose() {
|
||||||
val matrix = LinearSpace.real.one(3, 3)
|
val matrix = LinearSpace.real.one(3, 3)
|
||||||
val transposed = matrix.transpose()
|
val transposed = matrix.transpose()
|
||||||
assertEquals(matrix, transposed)
|
assertTrue { StructureND.contentEquals(matrix, transposed) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -50,8 +51,8 @@ class MatrixTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test2DDot() {
|
fun test2DDot() {
|
||||||
val firstMatrix = NDStructure.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D()
|
val firstMatrix = StructureND.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D()
|
||||||
val secondMatrix = NDStructure.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D()
|
val secondMatrix = StructureND.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D()
|
||||||
|
|
||||||
LinearSpace.real.run {
|
LinearSpace.real.run {
|
||||||
// val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() }
|
// val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() }
|
||||||
|
@ -4,13 +4,13 @@ import space.kscience.kmath.testutils.FieldVerifier
|
|||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class RealFieldTest {
|
internal class DoubleFieldTest {
|
||||||
@Test
|
@Test
|
||||||
fun verify() = FieldVerifier(RealField, 42.0, 66.0, 2.0, 5).verify()
|
fun verify() = FieldVerifier(DoubleField, 42.0, 66.0, 2.0, 5).verify()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSqrt() {
|
fun testSqrt() {
|
||||||
val sqrt = RealField { sqrt(25 * one) }
|
val sqrt = DoubleField { sqrt(25 * one) }
|
||||||
assertEquals(5.0, sqrt)
|
assertEquals(5.0, sqrt)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
import space.kscience.kmath.nd.get
|
import space.kscience.kmath.nd.get
|
||||||
import space.kscience.kmath.nd.real
|
import space.kscience.kmath.nd.real
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
@ -11,12 +11,12 @@ import kotlin.test.assertEquals
|
|||||||
internal class NDFieldTest {
|
internal class NDFieldTest {
|
||||||
@Test
|
@Test
|
||||||
fun verify() {
|
fun verify() {
|
||||||
(NDAlgebra.real(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) }
|
(AlgebraND.real(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testStrides() {
|
fun testStrides() {
|
||||||
val ndArray = NDAlgebra.real(10, 10).produce { (it[0] + it[1]).toDouble() }
|
val ndArray = AlgebraND.real(10, 10).produce { (it[0] + it[1]).toDouble() }
|
||||||
assertEquals(ndArray[5, 5], 10.0)
|
assertEquals(ndArray[5, 5], 10.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import kotlin.test.assertEquals
|
|||||||
|
|
||||||
@Suppress("UNUSED_VARIABLE")
|
@Suppress("UNUSED_VARIABLE")
|
||||||
class NumberNDFieldTest {
|
class NumberNDFieldTest {
|
||||||
val algebra = NDAlgebra.real(3,3)
|
val algebra = AlgebraND.real(3, 3)
|
||||||
val array1 = algebra.produce { (i, j) -> (i + j).toDouble() }
|
val array1 = algebra.produce { (i, j) -> (i + j).toDouble() }
|
||||||
val array2 = algebra.produce { (i, j) -> (i - j).toDouble() }
|
val array2 = algebra.produce { (i, j) -> (i - j).toDouble() }
|
||||||
|
|
||||||
@ -69,15 +69,15 @@ class NumberNDFieldTest {
|
|||||||
val division = array1.combine(array2, Double::div)
|
val division = array1.combine(array2, Double::div)
|
||||||
}
|
}
|
||||||
|
|
||||||
object L2Norm : Norm<NDStructure<out Number>, Double> {
|
object L2Norm : Norm<StructureND<out Number>, Double> {
|
||||||
override fun norm(arg: NDStructure<out Number>): Double =
|
override fun norm(arg: StructureND<out Number>): Double =
|
||||||
kotlin.math.sqrt(arg.elements().sumByDouble { it.second.toDouble() })
|
kotlin.math.sqrt(arg.elements().sumByDouble { it.second.toDouble() })
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testInternalContext() {
|
fun testInternalContext() {
|
||||||
algebra {
|
algebra {
|
||||||
(NDAlgebra.real(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } }
|
(AlgebraND.real(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package space.kscience.kmath.chains
|
|||||||
/**
|
/**
|
||||||
* Performance optimized chain for real values
|
* Performance optimized chain for real values
|
||||||
*/
|
*/
|
||||||
public abstract class BlockingRealChain : Chain<Double> {
|
public abstract class BlockingDoubleChain : Chain<Double> {
|
||||||
public abstract fun nextDouble(): Double
|
public abstract fun nextDouble(): Double
|
||||||
|
|
||||||
override suspend fun next(): Double = nextDouble()
|
override suspend fun next(): Double = nextDouble()
|
@ -83,7 +83,7 @@ public class StatefulChain<S, out R>(
|
|||||||
private val state: S,
|
private val state: S,
|
||||||
private val seed: S.() -> R,
|
private val seed: S.() -> R,
|
||||||
private val forkState: ((S) -> S),
|
private val forkState: ((S) -> S),
|
||||||
private val gen: suspend S.(R) -> R
|
private val gen: suspend S.(R) -> R,
|
||||||
) : Chain<R> {
|
) : Chain<R> {
|
||||||
private val mutex: Mutex = Mutex()
|
private val mutex: Mutex = Mutex()
|
||||||
private var value: R? = null
|
private var value: R? = null
|
||||||
@ -145,7 +145,7 @@ public fun <T, R> Chain<T>.collect(mapper: suspend (Chain<T>) -> R): Chain<R> =
|
|||||||
public fun <T, S, R> Chain<T>.collectWithState(
|
public fun <T, S, R> Chain<T>.collectWithState(
|
||||||
state: S,
|
state: S,
|
||||||
stateFork: (S) -> S,
|
stateFork: (S) -> S,
|
||||||
mapper: suspend S.(Chain<T>) -> R
|
mapper: suspend S.(Chain<T>) -> R,
|
||||||
): Chain<R> = object : Chain<R> {
|
): Chain<R> = object : Chain<R> {
|
||||||
override suspend fun next(): R = state.mapper(this@collectWithState)
|
override suspend fun next(): R = state.mapper(this@collectWithState)
|
||||||
|
|
||||||
|