Provide dynamic operations currying for Algebra<T> instead of eager calls and add JS code generation support #162

Merged
CommanderTvis merged 44 commits from feature/dynamic-ops-currying into dev 2021-01-05 16:36:51 +03:00
4 changed files with 154 additions and 20 deletions
Showing only changes of commit 50b62f8a3b - Show all commits

View File

@ -89,7 +89,16 @@ submit a feature request if you want something to be implemented first.
* ### [kmath-ast](kmath-ast) * ### [kmath-ast](kmath-ast)
> >
> >
> **Maturity**: EXPERIMENTAL > **Maturity**: PROTOTYPE
>
> **Features:**
> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
<hr/> <hr/>
* ### [kmath-commons](kmath-commons) * ### [kmath-commons](kmath-commons)
@ -122,7 +131,7 @@ submit a feature request if you want something to be implemented first.
* ### [kmath-dimensions](kmath-dimensions) * ### [kmath-dimensions](kmath-dimensions)
> >
> >
> **Maturity**: EXPERIMENTAL > **Maturity**: PROTOTYPE
<hr/> <hr/>
* ### [kmath-ejml](kmath-ejml) * ### [kmath-ejml](kmath-ejml)

View File

@ -2,56 +2,66 @@
This subproject implements the following features: This subproject implements the following features:
- Expression Language and its parser. - [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
- MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation. - [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
- Type-safe builder for MST. - [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
- Evaluating expressions by traversing MST. - [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
- [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
- [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
> #### Artifact: > #### Artifact:
> This module is distributed in the artifact `kscience.kmath:kmath-ast:0.1.4-dev-8`. >
> > This module artifact: `kscience.kmath:kmath-ast:0.2.0-dev-4`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
>
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-ast/_latestVersion)
>
> **Gradle:** > **Gradle:**
> >
> ```gradle > ```gradle
> repositories { > repositories {
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
> maven { url 'https://dl.bintray.com/mipt-npm/kscience' } > maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
> maven { url 'https://dl.bintray.com/mipt-npm/dev' } > maven { url 'https://dl.bintray.com/mipt-npm/dev' }
> maven { url https://dl.bintray.com/hotkeytlt/maven' } > maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
> } > }
> >
> dependencies { > dependencies {
> implementation 'kscience.kmath:kmath-ast:0.1.4-dev-8' > implementation 'kscience.kmath:kmath-ast:0.2.0-dev-4'
> } > }
> ``` > ```
> **Gradle Kotlin DSL:** > **Gradle Kotlin DSL:**
> >
> ```kotlin > ```kotlin
> repositories { > repositories {
> maven("https://dl.bintray.com/kotlin/kotlin-eap")
> maven("https://dl.bintray.com/mipt-npm/kscience") > maven("https://dl.bintray.com/mipt-npm/kscience")
> maven("https://dl.bintray.com/mipt-npm/dev") > maven("https://dl.bintray.com/mipt-npm/dev")
> maven("https://dl.bintray.com/hotkeytlt/maven") > maven("https://dl.bintray.com/hotkeytlt/maven")
> } > }
> >
> dependencies { > dependencies {
> implementation("kscience.kmath:kmath-ast:0.1.4-dev-8") > implementation("kscience.kmath:kmath-ast:0.2.0-dev-4")
> } > }
> ``` > ```
>
## Dynamic expression code generation ## Dynamic expression code generation
### On JVM ### On JVM
`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds `kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds
a special implementation of `Expression<T>` with implemented `invoke` function. a special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder: For example, the following builder:
```kotlin ```kotlin
RealField.mstInField { symbol("x") + 2 }.compile() RealField.mstInField { symbol("x") + 2 }.compile()
``` ```
… leads to generation of bytecode, which can be decompiled to the following Java class: … leads to generation of bytecode, which can be decompiled to the following Java class:
```java ```java
package kscience.kmath.asm.generated; package kscience.kmath.asm.generated;
@ -78,7 +88,7 @@ public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
### Example Usage ### Example Usage
This API extends MST and MstExpression, so you may optimize as both of them: This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin ```kotlin
RealField.mstInField { symbol("x") + 2 }.compile() RealField.mstInField { symbol("x") + 2 }.compile()
@ -88,11 +98,9 @@ RealField.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
class loading overhead. class loading overhead.
- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. - This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders.
Contributed by [Iaroslav Postovalov](https://github.com/CommanderTvis).
### On JS ### On JS
A similar feature is also available on JS. A similar feature is also available on JS.

View File

@ -42,4 +42,41 @@ kotlin.sourceSets {
readme { readme {
maturity = Maturity.PROTOTYPE maturity = Maturity.PROTOTYPE
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(
id = "expression-language",
description = "Expression language and its parser",
ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt"
)
feature(
id = "mst",
description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
)
feature(
id = "mst-building",
description = "MST building algebraic structure",
ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt"
)
feature(
id = "mst-interpreter",
description = "MST interpreter",
ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
)
feature(
id = "mst-jvm-codegen",
description = "Dynamic MST to JVM bytecode compiler",
ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt"
)
feature(
id = "mst-js-codegen",
description = "Dynamic MST to JS compiler",
ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt"
)
} }

View File

@ -0,0 +1,80 @@
# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`)
This subproject implements the following features:
${features}
${artifact}
## Dynamic expression code generation
### On JVM
`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds
a special implementation of `Expression<T>` with implemented `invoke` function.
For example, the following builder:
```kotlin
RealField.mstInField { symbol("x") + 2 }.compile()
```
… leads to generation of bytecode, which can be decompiled to the following Java class:
```java
package kscience.kmath.asm.generated;
import java.util.Map;
import kotlin.jvm.functions.Function2;
import kscience.kmath.asm.internal.MapIntrinsics;
import kscience.kmath.expressions.Expression;
import kscience.kmath.expressions.Symbol;
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
private final Object[] constants;
public final Double invoke(Map<Symbol, Double> arguments) {
return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2);
}
public AsmCompiledExpression_45045_0(Object[] constants) {
this.constants = constants;
}
}
```
### Example Usage
This API extends MST and MstExpression, so you may optimize as both of them:
```kotlin
RealField.mstInField { symbol("x") + 2 }.compile()
RealField.expression("x+2".parseMath())
```
#### Known issues
- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
class loading overhead.
- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders.
### On JS
A similar feature is also available on JS.
```kotlin
RealField.mstInField { symbol("x") + 2 }.compile()
```
The code above returns expression implemented with such a JS function:
```js
var executable = function (constants, arguments) {
return constants[1](constants[0](arguments, "x"), 2);
};
```
#### Known issues
- This feature uses `eval` which can be unavailable in several environments.