1
.github/workflows/build.yml
vendored
@ -8,6 +8,7 @@ jobs:
|
||||
matrix:
|
||||
os: [ macOS-latest, windows-latest ]
|
||||
runs-on: ${{matrix.os}}
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v2
|
||||
|
2
.github/workflows/publish.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
name: publish
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macOS-latest, windows-latest]
|
||||
os: [ macOS-latest, windows-latest ]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
|
4
.gitignore
vendored
@ -1,7 +1,11 @@
|
||||
.gradle
|
||||
build/
|
||||
out/
|
||||
|
||||
.idea/
|
||||
|
||||
!.idea/copyright/
|
||||
|
||||
.vscode/
|
||||
|
||||
# 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
|
||||
- ScaleOperations interface
|
||||
- Field extends ScaleOperations
|
||||
- Basic integration API
|
||||
- Basic MPP distributions and samplers
|
||||
- bindSymbolOrNull
|
||||
- Blocking chains and Statistics
|
||||
- Multiplatform integration
|
||||
- Integration for any Field element
|
||||
|
||||
### Changed
|
||||
- Exponential operations merged with hyperbolic functions
|
||||
- Space is replaced by Group. Space is reserved for vector spaces.
|
||||
- VectorSpace is now a vector space
|
||||
- Buffer factories for primitives moved to MutableBuffer.Companion
|
||||
- NDStructure and NDAlgebra to StructureND and AlgebraND respectively
|
||||
- Real -> Double
|
||||
- DataSets are moved from functions to core
|
||||
- Redesign advanced Chain API
|
||||
- Redesign MST. Remove MSTExpression.
|
||||
- Move MST to core
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
- Nearest in Domain. To be implemented in geometry package.
|
||||
- Number multiplication and division in main Algebra chain
|
||||
- `contentEquals` from Buffer. It moved to the companion.
|
||||
- MSTExpression
|
||||
|
||||
### Fixed
|
||||
- Ring inherits RingOperations, not GroupOperations
|
||||
|
||||
### Security
|
||||
|
||||
@ -73,6 +88,7 @@
|
||||
- `toGrid` method.
|
||||
- Public visibility of `BufferAccessor2D`
|
||||
- `Real` class
|
||||
- StructureND identity and equals
|
||||
|
||||
### Fixed
|
||||
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
|
||||
|
74
README.md
@ -1,9 +1,8 @@
|
||||
[![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)
|
||||
|
||||
![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%20AND%20a:%22kmath-core%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)
|
||||
[![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
|
||||
|
||||
@ -89,12 +88,12 @@ KMath is a modular library. Different modules provide different features with di
|
||||
> **Maturity**: PROTOTYPE
|
||||
>
|
||||
> **Features:**
|
||||
> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -110,8 +109,8 @@ KMath is a modular library. Different modules provide different features with di
|
||||
> **Maturity**: PROTOTYPE
|
||||
>
|
||||
> **Features:**
|
||||
> - [complex](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||
> - [quaternion](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||
> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -121,15 +120,15 @@ KMath is a modular library. Different modules provide different features with di
|
||||
> **Maturity**: DEVELOPMENT
|
||||
>
|
||||
> **Features:**
|
||||
> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||
> - [nd](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
|
||||
> - [linear](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
> - [buffers](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||
> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||
> - [algebras](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||
> - [nd](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
|
||||
> - [linear](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
> - [buffers](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||
> - [expressions](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||
performance calculations to code generation.
|
||||
> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
||||
> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||
> - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
|
||||
> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -149,6 +148,12 @@ performance calculations to code generation.
|
||||
>
|
||||
>
|
||||
> **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/>
|
||||
|
||||
* ### [kmath-for-real](kmath-for-real)
|
||||
@ -159,22 +164,23 @@ One can still use generic algebras though.
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
>
|
||||
> **Features:**
|
||||
> - [RealVector](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealVector.kt) : Numpy-like operations for Buffers/Points
|
||||
> - [RealMatrix](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt) : Numpy-like operations for 2d real structures
|
||||
> - [grids](kmath-for-real/src/commonMain/kotlin/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
||||
> - [DoubleVector](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points
|
||||
> - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures
|
||||
> - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators
|
||||
|
||||
<hr/>
|
||||
|
||||
* ### [kmath-functions](kmath-functions)
|
||||
> Functions and interpolation
|
||||
> Functions, integration and interpolation
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
>
|
||||
> **Features:**
|
||||
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt
|
||||
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt
|
||||
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt
|
||||
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt
|
||||
> - [piecewise](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt) : Piecewise functions.
|
||||
> - [polynomials](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Polynomial functions.
|
||||
> - [linear interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt) : Linear XY interpolator.
|
||||
> - [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/>
|
||||
|
||||
@ -208,9 +214,9 @@ One can still use generic algebras though.
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
>
|
||||
> **Features:**
|
||||
> - [nd4jarraystructure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray
|
||||
> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long
|
||||
> - [nd4jarrayfields](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : Fields over Nd4jArrayStructure of Float and Double
|
||||
> - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
|
||||
> - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long
|
||||
> - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double
|
||||
|
||||
<hr/>
|
||||
|
||||
@ -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
|
||||
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
|
||||
|
||||
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 {
|
||||
api("space.kscience:kmath-core:0.3.0-dev-2")
|
||||
// api("space.kscience:kmath-core-jvm:0.3.0-dev-2") for jvm-specific version
|
||||
api("space.kscience:kmath-core:0.3.0-dev-6")
|
||||
// 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.
|
||||
*/
|
||||
|
||||
import ru.mipt.npm.gradle.KSciencePublishingPlugin
|
||||
import org.jetbrains.dokka.gradle.DokkaTask
|
||||
import java.net.URL
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.project")
|
||||
@ -15,21 +16,41 @@ allprojects {
|
||||
maven("https://clojars.org/repo")
|
||||
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
|
||||
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("http://logicrunch.research.it.uu.se/maven/")
|
||||
maven{
|
||||
setUrl("http://logicrunch.research.it.uu.se/maven/")
|
||||
isAllowInsecureProtocol = true
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
group = "space.kscience"
|
||||
version = "0.3.0-dev-2"
|
||||
version = "0.3.0-dev-6"
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -31,7 +31,7 @@ multiplication;
|
||||
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
|
||||
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
|
||||
|
||||
A typical implementation of `Field<T>` is the `RealField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
||||
A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
||||
|
||||
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
|
||||
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot`
|
||||
|
@ -13,27 +13,30 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath24"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path22"
|
||||
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath><clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path34"
|
||||
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
|
||||
id="g10"><g
|
||||
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1299.34,651.602 h 4653.75 v 3208.87 H 1299.34 Z" /><path
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1651.48,1093.71 h 4076.99 v 114.609 H 1651.48 Z" /><g
|
||||
id="g18"><g
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1651.48,1093.71 h 4076.99 v 114.609 H 1651.48 Z"/><g
|
||||
id="g18"><g
|
||||
clip-path="url(#clipPath24)"
|
||||
id="g20"><g
|
||||
transform="matrix(6720,0,0,2810.4,0,1589.6)"
|
||||
@ -45,7 +48,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g30"><g
|
||||
id="g30"><g
|
||||
clip-path="url(#clipPath36)"
|
||||
id="g32"><g
|
||||
transform="matrix(3312,0,0,1591.2,3410,-1.19998)"
|
||||
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 248 KiB |
@ -13,35 +13,37 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath32"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path30"
|
||||
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
|
||||
id="g10"><g
|
||||
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 318.789,2616.17 6643.05,4723.79 c 239.45,79.76 496.44,-48.75 576.29,-288.17 79.8,-239.41 -48.72,-496.4 -288.13,-576.21 L 606.949,1751.84 c -239.449,-79.81 -496.437,48.71 -576.2888,288.12 -79.8008,239.45 48.7187,496.45 288.1288,576.21 z" /><path
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 3751.56,538.199 6636.91,4443.95 c 109.22,147.89 316.21,178.98 464.11,69.76 147.89,-109.22 178.98,-316.21 69.76,-464.06 L 4285.43,143.91 C 4176.17,-3.98047 3969.18,-35.0781 3821.29,74.1406 3673.44,183.359 3642.3,390.309 3751.56,538.199 Z" /><path
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 1400.43,708.48 H 6418.24 V 4168.4 H 1400.43 Z" /><path
|
||||
id="path20"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 6145.16,1753.83 h -358.6 V 3271.02 L 5158.28,1753.83 H 5005 L 4379.69,3271.02 V 1753.83 h -358.6 v 2044.53 h 505.79 l 554.68,-1345.63 557.97,1345.63 h 505.63 z" /><path
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1780.12,1185.24 h 4395.94 v 123.551 H 1780.12 Z" /><path
|
||||
id="path24"
|
||||
style="fill:none;stroke:#000000;stroke-width:22.00740051;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1780.12,3798.09 c 0,-2044.73 0,-2044.73 0,-2044.73 H 3824.84 L 2806.17,2778.24 3824.84,3798.09" /><g
|
||||
id="g26"><g
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 3751.56,538.199 6636.91,4443.95 c 109.22,147.89 316.21,178.98 464.11,69.76 147.89,-109.22 178.98,-316.21 69.76,-464.06 L 4285.43,143.91 C 4176.17,-3.98047 3969.18,-35.0781 3821.29,74.1406 3673.44,183.359 3642.3,390.309 3751.56,538.199 Z"/><path
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 1400.43,708.48 H 6418.24 V 4168.4 H 1400.43 Z"/><path
|
||||
id="path20"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 6145.16,1753.83 h -358.6 V 3271.02 L 5158.28,1753.83 H 5005 L 4379.69,3271.02 V 1753.83 h -358.6 v 2044.53 h 505.79 l 554.68,-1345.63 557.97,1345.63 h 505.63 z"/><path
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1780.12,1185.24 h 4395.94 v 123.551 H 1780.12 Z"/><path
|
||||
id="path24"
|
||||
style="fill:none;stroke:#000000;stroke-width:22.00740051;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1780.12,3798.09 c 0,-2044.73 0,-2044.73 0,-2044.73 H 3824.84 L 2806.17,2778.24 3824.84,3798.09"/><g
|
||||
id="g26"><g
|
||||
clip-path="url(#clipPath32)"
|
||||
id="g28"><g
|
||||
transform="matrix(2052,0,0,2052,1780,1748)"
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@ -13,35 +13,40 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath24"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path22"
|
||||
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath><clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath36"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path34"
|
||||
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath><clipPath
|
||||
id="clipPath48"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath48"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path46"
|
||||
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath><clipPath
|
||||
id="clipPath60"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath60"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path58"
|
||||
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
|
||||
id="g10"><g
|
||||
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 791.328,957.73 h 6401.56 V 3245.31 H 791.328 Z" /><path
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1049.45,1214.42 h 2988.24 v 86.9883 H 1049.45 Z" /><g
|
||||
id="g18"><g
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1049.45,1214.42 h 2988.24 v 86.9883 H 1049.45 Z"/><g
|
||||
id="g18"><g
|
||||
clip-path="url(#clipPath24)"
|
||||
id="g20"><g
|
||||
transform="matrix(6470.4,0,0,1272,0,3008)"
|
||||
@ -53,7 +58,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g30"><g
|
||||
id="g30"><g
|
||||
clip-path="url(#clipPath36)"
|
||||
id="g32"><g
|
||||
transform="matrix(7000.8,0,0,1420.8,0,1589.2)"
|
||||
@ -65,7 +70,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g42"><g
|
||||
id="g42"><g
|
||||
clip-path="url(#clipPath48)"
|
||||
id="g44"><g
|
||||
transform="matrix(6470.4,0,0,12,0,1578)"
|
||||
@ -77,7 +82,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g54"><g
|
||||
id="g54"><g
|
||||
clip-path="url(#clipPath60)"
|
||||
id="g56"><g
|
||||
transform="matrix(3180,0,0,1581.6,3280,-1.59972)"
|
||||
|
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 278 KiB |
@ -13,123 +13,144 @@
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath40"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path38"
|
||||
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath52"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath52"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path50"
|
||||
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath64"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath64"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path62"
|
||||
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath><clipPath
|
||||
id="clipPath76"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath76"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path74"
|
||||
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath88"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath88"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path86"
|
||||
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath100"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath100"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path98"
|
||||
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath><clipPath
|
||||
id="clipPath112"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath112"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path110"
|
||||
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath124"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath124"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path122"
|
||||
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath><clipPath
|
||||
id="clipPath136"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath136"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path134"
|
||||
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath148"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath148"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path146"
|
||||
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath><clipPath
|
||||
id="clipPath160"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath160"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path158"
|
||||
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath172"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath172"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path170"
|
||||
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath184"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath184"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path182"
|
||||
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath><clipPath
|
||||
id="clipPath196"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath196"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path194"
|
||||
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath208"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath208"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path206"
|
||||
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath><clipPath
|
||||
id="clipPath220"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath220"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path218"
|
||||
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath232"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath232"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path230"
|
||||
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath><clipPath
|
||||
id="clipPath244"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath244"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path242"
|
||||
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath256"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath256"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path254"
|
||||
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath><clipPath
|
||||
id="clipPath268"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath>
|
||||
<clipPath
|
||||
id="clipPath268"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path266"
|
||||
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
|
||||
id="g10"><g
|
||||
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs>
|
||||
<g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 265.859,2205.39 5500.51,3949.84 c 198.16,66.06 410.9,-40.31 476.99,-238.51 66.05,-198.17 -40.31,-410.86 -238.48,-476.92 L 504.379,1489.96 c -198.168,-66.05 -410.8985,40.31 -476.9571,238.48 -66.0938,198.16 40.2773,410.9 238.4371,476.95 z" /><path
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3096.33,444.379 2388.2,3232.811 c 90.43,122.38 261.76,148.12 384.18,57.73 122.38,-90.39 148.13,-261.72 57.74,-384.1 L 3538.2,117.969 C 3447.77,-4.41016 3276.45,-30.1602 3154.06,60.2305 3031.64,150.66 3005.9,321.949 3096.33,444.379 Z" /><path
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 734.691,901.211 h 5982.5 v 2109.69 h -5982.5 z" /><path
|
||||
id="path20"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3724.45,1489.53 h -225.93 v 956.09 l -395.94,-956.09 h -96.56 l -394.07,956.09 v -956.09 h -225.93 v 1288.28 h 318.59 l 349.69,-847.97 351.4,847.97 h 318.75 z" /><path
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 4767.23,1489.53 H 4564.41 V 1590 c -72.11,-82.42 -172.5,-123.59 -301.25,-123.59 -85,0 -160.39,27.34 -226.09,82.03 -65.62,54.68 -98.44,130.31 -98.44,226.87 0,99.14 32.5,174.46 97.5,225.94 65.08,51.56 140.78,77.34 227.03,77.34 132.58,0 233.01,-39.92 301.25,-119.68 v 139.06 c 0,54.06 -19.96,96.48 -59.84,127.34 -39.92,30.94 -92.73,46.41 -158.44,46.41 -104.29,0 -196.33,-39.3 -276.09,-117.81 L 3986.91,2295 c 105.63,100.39 236.29,150.62 392.04,150.62 114.68,0 208.04,-27.1 280.15,-81.24 72.07,-54.07 108.13,-139.65 108.13,-256.72 z m -424.85,115.94 c 101.64,0 175.67,32.19 222.03,96.56 v 140.94 c -46.36,64.37 -120.39,96.56 -222.03,96.56 -58.04,0 -105.74,-15.47 -143.12,-46.41 -37.31,-30.85 -55.94,-71.36 -55.94,-121.56 0,-50.23 18.63,-90.47 55.94,-120.78 37.38,-30.23 85.08,-45.31 143.12,-45.31 z" /><path
|
||||
id="path24"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 5308.32,1466.41 c -78.55,0 -138.12,20.58 -178.75,61.71 -40.55,41.26 -60.78,100.47 -60.78,177.66 v 538.91 h -154.53 v 177.65 h 154.53 v 255 h 202.81 v -255 h 189.22 V 2244.69 H 5271.6 v -488.6 c 0,-33.55 7.7,-60.31 23.13,-80.31 15.5,-19.92 37.42,-29.84 65.78,-29.84 41.13,0 71.4,10.94 90.78,32.81 l 48.28,-152.5 c -42.5,-39.88 -106.25,-59.84 -191.25,-59.84 z" /><path
|
||||
id="path26"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 6477.38,1489.53 h -202.65 v 587.19 c 0,68.2 -16.49,116.8 -49.38,145.78 -32.81,28.95 -79.49,43.44 -140,43.44 -47.62,0 -92.65,-12.27 -135.15,-36.72 -42.5,-24.49 -77.31,-54.06 -104.38,-88.75 v -650.94 h -202.66 v 1288.28 h 202.66 V 2295 c 34.77,41.13 81.45,76.48 140,106.09 58.63,29.69 122.07,44.53 190.31,44.53 200.82,0 301.25,-98.55 301.25,-295.62 z" /><path
|
||||
id="path28"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 973.949,1128.48 h 2769.84 v 80.6211 H 973.949 Z" /><path
|
||||
id="path30"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
d="m 978.828,2781.72 c 0,-1292.5 0,-1292.5 0,-1292.5 H 2262.3 l -639.45,647.85 639.45,644.65" /><path
|
||||
id="path32"
|
||||
style="fill:none;stroke:#000000;stroke-width:13.86260033;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 978.828,2781.72 c 0,-1292.5 0,-1292.5 0,-1292.5 H 2262.3 l -639.45,647.85 639.45,644.65" /><g
|
||||
id="g34"><g
|
||||
id="path16"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3096.33,444.379 2388.2,3232.811 c 90.43,122.38 261.76,148.12 384.18,57.73 122.38,-90.39 148.13,-261.72 57.74,-384.1 L 3538.2,117.969 C 3447.77,-4.41016 3276.45,-30.1602 3154.06,60.2305 3031.64,150.66 3005.9,321.949 3096.33,444.379 Z"/><path
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 734.691,901.211 h 5982.5 v 2109.69 h -5982.5 z"/><path
|
||||
id="path20"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3724.45,1489.53 h -225.93 v 956.09 l -395.94,-956.09 h -96.56 l -394.07,956.09 v -956.09 h -225.93 v 1288.28 h 318.59 l 349.69,-847.97 351.4,847.97 h 318.75 z"/><path
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 4767.23,1489.53 H 4564.41 V 1590 c -72.11,-82.42 -172.5,-123.59 -301.25,-123.59 -85,0 -160.39,27.34 -226.09,82.03 -65.62,54.68 -98.44,130.31 -98.44,226.87 0,99.14 32.5,174.46 97.5,225.94 65.08,51.56 140.78,77.34 227.03,77.34 132.58,0 233.01,-39.92 301.25,-119.68 v 139.06 c 0,54.06 -19.96,96.48 -59.84,127.34 -39.92,30.94 -92.73,46.41 -158.44,46.41 -104.29,0 -196.33,-39.3 -276.09,-117.81 L 3986.91,2295 c 105.63,100.39 236.29,150.62 392.04,150.62 114.68,0 208.04,-27.1 280.15,-81.24 72.07,-54.07 108.13,-139.65 108.13,-256.72 z m -424.85,115.94 c 101.64,0 175.67,32.19 222.03,96.56 v 140.94 c -46.36,64.37 -120.39,96.56 -222.03,96.56 -58.04,0 -105.74,-15.47 -143.12,-46.41 -37.31,-30.85 -55.94,-71.36 -55.94,-121.56 0,-50.23 18.63,-90.47 55.94,-120.78 37.38,-30.23 85.08,-45.31 143.12,-45.31 z"/><path
|
||||
id="path24"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 5308.32,1466.41 c -78.55,0 -138.12,20.58 -178.75,61.71 -40.55,41.26 -60.78,100.47 -60.78,177.66 v 538.91 h -154.53 v 177.65 h 154.53 v 255 h 202.81 v -255 h 189.22 V 2244.69 H 5271.6 v -488.6 c 0,-33.55 7.7,-60.31 23.13,-80.31 15.5,-19.92 37.42,-29.84 65.78,-29.84 41.13,0 71.4,10.94 90.78,32.81 l 48.28,-152.5 c -42.5,-39.88 -106.25,-59.84 -191.25,-59.84 z"/><path
|
||||
id="path26"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 6477.38,1489.53 h -202.65 v 587.19 c 0,68.2 -16.49,116.8 -49.38,145.78 -32.81,28.95 -79.49,43.44 -140,43.44 -47.62,0 -92.65,-12.27 -135.15,-36.72 -42.5,-24.49 -77.31,-54.06 -104.38,-88.75 v -650.94 h -202.66 v 1288.28 h 202.66 V 2295 c 34.77,41.13 81.45,76.48 140,106.09 58.63,29.69 122.07,44.53 190.31,44.53 200.82,0 301.25,-98.55 301.25,-295.62 z"/><path
|
||||
id="path28"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 973.949,1128.48 h 2769.84 v 80.6211 H 973.949 Z"/><path
|
||||
id="path30"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
d="m 978.828,2781.72 c 0,-1292.5 0,-1292.5 0,-1292.5 H 2262.3 l -639.45,647.85 639.45,644.65"/><path
|
||||
id="path32"
|
||||
style="fill:none;stroke:#000000;stroke-width:13.86260033;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 978.828,2781.72 c 0,-1292.5 0,-1292.5 0,-1292.5 H 2262.3 l -639.45,647.85 639.45,644.65"/><g
|
||||
id="g34"><g
|
||||
clip-path="url(#clipPath40)"
|
||||
id="g36"><g
|
||||
transform="matrix(1370.4,0,0,12,2370,2778)"
|
||||
@ -141,7 +162,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g46"><g
|
||||
id="g46"><g
|
||||
clip-path="url(#clipPath52)"
|
||||
id="g48"><g
|
||||
transform="matrix(861.6,0,0,12,5630,2778)"
|
||||
@ -153,7 +174,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g58"><g
|
||||
id="g58"><g
|
||||
clip-path="url(#clipPath64)"
|
||||
id="g60"><g
|
||||
transform="matrix(1300.8,0,0,91.2,970,2688.8)"
|
||||
@ -165,7 +186,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g70"><g
|
||||
id="g70"><g
|
||||
clip-path="url(#clipPath76)"
|
||||
id="g72"><g
|
||||
transform="matrix(1370.4,0,0,91.2,2370,2688.8)"
|
||||
@ -177,7 +198,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g82"><g
|
||||
id="g82"><g
|
||||
clip-path="url(#clipPath88)"
|
||||
id="g84"><g
|
||||
transform="matrix(861.6,0,0,91.2,5630,2688.8)"
|
||||
@ -189,7 +210,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g94"><g
|
||||
id="g94"><g
|
||||
clip-path="url(#clipPath100)"
|
||||
id="g96"><g
|
||||
transform="matrix(1300.8,0,0,230.4,970,2459.6)"
|
||||
@ -201,7 +222,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g106"><g
|
||||
id="g106"><g
|
||||
clip-path="url(#clipPath112)"
|
||||
id="g108"><g
|
||||
transform="matrix(1370.4,0,0,230.4,2370,2459.6)"
|
||||
@ -213,7 +234,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g118"><g
|
||||
id="g118"><g
|
||||
clip-path="url(#clipPath124)"
|
||||
id="g120"><g
|
||||
transform="matrix(621.6,0,0,230.4,4900,2459.6)"
|
||||
@ -225,7 +246,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g130"><g
|
||||
id="g130"><g
|
||||
clip-path="url(#clipPath136)"
|
||||
id="g132"><g
|
||||
transform="matrix(861.6,0,0,230.4,5630,2459.6)"
|
||||
@ -237,7 +258,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g142"><g
|
||||
id="g142"><g
|
||||
clip-path="url(#clipPath148)"
|
||||
id="g144"><g
|
||||
transform="matrix(1300.8,0,0,981.6,970,1478.4)"
|
||||
@ -249,7 +270,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g154"><g
|
||||
id="g154"><g
|
||||
clip-path="url(#clipPath160)"
|
||||
id="g156"><g
|
||||
transform="matrix(1370.4,0,0,981.6,2370,1478.4)"
|
||||
@ -261,7 +282,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g166"><g
|
||||
id="g166"><g
|
||||
clip-path="url(#clipPath172)"
|
||||
id="g168"><g
|
||||
transform="matrix(861.6,0,0,981.6,3920,1478.4)"
|
||||
@ -273,7 +294,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g178"><g
|
||||
id="g178"><g
|
||||
clip-path="url(#clipPath184)"
|
||||
id="g180"><g
|
||||
transform="matrix(621.6,0,0,981.6,4900,1478.4)"
|
||||
@ -285,7 +306,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g190"><g
|
||||
id="g190"><g
|
||||
clip-path="url(#clipPath196)"
|
||||
id="g192"><g
|
||||
transform="matrix(861.6,0,0,981.6,5630,1478.4)"
|
||||
@ -297,7 +318,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g202"><g
|
||||
id="g202"><g
|
||||
clip-path="url(#clipPath208)"
|
||||
id="g204"><g
|
||||
transform="matrix(1370.4,0,0,12,2370,1468)"
|
||||
@ -309,7 +330,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g214"><g
|
||||
id="g214"><g
|
||||
clip-path="url(#clipPath220)"
|
||||
id="g216"><g
|
||||
transform="matrix(861.6,0,0,12,3920,1468)"
|
||||
@ -321,7 +342,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g226"><g
|
||||
id="g226"><g
|
||||
clip-path="url(#clipPath232)"
|
||||
id="g228"><g
|
||||
transform="matrix(621.6,0,0,12,4900,1468)"
|
||||
@ -333,7 +354,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g238"><g
|
||||
id="g238"><g
|
||||
clip-path="url(#clipPath244)"
|
||||
id="g240"><g
|
||||
transform="matrix(861.6,0,0,12,5630,1468)"
|
||||
@ -345,7 +366,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g250"><g
|
||||
id="g250"><g
|
||||
clip-path="url(#clipPath256)"
|
||||
id="g252"><g
|
||||
transform="matrix(861.6,0,0,21.6,3920,1448.4)"
|
||||
@ -357,7 +378,7 @@
|
||||
style="image-rendering:optimizeSpeed"
|
||||
height="1"
|
||||
width="1" /></g></g></g><g
|
||||
id="g262"><g
|
||||
id="g262"><g
|
||||
clip-path="url(#clipPath268)"
|
||||
id="g264"><g
|
||||
transform="matrix(621.6,0,0,21.6,4900,1448.4)"
|
||||
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
@ -10,11 +10,11 @@ structures. In `kmath` performance depends on which particular context was used
|
||||
Let us consider following contexts:
|
||||
```kotlin
|
||||
// automatically build context most suited for given type.
|
||||
val autoField = NDField.auto(RealField, dim, dim)
|
||||
val autoField = NDField.auto(DoubleField, dim, dim)
|
||||
// specialized nd-field for Double. It works as generic Double field as well
|
||||
val specializedField = NDField.real(dim, dim)
|
||||
//A generic boxing field. It should be used for objects, not primitives.
|
||||
val genericField = NDField.buffered(RealField, dim, dim)
|
||||
val genericField = NDField.buffered(DoubleField, dim, dim)
|
||||
```
|
||||
Now let us perform several tests and see which implementation is best suited for each case:
|
||||
|
||||
|
62
docs/templates/ARTIFACT-TEMPLATE.md
vendored
@ -1,34 +1,28 @@
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `${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)
|
||||
>
|
||||
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/${name}/images/download.svg) ](https://bintray.com/mipt-npm/dev/${name}/_latestVersion)
|
||||
>
|
||||
> **Gradle:**
|
||||
>
|
||||
> ```gradle
|
||||
> repositories {
|
||||
> maven { url 'https://repo.kotlin.link' }
|
||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation '${group}:${name}:${version}'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
>
|
||||
> ```kotlin
|
||||
> repositories {
|
||||
> maven("https://repo.kotlin.link")
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("${group}:${name}:${version}")
|
||||
> }
|
||||
> ```
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `${group}:${name}:${version}`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation '${group}:${name}:${version}'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("${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)
|
||||
[![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)
|
||||
|
||||
[![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)
|
||||
[![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)
|
||||
[![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
|
||||
|
||||
@ -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
|
||||
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
|
||||
|
||||
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 ru.mipt.npm.gradle.Maturity
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
kotlin("plugin.allopen")
|
||||
id("kotlinx.benchmark")
|
||||
id("org.jetbrains.kotlinx.benchmark")
|
||||
}
|
||||
|
||||
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/kscience")
|
||||
maven("https://jitpack.io")
|
||||
maven("http://logicrunch.research.it.uu.se/maven/")
|
||||
maven{
|
||||
setUrl("http://logicrunch.research.it.uu.se/maven/")
|
||||
isAllowInsecureProtocol = true
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
@ -58,7 +62,7 @@ dependencies {
|
||||
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.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")
|
||||
|
||||
// plotting
|
||||
@ -105,19 +109,31 @@ benchmark {
|
||||
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
|
||||
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 {
|
||||
with(languageSettings) {
|
||||
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
|
||||
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
||||
useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "11"
|
||||
kotlinOptions{
|
||||
jvmTarget = "11"
|
||||
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
|
||||
}
|
||||
}
|
||||
|
||||
readme{
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
readme {
|
||||
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 space.kscience.kmath.complex.Complex
|
||||
import space.kscience.kmath.complex.complex
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
import space.kscience.kmath.structures.RealBuffer
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class BufferBenchmark {
|
||||
@Benchmark
|
||||
fun genericRealBufferReadWrite() {
|
||||
val buffer = RealBuffer(size) { it.toDouble() }
|
||||
fun genericDoubleBufferReadWrite() {
|
||||
val buffer = DoubleBuffer(size) { it.toDouble() }
|
||||
|
||||
(0 until size).forEach {
|
||||
buffer[it]
|
||||
|
@ -13,7 +13,7 @@ import space.kscience.kmath.commons.linear.CMLinearSpace
|
||||
import space.kscience.kmath.ejml.EjmlLinearSpace
|
||||
import space.kscience.kmath.linear.LinearSpace
|
||||
import space.kscience.kmath.linear.invoke
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@ -56,7 +56,7 @@ internal class DotBenchmark {
|
||||
|
||||
@Benchmark
|
||||
fun bufferedDot(blackhole: Blackhole) {
|
||||
LinearSpace.auto(RealField).invoke {
|
||||
LinearSpace.auto(DoubleField).invoke {
|
||||
blackhole.consume(matrix1 dot matrix2)
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,12 @@ import kotlinx.benchmark.Benchmark
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.asm.compile
|
||||
import space.kscience.kmath.ast.mstInField
|
||||
import space.kscience.kmath.expressions.Expression
|
||||
import space.kscience.kmath.expressions.expressionInField
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.expressions.symbol
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.asm.compileToExpression
|
||||
import space.kscience.kmath.expressions.*
|
||||
import space.kscience.kmath.misc.symbol
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.bindSymbol
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@ -33,20 +31,20 @@ internal class ExpressionsInterpretersBenchmark {
|
||||
|
||||
@Benchmark
|
||||
fun mstExpression(blackhole: Blackhole) {
|
||||
val expr = algebra.mstInField {
|
||||
val expr = MstField {
|
||||
val x = bindSymbol(x)
|
||||
x * 2.0 + number(2.0) / x - 16.0
|
||||
}
|
||||
}.toExpression(algebra)
|
||||
|
||||
invokeAndSum(expr, blackhole)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun asmExpression(blackhole: Blackhole) {
|
||||
val expr = algebra.mstInField {
|
||||
val expr = MstField {
|
||||
val x = bindSymbol(x)
|
||||
x * 2.0 + number(2.0) / x - 16.0
|
||||
}.compile()
|
||||
}.compileToExpression(algebra)
|
||||
|
||||
invokeAndSum(expr, blackhole)
|
||||
}
|
||||
@ -73,7 +71,7 @@ internal class ExpressionsInterpretersBenchmark {
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private val algebra = RealField
|
||||
private val algebra = DoubleField
|
||||
private val x by symbol
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.nd.*
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@ -18,7 +18,7 @@ internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun autoFieldAdd(blackhole: Blackhole) {
|
||||
with(autoField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += one }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -27,7 +27,7 @@ internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun specializedFieldAdd(blackhole: Blackhole) {
|
||||
with(specializedField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -37,7 +37,7 @@ internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun boxingFieldAdd(blackhole: Blackhole) {
|
||||
with(genericField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -46,8 +46,8 @@ internal class NDFieldBenchmark {
|
||||
private companion object {
|
||||
private const val dim = 1000
|
||||
private const val n = 100
|
||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
private val specializedField = NDAlgebra.real(dim, dim)
|
||||
private val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val specializedField = AlgebraND.real(dim, dim)
|
||||
private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||
}
|
||||
}
|
||||
|
@ -10,11 +10,11 @@ import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import org.jetbrains.bio.viktor.F64Array
|
||||
import space.kscience.kmath.nd.NDAlgebra
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.auto
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.viktor.ViktorNDField
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@ -22,7 +22,7 @@ internal class ViktorBenchmark {
|
||||
@Benchmark
|
||||
fun automaticFieldAddition(blackhole: Blackhole) {
|
||||
with(autoField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -31,7 +31,7 @@ internal class ViktorBenchmark {
|
||||
@Benchmark
|
||||
fun realFieldAddition(blackhole: Blackhole) {
|
||||
with(realField) {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
blackhole.consume(res)
|
||||
}
|
||||
@ -59,8 +59,8 @@ internal class ViktorBenchmark {
|
||||
private const val n = 100
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
private val realField = NDAlgebra.real(dim, dim)
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val realField = AlgebraND.real(dim, dim)
|
||||
private val viktorField = ViktorNDField(dim, dim)
|
||||
}
|
||||
}
|
||||
|
@ -10,11 +10,11 @@ import kotlinx.benchmark.Blackhole
|
||||
import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import org.jetbrains.bio.viktor.F64Array
|
||||
import space.kscience.kmath.nd.NDAlgebra
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.auto
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.viktor.ViktorNDField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.viktor.ViktorFieldND
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class ViktorLogBenchmark {
|
||||
@ -51,8 +51,8 @@ internal class ViktorLogBenchmark {
|
||||
private const val n = 100
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
private val realNdField = NDAlgebra.real(dim, dim)
|
||||
private val viktorField = ViktorNDField(intArrayOf(dim, dim))
|
||||
private val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
private val realNdField = AlgebraND.real(dim, dim)
|
||||
private val viktorField = ViktorFieldND(intArrayOf(dim, dim))
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
import space.kscience.kmath.expressions.invoke
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.expressions.MstField
|
||||
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() {
|
||||
val expr = RealField.mstInField {
|
||||
val x = bindSymbol("x")
|
||||
val expr = MstField {
|
||||
val x = bindSymbol(x)
|
||||
x * 2.0 + number(2.0) / x - 16.0
|
||||
}
|
||||
|
||||
repeat(10000000) {
|
||||
expr.invoke("x" to 1.0)
|
||||
expr.interpret(DoubleField, x to 1.0)
|
||||
}
|
||||
}
|
@ -5,12 +5,12 @@
|
||||
|
||||
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.invoke
|
||||
import space.kscience.kmath.expressions.symbol
|
||||
import space.kscience.kmath.kotlingrad.differentiable
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.kotlingrad.toDiffExpression
|
||||
import space.kscience.kmath.misc.symbol
|
||||
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
|
||||
@ -19,11 +19,11 @@ import space.kscience.kmath.operations.RealField
|
||||
fun main() {
|
||||
val x by symbol
|
||||
|
||||
val actualDerivative = MstExpression(RealField, "x^2-4*x-44".parseMath())
|
||||
.differentiable()
|
||||
val actualDerivative = "x^2-4*x-44".parseMath()
|
||||
.toDiffExpression(DoubleField)
|
||||
.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))
|
||||
}
|
||||
|
@ -12,11 +12,14 @@ import kscience.plotly.models.ScatterMode
|
||||
import kscience.plotly.models.TraceValues
|
||||
import space.kscience.kmath.commons.optimization.chiSquared
|
||||
import space.kscience.kmath.commons.optimization.minimize
|
||||
import space.kscience.kmath.expressions.symbol
|
||||
import space.kscience.kmath.real.RealVector
|
||||
import space.kscience.kmath.distributions.NormalDistribution
|
||||
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.step
|
||||
import space.kscience.kmath.stat.*
|
||||
import space.kscience.kmath.stat.RandomGenerator
|
||||
import space.kscience.kmath.structures.asIterable
|
||||
import space.kscience.kmath.structures.toList
|
||||
import kotlin.math.pow
|
||||
@ -31,17 +34,16 @@ private val c by symbol
|
||||
/**
|
||||
* Shortcut to use buffers in plotly
|
||||
*/
|
||||
operator fun TraceValues.invoke(vector: RealVector) {
|
||||
operator fun TraceValues.invoke(vector: DoubleVector) {
|
||||
numbers = vector.asIterable()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
val generator = Distribution.normal()
|
||||
val generator = NormalDistribution(2.0, 7.0)
|
||||
|
||||
//A chain/flow of random values with the given seed
|
||||
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)
|
||||
val y = x.map {
|
||||
val value = it.pow(2) + it + 1
|
||||
value + chain.nextDouble() * sqrt(value)
|
||||
value + chain.next() * sqrt(value)
|
||||
}
|
||||
// this will also work, but less effective:
|
||||
// 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)
|
||||
|
||||
// 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
|
||||
val a = bind(a)
|
||||
val b = bind(b)
|
||||
val a = bindSymbol(a)
|
||||
val b = bindSymbol(b)
|
||||
//Include default value for c if it is not provided as a parameter
|
||||
val c = bindSymbolOrNull(c) ?: one
|
||||
a * x1.pow(2) + b * x1 + c
|
||||
@ -95,13 +97,13 @@ fun main() {
|
||||
}
|
||||
}
|
||||
br()
|
||||
h3{
|
||||
h3 {
|
||||
+"Fit result: $result"
|
||||
}
|
||||
h3{
|
||||
h3 {
|
||||
+"Chi2/dof = ${result.value / (x.size - 3)}"
|
||||
}
|
||||
}
|
||||
|
||||
page.makeFile()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
import space.kscience.kmath.real.*
|
||||
import space.kscience.kmath.structures.RealBuffer
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
|
||||
fun main() {
|
||||
val x0 = Point(0.0, 0.0, 0.0)
|
||||
val sigma = Point(1.0, 1.0, 1.0)
|
||||
val x0 = DoubleVector(0.0, 0.0, 0.0)
|
||||
val sigma = DoubleVector(1.0, 1.0, 1.0)
|
||||
|
||||
val gaussian: (Point<Double>) -> Double = { x ->
|
||||
require(x.size == x0.size)
|
||||
@ -19,9 +19,9 @@ fun main() {
|
||||
|
||||
fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> {
|
||||
require(x.size == x0.size)
|
||||
return RealBuffer(x.size) { i ->
|
||||
return DoubleBuffer(x.size) { i ->
|
||||
val h = sigma[i] / 5
|
||||
val dVector = RealBuffer(x.size) { if (it == i) h else 0.0 }
|
||||
val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
|
||||
val f1 = invoke(x + dVector / 2)
|
||||
val f0 = invoke(x - dVector / 2)
|
||||
(f1 - f0) / h
|
||||
|
@ -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.nd.NDAlgebra
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
|
||||
fun main() {
|
||||
// 2d element
|
||||
val element = NDAlgebra.complex(2, 2).produce { (i, j) ->
|
||||
val element = AlgebraND.complex(2, 2).produce { (i, j) ->
|
||||
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
|
||||
}
|
||||
println(element)
|
||||
|
||||
// 1d element operation
|
||||
val result = with(NDAlgebra.complex(8)) {
|
||||
val result = with(AlgebraND.complex(8)) {
|
||||
val a = produce { (it) -> i * it - it.toDouble() }
|
||||
val b = 3
|
||||
val c = Complex(1.0, 1.0)
|
||||
|
@ -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.
|
||||
*/
|
||||
|
||||
package kscience.kmath.commons.prob
|
||||
package space.kscience.kmath.stat
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
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 space.kscience.kmath.stat.*
|
||||
import space.kscience.kmath.samplers.GaussianSampler
|
||||
import java.time.Duration
|
||||
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 normal = Distribution.normal(NormalSamplerMethod.Ziggurat)
|
||||
val normal = GaussianSampler(7.0, 2.0)
|
||||
val chain = normal.sample(generator)
|
||||
val startTime = Instant.now()
|
||||
var sum = 0.0
|
||||
|
||||
repeat(10000001) { counter ->
|
||||
sum += chain.nextDouble()
|
||||
sum += chain.next()
|
||||
|
||||
if (counter % 100000 == 0) {
|
||||
val duration = Duration.between(startTime, Instant.now())
|
||||
@ -34,9 +35,15 @@ private fun runChain(): Duration {
|
||||
return Duration.between(startTime, Instant.now())
|
||||
}
|
||||
|
||||
private fun runDirect(): Duration {
|
||||
val provider = RandomSource.create(RandomSource.MT, 123L)
|
||||
val sampler = ZigguratNormalizedGaussianSampler(provider)
|
||||
private fun runApacheDirect(): Duration {
|
||||
val rng = RandomSource.create(RandomSource.MT, 123L)
|
||||
|
||||
val sampler = CMGaussianSampler.of(
|
||||
BoxMullerNormalizedGaussianSampler.of(rng),
|
||||
7.0,
|
||||
2.0
|
||||
)
|
||||
|
||||
val startTime = Instant.now()
|
||||
var sum = 0.0
|
||||
|
||||
@ -56,11 +63,9 @@ private fun runDirect(): Duration {
|
||||
/**
|
||||
* Comparing chain sampling performance with direct sampling performance
|
||||
*/
|
||||
fun main() {
|
||||
runBlocking(Dispatchers.Default) {
|
||||
val chainJob = async { runChain() }
|
||||
val directJob = async { runDirect() }
|
||||
println("Chain: ${chainJob.await()}")
|
||||
println("Direct: ${directJob.await()}")
|
||||
}
|
||||
fun main(): Unit = runBlocking(Dispatchers.Default) {
|
||||
val directJob = async { runApacheDirect() }
|
||||
val chainJob = async { runKMathChained() }
|
||||
println("KMath Chained: ${chainJob.await()}")
|
||||
println("Apache Direct: ${directJob.await()}")
|
||||
}
|
||||
|
@ -8,14 +8,15 @@ package space.kscience.kmath.stat
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import space.kscience.kmath.chains.Chain
|
||||
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)
|
||||
|
||||
/**
|
||||
* Averaging
|
||||
* Averaging.
|
||||
*/
|
||||
private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChainState(), { it.copy() }) { chain ->
|
||||
val next = chain.next()
|
||||
@ -26,7 +27,7 @@ private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChai
|
||||
|
||||
|
||||
fun main() {
|
||||
val normal = Distribution.normal()
|
||||
val normal = NormalDistribution(0.0, 2.0)
|
||||
val chain = normal.sample(RandomGenerator.default).mean()
|
||||
|
||||
runBlocking {
|
||||
@ -37,4 +38,4 @@ fun main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ package space.kscience.kmath.structures
|
||||
|
||||
import space.kscience.kmath.complex.*
|
||||
import space.kscience.kmath.linear.transpose
|
||||
import space.kscience.kmath.nd.NDAlgebra
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.nd.AlgebraND
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.as2D
|
||||
import space.kscience.kmath.nd.real
|
||||
import space.kscience.kmath.operations.invoke
|
||||
@ -20,12 +20,12 @@ fun main() {
|
||||
val dim = 1000
|
||||
val n = 1000
|
||||
|
||||
val realField = NDAlgebra.real(dim, dim)
|
||||
val complexField: ComplexNDField = NDAlgebra.complex(dim, dim)
|
||||
val realField = AlgebraND.real(dim, dim)
|
||||
val complexField: ComplexFieldND = AlgebraND.complex(dim, dim)
|
||||
|
||||
val realTime = measureTimeMillis {
|
||||
realField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) {
|
||||
res += 1.0
|
||||
}
|
||||
@ -36,7 +36,7 @@ fun main() {
|
||||
|
||||
val complexTime = measureTimeMillis {
|
||||
complexField {
|
||||
var res: NDStructure<Complex> = one
|
||||
var res: StructureND<Complex> = one
|
||||
repeat(n) {
|
||||
res += 1.0
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import kotlinx.coroutines.GlobalScope
|
||||
import org.nd4j.linalg.factory.Nd4j
|
||||
import space.kscience.kmath.nd.*
|
||||
import space.kscience.kmath.nd4j.Nd4jArrayField
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.viktor.ViktorNDField
|
||||
import kotlin.contracts.InvocationKind
|
||||
@ -29,56 +29,56 @@ fun main() {
|
||||
val n = 1000
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
val autoField = AlgebraND.auto(DoubleField, dim, dim)
|
||||
// specialized nd-field for Double. It works as generic Double field as well
|
||||
val realField = NDAlgebra.real(dim, dim)
|
||||
val realField = AlgebraND.real(dim, dim)
|
||||
//A generic boxing field. It should be used for objects, not primitives.
|
||||
val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
||||
val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
|
||||
// Nd4j specialized field.
|
||||
val nd4jField = Nd4jArrayField.real(dim, dim)
|
||||
//viktor field
|
||||
val viktorField = ViktorNDField(dim,dim)
|
||||
val viktorField = ViktorNDField(dim, dim)
|
||||
//parallel processing based on Java Streams
|
||||
val parallelField = NDAlgebra.realWithStream(dim,dim)
|
||||
val parallelField = AlgebraND.realWithStream(dim, dim)
|
||||
|
||||
measureAndPrint("Boxing addition") {
|
||||
boxingField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Specialized addition") {
|
||||
realField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Nd4j specialized addition") {
|
||||
nd4jField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Viktor addition") {
|
||||
viktorField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Parallel stream addition") {
|
||||
parallelField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
measureAndPrint("Automatic field addition") {
|
||||
autoField {
|
||||
var res: NDStructure<Double> = one
|
||||
var res: StructureND<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
@ -1,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
|
||||
|
||||
import space.kscience.kmath.nd.BufferND
|
||||
import space.kscience.kmath.nd.DefaultStrides
|
||||
import space.kscience.kmath.nd.NDBuffer
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||
fun main() {
|
||||
val n = 6000
|
||||
val array = DoubleArray(n * n) { 1.0 }
|
||||
val buffer = RealBuffer(array)
|
||||
val buffer = DoubleBuffer(array)
|
||||
val strides = DefaultStrides(intArrayOf(n, n))
|
||||
val structure = NDBuffer(strides, buffer)
|
||||
val structure = BufferND(strides, buffer)
|
||||
|
||||
measureTimeMillis {
|
||||
var res = 0.0
|
||||
@ -39,4 +39,4 @@ fun main() {
|
||||
strides.indices().forEach { res = array[strides.offset(it)] }
|
||||
}
|
||||
println("Array reading finished in $time3 millis")
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,14 @@
|
||||
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.nd.StructureND
|
||||
import space.kscience.kmath.nd.mapToBuffer
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
fun main() {
|
||||
val n = 6000
|
||||
val structure = NDStructure.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
||||
val structure = StructureND.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
||||
structure.mapToBuffer { it + 1 } // warm-up
|
||||
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
|
||||
println("Structure mapping finished in $time1 millis")
|
||||
@ -25,10 +25,10 @@ fun main() {
|
||||
|
||||
println("Array mapping finished in $time2 millis")
|
||||
|
||||
val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
|
||||
val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 })
|
||||
|
||||
val time3 = measureTimeMillis {
|
||||
val target = RealBuffer(DoubleArray(n * n))
|
||||
val target = DoubleBuffer(DoubleArray(n * n))
|
||||
val res = array.forEachIndexed { index, value ->
|
||||
target[index] = value + 1
|
||||
}
|
||||
|
@ -9,5 +9,5 @@ kotlin.mpp.stability.nowarn=true
|
||||
kotlin.native.enableDependencyPropagation=false
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G
|
||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
|
||||
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
|
||||
distributionPath=wrapper/dists
|
||||
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
|
||||
- [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
- [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
- [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
- [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
- [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
- [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
|
||||
- [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
|
||||
- [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
|
||||
- [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
|
||||
- [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
|
||||
- [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
|
||||
|
||||
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `space.kscience:kmath-ast:0.3.0-dev-2`.
|
||||
>
|
||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
|
||||
>
|
||||
> Bintray 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)
|
||||
>
|
||||
> **Gradle:**
|
||||
>
|
||||
> ```gradle
|
||||
> repositories {
|
||||
> maven { url 'https://repo.kotlin.link' }
|
||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'space.kscience:kmath-ast:0.3.0-dev-2'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
>
|
||||
> ```kotlin
|
||||
> repositories {
|
||||
> maven("https://repo.kotlin.link")
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("space.kscience:kmath-ast:0.3.0-dev-2")
|
||||
> }
|
||||
> ```
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-6`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-ast:0.3.0-dev-6'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-ast:0.3.0-dev-6")
|
||||
}
|
||||
```
|
||||
|
||||
## Dynamic expression code generation
|
||||
|
||||
@ -55,7 +49,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
|
||||
For example, the following builder:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||
@ -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:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
RealField.expression("x+2".parseMath())
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.expression("x+2".parseMath())
|
||||
```
|
||||
|
||||
#### Known issues
|
||||
@ -103,7 +97,7 @@ RealField.expression("x+2".parseMath())
|
||||
A similar feature is also available on JS.
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
The code above returns expression implemented with such a JS function:
|
||||
@ -117,3 +111,39 @@ var executable = function (constants, arguments) {
|
||||
#### Known issues
|
||||
|
||||
- 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
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
kotlin("multiplatform")
|
||||
id("ru.mipt.npm.gradle.common")
|
||||
}
|
||||
|
||||
kotlin.js {
|
||||
@ -63,36 +64,36 @@ readme {
|
||||
feature(
|
||||
id = "expression-language",
|
||||
description = "Expression language and its parser",
|
||||
ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt"
|
||||
ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst",
|
||||
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-building",
|
||||
description = "MST building algebraic structure",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-interpreter",
|
||||
description = "MST interpreter",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-jvm-codegen",
|
||||
description = "Dynamic MST to JVM bytecode compiler",
|
||||
ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt"
|
||||
ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "mst-js-codegen",
|
||||
description = "Dynamic MST to JS compiler",
|
||||
ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt"
|
||||
ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt"
|
||||
)
|
||||
}
|
||||
|
@ -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}
|
||||
|
||||
@ -16,7 +16,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
|
||||
For example, the following builder:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
… leads to generation of bytecode, which can be decompiled to the following Java class:
|
||||
@ -49,8 +49,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
||||
This API extends MST and MstExpression, so you may optimize as both of them:
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
RealField.expression("x+2".parseMath())
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.expression("x+2".parseMath())
|
||||
```
|
||||
|
||||
#### Known issues
|
||||
@ -64,7 +64,7 @@ RealField.expression("x+2".parseMath())
|
||||
A similar feature is also available on JS.
|
||||
|
||||
```kotlin
|
||||
RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
DoubleField.mstInField { symbol("x") + 2 }.compile()
|
||||
```
|
||||
|
||||
The code above returns expression implemented with such a JS function:
|
||||
@ -78,3 +78,39 @@ var executable = function (constants, arguments) {
|
||||
#### Known issues
|
||||
|
||||
- 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
|
||||
|
||||
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.estree.BaseExpression
|
||||
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.NumericAlgebra
|
||||
|
||||
@ -18,11 +19,7 @@ import space.kscience.kmath.operations.NumericAlgebra
|
||||
internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
|
||||
fun ESTreeBuilder<T>.visit(node: MST): BaseExpression = when (node) {
|
||||
is Symbolic -> {
|
||||
val symbol = try {
|
||||
algebra.bindSymbol(node.value)
|
||||
} catch (ignored: IllegalStateException) {
|
||||
null
|
||||
}
|
||||
val symbol = algebra.bindSymbolOrNull(node.value)
|
||||
|
||||
if (symbol != null)
|
||||
constant(symbol)
|
||||
@ -34,16 +31,17 @@ internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
|
||||
|
||||
is Unary -> when {
|
||||
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))
|
||||
}
|
||||
|
||||
is Binary -> when {
|
||||
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant(
|
||||
algebra
|
||||
.binaryOperationFunction(node.operation)
|
||||
.invoke(algebra.number(node.left.value), algebra.number(node.right.value))
|
||||
algebra.binaryOperationFunction(node.operation).invoke(
|
||||
algebra.number((node.left as Numeric).value),
|
||||
algebra.number((node.right as Numeric).value)
|
||||
)
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @author Alexander Nozik.
|
||||
* Compile given MST to expression and evaluate it against [arguments]
|
||||
*/
|
||||
public fun <T : Any> Algebra<T>.expression(mst: MST): Expression<T> =
|
||||
mst.compileWith(this)
|
||||
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
|
||||
compileToExpression(algebra).invoke(arguments)
|
||||
|
||||
|
||||
/**
|
||||
* Optimizes performance of an [MstExpression] by compiling it into ESTree generated expression.
|
||||
*
|
||||
* @author Alexander Nozik.
|
||||
* Compile given MST to expression and evaluate it against [arguments]
|
||||
*/
|
||||
public fun <T : Any> MstExpression<T, Algebra<T>>.compile(): Expression<T> =
|
||||
mst.compileWith(algebra)
|
||||
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T =
|
||||
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.estree.*
|
||||
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) {
|
||||
private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> {
|
||||
|
@ -5,19 +5,22 @@
|
||||
|
||||
package space.kscience.kmath.estree
|
||||
|
||||
import space.kscience.kmath.ast.*
|
||||
import space.kscience.kmath.complex.ComplexField
|
||||
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.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestESTreeConsistencyWithInterpreter {
|
||||
|
||||
@Test
|
||||
fun mstSpace() {
|
||||
val res1 = MstGroup.mstInGroup {
|
||||
|
||||
val mst = MstGroup {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
||||
@ -28,27 +31,17 @@ internal class TestESTreeConsistencyWithInterpreter {
|
||||
|
||||
number(1)
|
||||
) + bindSymbol("x") + zero
|
||||
}("x" to MST.Numeric(2))
|
||||
}
|
||||
|
||||
val res2 = MstGroup.mstInGroup {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
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)
|
||||
assertEquals(
|
||||
mst.interpret(MstGroup, Symbol.x to MST.Numeric(2)),
|
||||
mst.compile(MstGroup, Symbol.x to MST.Numeric(2))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun byteRing() {
|
||||
val res1 = ByteRing.mstInRing {
|
||||
val mst = MstRing {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
(bindSymbol("x") - (2.toByte() + (scale(
|
||||
@ -59,62 +52,43 @@ internal class TestESTreeConsistencyWithInterpreter {
|
||||
|
||||
number(1)
|
||||
) * number(2)
|
||||
}("x" to 3.toByte())
|
||||
}
|
||||
|
||||
val res2 = ByteRing.mstInRing {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
(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)
|
||||
assertEquals(
|
||||
mst.interpret(ByteRing, Symbol.x to 3.toByte()),
|
||||
mst.compile(ByteRing, Symbol.x to 3.toByte())
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun realField() {
|
||||
val res1 = RealField.mstInField {
|
||||
val mst = MstField {
|
||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}("x" to 2.0)
|
||||
}
|
||||
|
||||
val res2 = RealField.mstInField {
|
||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}.compile()("x" to 2.0)
|
||||
|
||||
assertEquals(res1, res2)
|
||||
assertEquals(
|
||||
mst.interpret(DoubleField, Symbol.x to 2.0),
|
||||
mst.compile(DoubleField, Symbol.x to 2.0)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun complexField() {
|
||||
val res1 = ComplexField.mstInField {
|
||||
val mst = MstField {
|
||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}("x" to 2.0.toComplex())
|
||||
}
|
||||
|
||||
val res2 = ComplexField.mstInField {
|
||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}.compile()("x" to 2.0.toComplex())
|
||||
|
||||
assertEquals(res1, res2)
|
||||
assertEquals(
|
||||
mst.interpret(ComplexField, Symbol.x to 2.0.toComplex()),
|
||||
mst.compile(ComplexField, Symbol.x to 2.0.toComplex())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,10 @@
|
||||
|
||||
package space.kscience.kmath.estree
|
||||
|
||||
import space.kscience.kmath.ast.mstInExtendedField
|
||||
import space.kscience.kmath.ast.mstInField
|
||||
import space.kscience.kmath.ast.mstInGroup
|
||||
import space.kscience.kmath.expressions.MstExtendedField
|
||||
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.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
@ -17,27 +16,29 @@ import kotlin.test.assertEquals
|
||||
internal class TestESTreeOperationsSupport {
|
||||
@Test
|
||||
fun testUnaryOperationInvocation() {
|
||||
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile()
|
||||
val expression = MstExtendedField { -bindSymbol("x") }.compileToExpression(DoubleField)
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-2.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBinaryOperationInvocation() {
|
||||
val expression = RealField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
||||
val expression = MstExtendedField { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-1.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConstProductInvocation() {
|
||||
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
||||
val res = MstExtendedField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
|
||||
assertEquals(4.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultipleCalls() {
|
||||
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile()
|
||||
val e =
|
||||
MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
|
||||
.compileToExpression(DoubleField)
|
||||
val r = Random(0)
|
||||
var s = 0.0
|
||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||
|
@ -5,54 +5,64 @@
|
||||
|
||||
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.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestESTreeSpecialization {
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
val expr = RealField
|
||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||
.compile()
|
||||
val expr = MstExtendedField {
|
||||
binaryOperationFunction("pow")(bindSymbol("x"), number(2))
|
||||
}.compileToExpression(DoubleField)
|
||||
|
||||
assertEquals(4.0, expr("x" to 2.0))
|
||||
}
|
||||
|
@ -5,9 +5,10 @@
|
||||
|
||||
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.operations.ByteRing
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
@ -15,13 +16,13 @@ import kotlin.test.assertFailsWith
|
||||
internal class TestESTreeVariables {
|
||||
@Test
|
||||
fun testVariable() {
|
||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||
val expr = MstRing{ bindSymbol("x") }.compileToExpression(ByteRing)
|
||||
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUndefinedVariableFails() {
|
||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
|
||||
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.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.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.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> {
|
||||
fun AsmBuilder<T>.visit(node: MST): Unit = when (node) {
|
||||
is Symbolic -> {
|
||||
val symbol = try {
|
||||
algebra.bindSymbol(node.value)
|
||||
} catch (ignored: IllegalStateException) {
|
||||
null
|
||||
}
|
||||
val symbol = algebra.bindSymbolOrNull(node.value)
|
||||
|
||||
if (symbol != null)
|
||||
loadObjectConstant(symbol as Any)
|
||||
@ -42,15 +39,17 @@ internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Exp
|
||||
|
||||
is Unary -> when {
|
||||
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) }
|
||||
}
|
||||
|
||||
is Binary -> when {
|
||||
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant(
|
||||
algebra.binaryOperationFunction(node.operation)
|
||||
.invoke(algebra.number(node.left.value), algebra.number(node.right.value))
|
||||
algebra.binaryOperationFunction(node.operation).invoke(
|
||||
algebra.number((node.left as Numeric).value),
|
||||
algebra.number((node.right as Numeric).value)
|
||||
)
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @author Alexander Nozik.
|
||||
* Create a compiled expression with given [MST] and given [algebra].
|
||||
*/
|
||||
public inline fun <reified T : Any> MstExpression<T, Algebra<T>>.compile(): Expression<T> =
|
||||
mst.compileWith(T::class.java, algebra)
|
||||
public inline fun <reified T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> =
|
||||
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.commons.InstructionAdapter
|
||||
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.MST
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
import java.util.stream.Collectors.toMap
|
||||
|
@ -7,8 +7,8 @@ package space.kscience.kmath.asm.internal
|
||||
|
||||
import org.objectweb.asm.*
|
||||
import org.objectweb.asm.commons.InstructionAdapter
|
||||
import space.kscience.kmath.ast.MST
|
||||
import space.kscience.kmath.expressions.Expression
|
||||
import space.kscience.kmath.expressions.MST
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@ -91,7 +91,7 @@ internal inline fun ClassWriter.visitField(
|
||||
descriptor: String,
|
||||
signature: String?,
|
||||
value: Any?,
|
||||
block: FieldVisitor.() -> Unit
|
||||
block: FieldVisitor.() -> Unit,
|
||||
): FieldVisitor {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
return visitField(access, name, descriptor, signature, value).apply(block)
|
||||
|
@ -7,8 +7,8 @@
|
||||
|
||||
package space.kscience.kmath.asm.internal
|
||||
|
||||
import space.kscience.kmath.expressions.StringSymbol
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.StringSymbol
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
|
||||
/**
|
||||
* 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.parser.ParseResult
|
||||
import com.github.h0tk3y.betterParse.parser.Parser
|
||||
import space.kscience.kmath.expressions.MST
|
||||
import space.kscience.kmath.operations.FieldOperations
|
||||
import space.kscience.kmath.operations.GroupOperations
|
||||
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.
|
||||
*
|
||||
* @author Alexander Nozik and Iaroslav Postovalov
|
||||
* @author Alexander Nozik
|
||||
* @author Iaroslav Postovalov
|
||||
*/
|
||||
public object ArithmeticsEvaluator : Grammar<MST>() {
|
||||
// TODO replace with "...".toRegex() when better-parse 0.4.1 is released
|
||||
|
@ -5,19 +5,22 @@
|
||||
|
||||
package space.kscience.kmath.asm
|
||||
|
||||
import space.kscience.kmath.ast.*
|
||||
import space.kscience.kmath.complex.ComplexField
|
||||
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.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestAsmConsistencyWithInterpreter {
|
||||
|
||||
@Test
|
||||
fun mstSpace() {
|
||||
val res1 = MstGroup.mstInGroup {
|
||||
|
||||
val mst = MstGroup {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
number(3.toByte()) - (number(2.toByte()) + (scale(
|
||||
@ -28,27 +31,17 @@ internal class TestAsmConsistencyWithInterpreter {
|
||||
|
||||
number(1)
|
||||
) + bindSymbol("x") + zero
|
||||
}("x" to MST.Numeric(2))
|
||||
}
|
||||
|
||||
val res2 = MstGroup.mstInGroup {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
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)
|
||||
assertEquals(
|
||||
mst.interpret(MstGroup, x to MST.Numeric(2)),
|
||||
mst.compile(MstGroup, x to MST.Numeric(2))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun byteRing() {
|
||||
val res1 = ByteRing.mstInRing {
|
||||
val mst = MstRing {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
(bindSymbol("x") - (2.toByte() + (scale(
|
||||
@ -59,62 +52,43 @@ internal class TestAsmConsistencyWithInterpreter {
|
||||
|
||||
number(1)
|
||||
) * number(2)
|
||||
}("x" to 3.toByte())
|
||||
}
|
||||
|
||||
val res2 = ByteRing.mstInRing {
|
||||
binaryOperationFunction("+")(
|
||||
unaryOperationFunction("+")(
|
||||
(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)
|
||||
assertEquals(
|
||||
mst.interpret(ByteRing, x to 3.toByte()),
|
||||
mst.compile(ByteRing, x to 3.toByte())
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun realField() {
|
||||
val res1 = RealField.mstInField {
|
||||
val mst = MstField {
|
||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}("x" to 2.0)
|
||||
}
|
||||
|
||||
val res2 = RealField.mstInField {
|
||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}.compile()("x" to 2.0)
|
||||
|
||||
assertEquals(res1, res2)
|
||||
assertEquals(
|
||||
mst.interpret(DoubleField, x to 2.0),
|
||||
mst.compile(DoubleField, x to 2.0)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun complexField() {
|
||||
val res1 = ComplexField.mstInField {
|
||||
val mst = MstField {
|
||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}("x" to 2.0.toComplex())
|
||||
}
|
||||
|
||||
val res2 = ComplexField.mstInField {
|
||||
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
|
||||
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
|
||||
+ number(1),
|
||||
number(1) / 2 + number(2.0) * one
|
||||
) + zero
|
||||
}.compile()("x" to 2.0.toComplex())
|
||||
|
||||
assertEquals(res1, res2)
|
||||
assertEquals(
|
||||
mst.interpret(ComplexField, x to 2.0.toComplex()),
|
||||
mst.compile(ComplexField, x to 2.0.toComplex())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,12 @@
|
||||
|
||||
package space.kscience.kmath.asm
|
||||
|
||||
import space.kscience.kmath.ast.mstInExtendedField
|
||||
import space.kscience.kmath.ast.mstInField
|
||||
import space.kscience.kmath.ast.mstInGroup
|
||||
import space.kscience.kmath.expressions.MstExtendedField
|
||||
import space.kscience.kmath.expressions.MstField
|
||||
import space.kscience.kmath.expressions.MstGroup
|
||||
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.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
@ -17,27 +18,29 @@ import kotlin.test.assertEquals
|
||||
internal class TestAsmOperationsSupport {
|
||||
@Test
|
||||
fun testUnaryOperationInvocation() {
|
||||
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile()
|
||||
val expression = MstGroup { -bindSymbol("x") }.compileToExpression(DoubleField)
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-2.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBinaryOperationInvocation() {
|
||||
val expression = RealField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
|
||||
val expression = MstGroup { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
|
||||
val res = expression("x" to 2.0)
|
||||
assertEquals(-1.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConstProductInvocation() {
|
||||
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
|
||||
val res = MstField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
|
||||
assertEquals(4.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultipleCalls() {
|
||||
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile()
|
||||
val e =
|
||||
MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
|
||||
.compileToExpression(DoubleField)
|
||||
val r = Random(0)
|
||||
var s = 0.0
|
||||
repeat(1000000) { s += e("x" to r.nextDouble()) }
|
||||
|
@ -5,54 +5,64 @@
|
||||
|
||||
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.operations.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class TestAsmSpecialization {
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
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))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPower() {
|
||||
val expr = RealField
|
||||
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
|
||||
.compile()
|
||||
val expr = MstExtendedField {
|
||||
binaryOperationFunction("pow")(bindSymbol("x"), number(2))
|
||||
}.compileToExpression(DoubleField)
|
||||
|
||||
assertEquals(4.0, expr("x" to 2.0))
|
||||
}
|
||||
|
@ -5,9 +5,10 @@
|
||||
|
||||
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.operations.ByteRing
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
@ -15,13 +16,13 @@ import kotlin.test.assertFailsWith
|
||||
internal class TestAsmVariables {
|
||||
@Test
|
||||
fun testVariable() {
|
||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
|
||||
assertEquals(1.toByte(), expr("x" to 1.toByte()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUndefinedVariableFails() {
|
||||
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
|
||||
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
|
||||
assertFailsWith<NoSuchElementException> { expr() }
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,14 @@
|
||||
|
||||
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.RealField
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class ParserPrecedenceTest {
|
||||
private val f: Field<Double> = RealField
|
||||
private val f: Field<Double> = DoubleField
|
||||
|
||||
@Test
|
||||
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
|
||||
|
@ -7,9 +7,12 @@ package space.kscience.kmath.ast
|
||||
|
||||
import space.kscience.kmath.complex.Complex
|
||||
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.RealField
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -23,7 +26,7 @@ internal class ParserTest {
|
||||
|
||||
@Test
|
||||
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)
|
||||
}
|
||||
|
||||
@ -38,14 +41,14 @@ internal class ParserTest {
|
||||
@Test
|
||||
fun `evaluate MST with unary function`() {
|
||||
val mst = "sin(0)".parseMath()
|
||||
val res = RealField.evaluate(mst)
|
||||
val res = DoubleField.evaluate(mst)
|
||||
assertEquals(0.0, res)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `evaluate MST with binary function`() {
|
||||
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 {
|
||||
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 {
|
||||
id("ru.mipt.npm.gradle.jvm")
|
||||
kotlin("jvm")
|
||||
id("ru.mipt.npm.gradle.common")
|
||||
}
|
||||
description = "Commons math binding for kmath"
|
||||
|
||||
@ -17,6 +18,6 @@ dependencies {
|
||||
api("org.apache.commons:commons-math3:3.6.1")
|
||||
}
|
||||
|
||||
readme{
|
||||
readme {
|
||||
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
|
||||
}
|
@ -7,6 +7,7 @@ package space.kscience.kmath.commons.expressions
|
||||
|
||||
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
||||
import space.kscience.kmath.expressions.*
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.operations.ExtendedField
|
||||
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 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]
|
||||
@ -39,10 +40,10 @@ public class DerivativeStructureField(
|
||||
symbol: Symbol,
|
||||
value: Double,
|
||||
) : DerivativeStructure(size, order, index, value), Symbol {
|
||||
override val identity: String = symbol.identity
|
||||
override fun toString(): String = identity
|
||||
override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity
|
||||
override fun hashCode(): Int = identity.hashCode()
|
||||
public override val identity: String = symbol.identity
|
||||
public override fun toString(): String = identity
|
||||
public override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity
|
||||
public override fun hashCode(): Int = identity.hashCode()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,13 +53,13 @@ public class DerivativeStructureField(
|
||||
key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value)
|
||||
}.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)
|
||||
|
||||
override fun bindSymbol(value: String): DerivativeStructureSymbol = bind(StringSymbol(value))
|
||||
public fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity]
|
||||
public fun bindSymbol(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity)
|
||||
|
||||
public fun DerivativeStructure.derivative(symbols: List<Symbol>): Double {
|
||||
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())
|
||||
|
||||
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)
|
||||
|
||||
@ -111,7 +112,6 @@ public class DerivativeStructureField(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 space.kscience.kmath.linear.*
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.NDStructure
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.structures.RealBuffer
|
||||
import space.kscience.kmath.nd.StructureFeature
|
||||
import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
import kotlin.reflect.KClass
|
||||
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 operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is NDStructure<*>) return false
|
||||
return NDStructure.contentEquals(this, other)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = origin.hashCode()
|
||||
}
|
||||
|
||||
public inline class CMVector(public val origin: RealVector) : Point<Double> {
|
||||
public class CMVector(public val origin: RealVector) : Point<Double> {
|
||||
public override val size: Int get() = origin.dimension
|
||||
|
||||
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 object CMLinearSpace : LinearSpace<Double, RealField> {
|
||||
override val elementAlgebra: RealField get() = RealField
|
||||
public object CMLinearSpace : LinearSpace<Double, DoubleField> {
|
||||
override val elementAlgebra: DoubleField get() = DoubleField
|
||||
|
||||
public override fun buildMatrix(
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
initializer: RealField.(i: Int, j: Int) -> Double,
|
||||
initializer: DoubleField.(i: Int, j: Int) -> Double,
|
||||
): CMMatrix {
|
||||
val array = Array(rows) { i -> DoubleArray(columns) { j -> RealField.initializer(i, j) } }
|
||||
val array = Array(rows) { i -> DoubleArray(columns) { j -> DoubleField.initializer(i, j) } }
|
||||
return CMMatrix(Array2DRowRealMatrix(array))
|
||||
}
|
||||
|
||||
@ -69,8 +61,8 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
|
||||
internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this)
|
||||
internal fun RealVector.wrap(): CMVector = CMVector(this)
|
||||
|
||||
override fun buildVector(size: Int, initializer: RealField.(Int) -> Double): Point<Double> =
|
||||
ArrayRealVector(DoubleArray(size) { RealField.initializer(it) }).wrap()
|
||||
override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): Point<Double> =
|
||||
ArrayRealVector(DoubleArray(size) { DoubleField.initializer(it) }).wrap()
|
||||
|
||||
override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix =
|
||||
toCM().origin.add(other.toCM().origin).wrap()
|
||||
@ -103,7 +95,7 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
|
||||
v * this
|
||||
|
||||
@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
|
||||
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 s: Matrix<Double> by lazy { CMMatrix(sv.s) }
|
||||
override val v: Matrix<Double> by lazy { CMMatrix(sv.v) }
|
||||
override val singularValues: Point<Double> by lazy { RealBuffer(sv.singularValues) }
|
||||
override val singularValues: Point<Double> by lazy { DoubleBuffer(sv.singularValues) }
|
||||
}
|
||||
else -> null
|
||||
}?.let(type::cast)
|
||||
|
@ -19,7 +19,7 @@ public enum class CMDecomposition {
|
||||
|
||||
public fun CMLinearSpace.solver(
|
||||
a: Matrix<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): DecompositionSolver = when (decomposition) {
|
||||
CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver
|
||||
CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver
|
||||
@ -31,16 +31,16 @@ public fun CMLinearSpace.solver(
|
||||
public fun CMLinearSpace.solve(
|
||||
a: Matrix<Double>,
|
||||
b: Matrix<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap()
|
||||
|
||||
public fun CMLinearSpace.solve(
|
||||
a: Matrix<Double>,
|
||||
b: Point<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint()
|
||||
|
||||
public fun CMLinearSpace.inverse(
|
||||
a: Matrix<Double>,
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP
|
||||
decomposition: CMDecomposition = CMDecomposition.LUP,
|
||||
): CMMatrix = solver(a, decomposition).inverse.wrap()
|
||||
|
@ -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.NelderMeadSimplex
|
||||
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
|
||||
import space.kscience.kmath.expressions.*
|
||||
import space.kscience.kmath.stat.OptimizationFeature
|
||||
import space.kscience.kmath.stat.OptimizationProblem
|
||||
import space.kscience.kmath.stat.OptimizationProblemFactory
|
||||
import space.kscience.kmath.stat.OptimizationResult
|
||||
import space.kscience.kmath.expressions.DifferentiableExpression
|
||||
import space.kscience.kmath.expressions.Expression
|
||||
import space.kscience.kmath.expressions.SymbolIndexer
|
||||
import space.kscience.kmath.expressions.derivative
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.optimization.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
public operator fun PointValuePair.component1(): DoubleArray = point
|
||||
public operator fun PointValuePair.component2(): Double = value
|
||||
|
||||
public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
OptimizationProblem<Double>, SymbolIndexer, OptimizationFeature {
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class CMOptimization(
|
||||
override val symbols: List<Symbol>,
|
||||
) : FunctionOptimization<Double>, NoDerivFunctionOptimization<Double>, SymbolIndexer, OptimizationFeature {
|
||||
|
||||
private val optimizationData: HashMap<KClass<out OptimizationData>, OptimizationData> = HashMap()
|
||||
private var optimizatorBuilder: (() -> MultivariateOptimizer)? = null
|
||||
public var convergenceChecker: ConvergenceChecker<PointValuePair> = SimpleValueChecker(DEFAULT_RELATIVE_TOLERANCE,
|
||||
DEFAULT_ABSOLUTE_TOLERANCE, DEFAULT_MAX_ITER)
|
||||
private var optimizerBuilder: (() -> MultivariateOptimizer)? = null
|
||||
public var convergenceChecker: ConvergenceChecker<PointValuePair> = SimpleValueChecker(
|
||||
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) {
|
||||
optimizationData[data::class] = data
|
||||
@ -45,7 +59,7 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
addOptimizationData(InitialGuess(map.toDoubleArray()))
|
||||
}
|
||||
|
||||
public override fun expression(expression: Expression<Double>): Unit {
|
||||
public override fun function(expression: Expression<Double>): Unit {
|
||||
val objectiveFunction = ObjectiveFunction {
|
||||
val args = it.toMap()
|
||||
expression(args)
|
||||
@ -53,8 +67,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
addOptimizationData(objectiveFunction)
|
||||
}
|
||||
|
||||
public override fun diffExpression(expression: DifferentiableExpression<Double, Expression<Double>>) {
|
||||
expression(expression)
|
||||
public override fun diffFunction(expression: DifferentiableExpression<Double, Expression<Double>>) {
|
||||
function(expression)
|
||||
val gradientFunction = ObjectiveFunctionGradient {
|
||||
val args = it.toMap()
|
||||
DoubleArray(symbols.size) { index ->
|
||||
@ -62,8 +76,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
}
|
||||
}
|
||||
addOptimizationData(gradientFunction)
|
||||
if (optimizatorBuilder == null) {
|
||||
optimizatorBuilder = {
|
||||
if (optimizerBuilder == null) {
|
||||
optimizerBuilder = {
|
||||
NonLinearConjugateGradientOptimizer(
|
||||
NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES,
|
||||
convergenceChecker
|
||||
@ -75,8 +89,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
public fun simplex(simplex: AbstractSimplex) {
|
||||
addOptimizationData(simplex)
|
||||
//Set optimization builder to simplex if it is not present
|
||||
if (optimizatorBuilder == null) {
|
||||
optimizatorBuilder = { SimplexOptimizer(convergenceChecker) }
|
||||
if (optimizerBuilder == null) {
|
||||
optimizerBuilder = { SimplexOptimizer(convergenceChecker) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +103,7 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
}
|
||||
|
||||
public fun optimizer(block: () -> MultivariateOptimizer) {
|
||||
optimizatorBuilder = block
|
||||
optimizerBuilder = block
|
||||
}
|
||||
|
||||
override fun update(result: OptimizationResult<Double>) {
|
||||
@ -97,19 +111,19 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
|
||||
}
|
||||
|
||||
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())
|
||||
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_ABSOLUTE_TOLERANCE: Double = 1e-4
|
||||
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 CMOptimizationProblem.simplexSteps(vararg pairs: Pair<Symbol, Double>): Unit = simplexSteps(pairs.toMap())
|
||||
public fun CMOptimization.initialGuess(vararg pairs: Pair<Symbol, Double>): Unit = initialGuess(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
|
||||
|
||||
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.expressions.DifferentiableExpression
|
||||
import space.kscience.kmath.expressions.Expression
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.stat.Fitting
|
||||
import space.kscience.kmath.stat.OptimizationResult
|
||||
import space.kscience.kmath.stat.optimizeWith
|
||||
import space.kscience.kmath.misc.Symbol
|
||||
import space.kscience.kmath.optimization.FunctionOptimization
|
||||
import space.kscience.kmath.optimization.OptimizationResult
|
||||
import space.kscience.kmath.optimization.noDerivOptimizeWith
|
||||
import space.kscience.kmath.optimization.optimizeWith
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.asBuffer
|
||||
|
||||
/**
|
||||
* 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>,
|
||||
y: 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
|
||||
*/
|
||||
public fun Fitting.chiSquared(
|
||||
public fun FunctionOptimization.Companion.chiSquared(
|
||||
x: Iterable<Double>,
|
||||
y: Iterable<Double>,
|
||||
yErr: Iterable<Double>,
|
||||
@ -48,25 +48,26 @@ public fun Fitting.chiSquared(
|
||||
*/
|
||||
public fun Expression<Double>.optimize(
|
||||
vararg symbols: Symbol,
|
||||
configuration: CMOptimizationProblem.() -> Unit,
|
||||
): OptimizationResult<Double> = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration)
|
||||
configuration: CMOptimization.() -> Unit,
|
||||
): OptimizationResult<Double> = noDerivOptimizeWith(CMOptimization, symbols = symbols, configuration)
|
||||
|
||||
/**
|
||||
* Optimize differentiable expression
|
||||
*/
|
||||
public fun DifferentiableExpression<Double, Expression<Double>>.optimize(
|
||||
vararg symbols: Symbol,
|
||||
configuration: CMOptimizationProblem.() -> Unit,
|
||||
): OptimizationResult<Double> = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration)
|
||||
configuration: CMOptimization.() -> Unit,
|
||||
): OptimizationResult<Double> = optimizeWith(CMOptimization, symbols = symbols, configuration)
|
||||
|
||||
public fun DifferentiableExpression<Double, Expression<Double>>.minimize(
|
||||
vararg startPoint: Pair<Symbol, Double>,
|
||||
configuration: CMOptimizationProblem.() -> Unit = {},
|
||||
configuration: CMOptimization.() -> Unit = {},
|
||||
): OptimizationResult<Double> {
|
||||
require(startPoint.isNotEmpty()) { "Must provide a list of symbols for optimization" }
|
||||
val problem = CMOptimizationProblem(startPoint.map { it.first }).apply(configuration)
|
||||
problem.diffExpression(this)
|
||||
problem.initialGuess(startPoint.toMap())
|
||||
problem.goal(GoalType.MINIMIZE)
|
||||
return problem.optimize()
|
||||
val symbols = startPoint.map { it.first }.toTypedArray()
|
||||
return optimize(*symbols){
|
||||
maximize = false
|
||||
initialGuess(startPoint.toMap())
|
||||
diffFunction(this@minimize)
|
||||
configuration()
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ import space.kscience.kmath.streaming.spread
|
||||
import space.kscience.kmath.structures.*
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Streaming and buffer transformations
|
||||
*/
|
||||
@ -22,7 +23,7 @@ public object Transformations {
|
||||
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
|
||||
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
|
||||
|
||||
private fun Buffer<Double>.asArray() = if (this is RealBuffer) {
|
||||
private fun Buffer<Double>.asArray() = if (this is DoubleBuffer) {
|
||||
array
|
||||
} else {
|
||||
DoubleArray(size) { i -> get(i) }
|
||||
@ -38,34 +39,34 @@ public object Transformations {
|
||||
|
||||
public fun fourier(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Complex, Complex> = {
|
||||
FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun realFourier(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Complex> = {
|
||||
FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun sine(
|
||||
normalization: DstNormalization = DstNormalization.STANDARD_DST_I,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Double> = {
|
||||
FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun cosine(
|
||||
normalization: DctNormalization = DctNormalization.STANDARD_DCT_I,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Double> = {
|
||||
FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
|
||||
public fun hadamard(
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): SuspendBufferTransform<Double, Double> = {
|
||||
FastHadamardTransformer().transform(it.asArray(), direction).asBuffer()
|
||||
}
|
||||
@ -77,7 +78,7 @@ public object Transformations {
|
||||
@FlowPreview
|
||||
public fun Flow<Buffer<Complex>>.FFT(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Buffer<Complex>> {
|
||||
val transform = Transformations.fourier(normalization, direction)
|
||||
return map { transform(it) }
|
||||
@ -87,7 +88,7 @@ public fun Flow<Buffer<Complex>>.FFT(
|
||||
@JvmName("realFFT")
|
||||
public fun Flow<Buffer<Double>>.FFT(
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Buffer<Complex>> {
|
||||
val transform = Transformations.realFourier(normalization, direction)
|
||||
return map(transform)
|
||||
@ -101,7 +102,7 @@ public fun Flow<Buffer<Double>>.FFT(
|
||||
public fun Flow<Double>.FFT(
|
||||
bufferSize: Int = Int.MAX_VALUE,
|
||||
normalization: DftNormalization = DftNormalization.STANDARD,
|
||||
direction: TransformType = TransformType.FORWARD
|
||||
direction: TransformType = TransformType.FORWARD,
|
||||
): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread()
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,11 @@
|
||||
|
||||
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.contract
|
||||
import kotlin.test.Test
|
||||
@ -28,14 +32,14 @@ internal class AutoDiffTest {
|
||||
@Test
|
||||
fun derivativeStructureFieldTest() {
|
||||
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 z = x * (-sin(x * y) + y) + 2.0
|
||||
println(z.derivative(x))
|
||||
println(z.derivative(y,x))
|
||||
println(z.derivative(y, x))
|
||||
assertEquals(z.derivative(x, y), z.derivative(y, x))
|
||||
//check that improper order cause failure
|
||||
assertFails { z.derivative(x,x,y) }
|
||||
assertFails { z.derivative(x, x, y) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,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
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import space.kscience.kmath.commons.expressions.DerivativeStructureExpression
|
||||
import space.kscience.kmath.expressions.symbol
|
||||
import space.kscience.kmath.stat.Distribution
|
||||
import space.kscience.kmath.stat.Fitting
|
||||
import space.kscience.kmath.distributions.NormalDistribution
|
||||
import space.kscience.kmath.misc.symbol
|
||||
import space.kscience.kmath.optimization.FunctionOptimization
|
||||
import space.kscience.kmath.stat.RandomGenerator
|
||||
import space.kscience.kmath.stat.normal
|
||||
import kotlin.math.pow
|
||||
import kotlin.test.Test
|
||||
|
||||
internal class OptimizeTest {
|
||||
val x by symbol
|
||||
val y by symbol
|
||||
|
||||
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
|
||||
@ -39,35 +40,35 @@ internal class OptimizeTest {
|
||||
simplexSteps(x to 2.0, y to 0.5)
|
||||
//this sets simplex optimizer
|
||||
}
|
||||
|
||||
println(result.point)
|
||||
println(result.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCmFit() {
|
||||
fun testCmFit() = runBlocking {
|
||||
val a by symbol
|
||||
val b by symbol
|
||||
val c by symbol
|
||||
|
||||
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 x = (1..100).map(Int::toDouble)
|
||||
|
||||
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 chi2 = Fitting.chiSquared(x, y, yErr) { x1 ->
|
||||
val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 ->
|
||||
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)
|
||||
println(result)
|
||||
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
|
||||
- [quaternion](src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
- [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
|
||||
- [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
|
||||
|
||||
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `space.kscience:kmath-complex:0.3.0-dev-2`.
|
||||
>
|
||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-complex/_latestVersion)
|
||||
>
|
||||
> Bintray 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)
|
||||
>
|
||||
> **Gradle:**
|
||||
>
|
||||
> ```gradle
|
||||
> repositories {
|
||||
> maven { url 'https://repo.kotlin.link' }
|
||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'space.kscience:kmath-complex:0.3.0-dev-2'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
>
|
||||
> ```kotlin
|
||||
> repositories {
|
||||
> maven("https://repo.kotlin.link")
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("space.kscience:kmath-complex:0.3.0-dev-2")
|
||||
> }
|
||||
> ```
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-6`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-complex:0.3.0-dev-6'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-complex:0.3.0-dev-6")
|
||||
}
|
||||
```
|
||||
|
@ -1,12 +1,13 @@
|
||||
import ru.mipt.npm.gradle.Maturity
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import ru.mipt.npm.gradle.Maturity
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
kotlin("multiplatform")
|
||||
id("ru.mipt.npm.gradle.common")
|
||||
id("ru.mipt.npm.gradle.native")
|
||||
}
|
||||
|
||||
@ -30,12 +31,12 @@ readme {
|
||||
feature(
|
||||
id = "complex",
|
||||
description = "Complex Numbers",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/complex/Complex.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "quaternion",
|
||||
description = "Quaternions",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt"
|
||||
)
|
||||
}
|
||||
|
@ -1,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}
|
||||
|
||||
|
@ -126,8 +126,8 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Num
|
||||
/**
|
||||
* Adds complex number to real one.
|
||||
*
|
||||
* @receiver the addend.
|
||||
* @param c the augend.
|
||||
* @receiver the augend.
|
||||
* @param c the addend.
|
||||
* @return the sum.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @receiver the addend.
|
||||
* @param d the augend.
|
||||
* @receiver the augend.
|
||||
* @param d the addend.
|
||||
* @return the sum.
|
||||
*/
|
||||
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 bindSymbol(value: String): Complex =
|
||||
if (value == "i") i else super<ExtendedField>.bindSymbol(value)
|
||||
public override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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,14 +170,14 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Quaternion>,
|
||||
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 bindSymbol(value: String): Quaternion = when (value) {
|
||||
public override fun bindSymbolOrNull(value: String): Quaternion? = when (value) {
|
||||
"i" -> i
|
||||
"j" -> j
|
||||
"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()
|
||||
|
||||
public override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0
|
||||
public override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0
|
||||
|
@ -6,9 +6,9 @@
|
||||
package space.kscience.kmath.complex
|
||||
|
||||
import space.kscience.kmath.expressions.FunctionalExpressionField
|
||||
import space.kscience.kmath.expressions.bindSymbol
|
||||
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.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.
|
||||
- [nd](src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
|
||||
- [linear](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
- [buffers](src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||
- [expressions](src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||
- [algebras](src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
|
||||
- [nd](src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
|
||||
- [linear](src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
- [buffers](src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
|
||||
- [expressions](src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
|
||||
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
|
||||
performance calculations to code generation.
|
||||
- [domains](src/commonMain/kotlin/kscience/kmath/domains) : Domains
|
||||
- [autodif](src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||
- [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
|
||||
- [autodif](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
|
||||
|
||||
|
||||
> #### Artifact:
|
||||
>
|
||||
> This module artifact: `space.kscience:kmath-core:0.3.0-dev-2`.
|
||||
>
|
||||
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
|
||||
>
|
||||
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
|
||||
>
|
||||
> **Gradle:**
|
||||
>
|
||||
> ```gradle
|
||||
> repositories {
|
||||
> maven { url 'https://repo.kotlin.link' }
|
||||
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation 'space.kscience:kmath-core:0.3.0-dev-2'
|
||||
> }
|
||||
> ```
|
||||
> **Gradle Kotlin DSL:**
|
||||
>
|
||||
> ```kotlin
|
||||
> repositories {
|
||||
> maven("https://repo.kotlin.link")
|
||||
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
> }
|
||||
>
|
||||
> dependencies {
|
||||
> implementation("space.kscience:kmath-core:0.3.0-dev-2")
|
||||
> }
|
||||
> ```
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-6`.
|
||||
|
||||
**Gradle:**
|
||||
```gradle
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
|
||||
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:kmath-core:0.3.0-dev-6'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
|
||||
maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:kmath-core:0.3.0-dev-6")
|
||||
}
|
||||
```
|
||||
|
@ -6,7 +6,8 @@
|
||||
import ru.mipt.npm.gradle.Maturity
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
kotlin("multiplatform")
|
||||
id("ru.mipt.npm.gradle.common")
|
||||
id("ru.mipt.npm.gradle.native")
|
||||
}
|
||||
|
||||
@ -28,13 +29,13 @@ readme {
|
||||
description = """
|
||||
Algebraic structures like rings, spaces and fields.
|
||||
""".trimIndent(),
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "nd",
|
||||
description = "Many-dimensional structures and operations on them.",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
@ -42,13 +43,13 @@ readme {
|
||||
description = """
|
||||
Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
|
||||
""".trimIndent(),
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "buffers",
|
||||
description = "One-dimensional structure",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt"
|
||||
)
|
||||
|
||||
feature(
|
||||
@ -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
|
||||
performance calculations to code generation.
|
||||
""".trimIndent(),
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/expressions"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/expressions"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "domains",
|
||||
description = "Domains",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/domains"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/domains"
|
||||
)
|
||||
|
||||
feature(
|
||||
id = "autodif",
|
||||
description = "Automatic differentiation",
|
||||
ref = "src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt"
|
||||
ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt"
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# The Core Module (`kmath-core`)
|
||||
# Module kmath-core
|
||||
|
||||
The core features of KMath:
|
||||
The core interfaces of KMath.
|
||||
|
||||
${features}
|
||||
|
||||
|