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 .gradle
build/ build/
out/ out/
.idea/ .idea/
!.idea/copyright/
!.idea/scopes/
.vscode/ .vscode/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)

View File

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

View File

@ -0,0 +1,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 integration API
- Basic MPP distributions and samplers - Basic MPP distributions and samplers
- bindSymbolOrNull - bindSymbolOrNull
- Blocking chains and Statistics
- Multiplatform integration
- Integration for any Field element
- Extendend operations for ND4J fields
### Changed ### Changed
- Exponential operations merged with hyperbolic functions - Exponential operations merged with hyperbolic functions
@ -18,6 +22,8 @@
- DataSets are moved from functions to core - DataSets are moved from functions to core
- Redesign advanced Chain API - Redesign advanced Chain API
- Redesign MST. Remove MSTExpression. - Redesign MST. Remove MSTExpression.
- Move MST to core
- Separated benchmarks and examples
### Deprecated ### Deprecated
@ -28,6 +34,7 @@
- MSTExpression - MSTExpression
### Fixed ### Fixed
- Ring inherits RingOperations, not GroupOperations
### Security ### 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 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. be achieved with [kmath-for-real](/kmath-for-real) extension module.
[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/)
## Publications and talks ## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2) * [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/> <hr/>
* ### [benchmarks](benchmarks)
>
>
> **Maturity**: EXPERIMENTAL
<hr/>
* ### [examples](examples) * ### [examples](examples)
> >
> >
@ -86,12 +94,10 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: PROTOTYPE > **Maturity**: PROTOTYPE
> >
> **Features:** > **Features:**
> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser > - [expression-language](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler > - [mst-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 > - [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/> <hr/>
@ -169,15 +175,16 @@ One can still use generic algebras though.
<hr/> <hr/>
* ### [kmath-functions](kmath-functions) * ### [kmath-functions](kmath-functions)
> Functions and interpolation > Functions, integration and interpolation
> >
> **Maturity**: PROTOTYPE > **Maturity**: EXPERIMENTAL
> >
> **Features:** > **Features:**
> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt > - [piecewise](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt) : Piecewise functions.
> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt > - [polynomials](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Polynomial functions.
> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt > - [linear interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt) : Linear XY interpolator.
> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt > - [spline interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator.
> - [integration](kmath-functions/#) : Univariate and multivariate quadratures
<hr/> <hr/>
@ -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 native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy. better than SciPy.
## Requirements
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
### Repositories ### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
@ -259,8 +270,8 @@ repositories {
} }
dependencies { dependencies {
api("space.kscience:kmath-core:0.3.0-dev-4") api("space.kscience:kmath-core:0.3.0-dev-7")
// api("kscience.kmath:kmath-core-jvm:0.3.0-dev-4") for jvm-specific version // 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 package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark 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 package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark 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 package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark 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 package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark 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 package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark 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 package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark 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 package space.kscience.kmath.benchmarks
import kotlinx.benchmark.Benchmark 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 { plugins {
id("ru.mipt.npm.gradle.project") id("ru.mipt.npm.gradle.project")
} }
@ -13,19 +9,21 @@ allprojects {
maven("https://dl.bintray.com/egor-bogomolov/astminer/") maven("https://dl.bintray.com/egor-bogomolov/astminer/")
maven("https://dl.bintray.com/hotkeytlt/maven") maven("https://dl.bintray.com/hotkeytlt/maven")
maven("https://jitpack.io") maven("https://jitpack.io")
maven("http://logicrunch.research.it.uu.se/maven/") maven("http://logicrunch.research.it.uu.se/maven/") {
isAllowInsecureProtocol = true
}
mavenCentral() mavenCentral()
} }
group = "space.kscience" group = "space.kscience"
version = "0.3.0-dev-5" version = "0.3.0-dev-7"
} }
subprojects { subprojects {
if (name.startsWith("kmath")) apply<KSciencePublishingPlugin>() if (name.startsWith("kmath")) apply<MavenPublishPlugin>()
afterEvaluate { afterEvaluate {
tasks.withType<DokkaTask> { tasks.withType<org.jetbrains.dokka.gradle.DokkaTask> {
dokkaSourceSets.all { dokkaSourceSets.all {
val readmeFile = File(this@subprojects.projectDir, "./README.md") val readmeFile = File(this@subprojects.projectDir, "./README.md")
if (readmeFile.exists()) if (readmeFile.exists())
@ -35,7 +33,7 @@ subprojects {
"http://ejml.org/javadoc/", "http://ejml.org/javadoc/",
"https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/", "https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/",
"https://deeplearning4j.org/api/latest/" "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 { externalDocumentationLink {
packageListUrl.set(a) packageListUrl.set(a)
url.set(b) 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 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. be achieved with [kmath-for-real](/kmath-for-real) extension module.
[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/)
## Publications and talks ## Publications and talks
* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2) * [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 native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy. better than SciPy.
## Requirements
KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
### Repositories ### Repositories
Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of
@ -104,7 +110,7 @@ repositories {
dependencies { dependencies {
api("${group}:kmath-core:$version") 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 { plugins {
kotlin("jvm") kotlin("jvm")
kotlin("plugin.allopen")
id("kotlinx.benchmark")
} }
allOpen.annotation("org.openjdk.jmh.annotations.State")
sourceSets.register("benchmarks")
repositories { repositories {
mavenCentral()
jcenter() jcenter()
maven("https://repo.kotlin.link") maven("https://repo.kotlin.link")
maven("https://clojars.org/repo") maven("https://clojars.org/repo")
maven("https://dl.bintray.com/egor-bogomolov/astminer/") maven("https://dl.bintray.com/egor-bogomolov/astminer/")
maven("https://dl.bintray.com/hotkeytlt/maven") maven("https://dl.bintray.com/hotkeytlt/maven")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/kotlin/kotlinx")
maven("https://dl.bintray.com/mipt-npm/dev")
maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://jitpack.io") maven("https://jitpack.io")
maven("http://logicrunch.research.it.uu.se/maven/") maven{
mavenCentral() setUrl("http://logicrunch.research.it.uu.se/maven/")
isAllowInsecureProtocol = true
}
} }
dependencies { dependencies {
@ -39,7 +31,6 @@ dependencies {
implementation(project(":kmath-for-real")) implementation(project(":kmath-for-real"))
implementation("org.deeplearning4j:deeplearning4j-core:1.0.0-beta7")
implementation("org.nd4j:nd4j-native:1.0.0-beta7") implementation("org.nd4j:nd4j-native:1.0.0-beta7")
// uncomment if your system supports AVX2 // uncomment if your system supports AVX2
@ -52,54 +43,9 @@ dependencies {
// } else // } else
implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
implementation("org.jetbrains.kotlinx:kotlinx-io:0.2.0-npm-dev-11")
implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20")
implementation("org.slf4j:slf4j-simple:1.7.30") implementation("org.slf4j:slf4j-simple:1.7.30")
// plotting // plotting
implementation("kscience.plotlykt:plotlykt-server:0.3.1-dev") implementation("space.kscience:plotlykt-server:0.4.0-dev-2")
"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")
}
} }
kotlin.sourceSets.all { kotlin.sourceSets.all {
@ -110,8 +56,11 @@ kotlin.sourceSets.all {
} }
} }
tasks.withType<KotlinCompile> { tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "11" kotlinOptions{
jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
}
} }
readme { 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 package space.kscience.kmath.ast
import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess 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 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.misc.Symbol.Companion.x
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol 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 package space.kscience.kmath.ast
import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.asm.compileToExpression
@ -20,5 +25,5 @@ fun main() {
val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField) 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 package space.kscience.kmath.commons.fit
import kotlinx.html.br import kotlinx.html.br
import kotlinx.html.h3 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.chiSquared
import space.kscience.kmath.commons.optimization.minimize import space.kscience.kmath.commons.optimization.minimize
import space.kscience.kmath.distributions.NormalDistribution 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.stat.RandomGenerator
import space.kscience.kmath.structures.asIterable import space.kscience.kmath.structures.asIterable
import space.kscience.kmath.structures.toList import space.kscience.kmath.structures.toList
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.models.TraceValues
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt 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 package space.kscience.kmath.linear
import space.kscience.kmath.real.* import space.kscience.kmath.real.*
@ -17,8 +22,8 @@ fun main() {
return DoubleBuffer(x.size) { i -> return DoubleBuffer(x.size) { i ->
val h = sigma[i] / 5 val h = sigma[i] / 5
val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 } val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
val f1 = invoke(x + dVector / 2) val f1 = this(x + dVector / 2)
val f0 = invoke(x - dVector / 2) val f0 = this(x - dVector / 2)
(f1 - f0) / h (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 package space.kscience.kmath.operations
fun main() { 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 package space.kscience.kmath.operations
import space.kscience.kmath.complex.Complex 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 package space.kscience.kmath.stat
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.apache.commons.rng.sampling.distribution.BoxMullerNormalizedGaussianSampler
import org.apache.commons.rng.simple.RandomSource import org.apache.commons.rng.simple.RandomSource
import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.samplers.GaussianSampler
import java.time.Duration import java.time.Duration
import java.time.Instant import java.time.Instant
import org.apache.commons.rng.sampling.distribution.GaussianSampler as CMGaussianSampler 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 { private suspend fun runKMathChained(): Duration {
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L) val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
@ -34,7 +39,7 @@ private fun runApacheDirect(): Duration {
val rng = RandomSource.create(RandomSource.MT, 123L) val rng = RandomSource.create(RandomSource.MT, 123L)
val sampler = CMGaussianSampler.of( val sampler = CMGaussianSampler.of(
CMZigguratNormalizedGaussianSampler.of(rng), BoxMullerNormalizedGaussianSampler.of(rng),
7.0, 7.0,
2.0 2.0
) )
@ -59,8 +64,8 @@ private fun runApacheDirect(): Duration {
* Comparing chain sampling performance with direct sampling performance * Comparing chain sampling performance with direct sampling performance
*/ */
fun main(): Unit = runBlocking(Dispatchers.Default) { fun main(): Unit = runBlocking(Dispatchers.Default) {
val chainJob = async { runKMathChained() }
val directJob = async { runApacheDirect() } val directJob = async { runApacheDirect() }
val chainJob = async { runKMathChained() }
println("KMath Chained: ${chainJob.await()}") println("KMath Chained: ${chainJob.await()}")
println("Apache Direct: ${directJob.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 package space.kscience.kmath.stat
import kotlinx.coroutines.runBlocking 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") @file:Suppress("unused")
package space.kscience.kmath.structures 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 package space.kscience.kmath.structures
import kotlinx.coroutines.GlobalScope 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 package space.kscience.kmath.structures
import space.kscience.kmath.nd.* 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 package space.kscience.kmath.structures
import space.kscience.kmath.nd.BufferND 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 package space.kscience.kmath.structures
import space.kscience.kmath.nd.StructureND 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 package space.kscience.kmath.structures
import space.kscience.kmath.dimensions.D2 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.code.style=official
kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.mpp.stability.nowarn=true kotlin.mpp.stability.nowarn=true
kotlin.native.enableDependencyPropagation=false kotlin.native.enableDependencyPropagation=false
kotlin.parallel.tasks.in.project=true kotlin.parallel.tasks.in.project=true
org.gradle.configureondemand=true org.gradle.configureondemand=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=9G org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
org.gradle.parallel=true org.gradle.parallel=true

View File

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

View File

@ -2,17 +2,15 @@
Abstract syntax tree expression representation and related optimizations. Abstract syntax tree expression representation and related optimizations.
- [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser - [expression-language](src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
- [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
- [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
- [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
- [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler - [mst-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 - [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: ## 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:**
```gradle ```gradle
@ -23,7 +21,7 @@ repositories {
} }
dependencies { dependencies {
implementation 'space.kscience:kmath-ast:0.3.0-dev-4' implementation 'space.kscience:kmath-ast:0.3.0-dev-7'
} }
``` ```
**Gradle Kotlin DSL:** **Gradle Kotlin DSL:**
@ -35,7 +33,7 @@ repositories {
} }
dependencies { 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: For example, the following builder:
```kotlin ```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: … 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 #### Known issues
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid - 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. A similar feature is also available on JS.
```kotlin ```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile() MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
``` ```
The code above returns expression implemented with such a JS function: 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 #### 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 ## 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: 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) ![](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> <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). (see API reference).

View File

@ -1,7 +1,6 @@
import ru.mipt.npm.gradle.Maturity
plugins { plugins {
id("ru.mipt.npm.gradle.mpp") kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
} }
kotlin.js { kotlin.js {
@ -21,6 +20,7 @@ kotlin.js {
kotlin.sourceSets { kotlin.sourceSets {
commonMain { commonMain {
dependencies { dependencies {
api("com.github.h0tk3y.betterParse:better-parse:0.4.2")
api(project(":kmath-core")) api(project(":kmath-core"))
} }
} }
@ -33,13 +33,15 @@ kotlin.sourceSets {
jsMain { jsMain {
dependencies { 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 { jvmMain {
dependencies { dependencies {
api("com.github.h0tk3y.betterParse:better-parse:0.4.1")
implementation("org.ow2.asm:asm:9.1") implementation("org.ow2.asm:asm:9.1")
implementation("org.ow2.asm:asm-commons:9.1") implementation("org.ow2.asm:asm-commons:9.1")
} }
@ -52,31 +54,13 @@ tasks.dokkaHtml {
} }
readme { readme {
maturity = Maturity.PROTOTYPE maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature( feature(
id = "expression-language", id = "expression-language",
description = "Expression language and its parser", description = "Expression language and its parser",
ref = "src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt" ref = "src/commonMain/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"
) )
feature( feature(
@ -90,4 +74,10 @@ readme {
description = "Dynamic MST to JS compiler", description = "Dynamic MST to JS compiler",
ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt" 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: For example, the following builder:
```kotlin ```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: … 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 #### Known issues
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid - 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. A similar feature is also available on JS.
```kotlin ```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile() MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
``` ```
The code above returns expression implemented with such a JS function: 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 #### 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 ## 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: 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) ![](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> <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). (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 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.lexer.regexToken
import com.github.h0tk3y.betterParse.parser.ParseResult import com.github.h0tk3y.betterParse.parser.ParseResult
import com.github.h0tk3y.betterParse.parser.Parser import com.github.h0tk3y.betterParse.parser.Parser
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.FieldOperations import space.kscience.kmath.operations.FieldOperations
import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.GroupOperations
import space.kscience.kmath.operations.PowerOperations import space.kscience.kmath.operations.PowerOperations

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 package space.kscience.kmath.ast.rendering
/** /**
@ -66,6 +71,15 @@ public object LatexSyntaxRenderer : SyntaxRenderer {
append('}') append('}')
} }
is ExponentSyntax -> if (node.useOperatorForm) {
append("\\operatorname{exp}\\,")
render(node.operand)
} else {
append("e^{")
render(node.operand)
append('}')
}
is SuperscriptSyntax -> { is SuperscriptSyntax -> {
render(node.left) render(node.left)
append("^{") 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 package space.kscience.kmath.ast.rendering
/** /**
@ -77,6 +82,19 @@ public object MathMLSyntaxRenderer : SyntaxRenderer {
is RadicalSyntax -> tag("msqrt") { render(node.operand) } 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") { is SuperscriptSyntax -> tag("msup") {
tag("mrow") { render(node.left) } tag("mrow") { render(node.left) }
tag("mrow") { render(node.right) } 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 package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.MST import space.kscience.kmath.expressions.MST
/** /**
* Renders [MST] to [MathSyntax]. * Renders [MST] to [MathSyntax].
@ -78,7 +83,7 @@ public open class FeaturedMathRendererWithPostProcess(
Fraction.Default, Fraction.Default,
Power.Default, Power.Default,
SquareRoot.Default, SquareRoot.Default,
Exponential.Default, Exponent.Default,
InverseTrigonometricOperations.Default, InverseTrigonometricOperations.Default,
// Fallback option for unknown operations - printing them as operator // Fallback option for unknown operations - printing them as operator
@ -95,6 +100,7 @@ public open class FeaturedMathRendererWithPostProcess(
PrintSymbolic, PrintSymbolic,
), ),
listOf( listOf(
BetterExponent,
SimplifyParentheses.Default, SimplifyParentheses.Default,
BetterMultiplication, 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 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). * 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 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 package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.MST
import space.kscience.kmath.ast.rendering.FeaturedMathRenderer.RenderFeature import space.kscience.kmath.ast.rendering.FeaturedMathRenderer.RenderFeature
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
import kotlin.reflect.KClass 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 class PrettyPrintFloats(public val types: Set<KClass<out Number>>) : RenderFeature {
public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { 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
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) { if (toString.contains('E', ignoreCase = true)) {
val (beforeE, afterE) = toString.split('E') val (beforeE, afterE) = toString.split('E', ignoreCase = true)
val significand = beforeE.toDouble().toString().removeSuffix(".0") val significand = beforeE.toDouble().toString().removeSuffix(".0")
val exponent = afterE.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 class PrettyPrintIntegers(public val types: Set<KClass<out Number>>) : RenderFeature {
public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? {
if (node !is MST.Numeric || node.value::class !in types) if (node !is MST.Numeric || node.value::class !in types) return null
return null
return printSignedNumberString(node.value.toString()) 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 class Exponent(operations: Collection<String>?) : Unary(operations) {
public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = SuperscriptSyntax( public override fun render0(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = ExponentSyntax(
operation = node.operation, operation = node.operation,
left = SymbolSyntax(string = "e"), operand = OperandSyntax(operand = parent.render(node.value), parentheses = true),
right = parent.render(node.value), useOperatorForm = true,
) )
public companion object { 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 package space.kscience.kmath.ast.rendering
import space.kscience.kmath.operations.FieldOperations import space.kscience.kmath.operations.FieldOperations
@ -11,69 +16,110 @@ import space.kscience.kmath.operations.RingOperations
* @author Iaroslav Postovalov * @author Iaroslav Postovalov
*/ */
public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostProcessStage { public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostProcessStage {
public override fun perform(node: MathSyntax) { public override fun perform(node: MathSyntax): Unit = when (node) {
when (node) { is NumberSyntax -> Unit
is NumberSyntax -> Unit is SymbolSyntax -> Unit
is SymbolSyntax -> Unit is OperatorNameSyntax -> Unit
is OperatorNameSyntax -> Unit is SpecialSymbolSyntax -> Unit
is SpecialSymbolSyntax -> Unit is OperandSyntax -> perform(node.operand)
is OperandSyntax -> perform(node.operand)
is UnaryOperatorSyntax -> { is UnaryOperatorSyntax -> {
perform(node.prefix) perform(node.prefix)
perform(node.operand) 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 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) : public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) :
FeaturedMathRendererWithPostProcess.PostProcessStage { FeaturedMathRendererWithPostProcess.PostProcessStage {
public override fun perform(node: MathSyntax) { public override fun perform(node: MathSyntax): Unit = when (node) {
when (node) { is NumberSyntax -> Unit
is NumberSyntax -> Unit is SymbolSyntax -> Unit
is SymbolSyntax -> Unit is OperatorNameSyntax -> Unit
is OperatorNameSyntax -> Unit is SpecialSymbolSyntax -> Unit
is SpecialSymbolSyntax -> Unit
is OperandSyntax -> { is OperandSyntax -> {
val isRightOfSuperscript = val isRightOfSuperscript =
(node.parent is SuperscriptSyntax) && (node.parent as SuperscriptSyntax).right === node (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) { val needParenthesesByPrecedence = when (val parent = node.parent) {
null -> false null -> false
is BinarySyntax -> { is BinarySyntax -> {
val parentPrecedence = precedenceFunction(parent) val parentPrecedence = precedenceFunction(parent)
parentPrecedence < precedence || parentPrecedence < precedence ||
parentPrecedence == precedence && parentPrecedence != 0 && node === parent.right parentPrecedence == precedence && parentPrecedence != 0 && node === parent.right
}
else -> precedence > precedenceFunction(parent)
} }
node.parentheses = !isRightOfSuperscript else -> precedence > precedenceFunction(parent)
&& (needParenthesesByPrecedence || node.parent is UnaryOperatorSyntax)
perform(node.operand)
} }
is UnaryOperatorSyntax -> { val isInsideExpOperator =
perform(node.prefix) node.parent is ExponentSyntax && (node.parent as ExponentSyntax).useOperatorForm
perform(node.operand)
}
is UnaryPlusSyntax -> perform(node.operand) node.parentheses = !isRightOfSuperscript
is UnaryMinusSyntax -> { && (needParenthesesByPrecedence || node.parent is UnaryOperatorSyntax || isInsideExpOperator)
perform(node.operand)
}
is RadicalSyntax -> perform(node.operand)
is SuperscriptSyntax -> { perform(node.operand)
perform(node.left) }
perform(node.right)
}
is SubscriptSyntax -> { is UnaryOperatorSyntax -> {
perform(node.left) perform(node.prefix)
perform(node.right) perform(node.operand)
} }
is BinaryOperatorSyntax -> { is UnaryPlusSyntax -> perform(node.operand)
perform(node.prefix) is UnaryMinusSyntax -> perform(node.operand)
perform(node.left) is RadicalSyntax -> perform(node.operand)
perform(node.right) is ExponentSyntax -> perform(node.operand)
}
is BinaryPlusSyntax -> { is SuperscriptSyntax -> {
perform(node.left) perform(node.left)
perform(node.right) perform(node.right)
} }
is BinaryMinusSyntax -> { is SubscriptSyntax -> {
perform(node.left) perform(node.left)
perform(node.right) perform(node.right)
} }
is FractionSyntax -> { is BinaryOperatorSyntax -> {
perform(node.left) perform(node.prefix)
perform(node.right) perform(node.left)
} perform(node.right)
}
is MultiplicationSyntax -> { is BinaryPlusSyntax -> {
perform(node.left) perform(node.left)
perform(node.right) perform(node.right)
} }
is RadicalWithIndexSyntax -> { is BinaryMinusSyntax -> {
perform(node.left) perform(node.left)
perform(node.right) 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 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.DoubleField
import space.kscience.kmath.operations.Field
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class ParserPrecedenceTest { internal class ParserPrecedenceTest {
private val f: Field<Double> = DoubleField
@Test @Test
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath())) fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
@ -31,4 +35,8 @@ internal class ParserPrecedenceTest {
@Test @Test
fun test8(): Unit = assertEquals(18.0, f.evaluate("2*2^3+2".parseMath())) 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 package space.kscience.kmath.ast
import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.ComplexField import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.expressions.evaluate
import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class ParserTest { internal class ParserTest {
@Test @Test
fun `evaluate MST`() { fun evaluateParsedMst() {
val mst = "2+2*(2+2)".parseMath() val mst = "2+2*(2+2)".parseMath()
val res = ComplexField.evaluate(mst) val res = ComplexField.evaluate(mst)
assertEquals(Complex(10.0, 0.0), res) assertEquals(Complex(10.0, 0.0), res)
} }
@Test @Test
fun `evaluate MSTExpression`() { fun evaluateMstSymbol() {
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`() {
val mst = "i".parseMath() val mst = "i".parseMath()
val res = ComplexField.evaluate(mst) val res = ComplexField.evaluate(mst)
assertEquals(ComplexField.i, res) assertEquals(ComplexField.i, res)
@ -31,14 +30,14 @@ internal class ParserTest {
@Test @Test
fun `evaluate MST with unary function`() { fun evaluateMstUnary() {
val mst = "sin(0)".parseMath() val mst = "sin(0)".parseMath()
val res = DoubleField.evaluate(mst) val res = DoubleField.evaluate(mst)
assertEquals(0.0, res) assertEquals(0.0, res)
} }
@Test @Test
fun `evaluate MST with binary function`() { fun evaluateMstBinary() {
val magicalAlgebra = object : Algebra<String> { val magicalAlgebra = object : Algebra<String> {
override fun bindSymbolOrNull(value: String): String = value 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 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.ast.rendering.TestUtils.testLatex
import space.kscience.kmath.expressions.MST.Numeric
import kotlin.test.Test import kotlin.test.Test
internal class TestFeatures { 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.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(-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 @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 package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.MST
import space.kscience.kmath.ast.rendering.TestUtils.testLatex import space.kscience.kmath.ast.rendering.TestUtils.testLatex
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.GroupOperations
import kotlin.test.Test 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 package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.MST
import space.kscience.kmath.ast.rendering.TestUtils.testMathML import space.kscience.kmath.ast.rendering.TestUtils.testMathML
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.GroupOperations
import kotlin.test.Test 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 package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.rendering.TestUtils.testLatex 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", "\\left(x+x\\right)^{x}+x\\,x")
testLatex("x^(x+x)", "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 package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.MST
import space.kscience.kmath.ast.parseMath import space.kscience.kmath.ast.parseMath
import space.kscience.kmath.expressions.MST
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal object TestUtils { 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 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.ESTreeBuilder
import space.kscience.kmath.estree.internal.estree.BaseExpression
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.expressions.MST.*
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.internal.estree.BaseExpression
import space.kscience.kmath.misc.Symbol import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra import space.kscience.kmath.operations.NumericAlgebra
@ -26,16 +31,17 @@ internal fun <T> MST.compileWith(algebra: Algebra<T>): Expression<T> {
is Unary -> when { is Unary -> when {
algebra is NumericAlgebra && node.value is Numeric -> constant( algebra is NumericAlgebra && node.value is Numeric -> constant(
algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value))) algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value))
} }
is Binary -> when { is Binary -> when {
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant( algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant(
algebra algebra.binaryOperationFunction(node.operation).invoke(
.binaryOperationFunction(node.operation) algebra.number((node.left as Numeric).value),
.invoke(algebra.number(node.left.value), algebra.number(node.right.value)) algebra.number((node.right as Numeric).value)
)
) )
algebra is NumericAlgebra && node.left is Numeric -> call( algebra is NumericAlgebra && node.left is Numeric -> call(
@ -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] * 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) compileToExpression(algebra).invoke(arguments)
/** /**
* Compile given MST to expression and evaluate it against [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) 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 package space.kscience.kmath.estree.internal
import space.kscience.kmath.estree.internal.astring.generate
import space.kscience.kmath.estree.internal.estree.*
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.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 import space.kscience.kmath.misc.Symbol
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) { 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 package space.kscience.kmath.estree.internal.astring
internal typealias Generator = Any 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:JsModule("astring")
@file:JsNonModule @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 { internal external interface Options {
var indent: String? 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 { internal open external class Emitter {
constructor(obj: Any) 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 { internal fun Program(sourceType: String, vararg body: dynamic) = object : Program {
override var type = "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 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> { internal external interface IteratorYieldResult<TYield> {
var done: Boolean? 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") @file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION")
package space.kscience.kmath.estree.internal.tsstdlib package space.kscience.kmath.internal.tsstdlib
import kotlin.js.RegExp import kotlin.js.RegExp
@ -33,6 +38,8 @@ internal external interface RegExpConstructor {
var lastMatch: String var lastMatch: String
} }
internal typealias Record<K, T> = Any
internal external interface ConcatArray<T> { internal external interface ConcatArray<T> {
var length: Number var length: Number
@ -80,3 +87,10 @@ internal external interface ArrayLike<T> {
} }
internal typealias Extract<T, U> = Any 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 package space.kscience.kmath.estree
import space.kscience.kmath.ast.*
import space.kscience.kmath.complex.ComplexField import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.toComplex import space.kscience.kmath.complex.toComplex
import space.kscience.kmath.misc.Symbol import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.ByteRing import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class TestESTreeConsistencyWithInterpreter { internal class TestESTreeConsistencyWithInterpreter {
@Test @Test
fun mstSpace() { fun mstSpace() {
val mst = MstGroup { val mst = MstGroup {
binaryOperationFunction("+")( binaryOperationFunction("+")(
unaryOperationFunction("+")( unaryOperationFunction("+")(
@ -25,12 +29,12 @@ internal class TestESTreeConsistencyWithInterpreter {
), ),
number(1) number(1)
) + bindSymbol("x") + zero ) + bindSymbol(x) + zero
} }
assertEquals( assertEquals(
mst.interpret(MstGroup, Symbol.x to MST.Numeric(2)), mst.interpret(MstGroup, x to MST.Numeric(2)),
mst.compile(MstGroup, Symbol.x to MST.Numeric(2)) mst.compile(MstGroup, x to MST.Numeric(2))
) )
} }
@ -39,7 +43,7 @@ internal class TestESTreeConsistencyWithInterpreter {
val mst = MstRing { val mst = MstRing {
binaryOperationFunction("+")( binaryOperationFunction("+")(
unaryOperationFunction("+")( unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (scale( (bindSymbol(x) - (2.toByte() + (scale(
add(number(1), number(1)), add(number(1), number(1)),
2.0 2.0
) + 1.toByte()))) * 3.0 - 1.toByte() ) + 1.toByte()))) * 3.0 - 1.toByte()
@ -50,24 +54,24 @@ internal class TestESTreeConsistencyWithInterpreter {
} }
assertEquals( assertEquals(
mst.interpret(ByteRing, Symbol.x to 3.toByte()), mst.interpret(ByteRing, x to 3.toByte()),
mst.compile(ByteRing, Symbol.x to 3.toByte()) mst.compile(ByteRing, x to 3.toByte())
) )
} }
@Test @Test
fun realField() { fun doubleField() {
val mst = MstField { val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 (3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1), + number(1),
number(1) / 2 + number(2.0) * one number(1) / 2 + number(2.0) * one
) + zero ) + zero
} }
assertEquals( assertEquals(
mst.interpret(DoubleField, Symbol.x to 2.0), mst.interpret(DoubleField, x to 2.0),
mst.compile(DoubleField, Symbol.x to 2.0) mst.compile(DoubleField, x to 2.0)
) )
} }
@ -75,15 +79,19 @@ internal class TestESTreeConsistencyWithInterpreter {
fun complexField() { fun complexField() {
val mst = MstField { val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 (3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1), + number(1),
number(1) / 2 + number(2.0) * one number(1) / 2 + number(2.0) * one
) + zero ) + zero
} }
assertEquals( assertEquals(
mst.interpret(ComplexField, Symbol.x to 2.0.toComplex()), mst.interpret(ComplexField, x to 2.0.toComplex()),
mst.compile(ComplexField, Symbol.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 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.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.random.Random
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class TestESTreeOperationsSupport { internal class TestESTreeOperationsSupport {
@Test @Test
fun testUnaryOperationInvocation() { fun testUnaryOperationInvocation() {
val expression = MstExtendedField { -bindSymbol("x") }.compileToExpression(DoubleField) val expression = MstGroup { -bindSymbol(x) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0) val res = expression(x to 2.0)
assertEquals(-2.0, res) assertEquals(-2.0, res)
} }
@Test @Test
fun testBinaryOperationInvocation() { fun testBinaryOperationInvocation() {
val expression = MstExtendedField { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField) val expression = MstGroup { -bindSymbol(x) + number(1.0) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0) val res = expression(x to 2.0)
assertEquals(-1.0, res) assertEquals(-1.0, res)
} }
@Test @Test
fun testConstProductInvocation() { fun testConstProductInvocation() {
val res = 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) assertEquals(4.0, res)
} }
@Test private companion object {
fun testMultipleCalls() { private val x by symbol
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)
} }
} }

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 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.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -10,55 +17,60 @@ import kotlin.test.assertEquals
internal class TestESTreeSpecialization { internal class TestESTreeSpecialization {
@Test @Test
fun testUnaryPlus() { fun testUnaryPlus() {
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField) val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(2.0, expr("x" to 2.0)) assertEquals(2.0, expr(x to 2.0))
} }
@Test @Test
fun testUnaryMinus() { fun testUnaryMinus() {
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField) val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr("x" to 2.0)) assertEquals(-2.0, expr(x to 2.0))
} }
@Test @Test
fun testAdd() { fun testAdd() {
val expr = MstExtendedField { val expr = MstExtendedField {
binaryOperationFunction("+")(bindSymbol("x"), binaryOperationFunction("+")(
bindSymbol("x")) bindSymbol(x),
bindSymbol(x),
)
}.compileToExpression(DoubleField) }.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0)) assertEquals(4.0, expr(x to 2.0))
} }
@Test @Test
fun testSine() { fun testSine() {
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField) val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 0.0)) assertEquals(0.0, expr(x to 0.0))
} }
@Test @Test
fun testMinus() { fun testSubtract() {
val expr = MstExtendedField { val expr = MstExtendedField {
binaryOperationFunction("-")(bindSymbol("x"), binaryOperationFunction("-")(bindSymbol(x),
bindSymbol("x")) bindSymbol(x))
}.compileToExpression(DoubleField) }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 2.0)) assertEquals(0.0, expr(x to 2.0))
} }
@Test @Test
fun testDivide() { fun testDivide() {
val expr = MstExtendedField { val expr = MstExtendedField {
binaryOperationFunction("/")(bindSymbol("x"), binaryOperationFunction("/")(bindSymbol(x), bindSymbol(x))
bindSymbol("x"))
}.compileToExpression(DoubleField) }.compileToExpression(DoubleField)
assertEquals(1.0, expr("x" to 2.0)) assertEquals(1.0, expr(x to 2.0))
} }
@Test @Test
fun testPower() { fun testPower() {
val expr = MstExtendedField { val expr = MstExtendedField {
binaryOperationFunction("pow")(bindSymbol("x"), number(2)) binaryOperationFunction("pow")(bindSymbol(x), number(2))
}.compileToExpression(DoubleField) }.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 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.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.ByteRing import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -11,13 +18,17 @@ import kotlin.test.assertFailsWith
internal class TestESTreeVariables { internal class TestESTreeVariables {
@Test @Test
fun testVariable() { fun testVariable() {
val expr = MstRing{ bindSymbol("x") }.compileToExpression(ByteRing) val expr = MstRing { bindSymbol(x) }.compileToExpression(ByteRing)
assertEquals(1.toByte(), expr("x" to 1.toByte())) assertEquals(1.toByte(), expr(x to 1.toByte()))
} }
@Test @Test
fun testUndefinedVariableFails() { fun testUndefinedVariableFails() {
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing) val expr = MstRing { bindSymbol(x) }.compileToExpression(ByteRing)
assertFailsWith<NoSuchElementException> { expr() } 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 package space.kscience.kmath.asm
import space.kscience.kmath.asm.internal.AsmBuilder import space.kscience.kmath.asm.internal.AsmBuilder
import space.kscience.kmath.asm.internal.buildName import space.kscience.kmath.asm.internal.buildName
import space.kscience.kmath.ast.MST
import space.kscience.kmath.ast.MST.*
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.expressions.MST.*
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.Symbol import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.Algebra 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 { is Unary -> when {
algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant( algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant(
algebra.unaryOperationFunction(node.operation)(algebra.number(node.value.value))) algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value)))
else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) } else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) }
} }
is Binary -> when { is Binary -> when {
algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant( algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant(
algebra.binaryOperationFunction(node.operation) algebra.binaryOperationFunction(node.operation).invoke(
.invoke(algebra.number(node.left.value), algebra.number(node.right.value)) algebra.number((node.left as Numeric).value),
algebra.number((node.right as Numeric).value)
)
) )
algebra is NumericAlgebra && node.left is Numeric -> buildCall( algebra is NumericAlgebra && node.left is Numeric -> buildCall(
@ -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]. * 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) compileWith(T::class.java, algebra)
/** /**
* Compile given MST to expression and evaluate it against [arguments] * 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) compileToExpression(algebra).invoke(arguments)
/** /**
* Compile given MST to expression and evaluate it against [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) 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 package space.kscience.kmath.asm.internal
import org.objectweb.asm.* import org.objectweb.asm.*
@ -5,8 +10,8 @@ import org.objectweb.asm.Opcodes.*
import org.objectweb.asm.Type.* import org.objectweb.asm.Type.*
import org.objectweb.asm.commons.InstructionAdapter import org.objectweb.asm.commons.InstructionAdapter
import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader
import space.kscience.kmath.ast.MST
import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import java.lang.invoke.MethodHandles import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType import java.lang.invoke.MethodType
import java.util.stream.Collectors.toMap import java.util.stream.Collectors.toMap

View File

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

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") @file:JvmName("MapIntrinsics")
package space.kscience.kmath.asm.internal 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 package space.kscience.kmath.asm
import space.kscience.kmath.ast.*
import space.kscience.kmath.complex.ComplexField import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.toComplex import space.kscience.kmath.complex.toComplex
import space.kscience.kmath.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.ByteRing
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class TestAsmConsistencyWithInterpreter { internal class TestAsmConsistencyWithInterpreter {
@Test @Test
fun mstSpace() { fun mstSpace() {
val mst = MstGroup { val mst = MstGroup {
binaryOperationFunction("+")( binaryOperationFunction("+")(
unaryOperationFunction("+")( unaryOperationFunction("+")(
@ -25,7 +29,7 @@ internal class TestAsmConsistencyWithInterpreter {
), ),
number(1) number(1)
) + bindSymbol("x") + zero ) + bindSymbol(x) + zero
} }
assertEquals( assertEquals(
@ -39,7 +43,7 @@ internal class TestAsmConsistencyWithInterpreter {
val mst = MstRing { val mst = MstRing {
binaryOperationFunction("+")( binaryOperationFunction("+")(
unaryOperationFunction("+")( unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (scale( (bindSymbol(x) - (2.toByte() + (scale(
add(number(1), number(1)), add(number(1), number(1)),
2.0 2.0
) + 1.toByte()))) * 3.0 - 1.toByte() ) + 1.toByte()))) * 3.0 - 1.toByte()
@ -56,10 +60,10 @@ internal class TestAsmConsistencyWithInterpreter {
} }
@Test @Test
fun realField() { fun doubleField() {
val mst = MstField { val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 (3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1), + number(1),
number(1) / 2 + number(2.0) * one number(1) / 2 + number(2.0) * one
) + zero ) + zero
@ -75,7 +79,7 @@ internal class TestAsmConsistencyWithInterpreter {
fun complexField() { fun complexField() {
val mst = MstField { val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 (3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1), + number(1),
number(1) / 2 + number(2.0) * one number(1) / 2 + number(2.0) * one
) + zero ) + zero
@ -86,4 +90,8 @@ internal class TestAsmConsistencyWithInterpreter {
mst.compile(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,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 package space.kscience.kmath.asm
import space.kscience.kmath.ast.MstExtendedField import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.ast.MstField import space.kscience.kmath.expressions.MstGroup
import space.kscience.kmath.ast.MstGroup
import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.random.Random
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class TestAsmOperationsSupport { internal class TestAsmOperationsSupport {
@Test @Test
fun testUnaryOperationInvocation() { fun testUnaryOperationInvocation() {
val expression = MstGroup { -bindSymbol("x") }.compileToExpression(DoubleField) val expression = MstGroup { -bindSymbol(x) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0) val res = expression(x to 2.0)
assertEquals(-2.0, res) assertEquals(-2.0, res)
} }
@Test @Test
fun testBinaryOperationInvocation() { fun testBinaryOperationInvocation() {
val expression = MstGroup { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField) val expression = MstGroup { -bindSymbol(x) + number(1.0) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0) val res = expression(x to 2.0)
assertEquals(-1.0, res) assertEquals(-1.0, res)
} }
@Test @Test
fun testConstProductInvocation() { fun testConstProductInvocation() {
val res = 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) assertEquals(4.0, res)
} }
@Test private companion object {
fun testMultipleCalls() { private val x by symbol
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)
} }
} }

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 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.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -10,55 +17,60 @@ import kotlin.test.assertEquals
internal class TestAsmSpecialization { internal class TestAsmSpecialization {
@Test @Test
fun testUnaryPlus() { fun testUnaryPlus() {
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol("x")) }.compileToExpression(DoubleField) val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(2.0, expr("x" to 2.0)) assertEquals(2.0, expr(x to 2.0))
} }
@Test @Test
fun testUnaryMinus() { fun testUnaryMinus() {
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol("x")) }.compileToExpression(DoubleField) val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr("x" to 2.0)) assertEquals(-2.0, expr(x to 2.0))
} }
@Test @Test
fun testAdd() { fun testAdd() {
val expr = MstExtendedField { val expr = MstExtendedField {
binaryOperationFunction("+")(bindSymbol("x"), binaryOperationFunction("+")(
bindSymbol("x")) bindSymbol(x),
bindSymbol(x),
)
}.compileToExpression(DoubleField) }.compileToExpression(DoubleField)
assertEquals(4.0, expr("x" to 2.0)) assertEquals(4.0, expr(x to 2.0))
} }
@Test @Test
fun testSine() { fun testSine() {
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol("x")) }.compileToExpression(DoubleField) val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 0.0)) assertEquals(0.0, expr(x to 0.0))
} }
@Test @Test
fun testMinus() { fun testSubtract() {
val expr = MstExtendedField { val expr = MstExtendedField {
binaryOperationFunction("-")(bindSymbol("x"), binaryOperationFunction("-")(bindSymbol(x),
bindSymbol("x")) bindSymbol(x))
}.compileToExpression(DoubleField) }.compileToExpression(DoubleField)
assertEquals(0.0, expr("x" to 2.0)) assertEquals(0.0, expr(x to 2.0))
} }
@Test @Test
fun testDivide() { fun testDivide() {
val expr = MstExtendedField { val expr = MstExtendedField {
binaryOperationFunction("/")(bindSymbol("x"), binaryOperationFunction("/")(bindSymbol(x), bindSymbol(x))
bindSymbol("x"))
}.compileToExpression(DoubleField) }.compileToExpression(DoubleField)
assertEquals(1.0, expr("x" to 2.0)) assertEquals(1.0, expr(x to 2.0))
} }
@Test @Test
fun testPower() { fun testPower() {
val expr = MstExtendedField { val expr = MstExtendedField {
binaryOperationFunction("pow")(bindSymbol("x"), number(2)) binaryOperationFunction("pow")(bindSymbol(x), number(2))
}.compileToExpression(DoubleField) }.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 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.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.ByteRing import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -11,13 +18,17 @@ import kotlin.test.assertFailsWith
internal class TestAsmVariables { internal class TestAsmVariables {
@Test @Test
fun testVariable() { fun testVariable() {
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing) val expr = MstRing { bindSymbol(x) }.compileToExpression(ByteRing)
assertEquals(1.toByte(), expr("x" to 1.toByte())) assertEquals(1.toByte(), expr(x to 1.toByte()))
} }
@Test @Test
fun testUndefinedVariableFails() { fun testUndefinedVariableFails() {
val expr = MstRing { bindSymbol("x") }.compileToExpression(ByteRing) val expr = MstRing { bindSymbol(x) }.compileToExpression(ByteRing)
assertFailsWith<NoSuchElementException> { expr() } assertFailsWith<NoSuchElementException> { expr() }
} }
private companion object {
private val x by symbol
}
} }

View File

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

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