MST compilation to WebAssembly with Binaryen, reorganize internal JS bindings, tests refactor #284

Merged
CommanderTvis merged 1 commits from commandertvis/binaryen into dev 2021-04-21 15:31:31 +03:00
66 changed files with 3451 additions and 692 deletions
Showing only changes of commit b6a57dbfd0 - Show all commits

View File

@ -76,6 +76,12 @@ KMath is a modular library. Different modules provide different features with di
<hr/>
* ### [benchmarks](benchmarks)
>
>
> **Maturity**: EXPERIMENTAL
<hr/>
* ### [examples](examples)
>
>
@ -88,12 +94,10 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: PROTOTYPE
>
> **Features:**
> - [expression-language](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
> - [mst](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
> - [mst-building](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
> - [expression-language](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
> - [rendering](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering
<hr/>
@ -266,8 +270,8 @@ repositories {
}
dependencies {
api("space.kscience:kmath-core:0.3.0-dev-6")
// api("space.kscience:kmath-core-jvm:0.3.0-dev-6") for jvm-specific version
api("space.kscience:kmath-core:0.3.0-dev-7")
// api("space.kscience:kmath-core-jvm:0.3.0-dev-7") for jvm-specific version
}
```

View File

@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("multiplatform")
kotlin("plugin.allopen")
@ -14,8 +12,6 @@ plugins {
allOpen.annotation("org.openjdk.jmh.annotations.State")
sourceSets.register("benchmarks")
repositories {
mavenCentral()
jcenter()
@ -77,43 +73,35 @@ benchmark {
register("jvm")
}
fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() {
warmups = 1
iterations = 5
iterationTime = 1000
iterationTimeUnit = "ms"
}
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
commonConfiguration()
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
commonConfiguration()
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
commonConfiguration()
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
commonConfiguration()
include("MatrixInverseBenchmark")
}
configurations.register("bigInt") {
warmups = 1 // number of warmup iterations
iterations = 3 // number of iterations
iterationTime = 500 // time in seconds per iteration
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
commonConfiguration()
include("BigIntBenchmark")
}
}
@ -121,7 +109,7 @@ benchmark {
// Fix kotlinx-benchmarks bug
afterEvaluate {
val jvmBenchmarkJar by tasks.getting(org.gradle.jvm.tasks.Jar::class) {
duplicatesStrategy = org.gradle.api.file.DuplicatesStrategy.EXCLUDE
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
@ -143,5 +131,5 @@ tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
readme {
maturity = Maturity.EXPERIMENTAL
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -11,6 +11,7 @@ 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
@ -20,50 +21,22 @@ 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)
}
fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, 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)
}
fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, 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)
}
fun asmExpression(blackhole: Blackhole) = invokeAndSum(asm, 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)
}
fun rawExpression(blackhole: Blackhole) = invokeAndSum(raw, blackhole)
private fun invokeAndSum(expr: Expression<Double>, blackhole: Blackhole) {
val random = Random(0)
var sum = 0.0
repeat(1000000) {
repeat(times) {
sum += expr(x to random.nextDouble())
}
@ -71,7 +44,23 @@ internal class ExpressionsInterpretersBenchmark {
}
private companion object {
private val algebra = DoubleField
private val x by symbol
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

@ -3,9 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import org.jetbrains.dokka.gradle.DokkaTask
import java.net.URL
plugins {
id("ru.mipt.npm.gradle.project")
}
@ -17,8 +14,7 @@ allprojects {
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/")
maven("http://logicrunch.research.it.uu.se/maven/") {
isAllowInsecureProtocol = true
}
mavenCentral()
@ -32,7 +28,7 @@ subprojects {
if (name.startsWith("kmath")) apply<MavenPublishPlugin>()
afterEvaluate {
tasks.withType<DokkaTask> {
tasks.withType<org.jetbrains.dokka.gradle.DokkaTask> {
dokkaSourceSets.all {
val readmeFile = File(this@subprojects.projectDir, "./README.md")
if (readmeFile.exists())
@ -42,7 +38,7 @@ subprojects {
"http://ejml.org/javadoc/",
"https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/",
"https://deeplearning4j.org/api/latest/"
).map { URL("${it}package-list") to URL(it) }.forEach { (a, b) ->
).map { java.net.URL("${it}package-list") to java.net.URL(it) }.forEach { (a, b) ->
externalDocumentationLink {
packageListUrl.set(a)
url.set(b)

View File

@ -3,9 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("jvm")
}
@ -64,7 +61,7 @@ kotlin.sourceSets.all {
}
}
tasks.withType<KotlinCompile> {
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions{
jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
@ -72,5 +69,5 @@ tasks.withType<KotlinCompile> {
}
readme {
maturity = Maturity.EXPERIMENTAL
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -25,5 +25,5 @@ fun main() {
val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField)
assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
assert(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0))
}

View File

@ -2,17 +2,15 @@
Abstract syntax tree expression representation and related optimizations.
- [expression-language](src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
- [mst](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
- [mst-building](src/commonMain/kotlin/space/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
- [mst-interpreter](src/commonMain/kotlin/space/kscience/kmath/ast/MST.kt) : MST interpreter
- [expression-language](src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser
- [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
- [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
- [rendering](src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering
## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-6`.
The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-7`.
**Gradle:**
```gradle
@ -23,7 +21,7 @@ repositories {
}
dependencies {
implementation 'space.kscience:kmath-ast:0.3.0-dev-6'
implementation 'space.kscience:kmath-ast:0.3.0-dev-7'
}
```
**Gradle Kotlin DSL:**
@ -35,7 +33,7 @@ repositories {
}
dependencies {
implementation("space.kscience:kmath-ast:0.3.0-dev-6")
implementation("space.kscience:kmath-ast:0.3.0-dev-7")
}
```
@ -49,10 +47,10 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder:
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
… leads to generation of bytecode, which can be decompiled to the following Java class:
leads to generation of bytecode, which can be decompiled to the following Java class:
```java
package space.kscience.kmath.asm.generated;
@ -77,15 +75,6 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
```
### Example Usage
This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
DoubleField.expression("x+2".parseMath())
```
#### Known issues
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
@ -97,7 +86,7 @@ DoubleField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
The code above returns expression implemented with such a JS function:
@ -108,9 +97,28 @@ var executable = function (constants, arguments) {
};
```
```kotlin
import space.kscience.kmath.wasm.*
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
An example of emitted WASM IR in the form of WAT:
```lisp
(func $executable (param $0 f64) (result f64)
(f64.add
(local.get $0)
(f64.const 2)
)
)
```
#### Known issues
- This feature uses `eval` which can be unavailable in several environments.
- ESTree expression compilation uses `eval` which can be unavailable in several environments.
- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).
## Rendering expressions

View File

@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
@ -41,6 +39,9 @@ kotlin.sourceSets {
jsMain {
dependencies {
implementation(npm("astring", "1.7.4"))
implementation(npm("binaryen", "100.0"))
implementation(npm("js-base64", "3.6.0"))
implementation(npm("webassembly", "0.11.0"))
}
}
@ -58,7 +59,7 @@ tasks.dokkaHtml {
}
readme {
maturity = Maturity.PROTOTYPE
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(

View File

@ -16,7 +16,7 @@ a special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder:
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
… leads to generation of bytecode, which can be decompiled to the following Java class:
@ -44,15 +44,6 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
```
### Example Usage
This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
DoubleField.expression("x+2".parseMath())
```
#### Known issues
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
@ -64,7 +55,7 @@ DoubleField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
DoubleField.mstInField { symbol("x") + 2 }.compile()
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
The code above returns expression implemented with such a JS function:
@ -75,9 +66,28 @@ var executable = function (constants, arguments) {
};
```
```kotlin
import space.kscience.kmath.wasm.*
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
```
An example of emitted WASM IR in the form of WAT:
```lisp
(func \$executable (param \$0 f64) (result f64)
(f64.add
(local.get \$0)
(f64.const 2)
)
)
```
#### Known issues
- This feature uses `eval` which can be unavailable in several environments.
- ESTree expression compilation uses `eval` which can be unavailable in several environments.
- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).
## Rendering expressions

View File

@ -1,27 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscisnce.kmath.ast
import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.toExpression
import space.kscience.kmath.misc.Symbol.Companion.x
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
class InterpretTest {
@Test
fun interpretation(){
val expr = MstField {
val x = bindSymbol(x)
x * 2.0 + number(2.0) / x - 16.0
}.toExpression(DoubleField)
expr(x to 2.2)
}
}

View File

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

View File

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

View File

@ -6,11 +6,11 @@
package space.kscience.kmath.estree
import space.kscience.kmath.estree.internal.ESTreeBuilder
import space.kscience.kmath.estree.internal.estree.BaseExpression
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.expressions.MST.*
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.internal.estree.BaseExpression
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.NumericAlgebra

View File

@ -5,9 +5,14 @@
package space.kscience.kmath.estree.internal
import space.kscience.kmath.estree.internal.astring.generate
import space.kscience.kmath.estree.internal.estree.*
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.internal.astring.generate
import space.kscience.kmath.internal.estree.*
import space.kscience.kmath.internal.estree.BaseExpression
import space.kscience.kmath.internal.estree.BlockStatement
import space.kscience.kmath.internal.estree.Program
import space.kscience.kmath.internal.estree.VariableDeclaration
import space.kscience.kmath.internal.estree.VariableDeclarator
import space.kscience.kmath.misc.Symbol
internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {

View File

@ -1,12 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.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

@ -6,9 +6,9 @@
@file:JsModule("astring")
@file:JsNonModule
package space.kscience.kmath.estree.internal.astring
package space.kscience.kmath.internal.astring
import space.kscience.kmath.estree.internal.estree.BaseNode
import space.kscience.kmath.internal.estree.BaseNode
internal external interface Options {
var indent: String?

View File

@ -0,0 +1,3 @@
package space.kscience.kmath.internal.astring
internal typealias Generator = Any

View File

@ -0,0 +1,49 @@
@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,11 @@
@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

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

View File

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

View File

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

View File

@ -0,0 +1,7 @@
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

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

View File

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

View File

@ -0,0 +1,231 @@
@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,22 @@
@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,155 @@
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,77 @@
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,67 @@
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

@ -8,18 +8,17 @@ package space.kscience.kmath.estree
import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.toComplex
import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.Symbol
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestESTreeConsistencyWithInterpreter {
@Test
fun mstSpace() {
val mst = MstGroup {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
@ -30,12 +29,12 @@ internal class TestESTreeConsistencyWithInterpreter {
),
number(1)
) + bindSymbol("x") + zero
) + bindSymbol(x) + zero
}
assertEquals(
mst.interpret(MstGroup, Symbol.x to MST.Numeric(2)),
mst.compile(MstGroup, Symbol.x to MST.Numeric(2))
mst.interpret(MstGroup, x to MST.Numeric(2)),
mst.compile(MstGroup, x to MST.Numeric(2))
)
}
@ -44,7 +43,7 @@ internal class TestESTreeConsistencyWithInterpreter {
val mst = MstRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (scale(
(bindSymbol(x) - (2.toByte() + (scale(
add(number(1), number(1)),
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
@ -55,24 +54,24 @@ internal class TestESTreeConsistencyWithInterpreter {
}
assertEquals(
mst.interpret(ByteRing, Symbol.x to 3.toByte()),
mst.compile(ByteRing, Symbol.x to 3.toByte())
mst.interpret(ByteRing, x to 3.toByte()),
mst.compile(ByteRing, x to 3.toByte())
)
}
@Test
fun realField() {
fun doubleField() {
val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
}
assertEquals(
mst.interpret(DoubleField, Symbol.x to 2.0),
mst.compile(DoubleField, Symbol.x to 2.0)
mst.interpret(DoubleField, x to 2.0),
mst.compile(DoubleField, x to 2.0)
)
}
@ -80,15 +79,19 @@ internal class TestESTreeConsistencyWithInterpreter {
fun complexField() {
val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
}
assertEquals(
mst.interpret(ComplexField, Symbol.x to 2.0.toComplex()),
mst.compile(ComplexField, Symbol.x to 2.0.toComplex())
mst.interpret(ComplexField, x to 2.0.toComplex()),
mst.compile(ComplexField, x to 2.0.toComplex()),
)
}
private companion object {
private val x by symbol
}
}

View File

@ -5,43 +5,38 @@
package space.kscience.kmath.estree
import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.MstGroup
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestESTreeOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
val expression = MstExtendedField { -bindSymbol("x") }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
val expression = MstGroup { -bindSymbol(x) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-2.0, res)
}
@Test
fun testBinaryOperationInvocation() {
val expression = MstExtendedField { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
val expression = MstGroup { -bindSymbol(x) + number(1.0) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-1.0, res)
}
@Test
fun testConstProductInvocation() {
val res = MstExtendedField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
val res = MstField { bindSymbol(x) * 2 }.compileToExpression(DoubleField)(x to 2.0)
assertEquals(4.0, res)
}
@Test
fun testMultipleCalls() {
val e =
MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
.compileToExpression(DoubleField)
val r = Random(0)
var s = 0.0
repeat(1000000) { s += e("x" to r.nextDouble()) }
println(s)
private companion object {
private val x by symbol
}
}

View File

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

View File

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

View File

@ -0,0 +1,60 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.wasm
import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.MstRing
import space.kscience.kmath.expressions.interpret
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.IntRing
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestWasmConsistencyWithInterpreter {
@Test
fun intRing() {
val mst = MstRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol(x) - (2.toByte() + (scale(
add(number(1), number(1)),
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
),
number(1)
) * number(2)
}
assertEquals(
mst.interpret(IntRing, x to 3),
mst.compile(IntRing, x to 3)
)
}
@Test
fun doubleField() {
val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
}
assertEquals(
mst.interpret(DoubleField, x to 2.0),
mst.compile(DoubleField, x to 2.0)
)
}
private companion object {
private val x by symbol
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.wasm
import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.MstGroup
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestWasmOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
val expression = MstGroup { -bindSymbol(x) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-2.0, res)
}
@Test
fun testBinaryOperationInvocation() {
val expression = MstGroup { -bindSymbol(x) + number(1.0) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-1.0, res)
}
@Test
fun testConstProductInvocation() {
val res = MstField { bindSymbol(x) * 2 }.compileToExpression(DoubleField)(x to 2.0)
assertEquals(4.0, res)
}
private companion object {
private val x by symbol
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.wasm
import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestWasmSpecialization {
@Test
fun testUnaryPlus() {
val expr = MstExtendedField { unaryOperationFunction("+")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(2.0, expr(x to 2.0))
}
@Test
fun testUnaryMinus() {
val expr = MstExtendedField { unaryOperationFunction("-")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(-2.0, expr(x to 2.0))
}
@Test
fun testAdd() {
val expr = MstExtendedField {
binaryOperationFunction("+")(
bindSymbol(x),
bindSymbol(x),
)
}.compileToExpression(DoubleField)
assertEquals(4.0, expr(x to 2.0))
}
@Test
fun testSine() {
val expr = MstExtendedField { unaryOperationFunction("sin")(bindSymbol(x)) }.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 0.0))
}
@Test
fun testSubtract() {
val expr = MstExtendedField {
binaryOperationFunction("-")(bindSymbol(x),
bindSymbol(x))
}.compileToExpression(DoubleField)
assertEquals(0.0, expr(x to 2.0))
}
@Test
fun testDivide() {
val expr = MstExtendedField {
binaryOperationFunction("/")(bindSymbol(x), bindSymbol(x))
}.compileToExpression(DoubleField)
assertEquals(1.0, expr(x to 2.0))
}
@Test
fun testPower() {
val expr = MstExtendedField {
binaryOperationFunction("pow")(bindSymbol(x), number(2))
}.compileToExpression(DoubleField)
assertEquals(4.0, expr(x to 2.0))
}
private companion object {
private val x by symbol
}
}

View File

@ -0,0 +1,48 @@
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

@ -8,18 +8,17 @@ package space.kscience.kmath.asm
import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.complex.toComplex
import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.Symbol.Companion.x
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.ByteRing
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestAsmConsistencyWithInterpreter {
@Test
fun mstSpace() {
val mst = MstGroup {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
@ -30,7 +29,7 @@ internal class TestAsmConsistencyWithInterpreter {
),
number(1)
) + bindSymbol("x") + zero
) + bindSymbol(x) + zero
}
assertEquals(
@ -44,7 +43,7 @@ internal class TestAsmConsistencyWithInterpreter {
val mst = MstRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (scale(
(bindSymbol(x) - (2.toByte() + (scale(
add(number(1), number(1)),
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
@ -61,10 +60,10 @@ internal class TestAsmConsistencyWithInterpreter {
}
@Test
fun realField() {
fun doubleField() {
val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -80,7 +79,7 @@ internal class TestAsmConsistencyWithInterpreter {
fun complexField() {
val mst = MstField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -91,4 +90,8 @@ internal class TestAsmConsistencyWithInterpreter {
mst.compile(ComplexField, x to 2.0.toComplex())
)
}
private companion object {
private val x by symbol
}
}

View File

@ -5,45 +5,38 @@
package space.kscience.kmath.asm
import space.kscience.kmath.expressions.MstExtendedField
import space.kscience.kmath.expressions.MstField
import space.kscience.kmath.expressions.MstGroup
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.bindSymbol
import space.kscience.kmath.operations.invoke
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestAsmOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
val expression = MstGroup { -bindSymbol("x") }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
val expression = MstGroup { -bindSymbol(x) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-2.0, res)
}
@Test
fun testBinaryOperationInvocation() {
val expression = MstGroup { -bindSymbol("x") + number(1.0) }.compileToExpression(DoubleField)
val res = expression("x" to 2.0)
val expression = MstGroup { -bindSymbol(x) + number(1.0) }.compileToExpression(DoubleField)
val res = expression(x to 2.0)
assertEquals(-1.0, res)
}
@Test
fun testConstProductInvocation() {
val res = MstField { bindSymbol("x") * 2 }.compileToExpression(DoubleField)("x" to 2.0)
val res = MstField { bindSymbol(x) * 2 }.compileToExpression(DoubleField)(x to 2.0)
assertEquals(4.0, res)
}
@Test
fun testMultipleCalls() {
val e =
MstExtendedField { sin(bindSymbol("x")).pow(4) - 6 * bindSymbol("x") / tanh(bindSymbol("x")) }
.compileToExpression(DoubleField)
val r = Random(0)
var s = 0.0
repeat(1000000) { s += e("x" to r.nextDouble()) }
println(s)
private companion object {
private val x by symbol
}
}

View File

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

View File

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

View File

@ -1,100 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.rendering.TestUtils.testLatex
import space.kscience.kmath.expressions.MST.Numeric
import kotlin.test.Test
internal class TestFeatures {
@Test
fun printSymbolic() = testLatex("x", "x")
@Test
fun printNumeric() {
val num = object : Number() {
override fun toByte(): Byte = throw UnsupportedOperationException()
override fun toChar(): Char = throw UnsupportedOperationException()
override fun toDouble(): Double = throw UnsupportedOperationException()
override fun toFloat(): Float = throw UnsupportedOperationException()
override fun toInt(): Int = throw UnsupportedOperationException()
override fun toLong(): Long = throw UnsupportedOperationException()
override fun toShort(): Short = throw UnsupportedOperationException()
override fun toString(): String = "foo"
}
testLatex(Numeric(num), "foo")
}
@Test
fun prettyPrintFloats() {
testLatex(Numeric(Double.NaN), "NaN")
testLatex(Numeric(Double.POSITIVE_INFINITY), "\\infty")
testLatex(Numeric(Double.NEGATIVE_INFINITY), "-\\infty")
testLatex(Numeric(1.0), "1")
testLatex(Numeric(-1.0), "-1")
testLatex(Numeric(1.42), "1.42")
testLatex(Numeric(-1.42), "-1.42")
testLatex(Numeric(1.1e10), "1.1\\times10^{10}")
testLatex(Numeric(1.1e-10), "1.1\\times10^{-10}")
testLatex(Numeric(-1.1e-10), "-1.1\\times10^{-10}")
testLatex(Numeric(-1.1e10), "-1.1\\times10^{10}")
}
@Test
fun prettyPrintIntegers() {
testLatex(Numeric(42), "42")
testLatex(Numeric(-42), "-42")
}
@Test
fun prettyPrintPi() {
testLatex("pi", "\\pi")
}
@Test
fun binaryPlus() = testLatex("2+2", "2+2")
@Test
fun binaryMinus() = testLatex("2-2", "2-2")
@Test
fun fraction() = testLatex("2/2", "\\frac{2}{2}")
@Test
fun binaryOperator() = testLatex("f(x, y)", "\\operatorname{f}\\left(x,y\\right)")
@Test
fun unaryOperator() = testLatex("f(x)", "\\operatorname{f}\\,\\left(x\\right)")
@Test
fun power() = testLatex("x^y", "x^{y}")
@Test
fun squareRoot() = testLatex("sqrt(x)", "\\sqrt{x}")
@Test
fun exponential() = testLatex("exp(x)", "e^{x}")
@Test
fun multiplication() = testLatex("x*1", "x\\times1")
@Test
fun inverseTrigonometry() {
testLatex("asin(x)", "\\operatorname{sin}^{-1}\\,\\left(x\\right)")
testLatex("asinh(x)", "\\operatorname{sinh}^{-1}\\,\\left(x\\right)")
testLatex("acos(x)", "\\operatorname{cos}^{-1}\\,\\left(x\\right)")
testLatex("acosh(x)", "\\operatorname{cosh}^{-1}\\,\\left(x\\right)")
testLatex("atan(x)", "\\operatorname{tan}^{-1}\\,\\left(x\\right)")
testLatex("atanh(x)", "\\operatorname{tanh}^{-1}\\,\\left(x\\right)")
}
// @Test
// fun unaryPlus() {
// testLatex("+1", "+1")
// testLatex("+1", "++1")
// }
}

View File

@ -1,73 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.rendering.TestUtils.testLatex
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.GroupOperations
import kotlin.test.Test
internal class TestLatex {
@Test
fun number() = testLatex("42", "42")
@Test
fun symbol() = testLatex("x", "x")
@Test
fun operatorName() = testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)")
@Test
fun specialSymbol() {
testLatex(MST.Numeric(Double.POSITIVE_INFINITY), "\\infty")
testLatex("pi", "\\pi")
}
@Test
fun operand() {
testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)")
testLatex("1+1", "1+1")
}
@Test
fun unaryOperator() = testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)")
@Test
fun unaryPlus() = testLatex(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1")
@Test
fun unaryMinus() = testLatex("-x", "-x")
@Test
fun radical() = testLatex("sqrt(x)", "\\sqrt{x}")
@Test
fun superscript() = testLatex("x^y", "x^{y}")
@Test
fun subscript() = testLatex(SubscriptSyntax("", SymbolSyntax("x"), NumberSyntax("123")), "x_{123}")
@Test
fun binaryOperator() = testLatex("f(x, y)", "\\operatorname{f}\\left(x,y\\right)")
@Test
fun binaryPlus() = testLatex("x+x", "x+x")
@Test
fun binaryMinus() = testLatex("x-x", "x-x")
@Test
fun fraction() = testLatex("x/x", "\\frac{x}{x}")
@Test
fun radicalWithIndex() = testLatex(RadicalWithIndexSyntax("", SymbolSyntax("x"), SymbolSyntax("y")), "\\sqrt[x]{y}")
@Test
fun multiplication() {
testLatex("x*1", "x\\times1")
testLatex("1*x", "1\\,x")
}
}

View File

@ -1,92 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.rendering.TestUtils.testMathML
import space.kscience.kmath.expressions.MST
import space.kscience.kmath.operations.GroupOperations
import kotlin.test.Test
internal class TestMathML {
@Test
fun number() = testMathML("42", "<mn>42</mn>")
@Test
fun symbol() = testMathML("x", "<mi>x</mi>")
@Test
fun operatorName() = testMathML(
"sin(1)",
"<mo>sin</mo><mspace width=\"0.167em\"></mspace><mfenced open=\"(\" close=\")\" separators=\"\"><mn>1</mn></mfenced>",
)
@Test
fun specialSymbol() {
testMathML(MST.Numeric(Double.POSITIVE_INFINITY), "<mo>&infin;</mo>")
testMathML("pi", "<mo>&pi;</mo>")
}
@Test
fun operand() {
testMathML(
"sin(1)",
"<mo>sin</mo><mspace width=\"0.167em\"></mspace><mfenced open=\"(\" close=\")\" separators=\"\"><mn>1</mn></mfenced>",
)
testMathML("1+1", "<mn>1</mn><mo>+</mo><mn>1</mn>")
}
@Test
fun unaryOperator() = testMathML(
"sin(1)",
"<mo>sin</mo><mspace width=\"0.167em\"></mspace><mfenced open=\"(\" close=\")\" separators=\"\"><mn>1</mn></mfenced>",
)
@Test
fun unaryPlus() =
testMathML(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "<mo>+</mo><mn>1</mn>")
@Test
fun unaryMinus() = testMathML("-x", "<mo>-</mo><mi>x</mi>")
@Test
fun radical() = testMathML("sqrt(x)", "<msqrt><mi>x</mi></msqrt>")
@Test
fun superscript() = testMathML("x^y", "<msup><mrow><mi>x</mi></mrow><mrow><mi>y</mi></mrow></msup>")
@Test
fun subscript() = testMathML(
SubscriptSyntax("", SymbolSyntax("x"), NumberSyntax("123")),
"<msub><mrow><mi>x</mi></mrow><mrow><mn>123</mn></mrow></msub>",
)
@Test
fun binaryOperator() = testMathML(
"f(x, y)",
"<mo>f</mo><mfenced open=\"(\" close=\")\" separators=\"\"><mi>x</mi><mo>,</mo><mi>y</mi></mfenced>",
)
@Test
fun binaryPlus() = testMathML("x+x", "<mi>x</mi><mo>+</mo><mi>x</mi>")
@Test
fun binaryMinus() = testMathML("x-x", "<mi>x</mi><mo>-</mo><mi>x</mi>")
@Test
fun fraction() = testMathML("x/x", "<mfrac><mrow><mi>x</mi></mrow><mrow><mi>x</mi></mrow></mfrac>")
@Test
fun radicalWithIndex() =
testMathML(RadicalWithIndexSyntax("", SymbolSyntax("x"), SymbolSyntax("y")),
"<mroot><mrow><mi>y</mi></mrow><mrow><mi>x</mi></mrow></mroot>")
@Test
fun multiplication() {
testMathML("x*1", "<mi>x</mi><mo>&times;</mo><mn>1</mn>")
testMathML("1*x", "<mn>1</mn><mspace width=\"0.167em\"></mspace><mi>x</mi>")
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.rendering.TestUtils.testLatex
import kotlin.test.Test
internal class TestStages {
@Test
fun betterMultiplication() {
testLatex("a*1", "a\\times1")
testLatex("1*(2/3)", "1\\times\\left(\\frac{2}{3}\\right)")
testLatex("1*1", "1\\times1")
testLatex("2e10", "2\\times10^{10}")
testLatex("2*x", "2\\,x")
testLatex("2*(x+1)", "2\\,\\left(x+1\\right)")
testLatex("x*y", "x\\,y")
}
@Test
fun parentheses() {
testLatex("(x+1)", "x+1")
testLatex("x*x*x", "x\\,x\\,x")
testLatex("(x+x)*x", "\\left(x+x\\right)\\,x")
testLatex("x+x*x", "x+x\\,x")
testLatex("x+x^x*x+x", "x+x^{x}\\,x+x")
testLatex("(x+x)^x+x*x", "\\left(x+x\\right)^{x}+x\\,x")
testLatex("x^(x+x)", "x^{x+x}")
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.ast.rendering
import space.kscience.kmath.ast.parseMath
import space.kscience.kmath.expressions.MST
import kotlin.test.assertEquals
internal object TestUtils {
private fun mathSyntax(mst: MST) = FeaturedMathRendererWithPostProcess.Default.render(mst)
private fun latex(mst: MST) = LatexSyntaxRenderer.renderWithStringBuilder(mathSyntax(mst))
private fun mathML(mst: MST) = MathMLSyntaxRenderer.renderWithStringBuilder(mathSyntax(mst))
internal fun testLatex(mst: MST, expectedLatex: String) = assertEquals(
expected = expectedLatex,
actual = latex(mst),
)
internal fun testLatex(expression: String, expectedLatex: String) = assertEquals(
expected = expectedLatex,
actual = latex(expression.parseMath()),
)
internal fun testLatex(expression: MathSyntax, expectedLatex: String) = assertEquals(
expected = expectedLatex,
actual = LatexSyntaxRenderer.renderWithStringBuilder(expression),
)
internal fun testMathML(mst: MST, expectedMathML: String) = assertEquals(
expected = "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mrow>$expectedMathML</mrow></math>",
actual = mathML(mst),
)
internal fun testMathML(expression: String, expectedMathML: String) = assertEquals(
expected = "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mrow>$expectedMathML</mrow></math>",
actual = mathML(expression.parseMath()),
)
internal fun testMathML(expression: MathSyntax, expectedMathML: String) = assertEquals(
expected = "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mrow>$expectedMathML</mrow></math>",
actual = MathMLSyntaxRenderer.renderWithStringBuilder(expression),
)
}

View File

@ -8,7 +8,7 @@ Complex and hypercomplex number systems in KMath.
## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-6`.
The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-7`.
**Gradle:**
```gradle
@ -19,7 +19,7 @@ repositories {
}
dependencies {
implementation 'space.kscience:kmath-complex:0.3.0-dev-6'
implementation 'space.kscience:kmath-complex:0.3.0-dev-7'
}
```
**Gradle Kotlin DSL:**
@ -31,6 +31,6 @@ repositories {
}
dependencies {
implementation("space.kscience:kmath-complex:0.3.0-dev-6")
implementation("space.kscience:kmath-complex:0.3.0-dev-7")
}
```

View File

@ -1,5 +1,3 @@
import ru.mipt.npm.gradle.Maturity
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
@ -21,7 +19,7 @@ kotlin.sourceSets {
readme {
description = "Complex numbers and quaternions."
maturity = Maturity.PROTOTYPE
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(

View File

@ -15,7 +15,7 @@ performance calculations to code generation.
## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-6`.
The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-7`.
**Gradle:**
```gradle
@ -26,7 +26,7 @@ repositories {
}
dependencies {
implementation 'space.kscience:kmath-core:0.3.0-dev-6'
implementation 'space.kscience:kmath-core:0.3.0-dev-7'
}
```
**Gradle Kotlin DSL:**
@ -38,6 +38,6 @@ repositories {
}
dependencies {
implementation("space.kscience:kmath-core:0.3.0-dev-6")
implementation("space.kscience:kmath-core:0.3.0-dev-7")
}
```

View File

@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
@ -21,7 +19,7 @@ kotlin.sourceSets {
readme {
description = "Core classes, algebra definitions, basic linear algebra"
maturity = Maturity.DEVELOPMENT
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(

View File

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

View File

@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
@ -29,5 +27,5 @@ kotlin.sourceSets {
}
readme {
maturity = Maturity.EXPERIMENTAL
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -9,7 +9,7 @@ EJML based linear algebra implementation.
## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-6`.
The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-7`.
**Gradle:**
```gradle
@ -20,7 +20,7 @@ repositories {
}
dependencies {
implementation 'space.kscience:kmath-ejml:0.3.0-dev-6'
implementation 'space.kscience:kmath-ejml:0.3.0-dev-7'
}
```
**Gradle Kotlin DSL:**
@ -32,6 +32,6 @@ repositories {
}
dependencies {
implementation("space.kscience:kmath-ejml:0.3.0-dev-6")
implementation("space.kscience:kmath-ejml:0.3.0-dev-7")
}
```

View File

@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers.
## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-6`.
The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-7`.
**Gradle:**
```gradle
@ -20,7 +20,7 @@ repositories {
}
dependencies {
implementation 'space.kscience:kmath-for-real:0.3.0-dev-6'
implementation 'space.kscience:kmath-for-real:0.3.0-dev-7'
}
```
**Gradle Kotlin DSL:**
@ -32,6 +32,6 @@ repositories {
}
dependencies {
implementation("space.kscience:kmath-for-real:0.3.0-dev-6")
implementation("space.kscience:kmath-for-real:0.3.0-dev-7")
}
```

View File

@ -11,7 +11,7 @@ Functions and interpolations.
## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-6`.
The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-7`.
**Gradle:**
```gradle
@ -22,7 +22,7 @@ repositories {
}
dependencies {
implementation 'space.kscience:kmath-functions:0.3.0-dev-6'
implementation 'space.kscience:kmath-functions:0.3.0-dev-7'
}
```
**Gradle Kotlin DSL:**
@ -34,6 +34,6 @@ repositories {
}
dependencies {
implementation("space.kscience:kmath-functions:0.3.0-dev-6")
implementation("space.kscience:kmath-functions:0.3.0-dev-7")
}
```

View File

@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
@ -17,5 +15,5 @@ kotlin.sourceSets.commonMain {
}
readme {
maturity = Maturity.PROTOTYPE
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
}

View File

@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
@ -28,5 +26,5 @@ kotlin.sourceSets {
}
readme {
maturity = Maturity.PROTOTYPE
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
}

View File

@ -10,6 +10,7 @@ import space.kscience.kmath.asm.compileToExpression
import space.kscience.kmath.ast.parseMath
import space.kscience.kmath.expressions.MstAlgebra
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.operations.DoubleField
import kotlin.test.Test
import kotlin.test.assertEquals
@ -19,8 +20,8 @@ import kotlin.test.fail
internal class AdaptingTests {
@Test
fun symbol() {
val c1 = MstAlgebra.bindSymbol("x")
assertTrue(c1.toSVar<KMathNumber<Double, DoubleField>>().name == "x")
val c1 = MstAlgebra.bindSymbol(x.identity)
assertEquals(x.identity, c1.toSVar<KMathNumber<Double, DoubleField>>().name)
val c2 = "kitten".parseMath().toSFun<KMathNumber<Double, DoubleField>>()
if (c2 is SVar) assertTrue(c2.name == "kitten") else fail()
}
@ -45,23 +46,27 @@ internal class AdaptingTests {
@Test
fun simpleFunctionDerivative() {
val x = MstAlgebra.bindSymbol("x").toSVar<KMathNumber<Double, DoubleField>>()
val xSVar = MstAlgebra.bindSymbol(x.identity).toSVar<KMathNumber<Double, DoubleField>>()
val quadratic = "x^2-4*x-44".parseMath().toSFun<KMathNumber<Double, DoubleField>>()
val actualDerivative = quadratic.d(x).toMst().compileToExpression(DoubleField)
val actualDerivative = quadratic.d(xSVar).toMst().compileToExpression(DoubleField)
val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField)
assertEquals(actualDerivative("x" to 123.0), expectedDerivative("x" to 123.0))
assertEquals(actualDerivative(x to 123.0), expectedDerivative(x to 123.0))
}
@Test
fun moreComplexDerivative() {
val x = MstAlgebra.bindSymbol("x").toSVar<KMathNumber<Double, DoubleField>>()
val xSVar = MstAlgebra.bindSymbol(x.identity).toSVar<KMathNumber<Double, DoubleField>>()
val composition = "-sqrt(sin(x^2)-cos(x)^2-16*x)".parseMath().toSFun<KMathNumber<Double, DoubleField>>()
val actualDerivative = composition.d(x).toMst().compileToExpression(DoubleField)
val actualDerivative = composition.d(xSVar).toMst().compileToExpression(DoubleField)
val expectedDerivative =
"-(2*x*cos(x^2)+2*sin(x)*cos(x)-16)/(2*sqrt(sin(x^2)-16*x-cos(x)^2))".parseMath().compileToExpression(DoubleField)
val expectedDerivative = "-(2*x*cos(x^2)+2*sin(x)*cos(x)-16)/(2*sqrt(sin(x^2)-16*x-cos(x)^2))"
.parseMath()
.compileToExpression(DoubleField)
assertEquals(actualDerivative(x to 0.1), expectedDerivative(x to 0.1))
}
assertEquals(actualDerivative("x" to 0.1), expectedDerivative("x" to 0.1))
private companion object {
private val x by symbol
}
}

View File

@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions.
## Artifact:
The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-6`.
The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-7`.
**Gradle:**
```gradle
@ -20,7 +20,7 @@ repositories {
}
dependencies {
implementation 'space.kscience:kmath-nd4j:0.3.0-dev-6'
implementation 'space.kscience:kmath-nd4j:0.3.0-dev-7'
}
```
**Gradle Kotlin DSL:**
@ -32,7 +32,7 @@ repositories {
}
dependencies {
implementation("space.kscience:kmath-nd4j:0.3.0-dev-6")
implementation("space.kscience:kmath-nd4j:0.3.0-dev-7")
}
```

View File

@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("jvm")
id("ru.mipt.npm.gradle.common")
@ -20,7 +18,7 @@ dependencies {
readme {
description = "ND4J NDStructure implementation and according NDAlgebra classes"
maturity = Maturity.EXPERIMENTAL
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(

View File

@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
@ -30,5 +28,5 @@ kotlin.sourceSets {
}
readme {
maturity = Maturity.EXPERIMENTAL
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import ru.mipt.npm.gradle.Maturity
plugins {
kotlin("jvm")
id("ru.mipt.npm.gradle.common")
@ -18,5 +16,5 @@ dependencies {
}
readme {
maturity = Maturity.DEVELOPMENT
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
}