Merge dev

This commit is contained in:
Roland Grinis 2021-04-21 17:04:09 +01:00
commit 76b5cd0de5
333 changed files with 7527 additions and 2302 deletions

5
.gitignore vendored
View File

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

View File

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright 2018-2021 KMath contributors.&#10;Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file." />
<option name="myName" value="kmath" />
</copyright>
</component>

View File

@ -0,0 +1,21 @@
<component name="CopyrightManager">
<settings default="kmath">
<module2copyright>
<element module="Apply copyright" copyright="kmath" />
</module2copyright>
<LanguageOptions name="Groovy">
<option name="fileTypeOverride" value="1" />
</LanguageOptions>
<LanguageOptions name="HTML">
<option name="fileTypeOverride" value="1" />
<option name="prefixLines" value="false" />
</LanguageOptions>
<LanguageOptions name="Properties">
<option name="fileTypeOverride" value="1" />
</LanguageOptions>
<LanguageOptions name="XML">
<option name="fileTypeOverride" value="1" />
<option name="prefixLines" value="false" />
</LanguageOptions>
</settings>
</component>

View File

@ -0,0 +1,4 @@
<component name="DependencyValidationManager">
<scope name="Apply copyright"
pattern="!file[*]:*//testData//*&amp;&amp;!file[*]:testData//*&amp;&amp;!file[*]:*.gradle.kts&amp;&amp;!file[*]:*.gradle&amp;&amp;!file[group:kotlin-ultimate]:*/&amp;&amp;!file[kotlin.libraries]:stdlib/api//*"/>
</component>

View File

@ -7,6 +7,10 @@
- Basic integration API
- Basic MPP distributions and samplers
- bindSymbolOrNull
- Blocking chains and Statistics
- Multiplatform integration
- Integration for any Field element
- Extendend operations for ND4J fields
### Changed
- Exponential operations merged with hyperbolic functions
@ -18,6 +22,8 @@
- DataSets are moved from functions to core
- Redesign advanced Chain API
- Redesign MST. Remove MSTExpression.
- Move MST to core
- Separated benchmarks and examples
### Deprecated
@ -28,6 +34,7 @@
- MSTExpression
### Fixed
- Ring inherits RingOperations, not GroupOperations
### Security

View File

