Dev #280

Merged
altavir merged 99 commits from dev into master 2021-04-16 19:45:55 +03:00
283 changed files with 9250 additions and 5289 deletions

View File

@ -8,6 +8,7 @@ jobs:
matrix: matrix:
os: [ macOS-latest, windows-latest ] os: [ macOS-latest, windows-latest ]
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
timeout-minutes: 30
steps: steps:
- name: Checkout the repo - name: Checkout the repo
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -12,7 +12,7 @@ jobs:
name: publish name: publish
strategy: strategy:
matrix: matrix:
os: [macOS-latest, windows-latest] os: [ macOS-latest, windows-latest ]
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
steps: steps:
- name: Checkout the repo - name: Checkout the repo

4
.gitignore vendored
View File

@ -1,7 +1,11 @@
.gradle .gradle
build/ build/
out/ out/
.idea/ .idea/
!.idea/copyright/
.vscode/ .vscode/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)

View File

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright 2018-2021 KMath contributors.&#10;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>

View File

@ -0,0 +1,7 @@
<component name="CopyrightManager">
<settings default="kmath">
<module2copyright>
<element module="Project Files" copyright="kmath" />
</module2copyright>
</settings>
</component>

View File

@ -4,20 +4,35 @@
### Added ### Added
- ScaleOperations interface - ScaleOperations interface
- Field extends ScaleOperations - Field extends ScaleOperations
- Basic integration API
- Basic MPP distributions and samplers
- bindSymbolOrNull
- Blocking chains and Statistics
- Multiplatform integration
- Integration for any Field element
### Changed ### Changed
- Exponential operations merged with hyperbolic functions - Exponential operations merged with hyperbolic functions
- Space is replaced by Group. Space is reserved for vector spaces. - Space is replaced by Group. Space is reserved for vector spaces.
- VectorSpace is now a vector space - VectorSpace is now a vector space
- Buffer factories for primitives moved to MutableBuffer.Companion - Buffer factories for primitives moved to MutableBuffer.Companion
- NDStructure and NDAlgebra to StructureND and AlgebraND respectively
- Real -> Double
- DataSets are moved from functions to core
- Redesign advanced Chain API
- Redesign MST. Remove MSTExpression.
- Move MST to core
### Deprecated ### Deprecated
### Removed ### Removed
- Nearest in Domain. To be implemented in geometry package. - Nearest in Domain. To be implemented in geometry package.
- Number multiplication and division in main Algebra chain - Number multiplication and division in main Algebra chain
- `contentEquals` from Buffer. It moved to the companion.
- MSTExpression
### Fixed ### Fixed
- Ring inherits RingOperations, not GroupOperations
### Security ### Security
@ -73,6 +88,7 @@
- `toGrid` method. - `toGrid` method.
- Public visibility of `BufferAccessor2D` - Public visibility of `BufferAccessor2D`
- `Real` class - `Real` class
- StructureND identity and equals
### Fixed ### Fixed
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140) - `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)

View File

@ -1,9 +1,8 @@
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) ![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22)
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22kmath-core%22) [![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
# KMath # KMath
@ -89,12 +88,12 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
> >
> **Features:** > **Features:**
> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser > - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation > - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure > - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter > - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler > - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler > - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
<hr/> <hr/>
@ -110,8 +109,8 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
> >
> **Features:** > **Features:**
> - [complex](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers > - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
> - [quaternion](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions > - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
<hr/> <hr/>
@ -121,15 +120,15 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: DEVELOPMENT > **Maturity**: DEVELOPMENT
> >
> **Features:** > **Features:**
> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields. > - [algebras](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
> - [nd](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them. > - [nd](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
> - [linear](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition. > - [linear](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
> - [buffers](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure > - [buffers](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of > - [expressions](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation. performance calculations to code generation.
> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains > - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation > - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
<hr/> <hr/>
@ -149,6 +148,12 @@ performance calculations to code generation.
> >
> >
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
>
> **Features:**
> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : The Point implementation using SimpleMatrix.
> - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : The Matrix implementation using SimpleMatrix.
> - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : The LinearSpace implementation using SimpleMatrix.
<hr/> <hr/>
* ### [kmath-for-real](kmath-for-real) * ### [kmath-for-real](kmath-for-real)
@ -159,22 +164,23 @@ One can still use generic algebras though.
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
> >
> **Features:** > **Features:**
> - [RealVector](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealVector.kt) : Numpy-like operations for Buffers/Points > - [DoubleVector](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points
> - [RealMatrix](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt) : Numpy-like operations for 2d real structures > - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures
> - [grids](kmath-for-real/src/commonMain/kotlin/kscience/kmath/structures/grids.kt) : Uniform grid generators > - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators
<hr/> <hr/>
* ### [kmath-functions](kmath-functions) * ### [kmath-functions](kmath-functions)
> Functions and interpolation > Functions, integration and interpolation
> >
> **Maturity**: PROTOTYPE > **Maturity**: EXPERIMENTAL
> >
> **Features:** > **Features:**
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt > - [piecewise](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt) : Piecewise functions.
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt > - [polynomials](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Polynomial functions.
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt > - [linear interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt) : Linear XY interpolator.
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt > - [spline interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator.
> - [integration](kmath-functions/#) : Univariate and multivariate quadratures
<hr/> <hr/>
@ -208,9 +214,9 @@ One can still use generic algebras though.
> **Maturity**: EXPERIMENTAL > **Maturity**: EXPERIMENTAL
> >
> **Features:** > **Features:**
> - [nd4jarraystructure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray > - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long > - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long
> - [nd4jarrayfields](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : Fields over Nd4jArrayStructure of Float and Double > - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double
<hr/> <hr/>
@ -245,6 +251,10 @@ cases. We expect the worst KMath benchmarks will perform better than native Pyth
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy. better than SciPy.
## Requirements
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
### Repositories ### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
@ -256,8 +266,8 @@ repositories {
} }
dependencies { dependencies {
api("space.kscience:kmath-core:0.3.0-dev-2") api("space.kscience:kmath-core:0.3.0-dev-6")
// api("space.kscience:kmath-core-jvm:0.3.0-dev-2") for jvm-specific version // api("space.kscience:kmath-core-jvm:0.3.0-dev-6") for jvm-specific version
} }
``` ```

View File

@ -3,7 +3,8 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
import ru.mipt.npm.gradle.KSciencePublishingPlugin import org.jetbrains.dokka.gradle.DokkaTask
import java.net.URL
plugins { plugins {
id("ru.mipt.npm.gradle.project") id("ru.mipt.npm.gradle.project")
@ -15,21 +16,41 @@ allprojects {
maven("https://clojars.org/repo") maven("https://clojars.org/repo")
maven("https://dl.bintray.com/egor-bogomolov/astminer/") maven("https://dl.bintray.com/egor-bogomolov/astminer/")
maven("https://dl.bintray.com/hotkeytlt/maven") maven("https://dl.bintray.com/hotkeytlt/maven")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/kotlin/kotlinx")
maven("https://dl.bintray.com/mipt-npm/dev")
maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://jitpack.io") maven("https://jitpack.io")
maven("http://logicrunch.research.it.uu.se/maven/") maven{
setUrl("http://logicrunch.research.it.uu.se/maven/")
isAllowInsecureProtocol = true
}
mavenCentral() mavenCentral()
} }
group = "space.kscience" group = "space.kscience"
version = "0.3.0-dev-2" version = "0.3.0-dev-6"
} }
subprojects { subprojects {
if (name.startsWith("kmath")) apply<KSciencePublishingPlugin>() if (name.startsWith("kmath")) apply<MavenPublishPlugin>()
afterEvaluate {
tasks.withType<DokkaTask> {
dokkaSourceSets.all {
val readmeFile = File(this@subprojects.projectDir, "./README.md")
if (readmeFile.exists())
includes.setFrom(includes + readmeFile.absolutePath)
arrayOf(
"http://ejml.org/javadoc/",
"https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/",
"https://deeplearning4j.org/api/latest/"
).map { URL("${it}package-list") to URL(it) }.forEach { (a, b) ->
externalDocumentationLink {
packageListUrl.set(a)
url.set(b)
}
}
}
}
}
} }
readme { readme {

View File

@ -31,7 +31,7 @@ multiplication;
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1); - [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation. - [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
A typical implementation of `Field<T>` is the `RealField` which works on doubles, and `VectorSpace` for `Space<T>`. A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`.
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot` interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot`

View File

@ -13,16 +13,19 @@
version="1.1"><metadata version="1.1"><metadata
id="metadata8"><rdf:RDF><cc:Work id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
<defs
id="defs6"><clipPath id="defs6"><clipPath
id="clipPath24" id="clipPath24"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path22" id="path22"
d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath><clipPath d="M 0,1590 H 6720 V 4400 H 0 Z" /></clipPath>
<clipPath
id="clipPath36" id="clipPath36"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path34" id="path34"
d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs><g d="M 3410,0 H 6720 V 1590 H 3410 Z" /></clipPath></defs>
<g
transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)" transform="matrix(1.3333333,0,0,-1.3333333,0,586.66667)"
id="g10"><g id="g10"><g
transform="scale(0.1)" transform="scale(0.1)"
@ -32,7 +35,7 @@
d="m 1299.34,651.602 h 4653.75 v 3208.87 H 1299.34 Z" /><path d="m 1299.34,651.602 h 4653.75 v 3208.87 H 1299.34 Z" /><path
id="path16" id="path16"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 d="m 1651.48,1093.71 h 4076.99 v 114.609 H 1651.48 Z"/><g
id="g18"><g id="g18"><g
clip-path="url(#clipPath24)" clip-path="url(#clipPath24)"
id="g20"><g id="g20"><g

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 248 KiB

View File

@ -13,12 +13,14 @@
version="1.1"><metadata version="1.1"><metadata
id="metadata8"><rdf:RDF><cc:Work id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
<defs
id="defs6"><clipPath id="defs6"><clipPath
id="clipPath32" id="clipPath32"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path30" id="path30"
d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs><g d="M 1780,1750 H 3830 V 3800 H 1780 Z" /></clipPath></defs>
<g
transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)" transform="matrix(1.3333333,0,0,-1.3333333,0,633.33333)"
id="g10"><g id="g10"><g
transform="scale(0.1)" transform="scale(0.1)"
@ -28,19 +30,19 @@
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 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" id="path16"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 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" id="path18"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 d="M 1400.43,708.48 H 6418.24 V 4168.4 H 1400.43 Z"/><path
id="path20" id="path20"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 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" id="path22"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 d="m 1780.12,1185.24 h 4395.94 v 123.551 H 1780.12 Z"/><path
id="path24" 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" 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 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="g26"><g
clip-path="url(#clipPath32)" clip-path="url(#clipPath32)"
id="g28"><g id="g28"><g

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -13,24 +13,29 @@
version="1.1"><metadata version="1.1"><metadata
id="metadata8"><rdf:RDF><cc:Work id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
<defs
id="defs6"><clipPath id="defs6"><clipPath
id="clipPath24" id="clipPath24"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path22" id="path22"
d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath><clipPath d="M 0,3010 H 6470 V 4280 H 0 Z" /></clipPath>
<clipPath
id="clipPath36" id="clipPath36"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path34" id="path34"
d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath><clipPath d="M 0,1590 H 7000 V 3010 H 0 Z" /></clipPath>
<clipPath
id="clipPath48" id="clipPath48"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path46" id="path46"
d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath><clipPath d="m 0,1580 h 6470 v 10 H 0 Z" /></clipPath>
<clipPath
id="clipPath60" id="clipPath60"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path58" id="path58"
d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs><g d="M 3280,0 H 6460 V 1580 H 3280 Z" /></clipPath></defs>
<g
transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)" transform="matrix(1.3333333,0,0,-1.3333333,0,570.66667)"
id="g10"><g id="g10"><g
transform="scale(0.1)" transform="scale(0.1)"
@ -40,7 +45,7 @@
d="m 791.328,957.73 h 6401.56 V 3245.31 H 791.328 Z" /><path d="m 791.328,957.73 h 6401.56 V 3245.31 H 791.328 Z" /><path
id="path16" id="path16"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 d="m 1049.45,1214.42 h 2988.24 v 86.9883 H 1049.45 Z"/><g
id="g18"><g id="g18"><g
clip-path="url(#clipPath24)" clip-path="url(#clipPath24)"
id="g20"><g id="g20"><g

Before

Width:  |  Height:  |  Size: 278 KiB

After

Width:  |  Height:  |  Size: 278 KiB

View File

