diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 25f2cfd0d..f39e12a12 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,6 +8,7 @@ jobs:
matrix:
os: [ macOS-latest, windows-latest ]
runs-on: ${{matrix.os}}
+ timeout-minutes: 30
steps:
- name: Checkout the repo
uses: actions/checkout@v2
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 42fa6d3b6..ca374574e 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -12,7 +12,7 @@ jobs:
name: publish
strategy:
matrix:
- os: [macOS-latest, windows-latest]
+ os: [ macOS-latest, windows-latest ]
runs-on: ${{matrix.os}}
steps:
- name: Checkout the repo
diff --git a/.gitignore b/.gitignore
index 07589aa00..2a13b9e3c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,11 @@
.gradle
build/
out/
+
.idea/
+
+!.idea/copyright/
+
.vscode/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
diff --git a/.idea/copyright/kmath.xml b/.idea/copyright/kmath.xml
new file mode 100644
index 000000000..6fe438777
--- /dev/null
+++ b/.idea/copyright/kmath.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 000000000..6cc25cb4a
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index eb97698c6..c3bd2641a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,20 +4,35 @@
### Added
- ScaleOperations interface
- Field extends ScaleOperations
+- Basic integration API
+- Basic MPP distributions and samplers
+- bindSymbolOrNull
+- Blocking chains and Statistics
+- Multiplatform integration
+- Integration for any Field element
### Changed
- Exponential operations merged with hyperbolic functions
- Space is replaced by Group. Space is reserved for vector spaces.
- VectorSpace is now a vector space
- Buffer factories for primitives moved to MutableBuffer.Companion
+- NDStructure and NDAlgebra to StructureND and AlgebraND respectively
+- Real -> Double
+- DataSets are moved from functions to core
+- Redesign advanced Chain API
+- Redesign MST. Remove MSTExpression.
+- Move MST to core
### Deprecated
### Removed
- Nearest in Domain. To be implemented in geometry package.
- Number multiplication and division in main Algebra chain
+- `contentEquals` from Buffer. It moved to the companion.
+- MSTExpression
### Fixed
+- Ring inherits RingOperations, not GroupOperations
### Security
@@ -73,6 +88,7 @@
- `toGrid` method.
- Public visibility of `BufferAccessor2D`
- `Real` class
+- StructureND identity and equals
### Fixed
- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
diff --git a/README.md b/README.md
index bfa5c7fb0..0210b4caf 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,8 @@
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
-
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
-
-[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22kmath-core%22)
+[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22)
+[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
# KMath
@@ -89,12 +88,12 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: PROTOTYPE
>
> **Features:**
-> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
-> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
-> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
-> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
-> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
-> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
+> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
+> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
+> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
+> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
+> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
+> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
@@ -110,8 +109,8 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: PROTOTYPE
>
> **Features:**
-> - [complex](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
-> - [quaternion](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
+> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers
+> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions
@@ -121,15 +120,15 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: DEVELOPMENT
>
> **Features:**
-> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
-> - [nd](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
-> - [linear](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
-> - [buffers](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
-> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
+> - [algebras](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
+> - [nd](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them.
+> - [linear](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
+> - [buffers](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
+> - [expressions](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation.
-> - [domains](kmath-core/src/commonMain/kotlin/kscience/kmath/domains) : Domains
-> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
+> - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
+> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
@@ -149,6 +148,12 @@ performance calculations to code generation.
>
>
> **Maturity**: PROTOTYPE
+>
+> **Features:**
+> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : The Point implementation using SimpleMatrix.
+> - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : The Matrix implementation using SimpleMatrix.
+> - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : The LinearSpace implementation using SimpleMatrix.
+
* ### [kmath-for-real](kmath-for-real)
@@ -159,22 +164,23 @@ One can still use generic algebras though.
> **Maturity**: EXPERIMENTAL
>
> **Features:**
-> - [RealVector](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealVector.kt) : Numpy-like operations for Buffers/Points
-> - [RealMatrix](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt) : Numpy-like operations for 2d real structures
-> - [grids](kmath-for-real/src/commonMain/kotlin/kscience/kmath/structures/grids.kt) : Uniform grid generators
+> - [DoubleVector](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points
+> - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures
+> - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators
* ### [kmath-functions](kmath-functions)
-> Functions and interpolation
+> Functions, integration and interpolation
>
-> **Maturity**: PROTOTYPE
+> **Maturity**: EXPERIMENTAL
>
> **Features:**
-> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt
-> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt
-> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt
-> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt
+> - [piecewise](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt) : Piecewise functions.
+> - [polynomials](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Polynomial functions.
+> - [linear interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt) : Linear XY interpolator.
+> - [spline interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator.
+> - [integration](kmath-functions/#) : Univariate and multivariate quadratures
@@ -208,9 +214,9 @@ One can still use generic algebras though.
> **Maturity**: EXPERIMENTAL
>
> **Features:**
-> - [nd4jarraystructure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray
-> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long
-> - [nd4jarrayfields](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : Fields over Nd4jArrayStructure of Float and Double
+> - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
+> - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long
+> - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double
@@ -245,6 +251,10 @@ cases. We expect the worst KMath benchmarks will perform better than native Pyth
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy.
+## Requirements
+
+KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
+
### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
@@ -256,8 +266,8 @@ repositories {
}
dependencies {
- api("space.kscience:kmath-core:0.3.0-dev-2")
- // api("space.kscience:kmath-core-jvm:0.3.0-dev-2") for jvm-specific version
+ api("space.kscience:kmath-core:0.3.0-dev-6")
+ // api("space.kscience:kmath-core-jvm:0.3.0-dev-6") for jvm-specific version
}
```
diff --git a/build.gradle.kts b/build.gradle.kts
index ce9cb1528..9b2200cb4 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -3,7 +3,8 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
-import ru.mipt.npm.gradle.KSciencePublishingPlugin
+import org.jetbrains.dokka.gradle.DokkaTask
+import java.net.URL
plugins {
id("ru.mipt.npm.gradle.project")
@@ -15,21 +16,41 @@ allprojects {
maven("https://clojars.org/repo")
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
maven("https://dl.bintray.com/hotkeytlt/maven")
- maven("https://dl.bintray.com/kotlin/kotlin-eap")
- maven("https://dl.bintray.com/kotlin/kotlinx")
- maven("https://dl.bintray.com/mipt-npm/dev")
- maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://jitpack.io")
- maven("http://logicrunch.research.it.uu.se/maven/")
+ maven{
+ setUrl("http://logicrunch.research.it.uu.se/maven/")
+ isAllowInsecureProtocol = true
+ }
mavenCentral()
}
group = "space.kscience"
- version = "0.3.0-dev-2"
+ version = "0.3.0-dev-6"
}
subprojects {
- if (name.startsWith("kmath")) apply()
+ if (name.startsWith("kmath")) apply()
+
+ afterEvaluate {
+ tasks.withType {
+ 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 {
diff --git a/docs/algebra.md b/docs/algebra.md
index 6bfcde043..84693bb81 100644
--- a/docs/algebra.md
+++ b/docs/algebra.md
@@ -31,7 +31,7 @@ multiplication;
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
-A typical implementation of `Field` is the `RealField` which works on doubles, and `VectorSpace` for `Space`.
+A typical implementation of `Field` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space`.
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`
diff --git a/docs/images/KM.svg b/docs/images/KM.svg
index 50126cbc5..83af21f35 100644
--- a/docs/images/KM.svg
+++ b/docs/images/KM.svg
@@ -13,27 +13,30 @@
version="1.1">image/svg+xml
+
+
+ image/svg+xml
+
+ image/svg+xml
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #### Artifact:
->
-> This module artifact: `${group}:${name}:${version}`.
->
-> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/${name}/images/download.svg) ](https://bintray.com/mipt-npm/kscience/${name}/_latestVersion)
->
-> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/${name}/images/download.svg) ](https://bintray.com/mipt-npm/dev/${name}/_latestVersion)
->
-> **Gradle:**
->
-> ```gradle
-> repositories {
-> maven { url 'https://repo.kotlin.link' }
-> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
-> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
-> }
->
-> dependencies {
-> implementation '${group}:${name}:${version}'
-> }
-> ```
-> **Gradle Kotlin DSL:**
->
-> ```kotlin
-> repositories {
-> maven("https://repo.kotlin.link")
-> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
-> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
-> }
->
-> dependencies {
-> implementation("${group}:${name}:${version}")
-> }
-> ```
\ No newline at end of file
+## Artifact:
+
+The Maven coordinates of this project are `${group}:${name}:${version}`.
+
+**Gradle:**
+```gradle
+repositories {
+ maven { url 'https://repo.kotlin.link' }
+ maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
+ maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
+}
+
+dependencies {
+ implementation '${group}:${name}:${version}'
+}
+```
+**Gradle Kotlin DSL:**
+```kotlin
+repositories {
+ maven("https://repo.kotlin.link")
+ maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
+ maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
+}
+
+dependencies {
+ implementation("${group}:${name}:${version}")
+}
+```
\ No newline at end of file
diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md
index f0e68f575..99951b4d6 100644
--- a/docs/templates/README-TEMPLATE.md
+++ b/docs/templates/README-TEMPLATE.md
@@ -1,9 +1,8 @@
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
-
![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg)
-
-[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22kmath-core%22)
+[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22)
+[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
# KMath
@@ -95,6 +94,10 @@ cases. We expect the worst KMath benchmarks will perform better than native Pyth
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy.
+## Requirements
+
+KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
+
### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts
index 86ffa94a3..98d7b7073 100644
--- a/examples/build.gradle.kts
+++ b/examples/build.gradle.kts
@@ -4,11 +4,12 @@
*/
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("jvm")
kotlin("plugin.allopen")
- id("kotlinx.benchmark")
+ id("org.jetbrains.kotlinx.benchmark")
}
allOpen.annotation("org.openjdk.jmh.annotations.State")
@@ -25,7 +26,10 @@ repositories {
maven("https://dl.bintray.com/mipt-npm/dev")
maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://jitpack.io")
- maven("http://logicrunch.research.it.uu.se/maven/")
+ maven{
+ setUrl("http://logicrunch.research.it.uu.se/maven/")
+ isAllowInsecureProtocol = true
+ }
mavenCentral()
}
@@ -58,7 +62,7 @@ dependencies {
implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
implementation("org.jetbrains.kotlinx:kotlinx-io:0.2.0-npm-dev-11")
- implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20")
+ implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.0")
implementation("org.slf4j:slf4j-simple:1.7.30")
// plotting
@@ -105,19 +109,31 @@ benchmark {
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
include("MatrixInverseBenchmark")
}
+
+ configurations.register("bigInt") {
+ warmups = 1 // number of warmup iterations
+ iterations = 3 // number of iterations
+ iterationTime = 500 // time in seconds per iteration
+ iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
+ include("BigIntBenchmark")
+ }
}
kotlin.sourceSets.all {
with(languageSettings) {
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
+ useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
}
}
tasks.withType {
- kotlinOptions.jvmTarget = "11"
+ kotlinOptions{
+ jvmTarget = "11"
+ freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
+ }
}
-readme{
- maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
+readme {
+ maturity = Maturity.EXPERIMENTAL
}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
new file mode 100644
index 000000000..672efd5c2
--- /dev/null
+++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
index 8df4ce4da..39819d407 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
+++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
@@ -10,14 +10,14 @@ import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.complex
+import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.MutableBuffer
-import space.kscience.kmath.structures.RealBuffer
@State(Scope.Benchmark)
internal class BufferBenchmark {
@Benchmark
- fun genericRealBufferReadWrite() {
- val buffer = RealBuffer(size) { it.toDouble() }
+ fun genericDoubleBufferReadWrite() {
+ val buffer = DoubleBuffer(size) { it.toDouble() }
(0 until size).forEach {
buffer[it]
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
index ad6b8cbd3..23e73cb5f 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
+++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
@@ -13,7 +13,7 @@ import space.kscience.kmath.commons.linear.CMLinearSpace
import space.kscience.kmath.ejml.EjmlLinearSpace
import space.kscience.kmath.linear.LinearSpace
import space.kscience.kmath.linear.invoke
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.operations.DoubleField
import kotlin.random.Random
@State(Scope.Benchmark)
@@ -56,7 +56,7 @@ internal class DotBenchmark {
@Benchmark
fun bufferedDot(blackhole: Blackhole) {
- LinearSpace.auto(RealField).invoke {
+ LinearSpace.auto(DoubleField).invoke {
blackhole.consume(matrix1 dot matrix2)
}
}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
index c8e4a5a6f..d6fde8398 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
+++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
@@ -9,14 +9,12 @@ import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
-import space.kscience.kmath.asm.compile
-import space.kscience.kmath.ast.mstInField
-import space.kscience.kmath.expressions.Expression
-import space.kscience.kmath.expressions.expressionInField
-import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.expressions.symbol
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.asm.compileToExpression
+import space.kscience.kmath.expressions.*
+import space.kscience.kmath.misc.symbol
+import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
+import space.kscience.kmath.operations.invoke
import kotlin.random.Random
@State(Scope.Benchmark)
@@ -33,20 +31,20 @@ internal class ExpressionsInterpretersBenchmark {
@Benchmark
fun mstExpression(blackhole: Blackhole) {
- val expr = algebra.mstInField {
+ val expr = MstField {
val x = bindSymbol(x)
x * 2.0 + number(2.0) / x - 16.0
- }
+ }.toExpression(algebra)
invokeAndSum(expr, blackhole)
}
@Benchmark
fun asmExpression(blackhole: Blackhole) {
- val expr = algebra.mstInField {
+ val expr = MstField {
val x = bindSymbol(x)
x * 2.0 + number(2.0) / x - 16.0
- }.compile()
+ }.compileToExpression(algebra)
invokeAndSum(expr, blackhole)
}
@@ -73,7 +71,7 @@ internal class ExpressionsInterpretersBenchmark {
}
private companion object {
- private val algebra = RealField
+ private val algebra = DoubleField
private val x by symbol
}
}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
index 9a67d2afa..5e0c6735f 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
+++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
@@ -10,7 +10,7 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.structures.Buffer
@State(Scope.Benchmark)
@@ -18,7 +18,7 @@ internal class NDFieldBenchmark {
@Benchmark
fun autoFieldAdd(blackhole: Blackhole) {
with(autoField) {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += one }
blackhole.consume(res)
}
@@ -27,7 +27,7 @@ internal class NDFieldBenchmark {
@Benchmark
fun specializedFieldAdd(blackhole: Blackhole) {
with(specializedField) {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@@ -37,7 +37,7 @@ internal class NDFieldBenchmark {
@Benchmark
fun boxingFieldAdd(blackhole: Blackhole) {
with(genericField) {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@@ -46,8 +46,8 @@ internal class NDFieldBenchmark {
private companion object {
private const val dim = 1000
private const val n = 100
- private val autoField = NDAlgebra.auto(RealField, dim, dim)
- private val specializedField = NDAlgebra.real(dim, dim)
- private val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
+ private val autoField = AlgebraND.auto(DoubleField, dim, dim)
+ private val specializedField = AlgebraND.real(dim, dim)
+ private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
}
}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
index 4aac2568e..d2359a791 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
+++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
@@ -10,11 +10,11 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array
-import space.kscience.kmath.nd.NDAlgebra
-import space.kscience.kmath.nd.NDStructure
+import space.kscience.kmath.nd.AlgebraND
+import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.auto
import space.kscience.kmath.nd.real
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.viktor.ViktorNDField
@State(Scope.Benchmark)
@@ -22,7 +22,7 @@ internal class ViktorBenchmark {
@Benchmark
fun automaticFieldAddition(blackhole: Blackhole) {
with(autoField) {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@@ -31,7 +31,7 @@ internal class ViktorBenchmark {
@Benchmark
fun realFieldAddition(blackhole: Blackhole) {
with(realField) {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
blackhole.consume(res)
}
@@ -59,8 +59,8 @@ internal class ViktorBenchmark {
private const val n = 100
// automatically build context most suited for given type.
- private val autoField = NDAlgebra.auto(RealField, dim, dim)
- private val realField = NDAlgebra.real(dim, dim)
+ private val autoField = AlgebraND.auto(DoubleField, dim, dim)
+ private val realField = AlgebraND.real(dim, dim)
private val viktorField = ViktorNDField(dim, dim)
}
}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
index cd4b18f7b..eac8634f5 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
+++ b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
@@ -10,11 +10,11 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array
-import space.kscience.kmath.nd.NDAlgebra
+import space.kscience.kmath.nd.AlgebraND
import space.kscience.kmath.nd.auto
import space.kscience.kmath.nd.real
-import space.kscience.kmath.operations.RealField
-import space.kscience.kmath.viktor.ViktorNDField
+import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.viktor.ViktorFieldND
@State(Scope.Benchmark)
internal class ViktorLogBenchmark {
@@ -51,8 +51,8 @@ internal class ViktorLogBenchmark {
private const val n = 100
// automatically build context most suited for given type.
- private val autoField = NDAlgebra.auto(RealField, dim, dim)
- private val realNdField = NDAlgebra.real(dim, dim)
- private val viktorField = ViktorNDField(intArrayOf(dim, dim))
+ private val autoField = AlgebraND.auto(DoubleField, dim, dim)
+ private val realNdField = AlgebraND.real(dim, dim)
+ private val viktorField = ViktorFieldND(intArrayOf(dim, dim))
}
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt
new file mode 100644
index 000000000..e16769464
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt
@@ -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)
+}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt
index c4531df51..918134e04 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt
@@ -5,16 +5,20 @@
package space.kscience.kmath.ast
-import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.expressions.MstField
+import space.kscience.kmath.expressions.interpret
+import space.kscience.kmath.misc.Symbol.Companion.x
+import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.bindSymbol
+import space.kscience.kmath.operations.invoke
fun main() {
- val expr = RealField.mstInField {
- val x = bindSymbol("x")
+ val expr = MstField {
+ val x = bindSymbol(x)
x * 2.0 + number(2.0) / x - 16.0
}
repeat(10000000) {
- expr.invoke("x" to 1.0)
+ expr.interpret(DoubleField, x to 1.0)
}
}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
index de784fbef..4a31f33a3 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
@@ -5,12 +5,12 @@
package space.kscience.kmath.ast
-import space.kscience.kmath.asm.compile
+import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.expressions.symbol
-import space.kscience.kmath.kotlingrad.differentiable
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.kotlingrad.toDiffExpression
+import space.kscience.kmath.misc.symbol
+import space.kscience.kmath.operations.DoubleField
/**
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
@@ -19,11 +19,11 @@ import space.kscience.kmath.operations.RealField
fun main() {
val x by symbol
- val actualDerivative = MstExpression(RealField, "x^2-4*x-44".parseMath())
- .differentiable()
+ val actualDerivative = "x^2-4*x-44".parseMath()
+ .toDiffExpression(DoubleField)
.derivative(x)
- .compile()
- val expectedDerivative = MstExpression(RealField, "2*x-4".parseMath()).compile()
+
+ val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField)
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt
index a569e7bb0..be4dc461b 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt
@@ -12,11 +12,14 @@ import kscience.plotly.models.ScatterMode
import kscience.plotly.models.TraceValues
import space.kscience.kmath.commons.optimization.chiSquared
import space.kscience.kmath.commons.optimization.minimize
-import space.kscience.kmath.expressions.symbol
-import space.kscience.kmath.real.RealVector
+import space.kscience.kmath.distributions.NormalDistribution
+import space.kscience.kmath.misc.symbol
+import space.kscience.kmath.optimization.FunctionOptimization
+import space.kscience.kmath.optimization.OptimizationResult
+import space.kscience.kmath.real.DoubleVector
import space.kscience.kmath.real.map
import space.kscience.kmath.real.step
-import space.kscience.kmath.stat.*
+import space.kscience.kmath.stat.RandomGenerator
import space.kscience.kmath.structures.asIterable
import space.kscience.kmath.structures.toList
import kotlin.math.pow
@@ -31,17 +34,16 @@ private val c by symbol
/**
* Shortcut to use buffers in plotly
*/
-operator fun TraceValues.invoke(vector: RealVector) {
+operator fun TraceValues.invoke(vector: DoubleVector) {
numbers = vector.asIterable()
}
/**
* Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules.
*/
-fun main() {
-
+suspend fun main() {
//A generator for a normally distributed values
- val generator = Distribution.normal()
+ val generator = NormalDistribution(2.0, 7.0)
//A chain/flow of random values with the given seed
val chain = generator.sample(RandomGenerator.default(112667))
@@ -54,7 +56,7 @@ fun main() {
//Perform an operation on each x value (much more effective, than numpy)
val y = x.map {
val value = it.pow(2) + it + 1
- value + chain.nextDouble() * sqrt(value)
+ value + chain.next() * sqrt(value)
}
// this will also work, but less effective:
// val y = x.pow(2)+ x + 1 + chain.nextDouble()
@@ -63,10 +65,10 @@ fun main() {
val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma)
// compute differentiable chi^2 sum for given model ax^2 + bx + c
- val chi2 = Fitting.chiSquared(x, y, yErr) { x1 ->
+ val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 ->
//bind variables to autodiff context
- val a = bind(a)
- val b = bind(b)
+ val a = bindSymbol(a)
+ val b = bindSymbol(b)
//Include default value for c if it is not provided as a parameter
val c = bindSymbolOrNull(c) ?: one
a * x1.pow(2) + b * x1 + c
@@ -95,13 +97,13 @@ fun main() {
}
}
br()
- h3{
+ h3 {
+"Fit result: $result"
}
- h3{
+ h3 {
+"Chi2/dof = ${result.value / (x.size - 3)}"
}
}
page.makeFile()
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
new file mode 100644
index 000000000..90542adf4
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
@@ -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 = { 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)
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt
new file mode 100644
index 000000000..bd431c22c
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt
@@ -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 = { 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)
+ }
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
index 77bb75a5f..f7b284e89 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
@@ -6,11 +6,11 @@
package space.kscience.kmath.linear
import space.kscience.kmath.real.*
-import space.kscience.kmath.structures.RealBuffer
+import space.kscience.kmath.structures.DoubleBuffer
fun main() {
- val x0 = Point(0.0, 0.0, 0.0)
- val sigma = Point(1.0, 1.0, 1.0)
+ val x0 = DoubleVector(0.0, 0.0, 0.0)
+ val sigma = DoubleVector(1.0, 1.0, 1.0)
val gaussian: (Point) -> Double = { x ->
require(x.size == x0.size)
@@ -19,9 +19,9 @@ fun main() {
fun ((Point) -> Double).grad(x: Point): Point {
require(x.size == x0.size)
- return RealBuffer(x.size) { i ->
+ return DoubleBuffer(x.size) { i ->
val h = sigma[i] / 5
- val dVector = RealBuffer(x.size) { if (it == i) h else 0.0 }
+ val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
val f1 = invoke(x + dVector / 2)
val f0 = invoke(x - dVector / 2)
(f1 - f0) / h
diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt
index 324ce641f..f99dd8c0e 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt
@@ -7,17 +7,17 @@ package space.kscience.kmath.operations
import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.complex
-import space.kscience.kmath.nd.NDAlgebra
+import space.kscience.kmath.nd.AlgebraND
fun main() {
// 2d element
- val element = NDAlgebra.complex(2, 2).produce { (i, j) ->
+ val element = AlgebraND.complex(2, 2).produce { (i, j) ->
Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble())
}
println(element)
// 1d element operation
- val result = with(NDAlgebra.complex(8)) {
+ val result = with(AlgebraND.complex(8)) {
val a = produce { (it) -> i * it - it.toDouble() }
val b = 3
val c = Complex(1.0, 1.0)
diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
index eb50b26be..8e3cdf86f 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
@@ -3,26 +3,27 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
-package kscience.kmath.commons.prob
+package space.kscience.kmath.stat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
-import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler
+import org.apache.commons.rng.sampling.distribution.BoxMullerNormalizedGaussianSampler
import org.apache.commons.rng.simple.RandomSource
-import space.kscience.kmath.stat.*
+import space.kscience.kmath.samplers.GaussianSampler
import java.time.Duration
import java.time.Instant
+import org.apache.commons.rng.sampling.distribution.GaussianSampler as CMGaussianSampler
-private fun runChain(): Duration {
+private suspend fun runKMathChained(): Duration {
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
- val normal = Distribution.normal(NormalSamplerMethod.Ziggurat)
+ val normal = GaussianSampler(7.0, 2.0)
val chain = normal.sample(generator)
val startTime = Instant.now()
var sum = 0.0
repeat(10000001) { counter ->
- sum += chain.nextDouble()
+ sum += chain.next()
if (counter % 100000 == 0) {
val duration = Duration.between(startTime, Instant.now())
@@ -34,9 +35,15 @@ private fun runChain(): Duration {
return Duration.between(startTime, Instant.now())
}
-private fun runDirect(): Duration {
- val provider = RandomSource.create(RandomSource.MT, 123L)
- val sampler = ZigguratNormalizedGaussianSampler(provider)
+private fun runApacheDirect(): Duration {
+ val rng = RandomSource.create(RandomSource.MT, 123L)
+
+ val sampler = CMGaussianSampler.of(
+ BoxMullerNormalizedGaussianSampler.of(rng),
+ 7.0,
+ 2.0
+ )
+
val startTime = Instant.now()
var sum = 0.0
@@ -56,11 +63,9 @@ private fun runDirect(): Duration {
/**
* Comparing chain sampling performance with direct sampling performance
*/
-fun main() {
- runBlocking(Dispatchers.Default) {
- val chainJob = async { runChain() }
- val directJob = async { runDirect() }
- println("Chain: ${chainJob.await()}")
- println("Direct: ${directJob.await()}")
- }
+fun main(): Unit = runBlocking(Dispatchers.Default) {
+ val directJob = async { runApacheDirect() }
+ val chainJob = async { runKMathChained() }
+ println("KMath Chained: ${chainJob.await()}")
+ println("Apache Direct: ${directJob.await()}")
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt
index 0883e70c5..b319766e3 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt
@@ -8,14 +8,15 @@ package space.kscience.kmath.stat
import kotlinx.coroutines.runBlocking
import space.kscience.kmath.chains.Chain
import space.kscience.kmath.chains.collectWithState
+import space.kscience.kmath.distributions.NormalDistribution
/**
- * The state of distribution averager
+ * The state of distribution averager.
*/
private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
/**
- * Averaging
+ * Averaging.
*/
private fun Chain.mean(): Chain = collectWithState(AveragingChainState(), { it.copy() }) { chain ->
val next = chain.next()
@@ -26,7 +27,7 @@ private fun Chain.mean(): Chain = collectWithState(AveragingChai
fun main() {
- val normal = Distribution.normal()
+ val normal = NormalDistribution(0.0, 2.0)
val chain = normal.sample(RandomGenerator.default).mean()
runBlocking {
@@ -37,4 +38,4 @@ fun main() {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt
index 90e54bbd8..b30165f71 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt
@@ -9,8 +9,8 @@ package space.kscience.kmath.structures
import space.kscience.kmath.complex.*
import space.kscience.kmath.linear.transpose
-import space.kscience.kmath.nd.NDAlgebra
-import space.kscience.kmath.nd.NDStructure
+import space.kscience.kmath.nd.AlgebraND
+import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.as2D
import space.kscience.kmath.nd.real
import space.kscience.kmath.operations.invoke
@@ -20,12 +20,12 @@ fun main() {
val dim = 1000
val n = 1000
- val realField = NDAlgebra.real(dim, dim)
- val complexField: ComplexNDField = NDAlgebra.complex(dim, dim)
+ val realField = AlgebraND.real(dim, dim)
+ val complexField: ComplexFieldND = AlgebraND.complex(dim, dim)
val realTime = measureTimeMillis {
realField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) {
res += 1.0
}
@@ -36,7 +36,7 @@ fun main() {
val complexTime = measureTimeMillis {
complexField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) {
res += 1.0
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
index 65f1d13a5..cc1f5f680 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
@@ -9,7 +9,7 @@ import kotlinx.coroutines.GlobalScope
import org.nd4j.linalg.factory.Nd4j
import space.kscience.kmath.nd.*
import space.kscience.kmath.nd4j.Nd4jArrayField
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.viktor.ViktorNDField
import kotlin.contracts.InvocationKind
@@ -29,56 +29,56 @@ fun main() {
val n = 1000
// automatically build context most suited for given type.
- val autoField = NDAlgebra.auto(RealField, dim, dim)
+ val autoField = AlgebraND.auto(DoubleField, dim, dim)
// specialized nd-field for Double. It works as generic Double field as well
- val realField = NDAlgebra.real(dim, dim)
+ val realField = AlgebraND.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives.
- val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
+ val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim)
// Nd4j specialized field.
val nd4jField = Nd4jArrayField.real(dim, dim)
//viktor field
- val viktorField = ViktorNDField(dim,dim)
+ val viktorField = ViktorNDField(dim, dim)
//parallel processing based on Java Streams
- val parallelField = NDAlgebra.realWithStream(dim,dim)
+ val parallelField = AlgebraND.realWithStream(dim, dim)
measureAndPrint("Boxing addition") {
boxingField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Specialized addition") {
realField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Nd4j specialized addition") {
nd4jField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Viktor addition") {
viktorField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Parallel stream addition") {
parallelField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Automatic field addition") {
autoField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ParallelRealNDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ParallelRealNDField.kt
deleted file mode 100644
index 596142013..000000000
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/ParallelRealNDField.kt
+++ /dev/null
@@ -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,
- NumbersAddOperations>,
- ExtendedField> {
-
- private val strides = DefaultStrides(shape)
- override val elementContext: RealField get() = RealField
- override val zero: NDBuffer by lazy { produce { zero } }
- override val one: NDBuffer by lazy { produce { one } }
-
- override fun number(value: Number): NDBuffer {
- val d = value.toDouble() // minimize conversions
- return produce { d }
- }
-
- private val NDStructure.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 {
- 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.map(
- transform: RealField.(Double) -> Double,
- ): NDBuffer {
- val array = Arrays.stream(buffer.array).parallel().map { RealField.transform(it) }.toArray()
- return NDBuffer(strides, array.asBuffer())
- }
-
- override fun NDStructure.mapIndexed(
- transform: RealField.(index: IntArray, Double) -> Double,
- ): NDBuffer {
- 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,
- b: NDStructure,
- transform: RealField.(Double, Double) -> Double,
- ): NDBuffer {
- 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.unaryMinus(): NDStructure = map { -it }
-
- override fun scale(a: NDStructure, value: Double): NDStructure = a.map { it * value }
-
- override fun power(arg: NDStructure, pow: Number): NDBuffer = arg.map { power(it, pow) }
-
- override fun exp(arg: NDStructure): NDBuffer = arg.map { exp(it) }
-
- override fun ln(arg: NDStructure): NDBuffer = arg.map { ln(it) }
-
- override fun sin(arg: NDStructure): NDBuffer = arg.map { sin(it) }
- override fun cos(arg: NDStructure): NDBuffer = arg.map { cos(it) }
- override fun tan(arg: NDStructure): NDBuffer = arg.map { tan(it) }
- override fun asin(arg: NDStructure): NDBuffer = arg.map { asin(it) }
- override fun acos(arg: NDStructure): NDBuffer = arg.map { acos(it) }
- override fun atan(arg: NDStructure): NDBuffer = arg.map { atan(it) }
-
- override fun sinh(arg: NDStructure): NDBuffer = arg.map { sinh(it) }
- override fun cosh(arg: NDStructure): NDBuffer = arg.map { cosh(it) }
- override fun tanh(arg: NDStructure): NDBuffer = arg.map { tanh(it) }
- override fun asinh(arg: NDStructure): NDBuffer = arg.map { asinh(it) }
- override fun acosh(arg: NDStructure): NDBuffer = arg.map { acosh(it) }
- override fun atanh(arg: NDStructure): NDBuffer = arg.map { atanh(it) }
-}
-
-fun NDAlgebra.Companion.realWithStream(vararg shape: Int): StreamRealNDField = StreamRealNDField(shape)
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt
new file mode 100644
index 000000000..d53cfa9b9
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt
@@ -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,
+ NumbersAddOperations>,
+ ExtendedField> {
+
+ private val strides = DefaultStrides(shape)
+ override val elementContext: DoubleField get() = DoubleField
+ override val zero: BufferND by lazy { produce { zero } }
+ override val one: BufferND by lazy { produce { one } }
+
+ override fun number(value: Number): BufferND {
+ val d = value.toDouble() // minimize conversions
+ return produce { d }
+ }
+
+ private val StructureND.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 {
+ 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.map(
+ transform: DoubleField.(Double) -> Double,
+ ): BufferND {
+ val array = Arrays.stream(buffer.array).parallel().map { DoubleField.transform(it) }.toArray()
+ return BufferND(strides, array.asBuffer())
+ }
+
+ override fun StructureND.mapIndexed(
+ transform: DoubleField.(index: IntArray, Double) -> Double,
+ ): BufferND {
+ 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,
+ b: StructureND,
+ transform: DoubleField.(Double, Double) -> Double,
+ ): BufferND {
+ 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.unaryMinus(): StructureND = map { -it }
+
+ override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value }
+
+ override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) }
+
+ override fun exp(arg: StructureND): BufferND = arg.map { exp(it) }
+
+ override fun ln(arg: StructureND): BufferND = arg.map { ln(it) }
+
+ override fun sin(arg: StructureND): BufferND = arg.map { sin(it) }
+ override fun cos(arg: StructureND): BufferND = arg.map { cos(it) }
+ override fun tan(arg: StructureND): BufferND = arg.map { tan(it) }
+ override fun asin(arg: StructureND): BufferND = arg.map { asin(it) }
+ override fun acos(arg: StructureND): BufferND = arg.map { acos(it) }
+ override fun atan(arg: StructureND): BufferND = arg.map { atan(it) }
+
+ override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) }
+ override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) }
+ override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) }
+ override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) }
+ override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) }
+ override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) }
+}
+
+fun AlgebraND.Companion.realWithStream(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(shape)
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt
index 095467e5a..0d5358354 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt
@@ -5,17 +5,17 @@
package space.kscience.kmath.structures
+import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.DefaultStrides
-import space.kscience.kmath.nd.NDBuffer
import kotlin.system.measureTimeMillis
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
fun main() {
val n = 6000
val array = DoubleArray(n * n) { 1.0 }
- val buffer = RealBuffer(array)
+ val buffer = DoubleBuffer(array)
val strides = DefaultStrides(intArrayOf(n, n))
- val structure = NDBuffer(strides, buffer)
+ val structure = BufferND(strides, buffer)
measureTimeMillis {
var res = 0.0
@@ -39,4 +39,4 @@ fun main() {
strides.indices().forEach { res = array[strides.offset(it)] }
}
println("Array reading finished in $time3 millis")
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt
index f087a7166..dea7095a8 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt
@@ -5,14 +5,14 @@
package space.kscience.kmath.structures
-import space.kscience.kmath.nd.NDStructure
+import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.mapToBuffer
import kotlin.system.measureTimeMillis
@Suppress("UNUSED_VARIABLE")
fun main() {
val n = 6000
- val structure = NDStructure.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
+ val structure = StructureND.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
structure.mapToBuffer { it + 1 } // warm-up
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
println("Structure mapping finished in $time1 millis")
@@ -25,10 +25,10 @@ fun main() {
println("Array mapping finished in $time2 millis")
- val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
+ val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 })
val time3 = measureTimeMillis {
- val target = RealBuffer(DoubleArray(n * n))
+ val target = DoubleBuffer(DoubleArray(n * n))
val res = array.forEachIndexed { index, value ->
target[index] = value + 1
}
diff --git a/gradle.properties b/gradle.properties
index 3aaade368..7e9516660 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -9,5 +9,5 @@ kotlin.mpp.stability.nowarn=true
kotlin.native.enableDependencyPropagation=false
kotlin.parallel.tasks.in.project=true
org.gradle.configureondemand=true
-org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G
+org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2059e8ea0..442d9132e 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,8 +1,3 @@
-#
-# Copyright 2018-2021 KMath contributors.
-# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
-#
-
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
diff --git a/kmath-ast/README.md b/kmath-ast/README.md
index 529586424..b1ef9c7d3 100644
--- a/kmath-ast/README.md
+++ b/kmath-ast/README.md
@@ -1,49 +1,43 @@
-# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`)
+# Module kmath-ast
-This subproject implements the following features:
+Abstract syntax tree expression representation and related optimizations.
- - [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
- - [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
- - [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
- - [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
- - [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
- - [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
+ - [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
+ - [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
+ - [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
+ - [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
+ - [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
+ - [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
-> #### Artifact:
->
-> This module artifact: `space.kscience:kmath-ast:0.3.0-dev-2`.
->
-> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
->
-> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-ast/_latestVersion)
->
-> **Gradle:**
->
-> ```gradle
-> repositories {
-> maven { url 'https://repo.kotlin.link' }
-> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
-> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
-> }
->
-> dependencies {
-> implementation 'space.kscience:kmath-ast:0.3.0-dev-2'
-> }
-> ```
-> **Gradle Kotlin DSL:**
->
-> ```kotlin
-> repositories {
-> maven("https://repo.kotlin.link")
-> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
-> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
-> }
->
-> dependencies {
-> implementation("space.kscience:kmath-ast:0.3.0-dev-2")
-> }
-> ```
+## Artifact:
+
+The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-6`.
+
+**Gradle:**
+```gradle
+repositories {
+ maven { url 'https://repo.kotlin.link' }
+ maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
+ maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
+}
+
+dependencies {
+ implementation 'space.kscience:kmath-ast:0.3.0-dev-6'
+}
+```
+**Gradle Kotlin DSL:**
+```kotlin
+repositories {
+ maven("https://repo.kotlin.link")
+ maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
+ maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
+}
+
+dependencies {
+ implementation("space.kscience:kmath-ast:0.3.0-dev-6")
+}
+```
## Dynamic expression code generation
@@ -55,7 +49,7 @@ a special implementation of `Expression` with implemented `invoke` function.
For example, the following builder:
```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
+DoubleField.mstInField { symbol("x") + 2 }.compile()
```
… leads to generation of bytecode, which can be decompiled to the following Java class:
@@ -88,8 +82,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression {
This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
-RealField.expression("x+2".parseMath())
+DoubleField.mstInField { symbol("x") + 2 }.compile()
+DoubleField.expression("x+2".parseMath())
```
#### Known issues
@@ -103,7 +97,7 @@ RealField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
+DoubleField.mstInField { symbol("x") + 2 }.compile()
```
The code above returns expression implemented with such a JS function:
@@ -117,3 +111,39 @@ var executable = function (constants, arguments) {
#### Known issues
- This feature uses `eval` which can be unavailable in several environments.
+
+## Rendering expressions
+
+kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
+
+Example usage:
+
+```kotlin
+import space.kscience.kmath.ast.*
+import space.kscience.kmath.ast.rendering.*
+
+public fun main() {
+ val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
+ val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
+ val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
+ println("LaTeX:")
+ println(latex)
+ println()
+ val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax)
+ println("MathML:")
+ println(mathML)
+}
+```
+
+Result LaTeX:
+
+![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D)
+
+Result MathML (embedding MathML is not allowed by GitHub Markdown):
+
+```html
+ex-sin-12x2×1010+x3-12
+```
+
+It is also possible to create custom algorithms of render, and even add support of other markup languages
+(see API reference).
diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts
index 76a78a271..3f309b67c 100644
--- a/kmath-ast/build.gradle.kts
+++ b/kmath-ast/build.gradle.kts
@@ -6,7 +6,8 @@
import ru.mipt.npm.gradle.Maturity
plugins {
- id("ru.mipt.npm.gradle.mpp")
+ kotlin("multiplatform")
+ id("ru.mipt.npm.gradle.common")
}
kotlin.js {
@@ -63,36 +64,36 @@ readme {
feature(
id = "expression-language",
description = "Expression language and its parser",
- ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt"
+ ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt"
)
feature(
id = "mst",
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
- ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
+ ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
)
feature(
id = "mst-building",
description = "MST building algebraic structure",
- ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt"
+ ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt"
)
feature(
id = "mst-interpreter",
description = "MST interpreter",
- ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
+ ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
)
feature(
id = "mst-jvm-codegen",
description = "Dynamic MST to JVM bytecode compiler",
- ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt"
+ ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt"
)
feature(
id = "mst-js-codegen",
description = "Dynamic MST to JS compiler",
- ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt"
+ ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt"
)
}
diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md
index 2712cba75..9ed44d584 100644
--- a/kmath-ast/docs/README-TEMPLATE.md
+++ b/kmath-ast/docs/README-TEMPLATE.md
@@ -1,6 +1,6 @@
-# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`)
+# Module kmath-ast
-This subproject implements the following features:
+Abstract syntax tree expression representation and related optimizations.
${features}
@@ -16,7 +16,7 @@ a special implementation of `Expression` with implemented `invoke` function.
For example, the following builder:
```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
+DoubleField.mstInField { symbol("x") + 2 }.compile()
```
… leads to generation of bytecode, which can be decompiled to the following Java class:
@@ -49,8 +49,8 @@ public final class AsmCompiledExpression_45045_0 implements Expression {
This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
-RealField.expression("x+2".parseMath())
+DoubleField.mstInField { symbol("x") + 2 }.compile()
+DoubleField.expression("x+2".parseMath())
```
#### Known issues
@@ -64,7 +64,7 @@ RealField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
+DoubleField.mstInField { symbol("x") + 2 }.compile()
```
The code above returns expression implemented with such a JS function:
@@ -78,3 +78,39 @@ var executable = function (constants, arguments) {
#### Known issues
- This feature uses `eval` which can be unavailable in several environments.
+
+## Rendering expressions
+
+kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
+
+Example usage:
+
+```kotlin
+import space.kscience.kmath.ast.*
+import space.kscience.kmath.ast.rendering.*
+
+public fun main() {
+ val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath()
+ val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst)
+ val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax)
+ println("LaTeX:")
+ println(latex)
+ println()
+ val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax)
+ println("MathML:")
+ println(mathML)
+}
+```
+
+Result LaTeX:
+
+![](http://chart.googleapis.com/chart?cht=tx&chl=e%5E%7B%5Csqrt%7Bx%7D%7D-%5Cfrac%7B%5Cfrac%7B%5Coperatorname%7Bsin%7D%5E%7B-1%7D%5C,%5Cleft(2%5C,x%5Cright)%7D%7B2%5Ctimes10%5E%7B10%7D%2Bx%5E%7B3%7D%7D%7D%7B-12%7D)
+
+Result MathML (embedding MathML is not allowed by GitHub Markdown):
+
+```html
+ex-sin-12x2×1010+x3-12
+```
+
+It is also possible to create custom algorithms of render, and even add support of other markup languages
+(see API reference).
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstExpression.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstExpression.kt
deleted file mode 100644
index 9329d5877..000000000
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstExpression.kt
+++ /dev/null
@@ -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>(public val algebra: A, public val mst: MST) : Expression {
- private inner class InnerAlgebra(val arguments: Map) : NumericAlgebra {
- 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).number(value)
- else
- error("Numeric nodes are not supported by $this")
- }
-
- override operator fun invoke(arguments: Map): T = InnerAlgebra(arguments).evaluate(mst)
-}
-
-/**
- * Builds [MstExpression] over [Algebra].
- *
- * @author Alexander Nozik
- */
-public inline fun , E : Algebra> A.mst(
- mstAlgebra: E,
- block: E.() -> MST,
-): MstExpression = MstExpression(this, mstAlgebra.block())
-
-/**
- * Builds [MstExpression] over [Group].
- *
- * @author Alexander Nozik
- */
-public inline fun > A.mstInGroup(block: MstGroup.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return MstExpression(this, MstGroup.block())
-}
-
-/**
- * Builds [MstExpression] over [Ring].
- *
- * @author Alexander Nozik
- */
-public inline fun > A.mstInRing(block: MstRing.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return MstExpression(this, MstRing.block())
-}
-
-/**
- * Builds [MstExpression] over [Field].
- *
- * @author Alexander Nozik
- */
-public inline fun > A.mstInField(block: MstField.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return MstExpression(this, MstField.block())
-}
-
-/**
- * Builds [MstExpression] over [ExtendedField].
- *
- * @author Iaroslav Postovalov
- */
-public inline fun > A.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return MstExpression(this, MstExtendedField.block())
-}
-
-/**
- * Builds [MstExpression] over [FunctionalExpressionGroup].
- *
- * @author Alexander Nozik
- */
-public inline fun > FunctionalExpressionGroup.mstInGroup(block: MstGroup.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return algebra.mstInGroup(block)
-}
-
-/**
- * Builds [MstExpression] over [FunctionalExpressionRing].
- *
- * @author Alexander Nozik
- */
-public inline fun > FunctionalExpressionRing.mstInRing(block: MstRing.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return algebra.mstInRing(block)
-}
-
-/**
- * Builds [MstExpression] over [FunctionalExpressionField].
- *
- * @author Alexander Nozik
- */
-public inline fun > FunctionalExpressionField.mstInField(block: MstField.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return algebra.mstInField(block)
-}
-
-/**
- * Builds [MstExpression] over [FunctionalExpressionExtendedField].
- *
- * @author Iaroslav Postovalov
- */
-public inline fun > FunctionalExpressionExtendedField.mstInExtendedField(
- block: MstExtendedField.() -> MST,
-): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return algebra.mstInExtendedField(block)
-}
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt
new file mode 100644
index 000000000..34230f3c8
--- /dev/null
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt
@@ -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)
+ }
+ }
+ }
+}
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt
new file mode 100644
index 000000000..f7487a356
--- /dev/null
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt
@@ -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("")
+ }
+
+ private fun render0(node: MathSyntax, output: Appendable): Unit = output.run {
+ fun tag(tagName: String, vararg attr: Pair, block: () -> Unit = {}) {
+ append('<')
+ append(tagName)
+
+ if (attr.isNotEmpty()) {
+ append(' ')
+ var count = 0
+
+ for ((name, value) in attr) {
+ if (++count > 1) append(' ')
+ append(name)
+ append("=\"")
+ append(value)
+ append('"')
+ }
+ }
+
+ append('>')
+ block()
+ append("")
+ append(tagName)
+ append('>')
+ }
+
+ fun render(syntax: MathSyntax) = render0(syntax, output)
+
+ when (node) {
+ is NumberSyntax -> tag("mn") { append(node.string) }
+ is SymbolSyntax -> tag("mi") { append(node.string) }
+ is OperatorNameSyntax -> tag("mo") { append(node.name) }
+
+ is SpecialSymbolSyntax -> when (node.kind) {
+ SpecialSymbolSyntax.Kind.INFINITY -> tag("mo") { append("∞") }
+ SpecialSymbolSyntax.Kind.SMALL_PI -> tag("mo") { append("π") }
+ }
+
+ is OperandSyntax -> if (node.parentheses) {
+ tag("mfenced", "open" to "(", "close" to ")", "separators" to "") {
+ render(node.operand)
+ }
+ } else {
+ render(node.operand)
+ }
+
+ is UnaryOperatorSyntax -> {
+ render(node.prefix)
+ tag("mspace", "width" to "0.167em")
+ render(node.operand)
+ }
+
+ is UnaryPlusSyntax -> {
+ tag("mo") { append('+') }
+ render(node.operand)
+ }
+
+ is UnaryMinusSyntax -> {
+ tag("mo") { append("-") }
+ render(node.operand)
+ }
+
+ is RadicalSyntax -> tag("msqrt") { render(node.operand) }
+
+ is SuperscriptSyntax -> tag("msup") {
+ tag("mrow") { render(node.left) }
+ tag("mrow") { render(node.right) }
+ }
+
+ is SubscriptSyntax -> tag("msub") {
+ tag("mrow") { render(node.left) }
+ tag("mrow") { render(node.right) }
+ }
+
+ is BinaryOperatorSyntax -> {
+ render(node.prefix)
+
+ tag("mfenced", "open" to "(", "close" to ")", "separators" to "") {
+ render(node.left)
+ tag("mo") { append(',') }
+ render(node.right)
+ }
+ }
+
+ is BinaryPlusSyntax -> {
+ render(node.left)
+ tag("mo") { append('+') }
+ render(node.right)
+ }
+
+ is BinaryMinusSyntax -> {
+ render(node.left)
+ tag("mo") { append('-') }
+ render(node.right)
+ }
+
+ is FractionSyntax -> tag("mfrac") {
+ tag("mrow") {
+ render(node.left)
+ }
+
+ tag("mrow") {
+ render(node.right)
+ }
+ }
+
+ is RadicalWithIndexSyntax -> tag("mroot") {
+ tag("mrow") { render(node.right) }
+ tag("mrow") { render(node.left) }
+ }
+
+ is MultiplicationSyntax -> {
+ render(node.left)
+ if (node.times) tag("mo") { append("×") } else tag("mspace", "width" to "0.167em")
+ render(node.right)
+ }
+ }
+ }
+}
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt
new file mode 100644
index 000000000..891e8f05b
--- /dev/null
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt
@@ -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) : 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,
+ public val stages: List,
+) : 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,
+ ),
+ )
+ }
+}
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt
new file mode 100644
index 000000000..069e56c71
--- /dev/null
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.ast.rendering
+
+/**
+ * Mathematical typography syntax node.
+ *
+ * @author Iaroslav Postovalov
+ */
+public sealed class MathSyntax {
+ /**
+ * The parent node of this syntax node.
+ */
+ public var parent: MathSyntax? = null
+}
+
+/**
+ * Terminal node, which should not have any children nodes.
+ *
+ * @author Iaroslav Postovalov
+ */
+public sealed class TerminalSyntax : MathSyntax()
+
+/**
+ * Node containing a certain operation.
+ *
+ * @author Iaroslav Postovalov
+ */
+public sealed class OperationSyntax : MathSyntax() {
+ /**
+ * The operation token.
+ */
+ public abstract val operation: String
+}
+
+/**
+ * Unary node, which has only one child.
+ *
+ * @author Iaroslav Postovalov
+ */
+public sealed class UnarySyntax : OperationSyntax() {
+ /**
+ * The operand of this node.
+ */
+ public abstract val operand: MathSyntax
+}
+
+/**
+ * Binary node, which has only two children.
+ *
+ * @author Iaroslav Postovalov
+ */
+public sealed class BinarySyntax : OperationSyntax() {
+ /**
+ * The left-hand side operand.
+ */
+ public abstract val left: MathSyntax
+
+ /**
+ * The right-hand side operand.
+ */
+ public abstract val right: MathSyntax
+}
+
+/**
+ * Represents a number.
+ *
+ * @property string The digits of number.
+ * @author Iaroslav Postovalov
+ */
+public data class NumberSyntax(public var string: String) : TerminalSyntax()
+
+/**
+ * Represents a symbol.
+ *
+ * @property string The symbol.
+ * @author Iaroslav Postovalov
+ */
+public data class SymbolSyntax(public var string: String) : TerminalSyntax()
+
+/**
+ * Represents special typing for operator name.
+ *
+ * @property name The operator name.
+ * @see BinaryOperatorSyntax
+ * @see UnaryOperatorSyntax
+ * @author Iaroslav Postovalov
+ */
+public data class OperatorNameSyntax(public var name: String) : TerminalSyntax()
+
+/**
+ * Represents a usage of special symbols.
+ *
+ * @property kind The kind of symbol.
+ * @author Iaroslav Postovalov
+ */
+public data class SpecialSymbolSyntax(public var kind: Kind) : TerminalSyntax() {
+ /**
+ * The kind of symbol.
+ */
+ public enum class Kind {
+ /**
+ * The infinity (∞) symbol.
+ */
+ INFINITY,
+
+ /**
+ * The Pi (π) symbol.
+ */
+ SMALL_PI;
+ }
+}
+
+/**
+ * Represents operand of a certain operator wrapped with parentheses or not.
+ *
+ * @property operand The operand.
+ * @property parentheses Whether the operand should be wrapped with parentheses.
+ * @author Iaroslav Postovalov
+ */
+public data class OperandSyntax(
+ public val operand: MathSyntax,
+ public var parentheses: Boolean,
+) : MathSyntax() {
+ init {
+ operand.parent = this
+ }
+}
+
+/**
+ * Represents unary, prefix operator syntax (like f x).
+ *
+ * @property prefix The prefix.
+ * @author Iaroslav Postovalov
+ */
+public data class UnaryOperatorSyntax(
+ public override val operation: String,
+ public var prefix: MathSyntax,
+ public override val operand: OperandSyntax,
+) : UnarySyntax() {
+ init {
+ operand.parent = this
+ }
+}
+
+/**
+ * Represents prefix, unary plus operator.
+ *
+ * @author Iaroslav Postovalov
+ */
+public data class UnaryPlusSyntax(
+ public override val operation: String,
+ public override val operand: OperandSyntax,
+) : UnarySyntax() {
+ init {
+ operand.parent = this
+ }
+}
+
+/**
+ * Represents prefix, unary minus operator.
+ *
+ * @author Iaroslav Postovalov
+ */
+public data class UnaryMinusSyntax(
+ public override val operation: String,
+ public override val operand: OperandSyntax,
+) : UnarySyntax() {
+ init {
+ operand.parent = this
+ }
+}
+
+/**
+ * Represents radical with a node inside it.
+ *
+ * @property operand The radicand.
+ * @author Iaroslav Postovalov
+ */
+public data class RadicalSyntax(
+ public override val operation: String,
+ public override val operand: MathSyntax,
+) : UnarySyntax() {
+ init {
+ operand.parent = this
+ }
+}
+
+/**
+ * Represents a syntax node with superscript (usually, for exponentiation).
+ *
+ * @property left The node.
+ * @property right The superscript.
+ * @author Iaroslav Postovalov
+ */
+public data class SuperscriptSyntax(
+ public override val operation: String,
+ public override val left: MathSyntax,
+ public override val right: MathSyntax,
+) : BinarySyntax() {
+ init {
+ left.parent = this
+ right.parent = this
+ }
+}
+
+/**
+ * Represents a syntax node with subscript.
+ *
+ * @property left The node.
+ * @property right The subscript.
+ * @author Iaroslav Postovalov
+ */
+public data class SubscriptSyntax(
+ public override val operation: String,
+ public override val left: MathSyntax,
+ public override val right: MathSyntax,
+) : BinarySyntax() {
+ init {
+ left.parent = this
+ right.parent = this
+ }
+}
+
+/**
+ * Represents binary, prefix operator syntax (like f(a, b)).
+ *
+ * @property prefix The prefix.
+ * @author Iaroslav Postovalov
+ */
+public data class BinaryOperatorSyntax(
+ public override val operation: String,
+ public var prefix: MathSyntax,
+ public override val left: MathSyntax,
+ public override val right: MathSyntax,
+) : BinarySyntax() {
+ init {
+ left.parent = this
+ right.parent = this
+ }
+}
+
+/**
+ * Represents binary, infix addition.
+ *
+ * @param left The augend.
+ * @param right The addend.
+ * @author Iaroslav Postovalov
+ */
+public data class BinaryPlusSyntax(
+ public override val operation: String,
+ public override val left: OperandSyntax,
+ public override val right: OperandSyntax,
+) : BinarySyntax() {
+ init {
+ left.parent = this
+ right.parent = this
+ }
+}
+
+/**
+ * Represents binary, infix subtraction.
+ *
+ * @param left The minuend.
+ * @param right The subtrahend.
+ * @author Iaroslav Postovalov
+ */
+public data class BinaryMinusSyntax(
+ public override val operation: String,
+ public override val left: OperandSyntax,
+ public override val right: OperandSyntax,
+) : BinarySyntax() {
+ init {
+ left.parent = this
+ right.parent = this
+ }
+}
+
+/**
+ * Represents fraction with numerator and denominator.
+ *
+ * @property left The numerator.
+ * @property right The denominator.
+ * @author Iaroslav Postovalov
+ */
+public data class FractionSyntax(
+ public override val operation: String,
+ public override val left: MathSyntax,
+ public override val right: MathSyntax,
+) : BinarySyntax() {
+ init {
+ left.parent = this
+ right.parent = this
+ }
+}
+
+/**
+ * Represents radical syntax with index.
+ *
+ * @property left The index.
+ * @property right The radicand.
+ * @author Iaroslav Postovalov
+ */
+public data class RadicalWithIndexSyntax(
+ public override val operation: String,
+ public override val left: MathSyntax,
+ public override val right: MathSyntax,
+) : BinarySyntax() {
+ init {
+ left.parent = this
+ right.parent = this
+ }
+}
+
+/**
+ * Represents binary, infix multiplication in the form of coefficient (2 x) or with operator (x×2).
+ *
+ * @property left The multiplicand.
+ * @property right The multiplier.
+ * @property times whether the times (×) symbol should be used.
+ * @author Iaroslav Postovalov
+ */
+public data class MultiplicationSyntax(
+ public override val operation: String,
+ public override val left: OperandSyntax,
+ public override val right: OperandSyntax,
+ public var times: Boolean,
+) : BinarySyntax() {
+ init {
+ left.parent = this
+ right.parent = this
+ }
+}
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt
new file mode 100644
index 000000000..7fa91e158
--- /dev/null
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt
@@ -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()
+}
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt
new file mode 100644
index 000000000..5d6c7bb0a
--- /dev/null
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt
@@ -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>) : 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>) : 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) : 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?) : 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?) : 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?) : 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?) : 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?) : 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?) : 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?) : 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?) : 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?) : 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?) : 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?) : 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?) : 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?) : 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?) : 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,
+ ))
+ }
+}
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt
new file mode 100644
index 000000000..0ebb41b28
--- /dev/null
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.ast.rendering
+
+import space.kscience.kmath.operations.FieldOperations
+import space.kscience.kmath.operations.GroupOperations
+import space.kscience.kmath.operations.PowerOperations
+import space.kscience.kmath.operations.RingOperations
+
+/**
+ * Removes unnecessary times (×) symbols from [MultiplicationSyntax].
+ *
+ * @author Iaroslav Postovalov
+ */
+public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostProcessStage {
+ public override fun perform(node: MathSyntax) {
+ when (node) {
+ is NumberSyntax -> Unit
+ is SymbolSyntax -> Unit
+ is OperatorNameSyntax -> Unit
+ is SpecialSymbolSyntax -> Unit
+ is OperandSyntax -> perform(node.operand)
+
+ is UnaryOperatorSyntax -> {
+ perform(node.prefix)
+ perform(node.operand)
+ }
+
+ is UnaryPlusSyntax -> perform(node.operand)
+ is UnaryMinusSyntax -> perform(node.operand)
+ is RadicalSyntax -> perform(node.operand)
+
+ is SuperscriptSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is SubscriptSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is BinaryOperatorSyntax -> {
+ perform(node.prefix)
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is BinaryPlusSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is BinaryMinusSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is FractionSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is RadicalWithIndexSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is MultiplicationSyntax -> {
+ node.times = node.right.operand is NumberSyntax && !node.right.parentheses
+ || node.left.operand is NumberSyntax && node.right.operand is FractionSyntax
+ || node.left.operand is NumberSyntax && node.right.operand is NumberSyntax
+ || node.left.operand is NumberSyntax && node.right.operand is SuperscriptSyntax && node.right.operand.left is NumberSyntax
+
+ perform(node.left)
+ perform(node.right)
+ }
+ }
+ }
+}
+
+/**
+ * Removes unnecessary parentheses from [OperandSyntax].
+ *
+ * @property precedenceFunction Returns the precedence number for syntax node. Higher number is lower priority.
+ * @author Iaroslav Postovalov
+ */
+public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) :
+ FeaturedMathRendererWithPostProcess.PostProcessStage {
+ public override fun perform(node: MathSyntax) {
+ when (node) {
+ is NumberSyntax -> Unit
+ is SymbolSyntax -> Unit
+ is OperatorNameSyntax -> Unit
+ is SpecialSymbolSyntax -> Unit
+
+ is OperandSyntax -> {
+ val isRightOfSuperscript =
+ (node.parent is SuperscriptSyntax) && (node.parent as SuperscriptSyntax).right === node
+
+ val precedence = precedenceFunction(node.operand)
+
+ val needParenthesesByPrecedence = when (val parent = node.parent) {
+ null -> false
+
+ is BinarySyntax -> {
+ val parentPrecedence = precedenceFunction(parent)
+
+ parentPrecedence < precedence ||
+ parentPrecedence == precedence && parentPrecedence != 0 && node === parent.right
+ }
+
+ else -> precedence > precedenceFunction(parent)
+ }
+
+ node.parentheses = !isRightOfSuperscript
+ && (needParenthesesByPrecedence || node.parent is UnaryOperatorSyntax)
+
+ perform(node.operand)
+ }
+
+ is UnaryOperatorSyntax -> {
+ perform(node.prefix)
+ perform(node.operand)
+ }
+
+ is UnaryPlusSyntax -> perform(node.operand)
+ is UnaryMinusSyntax -> {
+ perform(node.operand)
+ }
+ is RadicalSyntax -> perform(node.operand)
+
+ is SuperscriptSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is SubscriptSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is BinaryOperatorSyntax -> {
+ perform(node.prefix)
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is BinaryPlusSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is BinaryMinusSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is FractionSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is MultiplicationSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+
+ is RadicalWithIndexSyntax -> {
+ perform(node.left)
+ perform(node.right)
+ }
+ }
+ }
+
+ public companion object {
+ /**
+ * The default configuration of [SimplifyParentheses] where power is 1, multiplicative operations are 2,
+ * additive operations are 3.
+ */
+ public val Default: SimplifyParentheses = SimplifyParentheses {
+ when (it) {
+ is TerminalSyntax -> 0
+ is UnarySyntax -> 2
+
+ is BinarySyntax -> when (it.operation) {
+ PowerOperations.POW_OPERATION -> 1
+ RingOperations.TIMES_OPERATION -> 3
+ FieldOperations.DIV_OPERATION -> 3
+ GroupOperations.MINUS_OPERATION -> 4
+ GroupOperations.PLUS_OPERATION -> 4
+ else -> 0
+ }
+
+ else -> 0
+ }
+ }
+ }
+}
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscisnce/kmath/ast/InterpretTest.kt b/kmath-ast/src/commonTest/kotlin/space/kscisnce/kmath/ast/InterpretTest.kt
new file mode 100644
index 000000000..93fde5aab
--- /dev/null
+++ b/kmath-ast/src/commonTest/kotlin/space/kscisnce/kmath/ast/InterpretTest.kt
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt
index 909e8e575..83914f3ec 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt
@@ -5,12 +5,13 @@
package space.kscience.kmath.estree
-import space.kscience.kmath.ast.MST
-import space.kscience.kmath.ast.MST.*
-import space.kscience.kmath.ast.MstExpression
import space.kscience.kmath.estree.internal.ESTreeBuilder
import space.kscience.kmath.estree.internal.estree.BaseExpression
import space.kscience.kmath.expressions.Expression
+import space.kscience.kmath.expressions.MST
+import space.kscience.kmath.expressions.MST.*
+import space.kscience.kmath.expressions.invoke
+import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra
@@ -18,11 +19,7 @@ import space.kscience.kmath.operations.NumericAlgebra
internal fun MST.compileWith(algebra: Algebra): Expression {
fun ESTreeBuilder.visit(node: MST): BaseExpression = when (node) {
is Symbolic -> {
- val symbol = try {
- algebra.bindSymbol(node.value)
- } catch (ignored: IllegalStateException) {
- null
- }
+ val symbol = algebra.bindSymbolOrNull(node.value)
if (symbol != null)
constant(symbol)
@@ -34,16 +31,17 @@ internal fun MST.compileWith(algebra: Algebra): Expression {
is Unary -> when {
algebra is NumericAlgebra && node.value is Numeric -> constant(
- algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value)))
+ algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value))
}
is Binary -> when {
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant(
- algebra
- .binaryOperationFunction(node.operation)
- .invoke(algebra.number(node.left.value), algebra.number(node.right.value))
+ algebra.binaryOperationFunction(node.operation).invoke(
+ algebra.number((node.left as Numeric).value),
+ algebra.number((node.right as Numeric).value)
+ )
)
algebra is NumericAlgebra && node.left is Numeric -> call(
@@ -69,19 +67,21 @@ internal fun MST.compileWith(algebra: Algebra): Expression {
return ESTreeBuilder { visit(this@compileWith) }.instance
}
+/**
+ * Create a compiled expression with given [MST] and given [algebra].
+ */
+public fun MST.compileToExpression(algebra: Algebra): Expression = compileWith(algebra)
+
/**
- * Compiles an [MST] to ESTree generated expression using given algebra.
- *
- * @author Alexander Nozik.
+ * Compile given MST to expression and evaluate it against [arguments]
*/
-public fun Algebra.expression(mst: MST): Expression =
- mst.compileWith(this)
+public inline fun MST.compile(algebra: Algebra, arguments: Map): T =
+ compileToExpression(algebra).invoke(arguments)
+
/**
- * Optimizes performance of an [MstExpression] by compiling it into ESTree generated expression.
- *
- * @author Alexander Nozik.
+ * Compile given MST to expression and evaluate it against [arguments]
*/
-public fun MstExpression>.compile(): Expression =
- mst.compileWith(algebra)
+public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T =
+ compileToExpression(algebra).invoke(*arguments)
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt
index b7dfc31af..6f917a24c 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt
@@ -8,7 +8,7 @@ package space.kscience.kmath.estree.internal
import space.kscience.kmath.estree.internal.astring.generate
import space.kscience.kmath.estree.internal.estree.*
import space.kscience.kmath.expressions.Expression
-import space.kscience.kmath.expressions.Symbol
+import space.kscience.kmath.misc.Symbol
internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExpression) {
private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression {
diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt
index 99f037b7c..5823518ce 100644
--- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt
+++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt
@@ -5,19 +5,22 @@
package space.kscience.kmath.estree
-import space.kscience.kmath.ast.*
import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.toComplex
-import space.kscience.kmath.expressions.invoke
+import space.kscience.kmath.expressions.*
+import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.ByteRing
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestESTreeConsistencyWithInterpreter {
+
@Test
fun mstSpace() {
- val res1 = MstGroup.mstInGroup {
+
+ val mst = MstGroup {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
number(3.toByte()) - (number(2.toByte()) + (scale(
@@ -28,27 +31,17 @@ internal class TestESTreeConsistencyWithInterpreter {
number(1)
) + bindSymbol("x") + zero
- }("x" to MST.Numeric(2))
+ }
- val res2 = MstGroup.mstInGroup {
- binaryOperationFunction("+")(
- unaryOperationFunction("+")(
- number(3.toByte()) - (number(2.toByte()) + (scale(
- add(number(1), number(1)),
- 2.0
- ) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
- ),
-
- number(1)
- ) + bindSymbol("x") + zero
- }.compile()("x" to MST.Numeric(2))
-
- assertEquals(res1, res2)
+ assertEquals(
+ mst.interpret(MstGroup, Symbol.x to MST.Numeric(2)),
+ mst.compile(MstGroup, Symbol.x to MST.Numeric(2))
+ )
}
@Test
fun byteRing() {
- val res1 = ByteRing.mstInRing {
+ val mst = MstRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (scale(
@@ -59,62 +52,43 @@ internal class TestESTreeConsistencyWithInterpreter {
number(1)
) * number(2)
- }("x" to 3.toByte())
+ }
- val res2 = ByteRing.mstInRing {
- binaryOperationFunction("+")(
- unaryOperationFunction("+")(
- (bindSymbol("x") - (2.toByte() + (scale(
- add(number(1), number(1)),
- 2.0
- ) + 1.toByte()))) * 3.0 - 1.toByte()
- ),
- number(1)
- ) * number(2)
- }.compile()("x" to 3.toByte())
-
- assertEquals(res1, res2)
+ assertEquals(
+ mst.interpret(ByteRing, Symbol.x to 3.toByte()),
+ mst.compile(ByteRing, Symbol.x to 3.toByte())
+ )
}
@Test
fun realField() {
- val res1 = RealField.mstInField {
+ val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
- }("x" to 2.0)
+ }
- val res2 = RealField.mstInField {
- +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
- (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
- + number(1),
- number(1) / 2 + number(2.0) * one
- ) + zero
- }.compile()("x" to 2.0)
-
- assertEquals(res1, res2)
+ assertEquals(
+ mst.interpret(DoubleField, Symbol.x to 2.0),
+ mst.compile(DoubleField, Symbol.x to 2.0)
+ )
}
@Test
fun complexField() {
- val res1 = ComplexField.mstInField {
+ val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
- }("x" to 2.0.toComplex())
+ }
- val res2 = ComplexField.mstInField {
- +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
- (3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
- + number(1),
- number(1) / 2 + number(2.0) * one
- ) + zero
- }.compile()("x" to 2.0.toComplex())
-
- assertEquals(res1, res2)
+ assertEquals(
+ mst.interpret(ComplexField, Symbol.x to 2.0.toComplex()),
+ mst.compile(ComplexField, Symbol.x to 2.0.toComplex())
+ )
}
}
diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeOperationsSupport.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeOperationsSupport.kt
index 834495990..a1bff92d0 100644
--- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeOperationsSupport.kt
+++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeOperationsSupport.kt
@@ -5,11 +5,10 @@
package space.kscience.kmath.estree
-import space.kscience.kmath.ast.mstInExtendedField
-import space.kscience.kmath.ast.mstInField
-import space.kscience.kmath.ast.mstInGroup
+import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.invoke
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
@@ -17,27 +16,29 @@ import kotlin.test.assertEquals
internal class TestESTreeOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
- val expression = RealField.mstInGroup { -bindSymbol("x") }.compile()
+ val expression = MstExtendedField { -bindSymbol("x") }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
assertEquals(-2.0, res)
}
@Test
fun testBinaryOperationInvocation() {
- val expression = RealField.mstInGroup { -bindSymbol("x") + number(1.0) }.compile()
+ val expression = MstExtendedField { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
assertEquals(-1.0, res)
}
@Test
fun testConstProductInvocation() {
- val res = RealField.mstInField { bindSymbol("x") * 2 }("x" to 2.0)
+ val res = MstExtendedField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
assertEquals(4.0, res)
}
@Test
fun testMultipleCalls() {
- val e = RealField.mstInExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }.compile()
+ val e =
+ MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
+ .compileToExpression(DoubleField)
val r = Random(0)
var s = 0.0
repeat(1000000) { s += e("x" to r.nextDouble()) }
diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeSpecialization.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeSpecialization.kt
index 8824b08af..b5ae1ca3f 100644
--- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeSpecialization.kt
+++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeSpecialization.kt
@@ -5,54 +5,64 @@
package space.kscience.kmath.estree
-import space.kscience.kmath.ast.mstInField
+import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestESTreeSpecialization {
@Test
fun testUnaryPlus() {
- val expr = RealField.mstInField { unaryOperationFunction("+")(bindSymbol("x")) }.compile()
+ val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(2.0, expr("x" to 2.0))
}
@Test
fun testUnaryMinus() {
- val expr = RealField.mstInField { unaryOperationFunction("-")(bindSymbol("x")) }.compile()
+ val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr("x" to 2.0))
}
@Test
fun testAdd() {
- val expr = RealField.mstInField { binaryOperationFunction("+")(bindSymbol("x"), bindSymbol("x")) }.compile()
+ val expr = MstExtendedField {
+ binaryOperationFunction("+")(bindSymbol("x"),
+ bindSymbol("x"))
+ }.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0))
}
@Test
fun testSine() {
- val expr = RealField.mstInField { unaryOperationFunction("sin")(bindSymbol("x")) }.compile()
+ val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 0.0))
}
@Test
fun testMinus() {
- val expr = RealField.mstInField { binaryOperationFunction("-")(bindSymbol("x"), bindSymbol("x")) }.compile()
+ val expr = MstExtendedField {
+ binaryOperationFunction("-")(bindSymbol("x"),
+ bindSymbol("x"))
+ }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 2.0))
}
@Test
fun testDivide() {
- val expr = RealField.mstInField { binaryOperationFunction("/")(bindSymbol("x"), bindSymbol("x")) }.compile()
+ val expr = MstExtendedField {
+ binaryOperationFunction("/")(bindSymbol("x"),
+ bindSymbol("x"))
+ }.compileToExpression(DoubleField)
assertEquals(1.0, expr("x" to 2.0))
}
@Test
fun testPower() {
- val expr = RealField
- .mstInField { binaryOperationFunction("pow")(bindSymbol("x"), number(2)) }
- .compile()
+ val expr = MstExtendedField {
+ binaryOperationFunction("pow")(bindSymbol("x"), number(2))
+ }.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0))
}
diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeVariables.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeVariables.kt
index 5af26e147..1effe14e1 100644
--- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeVariables.kt
+++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/estree/TestESTreeVariables.kt
@@ -5,9 +5,10 @@
package space.kscience.kmath.estree
-import space.kscience.kmath.ast.mstInRing
+import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.operations.ByteRing
+import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@@ -15,13 +16,13 @@ import kotlin.test.assertFailsWith
internal class TestESTreeVariables {
@Test
fun testVariable() {
- val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
+ val expr = MstRing{ bindSymbol("x") }.compileToExpression(ByteRing)
assertEquals(1.toByte(), expr("x" to 1.toByte()))
}
@Test
fun testUndefinedVariableFails() {
- val expr = ByteRing.mstInRing { bindSymbol("x") }.compile()
+ val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
assertFailsWith { expr() }
}
}
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt
index d2a6505a0..dbce893d1 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt
+++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt
@@ -7,10 +7,11 @@ package space.kscience.kmath.asm
import space.kscience.kmath.asm.internal.AsmBuilder
import space.kscience.kmath.asm.internal.buildName
-import space.kscience.kmath.ast.MST
-import space.kscience.kmath.ast.MST.*
-import space.kscience.kmath.ast.MstExpression
import space.kscience.kmath.expressions.Expression
+import space.kscience.kmath.expressions.MST
+import space.kscience.kmath.expressions.MST.*
+import space.kscience.kmath.expressions.invoke
+import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra
@@ -26,11 +27,7 @@ import space.kscience.kmath.operations.NumericAlgebra
internal fun MST.compileWith(type: Class