@ -11,6 +11,8 @@ Python's NumPy library. Later we found that kotlin is much more flexible languag
designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could
be achieved with [kmath-for-real](/kmath-for-real) extension module.
[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/)
## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
@ -74,6 +76,12 @@ KMath is a modular library. Different modules provide different features with di
<hr/>
* ### [benchmarks](benchmarks)
>
>
> **Maturity**: EXPERIMENTAL
<hr/>
* ### [examples](examples)
>
>
@ -86,12 +94,10 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: PROTOTYPE
>
> **Features:**
> - [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
> - [expression-language](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
> - [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
> - [rendering](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering
<hr/>
@ -169,15 +175,16 @@ One can still use generic algebras though.
<hr/>
* ### [kmath-functions](kmath-functions)
> Functions and interpolation
> Functions, integration and interpolation
>
> **Maturity**: PROTOTYPE
> **Maturity**: EXPERIMENTAL
>
> **Features:**
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt
> - [piecewise](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt) : Piecewise functions.
> - [polynomials](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Polynomial functions.
> - [linear interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt) : Linear XY interpolator.
> - [spline interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator.
> - [integration](kmath-functions/#) : Univariate and multivariate quadratures
<hr/>
@ -248,6 +255,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
@ -259,8 +270,8 @@ repositories {
}
dependencies {
api("space.kscience:kmath-core:0.3.0-dev-4")
// api("kscience.kmath:kmath-core-jvm:0.3.0-dev-4") for jvm-specific version
api("space.kscience:kmath-core:0.3.0-dev-7")
// api("space.kscience:kmath-core-jvm:0.3.0-dev-7") for jvm-specific version
}
```

130
benchmarks/build.gradle.kts Normal file
View File

@ -0,0 +1,130 @@
plugins {
kotlin("multiplatform")
kotlin("plugin.allopen")
id("org.jetbrains.kotlinx.benchmark")
}
allOpen.annotation("org.openjdk.jmh.annotations.State")
sourceSets.register("benchmarks")
repositories {
mavenCentral()
jcenter()
maven("https://repo.kotlin.link")
maven("https://clojars.org/repo")
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
maven("https://dl.bintray.com/hotkeytlt/maven")
maven("https://jitpack.io")
maven {
setUrl("http://logicrunch.research.it.uu.se/maven/")
isAllowInsecureProtocol = true
}
}
kotlin {
jvm()
sourceSets {
val commonMain by getting {
dependencies {
implementation(project(":kmath-ast"))
implementation(project(":kmath-core"))
implementation(project(":kmath-coroutines"))
implementation(project(":kmath-complex"))
implementation(project(":kmath-stat"))
implementation(project(":kmath-dimensions"))
implementation(project(":kmath-for-real"))
implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.0")
}
}
val jvmMain by getting {
dependencies {
implementation(project(":kmath-commons"))
implementation(project(":kmath-ejml"))
implementation(project(":kmath-nd4j"))
implementation(project(":kmath-kotlingrad"))
implementation(project(":kmath-viktor"))
implementation("org.nd4j:nd4j-native:1.0.0-beta7")
// uncomment if your system supports AVX2
// val os = System.getProperty("os.name")
//
// if (System.getProperty("os.arch") in arrayOf("x86_64", "amd64")) when {
// os.startsWith("Windows") -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:windows-x86_64-avx2")
// os == "Linux" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:linux-x86_64-avx2")
// os == "Mac OS X" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:macosx-x86_64-avx2")
// } else
// implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
}
}
}
}
// Configure benchmark
benchmark {
// Setup configurations
targets {
register("jvm")
}
fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() {
warmups = 1
iterations = 5
iterationTime = 1000
iterationTimeUnit = "ms"
}
configurations.register("buffer") {
commonConfiguration()
include("BufferBenchmark")
}
configurations.register("dot") {
commonConfiguration()
include("DotBenchmark")
}
configurations.register("expressions") {
commonConfiguration()
include("ExpressionsInterpretersBenchmark")
}
configurations.register("matrixInverse") {
commonConfiguration()
include("MatrixInverseBenchmark")
}
configurations.register("bigInt") {
commonConfiguration()
include("BigIntBenchmark")
}
}
// Fix kotlinx-benchmarks bug
afterEvaluate {
val jvmBenchmarkJar by tasks.getting(org.gradle.jvm.tasks.Jar::class) {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
kotlin.sourceSets.all {
with(languageSettings) {
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
}
}
readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -1,3 +1,8 @@
/*
* 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.Benchmark

View File

@ -0,0 +1,68 @@
/*
* 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.BigInt
import space.kscience.kmath.operations.BigIntField
import space.kscience.kmath.operations.JBigIntegerField
import space.kscience.kmath.operations.invoke
private fun BigInt.pow(power: Int): BigInt = modPow(BigIntField.number(power), BigInt.ZERO)
@State(Scope.Benchmark)
internal class BigIntBenchmark {
val kmNumber = BigIntField.number(Int.MAX_VALUE)
val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE)
val largeKmNumber = BigIntField { number(11).pow(100_000) }
val largeJvmNumber = JBigIntegerField { number(11).pow(100_000) }
val bigExponent = 50_000
@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 kmMultiplyLarge(blackhole: Blackhole) = BigIntField {
blackhole.consume(largeKmNumber*largeKmNumber)
}
@Benchmark
fun jvmMultiply(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume(jvmNumber * jvmNumber * jvmNumber)
}
@Benchmark
fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerField {
blackhole.consume(largeJvmNumber*largeJvmNumber)
}
// @Benchmark
// fun kmPower(blackhole: Blackhole) = BigIntField {
// blackhole.consume(kmNumber.pow(bigExponent))
// }
//
// @Benchmark
// fun jvmPower(blackhole: Blackhole) = JBigIntegerField {
// blackhole.consume(jvmNumber.pow(bigExponent))
// }
}

View File

@ -1,3 +1,8 @@
/*
* 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.Benchmark

View File

@ -1,3 +1,8 @@
/*
* 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.Benchmark

View File

@ -0,0 +1,66 @@
/*
* 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.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.Symbol
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)
internal class ExpressionsInterpretersBenchmark {
@Benchmark
fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, blackhole)
@Benchmark
fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, blackhole)
@Benchmark
fun asmExpression(blackhole: Blackhole) = invokeAndSum(asm, blackhole)
@Benchmark
fun rawExpression(blackhole: Blackhole) = invokeAndSum(raw, blackhole)
private fun invokeAndSum(expr: Expression<Double>, blackhole: Blackhole) {
val random = Random(0)
var sum = 0.0
repeat(times) {
sum += expr(x to random.nextDouble())
}
blackhole.consume(sum)
}
private companion object {
private val x: Symbol by symbol
private val algebra: DoubleField = DoubleField
private const val times = 1_000_000
private val functional: Expression<Double> = DoubleField.expressionInExtendedField {
bindSymbol(x) * number(2.0) + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x))
}
private val node = MstExtendedField {
bindSymbol(x) * 2.0 + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x))
}
private val mst: Expression<Double> = node.toExpression(DoubleField)
private val asm: Expression<Double> = node.compileToExpression(DoubleField)
private val raw: Expression<Double> = Expression { args ->
args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 / kotlin.math.sin(args.getValue(x))
}
}
}

View File

@ -1,3 +1,8 @@
/*
* 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.Benchmark

View File

@ -1,3 +1,8 @@
/*
* 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.Benchmark

View File

@ -1,3 +1,8 @@
/*
* 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.Benchmark

View File

@ -1,3 +1,8 @@
/*
* 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.Benchmark

View File

@ -1,7 +1,3 @@
import org.jetbrains.dokka.gradle.DokkaTask
import ru.mipt.npm.gradle.KSciencePublishingPlugin
import java.net.URL
plugins {
id("ru.mipt.npm.gradle.project")
}
@ -13,19 +9,21 @@ allprojects {
maven("https://dl.bintray.com/egor-bogomolov/astminer/")
maven("https://dl.bintray.com/hotkeytlt/maven")
maven("https://jitpack.io")
maven("http://logicrunch.research.it.uu.se/maven/")
maven("http://logicrunch.research.it.uu.se/maven/") {
isAllowInsecureProtocol = true
}
mavenCentral()
}
group = "space.kscience"
version = "0.3.0-dev-5"
version = "0.3.0-dev-7"
}
subprojects {
if (name.startsWith("kmath")) apply<KSciencePublishingPlugin>()
if (name.startsWith("kmath")) apply<MavenPublishPlugin>()
afterEvaluate {
tasks.withType<DokkaTask> {
tasks.withType<org.jetbrains.dokka.gradle.DokkaTask> {
dokkaSourceSets.all {
val readmeFile = File(this@subprojects.projectDir, "./README.md")
if (readmeFile.exists())
@ -35,7 +33,7 @@ subprojects {
"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) ->
).map { java.net.URL("${it}package-list") to java.net.URL(it) }.forEach { (a, b) ->
externalDocumentationLink {
packageListUrl.set(a)
url.set(b)

View File

@ -11,6 +11,8 @@ Python's NumPy library. Later we found that kotlin is much more flexible languag
designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could
be achieved with [kmath-for-real](/kmath-for-real) extension module.
[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/)
## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
@ -92,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
@ -104,7 +110,7 @@ repositories {
dependencies {
api("${group}:kmath-core:$version")
// api("kscience.kmath:kmath-core-jvm:$version") for jvm-specific version
// api("${group}:kmath-core-jvm:$version") for jvm-specific version
}
```

View File

@ -1,27 +1,19 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
kotlin("plugin.allopen")
id("kotlinx.benchmark")
}
allOpen.annotation("org.openjdk.jmh.annotations.State")
sourceSets.register("benchmarks")
repositories {
mavenCentral()
jcenter()
maven("https://repo.kotlin.link")
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/")
mavenCentral()
maven{
setUrl("http://logicrunch.research.it.uu.se/maven/")
isAllowInsecureProtocol = true
}
}
dependencies {
@ -39,7 +31,6 @@ dependencies {
implementation(project(":kmath-for-real"))
implementation("org.deeplearning4j:deeplearning4j-core:1.0.0-beta7")
implementation("org.nd4j:nd4j-native:1.0.0-beta7")
// uncomment if your system supports AVX2
@ -52,54 +43,9 @@ dependencies {
// } else
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.slf4j:slf4j-simple:1.7.30")
// plotting
implementation("kscience.plotlykt:plotlykt-server:0.3.1-dev")
"benchmarksImplementation"("org.jetbrains.kotlinx:kotlinx.benchmark.runtime-jvm:0.2.0-dev-20")
"benchmarksImplementation"(sourceSets.main.get().output + sourceSets.main.get().runtimeClasspath)
}
// Configure benchmark
benchmark {
// Setup configurations
targets.register("benchmarks")
// This one matches sourceSet name above
configurations.register("buffer") {
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("BufferBenchmark")
}
configurations.register("dot") {
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("DotBenchmark")
}
configurations.register("expressions") {
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("ExpressionsInterpretersBenchmark")
}
configurations.register("matrixInverse") {
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("MatrixInverseBenchmark")
}
implementation("space.kscience:plotlykt-server:0.4.0-dev-2")
}
kotlin.sourceSets.all {
@ -110,8 +56,11 @@ kotlin.sourceSets.all {
}
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions{
jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
}
}
readme {

View File

@ -1,76 +0,0 @@
package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.ast.MstField
import space.kscience.kmath.ast.toExpression
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.expressionInField
import space.kscience.kmath.expressions.invoke
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)
internal class ExpressionsInterpretersBenchmark {
@Benchmark
fun functionalExpression(blackhole: Blackhole) {
val expr = algebra.expressionInField {
val x = bindSymbol(x)
x * const(2.0) + const(2.0) / x - const(16.0)
}
invokeAndSum(expr, blackhole)
}
@Benchmark
fun mstExpression(blackhole: Blackhole) {
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 = MstField {
val x = bindSymbol(x)
x * 2.0 + number(2.0) / x - 16.0
}.compileToExpression(algebra)
invokeAndSum(expr, blackhole)
}
@Benchmark
fun rawExpression(blackhole: Blackhole) {
val expr = Expression<Double> { args ->
val x = args.getValue(x)
x * 2.0 + 2.0 / x - 16.0
}
invokeAndSum(expr, blackhole)
}
private fun invokeAndSum(expr: Expression<Double>, blackhole: Blackhole) {
val random = Random(0)
var sum = 0.0
repeat(1000000) {
sum += expr(x to random.nextDouble())
}
blackhole.consume(sum)
}
private companion object {
private val algebra = DoubleField
private val x by symbol
}
}

View File

@ -1,3 +1,8 @@
/*
* 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

View File

@ -1,5 +1,12 @@
/*
* 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.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

View File

@ -1,3 +1,8 @@
/*
* 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.asm.compileToExpression
@ -20,5 +25,5 @@ fun main() {
val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField)
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
assert(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0))
}

View File

@ -1,10 +1,12 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.commons.fit
import kotlinx.html.br
import kotlinx.html.h3
import kscience.plotly.*
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.distributions.NormalDistribution
@ -17,6 +19,9 @@ import space.kscience.kmath.real.step
import space.kscience.kmath.stat.RandomGenerator
import space.kscience.kmath.structures.asIterable
import space.kscience.kmath.structures.toList
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.models.TraceValues
import kotlin.math.pow
import kotlin.math.sqrt

View File

@ -0,0 +1,22 @@
/*
* 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.functions
import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.value
import space.kscience.kmath.operations.DoubleField
import kotlin.math.pow
fun main() {
//Define a function
val function: UnivariateFunction<Double> = { x -> 3 * x.pow(2) + 2 * x + 1 }
//get the result of the integration
val result = DoubleField.integrate(0.0..10.0, function = function)
//the value is nullable because in some cases the integration could not succeed
println(result.value)
}

View File

@ -0,0 +1,32 @@
/*
* 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.functions
import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.value
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.nd
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
fun main(): Unit = DoubleField {
nd(2, 2) {
//Produce a diagonal StructureND
fun diagonal(v: Double) = produce { (i, j) ->
if (i == j) v else 0.0
}
//Define a function in a nd space
val function: (Double) -> StructureND<Double> = { x: Double -> 3 * number(x).pow(2) + 2 * diagonal(x) + 1 }
//get the result of the integration
val result = integrate(0.0..10.0, function = function)
//the value is nullable because in some cases the integration could not succeed
println(result.value)
}
}

View File

@ -1,3 +1,8 @@
/*
* 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.linear
import space.kscience.kmath.real.*
@ -17,8 +22,8 @@ fun main() {
return DoubleBuffer(x.size) { i ->
val h = sigma[i] / 5
val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
val f1 = invoke(x + dVector / 2)
val f0 = invoke(x - dVector / 2)
val f1 = this(x + dVector / 2)
val f0 = this(x - dVector / 2)
(f1 - f0) / h
}
}

View File

@ -1,3 +1,8 @@
/*
* 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.operations
fun main() {

View File

@ -1,3 +1,8 @@
/*
* 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.operations
import space.kscience.kmath.complex.Complex

View File

@ -1,14 +1,19 @@
/*
* 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.stat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.apache.commons.rng.sampling.distribution.BoxMullerNormalizedGaussianSampler
import org.apache.commons.rng.simple.RandomSource
import space.kscience.kmath.samplers.GaussianSampler
import java.time.Duration
import java.time.Instant
import org.apache.commons.rng.sampling.distribution.GaussianSampler as CMGaussianSampler
import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler as CMZigguratNormalizedGaussianSampler
private suspend fun runKMathChained(): Duration {
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
@ -34,7 +39,7 @@ private fun runApacheDirect(): Duration {
val rng = RandomSource.create(RandomSource.MT, 123L)
val sampler = CMGaussianSampler.of(
CMZigguratNormalizedGaussianSampler.of(rng),
BoxMullerNormalizedGaussianSampler.of(rng),
7.0,
2.0
)
@ -59,8 +64,8 @@ private fun runApacheDirect(): Duration {
* Comparing chain sampling performance with direct sampling performance
*/
fun main(): Unit = runBlocking(Dispatchers.Default) {
val chainJob = async { runKMathChained() }
val directJob = async { runApacheDirect() }
val chainJob = async { runKMathChained() }
println("KMath Chained: ${chainJob.await()}")
println("Apache Direct: ${directJob.await()}")
}

View File

@ -1,3 +1,8 @@
/*
* 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.stat
import kotlinx.coroutines.runBlocking

View File

@ -1,3 +1,8 @@
/*
* 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.
*/
@file:Suppress("unused")
package space.kscience.kmath.structures

View File

@ -1,3 +1,8 @@
/*
* 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 kotlinx.coroutines.GlobalScope

View File

@ -1,3 +1,8 @@
/*
* 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.*

View File

@ -1,3 +1,8 @@
/*
* 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.BufferND

View File

@ -1,3 +1,8 @@
/*
* 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.StructureND

View File

@ -1,3 +1,8 @@
/*
* 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.dimensions.D2

View File

@ -1,8 +1,13 @@
#
# 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.
#
kotlin.code.style=official
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.mpp.stability.nowarn=true
kotlin.native.enableDependencyPropagation=false
kotlin.parallel.tasks.in.project=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=9G
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
org.gradle.parallel=true

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -2,17 +2,15 @@
Abstract syntax tree expression representation and related optimizations.
- [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
- [expression-language](src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
- [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
- [rendering](src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering
## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-4`.
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-7`.
**Gradle:**
```gradle
@ -23,7 +21,7 @@ repositories {
}
dependencies {
implementation 'space.kscience:kmath-ast:0.3.0-dev-4'
implementation 'space.kscience:kmath-ast:0.3.0-dev-7'
}
```
**Gradle Kotlin DSL:**
@ -35,7 +33,7 @@ repositories {
}
dependencies {
implementation("space.kscience:kmath-ast:0.3.0-dev-4")
implementation("space.kscience:kmath-ast:0.3.0-dev-7")
}
```
@ -49,7 +47,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder:
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
… leads to generation of bytecode, which can be decompiled to the following Java class:
@ -77,15 +75,6 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
```
### Example Usage
This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
DoubleField.expression("x+2".parseMath())
```
#### Known issues
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
@ -97,7 +86,7 @@ DoubleField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
The code above returns expression implemented with such a JS function:
@ -108,13 +97,32 @@ var executable = function (constants, arguments) {
};
```
```kotlin
import space.kscience.kmath.wasm.*
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
An example of emitted WASM IR in the form of WAT:
```lisp
(func $executable (param $0 f64) (result f64)
(f64.add
(local.get $0)
(f64.const 2)
)
)
```
#### Known issues
- This feature uses `eval` which can be unavailable in several environments.
- ESTree expression compilation uses `eval` which can be unavailable in several environments.
- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).
## Rendering expressions
kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
Example usage:
@ -135,7 +143,7 @@ public fun main() {
}
```
Result LaTeX:
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)
@ -145,5 +153,5 @@ Result MathML (embedding MathML is not allowed by GitHub Markdown):
<mrow><msup><mrow><mi>e</mi></mrow><mrow><msqrt><mi>x</mi></msqrt></mrow></msup><mo>-</mo><mfrac><mrow><mfrac><mrow><msup><mrow><mo>sin</mo></mrow><mrow><mo>-</mo><mn>1</mn></mrow></msup><mspace width="0.167em"></mspace><mfenced open="(" close=")" separators=""><mn>2</mn><mspace width="0.167em"></mspace><mi>x</mi></mfenced></mrow><mrow><mn>2</mn><mo>&times;</mo><msup><mrow><mn>10</mn></mrow><mrow><mn>10</mn></mrow></msup><mo>+</mo><msup><mrow><mi>x</mi></mrow><mrow><mn>3</mn></mrow></msup></mrow></mfrac></mrow><mrow><mo>-</mo><mn>12</mn></mrow></mfrac></mrow>
```
It is also possible to create custom algorithms of render, and even add support of other markup languages
It is also possible to create custom algorithms of render, and even add support of other markup languages
(see API reference).

View File

@ -1,7 +1,6 @@
import ru.mipt.npm.gradle.Maturity
plugins {
id("ru.mipt.npm.gradle.mpp")
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
}
kotlin.js {
@ -21,6 +20,7 @@ kotlin.js {
kotlin.sourceSets {
commonMain {
dependencies {
api("com.github.h0tk3y.betterParse:better-parse:0.4.2")
api(project(":kmath-core"))
}
}
@ -33,13 +33,15 @@ kotlin.sourceSets {
jsMain {
dependencies {
implementation(npm("astring", "1.7.0"))
implementation(npm("astring", "1.7.4"))
implementation(npm("binaryen", "100.0"))
implementation(npm("js-base64", "3.6.0"))
implementation(npm("webassembly", "0.11.0"))
}
}
jvmMain {
dependencies {
api("com.github.h0tk3y.betterParse:better-parse:0.4.1")
implementation("org.ow2.asm:asm:9.1")
implementation("org.ow2.asm:asm-commons:9.1")
}
@ -52,31 +54,13 @@ tasks.dokkaHtml {
}
readme {
maturity = Maturity.PROTOTYPE
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(
id = "expression-language",
description = "Expression language and its parser",
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/space/kscience/kmath/ast/MST.kt"
)
feature(
id = "mst-building",
description = "MST building algebraic structure",
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt"
)
feature(
id = "mst-interpreter",
description = "MST interpreter",
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt"
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt"
)
feature(
@ -90,4 +74,10 @@ readme {
description = "Dynamic MST to JS compiler",
ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt"
)
feature(
id = "rendering",
description = "Extendable MST rendering",
ref = "src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt"
)
}

View File

@ -16,7 +16,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder:
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
… leads to generation of bytecode, which can be decompiled to the following Java class:
@ -44,15 +44,6 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
```
### Example Usage
This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
DoubleField.expression("x+2".parseMath())
```
#### Known issues
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
@ -64,7 +55,7 @@ DoubleField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
The code above returns expression implemented with such a JS function:
@ -75,13 +66,32 @@ var executable = function (constants, arguments) {
};
```
```kotlin
import space.kscience.kmath.wasm.*
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
An example of emitted WASM IR in the form of WAT:
```lisp
(func \$executable (param \$0 f64) (result f64)
(f64.add
(local.get \$0)
(f64.const 2)
)
)
```
#### Known issues
- This feature uses `eval` which can be unavailable in several environments.
- ESTree expression compilation uses `eval` which can be unavailable in several environments.
- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).
## Rendering expressions
kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
Example usage:
@ -102,7 +112,7 @@ public fun main() {
}
```
Result LaTeX:
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)
@ -112,5 +122,5 @@ Result MathML (embedding MathML is not allowed by GitHub Markdown):
<mrow><msup><mrow><mi>e</mi></mrow><mrow><msqrt><mi>x</mi></msqrt></mrow></msup><mo>-</mo><mfrac><mrow><mfrac><mrow><msup><mrow><mo>sin</mo></mrow><mrow><mo>-</mo><mn>1</mn></mrow></msup><mspace width="0.167em"></mspace><mfenced open="(" close=")" separators=""><mn>2</mn><mspace width="0.167em"></mspace><mi>x</mi></mfenced></mrow><mrow><mn>2</mn><mo>&times;</mo><msup><mrow><mn>10</mn></mrow><mrow><mn>10</mn></mrow></msup><mo>+</mo><msup><mrow><mi>x</mi></mrow><mrow><mn>3</mn></mrow></msup></mrow></mfrac></mrow><mrow><mo>-</mo><mn>12</mn></mrow></mfrac></mrow>
```
It is also possible to create custom algorithms of render, and even add support of other markup languages
It is also possible to create custom algorithms of render, and even add support of other markup languages
(see API reference).

View File

@ -1,4 +1,7 @@
// TODO move to common when https://github.com/h0tk3y/better-parse/pull/37 is merged
/*
* 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
@ -13,6 +16,7 @@ import com.github.h0tk3y.betterParse.lexer.literalToken
import com.github.h0tk3y.betterParse.lexer.regexToken
import com.github.h0tk3y.betterParse.parser.ParseResult
import com.github.h0tk3y.betterParse.parser.Parser
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.FieldOperations
import space.kscience.kmath.operations.GroupOperations
import space.kscience.kmath.operations.PowerOperations

View File

@ -1,3 +1,8 @@
/*
* 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
/**
@ -66,6 +71,15 @@ public object LatexSyntaxRenderer : SyntaxRenderer {
append('}')
}
is ExponentSyntax -> if (node.useOperatorForm) {
append("\\operatorname{exp}\\,")
render(node.operand)
} else {
append("e^{")
render(node.operand)
append('}')
}
is SuperscriptSyntax -> {
render(node.left)
append("^{")

View File

@ -1,3 +1,8 @@
/*
* 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
/**
@ -77,6 +82,19 @@ public object MathMLSyntaxRenderer : SyntaxRenderer {
is RadicalSyntax -> tag("msqrt") { render(node.operand) }
is ExponentSyntax -> if (node.useOperatorForm) {
tag("mo") { append("exp") }
tag("mspace", "width" to "0.167em")
render(node.operand)
} else {
tag("msup") {
tag("mrow") {
tag("mi") { append("e") }
}
tag("mrow") { render(node.operand) }
}
}
is SuperscriptSyntax -> tag("msup") {
tag("mrow") { render(node.left) }
tag("mrow") { render(node.right) }

View File

@ -1,6 +1,11 @@
/*
* 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.MST
import space.kscience.kmath.expressions.MST
/**
* Renders [MST] to [MathSyntax].
@ -78,7 +83,7 @@ public open class FeaturedMathRendererWithPostProcess(
Fraction.Default,
Power.Default,
SquareRoot.Default,
Exponential.Default,
Exponent.Default,
InverseTrigonometricOperations.Default,
// Fallback option for unknown operations - printing them as operator
@ -95,6 +100,7 @@ public open class FeaturedMathRendererWithPostProcess(
PrintSymbolic,
),
listOf(
BetterExponent,
SimplifyParentheses.Default,
BetterMultiplication,
),

View File

@ -1,3 +1,8 @@
/*
* 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
/**
@ -184,6 +189,24 @@ public data class RadicalSyntax(
}
}
/**
* Represents exponential function.
*
* @property operand The argument of function.
* @property useOperatorForm `true` if operator form is used (*exp (x)*), `false` if exponentiation form is used
* (*e<sup>x</sup>*).
* @author Iaroslav Postovalov
*/
public data class ExponentSyntax(
public override val operation: String,
public override val operand: OperandSyntax,
public var useOperatorForm: Boolean,
) : UnarySyntax() {
init {
operand.parent = this
}
}
/**
* Represents a syntax node with superscript (usually, for exponentiation).
*

View File

@ -1,3 +1,8 @@
/*
* 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
/**

View File

@ -1,7 +1,12 @@
/*
* 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.MST
import space.kscience.kmath.ast.rendering.FeaturedMathRenderer.RenderFeature
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.*
import kotlin.reflect.KClass
@ -51,10 +56,14 @@ private fun printSignedNumberString(s: String): MathSyntax {
public class PrettyPrintFloats(public val types: Set<KClass<out Number>>) : RenderFeature {
public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
if (node !is MST.Numeric || node.value::class !in types) return null
val toString = node.value.toString().removeSuffix(".0")
val toString = when (val v = node.value) {
is Float -> v.multiplatformToString()
is Double -> v.multiplatformToString()
else -> v.toString()
}.removeSuffix(".0")
if ('E' in toString) {
val (beforeE, afterE) = toString.split('E')
if (toString.contains('E', ignoreCase = true)) {
val (beforeE, afterE) = toString.split('E', ignoreCase = true)
val significand = beforeE.toDouble().toString().removeSuffix(".0")
val exponent = afterE.toDouble().toString().removeSuffix(".0")
@ -103,9 +112,7 @@ public class PrettyPrintFloats(public val types: Set<KClass<out Number>>) : Rend
*/
public class PrettyPrintIntegers(public val types: Set<KClass<out Number>>) : RenderFeature {
public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
if (node !is MST.Numeric || node.value::class !in types)
return null
if (node !is MST.Numeric || node.value::class !in types) return null
return printSignedNumberString(node.value.toString())
}
@ -277,15 +284,15 @@ public class SquareRoot(operations: Collection<String>?) : Unary(operations) {
}
}
public class Exponential(operations: Collection<String>?) : Unary(operations) {
public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = SuperscriptSyntax(
public class Exponent(operations: Collection<String>?) : Unary(operations) {
public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = ExponentSyntax(
operation = node.operation,
left = SymbolSyntax(string = "e"),
right = parent.render(node.value),
operand = OperandSyntax(operand = parent.render(node.value), parentheses = true),
useOperatorForm = true,
)
public companion object {
public val Default: Exponential = Exponential(setOf(ExponentialOperations.EXP_OPERATION))
public val Default: Exponent = Exponent(setOf(ExponentialOperations.EXP_OPERATION))
}
}

View File

@ -0,0 +1,9 @@
/*
* 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
internal expect fun Double.multiplatformToString(): String
internal expect fun Float.multiplatformToString(): String

View File

@ -1,3 +1,8 @@
/*
* 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
@ -11,69 +16,110 @@ import space.kscience.kmath.operations.RingOperations
* @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)
public override fun perform(node: MathSyntax): Unit = 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)
}
is UnaryOperatorSyntax -> {
perform(node.prefix)
perform(node.operand)
}
is UnaryPlusSyntax -> perform(node.operand)
is UnaryMinusSyntax -> perform(node.operand)
is RadicalSyntax -> perform(node.operand)
is ExponentSyntax -> 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)
}
}
}
/**
* Applies [ExponentSyntax.useOperatorForm] to [ExponentSyntax] when the operand contains a fraction, a
* superscript or a subscript to improve readability.
*
* @author Iaroslav Postovalov
*/
public object BetterExponent : FeaturedMathRendererWithPostProcess.PostProcessStage {
private fun perform0(node: MathSyntax): Boolean {
return when (node) {
is NumberSyntax -> false
is SymbolSyntax -> false
is OperatorNameSyntax -> false
is SpecialSymbolSyntax -> false
is OperandSyntax -> perform0(node.operand)
is UnaryOperatorSyntax -> perform0(node.prefix) || perform0(node.operand)
is UnaryPlusSyntax -> perform0(node.operand)
is UnaryMinusSyntax -> perform0(node.operand)
is RadicalSyntax -> perform0(node.operand)
is ExponentSyntax -> {
val r = perform0(node.operand)
node.useOperatorForm = r
r
}
is SuperscriptSyntax -> true
is SubscriptSyntax -> true
is BinaryOperatorSyntax -> perform0(node.prefix) || perform0(node.left) || perform0(node.right)
is BinaryPlusSyntax -> perform0(node.left) || perform0(node.right)
is BinaryMinusSyntax -> perform0(node.left) || perform0(node.right)
is FractionSyntax -> true
is RadicalWithIndexSyntax -> perform0(node.left) || perform0(node.right)
is MultiplicationSyntax -> perform0(node.left) || perform0(node.right)
}
}
public override fun perform(node: MathSyntax) {
perform0(node)
}
}
@ -85,89 +131,89 @@ public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostPro
*/
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
public override fun perform(node: MathSyntax): Unit = 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
is OperandSyntax -> {
val isRightOfSuperscript =
(node.parent is SuperscriptSyntax) && (node.parent as SuperscriptSyntax).right === node
val precedence = precedenceFunction(node.operand)
val precedence = precedenceFunction(node.operand)
val needParenthesesByPrecedence = when (val parent = node.parent) {
null -> false
val needParenthesesByPrecedence = when (val parent = node.parent) {
null -> false
is BinarySyntax -> {
val parentPrecedence = precedenceFunction(parent)
is BinarySyntax -> {
val parentPrecedence = precedenceFunction(parent)
parentPrecedence < precedence ||
parentPrecedence == precedence && parentPrecedence != 0 && node === parent.right
}
else -> precedence > precedenceFunction(parent)
parentPrecedence < precedence ||
parentPrecedence == precedence && parentPrecedence != 0 && node === parent.right
}
node.parentheses = !isRightOfSuperscript
&& (needParenthesesByPrecedence || node.parent is UnaryOperatorSyntax)
perform(node.operand)
else -> precedence > precedenceFunction(parent)
}
is UnaryOperatorSyntax -> {
perform(node.prefix)
perform(node.operand)
}
val isInsideExpOperator =
node.parent is ExponentSyntax && (node.parent as ExponentSyntax).useOperatorForm
is UnaryPlusSyntax -> perform(node.operand)
is UnaryMinusSyntax -> {
perform(node.operand)
}
is RadicalSyntax -> perform(node.operand)
node.parentheses = !isRightOfSuperscript
&& (needParenthesesByPrecedence || node.parent is UnaryOperatorSyntax || isInsideExpOperator)
is SuperscriptSyntax -> {
perform(node.left)
perform(node.right)
}
perform(node.operand)
}
is SubscriptSyntax -> {
perform(node.left)
perform(node.right)
}
is UnaryOperatorSyntax -> {
perform(node.prefix)
perform(node.operand)
}
is BinaryOperatorSyntax -> {
perform(node.prefix)
perform(node.left)
perform(node.right)
}
is UnaryPlusSyntax -> perform(node.operand)
is UnaryMinusSyntax -> perform(node.operand)
is RadicalSyntax -> perform(node.operand)
is ExponentSyntax -> perform(node.operand)
is BinaryPlusSyntax -> {
perform(node.left)
perform(node.right)
}
is SuperscriptSyntax -> {
perform(node.left)
perform(node.right)
}
is BinaryMinusSyntax -> {
perform(node.left)
perform(node.right)
}
is SubscriptSyntax -> {
perform(node.left)
perform(node.right)
}
is FractionSyntax -> {
perform(node.left)
perform(node.right)
}
is BinaryOperatorSyntax -> {
perform(node.prefix)
perform(node.left)
perform(node.right)
}
is MultiplicationSyntax -> {
perform(node.left)
perform(node.right)
}
is BinaryPlusSyntax -> {
perform(node.left)
perform(node.right)
}
is RadicalWithIndexSyntax -> {
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)
}
}

View File

@ -1,13 +1,17 @@
/*
* 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.parseMath
import space.kscience.kmath.expressions.evaluate
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.Field
import kotlin.test.Test
import kotlin.test.assertEquals
internal class ParserPrecedenceTest {
private val f: Field<Double> = DoubleField
@Test
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
@ -31,4 +35,8 @@ internal class ParserPrecedenceTest {
@Test
fun test8(): Unit = assertEquals(18.0, f.evaluate("2*2^3+2".parseMath()))
private companion object {
private val f = DoubleField
}
}

View File

@ -1,29 +1,28 @@
/*
* 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.complex.Complex
import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.expressions.evaluate
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class ParserTest {
@Test
fun `evaluate MST`() {
fun evaluateParsedMst() {
val mst = "2+2*(2+2)".parseMath()
val res = ComplexField.evaluate(mst)
assertEquals(Complex(10.0, 0.0), res)
}
@Test
fun `evaluate MSTExpression`() {
val res = MstField.invoke { number(2) + number(2) * (number(2) + number(2)) }.interpret(ComplexField)
assertEquals(Complex(10.0, 0.0), res)
}
@Test
fun `evaluate MST with singular`() {
fun evaluateMstSymbol() {
val mst = "i".parseMath()
val res = ComplexField.evaluate(mst)
assertEquals(ComplexField.i, res)
@ -31,14 +30,14 @@ internal class ParserTest {
@Test
fun `evaluate MST with unary function`() {
fun evaluateMstUnary() {
val mst = "sin(0)".parseMath()
val res = DoubleField.evaluate(mst)
assertEquals(0.0, res)
}
@Test
fun `evaluate MST with binary function`() {
fun evaluateMstBinary() {
val magicalAlgebra = object : Algebra<String> {
override fun bindSymbolOrNull(value: String): String = value

View File

@ -1,7 +1,12 @@
/*
* 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.MST.Numeric
import space.kscience.kmath.ast.rendering.TestUtils.testLatex
import space.kscience.kmath.expressions.MST.Numeric
import kotlin.test.Test
internal class TestFeatures {
@ -37,6 +42,22 @@ internal class TestFeatures {
testLatex(Numeric(1.1e-10), "1.1\\times10^{-10}")
testLatex(Numeric(-1.1e-10), "-1.1\\times10^{-10}")
testLatex(Numeric(-1.1e10), "-1.1\\times10^{10}")
testLatex(Numeric(0.001), "0.001")
testLatex(Numeric(0.0000001), "1\\times10^{-7}")
testLatex(Numeric(Float.NaN), "NaN")
testLatex(Numeric(Float.POSITIVE_INFINITY), "\\infty")
testLatex(Numeric(Float.NEGATIVE_INFINITY), "-\\infty")
testLatex(Numeric(1.0f), "1")
testLatex(Numeric(-1.0f), "-1")
testLatex(Numeric(1.42f), "1.42")
testLatex(Numeric(-1.42f), "-1.42")
testLatex(Numeric(1e10f), "1\\times10^{10}")
testLatex(Numeric(1e-10f), "1\\times10^{-10}")
testLatex(Numeric(-1e-10f), "-1\\times10^{-10}")
testLatex(Numeric(-1e10f), "-1\\times10^{10}")
testLatex(Numeric(0.001f), "0.001")
testLatex(Numeric(0.0000001f), "1\\times10^{-7}")
}
@Test

View File

@ -1,7 +1,12 @@
/*
* 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.MST
import space.kscience.kmath.ast.rendering.TestUtils.testLatex
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.GroupOperations
import kotlin.test.Test

View File

@ -1,7 +1,12 @@
/*
* 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.MST
import space.kscience.kmath.ast.rendering.TestUtils.testMathML
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.GroupOperations
import kotlin.test.Test

View File

@ -1,3 +1,8 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.rendering.TestUtils.testLatex
@ -25,4 +30,11 @@ internal class TestStages {
testLatex("(x+x)^x+x*x", "\\left(x+x\\right)^{x}+x\\,x")
testLatex("x^(x+x)", "x^{x+x}")
}
@Test
fun exponent() {
testLatex("exp(x)", "e^{x}")
testLatex("exp(x/2)", "\\operatorname{exp}\\,\\left(\\frac{x}{2}\\right)")
testLatex("exp(x^2)", "\\operatorname{exp}\\,\\left(x^{2}\\right)")
}
}

View File

@ -1,7 +1,12 @@
/*
* 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.MST
import space.kscience.kmath.ast.parseMath
import space.kscience.kmath.expressions.MST
import kotlin.test.assertEquals
internal object TestUtils {

View File

@ -1,22 +0,0 @@
package space.kscisnce.kmath.ast
import space.kscience.kmath.ast.MstField
import space.kscience.kmath.ast.toExpression
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.Symbol.Companion.x
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
class InterpretTest {
@Test
fun interpretation(){
val expr = MstField {
val x = bindSymbol(x)
x * 2.0 + number(2.0) / x - 16.0
}.toExpression(DoubleField)
expr(x to 2.2)
}
}

View File

@ -0,0 +1,18 @@
/*
* 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
internal actual fun Double.multiplatformToString(): String {
val d = this
if (d >= 1e7 || d <= -1e7) return js("d.toExponential()") as String
return toString()
}
internal actual fun Float.multiplatformToString(): String {
val d = this
if (d >= 1e7f || d <= -1e7f) return js("d.toExponential()") as String
return toString()
}

View File

@ -1,11 +1,16 @@
/*
* 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.estree
import space.kscience.kmath.ast.MST
import space.kscience.kmath.ast.MST.*
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.internal.estree.BaseExpression
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra
@ -26,16 +31,17 @@ internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
is Unary -> when {
algebra is NumericAlgebra && node.value is Numeric -> constant(
algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value)))
algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value))
}
is Binary -> when {
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant(
algebra
.binaryOperationFunction(node.operation)
.invoke(algebra.number(node.left.value), algebra.number(node.right.value))
algebra.binaryOperationFunction(node.operation).invoke(
algebra.number((node.left as Numeric).value),
algebra.number((node.right as Numeric).value)
)
)
algebra is NumericAlgebra && node.left is Numeric -> call(
@ -70,12 +76,12 @@ public fun <T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T>
/**
* Compile given MST to expression and evaluate it against [arguments]
*/
public inline fun <reified T: Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
compileToExpression(algebra).invoke(arguments)
/**
* Compile given MST to expression and evaluate it against [arguments]
*/
public inline fun <reified T: Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol,T>): T =
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T =
compileToExpression(algebra).invoke(*arguments)

View File

@ -1,8 +1,18 @@
/*
* 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.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.internal.astring.generate
import space.kscience.kmath.internal.estree.*
import space.kscience.kmath.internal.estree.BaseExpression
import space.kscience.kmath.internal.estree.BlockStatement
import space.kscience.kmath.internal.estree.Program
import space.kscience.kmath.internal.estree.VariableDeclaration
import space.kscience.kmath.internal.estree.VariableDeclarator
import space.kscience.kmath.misc.Symbol
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {

View File

@ -1,3 +1,8 @@
/*
* 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.estree.internal.astring
internal typealias Generator = Any

View File

@ -1,7 +0,0 @@
package space.kscience.kmath.estree.internal.stream
import space.kscience.kmath.estree.internal.emitter.Emitter
internal open external class Stream : Emitter {
open fun pipe(dest: Any, options: Any): Any
}

View File

@ -1,9 +1,14 @@
/*
* 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.
*/
@file:JsModule("astring")
@file:JsNonModule
package space.kscience.kmath.estree.internal.astring
package space.kscience.kmath.internal.astring
import space.kscience.kmath.estree.internal.estree.BaseNode
import space.kscience.kmath.internal.estree.BaseNode
internal external interface Options {
var indent: String?

View File

@ -0,0 +1,8 @@
/*
* 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.internal.astring
internal typealias Generator = Any

View File

@ -0,0 +1,54 @@
/*
* 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.
*/
@file:Suppress(
"INTERFACE_WITH_SUPERCLASS",
"OVERRIDING_FINAL_MEMBER",
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
"CONFLICTING_OVERLOADS",
"NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING",
"ObjectPropertyName",
"ClassName",
)
@file:JsNonModule
@file:JsModule("js-base64")
package space.kscience.kmath.internal.base64
import org.khronos.webgl.Uint8Array
internal external var version: Any
internal external var VERSION: Any
internal external var btoaPolyfill: (bin: String) -> String
internal external var _btoa: (bin: String) -> String
internal external var fromUint8Array: (u8a: Uint8Array, urlsafe: Boolean) -> String
internal external var utob: (u: String) -> String
internal external var encode: (src: String, urlsafe: Boolean) -> String
internal external var encodeURI: (src: String) -> String
internal external var btou: (b: String) -> String
internal external var atobPolyfill: (asc: String) -> String
internal external var _atob: (asc: String) -> String
internal external var toUint8Array: (a: String) -> Uint8Array
internal external var decode: (src: String) -> String
internal external var isValid: (src: Any) -> Boolean
internal external var extendString: () -> Unit
internal external var extendUint8Array: () -> Unit
internal external var extendBuiltins: () -> Unit

View File

@ -0,0 +1,16 @@
/*
* 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.
*/
@file:Suppress("PackageDirectoryMismatch", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation")
package space.kscience.kmath.internal.binaryen
internal typealias Type = Number
internal typealias ExpressionRef = Number
internal typealias FunctionRef = Number
internal typealias GlobalRef = Number
internal typealias ExportRef = Number
internal typealias EventRef = Number
internal typealias RelooperBlockRef = Number

View File

@ -1,4 +1,9 @@
package space.kscience.kmath.estree.internal.emitter
/*
* 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.internal.emitter
internal open external class Emitter {
constructor(obj: Any)

View File

@ -1,4 +1,9 @@
package space.kscience.kmath.estree.internal.estree
/*
* 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.internal.estree
internal fun Program(sourceType: String, vararg body: dynamic) = object : Program {
override var type = "Program"

View File

@ -1,4 +1,9 @@
package space.kscience.kmath.estree.internal.estree
/*
* 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.internal.estree
import kotlin.js.RegExp

View File

@ -0,0 +1,12 @@
/*
* 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.internal.stream
import space.kscience.kmath.internal.emitter.Emitter
internal open external class Stream : Emitter {
open fun pipe(dest: Any, options: Any): Any
}

View File

@ -1,4 +1,9 @@
package space.kscience.kmath.estree.internal.tsstdlib
/*
* 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.internal.tsstdlib
internal external interface IteratorYieldResult<TYield> {
var done: Boolean?

View File

@ -1,6 +1,11 @@
/*
* 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.
*/
@file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION")
package space.kscience.kmath.estree.internal.tsstdlib
package space.kscience.kmath.internal.tsstdlib
import kotlin.js.RegExp
@ -33,6 +38,8 @@ internal external interface RegExpConstructor {
var lastMatch: String
}
internal typealias Record<K, T> = Any
internal external interface ConcatArray<T> {
var length: Number
@ -80,3 +87,10 @@ internal external interface ArrayLike<T> {
}
internal typealias Extract<T, U> = Any
internal external interface PromiseLike<T> {
fun then(
onfulfilled: ((value: T) -> Any?)? = definedExternally,
onrejected: ((reason: Any) -> Any?)? = definedExternally
): PromiseLike<dynamic /* TResult1 | TResult2 */>
}

View File

@ -0,0 +1,236 @@
/*
* 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.
*/
@file:JsQualifier("WebAssembly")
@file:Suppress(
"INTERFACE_WITH_SUPERCLASS",
"OVERRIDING_FINAL_MEMBER",
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
"NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING",
"ClassName",
)
package space.kscience.kmath.internal.webassembly
import space.kscience.kmath.internal.tsstdlib.PromiseLike
import org.khronos.webgl.ArrayBuffer
import org.khronos.webgl.ArrayBufferView
import org.khronos.webgl.Uint8Array
import org.w3c.fetch.Response
import kotlin.js.Promise
@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
internal external interface CompileError {
companion object {
var prototype: CompileError
}
}
@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
internal external interface Global {
var value: Any
fun valueOf(): Any
companion object {
var prototype: Global
}
}
@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
@JsName("Instance")
internal external interface Instance1 {
var exports: Exports
companion object {
var prototype: Instance
}
}
@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
internal external interface LinkError {
companion object {
var prototype: LinkError
}
}
@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
internal external interface Memory {
var buffer: ArrayBuffer
fun grow(delta: Number): Number
companion object {
var prototype: Memory
}
}
@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
@JsName("Module")
internal external interface Module1 {
companion object {
var prototype: Module
fun customSections(moduleObject: Module, sectionName: String): Array<ArrayBuffer>
fun exports(moduleObject: Module): Array<ModuleExportDescriptor>
fun imports(moduleObject: Module): Array<ModuleImportDescriptor>
}
}
@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
internal external interface RuntimeError {
companion object {
var prototype: RuntimeError
}
}
@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
internal external interface Table {
var length: Number
fun get(index: Number): Function<*>?
fun grow(delta: Number): Number
fun set(index: Number, value: Function<*>?)
companion object {
var prototype: Table
}
}
internal external interface GlobalDescriptor {
var mutable: Boolean?
get() = definedExternally
set(value) = definedExternally
var value: String /* "f32" | "f64" | "i32" | "i64" */
}
internal external interface MemoryDescriptor {
var initial: Number
var maximum: Number?
get() = definedExternally
set(value) = definedExternally
}
internal external interface ModuleExportDescriptor {
var kind: String /* "function" | "global" | "memory" | "table" */
var name: String
}
internal external interface ModuleImportDescriptor {
var kind: String /* "function" | "global" | "memory" | "table" */
var module: String
var name: String
}
internal external interface TableDescriptor {
var element: String /* "anyfunc" */
var initial: Number
var maximum: Number?
get() = definedExternally
set(value) = definedExternally
}
internal external interface WebAssemblyInstantiatedSource {
var instance: Instance
var module: Module
}
internal external fun compile(bytes: ArrayBufferView): Promise<Module>
internal external fun compile(bytes: ArrayBuffer): Promise<Module>
internal external fun compileStreaming(source: Response): Promise<Module>
internal external fun compileStreaming(source: Promise<Response>): Promise<Module>
internal external fun instantiate(
bytes: ArrayBufferView,
importObject: Imports = definedExternally,
): Promise<WebAssemblyInstantiatedSource>
internal external fun instantiate(bytes: ArrayBufferView): Promise<WebAssemblyInstantiatedSource>
internal external fun instantiate(
bytes: ArrayBuffer,
importObject: Imports = definedExternally,
): dynamic /* Promise | Promise */
internal external fun instantiate(bytes: ArrayBuffer): dynamic /* Promise | Promise */
internal external fun instantiate(moduleObject: Module, importObject: Imports = definedExternally): Promise<Instance>
internal external fun instantiate(moduleObject: Module): Promise<Instance>
internal external fun instantiateStreaming(
response: Response,
importObject: Imports = definedExternally,
): Promise<WebAssemblyInstantiatedSource>
internal external fun instantiateStreaming(response: Response): Promise<WebAssemblyInstantiatedSource>
internal external fun instantiateStreaming(
response: PromiseLike<Response>,
importObject: Imports = definedExternally,
): Promise<WebAssemblyInstantiatedSource>
internal external fun instantiateStreaming(response: PromiseLike<Response>): Promise<WebAssemblyInstantiatedSource>
internal external fun validate(bytes: ArrayBufferView): Boolean
internal external fun validate(bytes: ArrayBuffer): Boolean
internal external interface `T$0` {
var name: String
var kind: String
}
internal external interface `T$1` {
var module: String
var name: String
var kind: String
}
internal open external class Module {
constructor(bufferSource: ArrayBuffer)
constructor(bufferSource: Uint8Array)
companion object {
fun customSections(module: Module, sectionName: String): Array<ArrayBuffer>
fun exports(module: Module): Array<`T$0`>
fun imports(module: Module): Array<`T$1`>
}
}
@JsName("Instance")
internal open external class Instance(module: Module, importObject: Any = definedExternally) {
open var exports: Any
}
@JsName("Memory")
internal open external class Memory1(memoryDescriptor: MemoryDescriptor) {
open var buffer: ArrayBuffer
open fun grow(numPages: Number): Number
}
@JsName("Table")
internal open external class Table1(tableDescriptor: TableDescriptor) {
open var length: Number
open fun get(index: Number): Function<*>
open fun grow(numElements: Number): Number
open fun set(index: Number, value: Function<*>)
}
internal external fun compile(bufferSource: Uint8Array): Promise<Module>
internal external interface ResultObject {
var module: Module
var instance: Instance
}
internal external fun instantiate(
bufferSource: Uint8Array,
importObject: Any = definedExternally,
): Promise<ResultObject>
internal external fun instantiate(bufferSource: Uint8Array): Promise<ResultObject>
internal external fun validate(bufferSource: Uint8Array): Boolean

View File

@ -0,0 +1,27 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("INTERFACE_WITH_SUPERCLASS",
"OVERRIDING_FINAL_MEMBER",
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
"CONFLICTING_OVERLOADS",
"NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING",
)
package space.kscience.kmath.internal.webassembly
import space.kscience.kmath.internal.tsstdlib.Record
internal typealias Exports = Record<String, dynamic /* Function<*> | Global | Memory | Table */>
internal typealias ModuleImports = Record<String, dynamic /* Function<*> | Global | Memory | Table | Number */>
internal typealias Imports = Record<String, ModuleImports>
internal typealias CompileError1 = Error
internal typealias LinkError1 = Error
internal typealias RuntimeError1 = Error

View File

@ -0,0 +1,160 @@
/*
* 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.wasm.internal
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.expressions.MST.*
import space.kscience.kmath.internal.binaryen.*
import space.kscience.kmath.internal.webassembly.Instance
import space.kscience.kmath.misc.StringSymbol
import space.kscience.kmath.operations.*
import space.kscience.kmath.internal.binaryen.Module as BinaryenModule
import space.kscience.kmath.internal.webassembly.Module as WasmModule
private val spreader = eval("(obj, args) => obj(...args)")
@Suppress("UnsafeCastFromDynamic")
internal sealed class WasmBuilder<T>(
val binaryenType: Type,
val algebra: Algebra<T>,
val target: MST,
) where T : Number {
val keys: MutableList<String> = mutableListOf()
lateinit var ctx: BinaryenModule
open fun visitSymbolic(mst: MST.Symbolic): ExpressionRef {
try {
algebra.bindSymbol(mst.value)
} catch (ignored: Throwable) {
null
}?.let { return visitNumeric(Numeric(it)) }
var idx = keys.indexOf(mst.value)
if (idx == -1) {
keys += mst.value
idx = keys.lastIndex
}
return ctx.local.get(idx, binaryenType)
}
abstract fun visitNumeric(mst: Numeric): ExpressionRef
open fun visitUnary(mst: Unary): ExpressionRef =
error("Unary operation ${mst.operation} not defined in $this")
open fun visitBinary(mst: Binary): ExpressionRef =
error("Binary operation ${mst.operation} not defined in $this")
open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()")
fun visit(mst: MST): ExpressionRef = when (mst) {
is Symbolic -> visitSymbolic(mst)
is Numeric -> visitNumeric(mst)
is Unary -> when {
algebra is NumericAlgebra && mst.value is Numeric -> visitNumeric(
Numeric(algebra.unaryOperationFunction(mst.operation)(algebra.number((mst.value as Numeric).value))))
else -> visitUnary(mst)
}
is Binary -> when {
algebra is NumericAlgebra && mst.left is Numeric && mst.right is Numeric -> visitNumeric(Numeric(
algebra.binaryOperationFunction(mst.operation)
.invoke(algebra.number((mst.left as Numeric).value), algebra.number((mst.right as Numeric).value))
))
else -> visitBinary(mst)
}
}
val instance by lazy {
val c = WasmModule(with(createModule()) {
ctx = this
val expr = visit(target)
addFunction(
"executable",
createType(Array(keys.size) { binaryenType }),
binaryenType,
arrayOf(),
expr
)
setOptimizeLevel(3)
optimizeFunction("executable")
addFunctionExport("executable", "executable")
val res = emitBinary()
dispose()
res
})
val i = Instance(c, js("{}") as Any)
val symbols = keys.map(::StringSymbol)
keys.clear()
Expression<T> { args ->
val params = symbols.map(args::getValue).toTypedArray()
spreader(i.exports.asDynamic().executable, params) as T
}
}
}
internal class DoubleWasmBuilder(target: MST) : WasmBuilder<Double>(f64, DoubleField, target) {
override fun createModule(): BinaryenModule = readBinary(f64StandardFunctions)
override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.f64.const(mst.value)
override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) {
GroupOperations.MINUS_OPERATION -> ctx.f64.neg(visit(mst.value))
GroupOperations.PLUS_OPERATION -> visit(mst.value)
PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(mst.value))
TrigonometricOperations.SIN_OPERATION -> ctx.call("sin", arrayOf(visit(mst.value)), f64)
TrigonometricOperations.COS_OPERATION -> ctx.call("cos", arrayOf(visit(mst.value)), f64)
TrigonometricOperations.TAN_OPERATION -> ctx.call("tan", arrayOf(visit(mst.value)), f64)
TrigonometricOperations.ASIN_OPERATION -> ctx.call("asin", arrayOf(visit(mst.value)), f64)
TrigonometricOperations.ACOS_OPERATION -> ctx.call("acos", arrayOf(visit(mst.value)), f64)
TrigonometricOperations.ATAN_OPERATION -> ctx.call("atan", arrayOf(visit(mst.value)), f64)
ExponentialOperations.SINH_OPERATION -> ctx.call("sinh", arrayOf(visit(mst.value)), f64)
ExponentialOperations.COSH_OPERATION -> ctx.call("cosh", arrayOf(visit(mst.value)), f64)
ExponentialOperations.TANH_OPERATION -> ctx.call("tanh", arrayOf(visit(mst.value)), f64)
ExponentialOperations.ASINH_OPERATION -> ctx.call("asinh", arrayOf(visit(mst.value)), f64)
ExponentialOperations.ACOSH_OPERATION -> ctx.call("acosh", arrayOf(visit(mst.value)), f64)
ExponentialOperations.ATANH_OPERATION -> ctx.call("atanh", arrayOf(visit(mst.value)), f64)
ExponentialOperations.EXP_OPERATION -> ctx.call("exp", arrayOf(visit(mst.value)), f64)
ExponentialOperations.LN_OPERATION -> ctx.call("log", arrayOf(visit(mst.value)), f64)
else -> super.visitUnary(mst)
}
override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) {
GroupOperations.PLUS_OPERATION -> ctx.f64.add(visit(mst.left), visit(mst.right))
GroupOperations.MINUS_OPERATION -> ctx.f64.sub(visit(mst.left), visit(mst.right))
RingOperations.TIMES_OPERATION -> ctx.f64.mul(visit(mst.left), visit(mst.right))
FieldOperations.DIV_OPERATION -> ctx.f64.div(visit(mst.left), visit(mst.right))
PowerOperations.POW_OPERATION -> ctx.call("pow", arrayOf(visit(mst.left), visit(mst.right)), f64)
else -> super.visitBinary(mst)
}
}
internal class IntWasmBuilder(target: MST) : WasmBuilder<Int>(i32, IntRing, target) {
override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.i32.const(mst.value)
override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) {
GroupOperations.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(mst.value))
GroupOperations.PLUS_OPERATION -> visit(mst.value)
else -> super.visitUnary(mst)
}
override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) {
GroupOperations.PLUS_OPERATION -> ctx.i32.add(visit(mst.left), visit(mst.right))
GroupOperations.MINUS_OPERATION -> ctx.i32.sub(visit(mst.left), visit(mst.right))
RingOperations.TIMES_OPERATION -> ctx.i32.mul(visit(mst.left), visit(mst.right))
else -> super.visitBinary(mst)
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,82 @@
/*
* 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.wasm
import space.kscience.kmath.estree.compileWith
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.IntRing
import space.kscience.kmath.wasm.internal.DoubleWasmBuilder
import space.kscience.kmath.wasm.internal.IntWasmBuilder
/**
* Compiles an [MST] to WASM in the context of reals.
*
* @author Iaroslav Postovalov
*/
public fun DoubleField.expression(mst: MST): Expression<Double> =
DoubleWasmBuilder(mst).instance
/**
* Compiles an [MST] to WASM in the context of integers.
*
* @author Iaroslav Postovalov
*/
public fun IntRing.expression(mst: MST): Expression<Int> =
IntWasmBuilder(mst).instance
/**
* Create a compiled expression with given [MST] and given [algebra].
*
* @author Iaroslav Postovalov
*/
public fun MST.compileToExpression(algebra: IntRing): Expression<Int> = compileWith(algebra)
/**
* Compile given MST to expression and evaluate it against [arguments].
*
* @author Iaroslav Postovalov
*/
public fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int =
compileToExpression(algebra).invoke(arguments)
/**
* Compile given MST to expression and evaluate it against [arguments].
*
* @author Iaroslav Postovalov
*/
public fun MST.compile(algebra: IntRing, vararg arguments: Pair<Symbol, Int>): Int =
compileToExpression(algebra)(*arguments)
/**
* Create a compiled expression with given [MST] and given [algebra].
*
* @author Iaroslav Postovalov
*/
public fun MST.compileToExpression(algebra: DoubleField): Expression<Double> = compileWith(algebra)
/**
* Compile given MST to expression and evaluate it against [arguments].
*
* @author Iaroslav Postovalov
*/
public fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Double =
compileToExpression(algebra).invoke(arguments)
/**
* Compile given MST to expression and evaluate it against [arguments].
*
* @author Iaroslav Postovalov
*/
public fun MST.compile(algebra: DoubleField, vararg arguments: Pair<Symbol, Double>): Double =
compileToExpression(algebra).invoke(*arguments)

View File

@ -0,0 +1,72 @@
/*
* 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.misc.symbol
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.math.sin
import kotlin.random.Random
import kotlin.test.Test
import kotlin.time.measureTime
import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression
import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression
internal class TestExecutionTime {
private companion object {
private const val times = 1_000_000
private val x by symbol
private val algebra: ExtendedField<Double> = DoubleField
private val functional = DoubleField.expressionInExtendedField {
bindSymbol(x) * const(2.0) + const(2.0) / bindSymbol(x) - const(16.0) / sin(bindSymbol(x))
}
private val node = MstExtendedField {
bindSymbol(x) * number(2.0) + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x))
}
private val mst = node.toExpression(DoubleField)
private val wasm = node.wasmCompileToExpression(DoubleField)
private val estree = node.estreeCompileToExpression(DoubleField)
// In JavaScript, the expression below is implemented like
// _no_name_provided__125.prototype.invoke_178 = function (args) {
// var tmp = getValue(args, raw$_get_x__3(this._$x$delegate_2)) * 2.0 + 2.0 / getValue(args, raw$_get_x__3(this._$x$delegate_2));
// var tmp0_sin_0_5 = getValue(args, raw$_get_x__3(this._$x$delegate_2));
// return tmp - 16.0 / Math.sin(tmp0_sin_0_5);
// };
private val raw = Expression<Double> { args ->
args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 / sin(args.getValue(x))
}
}
private fun invokeAndSum(name: String, expr: Expression<Double>) {
println(name)
val rng = Random(0)
var sum = 0.0
measureTime { repeat(times) { sum += expr(x to rng.nextDouble()) } }.also(::println)
}
@Test
fun functionalExpression() = invokeAndSum("functional", functional)
@Test
fun mstExpression() = invokeAndSum("mst", mst)
@Test
fun wasmExpression() = invokeAndSum("wasm", wasm)
@Test
fun estreeExpression() = invokeAndSum("estree", wasm)
@Test
fun rawExpression() = invokeAndSum("raw", raw)
}

View File

@ -1,20 +1,24 @@
/*
* 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.estree
import space.kscience.kmath.ast.*
import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.toComplex
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestESTreeConsistencyWithInterpreter {
@Test
fun mstSpace() {
val mst = MstGroup {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
@ -25,12 +29,12 @@ internal class TestESTreeConsistencyWithInterpreter {
),
number(1)
) + bindSymbol("x") + zero
) + bindSymbol(x) + zero
}
assertEquals(
mst.interpret(MstGroup, Symbol.x to MST.Numeric(2)),
mst.compile(MstGroup, Symbol.x to MST.Numeric(2))
mst.interpret(MstGroup, x to MST.Numeric(2)),
mst.compile(MstGroup, x to MST.Numeric(2))
)
}
@ -39,7 +43,7 @@ internal class TestESTreeConsistencyWithInterpreter {
val mst = MstRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (scale(
(bindSymbol(x) - (2.toByte() + (scale(
add(number(1), number(1)),
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
@ -50,24 +54,24 @@ internal class TestESTreeConsistencyWithInterpreter {
}
assertEquals(
mst.interpret(ByteRing, Symbol.x to 3.toByte()),
mst.compile(ByteRing, Symbol.x to 3.toByte())
mst.interpret(ByteRing, x to 3.toByte()),
mst.compile(ByteRing, x to 3.toByte())
)
}
@Test
fun realField() {
fun doubleField() {
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
(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
}
assertEquals(
mst.interpret(DoubleField, Symbol.x to 2.0),
mst.compile(DoubleField, Symbol.x to 2.0)
mst.interpret(DoubleField, x to 2.0),
mst.compile(DoubleField, x to 2.0)
)
}
@ -75,15 +79,19 @@ internal class TestESTreeConsistencyWithInterpreter {
fun complexField() {
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
(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
}
assertEquals(
mst.interpret(ComplexField, Symbol.x to 2.0.toComplex()),
mst.compile(ComplexField, Symbol.x to 2.0.toComplex())
mst.interpret(ComplexField, x to 2.0.toComplex()),
mst.compile(ComplexField, x to 2.0.toComplex()),
)
}
private companion object {
private val x by symbol
}
}

View File

@ -1,42 +1,42 @@
/*
* 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.estree
import space.kscience.kmath.ast.MstExtendedField
import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.MstGroup
import space.kscience.kmath.expressions.invoke
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
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestESTreeOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
val expression = MstExtendedField { -bindSymbol("x") }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
val expression = MstGroup { -bindSymbol(x) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-2.0, res)
}
@Test
fun testBinaryOperationInvocation() {
val expression = MstExtendedField { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
val expression = MstGroup { -bindSymbol(x) + number(1.0) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-1.0, res)
}
@Test
fun testConstProductInvocation() {
val res = MstExtendedField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
val res = MstField { bindSymbol(x) * 2 }.compileToExpression(DoubleField)(x to 2.0)
assertEquals(4.0, res)
}
@Test
fun testMultipleCalls() {
val e =
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()) }
println(s)
private companion object {
private val x by symbol
}
}

View File

@ -1,8 +1,15 @@
/*
* 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.estree
import space.kscience.kmath.ast.MstExtendedField
import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.invoke
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.test.Test
import kotlin.test.assertEquals
@ -10,55 +17,60 @@ import kotlin.test.assertEquals
internal class TestESTreeSpecialization {
@Test
fun testUnaryPlus() {
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(2.0, expr("x" to 2.0))
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(2.0, expr(x to 2.0))
}
@Test
fun testUnaryMinus() {
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr("x" to 2.0))
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr(x to 2.0))
}
@Test
fun testAdd() {
val expr = MstExtendedField {
binaryOperationFunction("+")(bindSymbol("x"),
bindSymbol("x"))
binaryOperationFunction("+")(
bindSymbol(x),
bindSymbol(x),
)
}.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0))
assertEquals(4.0, expr(x to 2.0))
}
@Test
fun testSine() {
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 0.0))
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 0.0))
}
@Test
fun testMinus() {
fun testSubtract() {
val expr = MstExtendedField {
binaryOperationFunction("-")(bindSymbol("x"),
bindSymbol("x"))
binaryOperationFunction("-")(bindSymbol(x),
bindSymbol(x))
}.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 2.0))
assertEquals(0.0, expr(x to 2.0))
}
@Test
fun testDivide() {
val expr = MstExtendedField {
binaryOperationFunction("/")(bindSymbol("x"),
bindSymbol("x"))
binaryOperationFunction("/")(bindSymbol(x), bindSymbol(x))
}.compileToExpression(DoubleField)
assertEquals(1.0, expr("x" to 2.0))
assertEquals(1.0, expr(x to 2.0))
}
@Test
fun testPower() {
val expr = MstExtendedField {
binaryOperationFunction("pow")(bindSymbol("x"), number(2))
binaryOperationFunction("pow")(bindSymbol(x), number(2))
}.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0))
assertEquals(4.0, expr(x to 2.0))
}
private companion object {
private val x by symbol
}
}

View File

@ -1,8 +1,15 @@
/*
* 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.estree
import space.kscience.kmath.ast.MstRing
import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
@ -11,13 +18,17 @@ import kotlin.test.assertFailsWith
internal class TestESTreeVariables {
@Test
fun testVariable() {
val expr = MstRing{ bindSymbol("x") }.compileToExpression(ByteRing)
assertEquals(1.toByte(), expr("x" to 1.toByte()))
val expr = MstRing { bindSymbol(x) }.compileToExpression(ByteRing)
assertEquals(1.toByte(), expr(x to 1.toByte()))
}
@Test
fun testUndefinedVariableFails() {
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
val expr = MstRing { bindSymbol(x) }.compileToExpression(ByteRing)
assertFailsWith<NoSuchElementException> { expr() }
}
private companion object {
private val x by symbol
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.wasm
import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.interpret
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.IntRing
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestWasmConsistencyWithInterpreter {
@Test
fun intRing() {
val mst = MstRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol(x) - (2.toByte() + (scale(
add(number(1), number(1)),
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
),
number(1)
) * number(2)
}
assertEquals(
mst.interpret(IntRing, x to 3),
mst.compile(IntRing, x to 3)
)
}
@Test
fun doubleField() {
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
}
assertEquals(
mst.interpret(DoubleField, x to 2.0),
mst.compile(DoubleField, x to 2.0)
)
}
private companion object {
private val x by symbol
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.wasm
import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.MstGroup
import space.kscience.kmath.expressions.invoke
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.test.Test
import kotlin.test.assertEquals
internal class TestWasmOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
val expression = MstGroup { -bindSymbol(x) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-2.0, res)
}
@Test
fun testBinaryOperationInvocation() {
val expression = MstGroup { -bindSymbol(x) + number(1.0) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-1.0, res)
}
@Test
fun testConstProductInvocation() {
val res = MstField { bindSymbol(x) * 2 }.compileToExpression(DoubleField)(x to 2.0)
assertEquals(4.0, res)
}
private companion object {
private val x by symbol
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.wasm
import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.invoke
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.test.Test
import kotlin.test.assertEquals
internal class TestWasmSpecialization {
@Test
fun testUnaryPlus() {
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(2.0, expr(x to 2.0))
}
@Test
fun testUnaryMinus() {
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr(x to 2.0))
}
@Test
fun testAdd() {
val expr = MstExtendedField {
binaryOperationFunction("+")(
bindSymbol(x),
bindSymbol(x),
)
}.compileToExpression(DoubleField)
assertEquals(4.0, expr(x to 2.0))
}
@Test
fun testSine() {
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 0.0))
}
@Test
fun testSubtract() {
val expr = MstExtendedField {
binaryOperationFunction("-")(bindSymbol(x),
bindSymbol(x))
}.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 2.0))
}
@Test
fun testDivide() {
val expr = MstExtendedField {
binaryOperationFunction("/")(bindSymbol(x), bindSymbol(x))
}.compileToExpression(DoubleField)
assertEquals(1.0, expr(x to 2.0))
}
@Test
fun testPower() {
val expr = MstExtendedField {
binaryOperationFunction("pow")(bindSymbol(x), number(2))
}.compileToExpression(DoubleField)
assertEquals(4.0, expr(x to 2.0))
}
private companion object {
private val x by symbol
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.wasm
import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.IntRing
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestWasmSpecific {
@Test
fun int() {
val res = MstRing { number(100000000) + number(10000000) }.compile(IntRing)
assertEquals(110000000, res)
}
@Test
fun real() {
val res = MstExtendedField { number(100000000) + number(2).pow(10) }.compile(DoubleField)
assertEquals(100001024.0, res)
}
@Test
fun argsPassing() {
val res = MstExtendedField { bindSymbol(y) + bindSymbol(x).pow(10) }.compile(
DoubleField,
x to 2.0,
y to 100000000.0,
)
assertEquals(100001024.0, res)
}
@Test
fun powFunction() {
val expr = MstExtendedField { bindSymbol(x).pow(1.0 / 6.0) }.compileToExpression(DoubleField)
assertEquals(0.9730585187140817, expr(x to 0.8488554755054833))
}
private companion object {
private val x by symbol
private val y by symbol
}
}

View File

@ -0,0 +1,34 @@
/*
* 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.wasm
import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.IntRing
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
internal class TestWasmVariables {
@Test
fun testVariable() {
val expr = MstRing { bindSymbol(x) }.compileToExpression(IntRing)
assertEquals(1, expr(x to 1))
}
@Test
fun testUndefinedVariableFails() {
val expr = MstRing { bindSymbol(x) }.compileToExpression(IntRing)
assertFailsWith<NoSuchElementException> { expr() }
}
private companion object {
private val x by symbol
}
}

View File

@ -1,10 +1,15 @@
/*
* 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.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.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
@ -34,15 +39,17 @@ internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Exp
is Unary -> when {
algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant(
algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value)))
algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) }
}
is Binary -> when {
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant(
algebra.binaryOperationFunction(node.operation)
.invoke(algebra.number(node.left.value), algebra.number(node.right.value))
algebra.binaryOperationFunction(node.operation).invoke(
algebra.number((node.left as Numeric).value),
algebra.number((node.right as Numeric).value)
)
)
algebra is NumericAlgebra && node.left is Numeric -> buildCall(
@ -71,18 +78,18 @@ internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Exp
/**
* Create a compiled expression with given [MST] and given [algebra].
*/
public inline fun <reified T: Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> =
public inline fun <reified T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> =
compileWith(T::class.java, algebra)
/**
* Compile given MST to expression and evaluate it against [arguments]
*/
public inline fun <reified T: Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
compileToExpression(algebra).invoke(arguments)
/**
* Compile given MST to expression and evaluate it against [arguments]
*/
public inline fun <reified T: Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol,T>): T =
public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T =
compileToExpression(algebra).invoke(*arguments)

View File

@ -1,3 +1,8 @@
/*
* 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.asm.internal
import org.objectweb.asm.*
@ -5,8 +10,8 @@ import org.objectweb.asm.Opcodes.*
import org.objectweb.asm.Type.*
import org.objectweb.asm.commons.InstructionAdapter
import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader
import space.kscience.kmath.ast.MST
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
import java.util.stream.Collectors.toMap

View File

@ -1,9 +1,14 @@
/*
* 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.asm.internal
import org.objectweb.asm.*
import org.objectweb.asm.commons.InstructionAdapter
import space.kscience.kmath.ast.MST
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

View File

@ -1,3 +1,8 @@
/*
* 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.
*/
@file:JvmName("MapIntrinsics")
package space.kscience.kmath.asm.internal

View File

@ -0,0 +1,9 @@
/*
* 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
internal actual fun Double.multiplatformToString(): String = toString()
internal actual fun Float.multiplatformToString(): String = toString()

View File

@ -1,20 +1,24 @@
/*
* 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.asm
import space.kscience.kmath.ast.*
import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.toComplex
import space.kscience.kmath.misc.Symbol.Companion.x
import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestAsmConsistencyWithInterpreter {
@Test
fun mstSpace() {
val mst = MstGroup {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
@ -25,7 +29,7 @@ internal class TestAsmConsistencyWithInterpreter {
),
number(1)
) + bindSymbol("x") + zero
) + bindSymbol(x) + zero
}
assertEquals(
@ -39,7 +43,7 @@ internal class TestAsmConsistencyWithInterpreter {
val mst = MstRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (scale(
(bindSymbol(x) - (2.toByte() + (scale(
add(number(1), number(1)),
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
@ -56,10 +60,10 @@ internal class TestAsmConsistencyWithInterpreter {
}
@Test
fun realField() {
fun doubleField() {
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
(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
@ -75,7 +79,7 @@ internal class TestAsmConsistencyWithInterpreter {
fun complexField() {
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
(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
@ -86,4 +90,8 @@ internal class TestAsmConsistencyWithInterpreter {
mst.compile(ComplexField, x to 2.0.toComplex())
)
}
private companion object {
private val x by symbol
}
}

View File

@ -1,44 +1,42 @@
/*
* 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.asm
import space.kscience.kmath.ast.MstExtendedField
import space.kscience.kmath.ast.MstField
import space.kscience.kmath.ast.MstGroup
import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.MstGroup
import space.kscience.kmath.expressions.invoke
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
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestAsmOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
val expression = MstGroup { -bindSymbol("x") }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
val expression = MstGroup { -bindSymbol(x) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-2.0, res)
}
@Test
fun testBinaryOperationInvocation() {
val expression = MstGroup { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
val expression = MstGroup { -bindSymbol(x) + number(1.0) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-1.0, res)
}
@Test
fun testConstProductInvocation() {
val res = MstField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
val res = MstField { bindSymbol(x) * 2 }.compileToExpression(DoubleField)(x to 2.0)
assertEquals(4.0, res)
}
@Test
fun testMultipleCalls() {
val e =
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()) }
println(s)
private companion object {
private val x by symbol
}
}

View File

@ -1,8 +1,15 @@
/*
* 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.asm
import space.kscience.kmath.ast.MstExtendedField
import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.invoke
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.test.Test
import kotlin.test.assertEquals
@ -10,55 +17,60 @@ import kotlin.test.assertEquals
internal class TestAsmSpecialization {
@Test
fun testUnaryPlus() {
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(2.0, expr("x" to 2.0))
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(2.0, expr(x to 2.0))
}
@Test
fun testUnaryMinus() {
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr("x" to 2.0))
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr(x to 2.0))
}
@Test
fun testAdd() {
val expr = MstExtendedField {
binaryOperationFunction("+")(bindSymbol("x"),
bindSymbol("x"))
binaryOperationFunction("+")(
bindSymbol(x),
bindSymbol(x),
)
}.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0))
assertEquals(4.0, expr(x to 2.0))
}
@Test
fun testSine() {
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 0.0))
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 0.0))
}
@Test
fun testMinus() {
fun testSubtract() {
val expr = MstExtendedField {
binaryOperationFunction("-")(bindSymbol("x"),
bindSymbol("x"))
binaryOperationFunction("-")(bindSymbol(x),
bindSymbol(x))
}.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 2.0))
assertEquals(0.0, expr(x to 2.0))
}
@Test
fun testDivide() {
val expr = MstExtendedField {
binaryOperationFunction("/")(bindSymbol("x"),
bindSymbol("x"))
binaryOperationFunction("/")(bindSymbol(x), bindSymbol(x))
}.compileToExpression(DoubleField)
assertEquals(1.0, expr("x" to 2.0))
assertEquals(1.0, expr(x to 2.0))
}
@Test
fun testPower() {
val expr = MstExtendedField {
binaryOperationFunction("pow")(bindSymbol("x"), number(2))
binaryOperationFunction("pow")(bindSymbol(x), number(2))
}.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0))
assertEquals(4.0, expr(x to 2.0))
}
private companion object {
private val x by symbol
}
}

View File

@ -1,8 +1,15 @@
/*
* 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.asm
import space.kscience.kmath.ast.MstRing
import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
@ -11,13 +18,17 @@ import kotlin.test.assertFailsWith
internal class TestAsmVariables {
@Test
fun testVariable() {
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
assertEquals(1.toByte(), expr("x" to 1.toByte()))
val expr = MstRing { bindSymbol(x) }.compileToExpression(ByteRing)
assertEquals(1.toByte(), expr(x to 1.toByte()))
}
@Test
fun testUndefinedVariableFails() {
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing)
val expr = MstRing { bindSymbol(x) }.compileToExpression(ByteRing)
assertFailsWith<NoSuchElementException> { expr() }
}
private companion object {
private val x by symbol
}
}

View File

@ -1,6 +1,8 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
kotlin("jvm")
id("ru.mipt.npm.gradle.common")
}
description = "Commons math binding for kmath"
dependencies {

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