@ -13,88 +13,109 @@
version="1.1"><metadata version="1.1"><metadata
id="metadata8"><rdf:RDF><cc:Work id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata>
<defs
id="defs6"><clipPath id="defs6"><clipPath
id="clipPath40" id="clipPath40"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path38" id="path38"
d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath><clipPath d="m 2370,2780 h 1370 v 10 H 2370 Z" /></clipPath>
<clipPath
id="clipPath52" id="clipPath52"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path50" id="path50"
d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath><clipPath d="m 5630,2780 h 860 v 10 h -860 z" /></clipPath>
<clipPath
id="clipPath64" id="clipPath64"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path62" id="path62"
d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath><clipPath d="m 970,2690 h 1300 v 90 H 970 Z" /></clipPath>
<clipPath
id="clipPath76" id="clipPath76"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path74" id="path74"
d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath><clipPath d="m 2370,2690 h 1370 v 90 H 2370 Z" /></clipPath>
<clipPath
id="clipPath88" id="clipPath88"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path86" id="path86"
d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath><clipPath d="m 5630,2690 h 860 v 90 h -860 z" /></clipPath>
<clipPath
id="clipPath100" id="clipPath100"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path98" id="path98"
d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath><clipPath d="m 970,2460 h 1300 v 230 H 970 Z" /></clipPath>
<clipPath
id="clipPath112" id="clipPath112"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path110" id="path110"
d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath><clipPath d="m 2370,2460 h 1370 v 230 H 2370 Z" /></clipPath>
<clipPath
id="clipPath124" id="clipPath124"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path122" id="path122"
d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath><clipPath d="m 4900,2460 h 620 v 230 h -620 z" /></clipPath>
<clipPath
id="clipPath136" id="clipPath136"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path134" id="path134"
d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath><clipPath d="m 5630,2460 h 860 v 230 h -860 z" /></clipPath>
<clipPath
id="clipPath148" id="clipPath148"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path146" id="path146"
d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath><clipPath d="m 970,1480 h 1300 v 980 H 970 Z" /></clipPath>
<clipPath
id="clipPath160" id="clipPath160"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path158" id="path158"
d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath><clipPath d="m 2370,1480 h 1370 v 980 H 2370 Z" /></clipPath>
<clipPath
id="clipPath172" id="clipPath172"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path170" id="path170"
d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath><clipPath d="m 3920,1480 h 860 v 980 h -860 z" /></clipPath>
<clipPath
id="clipPath184" id="clipPath184"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path182" id="path182"
d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath><clipPath d="m 4900,1480 h 620 v 980 h -620 z" /></clipPath>
<clipPath
id="clipPath196" id="clipPath196"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path194" id="path194"
d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath><clipPath d="m 5630,1480 h 860 v 980 h -860 z" /></clipPath>
<clipPath
id="clipPath208" id="clipPath208"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path206" id="path206"
d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath><clipPath d="m 2370,1470 h 1370 v 10 H 2370 Z" /></clipPath>
<clipPath
id="clipPath220" id="clipPath220"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path218" id="path218"
d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath><clipPath d="m 3920,1470 h 860 v 10 h -860 z" /></clipPath>
<clipPath
id="clipPath232" id="clipPath232"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path230" id="path230"
d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath><clipPath d="m 4900,1470 h 620 v 10 h -620 z" /></clipPath>
<clipPath
id="clipPath244" id="clipPath244"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path242" id="path242"
d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath><clipPath d="m 5630,1470 h 860 v 10 h -860 z" /></clipPath>
<clipPath
id="clipPath256" id="clipPath256"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path254" id="path254"
d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath><clipPath d="m 3920,1450 h 860 v 20 h -860 z" /></clipPath>
<clipPath
id="clipPath268" id="clipPath268"
clipPathUnits="userSpaceOnUse"><path clipPathUnits="userSpaceOnUse"><path
id="path266" id="path266"
d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs><g d="m 4900,1450 h 620 v 20 h -620 z" /></clipPath></defs>
<g
transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)" transform="matrix(1.3333333,0,0,-1.3333333,0,529.33333)"
id="g10"><g id="g10"><g
transform="scale(0.1)" transform="scale(0.1)"
@ -104,31 +125,31 @@
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 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" id="path16"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 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" id="path18"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 d="m 734.691,901.211 h 5982.5 v 2109.69 h -5982.5 z"/><path
id="path20" id="path20"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 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" id="path22"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 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" id="path24"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 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" id="path26"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 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" id="path28"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" 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 d="m 973.949,1128.48 h 2769.84 v 80.6211 H 973.949 Z"/><path
id="path30" id="path30"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" 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 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" 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" 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 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="g34"><g
clip-path="url(#clipPath40)" clip-path="url(#clipPath40)"
id="g36"><g id="g36"><g

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

View File

@ -10,11 +10,11 @@ structures. In `kmath` performance depends on which particular context was used
Let us consider following contexts: Let us consider following contexts:
```kotlin ```kotlin
// automatically build context most suited for given type. // automatically build context most suited for given type.
val autoField = NDField.auto(RealField, dim, dim) val autoField = NDField.auto(DoubleField, dim, dim)
// specialized nd-field for Double. It works as generic Double field as well // specialized nd-field for Double. It works as generic Double field as well
val specializedField = NDField.real(dim, dim) val specializedField = NDField.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives. //A generic boxing field. It should be used for objects, not primitives.
val genericField = NDField.buffered(RealField, dim, dim) val genericField = NDField.buffered(DoubleField, dim, dim)
``` ```
Now let us perform several tests and see which implementation is best suited for each case: Now let us perform several tests and see which implementation is best suited for each case:

View File

@ -1,34 +1,28 @@
> #### Artifact: ## Artifact:
>
> This module artifact: `${group}:${name}:${version}`. The Maven coordinates of this project are `${group}:${name}:${version}`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/${name}/images/download.svg) ](https://bintray.com/mipt-npm/kscience/${name}/_latestVersion) **Gradle:**
> ```gradle
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/${name}/images/download.svg) ](https://bintray.com/mipt-npm/dev/${name}/_latestVersion) repositories {
> maven { url 'https://repo.kotlin.link' }
> **Gradle:** maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
> ```gradle }
> repositories {
> maven { url 'https://repo.kotlin.link' } dependencies {
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' } implementation '${group}:${name}:${version}'
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap }
> } ```
> **Gradle Kotlin DSL:**
> dependencies { ```kotlin
> implementation '${group}:${name}:${version}' repositories {
> } maven("https://repo.kotlin.link")
> ``` maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
> **Gradle Kotlin DSL:** maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
> }
> ```kotlin
> repositories { dependencies {
> maven("https://repo.kotlin.link") implementation("${group}:${name}:${version}")
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap }
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a ```
> }
>
> dependencies {
> implementation("${group}:${name}:${version}")
> }
> ```

View File

@ -1,9 +1,8 @@
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) ![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22)
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22kmath-core%22) [![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
# KMath # KMath
@ -95,6 +94,10 @@ cases. We expect the worst KMath benchmarks will perform better than native Pyth
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy. better than SciPy.
## Requirements
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
### Repositories ### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of

View File

@ -4,11 +4,12 @@
*/ */
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import ru.mipt.npm.gradle.Maturity
plugins { plugins {
kotlin("jvm") kotlin("jvm")
kotlin("plugin.allopen") kotlin("plugin.allopen")
id("kotlinx.benchmark") id("org.jetbrains.kotlinx.benchmark")
} }
allOpen.annotation("org.openjdk.jmh.annotations.State") allOpen.annotation("org.openjdk.jmh.annotations.State")
@ -25,7 +26,10 @@ repositories {
maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/mipt-npm/dev")
maven("https://dl.bintray.com/mipt-npm/kscience") maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://jitpack.io") maven("https://jitpack.io")
maven("http://logicrunch.research.it.uu.se/maven/") maven{
setUrl("http://logicrunch.research.it.uu.se/maven/")
isAllowInsecureProtocol = true
}
mavenCentral() mavenCentral()
} }
@ -58,7 +62,7 @@ dependencies {
implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
implementation("org.jetbrains.kotlinx:kotlinx-io:0.2.0-npm-dev-11") implementation("org.jetbrains.kotlinx:kotlinx-io:0.2.0-npm-dev-11")
implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20") implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.0")
implementation("org.slf4j:slf4j-simple:1.7.30") implementation("org.slf4j:slf4j-simple:1.7.30")
// plotting // plotting
@ -105,19 +109,31 @@ benchmark {
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
include("MatrixInverseBenchmark") include("MatrixInverseBenchmark")
} }
configurations.register("bigInt") {
warmups = 1 // number of warmup iterations
iterations = 3 // number of iterations
iterationTime = 500 // time in seconds per iteration
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
include("BigIntBenchmark")
}
} }
kotlin.sourceSets.all { kotlin.sourceSets.all {
with(languageSettings) { with(languageSettings) {
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
} }
} }
tasks.withType<KotlinCompile> { tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11" kotlinOptions{
jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
}
} }
readme{ readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL maturity = Maturity.EXPERIMENTAL
} }

View File

@ -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)
}
}

View File

