Dev #280
1
.github/workflows/build.yml
vendored
@ -8,6 +8,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os: [ macOS-latest, windows-latest ]
|
os: [ macOS-latest, windows-latest ]
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
timeout-minutes: 30
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repo
|
- name: Checkout the repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
4
.gitignore
vendored
@ -1,7 +1,11 @@
|
|||||||
.gradle
|
.gradle
|
||||||
build/
|
build/
|
||||||
out/
|
out/
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
!.idea/copyright/
|
||||||
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
|
6
.idea/copyright/kmath.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="CopyrightManager">
|
||||||
|
<copyright>
|
||||||
|
<option name="notice" value="Copyright 2018-2021 KMath contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file." />
|
||||||
|
<option name="myName" value="kmath" />
|
||||||
|
</copyright>
|
||||||
|
</component>
|
7
.idea/copyright/profiles_settings.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<component name="CopyrightManager">
|
||||||
|
<settings default="kmath">
|
||||||
|
<module2copyright>
|
||||||
|
<element module="Project Files" copyright="kmath" />
|
||||||
|
</module2copyright>
|
||||||
|
</settings>
|
||||||
|
</component>
|
16
CHANGELOG.md
@ -4,20 +4,35 @@
|
|||||||
### Added
|
### Added
|
||||||
- ScaleOperations interface
|
- ScaleOperations interface
|
||||||
- Field extends ScaleOperations
|
- Field extends ScaleOperations
|
||||||
|
- Basic integration API
|
||||||
|
- Basic MPP distributions and samplers
|
||||||
|
- bindSymbolOrNull
|
||||||
|
- Blocking chains and Statistics
|
||||||
|
- Multiplatform integration
|
||||||
|
- Integration for any Field element
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Exponential operations merged with hyperbolic functions
|
- Exponential operations merged with hyperbolic functions
|
||||||
- Space is replaced by Group. Space is reserved for vector spaces.
|
- Space is replaced by Group. Space is reserved for vector spaces.
|
||||||
- VectorSpace is now a vector space
|
- VectorSpace is now a vector space
|
||||||
- Buffer factories for primitives moved to MutableBuffer.Companion
|
- Buffer factories for primitives moved to MutableBuffer.Companion
|
||||||
|
- NDStructure and NDAlgebra to StructureND and AlgebraND respectively
|
||||||
|
- Real -> Double
|
||||||
|
- DataSets are moved from functions to core
|
||||||
|
- Redesign advanced Chain API
|
||||||
|
- Redesign MST. Remove MSTExpression.
|
||||||
|
- Move MST to core
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Nearest in Domain. To be implemented in geometry package.
|
- Nearest in Domain. To be implemented in geometry package.
|
||||||
- Number multiplication and division in main Algebra chain
|
- Number multiplication and division in main Algebra chain
|
||||||
|
- `contentEquals` from Buffer. It moved to the companion.
|
||||||
|
- MSTExpression
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- Ring inherits RingOperations, not GroupOperations
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
@ -73,6 +88,7 @@
|
|||||||
- `toGrid` method.
|
- `toGrid` method.
|
||||||
- Public visibility of `BufferAccessor2D`
|
- Public visibility of `BufferAccessor2D`
|
||||||
- `Real` class
|
- `Real` class
|
||||||
|
- StructureND identity and equals
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
||||||
|
74
README.md
@ -1,9 +1,8 @@
|
|||||||
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
|
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
|
||||||
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
|
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
|
||||||
|
|
||||||
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
||||||
|
[![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)
|
||||||
[![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)
|
[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
|
||||||
|
|
||||||
# KMath
|
# KMath
|
||||||
|
|
||||||
@ -89,12 +88,12 @@ KMath is a modular library. Different modules provide different features with di
|
|||||||
> **Maturity**: PROTOTYPE
|
> **Maturity**: PROTOTYPE
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||||
> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||||
> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||||
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||||
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||||
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -110,8 +109,8 @@ KMath is a modular library. Different modules provide different features with di
|
|||||||
> **Maturity**: PROTOTYPE
|
> **Maturity**: PROTOTYPE
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [complex](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||||
> - [quaternion](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -121,15 +120,15 @@ KMath is a modular library. Different modules provide different features with di
|
|||||||
> **Maturity**: DEVELOPMENT
|
> **Maturity**: DEVELOPMENT
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
> - [algebras](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||||
> - [nd](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
|
> - [nd](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
|
||||||
> - [linear](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
> - [linear](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||||
> - [buffers](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
> - [buffers](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||||
> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
> - [expressions](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||||
performance calculations to code generation.
|
performance calculations to code generation.
|
||||||
> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
> - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
|
||||||
> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -149,6 +148,12 @@ performance calculations to code generation.
|
|||||||
>
|
>
|
||||||
>
|
>
|
||||||
> **Maturity**: PROTOTYPE
|
> **Maturity**: PROTOTYPE
|
||||||
|
>
|
||||||
|
> **Features:**
|
||||||
|
> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : The Point implementation using SimpleMatrix.
|
||||||
|
> - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : The Matrix implementation using SimpleMatrix.
|
||||||
|
> - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : The LinearSpace implementation using SimpleMatrix.
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-for-real](kmath-for-real)
|
* ### [kmath-for-real](kmath-for-real)
|
||||||
@ -159,22 +164,23 @@ One can still use generic algebras though.
|
|||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [RealVector](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealVector.kt) : Numpy-like operations for Buffers/Points
|
> - [DoubleVector](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points
|
||||||
> - [RealMatrix](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt) : Numpy-like operations for 2d real structures
|
> - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures
|
||||||
> - [grids](kmath-for-real/src/commonMain/kotlin/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
> - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
* ### [kmath-functions](kmath-functions)
|
* ### [kmath-functions](kmath-functions)
|
||||||
> Functions and interpolation
|
> Functions, integration and interpolation
|
||||||
>
|
>
|
||||||
> **Maturity**: PROTOTYPE
|
> **Maturity**: EXPERIMENTAL
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt
|
> - [piecewise](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt) : Piecewise functions.
|
||||||
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt
|
> - [polynomials](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Polynomial functions.
|
||||||
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt
|
> - [linear interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt) : Linear XY interpolator.
|
||||||
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt
|
> - [spline interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator.
|
||||||
|
> - [integration](kmath-functions/#) : Univariate and multivariate quadratures
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -208,9 +214,9 @@ One can still use generic algebras though.
|
|||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
>
|
>
|
||||||
> **Features:**
|
> **Features:**
|
||||||
> - [nd4jarraystructure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray
|
> - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
|
||||||
> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long
|
> - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long
|
||||||
> - [nd4jarrayfields](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : Fields over Nd4jArrayStructure of Float and Double
|
> - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -245,6 +251,10 @@ cases. We expect the worst KMath benchmarks will perform better than native Pyth
|
|||||||
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
|
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
|
||||||
better than SciPy.
|
better than SciPy.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
|
||||||
|
|
||||||
### Repositories
|
### Repositories
|
||||||
|
|
||||||
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
|
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
|
||||||
@ -256,8 +266,8 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api("space.kscience:kmath-core:0.3.0-dev-2")
|
api("space.kscience:kmath-core:0.3.0-dev-6")
|
||||||
// api("space.kscience:kmath-core-jvm:0.3.0-dev-2") for jvm-specific version
|
// api("space.kscience:kmath-core-jvm:0.3.0-dev-6") for jvm-specific version
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ru.mipt.npm.gradle.KSciencePublishingPlugin
|
import org.jetbrains.dokka.gradle.DokkaTask
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.gradle.project")
|
id("ru.mipt.npm.gradle.project")
|
||||||
@ -15,21 +16,41 @@ allprojects {
|
|||||||
maven("https://clojars.org/repo")
|
maven("https://clojars.org/repo")
|
||||||
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
|
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
|
||||||
maven("https://dl.bintray.com/hotkeytlt/maven")
|
maven("https://dl.bintray.com/hotkeytlt/maven")
|
||||||
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
|
||||||
maven("https://dl.bintray.com/kotlin/kotlinx")
|
|
||||||
maven("https://dl.bintray.com/mipt-npm/dev")
|
|
||||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
|
||||||
maven("https://jitpack.io")
|
maven("https://jitpack.io")
|
||||||
maven("http://logicrunch.research.it.uu.se/maven/")
|
maven{
|
||||||
|
setUrl("http://logicrunch.research.it.uu.se/maven/")
|
||||||
|
isAllowInsecureProtocol = true
|
||||||
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "space.kscience"
|
group = "space.kscience"
|
||||||
version = "0.3.0-dev-2"
|
version = "0.3.0-dev-6"
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
if (name.startsWith("kmath")) apply<KSciencePublishingPlugin>()
|
if (name.startsWith("kmath")) apply<MavenPublishPlugin>()
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
tasks.withType<DokkaTask> {
|
||||||
|
dokkaSourceSets.all {
|
||||||
|
val readmeFile = File(this@subprojects.projectDir, "./README.md")
|
||||||
|
if (readmeFile.exists())
|
||||||
|
includes.setFrom(includes + readmeFile.absolutePath)
|
||||||
|
|
||||||
|
arrayOf(
|
||||||
|
"http://ejml.org/javadoc/",
|
||||||
|
"https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/",
|
||||||
|
"https://deeplearning4j.org/api/latest/"
|
||||||
|
).map { URL("${it}package-list") to URL(it) }.forEach { (a, b) ->
|
||||||
|
externalDocumentationLink {
|
||||||
|
packageListUrl.set(a)
|
||||||
|
url.set(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readme {
|
readme {
|
||||||
|
@ -31,7 +31,7 @@ multiplication;
|
|||||||
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
|
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
|
||||||
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
|
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
|
||||||
|
|
||||||
A typical implementation of `Field<T>` is the `RealField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
||||||
|
|
||||||
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
|
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
|
||||||
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot`
|
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot`
|
||||||
|
@ -13,16 +13,19 @@
|
|||||||
version="1.1"><metadata
|
version="1.1"><metadata
|
||||||
id="metadata8"><rdf:RDF><cc:Work
|
id="metadata8"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||||
|
<defs
|
||||||
id="defs6"><clipPath
|
id="defs6"><clipPath
|
||||||
id="clipPath24"
|
id="clipPath24"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path22"
|
id="path22"
|
||||||
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath><clipPath
|
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath36"
|
id="clipPath36"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path34"
|
id="path34"
|
||||||
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs><g
|
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs>
|
||||||
|
<g
|
||||||
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
|
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
|
||||||
id="g10"><g
|
id="g10"><g
|
||||||
transform="scale(0.1)"
|
transform="scale(0.1)"
|
||||||
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 248 KiB |
@ -13,12 +13,14 @@
|
|||||||
version="1.1"><metadata
|
version="1.1"><metadata
|
||||||
id="metadata8"><rdf:RDF><cc:Work
|
id="metadata8"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||||
|
<defs
|
||||||
id="defs6"><clipPath
|
id="defs6"><clipPath
|
||||||
id="clipPath32"
|
id="clipPath32"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path30"
|
id="path30"
|
||||||
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs><g
|
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs>
|
||||||
|
<g
|
||||||
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
|
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
|
||||||
id="g10"><g
|
id="g10"><g
|
||||||
transform="scale(0.1)"
|
transform="scale(0.1)"
|
||||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@ -13,24 +13,29 @@
|
|||||||
version="1.1"><metadata
|
version="1.1"><metadata
|
||||||
id="metadata8"><rdf:RDF><cc:Work
|
id="metadata8"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||||
|
<defs
|
||||||
id="defs6"><clipPath
|
id="defs6"><clipPath
|
||||||
id="clipPath24"
|
id="clipPath24"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path22"
|
id="path22"
|
||||||
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath><clipPath
|
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath36"
|
id="clipPath36"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path34"
|
id="path34"
|
||||||
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath><clipPath
|
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath48"
|
id="clipPath48"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path46"
|
id="path46"
|
||||||
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath><clipPath
|
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath60"
|
id="clipPath60"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path58"
|
id="path58"
|
||||||
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs><g
|
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs>
|
||||||
|
<g
|
||||||
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
|
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
|
||||||
id="g10"><g
|
id="g10"><g
|
||||||
transform="scale(0.1)"
|
transform="scale(0.1)"
|
||||||
|
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 278 KiB |
@ -13,88 +13,109 @@
|
|||||||
version="1.1"><metadata
|
version="1.1"><metadata
|
||||||
id="metadata8"><rdf:RDF><cc:Work
|
id="metadata8"><rdf:RDF><cc:Work
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||||
|
<defs
|
||||||
id="defs6"><clipPath
|
id="defs6"><clipPath
|
||||||
id="clipPath40"
|
id="clipPath40"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path38"
|
id="path38"
|
||||||
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath52"
|
id="clipPath52"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path50"
|
id="path50"
|
||||||
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath><clipPath
|
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath64"
|
id="clipPath64"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path62"
|
id="path62"
|
||||||
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath><clipPath
|
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath76"
|
id="clipPath76"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path74"
|
id="path74"
|
||||||
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath88"
|
id="clipPath88"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path86"
|
id="path86"
|
||||||
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath><clipPath
|
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath100"
|
id="clipPath100"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path98"
|
id="path98"
|
||||||
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath><clipPath
|
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath112"
|
id="clipPath112"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path110"
|
id="path110"
|
||||||
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath124"
|
id="clipPath124"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path122"
|
id="path122"
|
||||||
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath><clipPath
|
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath136"
|
id="clipPath136"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path134"
|
id="path134"
|
||||||
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath><clipPath
|
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath148"
|
id="clipPath148"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path146"
|
id="path146"
|
||||||
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath><clipPath
|
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath160"
|
id="clipPath160"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path158"
|
id="path158"
|
||||||
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath172"
|
id="clipPath172"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path170"
|
id="path170"
|
||||||
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath184"
|
id="clipPath184"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path182"
|
id="path182"
|
||||||
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath><clipPath
|
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath196"
|
id="clipPath196"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path194"
|
id="path194"
|
||||||
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath208"
|
id="clipPath208"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path206"
|
id="path206"
|
||||||
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath220"
|
id="clipPath220"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path218"
|
id="path218"
|
||||||
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath232"
|
id="clipPath232"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path230"
|
id="path230"
|
||||||
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath><clipPath
|
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath244"
|
id="clipPath244"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path242"
|
id="path242"
|
||||||
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath256"
|
id="clipPath256"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path254"
|
id="path254"
|
||||||
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath><clipPath
|
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath>
|
||||||
|
<clipPath
|
||||||
id="clipPath268"
|
id="clipPath268"
|
||||||
clipPathUnits="userSpaceOnUse"><path
|
clipPathUnits="userSpaceOnUse"><path
|
||||||
id="path266"
|
id="path266"
|
||||||
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs><g
|
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs>
|
||||||
|
<g
|
||||||
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
|
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
|
||||||
id="g10"><g
|
id="g10"><g
|
||||||
transform="scale(0.1)"
|
transform="scale(0.1)"
|
||||||
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
@ -10,11 +10,11 @@ structures. In `kmath` performance depends on which particular context was used
|
|||||||
Let us consider following contexts:
|
Let us consider following contexts:
|
||||||
```kotlin
|
```kotlin
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
val autoField = NDField.auto(RealField, dim, dim)
|
val autoField = NDField.auto(DoubleField, dim, dim)
|
||||||
// specialized nd-field for Double. It works as generic Double field as well
|
// specialized nd-field for Double. It works as generic Double field as well
|
||||||
val specializedField = NDField.real(dim, dim)
|
val specializedField = NDField.real(dim, dim)
|
||||||
//A generic boxing field. It should be used for objects, not primitives.
|
//A generic boxing field. It should be used for objects, not primitives.
|
||||||
val genericField = NDField.buffered(RealField, dim, dim)
|
val genericField = NDField.buffered(DoubleField, dim, dim)
|
||||||
```
|
```
|
||||||
Now let us perform several tests and see which implementation is best suited for each case:
|
Now let us perform several tests and see which implementation is best suited for each case:
|
||||||
|
|
||||||
|
62
docs/templates/ARTIFACT-TEMPLATE.md
vendored
@ -1,34 +1,28 @@
|
|||||||
> #### Artifact:
|
## Artifact:
|
||||||
>
|
|
||||||
> This module artifact: `${group}:${name}:${version}`.
|
The Maven coordinates of this project are `${group}:${name}:${version}`.
|
||||||
>
|
|
||||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/${name}/images/download.svg) ](https://bintray.com/mipt-npm/kscience/${name}/_latestVersion)
|
**Gradle:**
|
||||||
>
|
```gradle
|
||||||
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/${name}/images/download.svg) ](https://bintray.com/mipt-npm/dev/${name}/_latestVersion)
|
repositories {
|
||||||
>
|
maven { url 'https://repo.kotlin.link' }
|
||||||
> **Gradle:**
|
maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||||
>
|
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||||
> ```gradle
|
}
|
||||||
> repositories {
|
|
||||||
> maven { url 'https://repo.kotlin.link' }
|
dependencies {
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
implementation '${group}:${name}:${version}'
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
}
|
||||||
> }
|
```
|
||||||
>
|
**Gradle Kotlin DSL:**
|
||||||
> dependencies {
|
```kotlin
|
||||||
> implementation '${group}:${name}:${version}'
|
repositories {
|
||||||
> }
|
maven("https://repo.kotlin.link")
|
||||||
> ```
|
maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> **Gradle Kotlin DSL:**
|
maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
>
|
}
|
||||||
> ```kotlin
|
|
||||||
> repositories {
|
dependencies {
|
||||||
> maven("https://repo.kotlin.link")
|
implementation("${group}:${name}:${version}")
|
||||||
> 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("${group}:${name}:${version}")
|
|
||||||
> }
|
|
||||||
> ```
|
|
9
docs/templates/README-TEMPLATE.md
vendored
@ -1,9 +1,8 @@
|
|||||||
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
|
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
|
||||||
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
|
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
|
||||||
|
|
||||||
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
|
||||||
|
[![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)
|
||||||
[![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)
|
[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
|
||||||
|
|
||||||
# KMath
|
# KMath
|
||||||
|
|
||||||
@ -95,6 +94,10 @@ cases. We expect the worst KMath benchmarks will perform better than native Pyth
|
|||||||
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
|
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
|
||||||
better than SciPy.
|
better than SciPy.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
|
||||||
|
|
||||||
### Repositories
|
### Repositories
|
||||||
|
|
||||||
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
|
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
|
||||||
|
@ -4,11 +4,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
import ru.mipt.npm.gradle.Maturity
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
kotlin("plugin.allopen")
|
kotlin("plugin.allopen")
|
||||||
id("kotlinx.benchmark")
|
id("org.jetbrains.kotlinx.benchmark")
|
||||||
}
|
}
|
||||||
|
|
||||||
allOpen.annotation("org.openjdk.jmh.annotations.State")
|
allOpen.annotation("org.openjdk.jmh.annotations.State")
|
||||||
@ -25,7 +26,10 @@ repositories {
|
|||||||
maven("https://dl.bintray.com/mipt-npm/dev")
|
maven("https://dl.bintray.com/mipt-npm/dev")
|
||||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||||
maven("https://jitpack.io")
|
maven("https://jitpack.io")
|
||||||
maven("http://logicrunch.research.it.uu.se/maven/")
|
maven{
|
||||||
|
setUrl("http://logicrunch.research.it.uu.se/maven/")
|
||||||
|
isAllowInsecureProtocol = true
|
||||||
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +62,7 @@ dependencies {
|
|||||||
implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
|
implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
|
||||||
|
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-io:0.2.0-npm-dev-11")
|
implementation("org.jetbrains.kotlinx:kotlinx-io:0.2.0-npm-dev-11")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20")
|
implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.0")
|
||||||
implementation("org.slf4j:slf4j-simple:1.7.30")
|
implementation("org.slf4j:slf4j-simple:1.7.30")
|
||||||
|
|
||||||
// plotting
|
// plotting
|
||||||
@ -105,19 +109,31 @@ benchmark {
|
|||||||
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
|
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
|
||||||
include("MatrixInverseBenchmark")
|
include("MatrixInverseBenchmark")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configurations.register("bigInt") {
|
||||||
|
warmups = 1 // number of warmup iterations
|
||||||
|
iterations = 3 // number of iterations
|
||||||
|
iterationTime = 500 // time in seconds per iteration
|
||||||
|
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
|
||||||
|
include("BigIntBenchmark")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin.sourceSets.all {
|
kotlin.sourceSets.all {
|
||||||
with(languageSettings) {
|
with(languageSettings) {
|
||||||
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
|
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
|
||||||
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
||||||
|
useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<KotlinCompile> {
|
tasks.withType<KotlinCompile> {
|
||||||
kotlinOptions.jvmTarget = "11"
|
kotlinOptions{
|
||||||
|
jvmTarget = "11"
|
||||||
|
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readme {
|
readme {
|
||||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
maturity = Maturity.EXPERIMENTAL
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.benchmarks
|
||||||
|
|
||||||
|
import kotlinx.benchmark.Blackhole
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark
|
||||||
|
import org.openjdk.jmh.annotations.Scope
|
||||||
|
import org.openjdk.jmh.annotations.State
|
||||||
|
import space.kscience.kmath.operations.BigIntField
|
||||||
|
import space.kscience.kmath.operations.JBigIntegerField
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
internal class BigIntBenchmark {
|
||||||
|
|
||||||
|
val kmNumber = BigIntField.number(Int.MAX_VALUE)
|
||||||
|
val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE)
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun kmAdd(blackhole: Blackhole) = BigIntField {
|
||||||
|
blackhole.consume(kmNumber + kmNumber + kmNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun jvmAdd(blackhole: Blackhole) = JBigIntegerField {
|
||||||
|
blackhole.consume(jvmNumber + jvmNumber + jvmNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun kmMultiply(blackhole: Blackhole) = BigIntField {
|
||||||
|
blackhole.consume(kmNumber * kmNumber * kmNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun jvmMultiply(blackhole: Blackhole) = JBigIntegerField {
|
||||||
|
blackhole.consume(jvmNumber * jvmNumber * jvmNumber)
|
||||||
|
}
|
||||||
|
}
|
@ -10,14 +10,14 @@ import kotlinx.benchmark.Scope
|
|||||||
import kotlinx.benchmark.State
|
import kotlinx.benchmark.State
|
||||||
import space.kscience.kmath.complex.Complex
|
import space.kscience.kmath.complex.Complex
|
||||||
import space.kscience.kmath.complex.complex
|
import space.kscience.kmath.complex.complex
|
||||||
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import space.kscience.kmath.structures.MutableBuffer
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
import space.kscience.kmath.structures.RealBuffer
|
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
internal class BufferBenchmark {
|
internal class BufferBenchmark {
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun genericRealBufferReadWrite() {
|
fun genericDoubleBufferReadWrite() {
|
||||||
val buffer = RealBuffer(size) { it.toDouble() }
|
val buffer = DoubleBuffer(size) { it.toDouble() }
|
||||||
|
|
||||||
(0 until size).forEach {
|
(0 until size).forEach {
|
||||||
buffer[it]
|
buffer[it]
|
||||||
|
@ -13,7 +13,7 @@ import space.kscience.kmath.commons.linear.CMLinearSpace
|
|||||||
import space.kscience.kmath.ejml.EjmlLinearSpace
|
import space.kscience.kmath.ejml.EjmlLinearSpace
|
||||||
import space.kscience.kmath.linear.LinearSpace
|
import space.kscience.kmath.linear.LinearSpace
|
||||||
import space.kscience.kmath.linear.invoke
|
import space.kscience.kmath.linear.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
@ -56,7 +56,7 @@ internal class DotBenchmark {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun bufferedDot(blackhole: Blackhole) {
|
fun bufferedDot(blackhole: Blackhole) {
|
||||||
LinearSpace.auto(RealField).invoke {
|
LinearSpace.auto(DoubleField).invoke {
|
||||||
blackhole.consume(matrix1 dot matrix2)
|
blackhole.consume(matrix1 dot matrix2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,12 @@ import kotlinx.benchmark.Benchmark
|
|||||||
import kotlinx.benchmark.Blackhole
|
import kotlinx.benchmark.Blackhole
|
||||||
import kotlinx.benchmark.Scope
|
import kotlinx.benchmark.Scope
|
||||||
import kotlinx.benchmark.State
|
import kotlinx.benchmark.State
|
||||||
import space.kscience.kmath.asm.compile
|
import space.kscience.kmath.asm.compileToExpression
|
||||||
import space.kscience.kmath.ast.mstInField
|
import space.kscience.kmath.expressions.*
|
||||||
import space.kscience.kmath.expressions.Expression
|
import space.kscience.kmath.misc.symbol
|
||||||
import space.kscience.kmath.expressions.expressionInField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.expressions.invoke
|
|
||||||
import space.kscience.kmath.expressions.symbol
|
|
||||||
import space.kscience.kmath.operations.RealField
|
|
||||||
import space.kscience.kmath.operations.bindSymbol
|
import space.kscience.kmath.operations.bindSymbol
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
@ -33,20 +31,20 @@ internal class ExpressionsInterpretersBenchmark {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun mstExpression(blackhole: Blackhole) {
|
fun mstExpression(blackhole: Blackhole) {
|
||||||
val expr = algebra.mstInField {
|
val expr = MstField {
|
||||||
val x = bindSymbol(x)
|
val x = bindSymbol(x)
|
||||||
x * 2.0 + number(2.0) / x - 16.0
|
x * 2.0 + number(2.0) / x - 16.0
|
||||||
}
|
}.toExpression(algebra)
|
||||||
|
|
||||||
invokeAndSum(expr, blackhole)
|
invokeAndSum(expr, blackhole)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun asmExpression(blackhole: Blackhole) {
|
fun asmExpression(blackhole: Blackhole) {
|
||||||
val expr = algebra.mstInField {
|
val expr = MstField {
|
||||||
val x = bindSymbol(x)
|
val x = bindSymbol(x)
|
||||||
x * 2.0 + number(2.0) / x - 16.0
|
x * 2.0 + number(2.0) / x - 16.0
|
||||||
}.compile()
|
}.compileToExpression(algebra)
|
||||||
|
|
||||||
invokeAndSum(expr, blackhole)
|
invokeAndSum(expr, blackhole)
|
||||||
}
|
}
|
||||||
@ -73,7 +71,7 @@ internal class ExpressionsInterpretersBenchmark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private val algebra = RealField
|
private val algebra = DoubleField
|
||||||
private val x by symbol
|
private val x by symbol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import kotlinx.benchmark.Blackhole
|
|||||||
import kotlinx.benchmark.Scope
|
import kotlinx.benchmark.Scope
|
||||||
import kotlinx.benchmark.State
|
import kotlinx.benchmark.State
|
||||||
import space.kscience.kmath.nd.*
|
import space.kscience.kmath.nd.*
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
@ -18,7 +18,7 @@ internal class NDFieldBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun autoFieldAdd(blackhole: Blackhole) {
|
fun autoFieldAdd(blackhole: Blackhole) {
|
||||||
with(autoField) {
|
with(autoField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += one }
|
repeat(n) { res += one }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ internal class NDFieldBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun specializedFieldAdd(blackhole: Blackhole) {
|
fun specializedFieldAdd(blackhole: Blackhole) {
|
||||||
with(specializedField) {
|
with(specializedField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ internal class NDFieldBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun boxingFieldAdd(blackhole: Blackhole) {
|
fun boxingFieldAdd(blackhole: Blackhole) {
|
||||||
with(genericField) {
|
with(genericField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -46,8 +46,8 @@ internal class NDFieldBenchmark {
|
|||||||
private companion object {
|
private companion object {
|
||||||
private const val dim = 1000
|
private const val dim = 1000
|
||||||
private const val n = 100
|
private const val n = 100
|
||||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||||
private val specializedField = NDAlgebra.real(dim, dim)
|
private val specializedField = AlgebraND.real(dim, dim)
|
||||||
private val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ import kotlinx.benchmark.Blackhole
|
|||||||
import kotlinx.benchmark.Scope
|
import kotlinx.benchmark.Scope
|
||||||
import kotlinx.benchmark.State
|
import kotlinx.benchmark.State
|
||||||
import org.jetbrains.bio.viktor.F64Array
|
import org.jetbrains.bio.viktor.F64Array
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.nd.auto
|
import space.kscience.kmath.nd.auto
|
||||||
import space.kscience.kmath.nd.real
|
import space.kscience.kmath.nd.real
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.viktor.ViktorNDField
|
import space.kscience.kmath.viktor.ViktorNDField
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
@ -22,7 +22,7 @@ internal class ViktorBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun automaticFieldAddition(blackhole: Blackhole) {
|
fun automaticFieldAddition(blackhole: Blackhole) {
|
||||||
with(autoField) {
|
with(autoField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ internal class ViktorBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun realFieldAddition(blackhole: Blackhole) {
|
fun realFieldAddition(blackhole: Blackhole) {
|
||||||
with(realField) {
|
with(realField) {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
blackhole.consume(res)
|
blackhole.consume(res)
|
||||||
}
|
}
|
||||||
@ -59,8 +59,8 @@ internal class ViktorBenchmark {
|
|||||||
private const val n = 100
|
private const val n = 100
|
||||||
|
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||||
private val realField = NDAlgebra.real(dim, dim)
|
private val realField = AlgebraND.real(dim, dim)
|
||||||
private val viktorField = ViktorNDField(dim, dim)
|
private val viktorField = ViktorNDField(dim, dim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ import kotlinx.benchmark.Blackhole
|
|||||||
import kotlinx.benchmark.Scope
|
import kotlinx.benchmark.Scope
|
||||||
import kotlinx.benchmark.State
|
import kotlinx.benchmark.State
|
||||||
import org.jetbrains.bio.viktor.F64Array
|
import org.jetbrains.bio.viktor.F64Array
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
import space.kscience.kmath.nd.auto
|
import space.kscience.kmath.nd.auto
|
||||||
import space.kscience.kmath.nd.real
|
import space.kscience.kmath.nd.real
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.viktor.ViktorNDField
|
import space.kscience.kmath.viktor.ViktorFieldND
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
internal class ViktorLogBenchmark {
|
internal class ViktorLogBenchmark {
|
||||||
@ -51,8 +51,8 @@ internal class ViktorLogBenchmark {
|
|||||||
private const val n = 100
|
private const val n = 100
|
||||||
|
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||||
private val realNdField = NDAlgebra.real(dim, dim)
|
private val realNdField = AlgebraND.real(dim, dim)
|
||||||
private val viktorField = ViktorNDField(intArrayOf(dim, dim))
|
private val viktorField = ViktorFieldND(intArrayOf(dim, dim))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
|
import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess
|
||||||
|
import space.kscience.kmath.ast.rendering.LatexSyntaxRenderer
|
||||||
|
import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer
|
||||||
|
import space.kscience.kmath.ast.rendering.renderWithStringBuilder
|
||||||
|
|
||||||
|
public fun main() {
|
||||||
|
val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
|
||||||
|
val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
|
||||||
|
println("MathSyntax:")
|
||||||
|
println(syntax)
|
||||||
|
println()
|
||||||
|
val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
|
||||||
|
println("LaTeX:")
|
||||||
|
println(latex)
|
||||||
|
println()
|
||||||
|
val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax)
|
||||||
|
println("MathML:")
|
||||||
|
println(mathML)
|
||||||
|
}
|
@ -5,16 +5,20 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.MstField
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.expressions.interpret
|
||||||
|
import space.kscience.kmath.misc.Symbol.Companion.x
|
||||||
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.bindSymbol
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val expr = RealField.mstInField {
|
val expr = MstField {
|
||||||
val x = bindSymbol("x")
|
val x = bindSymbol(x)
|
||||||
x * 2.0 + number(2.0) / x - 16.0
|
x * 2.0 + number(2.0) / x - 16.0
|
||||||
}
|
}
|
||||||
|
|
||||||
repeat(10000000) {
|
repeat(10000000) {
|
||||||
expr.invoke("x" to 1.0)
|
expr.interpret(DoubleField, x to 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,12 +5,12 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
import space.kscience.kmath.asm.compile
|
import space.kscience.kmath.asm.compileToExpression
|
||||||
import space.kscience.kmath.expressions.derivative
|
import space.kscience.kmath.expressions.derivative
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.kotlingrad.toDiffExpression
|
||||||
import space.kscience.kmath.kotlingrad.differentiable
|
import space.kscience.kmath.misc.symbol
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
|
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
|
||||||
@ -19,11 +19,11 @@ import space.kscience.kmath.operations.RealField
|
|||||||
fun main() {
|
fun main() {
|
||||||
val x by symbol
|
val x by symbol
|
||||||
|
|
||||||
val actualDerivative = MstExpression(RealField, "x^2-4*x-44".parseMath())
|
val actualDerivative = "x^2-4*x-44".parseMath()
|
||||||
.differentiable()
|
.toDiffExpression(DoubleField)
|
||||||
.derivative(x)
|
.derivative(x)
|
||||||
.compile()
|
|
||||||
|
|
||||||
val expectedDerivative = MstExpression(RealField, "2*x-4".parseMath()).compile()
|
|
||||||
|
val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField)
|
||||||
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
|
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,14 @@ import kscience.plotly.models.ScatterMode
|
|||||||
import kscience.plotly.models.TraceValues
|
import kscience.plotly.models.TraceValues
|
||||||
import space.kscience.kmath.commons.optimization.chiSquared
|
import space.kscience.kmath.commons.optimization.chiSquared
|
||||||
import space.kscience.kmath.commons.optimization.minimize
|
import space.kscience.kmath.commons.optimization.minimize
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.distributions.NormalDistribution
|
||||||
import space.kscience.kmath.real.RealVector
|
import space.kscience.kmath.misc.symbol
|
||||||
|
import space.kscience.kmath.optimization.FunctionOptimization
|
||||||
|
import space.kscience.kmath.optimization.OptimizationResult
|
||||||
|
import space.kscience.kmath.real.DoubleVector
|
||||||
import space.kscience.kmath.real.map
|
import space.kscience.kmath.real.map
|
||||||
import space.kscience.kmath.real.step
|
import space.kscience.kmath.real.step
|
||||||
import space.kscience.kmath.stat.*
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.structures.asIterable
|
import space.kscience.kmath.structures.asIterable
|
||||||
import space.kscience.kmath.structures.toList
|
import space.kscience.kmath.structures.toList
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -31,17 +34,16 @@ private val c by symbol
|
|||||||
/**
|
/**
|
||||||
* Shortcut to use buffers in plotly
|
* Shortcut to use buffers in plotly
|
||||||
*/
|
*/
|
||||||
operator fun TraceValues.invoke(vector: RealVector) {
|
operator fun TraceValues.invoke(vector: DoubleVector) {
|
||||||
numbers = vector.asIterable()
|
numbers = vector.asIterable()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules.
|
* Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules.
|
||||||
*/
|
*/
|
||||||
fun main() {
|
suspend fun main() {
|
||||||
|
|
||||||
//A generator for a normally distributed values
|
//A generator for a normally distributed values
|
||||||
val generator = Distribution.normal()
|
val generator = NormalDistribution(2.0, 7.0)
|
||||||
|
|
||||||
//A chain/flow of random values with the given seed
|
//A chain/flow of random values with the given seed
|
||||||
val chain = generator.sample(RandomGenerator.default(112667))
|
val chain = generator.sample(RandomGenerator.default(112667))
|
||||||
@ -54,7 +56,7 @@ fun main() {
|
|||||||
//Perform an operation on each x value (much more effective, than numpy)
|
//Perform an operation on each x value (much more effective, than numpy)
|
||||||
val y = x.map {
|
val y = x.map {
|
||||||
val value = it.pow(2) + it + 1
|
val value = it.pow(2) + it + 1
|
||||||
value + chain.nextDouble() * sqrt(value)
|
value + chain.next() * sqrt(value)
|
||||||
}
|
}
|
||||||
// this will also work, but less effective:
|
// this will also work, but less effective:
|
||||||
// val y = x.pow(2)+ x + 1 + chain.nextDouble()
|
// val y = x.pow(2)+ x + 1 + chain.nextDouble()
|
||||||
@ -63,10 +65,10 @@ fun main() {
|
|||||||
val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma)
|
val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma)
|
||||||
|
|
||||||
// compute differentiable chi^2 sum for given model ax^2 + bx + c
|
// compute differentiable chi^2 sum for given model ax^2 + bx + c
|
||||||
val chi2 = Fitting.chiSquared(x, y, yErr) { x1 ->
|
val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 ->
|
||||||
//bind variables to autodiff context
|
//bind variables to autodiff context
|
||||||
val a = bind(a)
|
val a = bindSymbol(a)
|
||||||
val b = bind(b)
|
val b = bindSymbol(b)
|
||||||
//Include default value for c if it is not provided as a parameter
|
//Include default value for c if it is not provided as a parameter
|
||||||
val c = bindSymbolOrNull(c) ?: one
|
val c = bindSymbolOrNull(c) ?: one
|
||||||
a * x1.pow(2) + b * x1 + c
|
a * x1.pow(2) + b * x1 + c
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package space.kscience.kmath.functions
|
||||||
|
|
||||||
|
import space.kscience.kmath.integration.integrate
|
||||||
|
import space.kscience.kmath.integration.value
|
||||||
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
//Define a function
|
||||||
|
val function: UnivariateFunction<Double> = { x -> 3 * x.pow(2) + 2 * x + 1 }
|
||||||
|
|
||||||
|
//get the result of the integration
|
||||||
|
val result = DoubleField.integrate(0.0..10.0, function = function)
|
||||||
|
|
||||||
|
//the value is nullable because in some cases the integration could not succeed
|
||||||
|
println(result.value)
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package space.kscience.kmath.functions
|
||||||
|
|
||||||
|
import space.kscience.kmath.integration.integrate
|
||||||
|
import space.kscience.kmath.integration.value
|
||||||
|
import space.kscience.kmath.nd.StructureND
|
||||||
|
import space.kscience.kmath.nd.nd
|
||||||
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
|
|
||||||
|
fun main(): Unit = DoubleField {
|
||||||
|
nd(2, 2) {
|
||||||
|
|
||||||
|
//Produce a diagonal StructureND
|
||||||
|
fun diagonal(v: Double) = produce { (i, j) ->
|
||||||
|
if (i == j) v else 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
//Define a function in a nd space
|
||||||
|
val function: (Double) -> StructureND<Double> = { x: Double -> 3 * number(x).pow(2) + 2 * diagonal(x) + 1 }
|
||||||
|
|
||||||
|
//get the result of the integration
|
||||||
|
val result = integrate(0.0..10.0, function = function)
|
||||||
|
|
||||||
|
//the value is nullable because in some cases the integration could not succeed
|
||||||
|
println(result.value)
|
||||||
|
}
|
||||||
|
}
|
@ -6,11 +6,11 @@
|
|||||||
package space.kscience.kmath.linear
|
package space.kscience.kmath.linear
|
||||||
|
|
||||||
import space.kscience.kmath.real.*
|
import space.kscience.kmath.real.*
|
||||||
import space.kscience.kmath.structures.RealBuffer
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val x0 = Point(0.0, 0.0, 0.0)
|
val x0 = DoubleVector(0.0, 0.0, 0.0)
|
||||||
val sigma = Point(1.0, 1.0, 1.0)
|
val sigma = DoubleVector(1.0, 1.0, 1.0)
|
||||||
|
|
||||||
val gaussian: (Point<Double>) -> Double = { x ->
|
val gaussian: (Point<Double>) -> Double = { x ->
|
||||||
require(x.size == x0.size)
|
require(x.size == x0.size)
|
||||||
@ -19,9 +19,9 @@ fun main() {
|
|||||||
|
|
||||||
fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> {
|
fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> {
|
||||||
require(x.size == x0.size)
|
require(x.size == x0.size)
|
||||||
return RealBuffer(x.size) { i ->
|
return DoubleBuffer(x.size) { i ->
|
||||||
val h = sigma[i] / 5
|
val h = sigma[i] / 5
|
||||||
val dVector = RealBuffer(x.size) { if (it == i) h else 0.0 }
|
val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
|
||||||
val f1 = invoke(x + dVector / 2)
|
val f1 = invoke(x + dVector / 2)
|
||||||
val f0 = invoke(x - dVector / 2)
|
val f0 = invoke(x - dVector / 2)
|
||||||
(f1 - f0) / h
|
(f1 - f0) / h
|
||||||
|
@ -7,17 +7,17 @@ package space.kscience.kmath.operations
|
|||||||
|
|
||||||
import space.kscience.kmath.complex.Complex
|
import space.kscience.kmath.complex.Complex
|
||||||
import space.kscience.kmath.complex.complex
|
import space.kscience.kmath.complex.complex
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
// 2d element
|
// 2d element
|
||||||
val element = NDAlgebra.complex(2, 2).produce { (i, j) ->
|
val element = AlgebraND.complex(2, 2).produce { (i, j) ->
|
||||||
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
||||||
}
|
}
|
||||||
println(element)
|
println(element)
|
||||||
|
|
||||||
// 1d element operation
|
// 1d element operation
|
||||||
val result = with(NDAlgebra.complex(8)) {
|
val result = with(AlgebraND.complex(8)) {
|
||||||
val a = produce { (it) -> i * it - it.toDouble() }
|
val a = produce { (it) -> i * it - it.toDouble() }
|
||||||
val b = 3
|
val b = 3
|
||||||
val c = Complex(1.0, 1.0)
|
val c = Complex(1.0, 1.0)
|
||||||
|
@ -3,26 +3,27 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kscience.kmath.commons.prob
|
package space.kscience.kmath.stat
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler
|
import org.apache.commons.rng.sampling.distribution.BoxMullerNormalizedGaussianSampler
|
||||||
import org.apache.commons.rng.simple.RandomSource
|
import org.apache.commons.rng.simple.RandomSource
|
||||||
import space.kscience.kmath.stat.*
|
import space.kscience.kmath.samplers.GaussianSampler
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
import org.apache.commons.rng.sampling.distribution.GaussianSampler as CMGaussianSampler
|
||||||
|
|
||||||
private fun runChain(): Duration {
|
private suspend fun runKMathChained(): Duration {
|
||||||
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
|
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
|
||||||
val normal = Distribution.normal(NormalSamplerMethod.Ziggurat)
|
val normal = GaussianSampler(7.0, 2.0)
|
||||||
val chain = normal.sample(generator)
|
val chain = normal.sample(generator)
|
||||||
val startTime = Instant.now()
|
val startTime = Instant.now()
|
||||||
var sum = 0.0
|
var sum = 0.0
|
||||||
|
|
||||||
repeat(10000001) { counter ->
|
repeat(10000001) { counter ->
|
||||||
sum += chain.nextDouble()
|
sum += chain.next()
|
||||||
|
|
||||||
if (counter % 100000 == 0) {
|
if (counter % 100000 == 0) {
|
||||||
val duration = Duration.between(startTime, Instant.now())
|
val duration = Duration.between(startTime, Instant.now())
|
||||||
@ -34,9 +35,15 @@ private fun runChain(): Duration {
|
|||||||
return Duration.between(startTime, Instant.now())
|
return Duration.between(startTime, Instant.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runDirect(): Duration {
|
private fun runApacheDirect(): Duration {
|
||||||
val provider = RandomSource.create(RandomSource.MT, 123L)
|
val rng = RandomSource.create(RandomSource.MT, 123L)
|
||||||
val sampler = ZigguratNormalizedGaussianSampler(provider)
|
|
||||||
|
val sampler = CMGaussianSampler.of(
|
||||||
|
BoxMullerNormalizedGaussianSampler.of(rng),
|
||||||
|
7.0,
|
||||||
|
2.0
|
||||||
|
)
|
||||||
|
|
||||||
val startTime = Instant.now()
|
val startTime = Instant.now()
|
||||||
var sum = 0.0
|
var sum = 0.0
|
||||||
|
|
||||||
@ -56,11 +63,9 @@ private fun runDirect(): Duration {
|
|||||||
/**
|
/**
|
||||||
* Comparing chain sampling performance with direct sampling performance
|
* Comparing chain sampling performance with direct sampling performance
|
||||||
*/
|
*/
|
||||||
fun main() {
|
fun main(): Unit = runBlocking(Dispatchers.Default) {
|
||||||
runBlocking(Dispatchers.Default) {
|
val directJob = async { runApacheDirect() }
|
||||||
val chainJob = async { runChain() }
|
val chainJob = async { runKMathChained() }
|
||||||
val directJob = async { runDirect() }
|
println("KMath Chained: ${chainJob.await()}")
|
||||||
println("Chain: ${chainJob.await()}")
|
println("Apache Direct: ${directJob.await()}")
|
||||||
println("Direct: ${directJob.await()}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,15 @@ package space.kscience.kmath.stat
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import space.kscience.kmath.chains.Chain
|
import space.kscience.kmath.chains.Chain
|
||||||
import space.kscience.kmath.chains.collectWithState
|
import space.kscience.kmath.chains.collectWithState
|
||||||
|
import space.kscience.kmath.distributions.NormalDistribution
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state of distribution averager
|
* The state of distribution averager.
|
||||||
*/
|
*/
|
||||||
private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
|
private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Averaging
|
* Averaging.
|
||||||
*/
|
*/
|
||||||
private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChainState(), { it.copy() }) { chain ->
|
private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChainState(), { it.copy() }) { chain ->
|
||||||
val next = chain.next()
|
val next = chain.next()
|
||||||
@ -26,7 +27,7 @@ private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChai
|
|||||||
|
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val normal = Distribution.normal()
|
val normal = NormalDistribution(0.0, 2.0)
|
||||||
val chain = normal.sample(RandomGenerator.default).mean()
|
val chain = normal.sample(RandomGenerator.default).mean()
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
|
@ -9,8 +9,8 @@ package space.kscience.kmath.structures
|
|||||||
|
|
||||||
import space.kscience.kmath.complex.*
|
import space.kscience.kmath.complex.*
|
||||||
import space.kscience.kmath.linear.transpose
|
import space.kscience.kmath.linear.transpose
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
import space.kscience.kmath.nd.AlgebraND
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.nd.as2D
|
import space.kscience.kmath.nd.as2D
|
||||||
import space.kscience.kmath.nd.real
|
import space.kscience.kmath.nd.real
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
@ -20,12 +20,12 @@ fun main() {
|
|||||||
val dim = 1000
|
val dim = 1000
|
||||||
val n = 1000
|
val n = 1000
|
||||||
|
|
||||||
val realField = NDAlgebra.real(dim, dim)
|
val realField = AlgebraND.real(dim, dim)
|
||||||
val complexField: ComplexNDField = NDAlgebra.complex(dim, dim)
|
val complexField: ComplexFieldND = AlgebraND.complex(dim, dim)
|
||||||
|
|
||||||
val realTime = measureTimeMillis {
|
val realTime = measureTimeMillis {
|
||||||
realField {
|
realField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) {
|
repeat(n) {
|
||||||
res += 1.0
|
res += 1.0
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ fun main() {
|
|||||||
|
|
||||||
val complexTime = measureTimeMillis {
|
val complexTime = measureTimeMillis {
|
||||||
complexField {
|
complexField {
|
||||||
var res: NDStructure<Complex> = one
|
var res: StructureND<Complex> = one
|
||||||
repeat(n) {
|
repeat(n) {
|
||||||
res += 1.0
|
res += 1.0
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import kotlinx.coroutines.GlobalScope
|
|||||||
import org.nd4j.linalg.factory.Nd4j
|
import org.nd4j.linalg.factory.Nd4j
|
||||||
import space.kscience.kmath.nd.*
|
import space.kscience.kmath.nd.*
|
||||||
import space.kscience.kmath.nd4j.Nd4jArrayField
|
import space.kscience.kmath.nd4j.Nd4jArrayField
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import space.kscience.kmath.viktor.ViktorNDField
|
import space.kscience.kmath.viktor.ViktorNDField
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
@ -29,56 +29,56 @@ fun main() {
|
|||||||
val n = 1000
|
val n = 1000
|
||||||
|
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
val autoField = NDAlgebra.auto(RealField, dim, dim)
|
val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||||
// specialized nd-field for Double. It works as generic Double field as well
|
// specialized nd-field for Double. It works as generic Double field as well
|
||||||
val realField = NDAlgebra.real(dim, dim)
|
val realField = AlgebraND.real(dim, dim)
|
||||||
//A generic boxing field. It should be used for objects, not primitives.
|
//A generic boxing field. It should be used for objects, not primitives.
|
||||||
val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||||
// Nd4j specialized field.
|
// Nd4j specialized field.
|
||||||
val nd4jField = Nd4jArrayField.real(dim, dim)
|
val nd4jField = Nd4jArrayField.real(dim, dim)
|
||||||
//viktor field
|
//viktor field
|
||||||
val viktorField = ViktorNDField(dim, dim)
|
val viktorField = ViktorNDField(dim, dim)
|
||||||
//parallel processing based on Java Streams
|
//parallel processing based on Java Streams
|
||||||
val parallelField = NDAlgebra.realWithStream(dim,dim)
|
val parallelField = AlgebraND.realWithStream(dim, dim)
|
||||||
|
|
||||||
measureAndPrint("Boxing addition") {
|
measureAndPrint("Boxing addition") {
|
||||||
boxingField {
|
boxingField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Specialized addition") {
|
measureAndPrint("Specialized addition") {
|
||||||
realField {
|
realField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Nd4j specialized addition") {
|
measureAndPrint("Nd4j specialized addition") {
|
||||||
nd4jField {
|
nd4jField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Viktor addition") {
|
measureAndPrint("Viktor addition") {
|
||||||
viktorField {
|
viktorField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Parallel stream addition") {
|
measureAndPrint("Parallel stream addition") {
|
||||||
parallelField {
|
parallelField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Automatic field addition") {
|
measureAndPrint("Automatic field addition") {
|
||||||
autoField {
|
autoField {
|
||||||
var res: NDStructure<Double> = one
|
var res: StructureND<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2018-2021 KMath contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
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 [java.util.stream.DoubleStream] for parallel
|
||||||
|
* execution.
|
||||||
|
*/
|
||||||
|
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)
|
@ -5,17 +5,17 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.kmath.nd.BufferND
|
||||||
import space.kscience.kmath.nd.DefaultStrides
|
import space.kscience.kmath.nd.DefaultStrides
|
||||||
import space.kscience.kmath.nd.NDBuffer
|
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||||
fun main() {
|
fun main() {
|
||||||
val n = 6000
|
val n = 6000
|
||||||
val array = DoubleArray(n * n) { 1.0 }
|
val array = DoubleArray(n * n) { 1.0 }
|
||||||
val buffer = RealBuffer(array)
|
val buffer = DoubleBuffer(array)
|
||||||
val strides = DefaultStrides(intArrayOf(n, n))
|
val strides = DefaultStrides(intArrayOf(n, n))
|
||||||
val structure = NDBuffer(strides, buffer)
|
val structure = BufferND(strides, buffer)
|
||||||
|
|
||||||
measureTimeMillis {
|
measureTimeMillis {
|
||||||
var res = 0.0
|
var res = 0.0
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.nd.mapToBuffer
|
import space.kscience.kmath.nd.mapToBuffer
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
@Suppress("UNUSED_VARIABLE")
|
@Suppress("UNUSED_VARIABLE")
|
||||||
fun main() {
|
fun main() {
|
||||||
val n = 6000
|
val n = 6000
|
||||||
val structure = NDStructure.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
val structure = StructureND.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
||||||
structure.mapToBuffer { it + 1 } // warm-up
|
structure.mapToBuffer { it + 1 } // warm-up
|
||||||
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
|
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
|
||||||
println("Structure mapping finished in $time1 millis")
|
println("Structure mapping finished in $time1 millis")
|
||||||
@ -25,10 +25,10 @@ fun main() {
|
|||||||
|
|
||||||
println("Array mapping finished in $time2 millis")
|
println("Array mapping finished in $time2 millis")
|
||||||
|
|
||||||
val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
|
val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 })
|
||||||
|
|
||||||
val time3 = measureTimeMillis {
|
val time3 = measureTimeMillis {
|
||||||
val target = RealBuffer(DoubleArray(n * n))
|
val target = DoubleBuffer(DoubleArray(n * n))
|
||||||
val res = array.forEachIndexed { index, value ->
|
val res = array.forEachIndexed { index, value ->
|
||||||
target[index] = value + 1
|
target[index] = value + 1
|
||||||
}
|
}
|
||||||
|
@ -9,5 +9,5 @@ kotlin.mpp.stability.nowarn=true
|
|||||||
kotlin.native.enableDependencyPropagation=false
|
kotlin.native.enableDependencyPropagation=false
|
||||||
kotlin.parallel.tasks.in.project=true
|
kotlin.parallel.tasks.in.project=true
|
||||||
org.gradle.configureondemand=true
|
org.gradle.configureondemand=true
|
||||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G
|
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
5
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,8 +1,3 @@
|
|||||||
#
|
|
||||||
# Copyright 2018-2021 KMath contributors.
|
|
||||||
# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
#
|
|
||||||
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
|
||||||
|
@ -1,49 +1,43 @@
|
|||||||
# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`)
|
# Module kmath-ast
|
||||||
|
|
||||||
This subproject implements the following features:
|
Abstract syntax tree expression representation and related optimizations.
|
||||||
|
|
||||||
- [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
- [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||||
- [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
- [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||||
- [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
- [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||||
- [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
- [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||||
- [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
- [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||||
- [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
- [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||||
|
|
||||||
|
|
||||||
> #### Artifact:
|
## Artifact:
|
||||||
>
|
|
||||||
> This module artifact: `space.kscience:kmath-ast:0.3.0-dev-2`.
|
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-6`.
|
||||||
>
|
|
||||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
|
**Gradle:**
|
||||||
>
|
```gradle
|
||||||
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-ast/_latestVersion)
|
repositories {
|
||||||
>
|
maven { url 'https://repo.kotlin.link' }
|
||||||
> **Gradle:**
|
maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||||
>
|
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||||
> ```gradle
|
}
|
||||||
> repositories {
|
|
||||||
> maven { url 'https://repo.kotlin.link' }
|
dependencies {
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
implementation 'space.kscience:kmath-ast:0.3.0-dev-6'
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
}
|
||||||
> }
|
```
|
||||||
>
|
**Gradle Kotlin DSL:**
|
||||||
> dependencies {
|
```kotlin
|
||||||
> implementation 'space.kscience:kmath-ast:0.3.0-dev-2'
|
repositories {
|
||||||
> }
|
maven("https://repo.kotlin.link")
|
||||||
> ```
|
maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> **Gradle Kotlin DSL:**
|
maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
>
|
}
|
||||||
> ```kotlin
|
|
||||||
> repositories {
|
dependencies {
|
||||||
> maven("https://repo.kotlin.link")
|
implementation("space.kscience:kmath-ast:0.3.0-dev-6")
|
||||||
> 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-ast:0.3.0-dev-2")
|
|
||||||
> }
|
|
||||||
> ```
|
|
||||||
|
|
||||||
## Dynamic expression code generation
|
## Dynamic expression code generation
|
||||||
|
|
||||||
@ -55,7 +49,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
|
|||||||
For example, the following builder:
|
For example, the following builder:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
```
|
```
|
||||||
|
|
||||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||||
@ -88,8 +82,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
|||||||
This API extends MST and MstExpression, so you may optimize as both of them:
|
This API extends MST and MstExpression, so you may optimize as both of them:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
RealField.expression("x+2".parseMath())
|
DoubleField.expression("x+2".parseMath())
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Known issues
|
#### Known issues
|
||||||
@ -103,7 +97,7 @@ RealField.expression("x+2".parseMath())
|
|||||||
A similar feature is also available on JS.
|
A similar feature is also available on JS.
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
```
|
```
|
||||||
|
|
||||||
The code above returns expression implemented with such a JS function:
|
The code above returns expression implemented with such a JS function:
|
||||||
@ -117,3 +111,39 @@ var executable = function (constants, arguments) {
|
|||||||
#### Known issues
|
#### Known issues
|
||||||
|
|
||||||
- This feature uses `eval` which can be unavailable in several environments.
|
- This feature uses `eval` which can be unavailable in several environments.
|
||||||
|
|
||||||
|
## Rendering expressions
|
||||||
|
|
||||||
|
kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
import space.kscience.kmath.ast.*
|
||||||
|
import space.kscience.kmath.ast.rendering.*
|
||||||
|
|
||||||
|
public fun main() {
|
||||||
|
val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
|
||||||
|
val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
|
||||||
|
val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
|
||||||
|
println("LaTeX:")
|
||||||
|
println(latex)
|
||||||
|
println()
|
||||||
|
val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax)
|
||||||
|
println("MathML:")
|
||||||
|
println(mathML)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result LaTeX:
|
||||||
|
|
||||||
|
![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D)
|
||||||
|
|
||||||
|
Result MathML (embedding MathML is not allowed by GitHub Markdown):
|
||||||
|
|
||||||
|
```html
|
||||||
|
<mrow><msup><mrow><mi>e</mi></mrow><mrow><msqrt><mi>x</mi></msqrt></mrow></msup><mo>-</mo><mfrac><mrow><mfrac><mrow><msup><mrow><mo>sin</mo></mrow><mrow><mo>-</mo><mn>1</mn></mrow></msup><mspace width="0.167em"></mspace><mfenced open="(" close=")" separators=""><mn>2</mn><mspace width="0.167em"></mspace><mi>x</mi></mfenced></mrow><mrow><mn>2</mn><mo>×</mo><msup><mrow><mn>10</mn></mrow><mrow><mn>10</mn></mrow></msup><mo>+</mo><msup><mrow><mi>x</mi></mrow><mrow><mn>3</mn></mrow></msup></mrow></mfrac></mrow><mrow><mo>-</mo><mn>12</mn></mrow></mfrac></mrow>
|
||||||
|
```
|
||||||
|
|
||||||
|
It is also possible to create custom algorithms of render, and even add support of other markup languages
|
||||||
|
(see API reference).
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
import ru.mipt.npm.gradle.Maturity
|
import ru.mipt.npm.gradle.Maturity
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.gradle.mpp")
|
kotlin("multiplatform")
|
||||||
|
id("ru.mipt.npm.gradle.common")
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin.js {
|
kotlin.js {
|
||||||
@ -63,36 +64,36 @@ readme {
|
|||||||
feature(
|
feature(
|
||||||
id = "expression-language",
|
id = "expression-language",
|
||||||
description = "Expression language and its parser",
|
description = "Expression language and its parser",
|
||||||
ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt"
|
ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst",
|
id = "mst",
|
||||||
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
|
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst-building",
|
id = "mst-building",
|
||||||
description = "MST building algebraic structure",
|
description = "MST building algebraic structure",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst-interpreter",
|
id = "mst-interpreter",
|
||||||
description = "MST interpreter",
|
description = "MST interpreter",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst-jvm-codegen",
|
id = "mst-jvm-codegen",
|
||||||
description = "Dynamic MST to JVM bytecode compiler",
|
description = "Dynamic MST to JVM bytecode compiler",
|
||||||
ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt"
|
ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "mst-js-codegen",
|
id = "mst-js-codegen",
|
||||||
description = "Dynamic MST to JS compiler",
|
description = "Dynamic MST to JS compiler",
|
||||||
ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt"
|
ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`)
|
# Module kmath-ast
|
||||||
|
|
||||||
This subproject implements the following features:
|
Abstract syntax tree expression representation and related optimizations.
|
||||||
|
|
||||||
${features}
|
${features}
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
|
|||||||
For example, the following builder:
|
For example, the following builder:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
```
|
```
|
||||||
|
|
||||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||||
@ -49,8 +49,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
|||||||
This API extends MST and MstExpression, so you may optimize as both of them:
|
This API extends MST and MstExpression, so you may optimize as both of them:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
RealField.expression("x+2".parseMath())
|
DoubleField.expression("x+2".parseMath())
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Known issues
|
#### Known issues
|
||||||
@ -64,7 +64,7 @@ RealField.expression("x+2".parseMath())
|
|||||||
A similar feature is also available on JS.
|
A similar feature is also available on JS.
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||||
```
|
```
|
||||||
|
|
||||||
The code above returns expression implemented with such a JS function:
|
The code above returns expression implemented with such a JS function:
|
||||||
@ -78,3 +78,39 @@ var executable = function (constants, arguments) {
|
|||||||
#### Known issues
|
#### Known issues
|
||||||
|
|
||||||
- This feature uses `eval` which can be unavailable in several environments.
|
- This feature uses `eval` which can be unavailable in several environments.
|
||||||
|
|
||||||
|
## Rendering expressions
|
||||||
|
|
||||||
|
kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
import space.kscience.kmath.ast.*
|
||||||
|
import space.kscience.kmath.ast.rendering.*
|
||||||
|
|
||||||
|
public fun main() {
|
||||||
|
val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
|
||||||
|
val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
|
||||||
|
val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
|
||||||
|
println("LaTeX:")
|
||||||
|
println(latex)
|
||||||
|
println()
|
||||||
|
val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax)
|
||||||
|
println("MathML:")
|
||||||
|
println(mathML)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result LaTeX:
|
||||||
|
|
||||||
|
![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D)
|
||||||
|
|
||||||
|
Result MathML (embedding MathML is not allowed by GitHub Markdown):
|
||||||
|
|
||||||
|
```html
|
||||||
|
<mrow><msup><mrow><mi>e</mi></mrow><mrow><msqrt><mi>x</mi></msqrt></mrow></msup><mo>-</mo><mfrac><mrow><mfrac><mrow><msup><mrow><mo>sin</mo></mrow><mrow><mo>-</mo><mn>1</mn></mrow></msup><mspace width="0.167em"></mspace><mfenced open="(" close=")" separators=""><mn>2</mn><mspace width="0.167em"></mspace><mi>x</mi></mfenced></mrow><mrow><mn>2</mn><mo>×</mo><msup><mrow><mn>10</mn></mrow><mrow><mn>10</mn></mrow></msup><mo>+</mo><msup><mrow><mi>x</mi></mrow><mrow><mn>3</mn></mrow></msup></mrow></mfrac></mrow><mrow><mo>-</mo><mn>12</mn></mrow></mfrac></mrow>
|
||||||
|
```
|
||||||
|
|
||||||
|
It is also possible to create custom algorithms of render, and even add support of other markup languages
|
||||||
|
(see API reference).
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2018-2021 KMath contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package space.kscience.kmath.ast
|
|
||||||
|
|
||||||
import space.kscience.kmath.expressions.*
|
|
||||||
import space.kscience.kmath.operations.*
|
|
||||||
import kotlin.contracts.InvocationKind
|
|
||||||
import kotlin.contracts.contract
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The expression evaluates MST on-flight. Should be much faster than functional expression, but slower than
|
|
||||||
* ASM-generated expressions.
|
|
||||||
*
|
|
||||||
* @property algebra the algebra that provides operations.
|
|
||||||
* @property mst the [MST] node.
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
public class MstExpression<T, out A : Algebra<T>>(public val algebra: A, public val mst: MST) : Expression<T> {
|
|
||||||
private inner class InnerAlgebra(val arguments: Map<Symbol, T>) : NumericAlgebra<T> {
|
|
||||||
override fun bindSymbol(value: String): T = try {
|
|
||||||
algebra.bindSymbol(value)
|
|
||||||
} catch (ignored: IllegalStateException) {
|
|
||||||
null
|
|
||||||
} ?: arguments.getValue(StringSymbol(value))
|
|
||||||
|
|
||||||
override fun unaryOperation(operation: String, arg: T): T =
|
|
||||||
algebra.unaryOperation(operation, arg)
|
|
||||||
|
|
||||||
override fun binaryOperation(operation: String, left: T, right: T): T =
|
|
||||||
algebra.binaryOperation(operation, left, right)
|
|
||||||
|
|
||||||
override fun unaryOperationFunction(operation: String): (arg: T) -> T =
|
|
||||||
algebra.unaryOperationFunction(operation)
|
|
||||||
|
|
||||||
override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T =
|
|
||||||
algebra.binaryOperationFunction(operation)
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun number(value: Number): T = if (algebra is NumericAlgebra<*>)
|
|
||||||
(algebra as NumericAlgebra<T>).number(value)
|
|
||||||
else
|
|
||||||
error("Numeric nodes are not supported by $this")
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun invoke(arguments: Map<Symbol, T>): T = InnerAlgebra(arguments).evaluate(mst)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds [MstExpression] over [Algebra].
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any, A : Algebra<T>, E : Algebra<MST>> A.mst(
|
|
||||||
mstAlgebra: E,
|
|
||||||
block: E.() -> MST,
|
|
||||||
): MstExpression<T, A> = MstExpression(this, mstAlgebra.block())
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds [MstExpression] over [Group].
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any, A : Group<T>> A.mstInGroup(block: MstGroup.() -> MST): MstExpression<T, A> {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return MstExpression(this, MstGroup.block())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds [MstExpression] over [Ring].
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any, A : Ring<T>> A.mstInRing(block: MstRing.() -> MST): MstExpression<T, A> {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return MstExpression(this, MstRing.block())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds [MstExpression] over [Field].
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any, A : Field<T>> A.mstInField(block: MstField.() -> MST): MstExpression<T, A> {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return MstExpression(this, MstField.block())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds [MstExpression] over [ExtendedField].
|
|
||||||
*
|
|
||||||
* @author Iaroslav Postovalov
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any, A : ExtendedField<T>> A.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression<T, A> {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return MstExpression(this, MstExtendedField.block())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds [MstExpression] over [FunctionalExpressionGroup].
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any, A : Group<T>> FunctionalExpressionGroup<T, A>.mstInGroup(block: MstGroup.() -> MST): MstExpression<T, A> {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return algebra.mstInGroup(block)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds [MstExpression] over [FunctionalExpressionRing].
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any, A : Ring<T>> FunctionalExpressionRing<T, A>.mstInRing(block: MstRing.() -> MST): MstExpression<T, A> {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return algebra.mstInRing(block)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds [MstExpression] over [FunctionalExpressionField].
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any, A : Field<T>> FunctionalExpressionField<T, A>.mstInField(block: MstField.() -> MST): MstExpression<T, A> {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return algebra.mstInField(block)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds [MstExpression] over [FunctionalExpressionExtendedField].
|
|
||||||
*
|
|
||||||
* @author Iaroslav Postovalov
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any, A : ExtendedField<T>> FunctionalExpressionExtendedField<T, A>.mstInExtendedField(
|
|
||||||
block: MstExtendedField.() -> MST,
|
|
||||||
): MstExpression<T, A> {
|
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return algebra.mstInExtendedField(block)
|
|
||||||
}
|
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [SyntaxRenderer] implementation for LaTeX.
|
||||||
|
*
|
||||||
|
* The generated string is a valid LaTeX fragment to be used in the Math Mode.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* \documentclass{article}
|
||||||
|
* \begin{document}
|
||||||
|
* \begin{equation}
|
||||||
|
* %code generated by the syntax renderer
|
||||||
|
* \end{equation}
|
||||||
|
* \end{document}
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public object LatexSyntaxRenderer : SyntaxRenderer {
|
||||||
|
public override fun render(node: MathSyntax, output: Appendable): Unit = output.run {
|
||||||
|
fun render(syntax: MathSyntax) = render(syntax, output)
|
||||||
|
|
||||||
|
when (node) {
|
||||||
|
is NumberSyntax -> append(node.string)
|
||||||
|
is SymbolSyntax -> append(node.string)
|
||||||
|
|
||||||
|
is OperatorNameSyntax -> {
|
||||||
|
append("\\operatorname{")
|
||||||
|
append(node.name)
|
||||||
|
append('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
is SpecialSymbolSyntax -> when (node.kind) {
|
||||||
|
SpecialSymbolSyntax.Kind.INFINITY -> append("\\infty")
|
||||||
|
SpecialSymbolSyntax.Kind.SMALL_PI -> append("\\pi")
|
||||||
|
}
|
||||||
|
|
||||||
|
is OperandSyntax -> {
|
||||||
|
if (node.parentheses) append("\\left(")
|
||||||
|
render(node.operand)
|
||||||
|
if (node.parentheses) append("\\right)")
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnaryOperatorSyntax -> {
|
||||||
|
render(node.prefix)
|
||||||
|
append("\\,")
|
||||||
|
render(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnaryPlusSyntax -> {
|
||||||
|
append('+')
|
||||||
|
render(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnaryMinusSyntax -> {
|
||||||
|
append('-')
|
||||||
|
render(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is RadicalSyntax -> {
|
||||||
|
append("\\sqrt")
|
||||||
|
append('{')
|
||||||
|
render(node.operand)
|
||||||
|
append('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
is SuperscriptSyntax -> {
|
||||||
|
render(node.left)
|
||||||
|
append("^{")
|
||||||
|
render(node.right)
|
||||||
|
append('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
is SubscriptSyntax -> {
|
||||||
|
render(node.left)
|
||||||
|
append("_{")
|
||||||
|
render(node.right)
|
||||||
|
append('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryOperatorSyntax -> {
|
||||||
|
render(node.prefix)
|
||||||
|
append("\\left(")
|
||||||
|
render(node.left)
|
||||||
|
append(',')
|
||||||
|
render(node.right)
|
||||||
|
append("\\right)")
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryPlusSyntax -> {
|
||||||
|
render(node.left)
|
||||||
|
append('+')
|
||||||
|
render(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryMinusSyntax -> {
|
||||||
|
render(node.left)
|
||||||
|
append('-')
|
||||||
|
render(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is FractionSyntax -> {
|
||||||
|
append("\\frac{")
|
||||||
|
render(node.left)
|
||||||
|
append("}{")
|
||||||
|
render(node.right)
|
||||||
|
append('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
is RadicalWithIndexSyntax -> {
|
||||||
|
append("\\sqrt")
|
||||||
|
append('[')
|
||||||
|
render(node.left)
|
||||||
|
append(']')
|
||||||
|
append('{')
|
||||||
|
render(node.right)
|
||||||
|
append('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
is MultiplicationSyntax -> {
|
||||||
|
render(node.left)
|
||||||
|
append(if (node.times) "\\times" else "\\,")
|
||||||
|
render(node.right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [SyntaxRenderer] implementation for MathML.
|
||||||
|
*
|
||||||
|
* The generated XML string is a valid MathML instance.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public object MathMLSyntaxRenderer : SyntaxRenderer {
|
||||||
|
public override fun render(node: MathSyntax, output: Appendable) {
|
||||||
|
output.append("<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mrow>")
|
||||||
|
render0(node, output)
|
||||||
|
output.append("</mrow></math>")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun render0(node: MathSyntax, output: Appendable): Unit = output.run {
|
||||||
|
fun tag(tagName: String, vararg attr: Pair<String, String>, block: () -> Unit = {}) {
|
||||||
|
append('<')
|
||||||
|
append(tagName)
|
||||||
|
|
||||||
|
if (attr.isNotEmpty()) {
|
||||||
|
append(' ')
|
||||||
|
var count = 0
|
||||||
|
|
||||||
|
for ((name, value) in attr) {
|
||||||
|
if (++count > 1) append(' ')
|
||||||
|
append(name)
|
||||||
|
append("=\"")
|
||||||
|
append(value)
|
||||||
|
append('"')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
append('>')
|
||||||
|
block()
|
||||||
|
append("</")
|
||||||
|
append(tagName)
|
||||||
|
append('>')
|
||||||
|
}
|
||||||
|
|
||||||
|
fun render(syntax: MathSyntax) = render0(syntax, output)
|
||||||
|
|
||||||
|
when (node) {
|
||||||
|
is NumberSyntax -> tag("mn") { append(node.string) }
|
||||||
|
is SymbolSyntax -> tag("mi") { append(node.string) }
|
||||||
|
is OperatorNameSyntax -> tag("mo") { append(node.name) }
|
||||||
|
|
||||||
|
is SpecialSymbolSyntax -> when (node.kind) {
|
||||||
|
SpecialSymbolSyntax.Kind.INFINITY -> tag("mo") { append("∞") }
|
||||||
|
SpecialSymbolSyntax.Kind.SMALL_PI -> tag("mo") { append("π") }
|
||||||
|
}
|
||||||
|
|
||||||
|
is OperandSyntax -> if (node.parentheses) {
|
||||||
|
tag("mfenced", "open" to "(", "close" to ")", "separators" to "") {
|
||||||
|
render(node.operand)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
render(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnaryOperatorSyntax -> {
|
||||||
|
render(node.prefix)
|
||||||
|
tag("mspace", "width" to "0.167em")
|
||||||
|
render(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnaryPlusSyntax -> {
|
||||||
|
tag("mo") { append('+') }
|
||||||
|
render(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnaryMinusSyntax -> {
|
||||||
|
tag("mo") { append("-") }
|
||||||
|
render(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is RadicalSyntax -> tag("msqrt") { render(node.operand) }
|
||||||
|
|
||||||
|
is SuperscriptSyntax -> tag("msup") {
|
||||||
|
tag("mrow") { render(node.left) }
|
||||||
|
tag("mrow") { render(node.right) }
|
||||||
|
}
|
||||||
|
|
||||||
|
is SubscriptSyntax -> tag("msub") {
|
||||||
|
tag("mrow") { render(node.left) }
|
||||||
|
tag("mrow") { render(node.right) }
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryOperatorSyntax -> {
|
||||||
|
render(node.prefix)
|
||||||
|
|
||||||
|
tag("mfenced", "open" to "(", "close" to ")", "separators" to "") {
|
||||||
|
render(node.left)
|
||||||
|
tag("mo") { append(',') }
|
||||||
|
render(node.right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryPlusSyntax -> {
|
||||||
|
render(node.left)
|
||||||
|
tag("mo") { append('+') }
|
||||||
|
render(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryMinusSyntax -> {
|
||||||
|
render(node.left)
|
||||||
|
tag("mo") { append('-') }
|
||||||
|
render(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is FractionSyntax -> tag("mfrac") {
|
||||||
|
tag("mrow") {
|
||||||
|
render(node.left)
|
||||||
|
}
|
||||||
|
|
||||||
|
tag("mrow") {
|
||||||
|
render(node.right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is RadicalWithIndexSyntax -> tag("mroot") {
|
||||||
|
tag("mrow") { render(node.right) }
|
||||||
|
tag("mrow") { render(node.left) }
|
||||||
|
}
|
||||||
|
|
||||||
|
is MultiplicationSyntax -> {
|
||||||
|
render(node.left)
|
||||||
|
if (node.times) tag("mo") { append("×") } else tag("mspace", "width" to "0.167em")
|
||||||
|
render(node.right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders [MST] to [MathSyntax].
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public fun interface MathRenderer {
|
||||||
|
/**
|
||||||
|
* Renders [MST] to [MathSyntax].
|
||||||
|
*/
|
||||||
|
public fun render(mst: MST): MathSyntax
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements [MST] render process with sequence of features.
|
||||||
|
*
|
||||||
|
* @property features The applied features.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public open class FeaturedMathRenderer(public val features: List<RenderFeature>) : MathRenderer {
|
||||||
|
public override fun render(mst: MST): MathSyntax {
|
||||||
|
for (feature in features) feature.render(this, mst)?.let { return it }
|
||||||
|
throw UnsupportedOperationException("Renderer $this has no appropriate feature to render node $mst.")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logical unit of [MST] rendering.
|
||||||
|
*/
|
||||||
|
public fun interface RenderFeature {
|
||||||
|
/**
|
||||||
|
* Renders [MST] to [MathSyntax] in the context of owning renderer.
|
||||||
|
*/
|
||||||
|
public fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends [FeaturedMathRenderer] by adding post-processing stages.
|
||||||
|
*
|
||||||
|
* @property stages The applied stages.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public open class FeaturedMathRendererWithPostProcess(
|
||||||
|
features: List<RenderFeature>,
|
||||||
|
public val stages: List<PostProcessStage>,
|
||||||
|
) : FeaturedMathRenderer(features) {
|
||||||
|
public override fun render(mst: MST): MathSyntax {
|
||||||
|
val res = super.render(mst)
|
||||||
|
for (stage in stages) stage.perform(res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logical unit of [MathSyntax] post-processing.
|
||||||
|
*/
|
||||||
|
public fun interface PostProcessStage {
|
||||||
|
/**
|
||||||
|
* Performs the specified action over [MathSyntax].
|
||||||
|
*/
|
||||||
|
public fun perform(node: MathSyntax)
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
/**
|
||||||
|
* The default setup of [FeaturedMathRendererWithPostProcess].
|
||||||
|
*/
|
||||||
|
public val Default: FeaturedMathRendererWithPostProcess = FeaturedMathRendererWithPostProcess(
|
||||||
|
listOf(
|
||||||
|
// Printing known operations
|
||||||
|
BinaryPlus.Default,
|
||||||
|
BinaryMinus.Default,
|
||||||
|
UnaryPlus.Default,
|
||||||
|
UnaryMinus.Default,
|
||||||
|
Multiplication.Default,
|
||||||
|
Fraction.Default,
|
||||||
|
Power.Default,
|
||||||
|
SquareRoot.Default,
|
||||||
|
Exponential.Default,
|
||||||
|
InverseTrigonometricOperations.Default,
|
||||||
|
|
||||||
|
// Fallback option for unknown operations - printing them as operator
|
||||||
|
BinaryOperator.Default,
|
||||||
|
UnaryOperator.Default,
|
||||||
|
|
||||||
|
// Pretty printing for some objects
|
||||||
|
PrettyPrintFloats.Default,
|
||||||
|
PrettyPrintIntegers.Default,
|
||||||
|
PrettyPrintPi.Default,
|
||||||
|
|
||||||
|
// Printing terminal nodes as string
|
||||||
|
PrintNumeric,
|
||||||
|
PrintSymbolic,
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
SimplifyParentheses.Default,
|
||||||
|
BetterMultiplication,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,336 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mathematical typography syntax node.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public sealed class MathSyntax {
|
||||||
|
/**
|
||||||
|
* The parent node of this syntax node.
|
||||||
|
*/
|
||||||
|
public var parent: MathSyntax? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminal node, which should not have any children nodes.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public sealed class TerminalSyntax : MathSyntax()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node containing a certain operation.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public sealed class OperationSyntax : MathSyntax() {
|
||||||
|
/**
|
||||||
|
* The operation token.
|
||||||
|
*/
|
||||||
|
public abstract val operation: String
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unary node, which has only one child.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public sealed class UnarySyntax : OperationSyntax() {
|
||||||
|
/**
|
||||||
|
* The operand of this node.
|
||||||
|
*/
|
||||||
|
public abstract val operand: MathSyntax
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binary node, which has only two children.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public sealed class BinarySyntax : OperationSyntax() {
|
||||||
|
/**
|
||||||
|
* The left-hand side operand.
|
||||||
|
*/
|
||||||
|
public abstract val left: MathSyntax
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The right-hand side operand.
|
||||||
|
*/
|
||||||
|
public abstract val right: MathSyntax
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a number.
|
||||||
|
*
|
||||||
|
* @property string The digits of number.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class NumberSyntax(public var string: String) : TerminalSyntax()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a symbol.
|
||||||
|
*
|
||||||
|
* @property string The symbol.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class SymbolSyntax(public var string: String) : TerminalSyntax()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents special typing for operator name.
|
||||||
|
*
|
||||||
|
* @property name The operator name.
|
||||||
|
* @see BinaryOperatorSyntax
|
||||||
|
* @see UnaryOperatorSyntax
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class OperatorNameSyntax(public var name: String) : TerminalSyntax()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a usage of special symbols.
|
||||||
|
*
|
||||||
|
* @property kind The kind of symbol.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class SpecialSymbolSyntax(public var kind: Kind) : TerminalSyntax() {
|
||||||
|
/**
|
||||||
|
* The kind of symbol.
|
||||||
|
*/
|
||||||
|
public enum class Kind {
|
||||||
|
/**
|
||||||
|
* The infinity (∞) symbol.
|
||||||
|
*/
|
||||||
|
INFINITY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Pi (π) symbol.
|
||||||
|
*/
|
||||||
|
SMALL_PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents operand of a certain operator wrapped with parentheses or not.
|
||||||
|
*
|
||||||
|
* @property operand The operand.
|
||||||
|
* @property parentheses Whether the operand should be wrapped with parentheses.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class OperandSyntax(
|
||||||
|
public val operand: MathSyntax,
|
||||||
|
public var parentheses: Boolean,
|
||||||
|
) : MathSyntax() {
|
||||||
|
init {
|
||||||
|
operand.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents unary, prefix operator syntax (like f x).
|
||||||
|
*
|
||||||
|
* @property prefix The prefix.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class UnaryOperatorSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public var prefix: MathSyntax,
|
||||||
|
public override val operand: OperandSyntax,
|
||||||
|
) : UnarySyntax() {
|
||||||
|
init {
|
||||||
|
operand.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents prefix, unary plus operator.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class UnaryPlusSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val operand: OperandSyntax,
|
||||||
|
) : UnarySyntax() {
|
||||||
|
init {
|
||||||
|
operand.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents prefix, unary minus operator.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class UnaryMinusSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val operand: OperandSyntax,
|
||||||
|
) : UnarySyntax() {
|
||||||
|
init {
|
||||||
|
operand.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents radical with a node inside it.
|
||||||
|
*
|
||||||
|
* @property operand The radicand.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class RadicalSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val operand: MathSyntax,
|
||||||
|
) : UnarySyntax() {
|
||||||
|
init {
|
||||||
|
operand.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a syntax node with superscript (usually, for exponentiation).
|
||||||
|
*
|
||||||
|
* @property left The node.
|
||||||
|
* @property right The superscript.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class SuperscriptSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val left: MathSyntax,
|
||||||
|
public override val right: MathSyntax,
|
||||||
|
) : BinarySyntax() {
|
||||||
|
init {
|
||||||
|
left.parent = this
|
||||||
|
right.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a syntax node with subscript.
|
||||||
|
*
|
||||||
|
* @property left The node.
|
||||||
|
* @property right The subscript.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class SubscriptSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val left: MathSyntax,
|
||||||
|
public override val right: MathSyntax,
|
||||||
|
) : BinarySyntax() {
|
||||||
|
init {
|
||||||
|
left.parent = this
|
||||||
|
right.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents binary, prefix operator syntax (like f(a, b)).
|
||||||
|
*
|
||||||
|
* @property prefix The prefix.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class BinaryOperatorSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public var prefix: MathSyntax,
|
||||||
|
public override val left: MathSyntax,
|
||||||
|
public override val right: MathSyntax,
|
||||||
|
) : BinarySyntax() {
|
||||||
|
init {
|
||||||
|
left.parent = this
|
||||||
|
right.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents binary, infix addition.
|
||||||
|
*
|
||||||
|
* @param left The augend.
|
||||||
|
* @param right The addend.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class BinaryPlusSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val left: OperandSyntax,
|
||||||
|
public override val right: OperandSyntax,
|
||||||
|
) : BinarySyntax() {
|
||||||
|
init {
|
||||||
|
left.parent = this
|
||||||
|
right.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents binary, infix subtraction.
|
||||||
|
*
|
||||||
|
* @param left The minuend.
|
||||||
|
* @param right The subtrahend.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class BinaryMinusSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val left: OperandSyntax,
|
||||||
|
public override val right: OperandSyntax,
|
||||||
|
) : BinarySyntax() {
|
||||||
|
init {
|
||||||
|
left.parent = this
|
||||||
|
right.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents fraction with numerator and denominator.
|
||||||
|
*
|
||||||
|
* @property left The numerator.
|
||||||
|
* @property right The denominator.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class FractionSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val left: MathSyntax,
|
||||||
|
public override val right: MathSyntax,
|
||||||
|
) : BinarySyntax() {
|
||||||
|
init {
|
||||||
|
left.parent = this
|
||||||
|
right.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents radical syntax with index.
|
||||||
|
*
|
||||||
|
* @property left The index.
|
||||||
|
* @property right The radicand.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class RadicalWithIndexSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val left: MathSyntax,
|
||||||
|
public override val right: MathSyntax,
|
||||||
|
) : BinarySyntax() {
|
||||||
|
init {
|
||||||
|
left.parent = this
|
||||||
|
right.parent = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents binary, infix multiplication in the form of coefficient (2 x) or with operator (x×2).
|
||||||
|
*
|
||||||
|
* @property left The multiplicand.
|
||||||
|
* @property right The multiplier.
|
||||||
|
* @property times whether the times (×) symbol should be used.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public data class MultiplicationSyntax(
|
||||||
|
public override val operation: String,
|
||||||
|
public override val left: OperandSyntax,
|
||||||
|
public override val right: OperandSyntax,
|
||||||
|
public var times: Boolean,
|
||||||
|
) : BinarySyntax() {
|
||||||
|
init {
|
||||||
|
left.parent = this
|
||||||
|
right.parent = this
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstraction of writing [MathSyntax] as a string of an actual markup language. Typical implementation should
|
||||||
|
* involve traversal of MathSyntax with handling each its subtype.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public fun interface SyntaxRenderer {
|
||||||
|
/**
|
||||||
|
* Renders the [MathSyntax] to [output].
|
||||||
|
*/
|
||||||
|
public fun render(node: MathSyntax, output: Appendable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls [SyntaxRenderer.render] with given [node] and a new [StringBuilder] instance, and returns its content.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public fun SyntaxRenderer.renderWithStringBuilder(node: MathSyntax): String {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
render(node, sb)
|
||||||
|
return sb.toString()
|
||||||
|
}
|
@ -0,0 +1,336 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
import space.kscience.kmath.ast.rendering.FeaturedMathRenderer.RenderFeature
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
|
import space.kscience.kmath.operations.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints any [MST.Symbolic] as a [SymbolSyntax] containing the [MST.Symbolic.value] of it.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public object PrintSymbolic : RenderFeature {
|
||||||
|
public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
|
||||||
|
if (node !is MST.Symbolic) return null
|
||||||
|
return SymbolSyntax(string = node.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints any [MST.Numeric] as a [NumberSyntax] containing the [Any.toString] result of it.
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public object PrintNumeric : RenderFeature {
|
||||||
|
public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
|
||||||
|
if (node !is MST.Numeric) return null
|
||||||
|
return NumberSyntax(string = node.value.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printSignedNumberString(s: String): MathSyntax {
|
||||||
|
if (s.startsWith('-'))
|
||||||
|
return UnaryMinusSyntax(
|
||||||
|
operation = GroupOperations.MINUS_OPERATION,
|
||||||
|
operand = OperandSyntax(
|
||||||
|
operand = NumberSyntax(string = s.removePrefix("-")),
|
||||||
|
parentheses = true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return NumberSyntax(string = s)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special printing for numeric types which are printed in form of
|
||||||
|
* *('-'? (DIGIT+ ('.' DIGIT+)? ('E' '-'? DIGIT+)? | 'Infinity')) | 'NaN'*.
|
||||||
|
*
|
||||||
|
* @property types The suitable types.
|
||||||
|
*/
|
||||||
|
public class PrettyPrintFloats(public val types: Set<KClass<out Number>>) : RenderFeature {
|
||||||
|
public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
|
||||||
|
if (node !is MST.Numeric || node.value::class !in types) return null
|
||||||
|
val toString = node.value.toString().removeSuffix(".0")
|
||||||
|
|
||||||
|
if ('E' in toString) {
|
||||||
|
val (beforeE, afterE) = toString.split('E')
|
||||||
|
val significand = beforeE.toDouble().toString().removeSuffix(".0")
|
||||||
|
val exponent = afterE.toDouble().toString().removeSuffix(".0")
|
||||||
|
|
||||||
|
return MultiplicationSyntax(
|
||||||
|
operation = RingOperations.TIMES_OPERATION,
|
||||||
|
left = OperandSyntax(operand = NumberSyntax(significand), parentheses = true),
|
||||||
|
right = OperandSyntax(
|
||||||
|
operand = SuperscriptSyntax(
|
||||||
|
operation = PowerOperations.POW_OPERATION,
|
||||||
|
left = NumberSyntax(string = "10"),
|
||||||
|
right = printSignedNumberString(exponent),
|
||||||
|
),
|
||||||
|
parentheses = true,
|
||||||
|
),
|
||||||
|
times = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toString.endsWith("Infinity")) {
|
||||||
|
val infty = SpecialSymbolSyntax(SpecialSymbolSyntax.Kind.INFINITY)
|
||||||
|
|
||||||
|
if (toString.startsWith('-'))
|
||||||
|
return UnaryMinusSyntax(
|
||||||
|
operation = GroupOperations.MINUS_OPERATION,
|
||||||
|
operand = OperandSyntax(operand = infty, parentheses = true),
|
||||||
|
)
|
||||||
|
|
||||||
|
return infty
|
||||||
|
}
|
||||||
|
|
||||||
|
return printSignedNumberString(toString)
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
/**
|
||||||
|
* The default instance containing [Float], and [Double].
|
||||||
|
*/
|
||||||
|
public val Default: PrettyPrintFloats = PrettyPrintFloats(setOf(Float::class, Double::class))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special printing for numeric types which are printed in form of *'-'? DIGIT+*.
|
||||||
|
*
|
||||||
|
* @property types The suitable types.
|
||||||
|
*/
|
||||||
|
public class PrettyPrintIntegers(public val types: Set<KClass<out Number>>) : RenderFeature {
|
||||||
|
public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
|
||||||
|
if (node !is MST.Numeric || node.value::class !in types)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return printSignedNumberString(node.value.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
/**
|
||||||
|
* The default instance containing [Byte], [Short], [Int], and [Long].
|
||||||
|
*/
|
||||||
|
public val Default: PrettyPrintIntegers =
|
||||||
|
PrettyPrintIntegers(setOf(Byte::class, Short::class, Int::class, Long::class))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special printing for symbols meaning Pi.
|
||||||
|
*
|
||||||
|
* @property symbols The allowed symbols.
|
||||||
|
*/
|
||||||
|
public class PrettyPrintPi(public val symbols: Set<String>) : RenderFeature {
|
||||||
|
public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
|
||||||
|
if (node !is MST.Symbolic || node.value !in symbols) return null
|
||||||
|
return SpecialSymbolSyntax(kind = SpecialSymbolSyntax.Kind.SMALL_PI)
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
/**
|
||||||
|
* The default instance containing `pi`.
|
||||||
|
*/
|
||||||
|
public val Default: PrettyPrintPi = PrettyPrintPi(setOf("pi"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is
|
||||||
|
* not [MST.Unary].
|
||||||
|
*
|
||||||
|
* @param operations the allowed operations. If `null`, any operation is accepted.
|
||||||
|
*/
|
||||||
|
public abstract class Unary(public val operations: Collection<String>?) : RenderFeature {
|
||||||
|
/**
|
||||||
|
* The actual render function.
|
||||||
|
*/
|
||||||
|
protected abstract fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax?
|
||||||
|
|
||||||
|
public final override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
|
||||||
|
if (node !is MST.Unary || operations != null && node.operation !in operations) return null
|
||||||
|
return render0(renderer, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is
|
||||||
|
* not [MST.Binary].
|
||||||
|
*
|
||||||
|
* @property operations the allowed operations. If `null`, any operation is accepted.
|
||||||
|
*/
|
||||||
|
public abstract class Binary(public val operations: Collection<String>?) : RenderFeature {
|
||||||
|
/**
|
||||||
|
* The actual render function.
|
||||||
|
*/
|
||||||
|
protected abstract fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax?
|
||||||
|
|
||||||
|
public final override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
|
||||||
|
if (node !is MST.Binary || operations != null && node.operation !in operations) return null
|
||||||
|
return render0(renderer, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BinaryPlus(operations: Collection<String>?) : Binary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryPlusSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
left = OperandSyntax(parent.render(node.left), true),
|
||||||
|
right = OperandSyntax(parent.render(node.right), true),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: BinaryPlus = BinaryPlus(setOf(GroupOperations.PLUS_OPERATION))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BinaryMinus(operations: Collection<String>?) : Binary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryMinusSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
left = OperandSyntax(operand = parent.render(node.left), parentheses = true),
|
||||||
|
right = OperandSyntax(operand = parent.render(node.right), parentheses = true),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: BinaryMinus = BinaryMinus(setOf(GroupOperations.MINUS_OPERATION))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UnaryPlus(operations: Collection<String>?) : Unary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryPlusSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
operand = OperandSyntax(operand = parent.render(node.value), parentheses = true),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: UnaryPlus = UnaryPlus(setOf(GroupOperations.PLUS_OPERATION))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UnaryMinus(operations: Collection<String>?) : Unary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryMinusSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
operand = OperandSyntax(operand = parent.render(node.value), parentheses = true),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: UnaryMinus = UnaryMinus(setOf(GroupOperations.MINUS_OPERATION))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Fraction(operations: Collection<String>?) : Binary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = FractionSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
left = parent.render(node.left),
|
||||||
|
right = parent.render(node.right),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: Fraction = Fraction(setOf(FieldOperations.DIV_OPERATION))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BinaryOperator(operations: Collection<String>?) : Binary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryOperatorSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
prefix = OperatorNameSyntax(name = node.operation),
|
||||||
|
left = parent.render(node.left),
|
||||||
|
right = parent.render(node.right),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: BinaryOperator = BinaryOperator(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UnaryOperator(operations: Collection<String>?) : Unary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
prefix = OperatorNameSyntax(node.operation),
|
||||||
|
operand = OperandSyntax(parent.render(node.value), true),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: UnaryOperator = UnaryOperator(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Power(operations: Collection<String>?) : Binary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = SuperscriptSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
left = OperandSyntax(parent.render(node.left), true),
|
||||||
|
right = OperandSyntax(parent.render(node.right), true),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: Power = Power(setOf(PowerOperations.POW_OPERATION))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SquareRoot(operations: Collection<String>?) : Unary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax =
|
||||||
|
RadicalSyntax(operation = node.operation, operand = parent.render(node.value))
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: SquareRoot = SquareRoot(setOf(PowerOperations.SQRT_OPERATION))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Exponential(operations: Collection<String>?) : Unary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = SuperscriptSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
left = SymbolSyntax(string = "e"),
|
||||||
|
right = parent.render(node.value),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: Exponential = Exponential(setOf(ExponentialOperations.EXP_OPERATION))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Multiplication(operations: Collection<String>?) : Binary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = MultiplicationSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
left = OperandSyntax(operand = parent.render(node.left), parentheses = true),
|
||||||
|
right = OperandSyntax(operand = parent.render(node.right), parentheses = true),
|
||||||
|
times = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: Multiplication = Multiplication(setOf(
|
||||||
|
RingOperations.TIMES_OPERATION,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InverseTrigonometricOperations(operations: Collection<String>?) : Unary(operations) {
|
||||||
|
public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax(
|
||||||
|
operation = node.operation,
|
||||||
|
prefix = SuperscriptSyntax(
|
||||||
|
operation = PowerOperations.POW_OPERATION,
|
||||||
|
left = OperatorNameSyntax(name = node.operation.removePrefix("a")),
|
||||||
|
right = UnaryMinusSyntax(
|
||||||
|
operation = GroupOperations.MINUS_OPERATION,
|
||||||
|
operand = OperandSyntax(operand = NumberSyntax(string = "1"), parentheses = true),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
operand = OperandSyntax(operand = parent.render(node.value), parentheses = true),
|
||||||
|
)
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
public val Default: InverseTrigonometricOperations = InverseTrigonometricOperations(setOf(
|
||||||
|
TrigonometricOperations.ACOS_OPERATION,
|
||||||
|
TrigonometricOperations.ASIN_OPERATION,
|
||||||
|
TrigonometricOperations.ATAN_OPERATION,
|
||||||
|
ExponentialOperations.ACOSH_OPERATION,
|
||||||
|
ExponentialOperations.ASINH_OPERATION,
|
||||||
|
ExponentialOperations.ATANH_OPERATION,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.FieldOperations
|
||||||
|
import space.kscience.kmath.operations.GroupOperations
|
||||||
|
import space.kscience.kmath.operations.PowerOperations
|
||||||
|
import space.kscience.kmath.operations.RingOperations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes unnecessary times (×) symbols from [MultiplicationSyntax].
|
||||||
|
*
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostProcessStage {
|
||||||
|
public override fun perform(node: MathSyntax) {
|
||||||
|
when (node) {
|
||||||
|
is NumberSyntax -> Unit
|
||||||
|
is SymbolSyntax -> Unit
|
||||||
|
is OperatorNameSyntax -> Unit
|
||||||
|
is SpecialSymbolSyntax -> Unit
|
||||||
|
is OperandSyntax -> perform(node.operand)
|
||||||
|
|
||||||
|
is UnaryOperatorSyntax -> {
|
||||||
|
perform(node.prefix)
|
||||||
|
perform(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnaryPlusSyntax -> perform(node.operand)
|
||||||
|
is UnaryMinusSyntax -> perform(node.operand)
|
||||||
|
is RadicalSyntax -> perform(node.operand)
|
||||||
|
|
||||||
|
is SuperscriptSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is SubscriptSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryOperatorSyntax -> {
|
||||||
|
perform(node.prefix)
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryPlusSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryMinusSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is FractionSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is RadicalWithIndexSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is MultiplicationSyntax -> {
|
||||||
|
node.times = node.right.operand is NumberSyntax && !node.right.parentheses
|
||||||
|
|| node.left.operand is NumberSyntax && node.right.operand is FractionSyntax
|
||||||
|
|| node.left.operand is NumberSyntax && node.right.operand is NumberSyntax
|
||||||
|
|| node.left.operand is NumberSyntax && node.right.operand is SuperscriptSyntax && node.right.operand.left is NumberSyntax
|
||||||
|
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes unnecessary parentheses from [OperandSyntax].
|
||||||
|
*
|
||||||
|
* @property precedenceFunction Returns the precedence number for syntax node. Higher number is lower priority.
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
|
*/
|
||||||
|
public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) :
|
||||||
|
FeaturedMathRendererWithPostProcess.PostProcessStage {
|
||||||
|
public override fun perform(node: MathSyntax) {
|
||||||
|
when (node) {
|
||||||
|
is NumberSyntax -> Unit
|
||||||
|
is SymbolSyntax -> Unit
|
||||||
|
is OperatorNameSyntax -> Unit
|
||||||
|
is SpecialSymbolSyntax -> Unit
|
||||||
|
|
||||||
|
is OperandSyntax -> {
|
||||||
|
val isRightOfSuperscript =
|
||||||
|
(node.parent is SuperscriptSyntax) && (node.parent as SuperscriptSyntax).right === node
|
||||||
|
|
||||||
|
val precedence = precedenceFunction(node.operand)
|
||||||
|
|
||||||
|
val needParenthesesByPrecedence = when (val parent = node.parent) {
|
||||||
|
null -> false
|
||||||
|
|
||||||
|
is BinarySyntax -> {
|
||||||
|
val parentPrecedence = precedenceFunction(parent)
|
||||||
|
|
||||||
|
parentPrecedence < precedence ||
|
||||||
|
parentPrecedence == precedence && parentPrecedence != 0 && node === parent.right
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> precedence > precedenceFunction(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
node.parentheses = !isRightOfSuperscript
|
||||||
|
&& (needParenthesesByPrecedence || node.parent is UnaryOperatorSyntax)
|
||||||
|
|
||||||
|
perform(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnaryOperatorSyntax -> {
|
||||||
|
perform(node.prefix)
|
||||||
|
perform(node.operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UnaryPlusSyntax -> perform(node.operand)
|
||||||
|
is UnaryMinusSyntax -> {
|
||||||
|
perform(node.operand)
|
||||||
|
}
|
||||||
|
is RadicalSyntax -> perform(node.operand)
|
||||||
|
|
||||||
|
is SuperscriptSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is SubscriptSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryOperatorSyntax -> {
|
||||||
|
perform(node.prefix)
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryPlusSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is BinaryMinusSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is FractionSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is MultiplicationSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
|
||||||
|
is RadicalWithIndexSyntax -> {
|
||||||
|
perform(node.left)
|
||||||
|
perform(node.right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
/**
|
||||||
|
* The default configuration of [SimplifyParentheses] where power is 1, multiplicative operations are 2,
|
||||||
|
* additive operations are 3.
|
||||||
|
*/
|
||||||
|
public val Default: SimplifyParentheses = SimplifyParentheses {
|
||||||
|
when (it) {
|
||||||
|
is TerminalSyntax -> 0
|
||||||
|
is UnarySyntax -> 2
|
||||||
|
|
||||||
|
is BinarySyntax -> when (it.operation) {
|
||||||
|
PowerOperations.POW_OPERATION -> 1
|
||||||
|
RingOperations.TIMES_OPERATION -> 3
|
||||||
|
FieldOperations.DIV_OPERATION -> 3
|
||||||
|
GroupOperations.MINUS_OPERATION -> 4
|
||||||
|
GroupOperations.PLUS_OPERATION -> 4
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscisnce.kmath.ast
|
||||||
|
|
||||||
|
import space.kscience.kmath.expressions.MstField
|
||||||
|
import space.kscience.kmath.expressions.invoke
|
||||||
|
import space.kscience.kmath.expressions.toExpression
|
||||||
|
import space.kscience.kmath.misc.Symbol.Companion.x
|
||||||
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.bindSymbol
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
class InterpretTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun interpretation(){
|
||||||
|
val expr = MstField {
|
||||||
|
val x = bindSymbol(x)
|
||||||
|
x * 2.0 + number(2.0) / x - 16.0
|
||||||
|
}.toExpression(DoubleField)
|
||||||
|
expr(x to 2.2)
|
||||||
|
}
|
||||||
|
}
|
@ -5,12 +5,13 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import space.kscience.kmath.ast.MST
|
|
||||||
import space.kscience.kmath.ast.MST.*
|
|
||||||
import space.kscience.kmath.ast.MstExpression
|
|
||||||
import space.kscience.kmath.estree.internal.ESTreeBuilder
|
import space.kscience.kmath.estree.internal.ESTreeBuilder
|
||||||
import space.kscience.kmath.estree.internal.estree.BaseExpression
|
import space.kscience.kmath.estree.internal.estree.BaseExpression
|
||||||
import space.kscience.kmath.expressions.Expression
|
import space.kscience.kmath.expressions.Expression
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
|
import space.kscience.kmath.expressions.MST.*
|
||||||
|
import space.kscience.kmath.expressions.invoke
|
||||||
|
import space.kscience.kmath.misc.Symbol
|
||||||
import space.kscience.kmath.operations.Algebra
|
import space.kscience.kmath.operations.Algebra
|
||||||
import space.kscience.kmath.operations.NumericAlgebra
|
import space.kscience.kmath.operations.NumericAlgebra
|
||||||
|
|
||||||
@ -18,11 +19,7 @@ import space.kscience.kmath.operations.NumericAlgebra
|
|||||||
internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
|
internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
|
||||||
fun ESTreeBuilder<T>.visit(node: MST): BaseExpression = when (node) {
|
fun ESTreeBuilder<T>.visit(node: MST): BaseExpression = when (node) {
|
||||||
is Symbolic -> {
|
is Symbolic -> {
|
||||||
val symbol = try {
|
val symbol = algebra.bindSymbolOrNull(node.value)
|
||||||
algebra.bindSymbol(node.value)
|
|
||||||
} catch (ignored: IllegalStateException) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (symbol != null)
|
if (symbol != null)
|
||||||
constant(symbol)
|
constant(symbol)
|
||||||
@ -34,16 +31,17 @@ internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
|
|||||||
|
|
||||||
is Unary -> when {
|
is Unary -> when {
|
||||||
algebra is NumericAlgebra && node.value is Numeric -> constant(
|
algebra is NumericAlgebra && node.value is Numeric -> constant(
|
||||||
algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value)))
|
algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
|
||||||
|
|
||||||
else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value))
|
else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
is Binary -> when {
|
is Binary -> when {
|
||||||
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant(
|
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant(
|
||||||
algebra
|
algebra.binaryOperationFunction(node.operation).invoke(
|
||||||
.binaryOperationFunction(node.operation)
|
algebra.number((node.left as Numeric).value),
|
||||||
.invoke(algebra.number(node.left.value), algebra.number(node.right.value))
|
algebra.number((node.right as Numeric).value)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
algebra is NumericAlgebra && node.left is Numeric -> call(
|
algebra is NumericAlgebra && node.left is Numeric -> call(
|
||||||
@ -69,19 +67,21 @@ internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
|
|||||||
return ESTreeBuilder<T> { visit(this@compileWith) }.instance
|
return ESTreeBuilder<T> { visit(this@compileWith) }.instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a compiled expression with given [MST] and given [algebra].
|
||||||
|
*/
|
||||||
|
public fun <T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> = compileWith(algebra)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles an [MST] to ESTree generated expression using given algebra.
|
* Compile given MST to expression and evaluate it against [arguments]
|
||||||
*
|
|
||||||
* @author Alexander Nozik.
|
|
||||||
*/
|
*/
|
||||||
public fun <T : Any> Algebra<T>.expression(mst: MST): Expression<T> =
|
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
|
||||||
mst.compileWith(this)
|
compileToExpression(algebra).invoke(arguments)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimizes performance of an [MstExpression] by compiling it into ESTree generated expression.
|
* Compile given MST to expression and evaluate it against [arguments]
|
||||||
*
|
|
||||||
* @author Alexander Nozik.
|
|
||||||
*/
|
*/
|
||||||
public fun <T : Any> MstExpression<T, Algebra<T>>.compile(): Expression<T> =
|
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T =
|
||||||
mst.compileWith(algebra)
|
compileToExpression(algebra).invoke(*arguments)
|
||||||
|
@ -8,7 +8,7 @@ package space.kscience.kmath.estree.internal
|
|||||||
import space.kscience.kmath.estree.internal.astring.generate
|
import space.kscience.kmath.estree.internal.astring.generate
|
||||||
import space.kscience.kmath.estree.internal.estree.*
|
import space.kscience.kmath.estree.internal.estree.*
|
||||||
import space.kscience.kmath.expressions.Expression
|
import space.kscience.kmath.expressions.Expression
|
||||||
import space.kscience.kmath.expressions.Symbol
|
import space.kscience.kmath.misc.Symbol
|
||||||
|
|
||||||
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {
|
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {
|
||||||
private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> {
|
private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> {
|
||||||
|
@ -5,19 +5,22 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import space.kscience.kmath.ast.*
|
|
||||||
import space.kscience.kmath.complex.ComplexField
|
import space.kscience.kmath.complex.ComplexField
|
||||||
import space.kscience.kmath.complex.toComplex
|
import space.kscience.kmath.complex.toComplex
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.*
|
||||||
|
import space.kscience.kmath.misc.Symbol
|
||||||
import space.kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.operations.ByteRing
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class TestESTreeConsistencyWithInterpreter {
|
internal class TestESTreeConsistencyWithInterpreter {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun mstSpace() {
|
fun mstSpace() {
|
||||||
val res1 = MstGroup.mstInGroup {
|
|
||||||
|
val mst = MstGroup {
|
||||||
binaryOperationFunction("+")(
|
binaryOperationFunction("+")(
|
||||||
unaryOperationFunction("+")(
|
unaryOperationFunction("+")(
|
||||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
number(3.toByte()) - (number(2.toByte()) + (scale(
|
||||||
@ -28,27 +31,17 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
|
|
||||||
number(1)
|
number(1)
|
||||||
) + bindSymbol("x") + zero
|
) + bindSymbol("x") + zero
|
||||||
}("x" to MST.Numeric(2))
|
}
|
||||||
|
|
||||||
val res2 = MstGroup.mstInGroup {
|
assertEquals(
|
||||||
binaryOperationFunction("+")(
|
mst.interpret(MstGroup, Symbol.x to MST.Numeric(2)),
|
||||||
unaryOperationFunction("+")(
|
mst.compile(MstGroup, Symbol.x to MST.Numeric(2))
|
||||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
)
|
||||||
add(number(1), number(1)),
|
|
||||||
2.0
|
|
||||||
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
|
|
||||||
),
|
|
||||||
|
|
||||||
number(1)
|
|
||||||
) + bindSymbol("x") + zero
|
|
||||||
}.compile()("x" to MST.Numeric(2))
|
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun byteRing() {
|
fun byteRing() {
|
||||||
val res1 = ByteRing.mstInRing {
|
val mst = MstRing {
|
||||||
binaryOperationFunction("+")(
|
binaryOperationFunction("+")(
|
||||||
unaryOperationFunction("+")(
|
unaryOperationFunction("+")(
|
||||||
(bindSymbol("x") - (2.toByte() + (scale(
|
(bindSymbol("x") - (2.toByte() + (scale(
|
||||||
@ -59,62 +52,43 @@ internal class TestESTreeConsistencyWithInterpreter {
|
|||||||
|
|
||||||
number(1)
|
number(1)
|
||||||
) * number(2)
|
) * number(2)
|
||||||
}("x" to 3.toByte())
|
}
|
||||||
|
|
||||||
val res2 = ByteRing.mstInRing {
|
assertEquals(
|
||||||
binaryOperationFunction("+")(
|
mst.interpret(ByteRing, Symbol.x to 3.toByte()),
|
||||||
unaryOperationFunction("+")(
|
mst.compile(ByteRing, Symbol.x to 3.toByte())
|
||||||
(bindSymbol("x") - (2.toByte() + (scale(
|
)
|
||||||
add(number(1), number(1)),
|
|
||||||
2.0
|
|
||||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
|
||||||
),
|
|
||||||
number(1)
|
|
||||||
) * number(2)
|
|
||||||
}.compile()("x" to 3.toByte())
|
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun realField() {
|
fun realField() {
|
||||||
val res1 = RealField.mstInField {
|
val mst = MstField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
}("x" to 2.0)
|
}
|
||||||
|
|
||||||
val res2 = RealField.mstInField {
|
assertEquals(
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
mst.interpret(DoubleField, Symbol.x to 2.0),
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
mst.compile(DoubleField, Symbol.x to 2.0)
|
||||||
+ number(1),
|
)
|
||||||
number(1) / 2 + number(2.0) * one
|
|
||||||
) + zero
|
|
||||||
}.compile()("x" to 2.0)
|
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun complexField() {
|
fun complexField() {
|
||||||
val res1 = ComplexField.mstInField {
|
val mst = MstField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
}("x" to 2.0.toComplex())
|
}
|
||||||
|
|
||||||
val res2 = ComplexField.mstInField {
|
assertEquals(
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
mst.interpret(ComplexField, Symbol.x to 2.0.toComplex()),
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
mst.compile(ComplexField, Symbol.x to 2.0.toComplex())
|
||||||
+ number(1),
|
)
|
||||||
number(1) / 2 + number(2.0) * one
|
|
||||||
) + zero
|
|
||||||
}.compile()("x" to 2.0.toComplex())
|
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,10 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import space.kscience.kmath.ast.mstInExtendedField
|
import space.kscience.kmath.expressions.MstExtendedField
|
||||||
import space.kscience.kmath.ast.mstInField
|
|
||||||
import space.kscience.kmath.ast.mstInGroup
|
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -17,27 +16,29 @@ import kotlin.test.assertEquals
|
|||||||
internal class TestESTreeOperationsSupport {
|
internal class TestESTreeOperationsSupport {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryOperationInvocation() {
|
fun testUnaryOperationInvocation() {
|
||||||
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile()
|
val expression = MstExtendedField { -bindSymbol("x") }.compileToExpression(DoubleField)
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-2.0, res)
|
assertEquals(-2.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBinaryOperationInvocation() {
|
fun testBinaryOperationInvocation() {
|
||||||
val expression = RealField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
val expression = MstExtendedField { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-1.0, res)
|
assertEquals(-1.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testConstProductInvocation() {
|
fun testConstProductInvocation() {
|
||||||
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
val res = MstExtendedField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
|
||||||
assertEquals(4.0, res)
|
assertEquals(4.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMultipleCalls() {
|
fun testMultipleCalls() {
|
||||||
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile()
|
val e =
|
||||||
|
MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
|
||||||
|
.compileToExpression(DoubleField)
|
||||||
val r = Random(0)
|
val r = Random(0)
|
||||||
var s = 0.0
|
var s = 0.0
|
||||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||||
|
@ -5,54 +5,64 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import space.kscience.kmath.ast.mstInField
|
import space.kscience.kmath.expressions.MstExtendedField
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class TestESTreeSpecialization {
|
internal class TestESTreeSpecialization {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryPlus() {
|
fun testUnaryPlus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField)
|
||||||
assertEquals(2.0, expr("x" to 2.0))
|
assertEquals(2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryMinus() {
|
fun testUnaryMinus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField)
|
||||||
assertEquals(-2.0, expr("x" to 2.0))
|
assertEquals(-2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAdd() {
|
fun testAdd() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = MstExtendedField {
|
||||||
|
binaryOperationFunction("+")(bindSymbol("x"),
|
||||||
|
bindSymbol("x"))
|
||||||
|
}.compileToExpression(DoubleField)
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSine() {
|
fun testSine() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField)
|
||||||
assertEquals(0.0, expr("x" to 0.0))
|
assertEquals(0.0, expr("x" to 0.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMinus() {
|
fun testMinus() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = MstExtendedField {
|
||||||
|
binaryOperationFunction("-")(bindSymbol("x"),
|
||||||
|
bindSymbol("x"))
|
||||||
|
}.compileToExpression(DoubleField)
|
||||||
assertEquals(0.0, expr("x" to 2.0))
|
assertEquals(0.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDivide() {
|
fun testDivide() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = MstExtendedField {
|
||||||
|
binaryOperationFunction("/")(bindSymbol("x"),
|
||||||
|
bindSymbol("x"))
|
||||||
|
}.compileToExpression(DoubleField)
|
||||||
assertEquals(1.0, expr("x" to 2.0))
|
assertEquals(1.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPower() {
|
fun testPower() {
|
||||||
val expr = RealField
|
val expr = MstExtendedField {
|
||||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
binaryOperationFunction("pow")(bindSymbol("x"), number(2))
|
||||||
.compile()
|
}.compileToExpression(DoubleField)
|
||||||
|
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,10 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.estree
|
package space.kscience.kmath.estree
|
||||||
|
|
||||||
import space.kscience.kmath.ast.mstInRing
|
import space.kscience.kmath.expressions.MstRing
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.operations.ByteRing
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
@ -15,13 +16,13 @@ import kotlin.test.assertFailsWith
|
|||||||
internal class TestESTreeVariables {
|
internal class TestESTreeVariables {
|
||||||
@Test
|
@Test
|
||||||
fun testVariable() {
|
fun testVariable() {
|
||||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
val expr = MstRing{ bindSymbol("x") }.compileToExpression(ByteRing)
|
||||||
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUndefinedVariableFails() {
|
fun testUndefinedVariableFails() {
|
||||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
|
||||||
assertFailsWith<NoSuchElementException> { expr() }
|
assertFailsWith<NoSuchElementException> { expr() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,11 @@ package space.kscience.kmath.asm
|
|||||||
|
|
||||||
import space.kscience.kmath.asm.internal.AsmBuilder
|
import space.kscience.kmath.asm.internal.AsmBuilder
|
||||||
import space.kscience.kmath.asm.internal.buildName
|
import space.kscience.kmath.asm.internal.buildName
|
||||||
import space.kscience.kmath.ast.MST
|
|
||||||
import space.kscience.kmath.ast.MST.*
|
|
||||||
import space.kscience.kmath.ast.MstExpression
|
|
||||||
import space.kscience.kmath.expressions.Expression
|
import space.kscience.kmath.expressions.Expression
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
|
import space.kscience.kmath.expressions.MST.*
|
||||||
|
import space.kscience.kmath.expressions.invoke
|
||||||
|
import space.kscience.kmath.misc.Symbol
|
||||||
import space.kscience.kmath.operations.Algebra
|
import space.kscience.kmath.operations.Algebra
|
||||||
import space.kscience.kmath.operations.NumericAlgebra
|
import space.kscience.kmath.operations.NumericAlgebra
|
||||||
|
|
||||||
@ -26,11 +27,7 @@ import space.kscience.kmath.operations.NumericAlgebra
|
|||||||
internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Expression<T> {
|
internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Expression<T> {
|
||||||
fun AsmBuilder<T>.visit(node: MST): Unit = when (node) {
|
fun AsmBuilder<T>.visit(node: MST): Unit = when (node) {
|
||||||
is Symbolic -> {
|
is Symbolic -> {
|
||||||
val symbol = try {
|
val symbol = algebra.bindSymbolOrNull(node.value)
|
||||||
algebra.bindSymbol(node.value)
|
|
||||||
} catch (ignored: IllegalStateException) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (symbol != null)
|
if (symbol != null)
|
||||||
loadObjectConstant(symbol as Any)
|
loadObjectConstant(symbol as Any)
|
||||||
@ -42,15 +39,17 @@ internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Exp
|
|||||||
|
|
||||||
is Unary -> when {
|
is Unary -> when {
|
||||||
algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant(
|
algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant(
|
||||||
algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value)))
|
algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
|
||||||
|
|
||||||
else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) }
|
else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
is Binary -> when {
|
is Binary -> when {
|
||||||
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant(
|
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant(
|
||||||
algebra.binaryOperationFunction(node.operation)
|
algebra.binaryOperationFunction(node.operation).invoke(
|
||||||
.invoke(algebra.number(node.left.value), algebra.number(node.right.value))
|
algebra.number((node.left as Numeric).value),
|
||||||
|
algebra.number((node.right as Numeric).value)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
algebra is NumericAlgebra && node.left is Numeric -> buildCall(
|
algebra is NumericAlgebra && node.left is Numeric -> buildCall(
|
||||||
@ -75,18 +74,22 @@ internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Exp
|
|||||||
return AsmBuilder<T>(type, buildName(this)) { visit(this@compileWith) }.instance
|
return AsmBuilder<T>(type, buildName(this)) { visit(this@compileWith) }.instance
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compiles an [MST] to ASM using given algebra.
|
|
||||||
*
|
|
||||||
* @author Alexander Nozik.
|
|
||||||
*/
|
|
||||||
public inline fun <reified T : Any> Algebra<T>.expression(mst: MST): Expression<T> =
|
|
||||||
mst.compileWith(T::class.java, this)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimizes performance of an [MstExpression] using ASM codegen.
|
* Create a compiled expression with given [MST] and given [algebra].
|
||||||
*
|
|
||||||
* @author Alexander Nozik.
|
|
||||||
*/
|
*/
|
||||||
public inline fun <reified T : Any> MstExpression<T, Algebra<T>>.compile(): Expression<T> =
|
public inline fun <reified T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> =
|
||||||
mst.compileWith(T::class.java, algebra)
|
compileWith(T::class.java, algebra)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile given MST to expression and evaluate it against [arguments]
|
||||||
|
*/
|
||||||
|
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
|
||||||
|
compileToExpression(algebra).invoke(arguments)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile given MST to expression and evaluate it against [arguments]
|
||||||
|
*/
|
||||||
|
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T =
|
||||||
|
compileToExpression(algebra).invoke(*arguments)
|
||||||
|
@ -10,8 +10,8 @@ import org.objectweb.asm.Opcodes.*
|
|||||||
import org.objectweb.asm.Type.*
|
import org.objectweb.asm.Type.*
|
||||||
import org.objectweb.asm.commons.InstructionAdapter
|
import org.objectweb.asm.commons.InstructionAdapter
|
||||||
import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader
|
import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader
|
||||||
import space.kscience.kmath.ast.MST
|
|
||||||
import space.kscience.kmath.expressions.Expression
|
import space.kscience.kmath.expressions.Expression
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
import java.lang.invoke.MethodHandles
|
import java.lang.invoke.MethodHandles
|
||||||
import java.lang.invoke.MethodType
|
import java.lang.invoke.MethodType
|
||||||
import java.util.stream.Collectors.toMap
|
import java.util.stream.Collectors.toMap
|
||||||
|
@ -7,8 +7,8 @@ package space.kscience.kmath.asm.internal
|
|||||||
|
|
||||||
import org.objectweb.asm.*
|
import org.objectweb.asm.*
|
||||||
import org.objectweb.asm.commons.InstructionAdapter
|
import org.objectweb.asm.commons.InstructionAdapter
|
||||||
import space.kscience.kmath.ast.MST
|
|
||||||
import space.kscience.kmath.expressions.Expression
|
import space.kscience.kmath.expressions.Expression
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ internal inline fun ClassWriter.visitField(
|
|||||||
descriptor: String,
|
descriptor: String,
|
||||||
signature: String?,
|
signature: String?,
|
||||||
value: Any?,
|
value: Any?,
|
||||||
block: FieldVisitor.() -> Unit
|
block: FieldVisitor.() -> Unit,
|
||||||
): FieldVisitor {
|
): FieldVisitor {
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||||
return visitField(access, name, descriptor, signature, value).apply(block)
|
return visitField(access, name, descriptor, signature, value).apply(block)
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.asm.internal
|
package space.kscience.kmath.asm.internal
|
||||||
|
|
||||||
import space.kscience.kmath.expressions.StringSymbol
|
import space.kscience.kmath.misc.StringSymbol
|
||||||
import space.kscience.kmath.expressions.Symbol
|
import space.kscience.kmath.misc.Symbol
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets value with given [key] or throws [NoSuchElementException] whenever it is not present.
|
* Gets value with given [key] or throws [NoSuchElementException] whenever it is not present.
|
||||||
|
@ -18,6 +18,7 @@ import com.github.h0tk3y.betterParse.lexer.literalToken
|
|||||||
import com.github.h0tk3y.betterParse.lexer.regexToken
|
import com.github.h0tk3y.betterParse.lexer.regexToken
|
||||||
import com.github.h0tk3y.betterParse.parser.ParseResult
|
import com.github.h0tk3y.betterParse.parser.ParseResult
|
||||||
import com.github.h0tk3y.betterParse.parser.Parser
|
import com.github.h0tk3y.betterParse.parser.Parser
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
import space.kscience.kmath.operations.FieldOperations
|
import space.kscience.kmath.operations.FieldOperations
|
||||||
import space.kscience.kmath.operations.GroupOperations
|
import space.kscience.kmath.operations.GroupOperations
|
||||||
import space.kscience.kmath.operations.PowerOperations
|
import space.kscience.kmath.operations.PowerOperations
|
||||||
@ -26,7 +27,8 @@ import space.kscience.kmath.operations.RingOperations
|
|||||||
/**
|
/**
|
||||||
* better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4.
|
* better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4.
|
||||||
*
|
*
|
||||||
* @author Alexander Nozik and Iaroslav Postovalov
|
* @author Alexander Nozik
|
||||||
|
* @author Iaroslav Postovalov
|
||||||
*/
|
*/
|
||||||
public object ArithmeticsEvaluator : Grammar<MST>() {
|
public object ArithmeticsEvaluator : Grammar<MST>() {
|
||||||
// TODO replace with "...".toRegex() when better-parse 0.4.1 is released
|
// TODO replace with "...".toRegex() when better-parse 0.4.1 is released
|
||||||
|
@ -5,19 +5,22 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.asm
|
package space.kscience.kmath.asm
|
||||||
|
|
||||||
import space.kscience.kmath.ast.*
|
|
||||||
import space.kscience.kmath.complex.ComplexField
|
import space.kscience.kmath.complex.ComplexField
|
||||||
import space.kscience.kmath.complex.toComplex
|
import space.kscience.kmath.complex.toComplex
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.*
|
||||||
|
import space.kscience.kmath.misc.Symbol.Companion.x
|
||||||
import space.kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.operations.ByteRing
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class TestAsmConsistencyWithInterpreter {
|
internal class TestAsmConsistencyWithInterpreter {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun mstSpace() {
|
fun mstSpace() {
|
||||||
val res1 = MstGroup.mstInGroup {
|
|
||||||
|
val mst = MstGroup {
|
||||||
binaryOperationFunction("+")(
|
binaryOperationFunction("+")(
|
||||||
unaryOperationFunction("+")(
|
unaryOperationFunction("+")(
|
||||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
number(3.toByte()) - (number(2.toByte()) + (scale(
|
||||||
@ -28,27 +31,17 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
|
|
||||||
number(1)
|
number(1)
|
||||||
) + bindSymbol("x") + zero
|
) + bindSymbol("x") + zero
|
||||||
}("x" to MST.Numeric(2))
|
}
|
||||||
|
|
||||||
val res2 = MstGroup.mstInGroup {
|
assertEquals(
|
||||||
binaryOperationFunction("+")(
|
mst.interpret(MstGroup, x to MST.Numeric(2)),
|
||||||
unaryOperationFunction("+")(
|
mst.compile(MstGroup, x to MST.Numeric(2))
|
||||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
)
|
||||||
add(number(1), number(1)),
|
|
||||||
2.0
|
|
||||||
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
|
|
||||||
),
|
|
||||||
|
|
||||||
number(1)
|
|
||||||
) + bindSymbol("x") + zero
|
|
||||||
}.compile()("x" to MST.Numeric(2))
|
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun byteRing() {
|
fun byteRing() {
|
||||||
val res1 = ByteRing.mstInRing {
|
val mst = MstRing {
|
||||||
binaryOperationFunction("+")(
|
binaryOperationFunction("+")(
|
||||||
unaryOperationFunction("+")(
|
unaryOperationFunction("+")(
|
||||||
(bindSymbol("x") - (2.toByte() + (scale(
|
(bindSymbol("x") - (2.toByte() + (scale(
|
||||||
@ -59,62 +52,43 @@ internal class TestAsmConsistencyWithInterpreter {
|
|||||||
|
|
||||||
number(1)
|
number(1)
|
||||||
) * number(2)
|
) * number(2)
|
||||||
}("x" to 3.toByte())
|
}
|
||||||
|
|
||||||
val res2 = ByteRing.mstInRing {
|
assertEquals(
|
||||||
binaryOperationFunction("+")(
|
mst.interpret(ByteRing, x to 3.toByte()),
|
||||||
unaryOperationFunction("+")(
|
mst.compile(ByteRing, x to 3.toByte())
|
||||||
(bindSymbol("x") - (2.toByte() + (scale(
|
)
|
||||||
add(number(1), number(1)),
|
|
||||||
2.0
|
|
||||||
) + 1.toByte()))) * 3.0 - 1.toByte()
|
|
||||||
),
|
|
||||||
number(1)
|
|
||||||
) * number(2)
|
|
||||||
}.compile()("x" to 3.toByte())
|
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun realField() {
|
fun realField() {
|
||||||
val res1 = RealField.mstInField {
|
val mst = MstField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
}("x" to 2.0)
|
}
|
||||||
|
|
||||||
val res2 = RealField.mstInField {
|
assertEquals(
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
mst.interpret(DoubleField, x to 2.0),
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
mst.compile(DoubleField, x to 2.0)
|
||||||
+ number(1),
|
)
|
||||||
number(1) / 2 + number(2.0) * one
|
|
||||||
) + zero
|
|
||||||
}.compile()("x" to 2.0)
|
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun complexField() {
|
fun complexField() {
|
||||||
val res1 = ComplexField.mstInField {
|
val mst = MstField {
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||||
+ number(1),
|
+ number(1),
|
||||||
number(1) / 2 + number(2.0) * one
|
number(1) / 2 + number(2.0) * one
|
||||||
) + zero
|
) + zero
|
||||||
}("x" to 2.0.toComplex())
|
}
|
||||||
|
|
||||||
val res2 = ComplexField.mstInField {
|
assertEquals(
|
||||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
mst.interpret(ComplexField, x to 2.0.toComplex()),
|
||||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
mst.compile(ComplexField, x to 2.0.toComplex())
|
||||||
+ number(1),
|
)
|
||||||
number(1) / 2 + number(2.0) * one
|
|
||||||
) + zero
|
|
||||||
}.compile()("x" to 2.0.toComplex())
|
|
||||||
|
|
||||||
assertEquals(res1, res2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,12 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.asm
|
package space.kscience.kmath.asm
|
||||||
|
|
||||||
import space.kscience.kmath.ast.mstInExtendedField
|
import space.kscience.kmath.expressions.MstExtendedField
|
||||||
import space.kscience.kmath.ast.mstInField
|
import space.kscience.kmath.expressions.MstField
|
||||||
import space.kscience.kmath.ast.mstInGroup
|
import space.kscience.kmath.expressions.MstGroup
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -17,27 +18,29 @@ import kotlin.test.assertEquals
|
|||||||
internal class TestAsmOperationsSupport {
|
internal class TestAsmOperationsSupport {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryOperationInvocation() {
|
fun testUnaryOperationInvocation() {
|
||||||
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile()
|
val expression = MstGroup { -bindSymbol("x") }.compileToExpression(DoubleField)
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-2.0, res)
|
assertEquals(-2.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBinaryOperationInvocation() {
|
fun testBinaryOperationInvocation() {
|
||||||
val expression = RealField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
val expression = MstGroup { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
|
||||||
val res = expression("x" to 2.0)
|
val res = expression("x" to 2.0)
|
||||||
assertEquals(-1.0, res)
|
assertEquals(-1.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testConstProductInvocation() {
|
fun testConstProductInvocation() {
|
||||||
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
val res = MstField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
|
||||||
assertEquals(4.0, res)
|
assertEquals(4.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMultipleCalls() {
|
fun testMultipleCalls() {
|
||||||
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile()
|
val e =
|
||||||
|
MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
|
||||||
|
.compileToExpression(DoubleField)
|
||||||
val r = Random(0)
|
val r = Random(0)
|
||||||
var s = 0.0
|
var s = 0.0
|
||||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||||
|
@ -5,54 +5,64 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.asm
|
package space.kscience.kmath.asm
|
||||||
|
|
||||||
import space.kscience.kmath.ast.mstInField
|
import space.kscience.kmath.expressions.MstExtendedField
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class TestAsmSpecialization {
|
internal class TestAsmSpecialization {
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryPlus() {
|
fun testUnaryPlus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
|
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField)
|
||||||
assertEquals(2.0, expr("x" to 2.0))
|
assertEquals(2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUnaryMinus() {
|
fun testUnaryMinus() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
|
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField)
|
||||||
assertEquals(-2.0, expr("x" to 2.0))
|
assertEquals(-2.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAdd() {
|
fun testAdd() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = MstExtendedField {
|
||||||
|
binaryOperationFunction("+")(bindSymbol("x"),
|
||||||
|
bindSymbol("x"))
|
||||||
|
}.compileToExpression(DoubleField)
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSine() {
|
fun testSine() {
|
||||||
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
|
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField)
|
||||||
assertEquals(0.0, expr("x" to 0.0))
|
assertEquals(0.0, expr("x" to 0.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMinus() {
|
fun testMinus() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = MstExtendedField {
|
||||||
|
binaryOperationFunction("-")(bindSymbol("x"),
|
||||||
|
bindSymbol("x"))
|
||||||
|
}.compileToExpression(DoubleField)
|
||||||
assertEquals(0.0, expr("x" to 2.0))
|
assertEquals(0.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDivide() {
|
fun testDivide() {
|
||||||
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
|
val expr = MstExtendedField {
|
||||||
|
binaryOperationFunction("/")(bindSymbol("x"),
|
||||||
|
bindSymbol("x"))
|
||||||
|
}.compileToExpression(DoubleField)
|
||||||
assertEquals(1.0, expr("x" to 2.0))
|
assertEquals(1.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPower() {
|
fun testPower() {
|
||||||
val expr = RealField
|
val expr = MstExtendedField {
|
||||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
binaryOperationFunction("pow")(bindSymbol("x"), number(2))
|
||||||
.compile()
|
}.compileToExpression(DoubleField)
|
||||||
|
|
||||||
assertEquals(4.0, expr("x" to 2.0))
|
assertEquals(4.0, expr("x" to 2.0))
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,10 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.asm
|
package space.kscience.kmath.asm
|
||||||
|
|
||||||
import space.kscience.kmath.ast.mstInRing
|
import space.kscience.kmath.expressions.MstRing
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.operations.ByteRing
|
import space.kscience.kmath.operations.ByteRing
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
@ -15,13 +16,13 @@ import kotlin.test.assertFailsWith
|
|||||||
internal class TestAsmVariables {
|
internal class TestAsmVariables {
|
||||||
@Test
|
@Test
|
||||||
fun testVariable() {
|
fun testVariable() {
|
||||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
|
||||||
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUndefinedVariableFails() {
|
fun testUndefinedVariableFails() {
|
||||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
|
||||||
assertFailsWith<NoSuchElementException> { expr() }
|
assertFailsWith<NoSuchElementException> { expr() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,14 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.ast
|
package space.kscience.kmath.ast
|
||||||
|
|
||||||
|
import space.kscience.kmath.expressions.evaluate
|
||||||
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.operations.Field
|
import space.kscience.kmath.operations.Field
|
||||||
import space.kscience.kmath.operations.RealField
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal class ParserPrecedenceTest {
|
internal class ParserPrecedenceTest {
|
||||||
private val f: Field<Double> = RealField
|
private val f: Field<Double> = DoubleField
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
|
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
|
||||||
|
@ -7,9 +7,12 @@ package space.kscience.kmath.ast
|
|||||||
|
|
||||||
import space.kscience.kmath.complex.Complex
|
import space.kscience.kmath.complex.Complex
|
||||||
import space.kscience.kmath.complex.ComplexField
|
import space.kscience.kmath.complex.ComplexField
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.MstField
|
||||||
|
import space.kscience.kmath.expressions.evaluate
|
||||||
|
import space.kscience.kmath.expressions.interpret
|
||||||
import space.kscience.kmath.operations.Algebra
|
import space.kscience.kmath.operations.Algebra
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -23,7 +26,7 @@ internal class ParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `evaluate MSTExpression`() {
|
fun `evaluate MSTExpression`() {
|
||||||
val res = ComplexField.mstInField { number(2) + number(2) * (number(2) + number(2)) }()
|
val res = MstField.invoke { number(2) + number(2) * (number(2) + number(2)) }.interpret(ComplexField)
|
||||||
assertEquals(Complex(10.0, 0.0), res)
|
assertEquals(Complex(10.0, 0.0), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,14 +41,14 @@ internal class ParserTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `evaluate MST with unary function`() {
|
fun `evaluate MST with unary function`() {
|
||||||
val mst = "sin(0)".parseMath()
|
val mst = "sin(0)".parseMath()
|
||||||
val res = RealField.evaluate(mst)
|
val res = DoubleField.evaluate(mst)
|
||||||
assertEquals(0.0, res)
|
assertEquals(0.0, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `evaluate MST with binary function`() {
|
fun `evaluate MST with binary function`() {
|
||||||
val magicalAlgebra = object : Algebra<String> {
|
val magicalAlgebra = object : Algebra<String> {
|
||||||
override fun bindSymbol(value: String): String = value
|
override fun bindSymbolOrNull(value: String): String = value
|
||||||
|
|
||||||
override fun unaryOperationFunction(operation: String): (arg: String) -> String {
|
override fun unaryOperationFunction(operation: String): (arg: String) -> String {
|
||||||
throw NotImplementedError()
|
throw NotImplementedError()
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
import space.kscience.kmath.ast.rendering.TestUtils.testLatex
|
||||||
|
import space.kscience.kmath.expressions.MST.Numeric
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
internal class TestFeatures {
|
||||||
|
@Test
|
||||||
|
fun printSymbolic() = testLatex("x", "x")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun printNumeric() {
|
||||||
|
val num = object : Number() {
|
||||||
|
override fun toByte(): Byte = throw UnsupportedOperationException()
|
||||||
|
override fun toChar(): Char = throw UnsupportedOperationException()
|
||||||
|
override fun toDouble(): Double = throw UnsupportedOperationException()
|
||||||
|
override fun toFloat(): Float = throw UnsupportedOperationException()
|
||||||
|
override fun toInt(): Int = throw UnsupportedOperationException()
|
||||||
|
override fun toLong(): Long = throw UnsupportedOperationException()
|
||||||
|
override fun toShort(): Short = throw UnsupportedOperationException()
|
||||||
|
override fun toString(): String = "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
testLatex(Numeric(num), "foo")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun prettyPrintFloats() {
|
||||||
|
testLatex(Numeric(Double.NaN), "NaN")
|
||||||
|
testLatex(Numeric(Double.POSITIVE_INFINITY), "\\infty")
|
||||||
|
testLatex(Numeric(Double.NEGATIVE_INFINITY), "-\\infty")
|
||||||
|
testLatex(Numeric(1.0), "1")
|
||||||
|
testLatex(Numeric(-1.0), "-1")
|
||||||
|
testLatex(Numeric(1.42), "1.42")
|
||||||
|
testLatex(Numeric(-1.42), "-1.42")
|
||||||
|
testLatex(Numeric(1.1e10), "1.1\\times10^{10}")
|
||||||
|
testLatex(Numeric(1.1e-10), "1.1\\times10^{-10}")
|
||||||
|
testLatex(Numeric(-1.1e-10), "-1.1\\times10^{-10}")
|
||||||
|
testLatex(Numeric(-1.1e10), "-1.1\\times10^{10}")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun prettyPrintIntegers() {
|
||||||
|
testLatex(Numeric(42), "42")
|
||||||
|
testLatex(Numeric(-42), "-42")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun prettyPrintPi() {
|
||||||
|
testLatex("pi", "\\pi")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun binaryPlus() = testLatex("2+2", "2+2")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun binaryMinus() = testLatex("2-2", "2-2")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun fraction() = testLatex("2/2", "\\frac{2}{2}")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun binaryOperator() = testLatex("f(x, y)", "\\operatorname{f}\\left(x,y\\right)")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unaryOperator() = testLatex("f(x)", "\\operatorname{f}\\,\\left(x\\right)")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun power() = testLatex("x^y", "x^{y}")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun squareRoot() = testLatex("sqrt(x)", "\\sqrt{x}")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun exponential() = testLatex("exp(x)", "e^{x}")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multiplication() = testLatex("x*1", "x\\times1")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun inverseTrigonometry() {
|
||||||
|
testLatex("asin(x)", "\\operatorname{sin}^{-1}\\,\\left(x\\right)")
|
||||||
|
testLatex("asinh(x)", "\\operatorname{sinh}^{-1}\\,\\left(x\\right)")
|
||||||
|
testLatex("acos(x)", "\\operatorname{cos}^{-1}\\,\\left(x\\right)")
|
||||||
|
testLatex("acosh(x)", "\\operatorname{cosh}^{-1}\\,\\left(x\\right)")
|
||||||
|
testLatex("atan(x)", "\\operatorname{tan}^{-1}\\,\\left(x\\right)")
|
||||||
|
testLatex("atanh(x)", "\\operatorname{tanh}^{-1}\\,\\left(x\\right)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
// fun unaryPlus() {
|
||||||
|
// testLatex("+1", "+1")
|
||||||
|
// testLatex("+1", "++1")
|
||||||
|
// }
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
import space.kscience.kmath.ast.rendering.TestUtils.testLatex
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
|
import space.kscience.kmath.operations.GroupOperations
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
internal class TestLatex {
|
||||||
|
@Test
|
||||||
|
fun number() = testLatex("42", "42")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbol() = testLatex("x", "x")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun operatorName() = testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun specialSymbol() {
|
||||||
|
testLatex(MST.Numeric(Double.POSITIVE_INFINITY), "\\infty")
|
||||||
|
testLatex("pi", "\\pi")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun operand() {
|
||||||
|
testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)")
|
||||||
|
testLatex("1+1", "1+1")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unaryOperator() = testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unaryPlus() = testLatex(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unaryMinus() = testLatex("-x", "-x")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun radical() = testLatex("sqrt(x)", "\\sqrt{x}")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun superscript() = testLatex("x^y", "x^{y}")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun subscript() = testLatex(SubscriptSyntax("", SymbolSyntax("x"), NumberSyntax("123")), "x_{123}")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun binaryOperator() = testLatex("f(x, y)", "\\operatorname{f}\\left(x,y\\right)")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun binaryPlus() = testLatex("x+x", "x+x")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun binaryMinus() = testLatex("x-x", "x-x")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun fraction() = testLatex("x/x", "\\frac{x}{x}")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun radicalWithIndex() = testLatex(RadicalWithIndexSyntax("", SymbolSyntax("x"), SymbolSyntax("y")), "\\sqrt[x]{y}")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multiplication() {
|
||||||
|
testLatex("x*1", "x\\times1")
|
||||||
|
testLatex("1*x", "1\\,x")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
import space.kscience.kmath.ast.rendering.TestUtils.testMathML
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
|
import space.kscience.kmath.operations.GroupOperations
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
internal class TestMathML {
|
||||||
|
@Test
|
||||||
|
fun number() = testMathML("42", "<mn>42</mn>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun symbol() = testMathML("x", "<mi>x</mi>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun operatorName() = testMathML(
|
||||||
|
"sin(1)",
|
||||||
|
"<mo>sin</mo><mspace width=\"0.167em\"></mspace><mfenced open=\"(\" close=\")\" separators=\"\"><mn>1</mn></mfenced>",
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun specialSymbol() {
|
||||||
|
testMathML(MST.Numeric(Double.POSITIVE_INFINITY), "<mo>∞</mo>")
|
||||||
|
testMathML("pi", "<mo>π</mo>")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun operand() {
|
||||||
|
testMathML(
|
||||||
|
"sin(1)",
|
||||||
|
"<mo>sin</mo><mspace width=\"0.167em\"></mspace><mfenced open=\"(\" close=\")\" separators=\"\"><mn>1</mn></mfenced>",
|
||||||
|
)
|
||||||
|
|
||||||
|
testMathML("1+1", "<mn>1</mn><mo>+</mo><mn>1</mn>")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unaryOperator() = testMathML(
|
||||||
|
"sin(1)",
|
||||||
|
"<mo>sin</mo><mspace width=\"0.167em\"></mspace><mfenced open=\"(\" close=\")\" separators=\"\"><mn>1</mn></mfenced>",
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unaryPlus() =
|
||||||
|
testMathML(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "<mo>+</mo><mn>1</mn>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unaryMinus() = testMathML("-x", "<mo>-</mo><mi>x</mi>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun radical() = testMathML("sqrt(x)", "<msqrt><mi>x</mi></msqrt>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun superscript() = testMathML("x^y", "<msup><mrow><mi>x</mi></mrow><mrow><mi>y</mi></mrow></msup>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun subscript() = testMathML(
|
||||||
|
SubscriptSyntax("", SymbolSyntax("x"), NumberSyntax("123")),
|
||||||
|
"<msub><mrow><mi>x</mi></mrow><mrow><mn>123</mn></mrow></msub>",
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun binaryOperator() = testMathML(
|
||||||
|
"f(x, y)",
|
||||||
|
"<mo>f</mo><mfenced open=\"(\" close=\")\" separators=\"\"><mi>x</mi><mo>,</mo><mi>y</mi></mfenced>",
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun binaryPlus() = testMathML("x+x", "<mi>x</mi><mo>+</mo><mi>x</mi>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun binaryMinus() = testMathML("x-x", "<mi>x</mi><mo>-</mo><mi>x</mi>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun fraction() = testMathML("x/x", "<mfrac><mrow><mi>x</mi></mrow><mrow><mi>x</mi></mrow></mfrac>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun radicalWithIndex() =
|
||||||
|
testMathML(RadicalWithIndexSyntax("", SymbolSyntax("x"), SymbolSyntax("y")),
|
||||||
|
"<mroot><mrow><mi>y</mi></mrow><mrow><mi>x</mi></mrow></mroot>")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multiplication() {
|
||||||
|
testMathML("x*1", "<mi>x</mi><mo>×</mo><mn>1</mn>")
|
||||||
|
testMathML("1*x", "<mn>1</mn><mspace width=\"0.167em\"></mspace><mi>x</mi>")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
import space.kscience.kmath.ast.rendering.TestUtils.testLatex
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
internal class TestStages {
|
||||||
|
@Test
|
||||||
|
fun betterMultiplication() {
|
||||||
|
testLatex("a*1", "a\\times1")
|
||||||
|
testLatex("1*(2/3)", "1\\times\\left(\\frac{2}{3}\\right)")
|
||||||
|
testLatex("1*1", "1\\times1")
|
||||||
|
testLatex("2e10", "2\\times10^{10}")
|
||||||
|
testLatex("2*x", "2\\,x")
|
||||||
|
testLatex("2*(x+1)", "2\\,\\left(x+1\\right)")
|
||||||
|
testLatex("x*y", "x\\,y")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parentheses() {
|
||||||
|
testLatex("(x+1)", "x+1")
|
||||||
|
testLatex("x*x*x", "x\\,x\\,x")
|
||||||
|
testLatex("(x+x)*x", "\\left(x+x\\right)\\,x")
|
||||||
|
testLatex("x+x*x", "x+x\\,x")
|
||||||
|
testLatex("x+x^x*x+x", "x+x^{x}\\,x+x")
|
||||||
|
testLatex("(x+x)^x+x*x", "\\left(x+x\\right)^{x}+x\\,x")
|
||||||
|
testLatex("x^(x+x)", "x^{x+x}")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.ast.rendering
|
||||||
|
|
||||||
|
import space.kscience.kmath.ast.parseMath
|
||||||
|
import space.kscience.kmath.expressions.MST
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
internal object TestUtils {
|
||||||
|
private fun mathSyntax(mst: MST) = FeaturedMathRendererWithPostProcess.Default.render(mst)
|
||||||
|
private fun latex(mst: MST) = LatexSyntaxRenderer.renderWithStringBuilder(mathSyntax(mst))
|
||||||
|
private fun mathML(mst: MST) = MathMLSyntaxRenderer.renderWithStringBuilder(mathSyntax(mst))
|
||||||
|
|
||||||
|
internal fun testLatex(mst: MST, expectedLatex: String) = assertEquals(
|
||||||
|
expected = expectedLatex,
|
||||||
|
actual = latex(mst),
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun testLatex(expression: String, expectedLatex: String) = assertEquals(
|
||||||
|
expected = expectedLatex,
|
||||||
|
actual = latex(expression.parseMath()),
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun testLatex(expression: MathSyntax, expectedLatex: String) = assertEquals(
|
||||||
|
expected = expectedLatex,
|
||||||
|
actual = LatexSyntaxRenderer.renderWithStringBuilder(expression),
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun testMathML(mst: MST, expectedMathML: String) = assertEquals(
|
||||||
|
expected = "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mrow>$expectedMathML</mrow></math>",
|
||||||
|
actual = mathML(mst),
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun testMathML(expression: String, expectedMathML: String) = assertEquals(
|
||||||
|
expected = "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mrow>$expectedMathML</mrow></math>",
|
||||||
|
actual = mathML(expression.parseMath()),
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun testMathML(expression: MathSyntax, expectedMathML: String) = assertEquals(
|
||||||
|
expected = "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mrow>$expectedMathML</mrow></math>",
|
||||||
|
actual = MathMLSyntaxRenderer.renderWithStringBuilder(expression),
|
||||||
|
)
|
||||||
|
}
|
@ -4,7 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.gradle.jvm")
|
kotlin("jvm")
|
||||||
|
id("ru.mipt.npm.gradle.common")
|
||||||
}
|
}
|
||||||
description = "Commons math binding for kmath"
|
description = "Commons math binding for kmath"
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ package space.kscience.kmath.commons.expressions
|
|||||||
|
|
||||||
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
||||||
import space.kscience.kmath.expressions.*
|
import space.kscience.kmath.expressions.*
|
||||||
|
import space.kscience.kmath.misc.Symbol
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.operations.ExtendedField
|
import space.kscience.kmath.operations.ExtendedField
|
||||||
import space.kscience.kmath.operations.NumbersAddOperations
|
import space.kscience.kmath.operations.NumbersAddOperations
|
||||||
@ -28,7 +29,7 @@ public class DerivativeStructureField(
|
|||||||
public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) }
|
public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) }
|
||||||
public override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) }
|
public override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) }
|
||||||
|
|
||||||
override fun number(value: Number): DerivativeStructure = const(value.toDouble())
|
public override fun number(value: Number): DerivativeStructure = const(value.toDouble())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that implements both [DerivativeStructure] and a [Symbol]
|
* A class that implements both [DerivativeStructure] and a [Symbol]
|
||||||
@ -39,10 +40,10 @@ public class DerivativeStructureField(
|
|||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
value: Double,
|
value: Double,
|
||||||
) : DerivativeStructure(size, order, index, value), Symbol {
|
) : DerivativeStructure(size, order, index, value), Symbol {
|
||||||
override val identity: String = symbol.identity
|
public override val identity: String = symbol.identity
|
||||||
override fun toString(): String = identity
|
public override fun toString(): String = identity
|
||||||
override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity
|
public override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity
|
||||||
override fun hashCode(): Int = identity.hashCode()
|
public override fun hashCode(): Int = identity.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,13 +53,13 @@ public class DerivativeStructureField(
|
|||||||
key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value)
|
key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value)
|
||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value)
|
public override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value)
|
||||||
|
|
||||||
public override fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity]
|
public override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[value]
|
||||||
|
public override fun bindSymbol(value: String): DerivativeStructureSymbol = variables.getValue(value)
|
||||||
|
|
||||||
public fun bind(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity)
|
public fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity]
|
||||||
|
public fun bindSymbol(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity)
|
||||||
override fun bindSymbol(value: String): DerivativeStructureSymbol = bind(StringSymbol(value))
|
|
||||||
|
|
||||||
public fun DerivativeStructure.derivative(symbols: List<Symbol>): Double {
|
public fun DerivativeStructure.derivative(symbols: List<Symbol>): Double {
|
||||||
require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" }
|
require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" }
|
||||||
@ -68,7 +69,7 @@ public class DerivativeStructureField(
|
|||||||
|
|
||||||
public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList())
|
public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList())
|
||||||
|
|
||||||
override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate()
|
public override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate()
|
||||||
|
|
||||||
public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b)
|
public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b)
|
||||||
|
|
||||||
@ -111,7 +112,6 @@ public class DerivativeStructureField(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A constructs that creates a derivative structure with required order on-demand
|
* A constructs that creates a derivative structure with required order on-demand
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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) +
|
||||||
|
IntegrandCallsPerformed(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,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
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) + IntegrandCallsPerformed(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!!
|
||||||
|
}
|
||||||
|
}
|
@ -8,9 +8,9 @@ package space.kscience.kmath.commons.linear
|
|||||||
import org.apache.commons.math3.linear.*
|
import org.apache.commons.math3.linear.*
|
||||||
import space.kscience.kmath.linear.*
|
import space.kscience.kmath.linear.*
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.NDStructure
|
import space.kscience.kmath.nd.StructureFeature
|
||||||
import space.kscience.kmath.operations.RealField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.structures.RealBuffer
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.cast
|
import kotlin.reflect.cast
|
||||||
|
|
||||||
@ -19,17 +19,9 @@ public class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
|
|||||||
public override val colNum: Int get() = origin.columnDimension
|
public override val colNum: Int get() = origin.columnDimension
|
||||||
|
|
||||||
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
|
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other !is NDStructure<*>) return false
|
|
||||||
return NDStructure.contentEquals(this, other)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int = origin.hashCode()
|
public class CMVector(public val origin: RealVector) : Point<Double> {
|
||||||
}
|
|
||||||
|
|
||||||
public inline class CMVector(public val origin: RealVector) : Point<Double> {
|
|
||||||
public override val size: Int get() = origin.dimension
|
public override val size: Int get() = origin.dimension
|
||||||
|
|
||||||
public override operator fun get(index: Int): Double = origin.getEntry(index)
|
public override operator fun get(index: Int): Double = origin.getEntry(index)
|
||||||
@ -39,15 +31,15 @@ public inline class CMVector(public val origin: RealVector) : Point<Double> {
|
|||||||
|
|
||||||
public fun RealVector.toPoint(): CMVector = CMVector(this)
|
public fun RealVector.toPoint(): CMVector = CMVector(this)
|
||||||
|
|
||||||
public object CMLinearSpace : LinearSpace<Double, RealField> {
|
public object CMLinearSpace : LinearSpace<Double, DoubleField> {
|
||||||
override val elementAlgebra: RealField get() = RealField
|
override val elementAlgebra: DoubleField get() = DoubleField
|
||||||
|
|
||||||
public override fun buildMatrix(
|
public override fun buildMatrix(
|
||||||
rows: Int,
|
rows: Int,
|
||||||
columns: Int,
|
columns: Int,
|
||||||
initializer: RealField.(i: Int, j: Int) -> Double,
|
initializer: DoubleField.(i: Int, j: Int) -> Double,
|
||||||
): CMMatrix {
|
): CMMatrix {
|
||||||
val array = Array(rows) { i -> DoubleArray(columns) { j -> RealField.initializer(i, j) } }
|
val array = Array(rows) { i -> DoubleArray(columns) { j -> DoubleField.initializer(i, j) } }
|
||||||
return CMMatrix(Array2DRowRealMatrix(array))
|
return CMMatrix(Array2DRowRealMatrix(array))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,8 +61,8 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
|
|||||||
internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this)
|
internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this)
|
||||||
internal fun RealVector.wrap(): CMVector = CMVector(this)
|
internal fun RealVector.wrap(): CMVector = CMVector(this)
|
||||||
|
|
||||||
override fun buildVector(size: Int, initializer: RealField.(Int) -> Double): Point<Double> =
|
override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): Point<Double> =
|
||||||
ArrayRealVector(DoubleArray(size) { RealField.initializer(it) }).wrap()
|
ArrayRealVector(DoubleArray(size) { DoubleField.initializer(it) }).wrap()
|
||||||
|
|
||||||
override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix =
|
override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix =
|
||||||
toCM().origin.add(other.toCM().origin).wrap()
|
toCM().origin.add(other.toCM().origin).wrap()
|
||||||
@ -103,7 +95,7 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
|
|||||||
v * this
|
v * this
|
||||||
|
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
override fun <F : Any> getFeature(structure: Matrix<Double>, type: KClass<F>): F? {
|
override fun <F : StructureFeature> getFeature(structure: Matrix<Double>, type: KClass<out F>): F? {
|
||||||
//Return the feature if it is intrinsic to the structure
|
//Return the feature if it is intrinsic to the structure
|
||||||
structure.getFeature(type)?.let { return it }
|
structure.getFeature(type)?.let { return it }
|
||||||
|
|
||||||
@ -140,7 +132,7 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
|
|||||||
override val u: Matrix<Double> by lazy { CMMatrix(sv.u) }
|
override val u: Matrix<Double> by lazy { CMMatrix(sv.u) }
|
||||||
override val s: Matrix<Double> by lazy { CMMatrix(sv.s) }
|
override val s: Matrix<Double> by lazy { CMMatrix(sv.s) }
|
||||||
override val v: Matrix<Double> by lazy { CMMatrix(sv.v) }
|
override val v: Matrix<Double> by lazy { CMMatrix(sv.v) }
|
||||||
override val singularValues: Point<Double> by lazy { RealBuffer(sv.singularValues) }
|
override val singularValues: Point<Double> by lazy { DoubleBuffer(sv.singularValues) }
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}?.let(type::cast)
|
}?.let(type::cast)
|
||||||
|
@ -19,7 +19,7 @@ public enum class CMDecomposition {
|
|||||||
|
|
||||||
public fun CMLinearSpace.solver(
|
public fun CMLinearSpace.solver(
|
||||||
a: Matrix<Double>,
|
a: Matrix<Double>,
|
||||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||||
): DecompositionSolver = when (decomposition) {
|
): DecompositionSolver = when (decomposition) {
|
||||||
CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver
|
CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver
|
||||||
CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver
|
CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver
|
||||||
@ -31,16 +31,16 @@ public fun CMLinearSpace.solver(
|
|||||||
public fun CMLinearSpace.solve(
|
public fun CMLinearSpace.solve(
|
||||||
a: Matrix<Double>,
|
a: Matrix<Double>,
|
||||||
b: Matrix<Double>,
|
b: Matrix<Double>,
|
||||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||||
): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap()
|
): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap()
|
||||||
|
|
||||||
public fun CMLinearSpace.solve(
|
public fun CMLinearSpace.solve(
|
||||||
a: Matrix<Double>,
|
a: Matrix<Double>,
|
||||||
b: Point<Double>,
|
b: Point<Double>,
|
||||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||||
): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint()
|
): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint()
|
||||||
|
|
||||||
public fun CMLinearSpace.inverse(
|
public fun CMLinearSpace.inverse(
|
||||||
a: Matrix<Double>,
|
a: Matrix<Double>,
|
||||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||||
): CMMatrix = solver(a, decomposition).inverse.wrap()
|
): CMMatrix = solver(a, decomposition).inverse.wrap()
|
||||||
|
@ -14,22 +14,36 @@ import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjuga
|
|||||||
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex
|
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex
|
||||||
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex
|
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex
|
||||||
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
|
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
|
||||||
import space.kscience.kmath.expressions.*
|
import space.kscience.kmath.expressions.DifferentiableExpression
|
||||||
import space.kscience.kmath.stat.OptimizationFeature
|
import space.kscience.kmath.expressions.Expression
|
||||||
import space.kscience.kmath.stat.OptimizationProblem
|
import space.kscience.kmath.expressions.SymbolIndexer
|
||||||
import space.kscience.kmath.stat.OptimizationProblemFactory
|
import space.kscience.kmath.expressions.derivative
|
||||||
import space.kscience.kmath.stat.OptimizationResult
|
import space.kscience.kmath.misc.Symbol
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.optimization.*
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
public operator fun PointValuePair.component1(): DoubleArray = point
|
public operator fun PointValuePair.component1(): DoubleArray = point
|
||||||
public operator fun PointValuePair.component2(): Double = value
|
public operator fun PointValuePair.component2(): Double = value
|
||||||
|
|
||||||
public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
@OptIn(UnstableKMathAPI::class)
|
||||||
OptimizationProblem<Double>, SymbolIndexer, OptimizationFeature {
|
public class CMOptimization(
|
||||||
|
override val symbols: List<Symbol>,
|
||||||
|
) : FunctionOptimization<Double>, NoDerivFunctionOptimization<Double>, SymbolIndexer, OptimizationFeature {
|
||||||
|
|
||||||
private val optimizationData: HashMap<KClass<out OptimizationData>, OptimizationData> = HashMap()
|
private val optimizationData: HashMap<KClass<out OptimizationData>, OptimizationData> = HashMap()
|
||||||
private var optimizatorBuilder: (() -> MultivariateOptimizer)? = null
|
private var optimizerBuilder: (() -> MultivariateOptimizer)? = null
|
||||||
public var convergenceChecker: ConvergenceChecker<PointValuePair> = SimpleValueChecker(DEFAULT_RELATIVE_TOLERANCE,
|
public var convergenceChecker: ConvergenceChecker<PointValuePair> = SimpleValueChecker(
|
||||||
DEFAULT_ABSOLUTE_TOLERANCE, DEFAULT_MAX_ITER)
|
DEFAULT_RELATIVE_TOLERANCE,
|
||||||
|
DEFAULT_ABSOLUTE_TOLERANCE,
|
||||||
|
DEFAULT_MAX_ITER
|
||||||
|
)
|
||||||
|
|
||||||
|
override var maximize: Boolean
|
||||||
|
get() = optimizationData[GoalType::class] == GoalType.MAXIMIZE
|
||||||
|
set(value) {
|
||||||
|
optimizationData[GoalType::class] = if (value) GoalType.MAXIMIZE else GoalType.MINIMIZE
|
||||||
|
}
|
||||||
|
|
||||||
public fun addOptimizationData(data: OptimizationData) {
|
public fun addOptimizationData(data: OptimizationData) {
|
||||||
optimizationData[data::class] = data
|
optimizationData[data::class] = data
|
||||||
@ -45,7 +59,7 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
|||||||
addOptimizationData(InitialGuess(map.toDoubleArray()))
|
addOptimizationData(InitialGuess(map.toDoubleArray()))
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun expression(expression: Expression<Double>): Unit {
|
public override fun function(expression: Expression<Double>): Unit {
|
||||||
val objectiveFunction = ObjectiveFunction {
|
val objectiveFunction = ObjectiveFunction {
|
||||||
val args = it.toMap()
|
val args = it.toMap()
|
||||||
expression(args)
|
expression(args)
|
||||||
@ -53,8 +67,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
|||||||
addOptimizationData(objectiveFunction)
|
addOptimizationData(objectiveFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun diffExpression(expression: DifferentiableExpression<Double, Expression<Double>>) {
|
public override fun diffFunction(expression: DifferentiableExpression<Double, Expression<Double>>) {
|
||||||
expression(expression)
|
function(expression)
|
||||||
val gradientFunction = ObjectiveFunctionGradient {
|
val gradientFunction = ObjectiveFunctionGradient {
|
||||||
val args = it.toMap()
|
val args = it.toMap()
|
||||||
DoubleArray(symbols.size) { index ->
|
DoubleArray(symbols.size) { index ->
|
||||||
@ -62,8 +76,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
addOptimizationData(gradientFunction)
|
addOptimizationData(gradientFunction)
|
||||||
if (optimizatorBuilder == null) {
|
if (optimizerBuilder == null) {
|
||||||
optimizatorBuilder = {
|
optimizerBuilder = {
|
||||||
NonLinearConjugateGradientOptimizer(
|
NonLinearConjugateGradientOptimizer(
|
||||||
NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES,
|
NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES,
|
||||||
convergenceChecker
|
convergenceChecker
|
||||||
@ -75,8 +89,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
|||||||
public fun simplex(simplex: AbstractSimplex) {
|
public fun simplex(simplex: AbstractSimplex) {
|
||||||
addOptimizationData(simplex)
|
addOptimizationData(simplex)
|
||||||
//Set optimization builder to simplex if it is not present
|
//Set optimization builder to simplex if it is not present
|
||||||
if (optimizatorBuilder == null) {
|
if (optimizerBuilder == null) {
|
||||||
optimizatorBuilder = { SimplexOptimizer(convergenceChecker) }
|
optimizerBuilder = { SimplexOptimizer(convergenceChecker) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +103,7 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun optimizer(block: () -> MultivariateOptimizer) {
|
public fun optimizer(block: () -> MultivariateOptimizer) {
|
||||||
optimizatorBuilder = block
|
optimizerBuilder = block
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun update(result: OptimizationResult<Double>) {
|
override fun update(result: OptimizationResult<Double>) {
|
||||||
@ -97,19 +111,19 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun optimize(): OptimizationResult<Double> {
|
override fun optimize(): OptimizationResult<Double> {
|
||||||
val optimizer = optimizatorBuilder?.invoke() ?: error("Optimizer not defined")
|
val optimizer = optimizerBuilder?.invoke() ?: error("Optimizer not defined")
|
||||||
val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray())
|
val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray())
|
||||||
return OptimizationResult(point.toMap(), value, setOf(this))
|
return OptimizationResult(point.toMap(), value, setOf(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
public companion object : OptimizationProblemFactory<Double, CMOptimizationProblem> {
|
public companion object : OptimizationProblemFactory<Double, CMOptimization> {
|
||||||
public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4
|
public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4
|
||||||
public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4
|
public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4
|
||||||
public const val DEFAULT_MAX_ITER: Int = 1000
|
public const val DEFAULT_MAX_ITER: Int = 1000
|
||||||
|
|
||||||
override fun build(symbols: List<Symbol>): CMOptimizationProblem = CMOptimizationProblem(symbols)
|
override fun build(symbols: List<Symbol>): CMOptimization = CMOptimization(symbols)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun CMOptimizationProblem.initialGuess(vararg pairs: Pair<Symbol, Double>): Unit = initialGuess(pairs.toMap())
|
public fun CMOptimization.initialGuess(vararg pairs: Pair<Symbol, Double>): Unit = initialGuess(pairs.toMap())
|
||||||
public fun CMOptimizationProblem.simplexSteps(vararg pairs: Pair<Symbol, Double>): Unit = simplexSteps(pairs.toMap())
|
public fun CMOptimization.simplexSteps(vararg pairs: Pair<Symbol, Double>): Unit = simplexSteps(pairs.toMap())
|
@ -6,21 +6,21 @@
|
|||||||
package space.kscience.kmath.commons.optimization
|
package space.kscience.kmath.commons.optimization
|
||||||
|
|
||||||
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
||||||
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType
|
|
||||||
import space.kscience.kmath.commons.expressions.DerivativeStructureField
|
import space.kscience.kmath.commons.expressions.DerivativeStructureField
|
||||||
import space.kscience.kmath.expressions.DifferentiableExpression
|
import space.kscience.kmath.expressions.DifferentiableExpression
|
||||||
import space.kscience.kmath.expressions.Expression
|
import space.kscience.kmath.expressions.Expression
|
||||||
import space.kscience.kmath.expressions.Symbol
|
import space.kscience.kmath.misc.Symbol
|
||||||
import space.kscience.kmath.stat.Fitting
|
import space.kscience.kmath.optimization.FunctionOptimization
|
||||||
import space.kscience.kmath.stat.OptimizationResult
|
import space.kscience.kmath.optimization.OptimizationResult
|
||||||
import space.kscience.kmath.stat.optimizeWith
|
import space.kscience.kmath.optimization.noDerivOptimizeWith
|
||||||
|
import space.kscience.kmath.optimization.optimizeWith
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.asBuffer
|
import space.kscience.kmath.structures.asBuffer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
|
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
|
||||||
*/
|
*/
|
||||||
public fun Fitting.chiSquared(
|
public fun FunctionOptimization.Companion.chiSquared(
|
||||||
x: Buffer<Double>,
|
x: Buffer<Double>,
|
||||||
y: Buffer<Double>,
|
y: Buffer<Double>,
|
||||||
yErr: Buffer<Double>,
|
yErr: Buffer<Double>,
|
||||||
@ -30,7 +30,7 @@ public fun Fitting.chiSquared(
|
|||||||
/**
|
/**
|
||||||
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
|
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
|
||||||
*/
|
*/
|
||||||
public fun Fitting.chiSquared(
|
public fun FunctionOptimization.Companion.chiSquared(
|
||||||
x: Iterable<Double>,
|
x: Iterable<Double>,
|
||||||
y: Iterable<Double>,
|
y: Iterable<Double>,
|
||||||
yErr: Iterable<Double>,
|
yErr: Iterable<Double>,
|
||||||
@ -48,25 +48,26 @@ public fun Fitting.chiSquared(
|
|||||||
*/
|
*/
|
||||||
public fun Expression<Double>.optimize(
|
public fun Expression<Double>.optimize(
|
||||||
vararg symbols: Symbol,
|
vararg symbols: Symbol,
|
||||||
configuration: CMOptimizationProblem.() -> Unit,
|
configuration: CMOptimization.() -> Unit,
|
||||||
): OptimizationResult<Double> = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration)
|
): OptimizationResult<Double> = noDerivOptimizeWith(CMOptimization, symbols = symbols, configuration)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optimize differentiable expression
|
* Optimize differentiable expression
|
||||||
*/
|
*/
|
||||||
public fun DifferentiableExpression<Double, Expression<Double>>.optimize(
|
public fun DifferentiableExpression<Double, Expression<Double>>.optimize(
|
||||||
vararg symbols: Symbol,
|
vararg symbols: Symbol,
|
||||||
configuration: CMOptimizationProblem.() -> Unit,
|
configuration: CMOptimization.() -> Unit,
|
||||||
): OptimizationResult<Double> = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration)
|
): OptimizationResult<Double> = optimizeWith(CMOptimization, symbols = symbols, configuration)
|
||||||
|
|
||||||
public fun DifferentiableExpression<Double, Expression<Double>>.minimize(
|
public fun DifferentiableExpression<Double, Expression<Double>>.minimize(
|
||||||
vararg startPoint: Pair<Symbol, Double>,
|
vararg startPoint: Pair<Symbol, Double>,
|
||||||
configuration: CMOptimizationProblem.() -> Unit = {},
|
configuration: CMOptimization.() -> Unit = {},
|
||||||
): OptimizationResult<Double> {
|
): OptimizationResult<Double> {
|
||||||
require(startPoint.isNotEmpty()) { "Must provide a list of symbols for optimization" }
|
val symbols = startPoint.map { it.first }.toTypedArray()
|
||||||
val problem = CMOptimizationProblem(startPoint.map { it.first }).apply(configuration)
|
return optimize(*symbols){
|
||||||
problem.diffExpression(this)
|
maximize = false
|
||||||
problem.initialGuess(startPoint.toMap())
|
initialGuess(startPoint.toMap())
|
||||||
problem.goal(GoalType.MINIMIZE)
|
diffFunction(this@minimize)
|
||||||
return problem.optimize()
|
configuration()
|
||||||
|
}
|
||||||
}
|
}
|
@ -15,6 +15,7 @@ import space.kscience.kmath.streaming.spread
|
|||||||
import space.kscience.kmath.structures.*
|
import space.kscience.kmath.structures.*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Streaming and buffer transformations
|
* Streaming and buffer transformations
|
||||||
*/
|
*/
|
||||||
@ -22,7 +23,7 @@ public object Transformations {
|
|||||||
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
|
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
|
||||||
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
|
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
|
||||||
|
|
||||||
private fun Buffer<Double>.asArray() = if (this is RealBuffer) {
|
private fun Buffer<Double>.asArray() = if (this is DoubleBuffer) {
|
||||||
array
|
array
|
||||||
} else {
|
} else {
|
||||||
DoubleArray(size) { i -> get(i) }
|
DoubleArray(size) { i -> get(i) }
|
||||||
@ -38,34 +39,34 @@ public object Transformations {
|
|||||||
|
|
||||||
public fun fourier(
|
public fun fourier(
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Complex, Complex> = {
|
): SuspendBufferTransform<Complex, Complex> = {
|
||||||
FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer()
|
FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun realFourier(
|
public fun realFourier(
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Double, Complex> = {
|
): SuspendBufferTransform<Double, Complex> = {
|
||||||
FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun sine(
|
public fun sine(
|
||||||
normalization: DstNormalization = DstNormalization.STANDARD_DST_I,
|
normalization: DstNormalization = DstNormalization.STANDARD_DST_I,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Double, Double> = {
|
): SuspendBufferTransform<Double, Double> = {
|
||||||
FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun cosine(
|
public fun cosine(
|
||||||
normalization: DctNormalization = DctNormalization.STANDARD_DCT_I,
|
normalization: DctNormalization = DctNormalization.STANDARD_DCT_I,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Double, Double> = {
|
): SuspendBufferTransform<Double, Double> = {
|
||||||
FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun hadamard(
|
public fun hadamard(
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): SuspendBufferTransform<Double, Double> = {
|
): SuspendBufferTransform<Double, Double> = {
|
||||||
FastHadamardTransformer().transform(it.asArray(), direction).asBuffer()
|
FastHadamardTransformer().transform(it.asArray(), direction).asBuffer()
|
||||||
}
|
}
|
||||||
@ -77,7 +78,7 @@ public object Transformations {
|
|||||||
@FlowPreview
|
@FlowPreview
|
||||||
public fun Flow<Buffer<Complex>>.FFT(
|
public fun Flow<Buffer<Complex>>.FFT(
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): Flow<Buffer<Complex>> {
|
): Flow<Buffer<Complex>> {
|
||||||
val transform = Transformations.fourier(normalization, direction)
|
val transform = Transformations.fourier(normalization, direction)
|
||||||
return map { transform(it) }
|
return map { transform(it) }
|
||||||
@ -87,7 +88,7 @@ public fun Flow<Buffer<Complex>>.FFT(
|
|||||||
@JvmName("realFFT")
|
@JvmName("realFFT")
|
||||||
public fun Flow<Buffer<Double>>.FFT(
|
public fun Flow<Buffer<Double>>.FFT(
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): Flow<Buffer<Complex>> {
|
): Flow<Buffer<Complex>> {
|
||||||
val transform = Transformations.realFourier(normalization, direction)
|
val transform = Transformations.realFourier(normalization, direction)
|
||||||
return map(transform)
|
return map(transform)
|
||||||
@ -101,7 +102,7 @@ public fun Flow<Buffer<Double>>.FFT(
|
|||||||
public fun Flow<Double>.FFT(
|
public fun Flow<Double>.FFT(
|
||||||
bufferSize: Int = Int.MAX_VALUE,
|
bufferSize: Int = Int.MAX_VALUE,
|
||||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||||
direction: TransformType = TransformType.FORWARD
|
direction: TransformType = TransformType.FORWARD,
|
||||||
): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread()
|
): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,11 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.commons.expressions
|
package space.kscience.kmath.commons.expressions
|
||||||
|
|
||||||
import space.kscience.kmath.expressions.*
|
import space.kscience.kmath.expressions.binding
|
||||||
|
import space.kscience.kmath.expressions.derivative
|
||||||
|
import space.kscience.kmath.expressions.invoke
|
||||||
|
import space.kscience.kmath.misc.Symbol
|
||||||
|
import space.kscience.kmath.misc.symbol
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@ -28,7 +32,7 @@ internal class AutoDiffTest {
|
|||||||
@Test
|
@Test
|
||||||
fun derivativeStructureFieldTest() {
|
fun derivativeStructureFieldTest() {
|
||||||
diff(2, x to 1.0, y to 1.0) {
|
diff(2, x to 1.0, y to 1.0) {
|
||||||
val x = bind(x)//by binding()
|
val x = bindSymbol(x)//by binding()
|
||||||
val y = bindSymbol("y")
|
val y = bindSymbol("y")
|
||||||
val z = x * (-sin(x * y) + y) + 2.0
|
val z = x * (-sin(x * y) + y) + 2.0
|
||||||
println(z.derivative(x))
|
println(z.derivative(x))
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
}
|
@ -5,21 +5,22 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.commons.optimization
|
package space.kscience.kmath.commons.optimization
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test
|
import kotlinx.coroutines.runBlocking
|
||||||
import space.kscience.kmath.commons.expressions.DerivativeStructureExpression
|
import space.kscience.kmath.commons.expressions.DerivativeStructureExpression
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.distributions.NormalDistribution
|
||||||
import space.kscience.kmath.stat.Distribution
|
import space.kscience.kmath.misc.symbol
|
||||||
import space.kscience.kmath.stat.Fitting
|
import space.kscience.kmath.optimization.FunctionOptimization
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.stat.normal
|
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
internal class OptimizeTest {
|
internal class OptimizeTest {
|
||||||
val x by symbol
|
val x by symbol
|
||||||
val y by symbol
|
val y by symbol
|
||||||
|
|
||||||
val normal = DerivativeStructureExpression {
|
val normal = DerivativeStructureExpression {
|
||||||
exp(-bind(x).pow(2) / 2) + exp(-bind(y).pow(2) / 2)
|
exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y)
|
||||||
|
.pow(2) / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -39,35 +40,35 @@ internal class OptimizeTest {
|
|||||||
simplexSteps(x to 2.0, y to 0.5)
|
simplexSteps(x to 2.0, y to 0.5)
|
||||||
//this sets simplex optimizer
|
//this sets simplex optimizer
|
||||||
}
|
}
|
||||||
|
|
||||||
println(result.point)
|
println(result.point)
|
||||||
println(result.value)
|
println(result.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCmFit() {
|
fun testCmFit() = runBlocking {
|
||||||
val a by symbol
|
val a by symbol
|
||||||
val b by symbol
|
val b by symbol
|
||||||
val c by symbol
|
val c by symbol
|
||||||
|
|
||||||
val sigma = 1.0
|
val sigma = 1.0
|
||||||
val generator = Distribution.normal(0.0, sigma)
|
val generator = NormalDistribution(0.0, sigma)
|
||||||
val chain = generator.sample(RandomGenerator.default(112667))
|
val chain = generator.sample(RandomGenerator.default(112667))
|
||||||
val x = (1..100).map(Int::toDouble)
|
val x = (1..100).map(Int::toDouble)
|
||||||
|
|
||||||
val y = x.map {
|
val y = x.map {
|
||||||
it.pow(2) + it + 1 + chain.nextDouble()
|
it.pow(2) + it + 1 + chain.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
val yErr = List(x.size) { sigma }
|
val yErr = List(x.size) { sigma }
|
||||||
|
|
||||||
val chi2 = Fitting.chiSquared(x, y, yErr) { x1 ->
|
val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 ->
|
||||||
val cWithDefault = bindSymbolOrNull(c) ?: one
|
val cWithDefault = bindSymbolOrNull(c) ?: one
|
||||||
bind(a) * x1.pow(2) + bind(b) * x1 + cWithDefault
|
bindSymbol(a) * x1.pow(2) + bindSymbol(b) * x1 + cWithDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = chi2.minimize(a to 1.5, b to 0.9, c to 1.0)
|
val result = chi2.minimize(a to 1.5, b to 0.9, c to 1.0)
|
||||||
println(result)
|
println(result)
|
||||||
println("Chi2/dof = ${result.value / (x.size - 3)}")
|
println("Chi2/dof = ${result.value / (x.size - 3)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,42 +1,36 @@
|
|||||||
# The Core Module (`kmath-core`)
|
# Module kmath-complex
|
||||||
|
|
||||||
Complex and hypercomplex number systems in KMath:
|
Complex and hypercomplex number systems in KMath.
|
||||||
|
|
||||||
- [complex](src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
- [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||||
- [quaternion](src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
- [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||||
|
|
||||||
|
|
||||||
> #### Artifact:
|
## Artifact:
|
||||||
>
|
|
||||||
> This module artifact: `space.kscience:kmath-complex:0.3.0-dev-2`.
|
The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-6`.
|
||||||
>
|
|
||||||
> 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)
|
**Gradle:**
|
||||||
>
|
```gradle
|
||||||
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-complex/_latestVersion)
|
repositories {
|
||||||
>
|
maven { url 'https://repo.kotlin.link' }
|
||||||
> **Gradle:**
|
maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||||
>
|
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||||
> ```gradle
|
}
|
||||||
> repositories {
|
|
||||||
> maven { url 'https://repo.kotlin.link' }
|
dependencies {
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
implementation 'space.kscience:kmath-complex:0.3.0-dev-6'
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
}
|
||||||
> }
|
```
|
||||||
>
|
**Gradle Kotlin DSL:**
|
||||||
> dependencies {
|
```kotlin
|
||||||
> implementation 'space.kscience:kmath-complex:0.3.0-dev-2'
|
repositories {
|
||||||
> }
|
maven("https://repo.kotlin.link")
|
||||||
> ```
|
maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> **Gradle Kotlin DSL:**
|
maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
>
|
}
|
||||||
> ```kotlin
|
|
||||||
> repositories {
|
dependencies {
|
||||||
> maven("https://repo.kotlin.link")
|
implementation("space.kscience:kmath-complex:0.3.0-dev-6")
|
||||||
> 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-complex:0.3.0-dev-2")
|
|
||||||
> }
|
|
||||||
> ```
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
|
import ru.mipt.npm.gradle.Maturity
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2018-2021 KMath contributors.
|
* Copyright 2018-2021 KMath contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ru.mipt.npm.gradle.Maturity
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.gradle.mpp")
|
kotlin("multiplatform")
|
||||||
|
id("ru.mipt.npm.gradle.common")
|
||||||
id("ru.mipt.npm.gradle.native")
|
id("ru.mipt.npm.gradle.native")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,12 +31,12 @@ readme {
|
|||||||
feature(
|
feature(
|
||||||
id = "complex",
|
id = "complex",
|
||||||
description = "Complex Numbers",
|
description = "Complex Numbers",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/complex/Complex.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "quaternion",
|
id = "quaternion",
|
||||||
description = "Quaternions",
|
description = "Quaternions",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# The Core Module (`kmath-core`)
|
# Module kmath-complex
|
||||||
|
|
||||||
Complex and hypercomplex number systems in KMath:
|
Complex and hypercomplex number systems in KMath.
|
||||||
|
|
||||||
${features}
|
${features}
|
||||||
|
|
||||||
|
@ -126,8 +126,8 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Num
|
|||||||
/**
|
/**
|
||||||
* Adds complex number to real one.
|
* Adds complex number to real one.
|
||||||
*
|
*
|
||||||
* @receiver the addend.
|
* @receiver the augend.
|
||||||
* @param c the augend.
|
* @param c the addend.
|
||||||
* @return the sum.
|
* @return the sum.
|
||||||
*/
|
*/
|
||||||
public operator fun Double.plus(c: Complex): Complex = add(this.toComplex(), c)
|
public operator fun Double.plus(c: Complex): Complex = add(this.toComplex(), c)
|
||||||
@ -144,8 +144,8 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Num
|
|||||||
/**
|
/**
|
||||||
* Adds real number to complex one.
|
* Adds real number to complex one.
|
||||||
*
|
*
|
||||||
* @receiver the addend.
|
* @receiver the augend.
|
||||||
* @param d the augend.
|
* @param d the addend.
|
||||||
* @return the sum.
|
* @return the sum.
|
||||||
*/
|
*/
|
||||||
public operator fun Complex.plus(d: Double): Complex = d + this
|
public operator fun Complex.plus(d: Double): Complex = d + this
|
||||||
@ -170,8 +170,7 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Num
|
|||||||
|
|
||||||
public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
|
public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
|
||||||
|
|
||||||
public override fun bindSymbol(value: String): Complex =
|
public override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null
|
||||||
if (value == "i") i else super<ExtendedField>.bindSymbol(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
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
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optimized nd-field for complex numbers
|
||||||
|
*/
|
||||||
|
@OptIn(UnstableKMathAPI::class)
|
||||||
|
public class ComplexFieldND(
|
||||||
|
shape: IntArray,
|
||||||
|
) : BufferedFieldND<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
|
||||||
|
NumbersAddOperations<StructureND<Complex>>,
|
||||||
|
ExtendedField<StructureND<Complex>> {
|
||||||
|
|
||||||
|
public override val zero: BufferND<Complex> by lazy { produce { zero } }
|
||||||
|
public override val one: BufferND<Complex> by lazy { produce { one } }
|
||||||
|
|
||||||
|
public override fun number(value: Number): BufferND<Complex> {
|
||||||
|
val d = value.toComplex() // minimize conversions
|
||||||
|
return produce { d }
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
// override inline fun map(
|
||||||
|
// arg: AbstractNDBuffer<Double>,
|
||||||
|
// transform: DoubleField.(Double) -> Double,
|
||||||
|
// ): RealNDElement {
|
||||||
|
// check(arg)
|
||||||
|
// 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: DoubleField.(IntArray) -> Double): RealNDElement {
|
||||||
|
// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
||||||
|
// return BufferedNDFieldElement(this, array)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
// override inline fun mapIndexed(
|
||||||
|
// arg: AbstractNDBuffer<Double>,
|
||||||
|
// transform: DoubleField.(index: IntArray, Double) -> Double,
|
||||||
|
// ): RealNDElement {
|
||||||
|
// check(arg)
|
||||||
|
// return BufferedNDFieldElement(
|
||||||
|
// this,
|
||||||
|
// RealBuffer(arg.strides.linearSize) { offset ->
|
||||||
|
// elementContext.transform(
|
||||||
|
// arg.strides.index(offset),
|
||||||
|
// arg.buffer[offset]
|
||||||
|
// )
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
// override inline fun combine(
|
||||||
|
// a: AbstractNDBuffer<Double>,
|
||||||
|
// b: AbstractNDBuffer<Double>,
|
||||||
|
// transform: DoubleField.(Double, Double) -> Double,
|
||||||
|
// ): RealNDElement {
|
||||||
|
// check(a, b)
|
||||||
|
// val buffer = RealBuffer(strides.linearSize) { offset ->
|
||||||
|
// elementContext.transform(a.buffer[offset], b.buffer[offset])
|
||||||
|
// }
|
||||||
|
// return BufferedNDFieldElement(this, buffer)
|
||||||
|
// }
|
||||||
|
|
||||||
|
public override fun power(arg: StructureND<Complex>, pow: Number): BufferND<Complex> = arg.map { power(it, pow) }
|
||||||
|
|
||||||
|
public override fun exp(arg: StructureND<Complex>): BufferND<Complex> = arg.map { exp(it) }
|
||||||
|
|
||||||
|
public override fun ln(arg: StructureND<Complex>): BufferND<Complex> = arg.map { ln(it) }
|
||||||
|
|
||||||
|
public override fun sin(arg: StructureND<Complex>): BufferND<Complex> = arg.map { sin(it) }
|
||||||
|
public override fun cos(arg: StructureND<Complex>): BufferND<Complex> = arg.map { cos(it) }
|
||||||
|
public override fun tan(arg: StructureND<Complex>): BufferND<Complex> = arg.map { tan(it) }
|
||||||
|
public override fun asin(arg: StructureND<Complex>): BufferND<Complex> = arg.map { asin(it) }
|
||||||
|
public override fun acos(arg: StructureND<Complex>): BufferND<Complex> = arg.map { acos(it) }
|
||||||
|
public override fun atan(arg: StructureND<Complex>): BufferND<Complex> = arg.map { atan(it) }
|
||||||
|
|
||||||
|
public override fun sinh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { sinh(it) }
|
||||||
|
public override fun cosh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { cosh(it) }
|
||||||
|
public override fun tanh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { tanh(it) }
|
||||||
|
public override fun asinh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { asinh(it) }
|
||||||
|
public override fun acosh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { acosh(it) }
|
||||||
|
public override fun atanh(arg: StructureND<Complex>): BufferND<Complex> = arg.map { atanh(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fast element production using function inlining
|
||||||
|
*/
|
||||||
|
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 BufferND(strides, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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: ComplexFieldND.() -> R): R {
|
||||||
|
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||||
|
return ComplexFieldND(shape).action()
|
||||||
|
}
|
@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2018-2021 KMath contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package space.kscience.kmath.complex
|
|
||||||
|
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
|
||||||
import space.kscience.kmath.nd.BufferedNDField
|
|
||||||
import space.kscience.kmath.nd.NDAlgebra
|
|
||||||
import space.kscience.kmath.nd.NDBuffer
|
|
||||||
import space.kscience.kmath.nd.NDStructure
|
|
||||||
import space.kscience.kmath.operations.ExtendedField
|
|
||||||
import space.kscience.kmath.operations.NumbersAddOperations
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
|
||||||
import kotlin.contracts.InvocationKind
|
|
||||||
import kotlin.contracts.contract
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An optimized nd-field for complex numbers
|
|
||||||
*/
|
|
||||||
@OptIn(UnstableKMathAPI::class)
|
|
||||||
public class ComplexNDField(
|
|
||||||
shape: IntArray,
|
|
||||||
) : BufferedNDField<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
|
|
||||||
NumbersAddOperations<NDStructure<Complex>>,
|
|
||||||
ExtendedField<NDStructure<Complex>> {
|
|
||||||
|
|
||||||
override val zero: NDBuffer<Complex> by lazy { produce { zero } }
|
|
||||||
override val one: NDBuffer<Complex> by lazy { produce { one } }
|
|
||||||
|
|
||||||
override fun number(value: Number): NDBuffer<Complex> {
|
|
||||||
val d = value.toComplex() // minimize conversions
|
|
||||||
return produce { d }
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
|
||||||
// override inline fun map(
|
|
||||||
// arg: AbstractNDBuffer<Double>,
|
|
||||||
// transform: RealField.(Double) -> Double,
|
|
||||||
// ): RealNDElement {
|
|
||||||
// check(arg)
|
|
||||||
// val array = RealBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) }
|
|
||||||
// return BufferedNDFieldElement(this, array)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
|
||||||
// override inline fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement {
|
|
||||||
// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
|
||||||
// return BufferedNDFieldElement(this, array)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
|
||||||
// override inline fun mapIndexed(
|
|
||||||
// arg: AbstractNDBuffer<Double>,
|
|
||||||
// transform: RealField.(index: IntArray, Double) -> Double,
|
|
||||||
// ): RealNDElement {
|
|
||||||
// check(arg)
|
|
||||||
// return BufferedNDFieldElement(
|
|
||||||
// this,
|
|
||||||
// RealBuffer(arg.strides.linearSize) { offset ->
|
|
||||||
// elementContext.transform(
|
|
||||||
// arg.strides.index(offset),
|
|
||||||
// arg.buffer[offset]
|
|
||||||
// )
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
|
||||||
// override inline fun combine(
|
|
||||||
// a: AbstractNDBuffer<Double>,
|
|
||||||
// b: AbstractNDBuffer<Double>,
|
|
||||||
// transform: RealField.(Double, Double) -> Double,
|
|
||||||
// ): RealNDElement {
|
|
||||||
// check(a, b)
|
|
||||||
// val buffer = RealBuffer(strides.linearSize) { offset ->
|
|
||||||
// elementContext.transform(a.buffer[offset], b.buffer[offset])
|
|
||||||
// }
|
|
||||||
// return BufferedNDFieldElement(this, buffer)
|
|
||||||
// }
|
|
||||||
|
|
||||||
override fun power(arg: NDStructure<Complex>, pow: Number): NDBuffer<Complex> = arg.map { power(it, pow) }
|
|
||||||
|
|
||||||
override fun exp(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { exp(it) }
|
|
||||||
|
|
||||||
override fun ln(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { ln(it) }
|
|
||||||
|
|
||||||
override fun sin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { sin(it) }
|
|
||||||
override fun cos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { cos(it) }
|
|
||||||
override fun tan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { tan(it) }
|
|
||||||
override fun asin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { asin(it) }
|
|
||||||
override fun acos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { acos(it) }
|
|
||||||
override fun atan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { atan(it) }
|
|
||||||
|
|
||||||
override fun sinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { sinh(it) }
|
|
||||||
override fun cosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { cosh(it) }
|
|
||||||
override fun tanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { tanh(it) }
|
|
||||||
override fun asinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { asinh(it) }
|
|
||||||
override fun acosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { acosh(it) }
|
|
||||||
override fun atanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { atanh(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fast element production using function inlining
|
|
||||||
*/
|
|
||||||
public inline fun BufferedNDField<Complex, ComplexField>.produceInline(initializer: ComplexField.(Int) -> Complex): NDBuffer<Complex> {
|
|
||||||
contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) }
|
|
||||||
return NDBuffer(strides, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public fun NDAlgebra.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Produce a context for n-dimensional operations inside this real field
|
|
||||||
*/
|
|
||||||
public inline fun <R> ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R {
|
|
||||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
|
||||||
return ComplexNDField(shape).action()
|
|
||||||
}
|
|
@ -170,11 +170,11 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Quaternion>,
|
|||||||
public override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z)
|
public override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z)
|
||||||
public override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg)
|
public override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg)
|
||||||
|
|
||||||
public override fun bindSymbol(value: String): Quaternion = when (value) {
|
public override fun bindSymbolOrNull(value: String): Quaternion? = when (value) {
|
||||||
"i" -> i
|
"i" -> i
|
||||||
"j" -> j
|
"j" -> j
|
||||||
"k" -> k
|
"k" -> k
|
||||||
else -> super<Field>.bindSymbol(value)
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun number(value: Number): Quaternion = value.toQuaternion()
|
override fun number(value: Number): Quaternion = value.toQuaternion()
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
package space.kscience.kmath.complex
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
import space.kscience.kmath.expressions.FunctionalExpressionField
|
import space.kscience.kmath.expressions.FunctionalExpressionField
|
||||||
import space.kscience.kmath.expressions.bindSymbol
|
|
||||||
import space.kscience.kmath.expressions.invoke
|
import space.kscience.kmath.expressions.invoke
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.misc.symbol
|
||||||
|
import space.kscience.kmath.operations.bindSymbol
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -1,49 +1,43 @@
|
|||||||
# The Core Module (`kmath-core`)
|
# Module kmath-core
|
||||||
|
|
||||||
The core features of KMath:
|
The core interfaces of KMath.
|
||||||
|
|
||||||
- [algebras](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
- [algebras](src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||||
- [nd](src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
|
- [nd](src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
|
||||||
- [linear](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
- [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/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
- [buffers](src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||||
- [expressions](src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
- [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
|
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||||
performance calculations to code generation.
|
performance calculations to code generation.
|
||||||
- [domains](src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
- [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
|
||||||
- [autodif](src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
- [autodif](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||||
|
|
||||||
|
|
||||||
> #### Artifact:
|
## Artifact:
|
||||||
>
|
|
||||||
> This module artifact: `space.kscience:kmath-core:0.3.0-dev-2`.
|
The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-6`.
|
||||||
>
|
|
||||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
**Gradle:**
|
||||||
>
|
```gradle
|
||||||
> 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)
|
repositories {
|
||||||
>
|
maven { url 'https://repo.kotlin.link' }
|
||||||
> **Gradle:**
|
maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||||
>
|
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||||
> ```gradle
|
}
|
||||||
> repositories {
|
|
||||||
> maven { url 'https://repo.kotlin.link' }
|
dependencies {
|
||||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
implementation 'space.kscience:kmath-core:0.3.0-dev-6'
|
||||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
}
|
||||||
> }
|
```
|
||||||
>
|
**Gradle Kotlin DSL:**
|
||||||
> dependencies {
|
```kotlin
|
||||||
> implementation 'space.kscience:kmath-core:0.3.0-dev-2'
|
repositories {
|
||||||
> }
|
maven("https://repo.kotlin.link")
|
||||||
> ```
|
maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||||
> **Gradle Kotlin DSL:**
|
maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||||
>
|
}
|
||||||
> ```kotlin
|
|
||||||
> repositories {
|
dependencies {
|
||||||
> maven("https://repo.kotlin.link")
|
implementation("space.kscience:kmath-core:0.3.0-dev-6")
|
||||||
> 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-2")
|
|
||||||
> }
|
|
||||||
> ```
|
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
import ru.mipt.npm.gradle.Maturity
|
import ru.mipt.npm.gradle.Maturity
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.gradle.mpp")
|
kotlin("multiplatform")
|
||||||
|
id("ru.mipt.npm.gradle.common")
|
||||||
id("ru.mipt.npm.gradle.native")
|
id("ru.mipt.npm.gradle.native")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,13 +29,13 @@ readme {
|
|||||||
description = """
|
description = """
|
||||||
Algebraic structures like rings, spaces and fields.
|
Algebraic structures like rings, spaces and fields.
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "nd",
|
id = "nd",
|
||||||
description = "Many-dimensional structures and operations on them.",
|
description = "Many-dimensional structures and operations on them.",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
@ -42,13 +43,13 @@ readme {
|
|||||||
description = """
|
description = """
|
||||||
Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "buffers",
|
id = "buffers",
|
||||||
description = "One-dimensional structure",
|
description = "One-dimensional structure",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
@ -58,18 +59,18 @@ readme {
|
|||||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||||
performance calculations to code generation.
|
performance calculations to code generation.
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/expressions"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/expressions"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "domains",
|
id = "domains",
|
||||||
description = "Domains",
|
description = "Domains",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/domains"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/domains"
|
||||||
)
|
)
|
||||||
|
|
||||||
feature(
|
feature(
|
||||||
id = "autodif",
|
id = "autodif",
|
||||||
description = "Automatic differentiation",
|
description = "Automatic differentiation",
|
||||||
ref = "src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt"
|
ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# The Core Module (`kmath-core`)
|
# Module kmath-core
|
||||||
|
|
||||||
The core features of KMath:
|
The core interfaces of KMath.
|
||||||
|
|
||||||
${features}
|
${features}
|
||||||
|
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.data
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.Symbol
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
import space.kscience.kmath.nd.Structure2D
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A column-based data set with all columns of the same size (not necessary fixed in time).
|
||||||
|
* The column could be retrieved by a [get] operation.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public interface ColumnarData<out T> {
|
||||||
|
public val size: Int
|
||||||
|
|
||||||
|
public operator fun get(symbol: Symbol): Buffer<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A zero-copy method to represent a [Structure2D] as a two-column x-y data.
|
||||||
|
* There could more than two columns in the structure.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <T> Structure2D<T>.asColumnarData(mapping: Map<Symbol, Int>): ColumnarData<T> {
|
||||||
|
require(shape[1] >= mapping.maxOf { it.value }) { "Column index out of bounds" }
|
||||||
|
return object : ColumnarData<T> {
|
||||||
|
override val size: Int get() = shape[0]
|
||||||
|
override fun get(symbol: Symbol): Buffer<T> {
|
||||||
|
val index = mapping[symbol] ?: error("No column mapping for symbol $symbol")
|
||||||
|
return columns[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|