Merge dev, API check failed
15
.github/workflows/pages.yml
vendored
@ -22,10 +22,19 @@ jobs:
|
||||
key: ubuntu-20.04-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
ubuntu-20.04-gradle-
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.konan
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Build
|
||||
run: ./gradlew 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
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.0
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: build/dokka/htmlMultiModule
|
||||
branch: gh-pages
|
||||
folder: build/dokka/htmlMultiModule
|
||||
|
2
.github/workflows/publish.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
name: publish
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macOS-latest, windows-latest]
|
||||
os: [ macOS-latest, windows-latest ]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
|
@ -4,18 +4,22 @@
|
||||
### Added
|
||||
- ScaleOperations interface
|
||||
- Field extends ScaleOperations
|
||||
- Basic integration API
|
||||
|
||||
### Changed
|
||||
- Exponential operations merged with hyperbolic functions
|
||||
- Space is replaced by Group. Space is reserved for vector spaces.
|
||||
- VectorSpace is now a vector space
|
||||
-
|
||||
- Buffer factories for primitives moved to MutableBuffer.Companion
|
||||
- NDStructure and NDAlgebra to StructureND and AlgebraND respectively
|
||||
- Real -> Double
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
- Nearest in Domain. To be implemented in geometry package.
|
||||
- Number multiplication and division in main Algebra chain
|
||||
- `contentEquals` from Buffer. It moved to the companion.
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -73,6 +77,7 @@
|
||||
- `toGrid` method.
|
||||
- Public visibility of `BufferAccessor2D`
|
||||
- `Real` class
|
||||
- StructureND identity and equals
|
||||
|
||||
### Fixed
|
||||
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
||||
|
58
README.md
@ -3,9 +3,7 @@
|
||||
|
||||
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
||||
|
||||
Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
||||
|
||||
Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
|
||||
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22kmath-core%22)
|
||||
|
||||
# KMath
|
||||
|
||||
@ -89,12 +87,12 @@ KMath is a modular library. Different modules provide different features with di
|
||||
> **Maturity**: PROTOTYPE
|
||||
>
|
||||
> **Features:**
|
||||
> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -110,8 +108,8 @@ KMath is a modular library. Different modules provide different features with di
|
||||
> **Maturity**: PROTOTYPE
|
||||
>
|
||||
> **Features:**
|
||||
> - [complex](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||
> - [quaternion](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||
> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -121,15 +119,15 @@ KMath is a modular library. Different modules provide different features with di
|
||||
> **Maturity**: DEVELOPMENT
|
||||
>
|
||||
> **Features:**
|
||||
> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||
> - [nd](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
|
||||
> - [linear](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
> - [buffers](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||
> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||
> - [algebras](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||
> - [nd](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
|
||||
> - [linear](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
> - [buffers](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||
> - [expressions](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||
performance calculations to code generation.
|
||||
> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
||||
> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||
> - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
|
||||
> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -159,9 +157,9 @@ One can still use generic algebras though.
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
>
|
||||
> **Features:**
|
||||
> - [RealVector](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealVector.kt) : Numpy-like operations for Buffers/Points
|
||||
> - [RealMatrix](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt) : Numpy-like operations for 2d real structures
|
||||
> - [grids](kmath-for-real/src/commonMain/kotlin/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
||||
> - [DoubleVector](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points
|
||||
> - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures
|
||||
> - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -171,10 +169,10 @@ One can still use generic algebras though.
|
||||
> **Maturity**: PROTOTYPE
|
||||
>
|
||||
> **Features:**
|
||||
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt
|
||||
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt
|
||||
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt
|
||||
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt
|
||||
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt
|
||||
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt
|
||||
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt
|
||||
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -208,9 +206,9 @@ One can still use generic algebras though.
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
>
|
||||
> **Features:**
|
||||
> - [nd4jarraystructure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray
|
||||
> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long
|
||||
> - [nd4jarrayfields](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : Fields over Nd4jArrayStructure of Float and Double
|
||||
> - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
|
||||
> - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long
|
||||
> - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -256,8 +254,8 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api("kscience.kmath:kmath-core:() -> kotlin.Any")
|
||||
// api("kscience.kmath:kmath-core-jvm:() -> kotlin.Any") for jvm-specific version
|
||||
api("space.kscience:kmath-core:0.3.0-dev-3")
|
||||
// api("kscience.kmath:kmath-core-jvm:0.3.0-dev-3") for jvm-specific version
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -20,7 +20,7 @@ allprojects {
|
||||
}
|
||||
|
||||
group = "space.kscience"
|
||||
version = "0.3.0"
|
||||
version = "0.3.0-dev-3"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
@ -31,7 +31,7 @@ multiplication;
|
||||
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
|
||||
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
|
||||
|
||||
A typical implementation of `Field<T>` is the `RealField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
||||
A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
||||
|
||||
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
|
||||
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot`
|
||||
|
@ -13,27 +13,30 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath24"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path22"
|
||||
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath><clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path34"
|
||||
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
|
||||
id="g10"><g
|
||||
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1299.34,651.602 h 4653.75 v 3208.87 H 1299.34 Z" /><path
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1651.48,1093.71 h 4076.99 v 114.609 H 1651.48 Z" /><g
|
||||
id="g18"><g
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1651.48,1093.71 h 4076.99 v 114.609 H 1651.48 Z"/><g
|
||||
id="g18"><g
|
||||
clip-path="url(#clipPath24)"
|
||||
id="g20"><g
|
||||
transform="matrix(6720,0,0,2810.4,0,1589.6)"
|
||||
@ -45,7 +48,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g30"><g
|
||||
id="g30"><g
|
||||
clip-path="url(#clipPath36)"
|
||||
id="g32"><g
|
||||
transform="matrix(3312,0,0,1591.2,3410,-1.19998)"
|
||||
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 248 KiB |
@ -13,35 +13,37 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath32"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path30"
|
||||
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
|
||||
id="g10"><g
|
||||
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 318.789,2616.17 6643.05,4723.79 c 239.45,79.76 496.44,-48.75 576.29,-288.17 79.8,-239.41 -48.72,-496.4 -288.13,-576.21 L 606.949,1751.84 c -239.449,-79.81 -496.437,48.71 -576.2888,288.12 -79.8008,239.45 48.7187,496.45 288.1288,576.21 z" /><path
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 3751.56,538.199 6636.91,4443.95 c 109.22,147.89 316.21,178.98 464.11,69.76 147.89,-109.22 178.98,-316.21 69.76,-464.06 L 4285.43,143.91 C 4176.17,-3.98047 3969.18,-35.0781 3821.29,74.1406 3673.44,183.359 3642.3,390.309 3751.56,538.199 Z" /><path
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 1400.43,708.48 H 6418.24 V 4168.4 H 1400.43 Z" /><path
|
||||
id="path20"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 6145.16,1753.83 h -358.6 V 3271.02 L 5158.28,1753.83 H 5005 L 4379.69,3271.02 V 1753.83 h -358.6 v 2044.53 h 505.79 l 554.68,-1345.63 557.97,1345.63 h 505.63 z" /><path
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1780.12,1185.24 h 4395.94 v 123.551 H 1780.12 Z" /><path
|
||||
id="path24"
|
||||
style="fill:none;stroke:#000000;stroke-width:22.00740051;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1780.12,3798.09 c 0,-2044.73 0,-2044.73 0,-2044.73 H 3824.84 L 2806.17,2778.24 3824.84,3798.09" /><g
|
||||
id="g26"><g
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 3751.56,538.199 6636.91,4443.95 c 109.22,147.89 316.21,178.98 464.11,69.76 147.89,-109.22 178.98,-316.21 69.76,-464.06 L 4285.43,143.91 C 4176.17,-3.98047 3969.18,-35.0781 3821.29,74.1406 3673.44,183.359 3642.3,390.309 3751.56,538.199 Z"/><path
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 1400.43,708.48 H 6418.24 V 4168.4 H 1400.43 Z"/><path
|
||||
id="path20"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 6145.16,1753.83 h -358.6 V 3271.02 L 5158.28,1753.83 H 5005 L 4379.69,3271.02 V 1753.83 h -358.6 v 2044.53 h 505.79 l 554.68,-1345.63 557.97,1345.63 h 505.63 z"/><path
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1780.12,1185.24 h 4395.94 v 123.551 H 1780.12 Z"/><path
|
||||
id="path24"
|
||||
style="fill:none;stroke:#000000;stroke-width:22.00740051;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1780.12,3798.09 c 0,-2044.73 0,-2044.73 0,-2044.73 H 3824.84 L 2806.17,2778.24 3824.84,3798.09"/><g
|
||||
id="g26"><g
|
||||
clip-path="url(#clipPath32)"
|
||||
id="g28"><g
|
||||
transform="matrix(2052,0,0,2052,1780,1748)"
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@ -13,35 +13,40 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath24"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path22"
|
||||
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath><clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path34"
|
||||
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath><clipPath
|
||||
id="clipPath48"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath48"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path46"
|
||||
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath><clipPath
|
||||
id="clipPath60"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath60"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path58"
|
||||
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
|
||||
id="g10"><g
|
||||
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 791.328,957.73 h 6401.56 V 3245.31 H 791.328 Z" /><path
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1049.45,1214.42 h 2988.24 v 86.9883 H 1049.45 Z" /><g
|
||||
id="g18"><g
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1049.45,1214.42 h 2988.24 v 86.9883 H 1049.45 Z"/><g
|
||||
id="g18"><g
|
||||
clip-path="url(#clipPath24)"
|
||||
id="g20"><g
|
||||
transform="matrix(6470.4,0,0,1272,0,3008)"
|
||||
@ -53,7 +58,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g30"><g
|
||||
id="g30"><g
|
||||
clip-path="url(#clipPath36)"
|
||||
id="g32"><g
|
||||
transform="matrix(7000.8,0,0,1420.8,0,1589.2)"
|
||||
@ -65,7 +70,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g42"><g
|
||||
id="g42"><g
|
||||
clip-path="url(#clipPath48)"
|
||||
id="g44"><g
|
||||
transform="matrix(6470.4,0,0,12,0,1578)"
|
||||
@ -77,7 +82,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g54"><g
|
||||
id="g54"><g
|
||||
clip-path="url(#clipPath60)"
|
||||
id="g56"><g
|
||||
transform="matrix(3180,0,0,1581.6,3280,-1.59972)"
|
||||
|
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 278 KiB |
@ -13,123 +13,144 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath40"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path38"
|
||||
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath52"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath52"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path50"
|
||||
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath64"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath64"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path62"
|
||||
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath><clipPath
|
||||
id="clipPath76"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath76"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path74"
|
||||
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath88"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath88"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path86"
|
||||
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath100"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath100"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path98"
|
||||
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath><clipPath
|
||||
id="clipPath112"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath112"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path110"
|
||||
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath124"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath124"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path122"
|
||||
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath><clipPath
|
||||
id="clipPath136"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath136"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path134"
|
||||
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath148"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath148"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path146"
|
||||
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath><clipPath
|
||||
id="clipPath160"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath160"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path158"
|
||||
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath172"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath172"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path170"
|
||||
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath184"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath184"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path182"
|
||||
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath><clipPath
|
||||
id="clipPath196"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath196"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path194"
|
||||
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath208"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath208"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path206"
|
||||
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath220"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath220"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path218"
|
||||
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath232"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath232"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path230"
|
||||
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath><clipPath
|
||||
id="clipPath244"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath244"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path242"
|
||||
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath256"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath256"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path254"
|
||||
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath268"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath268"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path266"
|
||||
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
|
||||
id="g10"><g
|
||||
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 265.859,2205.39 5500.51,3949.84 c 198.16,66.06 410.9,-40.31 476.99,-238.51 66.05,-198.17 -40.31,-410.86 -238.48,-476.92 L 504.379,1489.96 c -198.168,-66.05 -410.8985,40.31 -476.9571,238.48 -66.0938,198.16 40.2773,410.9 238.4371,476.95 z" /><path
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3096.33,444.379 2388.2,3232.811 c 90.43,122.38 261.76,148.12 384.18,57.73 122.38,-90.39 148.13,-261.72 57.74,-384.1 L 3538.2,117.969 C 3447.77,-4.41016 3276.45,-30.1602 3154.06,60.2305 3031.64,150.66 3005.9,321.949 3096.33,444.379 Z" /><path
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 734.691,901.211 h 5982.5 v 2109.69 h -5982.5 z" /><path
|
||||
id="path20"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3724.45,1489.53 h -225.93 v 956.09 l -395.94,-956.09 h -96.56 l -394.07,956.09 v -956.09 h -225.93 v 1288.28 h 318.59 l 349.69,-847.97 351.4,847.97 h 318.75 z" /><path
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 4767.23,1489.53 H 4564.41 V 1590 c -72.11,-82.42 -172.5,-123.59 -301.25,-123.59 -85,0 -160.39,27.34 -226.09,82.03 -65.62,54.68 -98.44,130.31 -98.44,226.87 0,99.14 32.5,174.46 97.5,225.94 65.08,51.56 140.78,77.34 227.03,77.34 132.58,0 233.01,-39.92 301.25,-119.68 v 139.06 c 0,54.06 -19.96,96.48 -59.84,127.34 -39.92,30.94 -92.73,46.41 -158.44,46.41 -104.29,0 -196.33,-39.3 -276.09,-117.81 L 3986.91,2295 c 105.63,100.39 236.29,150.62 392.04,150.62 114.68,0 208.04,-27.1 280.15,-81.24 72.07,-54.07 108.13,-139.65 108.13,-256.72 z m -424.85,115.94 c 101.64,0 175.67,32.19 222.03,96.56 v 140.94 c -46.36,64.37 -120.39,96.56 -222.03,96.56 -58.04,0 -105.74,-15.47 -143.12,-46.41 -37.31,-30.85 -55.94,-71.36 -55.94,-121.56 0,-50.23 18.63,-90.47 55.94,-120.78 37.38,-30.23 85.08,-45.31 143.12,-45.31 z" /><path
|
||||
id="path24"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 5308.32,1466.41 c -78.55,0 -138.12,20.58 -178.75,61.71 -40.55,41.26 -60.78,100.47 -60.78,177.66 v 538.91 h -154.53 v 177.65 h 154.53 v 255 h 202.81 v -255 h 189.22 V 2244.69 H 5271.6 v -488.6 c 0,-33.55 7.7,-60.31 23.13,-80.31 15.5,-19.92 37.42,-29.84 65.78,-29.84 41.13,0 71.4,10.94 90.78,32.81 l 48.28,-152.5 c -42.5,-39.88 -106.25,-59.84 -191.25,-59.84 z" /><path
|
||||
id="path26"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 6477.38,1489.53 h -202.65 v 587.19 c 0,68.2 -16.49,116.8 -49.38,145.78 -32.81,28.95 -79.49,43.44 -140,43.44 -47.62,0 -92.65,-12.27 -135.15,-36.72 -42.5,-24.49 -77.31,-54.06 -104.38,-88.75 v -650.94 h -202.66 v 1288.28 h 202.66 V 2295 c 34.77,41.13 81.45,76.48 140,106.09 58.63,29.69 122.07,44.53 190.31,44.53 200.82,0 301.25,-98.55 301.25,-295.62 z" /><path
|
||||
id="path28"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 973.949,1128.48 h 2769.84 v 80.6211 H 973.949 Z" /><path
|
||||
id="path30"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
d="m 978.828,2781.72 c 0,-1292.5 0,-1292.5 0,-1292.5 H 2262.3 l -639.45,647.85 639.45,644.65" /><path
|
||||
id="path32"
|
||||
style="fill:none;stroke:#000000;stroke-width:13.86260033;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 978.828,2781.72 c 0,-1292.5 0,-1292.5 0,-1292.5 H 2262.3 l -639.45,647.85 639.45,644.65" /><g
|
||||
id="g34"><g
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3096.33,444.379 2388.2,3232.811 c 90.43,122.38 261.76,148.12 384.18,57.73 122.38,-90.39 148.13,-261.72 57.74,-384.1 L 3538.2,117.969 C 3447.77,-4.41016 3276.45,-30.1602 3154.06,60.2305 3031.64,150.66 3005.9,321.949 3096.33,444.379 Z"/><path
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 734.691,901.211 h 5982.5 v 2109.69 h -5982.5 z"/><path
|
||||
id="path20"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3724.45,1489.53 h -225.93 v 956.09 l -395.94,-956.09 h -96.56 l -394.07,956.09 v -956.09 h -225.93 v 1288.28 h 318.59 l 349.69,-847.97 351.4,847.97 h 318.75 z"/><path
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 4767.23,1489.53 H 4564.41 V 1590 c -72.11,-82.42 -172.5,-123.59 -301.25,-123.59 -85,0 -160.39,27.34 -226.09,82.03 -65.62,54.68 -98.44,130.31 -98.44,226.87 0,99.14 32.5,174.46 97.5,225.94 65.08,51.56 140.78,77.34 227.03,77.34 132.58,0 233.01,-39.92 301.25,-119.68 v 139.06 c 0,54.06 -19.96,96.48 -59.84,127.34 -39.92,30.94 -92.73,46.41 -158.44,46.41 -104.29,0 -196.33,-39.3 -276.09,-117.81 L 3986.91,2295 c 105.63,100.39 236.29,150.62 392.04,150.62 114.68,0 208.04,-27.1 280.15,-81.24 72.07,-54.07 108.13,-139.65 108.13,-256.72 z m -424.85,115.94 c 101.64,0 175.67,32.19 222.03,96.56 v 140.94 c -46.36,64.37 -120.39,96.56 -222.03,96.56 -58.04,0 -105.74,-15.47 -143.12,-46.41 -37.31,-30.85 -55.94,-71.36 -55.94,-121.56 0,-50.23 18.63,-90.47 55.94,-120.78 37.38,-30.23 85.08,-45.31 143.12,-45.31 z"/><path
|
||||
id="path24"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 5308.32,1466.41 c -78.55,0 -138.12,20.58 -178.75,61.71 -40.55,41.26 -60.78,100.47 -60.78,177.66 v 538.91 h -154.53 v 177.65 h 154.53 v 255 h 202.81 v -255 h 189.22 V 2244.69 H 5271.6 v -488.6 c 0,-33.55 7.7,-60.31 23.13,-80.31 15.5,-19.92 37.42,-29.84 65.78,-29.84 41.13,0 71.4,10.94 90.78,32.81 l 48.28,-152.5 c -42.5,-39.88 -106.25,-59.84 -191.25,-59.84 z"/><path
|
||||
id="path26"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 6477.38,1489.53 h -202.65 v 587.19 c 0,68.2 -16.49,116.8 -49.38,145.78 -32.81,28.95 -79.49,43.44 -140,43.44 -47.62,0 -92.65,-12.27 -135.15,-36.72 -42.5,-24.49 -77.31,-54.06 -104.38,-88.75 v -650.94 h -202.66 v 1288.28 h 202.66 V 2295 c 34.77,41.13 81.45,76.48 140,106.09 58.63,29.69 122.07,44.53 190.31,44.53 200.82,0 301.25,-98.55 301.25,-295.62 z"/><path
|
||||
id="path28"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 973.949,1128.48 h 2769.84 v 80.6211 H 973.949 Z"/><path
|
||||
id="path30"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
d="m 978.828,2781.72 c 0,-1292.5 0,-1292.5 0,-1292.5 H 2262.3 l -639.45,647.85 639.45,644.65"/><path
|
||||
id="path32"
|
||||
style="fill:none;stroke:#000000;stroke-width:13.86260033;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 978.828,2781.72 c 0,-1292.5 0,-1292.5 0,-1292.5 H 2262.3 l -639.45,647.85 639.45,644.65"/><g
|
||||
id="g34"><g
|
||||
clip-path="url(#clipPath40)"
|
||||
id="g36"><g
|
||||
transform="matrix(1370.4,0,0,12,2370,2778)"
|
||||
@ -141,7 +162,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g46"><g
|
||||
id="g46"><g
|
||||
clip-path="url(#clipPath52)"
|
||||
id="g48"><g
|
||||
transform="matrix(861.6,0,0,12,5630,2778)"
|
||||
@ -153,7 +174,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g58"><g
|
||||
id="g58"><g
|
||||
clip-path="url(#clipPath64)"
|
||||
id="g60"><g
|
||||
transform="matrix(1300.8,0,0,91.2,970,2688.8)"
|
||||
@ -165,7 +186,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g70"><g
|
||||
id="g70"><g
|
||||
clip-path="url(#clipPath76)"
|
||||
id="g72"><g
|
||||
transform="matrix(1370.4,0,0,91.2,2370,2688.8)"
|
||||
@ -177,7 +198,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g82"><g
|
||||
id="g82"><g
|
||||
clip-path="url(#clipPath88)"
|
||||
id="g84"><g
|
||||
transform="matrix(861.6,0,0,91.2,5630,2688.8)"
|
||||
@ -189,7 +210,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g94"><g
|
||||
id="g94"><g
|
||||
clip-path="url(#clipPath100)"
|
||||
id="g96"><g
|
||||
transform="matrix(1300.8,0,0,230.4,970,2459.6)"
|
||||
@ -201,7 +222,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g106"><g
|
||||
id="g106"><g
|
||||
clip-path="url(#clipPath112)"
|
||||
id="g108"><g
|
||||
transform="matrix(1370.4,0,0,230.4,2370,2459.6)"
|
||||
@ -213,7 +234,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g118"><g
|
||||
id="g118"><g
|
||||
clip-path="url(#clipPath124)"
|
||||
id="g120"><g
|
||||
transform="matrix(621.6,0,0,230.4,4900,2459.6)"
|
||||
@ -225,7 +246,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g130"><g
|
||||
id="g130"><g
|
||||
clip-path="url(#clipPath136)"
|
||||
id="g132"><g
|
||||
transform="matrix(861.6,0,0,230.4,5630,2459.6)"
|
||||
@ -237,7 +258,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g142"><g
|
||||
id="g142"><g
|
||||
clip-path="url(#clipPath148)"
|
||||
id="g144"><g
|
||||
transform="matrix(1300.8,0,0,981.6,970,1478.4)"
|
||||
@ -249,7 +270,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g154"><g
|
||||
id="g154"><g
|
||||
clip-path="url(#clipPath160)"
|
||||
id="g156"><g
|
||||
transform="matrix(1370.4,0,0,981.6,2370,1478.4)"
|
||||
@ -261,7 +282,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g166"><g
|
||||
id="g166"><g
|
||||
clip-path="url(#clipPath172)"
|
||||
id="g168"><g
|
||||
transform="matrix(861.6,0,0,981.6,3920,1478.4)"
|
||||
@ -273,7 +294,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g178"><g
|
||||
id="g178"><g
|
||||
clip-path="url(#clipPath184)"
|
||||
id="g180"><g
|
||||
transform="matrix(621.6,0,0,981.6,4900,1478.4)"
|
||||
@ -285,7 +306,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g190"><g
|
||||
id="g190"><g
|
||||
clip-path="url(#clipPath196)"
|
||||
id="g192"><g
|
||||
transform="matrix(861.6,0,0,981.6,5630,1478.4)"
|
||||
@ -297,7 +318,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g202"><g
|
||||
id="g202"><g
|
||||
clip-path="url(#clipPath208)"
|
||||
id="g204"><g
|
||||
transform="matrix(1370.4,0,0,12,2370,1468)"
|
||||
@ -309,7 +330,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g214"><g
|
||||
id="g214"><g
|
||||
clip-path="url(#clipPath220)"
|
||||
id="g216"><g
|
||||
transform="matrix(861.6,0,0,12,3920,1468)"
|
||||
@ -321,7 +342,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g226"><g
|
||||
id="g226"><g
|
||||
clip-path="url(#clipPath232)"
|
||||
id="g228"><g
|
||||
transform="matrix(621.6,0,0,12,4900,1468)"
|
||||
@ -333,7 +354,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g238"><g
|
||||
id="g238"><g
|
||||
clip-path="url(#clipPath244)"
|
||||
id="g240"><g
|
||||
transform="matrix(861.6,0,0,12,5630,1468)"
|
||||
@ -345,7 +366,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g250"><g
|
||||
id="g250"><g
|
||||
clip-path="url(#clipPath256)"
|
||||
id="g252"><g
|
||||
transform="matrix(861.6,0,0,21.6,3920,1448.4)"
|
||||
@ -357,7 +378,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g262"><g
|
||||
id="g262"><g
|
||||
clip-path="url(#clipPath268)"
|
||||
id="g264"><g
|
||||
transform="matrix(621.6,0,0,21.6,4900,1448.4)"
|
||||
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
@ -10,11 +10,11 @@ structures. In `kmath` performance depends on which particular context was used
|
||||
Let us consider following contexts:
|
||||
```kotlin
|
||||
// automatically build context most suited for given type.
|
||||
val autoField = NDField.auto(RealField, dim, dim)
|
||||
val autoField = NDField.auto(DoubleField, dim, dim)
|
||||
// specialized nd-field for Double. It works as generic Double field as well
|
||||
val specializedField = NDField.real(dim, dim)
|
||||
//A generic boxing field. It should be used for objects, not primitives.
|
||||
val genericField = NDField.buffered(RealField, dim, dim)
|
||||
val genericField = NDField.buffered(DoubleField, dim, dim)
|
||||
```
|
||||
Now let us perform several tests and see which implementation is best suited for each case:
|
||||
|
||||
|
6
docs/templates/ARTIFACT-TEMPLATE.md
vendored
@ -13,9 +13,6 @@
|
||||
> maven { url 'https://repo.kotlin.link' }
|
||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
>// Uncomment if repo.kotlin.link is unavailable
|
||||
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
||||
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
@ -29,9 +26,6 @@
|
||||
> maven("https://repo.kotlin.link")
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
>// Uncomment if repo.kotlin.link is unavailable
|
||||
>// maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
>// maven("https://dl.bintray.com/mipt-npm/dev")
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
|
6
docs/templates/README-TEMPLATE.md
vendored
@ -3,9 +3,7 @@
|
||||
|
||||
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
||||
|
||||
Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
||||
|
||||
Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
|
||||
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22kmath-core%22)
|
||||
|
||||
# KMath
|
||||
|
||||
@ -106,7 +104,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api("kscience.kmath:kmath-core:$version")
|
||||
api("${group}:kmath-core:$version")
|
||||
// api("kscience.kmath:kmath-core-jvm:$version") for jvm-specific version
|
||||
}
|
||||
```
|
||||
|
@ -113,6 +113,6 @@ tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "11"
|
||||
}
|
||||
|
||||
readme{
|
||||
readme {
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
}
|
||||
|
@ -5,14 +5,14 @@ import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.complex.Complex
|
||||
import space.kscience.kmath.complex.complex
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
import space.kscience.kmath.structures.RealBuffer
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class BufferBenchmark {
|
||||
@Benchmark
|
||||
fun genericRealBufferReadWrite() {
|
||||
val buffer = RealBuffer(size) { it.toDouble() }
|
||||
fun genericDoubleBufferReadWrite() {
|
||||
val buffer = DoubleBuffer(size) { it.toDouble() }
|
||||
|
||||
(0 until size).forEach {
|
||||
buffer[it]
|
||||
|
@ -8,7 +8,7 @@ import space.kscience.kmath.commons.linear.CMLinearSpace
|
||||
import space.kscience.kmath.ejml.EjmlLinearSpace
|
||||
import space.kscience.kmath.linear.LinearSpace
|
||||
import space.kscience.kmath.linear.invoke
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@ -51,7 +51,7 @@ internal class DotBenchmark {
|
||||
|
||||
@Benchmark
|
||||
fun bufferedDot(blackhole: Blackhole) {
|
||||
LinearSpace.auto(RealField).invoke {
|
||||
LinearSpace.auto(DoubleField).invoke {
|
||||
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.invoke
|
||||
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 kotlin.random.Random
|
||||
|
||||
@ -68,7 +68,7 @@ internal class ExpressionsInterpretersBenchmark {
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private val algebra = RealField
|
||||
private val algebra = DoubleField
|
||||
private val x by symbol
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.nd.*
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@ -13,7 +13,7 @@ internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun autoFieldAdd(blackhole: Blackhole) {
|
||||
with(autoField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += one }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -22,7 +22,7 @@ internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun specializedFieldAdd(blackhole: Blackhole) {
|
||||
with(specializedField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -32,7 +32,7 @@ internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun boxingFieldAdd(blackhole: Blackhole) {
|
||||
with(genericField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -41,8 +41,8 @@ internal class NDFieldBenchmark {
|
||||
private companion object {
|
||||
private const val dim = 1000
|
||||
private const val n = 100
|
||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
private val specializedField = NDAlgebra.real(dim, dim)
|
||||
private val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val specializedField = AlgebraND.real(dim, dim)
|
||||
private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import org.jetbrains.bio.viktor.F64Array
|
||||
import space.kscience.kmath.nd.NDAlgebra
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.auto
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.viktor.ViktorNDField
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@ -17,7 +17,7 @@ internal class ViktorBenchmark {
|
||||
@Benchmark
|
||||
fun automaticFieldAddition(blackhole: Blackhole) {
|
||||
with(autoField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -26,7 +26,7 @@ internal class ViktorBenchmark {
|
||||
@Benchmark
|
||||
fun realFieldAddition(blackhole: Blackhole) {
|
||||
with(realField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -54,8 +54,8 @@ internal class ViktorBenchmark {
|
||||
private const val n = 100
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
private val realField = NDAlgebra.real(dim, dim)
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val realField = AlgebraND.real(dim, dim)
|
||||
private val viktorField = ViktorNDField(dim, dim)
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
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.real
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.viktor.ViktorNDField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.viktor.ViktorFieldND
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class ViktorLogBenchmark {
|
||||
@ -46,8 +46,8 @@ internal class ViktorLogBenchmark {
|
||||
private const val n = 100
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
private val realNdField = NDAlgebra.real(dim, dim)
|
||||
private val viktorField = ViktorNDField(intArrayOf(dim, dim))
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val realNdField = AlgebraND.real(dim, dim)
|
||||
private val viktorField = ViktorFieldND(intArrayOf(dim, dim))
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package space.kscience.kmath.ast
|
||||
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
|
||||
fun main() {
|
||||
val expr = RealField.mstInField {
|
||||
val expr = DoubleField.mstInField {
|
||||
val x = bindSymbol("x")
|
||||
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.symbol
|
||||
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
|
||||
@ -14,11 +14,11 @@ import space.kscience.kmath.operations.RealField
|
||||
fun main() {
|
||||
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()
|
||||
.derivative(x)
|
||||
.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))
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import kscience.plotly.models.TraceValues
|
||||
import space.kscience.kmath.commons.optimization.chiSquared
|
||||
import space.kscience.kmath.commons.optimization.minimize
|
||||
import space.kscience.kmath.expressions.symbol
|
||||
import space.kscience.kmath.real.RealVector
|
||||
import space.kscience.kmath.real.DoubleVector
|
||||
import space.kscience.kmath.real.map
|
||||
import space.kscience.kmath.real.step
|
||||
import space.kscience.kmath.stat.*
|
||||
@ -26,7 +26,7 @@ private val c by symbol
|
||||
/**
|
||||
* Shortcut to use buffers in plotly
|
||||
*/
|
||||
operator fun TraceValues.invoke(vector: RealVector) {
|
||||
operator fun TraceValues.invoke(vector: DoubleVector) {
|
||||
numbers = vector.asIterable()
|
||||
}
|
||||
|
||||
@ -90,10 +90,10 @@ fun main() {
|
||||
}
|
||||
}
|
||||
br()
|
||||
h3{
|
||||
h3 {
|
||||
+"Fit result: $result"
|
||||
}
|
||||
h3{
|
||||
h3 {
|
||||
+"Chi2/dof = ${result.value / (x.size - 3)}"
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package space.kscience.kmath.linear
|
||||
|
||||
import space.kscience.kmath.real.*
|
||||
import space.kscience.kmath.structures.RealBuffer
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
|
||||
fun main() {
|
||||
val x0 = Point(0.0, 0.0, 0.0)
|
||||
val sigma = Point(1.0, 1.0, 1.0)
|
||||
val x0 = DoubleVector(0.0, 0.0, 0.0)
|
||||
val sigma = DoubleVector(1.0, 1.0, 1.0)
|
||||
|
||||
val gaussian: (Point<Double>) -> Double = { x ->
|
||||
require(x.size == x0.size)
|
||||
@ -14,9 +14,9 @@ fun main() {
|
||||
|
||||
fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> {
|
||||
require(x.size == x0.size)
|
||||
return RealBuffer(x.size) { i ->
|
||||
return DoubleBuffer(x.size) { i ->
|
||||
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 f0 = invoke(x - dVector / 2)
|
||||
(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.nd.NDAlgebra
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
|
||||
fun main() {
|
||||
// 2d element
|
||||
val element = NDAlgebra.complex(2, 2).produce { (i, j) ->
|
||||
val element = AlgebraND.complex(2, 2).produce { (i, j) ->
|
||||
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
||||
}
|
||||
println(element)
|
||||
|
||||
// 1d element operation
|
||||
val result = with(NDAlgebra.complex(8)) {
|
||||
val result = with(AlgebraND.complex(8)) {
|
||||
val a = produce { (it) -> i * it - it.toDouble() }
|
||||
val b = 3
|
||||
val c = Complex(1.0, 1.0)
|
||||
|
@ -4,8 +4,8 @@ package space.kscience.kmath.structures
|
||||
|
||||
import space.kscience.kmath.complex.*
|
||||
import space.kscience.kmath.linear.transpose
|
||||
import space.kscience.kmath.nd.NDAlgebra
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.as2D
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.operations.invoke
|
||||
@ -15,12 +15,12 @@ fun main() {
|
||||
val dim = 1000
|
||||
val n = 1000
|
||||
|
||||
val realField = NDAlgebra.real(dim, dim)
|
||||
val complexField: ComplexNDField = NDAlgebra.complex(dim, dim)
|
||||
val realField = AlgebraND.real(dim, dim)
|
||||
val complexField: ComplexFieldND = AlgebraND.complex(dim, dim)
|
||||
|
||||
val realTime = measureTimeMillis {
|
||||
realField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) {
|
||||
res += 1.0
|
||||
}
|
||||
@ -31,7 +31,7 @@ fun main() {
|
||||
|
||||
val complexTime = measureTimeMillis {
|
||||
complexField {
|
||||
var res: NDStructure<Complex> = one
|
||||
var res: StructureND<Complex> = one
|
||||
repeat(n) {
|
||||
res += 1.0
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import kotlinx.coroutines.GlobalScope
|
||||
import org.nd4j.linalg.factory.Nd4j
|
||||
import space.kscience.kmath.nd.*
|
||||
import space.kscience.kmath.nd4j.Nd4jArrayField
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.viktor.ViktorNDField
|
||||
import kotlin.contracts.InvocationKind
|
||||
@ -24,56 +24,56 @@ fun main() {
|
||||
val n = 1000
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
// specialized nd-field for Double. It works as generic Double field as well
|
||||
val realField = NDAlgebra.real(dim, dim)
|
||||
val realField = AlgebraND.real(dim, dim)
|
||||
//A generic boxing field. It should be used for objects, not primitives.
|
||||
val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
||||
val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||
// Nd4j specialized field.
|
||||
val nd4jField = Nd4jArrayField.real(dim, dim)
|
||||
//viktor field
|
||||
val viktorField = ViktorNDField(dim,dim)
|
||||
val viktorField = ViktorNDField(dim, dim)
|
||||
//parallel processing based on Java Streams
|
||||
val parallelField = NDAlgebra.realWithStream(dim,dim)
|
||||
val parallelField = AlgebraND.realWithStream(dim, dim)
|
||||
|
||||
measureAndPrint("Boxing addition") {
|
||||
boxingField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Specialized addition") {
|
||||
realField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Nd4j specialized addition") {
|
||||
nd4jField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Viktor addition") {
|
||||
viktorField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Parallel stream addition") {
|
||||
parallelField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Automatic field addition") {
|
||||
autoField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
import space.kscience.kmath.nd.BufferND
|
||||
import space.kscience.kmath.nd.DefaultStrides
|
||||
import space.kscience.kmath.nd.NDBuffer
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||
fun main() {
|
||||
val n = 6000
|
||||
val array = DoubleArray(n * n) { 1.0 }
|
||||
val buffer = RealBuffer(array)
|
||||
val buffer = DoubleBuffer(array)
|
||||
val strides = DefaultStrides(intArrayOf(n, n))
|
||||
val structure = NDBuffer(strides, buffer)
|
||||
val structure = BufferND(strides, buffer)
|
||||
|
||||
measureTimeMillis {
|
||||
var res = 0.0
|
||||
|
@ -1,13 +1,13 @@
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.mapToBuffer
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
fun main() {
|
||||
val n = 6000
|
||||
val structure = NDStructure.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
|
||||
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
|
||||
println("Structure mapping finished in $time1 millis")
|
||||
@ -20,10 +20,10 @@ fun main() {
|
||||
|
||||
println("Array mapping finished in $time2 millis")
|
||||
|
||||
val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
|
||||
val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 })
|
||||
|
||||
val time3 = measureTimeMillis {
|
||||
val target = RealBuffer(DoubleArray(n * n))
|
||||
val target = DoubleBuffer(DoubleArray(n * n))
|
||||
val res = array.forEachIndexed { index, value ->
|
||||
target[index] = value + 1
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
kotlin.code.style=official
|
||||
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||
kotlin.mpp.stability.nowarn=true
|
||||
kotlin.native.enableDependencyPropagation=false
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
|
||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G
|
||||
org.gradle.parallel=true
|
||||
|
||||
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||
kotlin.native.enableDependencyPropagation=false
|
||||
|
||||
|
@ -2,17 +2,17 @@
|
||||
|
||||
This subproject implements the following features:
|
||||
|
||||
- [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
- [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
- [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
- [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
- [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
- [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
- [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
- [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
- [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
- [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
- [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
- [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
|
||||
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `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)
|
||||
>
|
||||
@ -25,13 +25,10 @@ This subproject implements the following features:
|
||||
> maven { url 'https://repo.kotlin.link' }
|
||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
>// Uncomment if repo.kotlin.link is unavailable
|
||||
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
||||
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'space.kscience:kmath-ast:0.2.0'
|
||||
> implementation 'space.kscience:kmath-ast:0.3.0-dev-3'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
@ -41,13 +38,10 @@ This subproject implements the following features:
|
||||
> maven("https://repo.kotlin.link")
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
>// Uncomment if repo.kotlin.link is unavailable
|
||||
>// maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
>// maven("https://dl.bintray.com/mipt-npm/dev")
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("space.kscience:kmath-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:
|
||||
|
||||
```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
|
||||
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:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
RealField.expression("x+2".parseMath())
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.expression("x+2".parseMath())
|
||||
```
|
||||
|
||||
#### Known issues
|
||||
@ -109,7 +103,7 @@ RealField.expression("x+2".parseMath())
|
||||
A similar feature is also available on JS.
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
The code above returns expression implemented with such a JS function:
|
||||
|
@ -58,36 +58,36 @@ readme {
|
||||
feature(
|
||||
id = "expression-language",
|
||||
description = "Expression language and its parser",
|
||||
ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt"
|
||||
ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst",
|
||||
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-building",
|
||||
description = "MST building algebraic structure",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-interpreter",
|
||||
description = "MST interpreter",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-jvm-codegen",
|
||||
description = "Dynamic MST to JVM bytecode compiler",
|
||||
ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt"
|
||||
ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-js-codegen",
|
||||
description = "Dynamic MST to JS compiler",
|
||||
ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt"
|
||||
ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt"
|
||||
)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
|
||||
For example, the following builder:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||
@ -49,8 +49,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
||||
This API extends MST and MstExpression, so you may optimize as both of them:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
RealField.expression("x+2".parseMath())
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.expression("x+2".parseMath())
|
||||
```
|
||||
|
||||
#### Known issues
|
||||
@ -64,7 +64,7 @@ RealField.expression("x+2".parseMath())
|
||||
A similar feature is also available on JS.
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
The code above returns expression implemented with such a JS function:
|
||||
|
@ -50,7 +50,7 @@ public object MstGroup : Group<MST>, NumericAlgebra<MST>, ScaleOperations<MST> {
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public object MstRing : Ring<MST>, NumbersAddOperations<MST>, ScaleOperations<MST> {
|
||||
public override val zero: MST.Numeric get() = MstGroup.zero
|
||||
public override val zero: MST.Numeric get() = MstGroup.zero
|
||||
public override val one: MST.Numeric = number(1.0)
|
||||
|
||||
public override fun number(value: Number): MST.Numeric = MstGroup.number(value)
|
||||
|
@ -5,7 +5,7 @@ import space.kscience.kmath.complex.ComplexField
|
||||
import space.kscience.kmath.complex.toComplex
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.ByteRing
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -73,7 +73,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
||||
|
||||
@Test
|
||||
fun realField() {
|
||||
val res1 = RealField.mstInField {
|
||||
val res1 = DoubleField.mstInField {
|
||||
+(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
|
||||
+ number(1),
|
||||
@ -81,7 +81,7 @@ internal class TestESTreeConsistencyWithInterpreter {
|
||||
) + zero
|
||||
}("x" to 2.0)
|
||||
|
||||
val res2 = RealField.mstInField {
|
||||
val res2 = DoubleField.mstInField {
|
||||
+(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
|
||||
+ number(1),
|
||||
|
@ -4,7 +4,7 @@ import space.kscience.kmath.ast.mstInExtendedField
|
||||
import space.kscience.kmath.ast.mstInField
|
||||
import space.kscience.kmath.ast.mstInGroup
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
@ -12,27 +12,29 @@ import kotlin.test.assertEquals
|
||||
internal class TestESTreeOperationsSupport {
|
||||
@Test
|
||||
fun testUnaryOperationInvocation() {
|
||||
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile()
|
||||
val expression = DoubleField.mstInGroup { -bindSymbol("x") }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-2.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
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)
|
||||
assertEquals(-1.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
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)
|
||||
}
|
||||
|
||||
@Test
|
||||
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)
|
||||
var s = 0.0
|
||||
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.expressions.invoke
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestESTreeSpecialization {
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
val expr = RealField
|
||||
val expr = DoubleField
|
||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||
.compile()
|
||||
|
||||
|
@ -86,7 +86,7 @@ internal inline fun ClassWriter.visitField(
|
||||
descriptor: String,
|
||||
signature: String?,
|
||||
value: Any?,
|
||||
block: FieldVisitor.() -> Unit
|
||||
block: FieldVisitor.() -> Unit,
|
||||
): FieldVisitor {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return visitField(access, name, descriptor, signature, value).apply(block)
|
||||
|
@ -5,7 +5,7 @@ import space.kscience.kmath.complex.ComplexField
|
||||
import space.kscience.kmath.complex.toComplex
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.ByteRing
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -73,7 +73,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
||||
|
||||
@Test
|
||||
fun realField() {
|
||||
val res1 = RealField.mstInField {
|
||||
val res1 = DoubleField.mstInField {
|
||||
+(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
|
||||
+ number(1),
|
||||
@ -81,7 +81,7 @@ internal class TestAsmConsistencyWithInterpreter {
|
||||
) + zero
|
||||
}("x" to 2.0)
|
||||
|
||||
val res2 = RealField.mstInField {
|
||||
val res2 = DoubleField.mstInField {
|
||||
+(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
|
||||
+ number(1),
|
||||
|
@ -4,7 +4,7 @@ import space.kscience.kmath.ast.mstInExtendedField
|
||||
import space.kscience.kmath.ast.mstInField
|
||||
import space.kscience.kmath.ast.mstInGroup
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
@ -12,27 +12,29 @@ import kotlin.test.assertEquals
|
||||
internal class TestAsmOperationsSupport {
|
||||
@Test
|
||||
fun testUnaryOperationInvocation() {
|
||||
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile()
|
||||
val expression = DoubleField.mstInGroup { -bindSymbol("x") }.compile()
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-2.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
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)
|
||||
assertEquals(-1.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
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)
|
||||
}
|
||||
|
||||
@Test
|
||||
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)
|
||||
var s = 0.0
|
||||
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.expressions.invoke
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestAsmSpecialization {
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
val expr = RealField
|
||||
val expr = DoubleField
|
||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||
.compile()
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
package space.kscience.kmath.ast
|
||||
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.Field
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class ParserPrecedenceTest {
|
||||
private val f: Field<Double> = RealField
|
||||
private val f: Field<Double> = DoubleField
|
||||
|
||||
@Test
|
||||
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
|
||||
|
@ -4,7 +4,7 @@ import space.kscience.kmath.complex.Complex
|
||||
import space.kscience.kmath.complex.ComplexField
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.Algebra
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -33,7 +33,7 @@ internal class ParserTest {
|
||||
@Test
|
||||
fun `evaluate MST with unary function`() {
|
||||
val mst = "sin(0)".parseMath()
|
||||
val res = RealField.evaluate(mst)
|
||||
val res = DoubleField.evaluate(mst)
|
||||
assertEquals(0.0, res)
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,6 @@ dependencies {
|
||||
api("org.apache.commons:commons-math3:3.6.1")
|
||||
}
|
||||
|
||||
readme{
|
||||
readme {
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
}
|
@ -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 space.kscience.kmath.linear.*
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.structures.RealBuffer
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
import kotlin.reflect.KClass
|
||||
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 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)
|
||||
|
||||
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> {
|
||||
@ -72,15 +25,15 @@ public inline class CMVector(public val origin: RealVector) : Point<Double> {
|
||||
|
||||
public fun RealVector.toPoint(): CMVector = CMVector(this)
|
||||
|
||||
public object CMLinearSpace : LinearSpace<Double, RealField> {
|
||||
override val elementAlgebra: RealField get() = RealField
|
||||
public object CMLinearSpace : LinearSpace<Double, DoubleField> {
|
||||
override val elementAlgebra: DoubleField get() = DoubleField
|
||||
|
||||
public override fun buildMatrix(
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
initializer: RealField.(i: Int, j: Int) -> Double,
|
||||
initializer: DoubleField.(i: Int, j: Int) -> Double,
|
||||
): 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))
|
||||
}
|
||||
|
||||
@ -102,8 +55,8 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
|
||||
internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this)
|
||||
internal fun RealVector.wrap(): CMVector = CMVector(this)
|
||||
|
||||
override fun buildVector(size: Int, initializer: RealField.(Int) -> Double): Point<Double> =
|
||||
ArrayRealVector(DoubleArray(size) { RealField.initializer(it) }).wrap()
|
||||
override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): Point<Double> =
|
||||
ArrayRealVector(DoubleArray(size) { DoubleField.initializer(it) }).wrap()
|
||||
|
||||
override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix =
|
||||
toCM().origin.add(other.toCM().origin).wrap()
|
||||
@ -134,13 +87,54 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
|
||||
|
||||
override fun Double.times(v: Point<Double>): CMVector =
|
||||
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) }
|
||||
}
|
||||
|
||||
CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
|
||||
override val l: Matrix<Double> by lazy {
|
||||
val cholesky = CholeskyDecomposition(origin)
|
||||
CMMatrix(cholesky.l) + LFeature
|
||||
}
|
||||
}
|
||||
|
||||
QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> {
|
||||
private val qr by lazy { QRDecomposition(origin) }
|
||||
override val q: Matrix<Double> by lazy { CMMatrix(qr.q) + OrthogonalFeature }
|
||||
override val r: Matrix<Double> by lazy { CMMatrix(qr.r) + UFeature }
|
||||
}
|
||||
|
||||
SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Double> {
|
||||
private val sv by lazy { SingularValueDecomposition(origin) }
|
||||
override val u: Matrix<Double> by lazy { CMMatrix(sv.u) }
|
||||
override val s: Matrix<Double> by lazy { CMMatrix(sv.s) }
|
||||
override val v: Matrix<Double> by lazy { CMMatrix(sv.v) }
|
||||
override val singularValues: Point<Double> by lazy { DoubleBuffer(sv.singularValues) }
|
||||
}
|
||||
else -> null
|
||||
}?.let(type::cast)
|
||||
}
|
||||
}
|
||||
|
||||
public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix =
|
||||
CMMatrix(origin.add(other.origin))
|
||||
public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix = CMMatrix(origin.add(other.origin))
|
||||
|
||||
public operator fun CMMatrix.minus(other: CMMatrix): CMMatrix =
|
||||
CMMatrix(origin.subtract(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))
|
||||
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(
|
||||
a: Matrix<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): DecompositionSolver = when (decomposition) {
|
||||
CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver
|
||||
CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver
|
||||
@ -26,16 +26,16 @@ public fun CMLinearSpace.solver(
|
||||
public fun CMLinearSpace.solve(
|
||||
a: Matrix<Double>,
|
||||
b: Matrix<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap()
|
||||
|
||||
public fun CMLinearSpace.solve(
|
||||
a: Matrix<Double>,
|
||||
b: Point<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint()
|
||||
|
||||
public fun CMLinearSpace.inverse(
|
||||
a: Matrix<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): 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.component2(): Double = value
|
||||
|
||||
public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
public class CMOptimizationProblem(override val symbols: List<Symbol>) :
|
||||
OptimizationProblem<Double>, SymbolIndexer, OptimizationFeature {
|
||||
private val optimizationData: HashMap<KClass<out OptimizationData>, OptimizationData> = HashMap()
|
||||
private var optimizatorBuilder: (() -> MultivariateOptimizer)? = null
|
||||
|
@ -10,6 +10,7 @@ import space.kscience.kmath.streaming.spread
|
||||
import space.kscience.kmath.structures.*
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Streaming and buffer transformations
|
||||
*/
|
||||
@ -17,7 +18,7 @@ public object Transformations {
|
||||
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
|
||||
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
|
||||
|
||||
private fun Buffer<Double>.asArray() = if (this is RealBuffer) {
|
||||
private fun Buffer<Double>.asArray() = if (this is DoubleBuffer) {
|
||||
array
|
||||
} else {
|
||||
DoubleArray(size) { i -> get(i) }
|
||||
@ -33,34 +34,34 @@ public object Transformations {
|
||||
|
||||
public fun fourier(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Complex, Complex> = {
|
||||
FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun realFourier(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Complex> = {
|
||||
FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun sine(
|
||||
normalization: DstNormalization = DstNormalization.STANDARD_DST_I,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Double> = {
|
||||
FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun cosine(
|
||||
normalization: DctNormalization = DctNormalization.STANDARD_DCT_I,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Double> = {
|
||||
FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun hadamard(
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Double> = {
|
||||
FastHadamardTransformer().transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
@ -72,7 +73,7 @@ public object Transformations {
|
||||
@FlowPreview
|
||||
public fun Flow<Buffer<Complex>>.FFT(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Buffer<Complex>> {
|
||||
val transform = Transformations.fourier(normalization, direction)
|
||||
return map { transform(it) }
|
||||
@ -82,7 +83,7 @@ public fun Flow<Buffer<Complex>>.FFT(
|
||||
@JvmName("realFFT")
|
||||
public fun Flow<Buffer<Double>>.FFT(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Buffer<Complex>> {
|
||||
val transform = Transformations.realFourier(normalization, direction)
|
||||
return map(transform)
|
||||
@ -96,7 +97,7 @@ public fun Flow<Buffer<Double>>.FFT(
|
||||
public fun Flow<Double>.FFT(
|
||||
bufferSize: Int = Int.MAX_VALUE,
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread()
|
||||
|
||||
/**
|
||||
|
@ -27,10 +27,10 @@ internal class AutoDiffTest {
|
||||
val y = bindSymbol("y")
|
||||
val z = x * (-sin(x * y) + y) + 2.0
|
||||
println(z.derivative(x))
|
||||
println(z.derivative(y,x))
|
||||
println(z.derivative(y, x))
|
||||
assertEquals(z.derivative(x, y), z.derivative(y, x))
|
||||
//check that improper order cause failure
|
||||
assertFails { z.derivative(x,x,y) }
|
||||
assertFails { z.derivative(x, x, y) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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](src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||
- [quaternion](src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
- [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||
- [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
|
||||
|
||||
> #### 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)
|
||||
>
|
||||
@ -21,13 +21,10 @@ Complex and hypercomplex number systems in KMath:
|
||||
> maven { url 'https://repo.kotlin.link' }
|
||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
>// Uncomment if repo.kotlin.link is unavailable
|
||||
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
|
||||
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'space.kscience:kmath-complex:0.2.0'
|
||||
> implementation 'space.kscience:kmath-complex:0.3.0-dev-3'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
@ -37,12 +34,9 @@ Complex and hypercomplex number systems in KMath:
|
||||
> maven("https://repo.kotlin.link")
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
>// Uncomment if repo.kotlin.link is unavailable
|
||||
>// maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
>// maven("https://dl.bintray.com/mipt-npm/dev")
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("space.kscience:kmath-complex:0.2.0")
|
||||
> implementation("space.kscience:kmath-complex:0.3.0-dev-3")
|
||||
> }
|
||||
> ```
|
||||
|
@ -25,12 +25,12 @@ readme {
|
||||
feature(
|
||||
id = "complex",
|
||||
description = "Complex Numbers",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/complex/Complex.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "quaternion",
|
||||
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
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.BufferedNDField
|
||||
import space.kscience.kmath.nd.NDAlgebra
|
||||
import space.kscience.kmath.nd.NDBuffer
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.BufferND
|
||||
import space.kscience.kmath.nd.BufferedFieldND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.operations.ExtendedField
|
||||
import space.kscience.kmath.operations.NumbersAddOperations
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
@ -16,16 +16,16 @@ import kotlin.contracts.contract
|
||||
* An optimized nd-field for complex numbers
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class ComplexNDField(
|
||||
public class ComplexFieldND(
|
||||
shape: IntArray,
|
||||
) : BufferedNDField<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
|
||||
NumbersAddOperations<NDStructure<Complex>>,
|
||||
ExtendedField<NDStructure<Complex>> {
|
||||
) : BufferedFieldND<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
|
||||
NumbersAddOperations<StructureND<Complex>>,
|
||||
ExtendedField<StructureND<Complex>> {
|
||||
|
||||
override val zero: NDBuffer<Complex> by lazy { produce { zero } }
|
||||
override val one: NDBuffer<Complex> by lazy { produce { one } }
|
||||
override val zero: BufferND<Complex> by lazy { produce { zero } }
|
||||
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
|
||||
return produce { d }
|
||||
}
|
||||
@ -34,15 +34,15 @@ public class ComplexNDField(
|
||||
// @Suppress("OVERRIDE_BY_INLINE")
|
||||
// override inline fun map(
|
||||
// arg: AbstractNDBuffer<Double>,
|
||||
// transform: RealField.(Double) -> Double,
|
||||
// transform: DoubleField.(Double) -> Double,
|
||||
// ): RealNDElement {
|
||||
// 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)
|
||||
// }
|
||||
//
|
||||
// @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)) }
|
||||
// return BufferedNDFieldElement(this, array)
|
||||
// }
|
||||
@ -50,7 +50,7 @@ public class ComplexNDField(
|
||||
// @Suppress("OVERRIDE_BY_INLINE")
|
||||
// override inline fun mapIndexed(
|
||||
// arg: AbstractNDBuffer<Double>,
|
||||
// transform: RealField.(index: IntArray, Double) -> Double,
|
||||
// transform: DoubleField.(index: IntArray, Double) -> Double,
|
||||
// ): RealNDElement {
|
||||
// check(arg)
|
||||
// return BufferedNDFieldElement(
|
||||
@ -67,7 +67,7 @@ public class ComplexNDField(
|
||||
// override inline fun combine(
|
||||
// a: AbstractNDBuffer<Double>,
|
||||
// b: AbstractNDBuffer<Double>,
|
||||
// transform: RealField.(Double, Double) -> Double,
|
||||
// transform: DoubleField.(Double, Double) -> Double,
|
||||
// ): RealNDElement {
|
||||
// check(a, b)
|
||||
// val buffer = RealBuffer(strides.linearSize) { offset ->
|
||||
@ -76,44 +76,44 @@ public class ComplexNDField(
|
||||
// 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 cos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { cos(it) }
|
||||
override fun tan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { tan(it) }
|
||||
override fun asin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { asin(it) }
|
||||
override fun acos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { acos(it) }
|
||||
override fun atan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { atan(it) }
|
||||
override fun sin(arg: StructureND<Complex>): BufferND<Complex> = arg.map { sin(it) }
|
||||
override fun cos(arg: StructureND<Complex>): BufferND<Complex> = arg.map { cos(it) }
|
||||
override fun tan(arg: StructureND<Complex>): BufferND<Complex> = arg.map { tan(it) }
|
||||
override fun asin(arg: StructureND<Complex>): BufferND<Complex> = arg.map { asin(it) }
|
||||
override fun acos(arg: StructureND<Complex>): BufferND<Complex> = arg.map { acos(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 cosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { cosh(it) }
|
||||
override fun tanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { tanh(it) }
|
||||
override fun asinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { asinh(it) }
|
||||
override fun acosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { acosh(it) }
|
||||
override fun atanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { atanh(it) }
|
||||
override fun sinh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { sinh(it) }
|
||||
override fun cosh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { cosh(it) }
|
||||
override fun tanh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { tanh(it) }
|
||||
override fun asinh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { asinh(it) }
|
||||
override fun acosh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { acosh(it) }
|
||||
override fun atanh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { atanh(it) }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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) }
|
||||
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
|
||||
*/
|
||||
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) }
|
||||
return ComplexNDField(shape).action()
|
||||
return ComplexFieldND(shape).action()
|
||||
}
|
@ -172,7 +172,7 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Quaternion>,
|
||||
else -> super<Field>.bindSymbol(value)
|
||||
}
|
||||
|
||||
override fun number(value: Number): Quaternion =value.toQuaternion()
|
||||
override fun number(value: Number): Quaternion = value.toQuaternion()
|
||||
|
||||
public override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0
|
||||
public override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0
|
||||
|
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 = """
|
||||
Algebraic structures like rings, spaces and fields.
|
||||
""".trimIndent(),
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "nd",
|
||||
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(
|
||||
@ -37,13 +37,13 @@ readme {
|
||||
description = """
|
||||
Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
""".trimIndent(),
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "buffers",
|
||||
description = "One-dimensional structure",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt"
|
||||
)
|
||||
|
||||
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
|
||||
performance calculations to code generation.
|
||||
""".trimIndent(),
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/expressions"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/expressions"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "domains",
|
||||
description = "Domains",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/domains"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/domains"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "autodif",
|
||||
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
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public interface RealDomain : Domain<Double> {
|
||||
public interface DoubleDomain : Domain<Double> {
|
||||
|
||||
/**
|
||||
* Global lower edge
|
@ -27,7 +27,7 @@ import space.kscience.kmath.structures.indices
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@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 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
|
||||
|
||||
@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 fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY
|
||||
|
@ -4,7 +4,7 @@ import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.misc.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 operator fun contains(d: Double): Boolean = range.contains(d)
|
||||
|
@ -28,7 +28,7 @@ public fun <T, R : Expression<T>> DifferentiableExpression<T, R>.derivative(name
|
||||
/**
|
||||
* A [DifferentiableExpression] that defines only first derivatives
|
||||
*/
|
||||
public abstract class FirstDerivativeExpression<T, R : Expression<T>> : DifferentiableExpression<T,R> {
|
||||
public abstract class FirstDerivativeExpression<T, R : Expression<T>> : DifferentiableExpression<T, R> {
|
||||
/**
|
||||
* Returns first derivative of this expression by given [symbol].
|
||||
*/
|
||||
|
@ -95,7 +95,7 @@ public fun <T, E> ExpressionAlgebra<T, E>.bindSymbol(symbol: Symbol): E =
|
||||
/**
|
||||
* A delegate to create a symbol with a string identity in this scope
|
||||
*/
|
||||
public val symbol: ReadOnlyProperty<Any?, Symbol> = ReadOnlyProperty { _, property ->
|
||||
public val symbol: ReadOnlyProperty<Any?, Symbol> = ReadOnlyProperty { _, property ->
|
||||
StringSymbol(property.name)
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ public open class FunctionalExpressionRing<T, A : Ring<T>>(
|
||||
super<FunctionalExpressionGroup>.binaryOperationFunction(operation)
|
||||
}
|
||||
|
||||
public open class FunctionalExpressionField<T, A: Field<T>>(
|
||||
public open class FunctionalExpressionField<T, A : Field<T>>(
|
||||
algebra: A,
|
||||
) : FunctionalExpressionRing<T, A>(algebra), Field<Expression<T>>,
|
||||
ScaleOperations<Expression<T>> {
|
||||
|
@ -198,7 +198,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
|
||||
* Example:
|
||||
* ```
|
||||
* 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(9.0, x.d) // dy/dx
|
||||
* ```
|
||||
|
@ -9,7 +9,7 @@ import space.kscience.kmath.structures.VirtualBuffer
|
||||
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,
|
||||
private val bufferFactory: BufferFactory<T>,
|
||||
) : LinearSpace<T, A> {
|
||||
@ -17,7 +17,7 @@ public class BufferLinearSpace<T : Any, A : Ring<T>>(
|
||||
private fun ndRing(
|
||||
rows: 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> =
|
||||
ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D()
|
||||
@ -48,7 +48,7 @@ public class BufferLinearSpace<T : Any, A : Ring<T>>(
|
||||
override fun Matrix<T>.dot(other: Matrix<T>): Matrix<T> {
|
||||
require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
|
||||
return elementAlgebra {
|
||||
val rows = this@dot.rows.map{it.linearize()}
|
||||
val rows = this@dot.rows.map { it.linearize() }
|
||||
val columns = other.columns.map { it.linearize() }
|
||||
buildMatrix(rowNum, other.colNum) { i, j ->
|
||||
val r = rows[i]
|
@ -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
|
||||
*/
|
||||
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>
|
||||
|
||||
/**
|
||||
* 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 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.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferFactory
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
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
|
||||
|
||||
/**
|
||||
* Gets a feature from the matrix. This function may return some additional features to
|
||||
* [space.kscience.kmath.nd.NDStructure.getFeature].
|
||||
* Get a feature of the structure in this scope. Structure features take precedence other context features
|
||||
*
|
||||
* @param F the type of feature.
|
||||
* @param m the matrix.
|
||||
* @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(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 {
|
||||
|
||||
@ -174,9 +174,9 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
|
||||
public fun <T : Any, A : Ring<T>> buffered(
|
||||
algebra: A,
|
||||
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
|
||||
@ -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
|
||||
* [space.kscience.kmath.nd.NDStructure.getFeature].
|
||||
* 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 M the type of operated matrices.
|
||||
* @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.
|
||||
*/
|
||||
@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.nd.getFeature
|
||||
import space.kscience.kmath.operations.*
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferAccessor2D
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
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,
|
||||
): LupDecomposition<T> = lup(MutableBuffer.Companion::auto, matrix, checkSingular)
|
||||
|
||||
public fun LinearSpace<Double, RealField>.lup(matrix: Matrix<Double>): LupDecomposition<Double> =
|
||||
lup(Buffer.Companion::real, matrix) { it < 1e-11 }
|
||||
public fun LinearSpace<Double, DoubleField>.lup(matrix: Matrix<Double>): LupDecomposition<Double> =
|
||||
lup(::DoubleBuffer, matrix) { it < 1e-11 }
|
||||
|
||||
public fun <T : Any> LupDecomposition<T>.solveWithLup(
|
||||
factory: MutableBufferFactory<T>,
|
||||
@ -228,9 +228,9 @@ public inline fun <reified T : Comparable<T>> LinearSpace<T, Field<T>>.inverseWi
|
||||
|
||||
|
||||
@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
|
||||
val bufferFactory: MutableBufferFactory<Double> = MutableBuffer.Companion::real
|
||||
val bufferFactory: MutableBufferFactory<Double> = ::DoubleBuffer
|
||||
val decomposition: LupDecomposition<Double> = a.getFeature() ?: lup(bufferFactory, a) { it < 1e-11 }
|
||||
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.
|
||||
*/
|
||||
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))
|
@ -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
|
||||
?: origin.getFeature(type)
|
||||
|
||||
override fun equals(other: Any?): Boolean = origin == other
|
||||
override fun hashCode(): Int = origin.hashCode()
|
||||
override fun toString(): String {
|
||||
return "MatrixWrapper(matrix=$origin, features=$features)"
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package space.kscience.kmath.linear
|
||||
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
|
||||
/**
|
||||
* 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>(
|
||||
override val rowNum: Int,
|
||||
override val colNum: Int,
|
||||
public val generator: (i: Int, j: Int) -> T
|
||||
public val generator: (i: Int, j: Int) -> T,
|
||||
) : Matrix<T> {
|
||||
|
||||
override val shape: IntArray get() = intArrayOf(rowNum, colNum)
|
||||
|
||||
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
|
||||
*/
|
||||
public fun <T> Iterable<T>.cumulativeSum(space: Group<T>): Iterable<T> =
|
||||
space { cumulative(zero) { element: T, sum: T -> sum + element } }
|
||||
public fun <T> Iterable<T>.cumulativeSum(group: Group<T>): Iterable<T> =
|
||||
group { cumulative(zero) { element: T, sum: T -> sum + element } }
|
||||
|
||||
@JvmName("cumulativeSumOfDouble")
|
||||
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")
|
||||
public fun Iterable<Long>.cumulativeSum(): Iterable<Long> = cumulative(0L) { element, sum -> sum + element }
|
||||
|
||||
public fun <T> Sequence<T>.cumulativeSum(space: Group<T>): Sequence<T> =
|
||||
space { cumulative(zero) { element: T, sum: T -> sum + element } }
|
||||
public fun <T> Sequence<T>.cumulativeSum(group: Group<T>): Sequence<T> =
|
||||
group { cumulative(zero) { element: T, sum: T -> sum + element } }
|
||||
|
||||
@JvmName("cumulativeSumOfDouble")
|
||||
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")
|
||||
public fun Sequence<Long>.cumulativeSum(): Sequence<Long> = cumulative(0L) { element, sum -> sum + element }
|
||||
|
||||
public fun <T> List<T>.cumulativeSum(space: Group<T>): List<T> =
|
||||
space { cumulative(zero) { element: T, sum: T -> sum + element } }
|
||||
public fun <T> List<T>.cumulativeSum(group: Group<T>): List<T> =
|
||||
group { cumulative(zero) { element: T, sum: T -> sum + element } }
|
||||
|
||||
@JvmName("cumulativeSumOfDouble")
|
||||
public fun List<Double>.cumulativeSum(): List<Double> = cumulative(0.0) { element, sum -> sum + element }
|
||||
|
@ -1,7 +1,9 @@
|
||||
package space.kscience.kmath.nd
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.*
|
||||
import space.kscience.kmath.structures.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* 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 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.
|
||||
*/
|
||||
@ -33,43 +35,67 @@ public interface NDAlgebra<T, C: Algebra<T>> {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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) }
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param structures the structures to check.
|
||||
* @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
|
||||
.map(NDStructure<T>::shape)
|
||||
.singleOrNull { !shape.contentEquals(it) }
|
||||
?.let<IntArray, Array<out NDStructure<T>>> { throw ShapeMismatchException(shape, it) }
|
||||
?: structures
|
||||
internal fun <T, C : Algebra<T>> AlgebraND<T, C>.checkShape(vararg structures: StructureND<T>): Array<out StructureND<T>> =
|
||||
structures
|
||||
.map(StructureND<T>::shape)
|
||||
.singleOrNull { !shape.contentEquals(it) }
|
||||
?.let<IntArray, Array<out StructureND<T>>> { throw ShapeMismatchException(shape, it) }
|
||||
?: structures
|
||||
|
||||
/**
|
||||
* Checks if given element is consistent with this context.
|
||||
@ -77,19 +103,19 @@ internal fun <T, C: Algebra<T>> NDAlgebra<T, C>.checkShape(vararg structures: ND
|
||||
* @param element the structure to check.
|
||||
* @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)
|
||||
return element
|
||||
}
|
||||
|
||||
/**
|
||||
* Space of [NDStructure].
|
||||
* Space of [StructureND].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param S the type of space of structure elements.
|
||||
*/
|
||||
public interface 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.
|
||||
*
|
||||
@ -97,7 +123,7 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
||||
* @param b the augend.
|
||||
* @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) }
|
||||
|
||||
// /**
|
||||
@ -118,7 +144,7 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
||||
* @param arg the augend.
|
||||
* @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.
|
||||
@ -127,7 +153,7 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
||||
* @param arg the divisor.
|
||||
* @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.
|
||||
@ -136,7 +162,7 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
||||
* @param arg the augend.
|
||||
* @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.
|
||||
@ -145,19 +171,19 @@ public interface NDGroup<T, S : Group<T>> : Group<NDStructure<T>>, NDAlgebra<T,
|
||||
* @param arg the divisor.
|
||||
* @return the quotient.
|
||||
*/
|
||||
public operator fun T.minus(arg: NDStructure<T>): NDStructure<T> = arg.map { value -> add(-this@minus, value) }
|
||||
public operator fun T.minus(arg: StructureND<T>): StructureND<T> = arg.map { value -> add(-this@minus, value) }
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* Ring of [NDStructure].
|
||||
* Ring of [StructureND].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param R the type of ring of structure elements.
|
||||
*/
|
||||
public interface NDRing<T, R : Ring<T>> : Ring<NDStructure<T>>, NDGroup<T, R> {
|
||||
public interface RingND<T, R : Ring<T>> : Ring<StructureND<T>>, GroupND<T, R> {
|
||||
/**
|
||||
* Element-wise multiplication.
|
||||
*
|
||||
@ -165,7 +191,7 @@ public interface NDRing<T, R : Ring<T>> : Ring<NDStructure<T>>, NDGroup<T, R> {
|
||||
* @param b the multiplier.
|
||||
* @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) }
|
||||
|
||||
//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.
|
||||
* @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.
|
||||
@ -186,19 +212,19 @@ public interface NDRing<T, R : Ring<T>> : Ring<NDStructure<T>>, NDGroup<T, R> {
|
||||
* @param arg the multiplier.
|
||||
* @return the product.
|
||||
*/
|
||||
public operator fun T.times(arg: NDStructure<T>): NDStructure<T> = arg.map { value -> multiply(this@times, value) }
|
||||
public operator fun T.times(arg: StructureND<T>): StructureND<T> = arg.map { value -> multiply(this@times, value) }
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* Field of [NDStructure].
|
||||
* Field of [StructureND].
|
||||
*
|
||||
* @param T the type of the element contained in ND structure.
|
||||
* @param N the type of ND structure.
|
||||
* @param F the type field of structure elements.
|
||||
*/
|
||||
public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F>, ScaleOperations<NDStructure<T>> {
|
||||
public interface FieldND<T, F : Field<T>> : Field<StructureND<T>>, RingND<T, F>, ScaleOperations<StructureND<T>> {
|
||||
/**
|
||||
* Element-wise division.
|
||||
*
|
||||
@ -206,7 +232,7 @@ public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F>,
|
||||
* @param b the divisor.
|
||||
* @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) }
|
||||
|
||||
//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.
|
||||
* @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.
|
||||
@ -226,7 +252,7 @@ public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F>,
|
||||
* @param arg the divisor.
|
||||
* @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
|
||||
// public companion object {
|
@ -6,132 +6,132 @@ import space.kscience.kmath.structures.BufferFactory
|
||||
import kotlin.contracts.InvocationKind
|
||||
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 bufferFactory: BufferFactory<T>
|
||||
|
||||
override fun produce(initializer: A.(IntArray) -> T): NDBuffer<T> = NDBuffer(
|
||||
override fun produce(initializer: A.(IntArray) -> T): BufferND<T> = BufferND(
|
||||
strides,
|
||||
bufferFactory(strides.linearSize) { offset ->
|
||||
elementContext.initializer(strides.index(offset))
|
||||
}
|
||||
)
|
||||
|
||||
public val NDStructure<T>.buffer: Buffer<T>
|
||||
public val StructureND<T>.buffer: Buffer<T>
|
||||
get() = when {
|
||||
!shape.contentEquals(this@BufferNDAlgebra.shape) -> throw ShapeMismatchException(
|
||||
this@BufferNDAlgebra.shape,
|
||||
!shape.contentEquals(this@BufferAlgebraND.shape) -> throw ShapeMismatchException(
|
||||
this@BufferAlgebraND.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)) }
|
||||
}
|
||||
|
||||
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 ->
|
||||
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 ->
|
||||
elementContext.transform(
|
||||
strides.index(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 ->
|
||||
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 elementContext: A,
|
||||
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 zero: NDBuffer<T> by lazy { produce { zero } }
|
||||
override fun NDStructure<T>.unaryMinus(): NDStructure<T> = produce { -get(it) }
|
||||
override val zero: BufferND<T> by lazy { produce { zero } }
|
||||
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,
|
||||
elementContext: R,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
) : BufferedNDGroup<T, R>(shape, elementContext, bufferFactory), NDRing<T, R> {
|
||||
override val one: NDBuffer<T> by lazy { produce { one } }
|
||||
) : BufferedGroupND<T, R>(shape, elementContext, bufferFactory), RingND<T, R> {
|
||||
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,
|
||||
elementContext: R,
|
||||
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
|
||||
public fun <T, A : Group<T>> NDAlgebra.Companion.group(
|
||||
public fun <T, A : Group<T>> AlgebraND.Companion.group(
|
||||
space: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
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(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
action: BufferedNDGroup<T, A>.() -> R,
|
||||
action: BufferedGroupND<T, A>.() -> R,
|
||||
): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return NDAlgebra.group(this, bufferFactory, *shape).run(action)
|
||||
return AlgebraND.group(this, bufferFactory, *shape).run(action)
|
||||
}
|
||||
|
||||
//ring factories
|
||||
public fun <T, A : Ring<T>> NDAlgebra.Companion.ring(
|
||||
public fun <T, A : Ring<T>> AlgebraND.Companion.ring(
|
||||
ring: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
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(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
action: BufferedNDRing<T, A>.() -> R,
|
||||
action: BufferedRingND<T, A>.() -> R,
|
||||
): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return NDAlgebra.ring(this, bufferFactory, *shape).run(action)
|
||||
return AlgebraND.ring(this, bufferFactory, *shape).run(action)
|
||||
}
|
||||
|
||||
//field factories
|
||||
public fun <T, A : Field<T>> NDAlgebra.Companion.field(
|
||||
public fun <T, A : Field<T>> AlgebraND.Companion.field(
|
||||
field: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
): BufferedNDField<T, A> = BufferedNDField(shape, field, bufferFactory)
|
||||
): BufferedFieldND<T, A> = BufferedFieldND(shape, field, bufferFactory)
|
||||
|
||||
@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,
|
||||
vararg shape: Int,
|
||||
): NDField<T, A> = when (field) {
|
||||
RealField -> RealNDField(shape) as NDField<T, A>
|
||||
else -> BufferedNDField(shape, field, Buffer.Companion::auto)
|
||||
): FieldND<T, A> = when (field) {
|
||||
DoubleField -> DoubleFieldND(shape) as FieldND<T, A>
|
||||
else -> BufferedFieldND(shape, field, Buffer.Companion::auto)
|
||||
}
|
||||
|
||||
public inline fun <T, A : Field<T>, R> A.ndField(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
action: BufferedNDField<T, A>.() -> R,
|
||||
action: BufferedFieldND<T, A>.() -> R,
|
||||
): R {
|
||||
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
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class ShortNDRing(
|
||||
public class ShortRingND(
|
||||
shape: IntArray,
|
||||
) : BufferedNDRing<Short, ShortRing>(shape, ShortRing, Buffer.Companion::auto),
|
||||
NumbersAddOperations<NDStructure<Short>> {
|
||||
) : BufferedRingND<Short, ShortRing>(shape, ShortRing, Buffer.Companion::auto),
|
||||
NumbersAddOperations<StructureND<Short>> {
|
||||
|
||||
override val zero: NDBuffer<Short> by lazy { produce { zero } }
|
||||
override val one: NDBuffer<Short> by lazy { produce { one } }
|
||||
override val zero: BufferND<Short> by lazy { produce { zero } }
|
||||
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
|
||||
return produce { d }
|
||||
}
|
||||
@ -26,11 +26,11 @@ public class ShortNDRing(
|
||||
/**
|
||||
* Fast element production using function inlining.
|
||||
*/
|
||||
public inline fun BufferedNDRing<Short, ShortRing>.produceInline(crossinline initializer: ShortRing.(Int) -> Short): NDBuffer<Short> {
|
||||
return NDBuffer(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) }))
|
||||
public inline fun BufferedRingND<Short, ShortRing>.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND<Short> {
|
||||
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) }
|
||||
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
|
||||
*/
|
||||
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 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
|
||||
*/
|
||||
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) {
|
||||
require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" }
|
||||
set(index[0], value)
|
||||
@ -32,7 +32,7 @@ public interface MutableStructure1D<T> : Structure1D<T>, MutableNDStructure<T>,
|
||||
/**
|
||||
* 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 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
|
||||
*/
|
||||
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 size: Int get() = structure.shape[0]
|
||||
override fun elements(): Sequence<Pair<IntArray, T>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
override fun elements(): Sequence<Pair<IntArray, T>> = structure.elements()
|
||||
|
||||
override fun get(index: Int): T = structure[index]
|
||||
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]
|
||||
}
|
||||
|
||||
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) {
|
||||
is NDBuffer -> Buffer1DWrapper(this.buffer)
|
||||
is BufferND -> Buffer1DWrapper(this.buffer)
|
||||
else -> Structure1DWrapper(this)
|
||||
}
|
||||
} 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) {
|
||||
when (this) {
|
||||
is MutableNDBuffer -> MutableBuffer1DWrapper(this.buffer)
|
||||
else -> MutableStructure1DWrapper(this)
|
||||
}
|
||||
MutableStructure1DWrapper(this)
|
||||
} 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> 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.
|
||||
*/
|
||||
public interface Structure2D<T> : NDStructure<T> {
|
||||
public interface Structure2D<T> : StructureND<T> {
|
||||
/**
|
||||
* The number of rows in this structure.
|
||||
*/
|
||||
@ -60,7 +60,7 @@ public interface Structure2D<T> : NDStructure<T> {
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -74,7 +74,7 @@ public interface MutableStructure2D<T> : Structure2D<T>, MutableNDStructure<T> {
|
||||
/**
|
||||
* 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 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 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
|
||||
*/
|
||||
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
|
||||
|
||||
@ -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)
|
||||
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> MutableNDStructure<T>.as2D(): MutableStructure2D<T> = this as? MutableStructure2D<T> ?: when (shape.size) {
|
||||
public fun <T> MutableStructureND<T>.as2D(): MutableStructure2D<T> = this as? MutableStructure2D<T> ?: when (shape.size) {
|
||||
2 -> MutableStructure2DWrapper(this)
|
||||
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
|
||||
|
||||
|
@ -3,8 +3,6 @@ package space.kscience.kmath.nd
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferFactory
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
import space.kscience.kmath.structures.asSequence
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.native.concurrent.ThreadLocal
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
* this structure.
|
||||
@ -43,32 +43,47 @@ public interface NDStructure<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
|
||||
* optimize operations and performance. If the feature is not present, null is defined.
|
||||
* Feature is some additional strucure information which allows to access it special properties or hints.
|
||||
* If the feature is not present, null is returned.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <F : Any> getFeature(type: KClass<F>): F? = null
|
||||
|
||||
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
|
||||
|
||||
// fast comparison of buffers if possible
|
||||
if (st1 is NDBuffer && st2 is NDBuffer && st1.strides == st2.strides)
|
||||
return st1.buffer.contentEquals(st2.buffer)
|
||||
if (st1 is BufferND && st2 is BufferND && st1.strides == st2.strides)
|
||||
return Buffer.contentEquals(st1.buffer, st2.buffer)
|
||||
|
||||
//element by element comparison if it could not be avoided
|
||||
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.
|
||||
*
|
||||
@ -78,7 +93,7 @@ public interface NDStructure<T> {
|
||||
strides: Strides,
|
||||
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
||||
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
|
||||
@ -86,37 +101,37 @@ public interface NDStructure<T> {
|
||||
public inline fun <reified T : Any> auto(
|
||||
strides: Strides,
|
||||
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(
|
||||
type: KClass<T>,
|
||||
strides: Strides,
|
||||
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(
|
||||
shape: IntArray,
|
||||
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
||||
initializer: (IntArray) -> T,
|
||||
): NDBuffer<T> = buffered(DefaultStrides(shape), bufferFactory, initializer)
|
||||
): BufferND<T> = buffered(DefaultStrides(shape), bufferFactory, initializer)
|
||||
|
||||
public inline fun <reified T : Any> auto(
|
||||
shape: IntArray,
|
||||
crossinline initializer: (IntArray) -> T,
|
||||
): NDBuffer<T> = auto(DefaultStrides(shape), initializer)
|
||||
): BufferND<T> = auto(DefaultStrides(shape), initializer)
|
||||
|
||||
@JvmName("autoVarArg")
|
||||
public inline fun <reified T : Any> auto(
|
||||
vararg shape: Int,
|
||||
crossinline initializer: (IntArray) -> T,
|
||||
): NDBuffer<T> =
|
||||
): BufferND<T> =
|
||||
auto(DefaultStrides(shape), initializer)
|
||||
|
||||
public inline fun <T : Any> auto(
|
||||
type: KClass<T>,
|
||||
vararg shape: Int,
|
||||
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.
|
||||
* @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
|
||||
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.
|
||||
*
|
||||
@ -147,7 +162,7 @@ public interface MutableNDStructure<T> : NDStructure<T> {
|
||||
/**
|
||||
* 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) }
|
||||
|
||||
/**
|
||||
@ -194,10 +209,11 @@ public interface Strides {
|
||||
}
|
||||
}
|
||||
|
||||
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]})")
|
||||
value * strides[i]
|
||||
}.sum()
|
||||
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]})")
|
||||
value * strides[i]
|
||||
}.sum()
|
||||
|
||||
/**
|
||||
* Simple implementation of [Strides].
|
||||
@ -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 {
|
||||
if (strides.linearSize != buffer.size) {
|
||||
error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}")
|
||||
}
|
||||
}
|
||||
|
||||
public open val buffer: Buffer<T> = buffer
|
||||
|
||||
override operator fun get(index: IntArray): T = buffer[strides.offset(index)]
|
||||
|
||||
override val shape: IntArray get() = strides.shape
|
||||
|
||||
override fun elements(): Sequence<Pair<IntArray, T>> = strides.indices().map {
|
||||
it to this[it]
|
||||
}
|
||||
|
||||
override fun 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>,
|
||||
public inline fun <reified T : Any> StructureND<T>.combine(
|
||||
struct: StructureND<T>,
|
||||
crossinline block: (T, T) -> T,
|
||||
): NDStructure<T> {
|
||||
): StructureND<T> {
|
||||
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]) }
|
||||
}
|
@ -41,7 +41,7 @@ public interface AlgebraElement<T, C : Algebra<T>> {
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public operator fun <T : AlgebraElement<T, S>, S : NumbersAddOperations<T>> T.minus(b: T): T =
|
||||
context.add(this, context.run { -b})
|
||||
context.add(this, context.run { -b })
|
||||
|
||||
/**
|
||||
* Adds element to this one.
|
||||
|
@ -1,8 +1,8 @@
|
||||
package space.kscience.kmath.operations
|
||||
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.BufferedNDRing
|
||||
import space.kscience.kmath.nd.NDAlgebra
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.BufferedRingND
|
||||
import space.kscience.kmath.operations.BigInt.Companion.BASE
|
||||
import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE
|
||||
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> =
|
||||
boxing(size, initializer)
|
||||
|
||||
public fun NDAlgebra.Companion.bigInt(vararg shape: Int): BufferedNDRing<BigInt, BigIntField> =
|
||||
BufferedNDRing(shape, BigIntField, Buffer.Companion::bigInt)
|
||||
public fun AlgebraND.Companion.bigInt(vararg shape: Int): BufferedRingND<BigInt, BigIntField> =
|
||||
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.
|
||||
*
|
||||
* @receiver the collection to sum up.
|
||||
* @param space the algebra that provides addition.
|
||||
* @param group the algebra that provides addition.
|
||||
* @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.
|
||||
*
|
||||
* @receiver the collection to sum up.
|
||||
* @param space the algebra that provides addition.
|
||||
* @param group the algebra that provides addition.
|
||||
* @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].
|
||||
@ -71,7 +71,7 @@ public fun <T> Sequence<T>.sumWith(space: Group<T>): T = space.sum(this)
|
||||
* @return the average value.
|
||||
* @author Iaroslav Postovalov
|
||||
*/
|
||||
public fun <T, S> Iterable<T>.averageWith(space: S): T where S : Group<T>, S : ScaleOperations<T> =
|
||||
public fun <T, S> Iterable<T>.averageWith(space: S): T where S : Group<T>, S : ScaleOperations<T> =
|
||||
space.average(this)
|
||||
|
||||
/**
|
||||
@ -82,7 +82,7 @@ public fun <T, S> Iterable<T>.averageWith(space: S): T where S : Group<T>, S :
|
||||
* @return the average value.
|
||||
* @author Iaroslav Postovalov
|
||||
*/
|
||||
public fun <T, S> Sequence<T>.averageWith(space: S): T where S : Group<T>, S : ScaleOperations<T> =
|
||||
public fun <T, S> Sequence<T>.averageWith(space: S): T where S : Group<T>, S : ScaleOperations<T> =
|
||||
space.average(this)
|
||||
|
||||
//TODO optimized power operation
|
||||
|
@ -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.
|
||||
*/
|
||||
@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 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>
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@ -37,49 +39,46 @@ public interface Buffer<out 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 {
|
||||
|
||||
/**
|
||||
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
|
||||
* [initializer] function.
|
||||
* Check the element-by-element match of content of two buffers.
|
||||
*/
|
||||
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
|
||||
RealBuffer(size) { initializer(it) }
|
||||
public fun <T: Any> contentEquals(first: Buffer<T>, second: Buffer<T>): Boolean{
|
||||
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
|
||||
* specified [initializer] function.
|
||||
*/
|
||||
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> =
|
||||
ListBuffer(List(size, initializer))
|
||||
|
||||
// TODO add resolution based on Annotation or companion resolution
|
||||
List(size, initializer).asBuffer()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public inline fun <T : Any> auto(type: KClass<T>, size: Int, initializer: (Int) -> T): Buffer<T> =
|
||||
when (type) {
|
||||
Double::class -> RealBuffer(size) { initializer(it) as Double } as Buffer<T>
|
||||
Short::class -> ShortBuffer(size) { initializer(it) as Short } as Buffer<T>
|
||||
Int::class -> IntBuffer(size) { initializer(it) as Int } as Buffer<T>
|
||||
Long::class -> LongBuffer(size) { initializer(it) as Long } as Buffer<T>
|
||||
Float::class -> FloatBuffer(size) { initializer(it) as Float } as Buffer<T>
|
||||
Double::class -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer<T>
|
||||
Short::class -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
|
||||
Int::class -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
|
||||
Long::class -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
|
||||
Float::class -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
|
||||
else -> boxing(size, initializer)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@ -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].
|
||||
*/
|
||||
@ -146,6 +110,44 @@ public interface MutableBuffer<T> : Buffer<T> {
|
||||
public fun copy(): MutableBuffer<T>
|
||||
|
||||
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
|
||||
*/
|
||||
@ -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
|
||||
* ([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.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
||||
when (type) {
|
||||
Double::class -> RealBuffer(size) { initializer(it) as Double } as MutableBuffer<T>
|
||||
Short::class -> ShortBuffer(size) { initializer(it) as Short } as MutableBuffer<T>
|
||||
Int::class -> IntBuffer(size) { initializer(it) as Int } as MutableBuffer<T>
|
||||
Float::class -> FloatBuffer(size) { initializer(it) as Float } as MutableBuffer<T>
|
||||
Long::class -> LongBuffer(size) { initializer(it) as Long } as MutableBuffer<T>
|
||||
Double::class -> double(size) { initializer(it) as Double } as MutableBuffer<T>
|
||||
Short::class -> short(size) { initializer(it) as Short } as MutableBuffer<T>
|
||||
Int::class -> int(size) { initializer(it) as Int } as MutableBuffer<T>
|
||||
Float::class -> float(size) { initializer(it) as Float } as MutableBuffer<T>
|
||||
Long::class -> long(size) { initializer(it) as Long } as MutableBuffer<T>
|
||||
else -> boxing(size, initializer)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
||||
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)
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*
|
||||
@ -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 [ListBuffer] that wraps the original list.
|
||||
>>>>>>> dev
|
||||
*/
|
||||
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> {
|
||||
// Can't inline because array is invariant
|
||||
override val size: Int
|
||||
get() = array.size
|
||||
override val size: Int get() = array.size
|
||||
|
||||
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)
|
||||
|
||||
/**
|
||||
* 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].
|
||||
*
|
||||
@ -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 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.
|
||||
*/
|
||||
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>
|
||||
public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this
|
@ -1,8 +1,8 @@
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
import space.kscience.kmath.nd.DefaultStrides
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.nd.Structure2D
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.as2D
|
||||
|
||||
/**
|
||||
@ -13,10 +13,10 @@ internal class BufferAccessor2D<T : Any>(
|
||||
public val colNum: Int,
|
||||
val factory: MutableBufferFactory<T>,
|
||||
) {
|
||||
public operator fun Buffer<T>.get(i: Int, j: Int): T = get(i*colNum + j)
|
||||
public operator fun Buffer<T>.get(i: Int, j: Int): T = get(i * colNum + j)
|
||||
|
||||
public operator fun MutableBuffer<T>.set(i: Int, j: Int, value: T) {
|
||||
set(i*colNum + j, value)
|
||||
set(i * colNum + j, value)
|
||||
}
|
||||
|
||||
public inline fun create(crossinline init: (i: Int, j: Int) -> T): MutableBuffer<T> =
|
||||
@ -25,7 +25,7 @@ internal class BufferAccessor2D<T : Any>(
|
||||
public fun create(mat: Structure2D<T>): MutableBuffer<T> = create { i, j -> mat[i, j] }
|
||||
|
||||
//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)),
|
||||
factory
|
||||
) { (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
|
||||
*/
|
||||
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?> {
|
||||
init {
|
||||
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()
|
||||
}
|
||||
|
||||
public inline fun FlaggedRealBuffer.forEachValid(block: (Double) -> Unit) {
|
||||
public inline fun FlaggedDoubleBuffer.forEachValid(block: (Double) -> Unit) {
|
||||
indices
|
||||
.asSequence()
|
||||
.filter(::isValid)
|
||||
|
@ -38,7 +38,7 @@ public fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats)
|
||||
/**
|
||||
* Returns a new [FloatArray] containing all of the elements of this [Buffer].
|
||||
*/
|
||||
public fun Buffer<Float>.toFloatArray(): FloatArray = when(this) {
|
||||
public fun Buffer<Float>.toFloatArray(): FloatArray = when (this) {
|
||||
is FloatBuffer -> array.copyOf()
|
||||
else -> FloatArray(size, ::get)
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints)
|
||||
/**
|
||||
* Returns a new [IntArray] containing all of the elements of this [Buffer].
|
||||
*/
|
||||
public fun Buffer<Int>.toIntArray(): IntArray = when(this) {
|
||||
public fun Buffer<Int>.toIntArray(): IntArray = when (this) {
|
||||
is IntBuffer -> array.copyOf()
|
||||
else -> IntArray(size, ::get)
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs)
|
||||
/**
|
||||
* Returns a new [LongArray] containing all of the elements of this [Buffer].
|
||||
*/
|
||||
public fun Buffer<Long>.toLongArray(): LongArray = when(this) {
|
||||
public fun Buffer<Long>.toLongArray(): LongArray = when (this) {
|
||||
is LongBuffer -> array.copyOf()
|
||||
else -> LongArray(size, ::get)
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ public open class MemoryBuffer<T : Any>(protected val memory: Memory, protected
|
||||
public inline fun <T : Any> create(
|
||||
spec: MemorySpec<T>,
|
||||
size: Int,
|
||||
initializer: (Int) -> T
|
||||
initializer: (Int) -> T,
|
||||
): MemoryBuffer<T> = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
||||
(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(
|
||||
spec: MemorySpec<T>,
|
||||
size: Int,
|
||||
initializer: (Int) -> T
|
||||
initializer: (Int) -> T,
|
||||
): MutableMemoryBuffer<T> = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
||||
(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)
|
||||
}
|
||||
}
|