@ -10,14 +10,14 @@ import kotlinx.benchmark.Scope
import kotlinx.benchmark.State import kotlinx.benchmark.State
import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.complex import space.kscience.kmath.complex.complex
import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.RealBuffer
@State(Scope.Benchmark) @State(Scope.Benchmark)
internal class BufferBenchmark { internal class BufferBenchmark {
@Benchmark @Benchmark
fun genericRealBufferReadWrite() { fun genericDoubleBufferReadWrite() {
val buffer = RealBuffer(size) { it.toDouble() } val buffer = DoubleBuffer(size) { it.toDouble() }
(0 until size).forEach { (0 until size).forEach {
buffer[it] buffer[it]

View File

@ -13,7 +13,7 @@ import space.kscience.kmath.commons.linear.CMLinearSpace
import space.kscience.kmath.ejml.EjmlLinearSpace import space.kscience.kmath.ejml.EjmlLinearSpace
import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.LinearSpace
import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.invoke
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import kotlin.random.Random import kotlin.random.Random
@State(Scope.Benchmark) @State(Scope.Benchmark)
@ -56,7 +56,7 @@ internal class DotBenchmark {
@Benchmark @Benchmark
fun bufferedDot(blackhole: Blackhole) { fun bufferedDot(blackhole: Blackhole) {
LinearSpace.auto(RealField).invoke { LinearSpace.auto(DoubleField).invoke {
blackhole.consume(matrix1 dot matrix2) blackhole.consume(matrix1 dot matrix2)
} }
} }

View File

@ -9,14 +9,12 @@ import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope import kotlinx.benchmark.Scope
import kotlinx.benchmark.State import kotlinx.benchmark.State
import space.kscience.kmath.asm.compile import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.ast.mstInField import space.kscience.kmath.expressions.*
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.misc.symbol
import space.kscience.kmath.expressions.expressionInField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.random.Random import kotlin.random.Random
@State(Scope.Benchmark) @State(Scope.Benchmark)
@ -33,20 +31,20 @@ internal class ExpressionsInterpretersBenchmark {
@Benchmark @Benchmark
fun mstExpression(blackhole: Blackhole) { fun mstExpression(blackhole: Blackhole) {
val expr = algebra.mstInField { val expr = MstField {
val x = bindSymbol(x) val x = bindSymbol(x)
x * 2.0 + number(2.0) / x - 16.0 x * 2.0 + number(2.0) / x - 16.0
} }.toExpression(algebra)
invokeAndSum(expr, blackhole) invokeAndSum(expr, blackhole)
} }
@Benchmark @Benchmark
fun asmExpression(blackhole: Blackhole) { fun asmExpression(blackhole: Blackhole) {
val expr = algebra.mstInField { val expr = MstField {
val x = bindSymbol(x) val x = bindSymbol(x)
x * 2.0 + number(2.0) / x - 16.0 x * 2.0 + number(2.0) / x - 16.0
}.compile() }.compileToExpression(algebra)
invokeAndSum(expr, blackhole) invokeAndSum(expr, blackhole)
} }
@ -73,7 +71,7 @@ internal class ExpressionsInterpretersBenchmark {
} }
private companion object { private companion object {
private val algebra = RealField private val algebra = DoubleField
private val x by symbol private val x by symbol
} }
} }

View File

@ -10,7 +10,7 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope import kotlinx.benchmark.Scope
import kotlinx.benchmark.State import kotlinx.benchmark.State
import space.kscience.kmath.nd.* import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
@State(Scope.Benchmark) @State(Scope.Benchmark)
@ -18,7 +18,7 @@ internal class NDFieldBenchmark {
@Benchmark @Benchmark
fun autoFieldAdd(blackhole: Blackhole) { fun autoFieldAdd(blackhole: Blackhole) {
with(autoField) { with(autoField) {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += one } repeat(n) { res += one }
blackhole.consume(res) blackhole.consume(res)
} }
@ -27,7 +27,7 @@ internal class NDFieldBenchmark {
@Benchmark @Benchmark
fun specializedFieldAdd(blackhole: Blackhole) { fun specializedFieldAdd(blackhole: Blackhole) {
with(specializedField) { with(specializedField) {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
blackhole.consume(res) blackhole.consume(res)
} }
@ -37,7 +37,7 @@ internal class NDFieldBenchmark {
@Benchmark @Benchmark
fun boxingFieldAdd(blackhole: Blackhole) { fun boxingFieldAdd(blackhole: Blackhole) {
with(genericField) { with(genericField) {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
blackhole.consume(res) blackhole.consume(res)
} }
@ -46,8 +46,8 @@ internal class NDFieldBenchmark {
private companion object { private companion object {
private const val dim = 1000 private const val dim = 1000
private const val n = 100 private const val n = 100
private val autoField = NDAlgebra.auto(RealField, dim, dim) private val autoField = AlgebraND.auto(DoubleField, dim, dim)
private val specializedField = NDAlgebra.real(dim, dim) private val specializedField = AlgebraND.real(dim, dim)
private val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim) private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
} }
} }

View File

@ -10,11 +10,11 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope import kotlinx.benchmark.Scope
import kotlinx.benchmark.State import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.nd.NDAlgebra import space.kscience.kmath.nd.AlgebraND
import space.kscience.kmath.nd.NDStructure import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.auto import space.kscience.kmath.nd.auto
import space.kscience.kmath.nd.real import space.kscience.kmath.nd.real
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.viktor.ViktorNDField import space.kscience.kmath.viktor.ViktorNDField
@State(Scope.Benchmark) @State(Scope.Benchmark)
@ -22,7 +22,7 @@ internal class ViktorBenchmark {
@Benchmark @Benchmark
fun automaticFieldAddition(blackhole: Blackhole) { fun automaticFieldAddition(blackhole: Blackhole) {
with(autoField) { with(autoField) {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
blackhole.consume(res) blackhole.consume(res)
} }
@ -31,7 +31,7 @@ internal class ViktorBenchmark {
@Benchmark @Benchmark
fun realFieldAddition(blackhole: Blackhole) { fun realFieldAddition(blackhole: Blackhole) {
with(realField) { with(realField) {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
blackhole.consume(res) blackhole.consume(res)
} }
@ -59,8 +59,8 @@ internal class ViktorBenchmark {
private const val n = 100 private const val n = 100
// automatically build context most suited for given type. // automatically build context most suited for given type.
private val autoField = NDAlgebra.auto(RealField, dim, dim) private val autoField = AlgebraND.auto(DoubleField, dim, dim)
private val realField = NDAlgebra.real(dim, dim) private val realField = AlgebraND.real(dim, dim)
private val viktorField = ViktorNDField(dim, dim) private val viktorField = ViktorNDField(dim, dim)
} }
} }

View File

@ -10,11 +10,11 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope import kotlinx.benchmark.Scope
import kotlinx.benchmark.State import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.nd.NDAlgebra import space.kscience.kmath.nd.AlgebraND
import space.kscience.kmath.nd.auto import space.kscience.kmath.nd.auto
import space.kscience.kmath.nd.real import space.kscience.kmath.nd.real
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.viktor.ViktorNDField import space.kscience.kmath.viktor.ViktorFieldND
@State(Scope.Benchmark) @State(Scope.Benchmark)
internal class ViktorLogBenchmark { internal class ViktorLogBenchmark {
@ -51,8 +51,8 @@ internal class ViktorLogBenchmark {
private const val n = 100 private const val n = 100
// automatically build context most suited for given type. // automatically build context most suited for given type.
private val autoField = NDAlgebra.auto(RealField, dim, dim) private val autoField = AlgebraND.auto(DoubleField, dim, dim)
private val realNdField = NDAlgebra.real(dim, dim) private val realNdField = AlgebraND.real(dim, dim)
private val viktorField = ViktorNDField(intArrayOf(dim, dim)) private val viktorField = ViktorFieldND(intArrayOf(dim, dim))
} }
} }

View File

@ -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)
}

View File

@ -5,16 +5,20 @@
package space.kscience.kmath.ast package space.kscience.kmath.ast
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.operations.RealField import space.kscience.kmath.expressions.interpret
import space.kscience.kmath.misc.Symbol.Companion.x
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
fun main() { fun main() {
val expr = RealField.mstInField { val expr = MstField {
val x = bindSymbol("x") val x = bindSymbol(x)
x * 2.0 + number(2.0) / x - 16.0 x * 2.0 + number(2.0) / x - 16.0
} }
repeat(10000000) { repeat(10000000) {
expr.invoke("x" to 1.0) expr.interpret(DoubleField, x to 1.0)
} }
} }

View File

@ -5,12 +5,12 @@
package space.kscience.kmath.ast package space.kscience.kmath.ast
import space.kscience.kmath.asm.compile import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.expressions.derivative import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.symbol import space.kscience.kmath.kotlingrad.toDiffExpression
import space.kscience.kmath.kotlingrad.differentiable import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
/** /**
* In this example, x^2-4*x-44 function is differentiated with Kotlin, and the autodiff result is compared with * In this example, x^2-4*x-44 function is differentiated with Kotlin, and the autodiff result is compared with
@ -19,11 +19,11 @@ import space.kscience.kmath.operations.RealField
fun main() { fun main() {
val x by symbol val x by symbol
val actualDerivative = MstExpression(RealField, "x^2-4*x-44".parseMath()) val actualDerivative = "x^2-4*x-44".parseMath()
.differentiable() .toDiffExpression(DoubleField)
.derivative(x) .derivative(x)
.compile()
val expectedDerivative = MstExpression(RealField, "2*x-4".parseMath()).compile()
val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField)
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0)) assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
} }

View File

@ -12,11 +12,14 @@ import kscience.plotly.models.ScatterMode
import kscience.plotly.models.TraceValues import kscience.plotly.models.TraceValues
import space.kscience.kmath.commons.optimization.chiSquared import space.kscience.kmath.commons.optimization.chiSquared
import space.kscience.kmath.commons.optimization.minimize import space.kscience.kmath.commons.optimization.minimize
import space.kscience.kmath.expressions.symbol import space.kscience.kmath.distributions.NormalDistribution
import space.kscience.kmath.real.RealVector import space.kscience.kmath.misc.symbol
import space.kscience.kmath.optimization.FunctionOptimization
import space.kscience.kmath.optimization.OptimizationResult
import space.kscience.kmath.real.DoubleVector
import space.kscience.kmath.real.map import space.kscience.kmath.real.map
import space.kscience.kmath.real.step import space.kscience.kmath.real.step
import space.kscience.kmath.stat.* import space.kscience.kmath.stat.RandomGenerator
import space.kscience.kmath.structures.asIterable import space.kscience.kmath.structures.asIterable
import space.kscience.kmath.structures.toList import space.kscience.kmath.structures.toList
import kotlin.math.pow import kotlin.math.pow
@ -31,17 +34,16 @@ private val c by symbol
/** /**
* Shortcut to use buffers in plotly * Shortcut to use buffers in plotly
*/ */
operator fun TraceValues.invoke(vector: RealVector) { operator fun TraceValues.invoke(vector: DoubleVector) {
numbers = vector.asIterable() numbers = vector.asIterable()
} }
/** /**
* Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules. * Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules.
*/ */
fun main() { suspend fun main() {
//A generator for a normally distributed values //A generator for a normally distributed values
val generator = Distribution.normal() val generator = NormalDistribution(2.0, 7.0)
//A chain/flow of random values with the given seed //A chain/flow of random values with the given seed
val chain = generator.sample(RandomGenerator.default(112667)) val chain = generator.sample(RandomGenerator.default(112667))
@ -54,7 +56,7 @@ fun main() {
//Perform an operation on each x value (much more effective, than numpy) //Perform an operation on each x value (much more effective, than numpy)
val y = x.map { val y = x.map {
val value = it.pow(2) + it + 1 val value = it.pow(2) + it + 1
value + chain.nextDouble() * sqrt(value) value + chain.next() * sqrt(value)
} }
// this will also work, but less effective: // this will also work, but less effective:
// val y = x.pow(2)+ x + 1 + chain.nextDouble() // val y = x.pow(2)+ x + 1 + chain.nextDouble()
@ -63,10 +65,10 @@ fun main() {
val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma) val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma)
// compute differentiable chi^2 sum for given model ax^2 + bx + c // compute differentiable chi^2 sum for given model ax^2 + bx + c
val chi2 = Fitting.chiSquared(x, y, yErr) { x1 -> val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 ->
//bind variables to autodiff context //bind variables to autodiff context
val a = bind(a) val a = bindSymbol(a)
val b = bind(b) val b = bindSymbol(b)
//Include default value for c if it is not provided as a parameter //Include default value for c if it is not provided as a parameter
val c = bindSymbolOrNull(c) ?: one val c = bindSymbolOrNull(c) ?: one
a * x1.pow(2) + b * x1 + c a * x1.pow(2) + b * x1 + c
@ -95,10 +97,10 @@ fun main() {
} }
} }
br() br()
h3{ h3 {
+"Fit result: $result" +"Fit result: $result"
} }
h3{ h3 {
+"Chi2/dof = ${result.value / (x.size - 3)}" +"Chi2/dof = ${result.value / (x.size - 3)}"
} }
} }

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -6,11 +6,11 @@
package space.kscience.kmath.linear package space.kscience.kmath.linear
import space.kscience.kmath.real.* import space.kscience.kmath.real.*
import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.DoubleBuffer
fun main() { fun main() {
val x0 = Point(0.0, 0.0, 0.0) val x0 = DoubleVector(0.0, 0.0, 0.0)
val sigma = Point(1.0, 1.0, 1.0) val sigma = DoubleVector(1.0, 1.0, 1.0)
val gaussian: (Point<Double>) -> Double = { x -> val gaussian: (Point<Double>) -> Double = { x ->
require(x.size == x0.size) require(x.size == x0.size)
@ -19,9 +19,9 @@ fun main() {
fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> { fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> {
require(x.size == x0.size) require(x.size == x0.size)
return RealBuffer(x.size) { i -> return DoubleBuffer(x.size) { i ->
val h = sigma[i] / 5 val h = sigma[i] / 5
val dVector = RealBuffer(x.size) { if (it == i) h else 0.0 } val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
val f1 = invoke(x + dVector / 2) val f1 = invoke(x + dVector / 2)
val f0 = invoke(x - dVector / 2) val f0 = invoke(x - dVector / 2)
(f1 - f0) / h (f1 - f0) / h

View File

@ -7,17 +7,17 @@ package space.kscience.kmath.operations
import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.complex import space.kscience.kmath.complex.complex
import space.kscience.kmath.nd.NDAlgebra import space.kscience.kmath.nd.AlgebraND
fun main() { fun main() {
// 2d element // 2d element
val element = NDAlgebra.complex(2, 2).produce { (i, j) -> val element = AlgebraND.complex(2, 2).produce { (i, j) ->
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble()) Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
} }
println(element) println(element)
// 1d element operation // 1d element operation
val result = with(NDAlgebra.complex(8)) { val result = with(AlgebraND.complex(8)) {
val a = produce { (it) -> i * it - it.toDouble() } val a = produce { (it) -> i * it - it.toDouble() }
val b = 3 val b = 3
val c = Complex(1.0, 1.0) val c = Complex(1.0, 1.0)

View File

@ -3,26 +3,27 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package kscience.kmath.commons.prob package space.kscience.kmath.stat
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler import org.apache.commons.rng.sampling.distribution.BoxMullerNormalizedGaussianSampler
import org.apache.commons.rng.simple.RandomSource import org.apache.commons.rng.simple.RandomSource
import space.kscience.kmath.stat.* import space.kscience.kmath.samplers.GaussianSampler
import java.time.Duration import java.time.Duration
import java.time.Instant import java.time.Instant
import org.apache.commons.rng.sampling.distribution.GaussianSampler as CMGaussianSampler
private fun runChain(): Duration { private suspend fun runKMathChained(): Duration {
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L) val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
val normal = Distribution.normal(NormalSamplerMethod.Ziggurat) val normal = GaussianSampler(7.0, 2.0)
val chain = normal.sample(generator) val chain = normal.sample(generator)
val startTime = Instant.now() val startTime = Instant.now()
var sum = 0.0 var sum = 0.0
repeat(10000001) { counter -> repeat(10000001) { counter ->
sum += chain.nextDouble() sum += chain.next()
if (counter % 100000 == 0) { if (counter % 100000 == 0) {
val duration = Duration.between(startTime, Instant.now()) val duration = Duration.between(startTime, Instant.now())
@ -34,9 +35,15 @@ private fun runChain(): Duration {
return Duration.between(startTime, Instant.now()) return Duration.between(startTime, Instant.now())
} }
private fun runDirect(): Duration { private fun runApacheDirect(): Duration {
val provider = RandomSource.create(RandomSource.MT, 123L) val rng = RandomSource.create(RandomSource.MT, 123L)
val sampler = ZigguratNormalizedGaussianSampler(provider)
val sampler = CMGaussianSampler.of(
BoxMullerNormalizedGaussianSampler.of(rng),
7.0,
2.0
)
val startTime = Instant.now() val startTime = Instant.now()
var sum = 0.0 var sum = 0.0
@ -56,11 +63,9 @@ private fun runDirect(): Duration {
/** /**
* Comparing chain sampling performance with direct sampling performance * Comparing chain sampling performance with direct sampling performance
*/ */
fun main() { fun main(): Unit = runBlocking(Dispatchers.Default) {
runBlocking(Dispatchers.Default) { val directJob = async { runApacheDirect() }
val chainJob = async { runChain() } val chainJob = async { runKMathChained() }
val directJob = async { runDirect() } println("KMath Chained: ${chainJob.await()}")
println("Chain: ${chainJob.await()}") println("Apache Direct: ${directJob.await()}")
println("Direct: ${directJob.await()}")
}
} }

View File

@ -8,14 +8,15 @@ package space.kscience.kmath.stat
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import space.kscience.kmath.chains.collectWithState import space.kscience.kmath.chains.collectWithState
import space.kscience.kmath.distributions.NormalDistribution
/** /**
* The state of distribution averager * The state of distribution averager.
*/ */
private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0) private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
/** /**
* Averaging * Averaging.
*/ */
private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChainState(), { it.copy() }) { chain -> private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChainState(), { it.copy() }) { chain ->
val next = chain.next() val next = chain.next()
@ -26,7 +27,7 @@ private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChai
fun main() { fun main() {
val normal = Distribution.normal() val normal = NormalDistribution(0.0, 2.0)
val chain = normal.sample(RandomGenerator.default).mean() val chain = normal.sample(RandomGenerator.default).mean()
runBlocking { runBlocking {

View File

@ -9,8 +9,8 @@ package space.kscience.kmath.structures
import space.kscience.kmath.complex.* import space.kscience.kmath.complex.*
import space.kscience.kmath.linear.transpose import space.kscience.kmath.linear.transpose
import space.kscience.kmath.nd.NDAlgebra import space.kscience.kmath.nd.AlgebraND
import space.kscience.kmath.nd.NDStructure import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.real import space.kscience.kmath.nd.real
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
@ -20,12 +20,12 @@ fun main() {
val dim = 1000 val dim = 1000
val n = 1000 val n = 1000
val realField = NDAlgebra.real(dim, dim) val realField = AlgebraND.real(dim, dim)
val complexField: ComplexNDField = NDAlgebra.complex(dim, dim) val complexField: ComplexFieldND = AlgebraND.complex(dim, dim)
val realTime = measureTimeMillis { val realTime = measureTimeMillis {
realField { realField {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { repeat(n) {
res += 1.0 res += 1.0
} }
@ -36,7 +36,7 @@ fun main() {
val complexTime = measureTimeMillis { val complexTime = measureTimeMillis {
complexField { complexField {
var res: NDStructure<Complex> = one var res: StructureND<Complex> = one
repeat(n) { repeat(n) {
res += 1.0 res += 1.0
} }

View File

@ -9,7 +9,7 @@ import kotlinx.coroutines.GlobalScope
import org.nd4j.linalg.factory.Nd4j import org.nd4j.linalg.factory.Nd4j
import space.kscience.kmath.nd.* import space.kscience.kmath.nd.*
import space.kscience.kmath.nd4j.Nd4jArrayField import space.kscience.kmath.nd4j.Nd4jArrayField
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import space.kscience.kmath.viktor.ViktorNDField import space.kscience.kmath.viktor.ViktorNDField
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
@ -29,56 +29,56 @@ fun main() {
val n = 1000 val n = 1000
// automatically build context most suited for given type. // automatically build context most suited for given type.
val autoField = NDAlgebra.auto(RealField, dim, dim) val autoField = AlgebraND.auto(DoubleField, dim, dim)
// specialized nd-field for Double. It works as generic Double field as well // specialized nd-field for Double. It works as generic Double field as well
val realField = NDAlgebra.real(dim, dim) val realField = AlgebraND.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives. //A generic boxing field. It should be used for objects, not primitives.
val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim) val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
// Nd4j specialized field. // Nd4j specialized field.
val nd4jField = Nd4jArrayField.real(dim, dim) val nd4jField = Nd4jArrayField.real(dim, dim)
//viktor field //viktor field
val viktorField = ViktorNDField(dim,dim) val viktorField = ViktorNDField(dim, dim)
//parallel processing based on Java Streams //parallel processing based on Java Streams
val parallelField = NDAlgebra.realWithStream(dim,dim) val parallelField = AlgebraND.realWithStream(dim, dim)
measureAndPrint("Boxing addition") { measureAndPrint("Boxing addition") {
boxingField { boxingField {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
} }
} }
measureAndPrint("Specialized addition") { measureAndPrint("Specialized addition") {
realField { realField {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
} }
} }
measureAndPrint("Nd4j specialized addition") { measureAndPrint("Nd4j specialized addition") {
nd4jField { nd4jField {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
} }
} }
measureAndPrint("Viktor addition") { measureAndPrint("Viktor addition") {
viktorField { viktorField {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
} }
} }
measureAndPrint("Parallel stream addition") { measureAndPrint("Parallel stream addition") {
parallelField { parallelField {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
} }
} }
measureAndPrint("Automatic field addition") { measureAndPrint("Automatic field addition") {
autoField { autoField {
var res: NDStructure<Double> = one var res: StructureND<Double> = one
repeat(n) { res += 1.0 } repeat(n) { res += 1.0 }
} }
} }

View File

@ -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)

View File

@ -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)

View File

@ -5,17 +5,17 @@
package space.kscience.kmath.structures package space.kscience.kmath.structures
import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.DefaultStrides
import space.kscience.kmath.nd.NDBuffer
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
fun main() { fun main() {
val n = 6000 val n = 6000
val array = DoubleArray(n * n) { 1.0 } val array = DoubleArray(n * n) { 1.0 }
val buffer = RealBuffer(array) val buffer = DoubleBuffer(array)
val strides = DefaultStrides(intArrayOf(n, n)) val strides = DefaultStrides(intArrayOf(n, n))
val structure = NDBuffer(strides, buffer) val structure = BufferND(strides, buffer)
measureTimeMillis { measureTimeMillis {
var res = 0.0 var res = 0.0

View File

@ -5,14 +5,14 @@
package space.kscience.kmath.structures package space.kscience.kmath.structures
import space.kscience.kmath.nd.NDStructure import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.mapToBuffer import space.kscience.kmath.nd.mapToBuffer
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
@Suppress("UNUSED_VARIABLE") @Suppress("UNUSED_VARIABLE")
fun main() { fun main() {
val n = 6000 val n = 6000
val structure = NDStructure.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 } val structure = StructureND.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
structure.mapToBuffer { it + 1 } // warm-up structure.mapToBuffer { it + 1 } // warm-up
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } } val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
println("Structure mapping finished in $time1 millis") println("Structure mapping finished in $time1 millis")
@ -25,10 +25,10 @@ fun main() {
println("Array mapping finished in $time2 millis") println("Array mapping finished in $time2 millis")
val buffer = RealBuffer(DoubleArray(n * n) { 1.0 }) val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 })
val time3 = measureTimeMillis { val time3 = measureTimeMillis {
val target = RealBuffer(DoubleArray(n * n)) val target = DoubleBuffer(DoubleArray(n * n))
val res = array.forEachIndexed { index, value -> val res = array.forEachIndexed { index, value ->
target[index] = value + 1 target[index] = value + 1
} }

View File

@ -9,5 +9,5 @@ kotlin.mpp.stability.nowarn=true
kotlin.native.enableDependencyPropagation=false kotlin.native.enableDependencyPropagation=false
kotlin.parallel.tasks.in.project=true kotlin.parallel.tasks.in.project=true
org.gradle.configureondemand=true org.gradle.configureondemand=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
org.gradle.parallel=true org.gradle.parallel=true

View File

@ -1,8 +1,3 @@
#
# Copyright 2018-2021 KMath contributors.
# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
#
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip

View File

@ -1,49 +1,43 @@
# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`) # Module kmath-ast
This subproject implements the following features: Abstract syntax tree expression representation and related optimizations.
- [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser - [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
- [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation - [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
- [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure - [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
- [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter - [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
- [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler - [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
- [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler - [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
> #### Artifact: ## Artifact:
>
> This module artifact: `space.kscience:kmath-ast:0.3.0-dev-2`. The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-6`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion) **Gradle:**
> ```gradle
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-ast/_latestVersion) repositories {
> maven { url 'https://repo.kotlin.link' }
> **Gradle:** maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
> ```gradle }
> repositories {
> maven { url 'https://repo.kotlin.link' } dependencies {
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' } implementation 'space.kscience:kmath-ast:0.3.0-dev-6'
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap }
> } ```
> **Gradle Kotlin DSL:**
> dependencies { ```kotlin
> implementation 'space.kscience:kmath-ast:0.3.0-dev-2' repositories {
> } maven("https://repo.kotlin.link")
> ``` maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
> **Gradle Kotlin DSL:** maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
> }
> ```kotlin
> repositories { dependencies {
> maven("https://repo.kotlin.link") implementation("space.kscience:kmath-ast:0.3.0-dev-6")
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap }
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a ```
> }
>
> dependencies {
> implementation("space.kscience:kmath-ast:0.3.0-dev-2")
> }
> ```
## Dynamic expression code generation ## Dynamic expression code generation
@ -55,7 +49,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder: For example, the following builder:
```kotlin ```kotlin
RealField.mstInField { symbol("x") + 2 }.compile() DoubleField.mstInField { symbol("x") + 2 }.compile()
``` ```
… leads to generation of bytecode, which can be decompiled to the following Java class: … leads to generation of bytecode, which can be decompiled to the following Java class:
@ -88,8 +82,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
This API extends MST and MstExpression, so you may optimize as both of them: This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin ```kotlin
RealField.mstInField { symbol("x") + 2 }.compile() DoubleField.mstInField { symbol("x") + 2 }.compile()
RealField.expression("x+2".parseMath()) DoubleField.expression("x+2".parseMath())
``` ```
#### Known issues #### Known issues
@ -103,7 +97,7 @@ RealField.expression("x+2".parseMath())
A similar feature is also available on JS. A similar feature is also available on JS.
```kotlin ```kotlin
RealField.mstInField { symbol("x") + 2 }.compile() DoubleField.mstInField { symbol("x") + 2 }.compile()
``` ```
The code above returns expression implemented with such a JS function: The code above returns expression implemented with such a JS function:
@ -117,3 +111,39 @@ var executable = function (constants, arguments) {
#### Known issues #### Known issues
- This feature uses `eval` which can be unavailable in several environments. - This feature uses `eval` which can be unavailable in several environments.
## Rendering expressions
kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
Example usage:
```kotlin
import space.kscience.kmath.ast.*
import space.kscience.kmath.ast.rendering.*
public fun main() {
val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
println("LaTeX:")
println(latex)
println()
val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax)
println("MathML:")
println(mathML)
}
```
Result LaTeX:
![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D)
Result MathML (embedding MathML is not allowed by GitHub Markdown):
```html
<mrow><msup><mrow><mi>e</mi></mrow><mrow><msqrt><mi>x</mi></msqrt></mrow></msup><mo>-</mo><mfrac><mrow><mfrac><mrow><msup><mrow><mo>sin</mo></mrow><mrow><mo>-</mo><mn>1</mn></mrow></msup><mspace width="0.167em"></mspace><mfenced open="(" close=")" separators=""><mn>2</mn><mspace width="0.167em"></mspace><mi>x</mi></mfenced></mrow><mrow><mn>2</mn><mo>&times;</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).

View File

@ -6,7 +6,8 @@
import ru.mipt.npm.gradle.Maturity import ru.mipt.npm.gradle.Maturity
plugins { plugins {
id("ru.mipt.npm.gradle.mpp") kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
} }
kotlin.js { kotlin.js {
@ -63,36 +64,36 @@ readme {
feature( feature(
id = "expression-language", id = "expression-language",
description = "Expression language and its parser", description = "Expression language and its parser",
ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt" ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt"
) )
feature( feature(
id = "mst", id = "mst",
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation", description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
) )
feature( feature(
id = "mst-building", id = "mst-building",
description = "MST building algebraic structure", description = "MST building algebraic structure",
ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt"
) )
feature( feature(
id = "mst-interpreter", id = "mst-interpreter",
description = "MST interpreter", description = "MST interpreter",
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
) )
feature( feature(
id = "mst-jvm-codegen", id = "mst-jvm-codegen",
description = "Dynamic MST to JVM bytecode compiler", description = "Dynamic MST to JVM bytecode compiler",
ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt" ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt"
) )
feature( feature(
id = "mst-js-codegen", id = "mst-js-codegen",
description = "Dynamic MST to JS compiler", description = "Dynamic MST to JS compiler",
ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt" ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt"
) )
} }

View File

@ -1,6 +1,6 @@
# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`) # Module kmath-ast
This subproject implements the following features: Abstract syntax tree expression representation and related optimizations.
${features} ${features}
@ -16,7 +16,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder: For example, the following builder:
```kotlin ```kotlin
RealField.mstInField { symbol("x") + 2 }.compile() DoubleField.mstInField { symbol("x") + 2 }.compile()
``` ```
… leads to generation of bytecode, which can be decompiled to the following Java class: … leads to generation of bytecode, which can be decompiled to the following Java class:
@ -49,8 +49,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
This API extends MST and MstExpression, so you may optimize as both of them: This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin ```kotlin
RealField.mstInField { symbol("x") + 2 }.compile() DoubleField.mstInField { symbol("x") + 2 }.compile()
RealField.expression("x+2".parseMath()) DoubleField.expression("x+2".parseMath())
``` ```
#### Known issues #### Known issues
@ -64,7 +64,7 @@ RealField.expression("x+2".parseMath())
A similar feature is also available on JS. A similar feature is also available on JS.
```kotlin ```kotlin
RealField.mstInField { symbol("x") + 2 }.compile() DoubleField.mstInField { symbol("x") + 2 }.compile()
``` ```
The code above returns expression implemented with such a JS function: The code above returns expression implemented with such a JS function:
@ -78,3 +78,39 @@ var executable = function (constants, arguments) {
#### Known issues #### Known issues
- This feature uses `eval` which can be unavailable in several environments. - This feature uses `eval` which can be unavailable in several environments.
## Rendering expressions
kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
Example usage:
```kotlin
import space.kscience.kmath.ast.*
import space.kscience.kmath.ast.rendering.*
public fun main() {
val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
println("LaTeX:")
println(latex)
println()
val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax)
println("MathML:")
println(mathML)
}
```
Result LaTeX:
![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D)
Result MathML (embedding MathML is not allowed by GitHub Markdown):
```html
<mrow><msup><mrow><mi>e</mi></mrow><mrow><msqrt><mi>x</mi></msqrt></mrow></msup><mo>-</mo><mfrac><mrow><mfrac><mrow><msup><mrow><mo>sin</mo></mrow><mrow><mo>-</mo><mn>1</mn></mrow></msup><mspace width="0.167em"></mspace><mfenced open="(" close=")" separators=""><mn>2</mn><mspace width="0.167em"></mspace><mi>x</mi></mfenced></mrow><mrow><mn>2</mn><mo>&times;</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).

View File

@ -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)
}

View File

@ -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)
}
}
}
}

View File

@ -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("&infin;") }
SpecialSymbolSyntax.Kind.SMALL_PI -> tag("mo") { append("&pi;") }
}
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("&times;") } else tag("mspace", "width" to "0.167em")
render(node.right)
}
}
}
}

View File

@ -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,
),
)
}
}

View File

@ -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 (&infin;) symbol.
*/
INFINITY,
/**
* The Pi (&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&times;2).
*
* @property left The multiplicand.
* @property right The multiplier.
* @property times whether the times (&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
}
}

View File

@ -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()
}

View File

@ -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,
))
}
}

View File

@ -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 (&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
}
}
}
}

View File

@ -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)
}
}

View File

@ -5,12 +5,13 @@
package space.kscience.kmath.estree package space.kscience.kmath.estree
import space.kscience.kmath.ast.MST
import space.kscience.kmath.ast.MST.*
import space.kscience.kmath.ast.MstExpression
import space.kscience.kmath.estree.internal.ESTreeBuilder import space.kscience.kmath.estree.internal.ESTreeBuilder
import space.kscience.kmath.estree.internal.estree.BaseExpression import space.kscience.kmath.estree.internal.estree.BaseExpression
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.expressions.MST.*
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra import space.kscience.kmath.operations.NumericAlgebra
@ -18,11 +19,7 @@ import space.kscience.kmath.operations.NumericAlgebra
internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> { internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
fun ESTreeBuilder<T>.visit(node: MST): BaseExpression = when (node) { fun ESTreeBuilder<T>.visit(node: MST): BaseExpression = when (node) {
is Symbolic -> { is Symbolic -> {
val symbol = try { val symbol = algebra.bindSymbolOrNull(node.value)
algebra.bindSymbol(node.value)
} catch (ignored: IllegalStateException) {
null
}
if (symbol != null) if (symbol != null)
constant(symbol) constant(symbol)
@ -34,16 +31,17 @@ internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
is Unary -> when { is Unary -> when {
algebra is NumericAlgebra && node.value is Numeric -> constant( algebra is NumericAlgebra && node.value is Numeric -> constant(
algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value))) algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value))
} }
is Binary -> when { is Binary -> when {
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant( algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant(
algebra algebra.binaryOperationFunction(node.operation).invoke(
.binaryOperationFunction(node.operation) algebra.number((node.left as Numeric).value),
.invoke(algebra.number(node.left.value), algebra.number(node.right.value)) algebra.number((node.right as Numeric).value)
)
) )
algebra is NumericAlgebra && node.left is Numeric -> call( algebra is NumericAlgebra && node.left is Numeric -> call(
@ -69,19 +67,21 @@ internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
return ESTreeBuilder<T> { visit(this@compileWith) }.instance return ESTreeBuilder<T> { visit(this@compileWith) }.instance
} }
/**
* Create a compiled expression with given [MST] and given [algebra].
*/
public fun <T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> = compileWith(algebra)
/** /**
* Compiles an [MST] to ESTree generated expression using given algebra. * Compile given MST to expression and evaluate it against [arguments]
*
* @author Alexander Nozik.
*/ */
public fun <T : Any> Algebra<T>.expression(mst: MST): Expression<T> = public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
mst.compileWith(this) compileToExpression(algebra).invoke(arguments)
/** /**
* Optimizes performance of an [MstExpression] by compiling it into ESTree generated expression. * Compile given MST to expression and evaluate it against [arguments]
*
* @author Alexander Nozik.
*/ */
public fun <T : Any> MstExpression<T, Algebra<T>>.compile(): Expression<T> = public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T =
mst.compileWith(algebra) compileToExpression(algebra).invoke(*arguments)

View File

@ -8,7 +8,7 @@ package space.kscience.kmath.estree.internal
import space.kscience.kmath.estree.internal.astring.generate import space.kscience.kmath.estree.internal.astring.generate
import space.kscience.kmath.estree.internal.estree.* import space.kscience.kmath.estree.internal.estree.*
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.Symbol
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) { internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {
private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> { private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> {

View File

@ -5,19 +5,22 @@
package space.kscience.kmath.estree package space.kscience.kmath.estree
import space.kscience.kmath.ast.*
import space.kscience.kmath.complex.ComplexField import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.toComplex import space.kscience.kmath.complex.toComplex
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.ByteRing import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class TestESTreeConsistencyWithInterpreter { internal class TestESTreeConsistencyWithInterpreter {
@Test @Test
fun mstSpace() { fun mstSpace() {
val res1 = MstGroup.mstInGroup {
val mst = MstGroup {
binaryOperationFunction("+")( binaryOperationFunction("+")(
unaryOperationFunction("+")( unaryOperationFunction("+")(
number(3.toByte()) - (number(2.toByte()) + (scale( number(3.toByte()) - (number(2.toByte()) + (scale(
@ -28,27 +31,17 @@ internal class TestESTreeConsistencyWithInterpreter {
number(1) number(1)
) + bindSymbol("x") + zero ) + bindSymbol("x") + zero
}("x" to MST.Numeric(2)) }
val res2 = MstGroup.mstInGroup { assertEquals(
binaryOperationFunction("+")( mst.interpret(MstGroup, Symbol.x to MST.Numeric(2)),
unaryOperationFunction("+")( mst.compile(MstGroup, Symbol.x to MST.Numeric(2))
number(3.toByte()) - (number(2.toByte()) + (scale( )
add(number(1), number(1)),
2.0
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
),
number(1)
) + bindSymbol("x") + zero
}.compile()("x" to MST.Numeric(2))
assertEquals(res1, res2)
} }
@Test @Test
fun byteRing() { fun byteRing() {
val res1 = ByteRing.mstInRing { val mst = MstRing {
binaryOperationFunction("+")( binaryOperationFunction("+")(
unaryOperationFunction("+")( unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (scale( (bindSymbol("x") - (2.toByte() + (scale(
@ -59,62 +52,43 @@ internal class TestESTreeConsistencyWithInterpreter {
number(1) number(1)
) * number(2) ) * number(2)
}("x" to 3.toByte()) }
val res2 = ByteRing.mstInRing { assertEquals(
binaryOperationFunction("+")( mst.interpret(ByteRing, Symbol.x to 3.toByte()),
unaryOperationFunction("+")( mst.compile(ByteRing, Symbol.x to 3.toByte())
(bindSymbol("x") - (2.toByte() + (scale( )
add(number(1), number(1)),
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
),
number(1)
) * number(2)
}.compile()("x" to 3.toByte())
assertEquals(res1, res2)
} }
@Test @Test
fun realField() { fun realField() {
val res1 = RealField.mstInField { val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1), + number(1),
number(1) / 2 + number(2.0) * one number(1) / 2 + number(2.0) * one
) + zero ) + zero
}("x" to 2.0) }
val res2 = RealField.mstInField { assertEquals(
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( mst.interpret(DoubleField, Symbol.x to 2.0),
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 mst.compile(DoubleField, Symbol.x to 2.0)
+ number(1), )
number(1) / 2 + number(2.0) * one
) + zero
}.compile()("x" to 2.0)
assertEquals(res1, res2)
} }
@Test @Test
fun complexField() { fun complexField() {
val res1 = ComplexField.mstInField { val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1), + number(1),
number(1) / 2 + number(2.0) * one number(1) / 2 + number(2.0) * one
) + zero ) + zero
}("x" to 2.0.toComplex()) }
val res2 = ComplexField.mstInField { assertEquals(
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( mst.interpret(ComplexField, Symbol.x to 2.0.toComplex()),
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 mst.compile(ComplexField, Symbol.x to 2.0.toComplex())
+ number(1), )
number(1) / 2 + number(2.0) * one
) + zero
}.compile()("x" to 2.0.toComplex())
assertEquals(res1, res2)
} }
} }

View File

@ -5,11 +5,10 @@
package space.kscience.kmath.estree package space.kscience.kmath.estree
import space.kscience.kmath.ast.mstInExtendedField import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.ast.mstInField
import space.kscience.kmath.ast.mstInGroup
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import kotlin.random.Random import kotlin.random.Random
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -17,27 +16,29 @@ import kotlin.test.assertEquals
internal class TestESTreeOperationsSupport { internal class TestESTreeOperationsSupport {
@Test @Test
fun testUnaryOperationInvocation() { fun testUnaryOperationInvocation() {
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile() val expression = MstExtendedField { -bindSymbol("x") }.compileToExpression(DoubleField)
val res = expression("x" to 2.0) val res = expression("x" to 2.0)
assertEquals(-2.0, res) assertEquals(-2.0, res)
} }
@Test @Test
fun testBinaryOperationInvocation() { fun testBinaryOperationInvocation() {
val expression = RealField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile() val expression = MstExtendedField { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0) val res = expression("x" to 2.0)
assertEquals(-1.0, res) assertEquals(-1.0, res)
} }
@Test @Test
fun testConstProductInvocation() { fun testConstProductInvocation() {
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0) val res = MstExtendedField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
assertEquals(4.0, res) assertEquals(4.0, res)
} }
@Test @Test
fun testMultipleCalls() { fun testMultipleCalls() {
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile() val e =
MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
.compileToExpression(DoubleField)
val r = Random(0) val r = Random(0)
var s = 0.0 var s = 0.0
repeat(1000000) { s += e("x" to r.nextDouble()) } repeat(1000000) { s += e("x" to r.nextDouble()) }

View File

@ -5,54 +5,64 @@
package space.kscience.kmath.estree package space.kscience.kmath.estree
import space.kscience.kmath.ast.mstInField import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class TestESTreeSpecialization { internal class TestESTreeSpecialization {
@Test @Test
fun testUnaryPlus() { fun testUnaryPlus() {
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile() val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(2.0, expr("x" to 2.0)) assertEquals(2.0, expr("x" to 2.0))
} }
@Test @Test
fun testUnaryMinus() { fun testUnaryMinus() {
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile() val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr("x" to 2.0)) assertEquals(-2.0, expr("x" to 2.0))
} }
@Test @Test
fun testAdd() { fun testAdd() {
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile() val expr = MstExtendedField {
binaryOperationFunction("+")(bindSymbol("x"),
bindSymbol("x"))
}.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0)) assertEquals(4.0, expr("x" to 2.0))
} }
@Test @Test
fun testSine() { fun testSine() {
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile() val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 0.0)) assertEquals(0.0, expr("x" to 0.0))
} }
@Test @Test
fun testMinus() { fun testMinus() {
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile() val expr = MstExtendedField {
binaryOperationFunction("-")(bindSymbol("x"),
bindSymbol("x"))
}.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 2.0)) assertEquals(0.0, expr("x" to 2.0))
} }
@Test @Test
fun testDivide() { fun testDivide() {
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile() val expr = MstExtendedField {
binaryOperationFunction("/")(bindSymbol("x"),
bindSymbol("x"))
}.compileToExpression(DoubleField)
assertEquals(1.0, expr("x" to 2.0)) assertEquals(1.0, expr("x" to 2.0))
} }
@Test @Test
fun testPower() { fun testPower() {
val expr = RealField val expr = MstExtendedField {
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) } binaryOperationFunction("pow")(bindSymbol("x"), number(2))
.compile() }.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0)) assertEquals(4.0, expr("x" to 2.0))
} }

View File

@ -5,9 +5,10 @@
package space.kscience.kmath.estree package space.kscience.kmath.estree
import space.kscience.kmath.ast.mstInRing import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.ByteRing import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
@ -15,13 +16,13 @@ import kotlin.test.assertFailsWith
internal class TestESTreeVariables { internal class TestESTreeVariables {
@Test @Test
fun testVariable() { fun testVariable() {
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile() val expr = MstRing{ bindSymbol("x") }.compileToExpression(ByteRing)
assertEquals(1.toByte(), expr("x" to 1.toByte())) assertEquals(1.toByte(), expr("x" to 1.toByte()))
} }
@Test @Test
fun testUndefinedVariableFails() { fun testUndefinedVariableFails() {
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile() val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
assertFailsWith<NoSuchElementException> { expr() } assertFailsWith<NoSuchElementException> { expr() }
} }
} }

View File

@ -7,10 +7,11 @@ package space.kscience.kmath.asm
import space.kscience.kmath.asm.internal.AsmBuilder import space.kscience.kmath.asm.internal.AsmBuilder
import space.kscience.kmath.asm.internal.buildName import space.kscience.kmath.asm.internal.buildName
import space.kscience.kmath.ast.MST
import space.kscience.kmath.ast.MST.*
import space.kscience.kmath.ast.MstExpression
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.expressions.MST.*
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra import space.kscience.kmath.operations.NumericAlgebra
@ -26,11 +27,7 @@ import space.kscience.kmath.operations.NumericAlgebra
internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Expression<T> { internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Expression<T> {
fun AsmBuilder<T>.visit(node: MST): Unit = when (node) { fun AsmBuilder<T>.visit(node: MST): Unit = when (node) {
is Symbolic -> { is Symbolic -> {
val symbol = try { val symbol = algebra.bindSymbolOrNull(node.value)
algebra.bindSymbol(node.value)
} catch (ignored: IllegalStateException) {
null
}
if (symbol != null) if (symbol != null)
loadObjectConstant(symbol as Any) loadObjectConstant(symbol as Any)
@ -42,15 +39,17 @@ internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Exp
is Unary -> when { is Unary -> when {
algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant( algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant(
algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value))) algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) } else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) }
} }
is Binary -> when { is Binary -> when {
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant( algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant(
algebra.binaryOperationFunction(node.operation) algebra.binaryOperationFunction(node.operation).invoke(
.invoke(algebra.number(node.left.value), algebra.number(node.right.value)) algebra.number((node.left as Numeric).value),
algebra.number((node.right as Numeric).value)
)
) )
algebra is NumericAlgebra && node.left is Numeric -> buildCall( algebra is NumericAlgebra && node.left is Numeric -> buildCall(
@ -75,18 +74,22 @@ internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Exp
return AsmBuilder<T>(type, buildName(this)) { visit(this@compileWith) }.instance return AsmBuilder<T>(type, buildName(this)) { visit(this@compileWith) }.instance
} }
/**
* Compiles an [MST] to ASM using given algebra.
*
* @author Alexander Nozik.
*/
public inline fun <reified T : Any> Algebra<T>.expression(mst: MST): Expression<T> =
mst.compileWith(T::class.java, this)
/** /**
* Optimizes performance of an [MstExpression] using ASM codegen. * Create a compiled expression with given [MST] and given [algebra].
*
* @author Alexander Nozik.
*/ */
public inline fun <reified T : Any> MstExpression<T, Algebra<T>>.compile(): Expression<T> = public inline fun <reified T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> =
mst.compileWith(T::class.java, algebra) compileWith(T::class.java, algebra)
/**
* Compile given MST to expression and evaluate it against [arguments]
*/
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
compileToExpression(algebra).invoke(arguments)
/**
* Compile given MST to expression and evaluate it against [arguments]
*/
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T =
compileToExpression(algebra).invoke(*arguments)

View File

@ -10,8 +10,8 @@ import org.objectweb.asm.Opcodes.*
import org.objectweb.asm.Type.* import org.objectweb.asm.Type.*
import org.objectweb.asm.commons.InstructionAdapter import org.objectweb.asm.commons.InstructionAdapter
import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader
import space.kscience.kmath.ast.MST
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import java.lang.invoke.MethodHandles import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType import java.lang.invoke.MethodType
import java.util.stream.Collectors.toMap import java.util.stream.Collectors.toMap

View File

@ -7,8 +7,8 @@ package space.kscience.kmath.asm.internal
import org.objectweb.asm.* import org.objectweb.asm.*
import org.objectweb.asm.commons.InstructionAdapter import org.objectweb.asm.commons.InstructionAdapter
import space.kscience.kmath.ast.MST
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
@ -91,7 +91,7 @@ internal inline fun ClassWriter.visitField(
descriptor: String, descriptor: String,
signature: String?, signature: String?,
value: Any?, value: Any?,
block: FieldVisitor.() -> Unit block: FieldVisitor.() -> Unit,
): FieldVisitor { ): FieldVisitor {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return visitField(access, name, descriptor, signature, value).apply(block) return visitField(access, name, descriptor, signature, value).apply(block)

View File

@ -7,8 +7,8 @@
package space.kscience.kmath.asm.internal package space.kscience.kmath.asm.internal
import space.kscience.kmath.expressions.StringSymbol import space.kscience.kmath.misc.StringSymbol
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.Symbol
/** /**
* Gets value with given [key] or throws [NoSuchElementException] whenever it is not present. * Gets value with given [key] or throws [NoSuchElementException] whenever it is not present.

View File

@ -18,6 +18,7 @@ import com.github.h0tk3y.betterParse.lexer.literalToken
import com.github.h0tk3y.betterParse.lexer.regexToken import com.github.h0tk3y.betterParse.lexer.regexToken
import com.github.h0tk3y.betterParse.parser.ParseResult import com.github.h0tk3y.betterParse.parser.ParseResult
import com.github.h0tk3y.betterParse.parser.Parser import com.github.h0tk3y.betterParse.parser.Parser
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.FieldOperations import space.kscience.kmath.operations.FieldOperations
import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.GroupOperations
import space.kscience.kmath.operations.PowerOperations import space.kscience.kmath.operations.PowerOperations
@ -26,7 +27,8 @@ import space.kscience.kmath.operations.RingOperations
/** /**
* better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4. * better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4.
* *
* @author Alexander Nozik and Iaroslav Postovalov * @author Alexander Nozik
* @author Iaroslav Postovalov
*/ */
public object ArithmeticsEvaluator : Grammar<MST>() { public object ArithmeticsEvaluator : Grammar<MST>() {
// TODO replace with "...".toRegex() when better-parse 0.4.1 is released // TODO replace with "...".toRegex() when better-parse 0.4.1 is released

View File

@ -5,19 +5,22 @@
package space.kscience.kmath.asm package space.kscience.kmath.asm
import space.kscience.kmath.ast.*
import space.kscience.kmath.complex.ComplexField import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.toComplex import space.kscience.kmath.complex.toComplex
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.Symbol.Companion.x
import space.kscience.kmath.operations.ByteRing import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class TestAsmConsistencyWithInterpreter { internal class TestAsmConsistencyWithInterpreter {
@Test @Test
fun mstSpace() { fun mstSpace() {
val res1 = MstGroup.mstInGroup {
val mst = MstGroup {
binaryOperationFunction("+")( binaryOperationFunction("+")(
unaryOperationFunction("+")( unaryOperationFunction("+")(
number(3.toByte()) - (number(2.toByte()) + (scale( number(3.toByte()) - (number(2.toByte()) + (scale(
@ -28,27 +31,17 @@ internal class TestAsmConsistencyWithInterpreter {
number(1) number(1)
) + bindSymbol("x") + zero ) + bindSymbol("x") + zero
}("x" to MST.Numeric(2)) }
val res2 = MstGroup.mstInGroup { assertEquals(
binaryOperationFunction("+")( mst.interpret(MstGroup, x to MST.Numeric(2)),
unaryOperationFunction("+")( mst.compile(MstGroup, x to MST.Numeric(2))
number(3.toByte()) - (number(2.toByte()) + (scale( )
add(number(1), number(1)),
2.0
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
),
number(1)
) + bindSymbol("x") + zero
}.compile()("x" to MST.Numeric(2))
assertEquals(res1, res2)
} }
@Test @Test
fun byteRing() { fun byteRing() {
val res1 = ByteRing.mstInRing { val mst = MstRing {
binaryOperationFunction("+")( binaryOperationFunction("+")(
unaryOperationFunction("+")( unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (scale( (bindSymbol("x") - (2.toByte() + (scale(
@ -59,62 +52,43 @@ internal class TestAsmConsistencyWithInterpreter {
number(1) number(1)
) * number(2) ) * number(2)
}("x" to 3.toByte()) }
val res2 = ByteRing.mstInRing { assertEquals(
binaryOperationFunction("+")( mst.interpret(ByteRing, x to 3.toByte()),
unaryOperationFunction("+")( mst.compile(ByteRing, x to 3.toByte())
(bindSymbol("x") - (2.toByte() + (scale( )
add(number(1), number(1)),
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
),
number(1)
) * number(2)
}.compile()("x" to 3.toByte())
assertEquals(res1, res2)
} }
@Test @Test
fun realField() { fun realField() {
val res1 = RealField.mstInField { val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1), + number(1),
number(1) / 2 + number(2.0) * one number(1) / 2 + number(2.0) * one
) + zero ) + zero
}("x" to 2.0) }
val res2 = RealField.mstInField { assertEquals(
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( mst.interpret(DoubleField, x to 2.0),
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 mst.compile(DoubleField, x to 2.0)
+ number(1), )
number(1) / 2 + number(2.0) * one
) + zero
}.compile()("x" to 2.0)
assertEquals(res1, res2)
} }
@Test @Test
fun complexField() { fun complexField() {
val res1 = ComplexField.mstInField { val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1), + number(1),
number(1) / 2 + number(2.0) * one number(1) / 2 + number(2.0) * one
) + zero ) + zero
}("x" to 2.0.toComplex()) }
val res2 = ComplexField.mstInField { assertEquals(
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( mst.interpret(ComplexField, x to 2.0.toComplex()),
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 mst.compile(ComplexField, x to 2.0.toComplex())
+ number(1), )
number(1) / 2 + number(2.0) * one
) + zero
}.compile()("x" to 2.0.toComplex())
assertEquals(res1, res2)
} }
} }

View File

@ -5,11 +5,12 @@
package space.kscience.kmath.asm package space.kscience.kmath.asm
import space.kscience.kmath.ast.mstInExtendedField import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.ast.mstInField import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.ast.mstInGroup import space.kscience.kmath.expressions.MstGroup
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import kotlin.random.Random import kotlin.random.Random
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -17,27 +18,29 @@ import kotlin.test.assertEquals
internal class TestAsmOperationsSupport { internal class TestAsmOperationsSupport {
@Test @Test
fun testUnaryOperationInvocation() { fun testUnaryOperationInvocation() {
val expression = RealField.mstInGroup { -bindSymbol("x") }.compile() val expression = MstGroup { -bindSymbol("x") }.compileToExpression(DoubleField)
val res = expression("x" to 2.0) val res = expression("x" to 2.0)
assertEquals(-2.0, res) assertEquals(-2.0, res)
} }
@Test @Test
fun testBinaryOperationInvocation() { fun testBinaryOperationInvocation() {
val expression = RealField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile() val expression = MstGroup { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0) val res = expression("x" to 2.0)
assertEquals(-1.0, res) assertEquals(-1.0, res)
} }
@Test @Test
fun testConstProductInvocation() { fun testConstProductInvocation() {
val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0) val res = MstField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
assertEquals(4.0, res) assertEquals(4.0, res)
} }
@Test @Test
fun testMultipleCalls() { fun testMultipleCalls() {
val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile() val e =
MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
.compileToExpression(DoubleField)
val r = Random(0) val r = Random(0)
var s = 0.0 var s = 0.0
repeat(1000000) { s += e("x" to r.nextDouble()) } repeat(1000000) { s += e("x" to r.nextDouble()) }

View File

@ -5,54 +5,64 @@
package space.kscience.kmath.asm package space.kscience.kmath.asm
import space.kscience.kmath.ast.mstInField import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class TestAsmSpecialization { internal class TestAsmSpecialization {
@Test @Test
fun testUnaryPlus() { fun testUnaryPlus() {
val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile() val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(2.0, expr("x" to 2.0)) assertEquals(2.0, expr("x" to 2.0))
} }
@Test @Test
fun testUnaryMinus() { fun testUnaryMinus() {
val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile() val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr("x" to 2.0)) assertEquals(-2.0, expr("x" to 2.0))
} }
@Test @Test
fun testAdd() { fun testAdd() {
val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile() val expr = MstExtendedField {
binaryOperationFunction("+")(bindSymbol("x"),
bindSymbol("x"))
}.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0)) assertEquals(4.0, expr("x" to 2.0))
} }
@Test @Test
fun testSine() { fun testSine() {
val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile() val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 0.0)) assertEquals(0.0, expr("x" to 0.0))
} }
@Test @Test
fun testMinus() { fun testMinus() {
val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile() val expr = MstExtendedField {
binaryOperationFunction("-")(bindSymbol("x"),
bindSymbol("x"))
}.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 2.0)) assertEquals(0.0, expr("x" to 2.0))
} }
@Test @Test
fun testDivide() { fun testDivide() {
val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile() val expr = MstExtendedField {
binaryOperationFunction("/")(bindSymbol("x"),
bindSymbol("x"))
}.compileToExpression(DoubleField)
assertEquals(1.0, expr("x" to 2.0)) assertEquals(1.0, expr("x" to 2.0))
} }
@Test @Test
fun testPower() { fun testPower() {
val expr = RealField val expr = MstExtendedField {
.mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) } binaryOperationFunction("pow")(bindSymbol("x"), number(2))
.compile() }.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0)) assertEquals(4.0, expr("x" to 2.0))
} }

View File

@ -5,9 +5,10 @@
package space.kscience.kmath.asm package space.kscience.kmath.asm
import space.kscience.kmath.ast.mstInRing import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.ByteRing import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
@ -15,13 +16,13 @@ import kotlin.test.assertFailsWith
internal class TestAsmVariables { internal class TestAsmVariables {
@Test @Test
fun testVariable() { fun testVariable() {
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile() val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
assertEquals(1.toByte(), expr("x" to 1.toByte())) assertEquals(1.toByte(), expr("x" to 1.toByte()))
} }
@Test @Test
fun testUndefinedVariableFails() { fun testUndefinedVariableFails() {
val expr = ByteRing.mstInRing { bindSymbol("x") }.compile() val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
assertFailsWith<NoSuchElementException> { expr() } assertFailsWith<NoSuchElementException> { expr() }
} }
} }

View File

@ -5,13 +5,14 @@
package space.kscience.kmath.ast package space.kscience.kmath.ast
import space.kscience.kmath.expressions.evaluate
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.RealField
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class ParserPrecedenceTest { internal class ParserPrecedenceTest {
private val f: Field<Double> = RealField private val f: Field<Double> = DoubleField
@Test @Test
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath())) fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))

View File

@ -7,9 +7,12 @@ package space.kscience.kmath.ast
import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.ComplexField import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.evaluate
import space.kscience.kmath.expressions.interpret
import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -23,7 +26,7 @@ internal class ParserTest {
@Test @Test
fun `evaluate MSTExpression`() { fun `evaluate MSTExpression`() {
val res = ComplexField.mstInField { number(2) + number(2) * (number(2) + number(2)) }() val res = MstField.invoke { number(2) + number(2) * (number(2) + number(2)) }.interpret(ComplexField)
assertEquals(Complex(10.0, 0.0), res) assertEquals(Complex(10.0, 0.0), res)
} }
@ -38,14 +41,14 @@ internal class ParserTest {
@Test @Test
fun `evaluate MST with unary function`() { fun `evaluate MST with unary function`() {
val mst = "sin(0)".parseMath() val mst = "sin(0)".parseMath()
val res = RealField.evaluate(mst) val res = DoubleField.evaluate(mst)
assertEquals(0.0, res) assertEquals(0.0, res)
} }
@Test @Test
fun `evaluate MST with binary function`() { fun `evaluate MST with binary function`() {
val magicalAlgebra = object : Algebra<String> { val magicalAlgebra = object : Algebra<String> {
override fun bindSymbol(value: String): String = value override fun bindSymbolOrNull(value: String): String = value
override fun unaryOperationFunction(operation: String): (arg: String) -> String { override fun unaryOperationFunction(operation: String): (arg: String) -> String {
throw NotImplementedError() throw NotImplementedError()

View File

@ -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")
// }
}

View File

@ -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")
}
}

View File

@ -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>&infin;</mo>")
testMathML("pi", "<mo>&pi;</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>&times;</mo><mn>1</mn>")
testMathML("1*x", "<mn>1</mn><mspace width=\"0.167em\"></mspace><mi>x</mi>")
}
}

View File

@ -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}")
}
}

View File

@ -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),
)
}

View File

@ -4,7 +4,8 @@
*/ */
plugins { plugins {
id("ru.mipt.npm.gradle.jvm") kotlin("jvm")
id("ru.mipt.npm.gradle.common")
} }
description = "Commons math binding for kmath" description = "Commons math binding for kmath"
@ -17,6 +18,6 @@ dependencies {
api("org.apache.commons:commons-math3:3.6.1") api("org.apache.commons:commons-math3:3.6.1")
} }
readme{ readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
} }

View File

@ -7,6 +7,7 @@ package space.kscience.kmath.commons.expressions
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
import space.kscience.kmath.expressions.* import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.NumbersAddOperations import space.kscience.kmath.operations.NumbersAddOperations
@ -28,7 +29,7 @@ public class DerivativeStructureField(
public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) }
public override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) } public override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) }
override fun number(value: Number): DerivativeStructure = const(value.toDouble()) public override fun number(value: Number): DerivativeStructure = const(value.toDouble())
/** /**
* A class that implements both [DerivativeStructure] and a [Symbol] * A class that implements both [DerivativeStructure] and a [Symbol]
@ -39,10 +40,10 @@ public class DerivativeStructureField(
symbol: Symbol, symbol: Symbol,
value: Double, value: Double,
) : DerivativeStructure(size, order, index, value), Symbol { ) : DerivativeStructure(size, order, index, value), Symbol {
override val identity: String = symbol.identity public override val identity: String = symbol.identity
override fun toString(): String = identity public override fun toString(): String = identity
override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity public override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity
override fun hashCode(): Int = identity.hashCode() public override fun hashCode(): Int = identity.hashCode()
} }
/** /**
@ -52,13 +53,13 @@ public class DerivativeStructureField(
key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value) key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value)
}.toMap() }.toMap()
override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value) public override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value)
public override fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity] public override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[value]
public override fun bindSymbol(value: String): DerivativeStructureSymbol = variables.getValue(value)
public fun bind(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity) public fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity]
public fun bindSymbol(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity)
override fun bindSymbol(value: String): DerivativeStructureSymbol = bind(StringSymbol(value))
public fun DerivativeStructure.derivative(symbols: List<Symbol>): Double { public fun DerivativeStructure.derivative(symbols: List<Symbol>): Double {
require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" } require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" }
@ -68,7 +69,7 @@ public class DerivativeStructureField(
public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList()) public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList())
override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() public override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate()
public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b)
@ -111,7 +112,6 @@ public class DerivativeStructureField(
} }
} }
/** /**
* A constructs that creates a derivative structure with required order on-demand * A constructs that creates a derivative structure with required order on-demand
*/ */

View File

@ -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)) }
}

View File

@ -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!!
}
}

View File

@ -8,9 +8,9 @@ package space.kscience.kmath.commons.linear
import org.apache.commons.math3.linear.* import org.apache.commons.math3.linear.*
import space.kscience.kmath.linear.* import space.kscience.kmath.linear.*
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.NDStructure import space.kscience.kmath.nd.StructureFeature
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.DoubleBuffer
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.cast import kotlin.reflect.cast
@ -19,17 +19,9 @@ public class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
public override val colNum: Int get() = origin.columnDimension public override val colNum: Int get() = origin.columnDimension
public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is NDStructure<*>) return false
return NDStructure.contentEquals(this, other)
}
override fun hashCode(): Int = origin.hashCode()
} }
public 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 val size: Int get() = origin.dimension
public override operator fun get(index: Int): Double = origin.getEntry(index) public override operator fun get(index: Int): Double = origin.getEntry(index)
@ -39,15 +31,15 @@ public inline class CMVector(public val origin: RealVector) : Point<Double> {
public fun RealVector.toPoint(): CMVector = CMVector(this) public fun RealVector.toPoint(): CMVector = CMVector(this)
public object CMLinearSpace : LinearSpace<Double, RealField> { public object CMLinearSpace : LinearSpace<Double, DoubleField> {
override val elementAlgebra: RealField get() = RealField override val elementAlgebra: DoubleField get() = DoubleField
public override fun buildMatrix( public override fun buildMatrix(
rows: Int, rows: Int,
columns: Int, columns: Int,
initializer: RealField.(i: Int, j: Int) -> Double, initializer: DoubleField.(i: Int, j: Int) -> Double,
): CMMatrix { ): CMMatrix {
val array = Array(rows) { i -> DoubleArray(columns) { j -> RealField.initializer(i, j) } } val array = Array(rows) { i -> DoubleArray(columns) { j -> DoubleField.initializer(i, j) } }
return CMMatrix(Array2DRowRealMatrix(array)) return CMMatrix(Array2DRowRealMatrix(array))
} }
@ -69,8 +61,8 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this) internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this)
internal fun RealVector.wrap(): CMVector = CMVector(this) internal fun RealVector.wrap(): CMVector = CMVector(this)
override fun buildVector(size: Int, initializer: RealField.(Int) -> Double): Point<Double> = override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): Point<Double> =
ArrayRealVector(DoubleArray(size) { RealField.initializer(it) }).wrap() ArrayRealVector(DoubleArray(size) { DoubleField.initializer(it) }).wrap()
override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix = override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix =
toCM().origin.add(other.toCM().origin).wrap() toCM().origin.add(other.toCM().origin).wrap()
@ -103,7 +95,7 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
v * this v * this
@UnstableKMathAPI @UnstableKMathAPI
override fun <F : Any> getFeature(structure: Matrix<Double>, type: KClass<F>): F? { override fun <F : StructureFeature> getFeature(structure: Matrix<Double>, type: KClass<out F>): F? {
//Return the feature if it is intrinsic to the structure //Return the feature if it is intrinsic to the structure
structure.getFeature(type)?.let { return it } structure.getFeature(type)?.let { return it }
@ -140,7 +132,7 @@ public object CMLinearSpace : LinearSpace<Double, RealField> {
override val u: Matrix<Double> by lazy { CMMatrix(sv.u) } override val u: Matrix<Double> by lazy { CMMatrix(sv.u) }
override val s: Matrix<Double> by lazy { CMMatrix(sv.s) } override val s: Matrix<Double> by lazy { CMMatrix(sv.s) }
override val v: Matrix<Double> by lazy { CMMatrix(sv.v) } override val v: Matrix<Double> by lazy { CMMatrix(sv.v) }
override val singularValues: Point<Double> by lazy { RealBuffer(sv.singularValues) } override val singularValues: Point<Double> by lazy { DoubleBuffer(sv.singularValues) }
} }
else -> null else -> null
}?.let(type::cast) }?.let(type::cast)

View File

@ -19,7 +19,7 @@ public enum class CMDecomposition {
public fun CMLinearSpace.solver( public fun CMLinearSpace.solver(
a: Matrix<Double>, a: Matrix<Double>,
decomposition: CMDecomposition = CMDecomposition.LUP decomposition: CMDecomposition = CMDecomposition.LUP,
): DecompositionSolver = when (decomposition) { ): DecompositionSolver = when (decomposition) {
CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver
CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver
@ -31,16 +31,16 @@ public fun CMLinearSpace.solver(
public fun CMLinearSpace.solve( public fun CMLinearSpace.solve(
a: Matrix<Double>, a: Matrix<Double>,
b: Matrix<Double>, b: Matrix<Double>,
decomposition: CMDecomposition = CMDecomposition.LUP decomposition: CMDecomposition = CMDecomposition.LUP,
): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap() ): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap()
public fun CMLinearSpace.solve( public fun CMLinearSpace.solve(
a: Matrix<Double>, a: Matrix<Double>,
b: Point<Double>, b: Point<Double>,
decomposition: CMDecomposition = CMDecomposition.LUP decomposition: CMDecomposition = CMDecomposition.LUP,
): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint() ): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint()
public fun CMLinearSpace.inverse( public fun CMLinearSpace.inverse(
a: Matrix<Double>, a: Matrix<Double>,
decomposition: CMDecomposition = CMDecomposition.LUP decomposition: CMDecomposition = CMDecomposition.LUP,
): CMMatrix = solver(a, decomposition).inverse.wrap() ): CMMatrix = solver(a, decomposition).inverse.wrap()

View File

@ -14,22 +14,36 @@ import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjuga
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
import space.kscience.kmath.expressions.* import space.kscience.kmath.expressions.DifferentiableExpression
import space.kscience.kmath.stat.OptimizationFeature import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.stat.OptimizationProblem import space.kscience.kmath.expressions.SymbolIndexer
import space.kscience.kmath.stat.OptimizationProblemFactory import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.stat.OptimizationResult import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.optimization.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
public operator fun PointValuePair.component1(): DoubleArray = point public operator fun PointValuePair.component1(): DoubleArray = point
public operator fun PointValuePair.component2(): Double = value public operator fun PointValuePair.component2(): Double = value
public class CMOptimizationProblem(override val symbols: List<Symbol>, ) : @OptIn(UnstableKMathAPI::class)
OptimizationProblem<Double>, SymbolIndexer, OptimizationFeature { public class CMOptimization(
override val symbols: List<Symbol>,
) : FunctionOptimization<Double>, NoDerivFunctionOptimization<Double>, SymbolIndexer, OptimizationFeature {
private val optimizationData: HashMap<KClass<out OptimizationData>, OptimizationData> = HashMap() private val optimizationData: HashMap<KClass<out OptimizationData>, OptimizationData> = HashMap()
private var optimizatorBuilder: (() -> MultivariateOptimizer)? = null private var optimizerBuilder: (() -> MultivariateOptimizer)? = null
public var convergenceChecker: ConvergenceChecker<PointValuePair> = SimpleValueChecker(DEFAULT_RELATIVE_TOLERANCE, public var convergenceChecker: ConvergenceChecker<PointValuePair> = SimpleValueChecker(
DEFAULT_ABSOLUTE_TOLERANCE, DEFAULT_MAX_ITER) DEFAULT_RELATIVE_TOLERANCE,
DEFAULT_ABSOLUTE_TOLERANCE,
DEFAULT_MAX_ITER
)
override var maximize: Boolean
get() = optimizationData[GoalType::class] == GoalType.MAXIMIZE
set(value) {
optimizationData[GoalType::class] = if (value) GoalType.MAXIMIZE else GoalType.MINIMIZE
}
public fun addOptimizationData(data: OptimizationData) { public fun addOptimizationData(data: OptimizationData) {
optimizationData[data::class] = data optimizationData[data::class] = data
@ -45,7 +59,7 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
addOptimizationData(InitialGuess(map.toDoubleArray())) addOptimizationData(InitialGuess(map.toDoubleArray()))
} }
public override fun expression(expression: Expression<Double>): Unit { public override fun function(expression: Expression<Double>): Unit {
val objectiveFunction = ObjectiveFunction { val objectiveFunction = ObjectiveFunction {
val args = it.toMap() val args = it.toMap()
expression(args) expression(args)
@ -53,8 +67,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
addOptimizationData(objectiveFunction) addOptimizationData(objectiveFunction)
} }
public override fun diffExpression(expression: DifferentiableExpression<Double, Expression<Double>>) { public override fun diffFunction(expression: DifferentiableExpression<Double, Expression<Double>>) {
expression(expression) function(expression)
val gradientFunction = ObjectiveFunctionGradient { val gradientFunction = ObjectiveFunctionGradient {
val args = it.toMap() val args = it.toMap()
DoubleArray(symbols.size) { index -> DoubleArray(symbols.size) { index ->
@ -62,8 +76,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
} }
} }
addOptimizationData(gradientFunction) addOptimizationData(gradientFunction)
if (optimizatorBuilder == null) { if (optimizerBuilder == null) {
optimizatorBuilder = { optimizerBuilder = {
NonLinearConjugateGradientOptimizer( NonLinearConjugateGradientOptimizer(
NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES,
convergenceChecker convergenceChecker
@ -75,8 +89,8 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
public fun simplex(simplex: AbstractSimplex) { public fun simplex(simplex: AbstractSimplex) {
addOptimizationData(simplex) addOptimizationData(simplex)
//Set optimization builder to simplex if it is not present //Set optimization builder to simplex if it is not present
if (optimizatorBuilder == null) { if (optimizerBuilder == null) {
optimizatorBuilder = { SimplexOptimizer(convergenceChecker) } optimizerBuilder = { SimplexOptimizer(convergenceChecker) }
} }
} }
@ -89,7 +103,7 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
} }
public fun optimizer(block: () -> MultivariateOptimizer) { public fun optimizer(block: () -> MultivariateOptimizer) {
optimizatorBuilder = block optimizerBuilder = block
} }
override fun update(result: OptimizationResult<Double>) { override fun update(result: OptimizationResult<Double>) {
@ -97,19 +111,19 @@ public class CMOptimizationProblem(override val symbols: List<Symbol>, ) :
} }
override fun optimize(): OptimizationResult<Double> { override fun optimize(): OptimizationResult<Double> {
val optimizer = optimizatorBuilder?.invoke() ?: error("Optimizer not defined") val optimizer = optimizerBuilder?.invoke() ?: error("Optimizer not defined")
val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray()) val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray())
return OptimizationResult(point.toMap(), value, setOf(this)) return OptimizationResult(point.toMap(), value, setOf(this))
} }
public companion object : OptimizationProblemFactory<Double, CMOptimizationProblem> { public companion object : OptimizationProblemFactory<Double, CMOptimization> {
public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4
public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4
public const val DEFAULT_MAX_ITER: Int = 1000 public const val DEFAULT_MAX_ITER: Int = 1000
override fun build(symbols: List<Symbol>): CMOptimizationProblem = CMOptimizationProblem(symbols) override fun build(symbols: List<Symbol>): CMOptimization = CMOptimization(symbols)
} }
} }
public fun CMOptimizationProblem.initialGuess(vararg pairs: Pair<Symbol, Double>): Unit = initialGuess(pairs.toMap()) public fun CMOptimization.initialGuess(vararg pairs: Pair<Symbol, Double>): Unit = initialGuess(pairs.toMap())
public fun CMOptimizationProblem.simplexSteps(vararg pairs: Pair<Symbol, Double>): Unit = simplexSteps(pairs.toMap()) public fun CMOptimization.simplexSteps(vararg pairs: Pair<Symbol, Double>): Unit = simplexSteps(pairs.toMap())

View File

@ -6,21 +6,21 @@
package space.kscience.kmath.commons.optimization package space.kscience.kmath.commons.optimization
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType
import space.kscience.kmath.commons.expressions.DerivativeStructureField import space.kscience.kmath.commons.expressions.DerivativeStructureField
import space.kscience.kmath.expressions.DifferentiableExpression import space.kscience.kmath.expressions.DifferentiableExpression
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.stat.Fitting import space.kscience.kmath.optimization.FunctionOptimization
import space.kscience.kmath.stat.OptimizationResult import space.kscience.kmath.optimization.OptimizationResult
import space.kscience.kmath.stat.optimizeWith import space.kscience.kmath.optimization.noDerivOptimizeWith
import space.kscience.kmath.optimization.optimizeWith
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.asBuffer
/** /**
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
*/ */
public fun Fitting.chiSquared( public fun FunctionOptimization.Companion.chiSquared(
x: Buffer<Double>, x: Buffer<Double>,
y: Buffer<Double>, y: Buffer<Double>,
yErr: Buffer<Double>, yErr: Buffer<Double>,
@ -30,7 +30,7 @@ public fun Fitting.chiSquared(
/** /**
* Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation
*/ */
public fun Fitting.chiSquared( public fun FunctionOptimization.Companion.chiSquared(
x: Iterable<Double>, x: Iterable<Double>,
y: Iterable<Double>, y: Iterable<Double>,
yErr: Iterable<Double>, yErr: Iterable<Double>,
@ -48,25 +48,26 @@ public fun Fitting.chiSquared(
*/ */
public fun Expression<Double>.optimize( public fun Expression<Double>.optimize(
vararg symbols: Symbol, vararg symbols: Symbol,
configuration: CMOptimizationProblem.() -> Unit, configuration: CMOptimization.() -> Unit,
): OptimizationResult<Double> = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration) ): OptimizationResult<Double> = noDerivOptimizeWith(CMOptimization, symbols = symbols, configuration)
/** /**
* Optimize differentiable expression * Optimize differentiable expression
*/ */
public fun DifferentiableExpression<Double, Expression<Double>>.optimize( public fun DifferentiableExpression<Double, Expression<Double>>.optimize(
vararg symbols: Symbol, vararg symbols: Symbol,
configuration: CMOptimizationProblem.() -> Unit, configuration: CMOptimization.() -> Unit,
): OptimizationResult<Double> = optimizeWith(CMOptimizationProblem, symbols = symbols, configuration) ): OptimizationResult<Double> = optimizeWith(CMOptimization, symbols = symbols, configuration)
public fun DifferentiableExpression<Double, Expression<Double>>.minimize( public fun DifferentiableExpression<Double, Expression<Double>>.minimize(
vararg startPoint: Pair<Symbol, Double>, vararg startPoint: Pair<Symbol, Double>,
configuration: CMOptimizationProblem.() -> Unit = {}, configuration: CMOptimization.() -> Unit = {},
): OptimizationResult<Double> { ): OptimizationResult<Double> {
require(startPoint.isNotEmpty()) { "Must provide a list of symbols for optimization" } val symbols = startPoint.map { it.first }.toTypedArray()
val problem = CMOptimizationProblem(startPoint.map { it.first }).apply(configuration) return optimize(*symbols){
problem.diffExpression(this) maximize = false
problem.initialGuess(startPoint.toMap()) initialGuess(startPoint.toMap())
problem.goal(GoalType.MINIMIZE) diffFunction(this@minimize)
return problem.optimize() configuration()
}
} }

View File

@ -15,6 +15,7 @@ import space.kscience.kmath.streaming.spread
import space.kscience.kmath.structures.* import space.kscience.kmath.structures.*
/** /**
* Streaming and buffer transformations * Streaming and buffer transformations
*/ */
@ -22,7 +23,7 @@ public object Transformations {
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> = private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) } Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
private fun Buffer<Double>.asArray() = if (this is RealBuffer) { private fun Buffer<Double>.asArray() = if (this is DoubleBuffer) {
array array
} else { } else {
DoubleArray(size) { i -> get(i) } DoubleArray(size) { i -> get(i) }
@ -38,34 +39,34 @@ public object Transformations {
public fun fourier( public fun fourier(
normalization: DftNormalization = DftNormalization.STANDARD, normalization: DftNormalization = DftNormalization.STANDARD,
direction: TransformType = TransformType.FORWARD direction: TransformType = TransformType.FORWARD,
): SuspendBufferTransform<Complex, Complex> = { ): SuspendBufferTransform<Complex, Complex> = {
FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer() FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer()
} }
public fun realFourier( public fun realFourier(
normalization: DftNormalization = DftNormalization.STANDARD, normalization: DftNormalization = DftNormalization.STANDARD,
direction: TransformType = TransformType.FORWARD direction: TransformType = TransformType.FORWARD,
): SuspendBufferTransform<Double, Complex> = { ): SuspendBufferTransform<Double, Complex> = {
FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer() FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer()
} }
public fun sine( public fun sine(
normalization: DstNormalization = DstNormalization.STANDARD_DST_I, normalization: DstNormalization = DstNormalization.STANDARD_DST_I,
direction: TransformType = TransformType.FORWARD direction: TransformType = TransformType.FORWARD,
): SuspendBufferTransform<Double, Double> = { ): SuspendBufferTransform<Double, Double> = {
FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer() FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
} }
public fun cosine( public fun cosine(
normalization: DctNormalization = DctNormalization.STANDARD_DCT_I, normalization: DctNormalization = DctNormalization.STANDARD_DCT_I,
direction: TransformType = TransformType.FORWARD direction: TransformType = TransformType.FORWARD,
): SuspendBufferTransform<Double, Double> = { ): SuspendBufferTransform<Double, Double> = {
FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer() FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer()
} }
public fun hadamard( public fun hadamard(
direction: TransformType = TransformType.FORWARD direction: TransformType = TransformType.FORWARD,
): SuspendBufferTransform<Double, Double> = { ): SuspendBufferTransform<Double, Double> = {
FastHadamardTransformer().transform(it.asArray(), direction).asBuffer() FastHadamardTransformer().transform(it.asArray(), direction).asBuffer()
} }
@ -77,7 +78,7 @@ public object Transformations {
@FlowPreview @FlowPreview
public fun Flow<Buffer<Complex>>.FFT( public fun Flow<Buffer<Complex>>.FFT(
normalization: DftNormalization = DftNormalization.STANDARD, normalization: DftNormalization = DftNormalization.STANDARD,
direction: TransformType = TransformType.FORWARD direction: TransformType = TransformType.FORWARD,
): Flow<Buffer<Complex>> { ): Flow<Buffer<Complex>> {
val transform = Transformations.fourier(normalization, direction) val transform = Transformations.fourier(normalization, direction)
return map { transform(it) } return map { transform(it) }
@ -87,7 +88,7 @@ public fun Flow<Buffer<Complex>>.FFT(
@JvmName("realFFT") @JvmName("realFFT")
public fun Flow<Buffer<Double>>.FFT( public fun Flow<Buffer<Double>>.FFT(
normalization: DftNormalization = DftNormalization.STANDARD, normalization: DftNormalization = DftNormalization.STANDARD,
direction: TransformType = TransformType.FORWARD direction: TransformType = TransformType.FORWARD,
): Flow<Buffer<Complex>> { ): Flow<Buffer<Complex>> {
val transform = Transformations.realFourier(normalization, direction) val transform = Transformations.realFourier(normalization, direction)
return map(transform) return map(transform)
@ -101,7 +102,7 @@ public fun Flow<Buffer<Double>>.FFT(
public fun Flow<Double>.FFT( public fun Flow<Double>.FFT(
bufferSize: Int = Int.MAX_VALUE, bufferSize: Int = Int.MAX_VALUE,
normalization: DftNormalization = DftNormalization.STANDARD, normalization: DftNormalization = DftNormalization.STANDARD,
direction: TransformType = TransformType.FORWARD direction: TransformType = TransformType.FORWARD,
): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread() ): Flow<Complex> = chunked(bufferSize).FFT(normalization, direction).spread()
/** /**

View File

@ -5,7 +5,11 @@
package space.kscience.kmath.commons.expressions package space.kscience.kmath.commons.expressions
import space.kscience.kmath.expressions.* import space.kscience.kmath.expressions.binding
import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.misc.symbol
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.test.Test import kotlin.test.Test
@ -28,14 +32,14 @@ internal class AutoDiffTest {
@Test @Test
fun derivativeStructureFieldTest() { fun derivativeStructureFieldTest() {
diff(2, x to 1.0, y to 1.0) { diff(2, x to 1.0, y to 1.0) {
val x = bind(x)//by binding() val x = bindSymbol(x)//by binding()
val y = bindSymbol("y") val y = bindSymbol("y")
val z = x * (-sin(x * y) + y) + 2.0 val z = x * (-sin(x * y) + y) + 2.0
println(z.derivative(x)) println(z.derivative(x))
println(z.derivative(y,x)) println(z.derivative(y, x))
assertEquals(z.derivative(x, y), z.derivative(y, x)) assertEquals(z.derivative(x, y), z.derivative(y, x))
//check that improper order cause failure //check that improper order cause failure
assertFails { z.derivative(x,x,y) } assertFails { z.derivative(x, x, y) }
} }
} }

View File

@ -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 }
}
}

View File

@ -5,21 +5,22 @@
package space.kscience.kmath.commons.optimization package space.kscience.kmath.commons.optimization
import org.junit.jupiter.api.Test import kotlinx.coroutines.runBlocking
import space.kscience.kmath.commons.expressions.DerivativeStructureExpression import space.kscience.kmath.commons.expressions.DerivativeStructureExpression
import space.kscience.kmath.expressions.symbol import space.kscience.kmath.distributions.NormalDistribution
import space.kscience.kmath.stat.Distribution import space.kscience.kmath.misc.symbol
import space.kscience.kmath.stat.Fitting import space.kscience.kmath.optimization.FunctionOptimization
import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import space.kscience.kmath.stat.normal
import kotlin.math.pow import kotlin.math.pow
import kotlin.test.Test
internal class OptimizeTest { internal class OptimizeTest {
val x by symbol val x by symbol
val y by symbol val y by symbol
val normal = DerivativeStructureExpression { val normal = DerivativeStructureExpression {
exp(-bind(x).pow(2) / 2) + exp(-bind(y).pow(2) / 2) exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y)
.pow(2) / 2)
} }
@Test @Test
@ -39,35 +40,35 @@ internal class OptimizeTest {
simplexSteps(x to 2.0, y to 0.5) simplexSteps(x to 2.0, y to 0.5)
//this sets simplex optimizer //this sets simplex optimizer
} }
println(result.point) println(result.point)
println(result.value) println(result.value)
} }
@Test @Test
fun testCmFit() { fun testCmFit() = runBlocking {
val a by symbol val a by symbol
val b by symbol val b by symbol
val c by symbol val c by symbol
val sigma = 1.0 val sigma = 1.0
val generator = Distribution.normal(0.0, sigma) val generator = NormalDistribution(0.0, sigma)
val chain = generator.sample(RandomGenerator.default(112667)) val chain = generator.sample(RandomGenerator.default(112667))
val x = (1..100).map(Int::toDouble) val x = (1..100).map(Int::toDouble)
val y = x.map { val y = x.map {
it.pow(2) + it + 1 + chain.nextDouble() it.pow(2) + it + 1 + chain.next()
} }
val yErr = List(x.size) { sigma } val yErr = List(x.size) { sigma }
val chi2 = Fitting.chiSquared(x, y, yErr) { x1 -> val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 ->
val cWithDefault = bindSymbolOrNull(c) ?: one val cWithDefault = bindSymbolOrNull(c) ?: one
bind(a) * x1.pow(2) + bind(b) * x1 + cWithDefault bindSymbol(a) * x1.pow(2) + bindSymbol(b) * x1 + cWithDefault
} }
val result = chi2.minimize(a to 1.5, b to 0.9, c to 1.0) val result = chi2.minimize(a to 1.5, b to 0.9, c to 1.0)
println(result) println(result)
println("Chi2/dof = ${result.value / (x.size - 3)}") println("Chi2/dof = ${result.value / (x.size - 3)}")
} }
} }

View File

@ -1,42 +1,36 @@
# The Core Module (`kmath-core`) # Module kmath-complex
Complex and hypercomplex number systems in KMath: Complex and hypercomplex number systems in KMath.
- [complex](src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
- [quaternion](src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
> #### Artifact: ## Artifact:
>
> This module artifact: `space.kscience:kmath-complex:0.3.0-dev-2`. The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-6`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-complex/_latestVersion) **Gradle:**
> ```gradle
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-complex/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-complex/_latestVersion) repositories {
> maven { url 'https://repo.kotlin.link' }
> **Gradle:** maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
> ```gradle }
> repositories {
> maven { url 'https://repo.kotlin.link' } dependencies {
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' } implementation 'space.kscience:kmath-complex:0.3.0-dev-6'
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap }
> } ```
> **Gradle Kotlin DSL:**
> dependencies { ```kotlin
> implementation 'space.kscience:kmath-complex:0.3.0-dev-2' repositories {
> } maven("https://repo.kotlin.link")
> ``` maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
> **Gradle Kotlin DSL:** maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
> }
> ```kotlin
> repositories { dependencies {
> maven("https://repo.kotlin.link") implementation("space.kscience:kmath-complex:0.3.0-dev-6")
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap }
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a ```
> }
>
> dependencies {
> implementation("space.kscience:kmath-complex:0.3.0-dev-2")
> }
> ```

View File

@ -1,12 +1,13 @@
import ru.mipt.npm.gradle.Maturity
/* /*
* Copyright 2018-2021 KMath contributors. * Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
import ru.mipt.npm.gradle.Maturity
plugins { plugins {
id("ru.mipt.npm.gradle.mpp") kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
id("ru.mipt.npm.gradle.native") id("ru.mipt.npm.gradle.native")
} }
@ -30,12 +31,12 @@ readme {
feature( feature(
id = "complex", id = "complex",
description = "Complex Numbers", description = "Complex Numbers",
ref = "src/commonMain/kotlin/kscience/kmath/complex/Complex.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt"
) )
feature( feature(
id = "quaternion", id = "quaternion",
description = "Quaternions", description = "Quaternions",
ref = "src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt"
) )
} }

View File

@ -1,6 +1,6 @@
# The Core Module (`kmath-core`) # Module kmath-complex
Complex and hypercomplex number systems in KMath: Complex and hypercomplex number systems in KMath.
${features} ${features}

View File

@ -126,8 +126,8 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Num
/** /**
* Adds complex number to real one. * Adds complex number to real one.
* *
* @receiver the addend. * @receiver the augend.
* @param c the augend. * @param c the addend.
* @return the sum. * @return the sum.
*/ */
public operator fun Double.plus(c: Complex): Complex = add(this.toComplex(), c) public operator fun Double.plus(c: Complex): Complex = add(this.toComplex(), c)
@ -144,8 +144,8 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Num
/** /**
* Adds real number to complex one. * Adds real number to complex one.
* *
* @receiver the addend. * @receiver the augend.
* @param d the augend. * @param d the addend.
* @return the sum. * @return the sum.
*/ */
public operator fun Complex.plus(d: Double): Complex = d + this public operator fun Complex.plus(d: Double): Complex = d + this
@ -170,8 +170,7 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Num
public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
public override fun bindSymbol(value: String): Complex = public override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null
if (value == "i") i else super<ExtendedField>.bindSymbol(value)
} }
/** /**

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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 Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z)
public override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) public override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg)
public override fun bindSymbol(value: String): Quaternion = when (value) { public override fun bindSymbolOrNull(value: String): Quaternion? = when (value) {
"i" -> i "i" -> i
"j" -> j "j" -> j
"k" -> k "k" -> k
else -> super<Field>.bindSymbol(value) else -> null
} }
override fun number(value: Number): Quaternion =value.toQuaternion() override fun number(value: Number): Quaternion = value.toQuaternion()
public override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 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 public override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0

View File

@ -6,9 +6,9 @@
package space.kscience.kmath.complex package space.kscience.kmath.complex
import space.kscience.kmath.expressions.FunctionalExpressionField import space.kscience.kmath.expressions.FunctionalExpressionField
import space.kscience.kmath.expressions.bindSymbol
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.symbol import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.bindSymbol
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals

View File

@ -1,49 +1,43 @@
# The Core Module (`kmath-core`) # Module kmath-core
The core features of KMath: The core interfaces of KMath.
- [algebras](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields. - [algebras](src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
- [nd](src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them. - [nd](src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
- [linear](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition. - [linear](src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
- [buffers](src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure - [buffers](src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
- [expressions](src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of - [expressions](src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation. performance calculations to code generation.
- [domains](src/commonMain/kotlin/kscience/kmath/domains) : Domains - [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
- [autodif](src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation - [autodif](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
> #### Artifact: ## Artifact:
>
> This module artifact: `space.kscience:kmath-core:0.3.0-dev-2`. The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-6`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion) **Gradle:**
> ```gradle
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion) repositories {
> maven { url 'https://repo.kotlin.link' }
> **Gradle:** maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
> ```gradle }
> repositories {
> maven { url 'https://repo.kotlin.link' } dependencies {
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' } implementation 'space.kscience:kmath-core:0.3.0-dev-6'
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap }
> } ```
> **Gradle Kotlin DSL:**
> dependencies { ```kotlin
> implementation 'space.kscience:kmath-core:0.3.0-dev-2' repositories {
> } maven("https://repo.kotlin.link")
> ``` maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
> **Gradle Kotlin DSL:** maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
> }
> ```kotlin
> repositories { dependencies {
> maven("https://repo.kotlin.link") implementation("space.kscience:kmath-core:0.3.0-dev-6")
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap }
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a ```
> }
>
> dependencies {
> implementation("space.kscience:kmath-core:0.3.0-dev-2")
> }
> ```

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,8 @@
import ru.mipt.npm.gradle.Maturity import ru.mipt.npm.gradle.Maturity
plugins { plugins {
id("ru.mipt.npm.gradle.mpp") kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
id("ru.mipt.npm.gradle.native") id("ru.mipt.npm.gradle.native")
} }
@ -28,13 +29,13 @@ readme {
description = """ description = """
Algebraic structures like rings, spaces and fields. Algebraic structures like rings, spaces and fields.
""".trimIndent(), """.trimIndent(),
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt"
) )
feature( feature(
id = "nd", id = "nd",
description = "Many-dimensional structures and operations on them.", description = "Many-dimensional structures and operations on them.",
ref = "src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt"
) )
feature( feature(
@ -42,13 +43,13 @@ readme {
description = """ description = """
Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition. Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
""".trimIndent(), """.trimIndent(),
ref = "src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt"
) )
feature( feature(
id = "buffers", id = "buffers",
description = "One-dimensional structure", description = "One-dimensional structure",
ref = "src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt"
) )
feature( feature(
@ -58,18 +59,18 @@ readme {
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation. performance calculations to code generation.
""".trimIndent(), """.trimIndent(),
ref = "src/commonMain/kotlin/kscience/kmath/expressions" ref = "src/commonMain/kotlin/space/kscience/kmath/expressions"
) )
feature( feature(
id = "domains", id = "domains",
description = "Domains", description = "Domains",
ref = "src/commonMain/kotlin/kscience/kmath/domains" ref = "src/commonMain/kotlin/space/kscience/kmath/domains"
) )
feature( feature(
id = "autodif", id = "autodif",
description = "Automatic differentiation", description = "Automatic differentiation",
ref = "src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt" ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt"
) )
} }

View File

@ -1,6 +1,6 @@
# The Core Module (`kmath-core`) # Module kmath-core
The core features of KMath: The core interfaces of KMath.
${features} ${features}

Some files were not shown because too many files have changed in this diff Show More