kmath-ast
Performance and visualization extensions to MST API.
src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt : Expression language and its parser
src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt : Dynamic MST to JVM bytecode compiler
src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt : Dynamic MST to JS compiler
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-8
.
Gradle:
repositories {
maven { url 'https://repo.kotlin.link' }
mavenCentral()
}
dependencies {
implementation 'space.kscience:kmath-ast:0.3.0-dev-8'
}
Gradle Kotlin DSL:
repositories {
maven("https://repo.kotlin.link")
mavenCentral()
}
dependencies {
implementation("space.kscience:kmath-ast:0.3.0-dev-8")
}
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:
import space.kscience.kmath.expressions.*
import space.kscience.kmath.operations.*
import space.kscience.kmath.asm.*
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
... leads to generation of bytecode, which can be decompiled to the following Java class:
package space.kscience.kmath.asm.generated;
import java.util.Map;
import kotlin.jvm.functions.Function2;
import space.kscience.kmath.asm.internal.MapIntrinsics;
import space.kscience.kmath.expressions.Expression;
import space.kscience.kmath.expressions.Symbol;
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
private final Object[] constants;
public final Double invoke(Map<Symbol, ? extends Double> arguments) {
return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2);
}
public AsmCompiledExpression_45045_0(Object[] constants) {
this.constants = constants;
}
}
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.
import space.kscience.kmath.expressions.*
import space.kscience.kmath.operations.*
import space.kscience.kmath.estree.*
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
The code above returns expression implemented with such a JS function:
var executable = function (constants, arguments) {
return constants[1](constants[0](arguments, "x"), 2);
};
JS also supports very experimental expression optimization with WebAssembly IR generation. Currently, only expressions inside DoubleField
and IntRing
are supported.
import space.kscience.kmath.expressions.*
import space.kscience.kmath.operations.*
import space.kscience.kmath.wasm.*
MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField)
An example of emitted Wasm IR in the form of WAT:
(func $executable (param $0 f64) (result f64)
(f64.add
(local.get $0)
(f64.const 2)
)
)
Known issues
ESTree expression compilation uses
eval
which can be unavailable in several environments.WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).
Rendering expressions
kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.
Example usage:
import space.kscience.kmath.ast.*
import space.kscience.kmath.ast.rendering.*
import space.kscience.kmath.misc.*