|
1 | 1 | # Module kmath-ast |
2 | 2 |
|
3 | | -Performance and visualization extensions to MST API. |
| 3 | +Extensions to MST API: transformations, dynamic compilation and visualization. |
4 | 4 |
|
5 | 5 | ${features} |
6 | 6 |
|
7 | 7 | ${artifact} |
8 | 8 |
|
| 9 | +## Parsing expressions |
| 10 | + |
| 11 | +In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances. |
| 12 | + |
| 13 | +Supported literals: |
| 14 | +1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`. |
| 15 | +2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`—all parsed either as `kotlin.Long` or `kotlin.Double`. |
| 16 | + |
| 17 | +Supported binary operators (from the highest precedence to the lowest one): |
| 18 | +1. `^` |
| 19 | +2. `*`, `/` |
| 20 | +3. `+`, `-` |
| 21 | + |
| 22 | +Supported unary operator: |
| 23 | +1. `-`, e. g. `-x` |
| 24 | + |
| 25 | +Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples: |
| 26 | +1. `sin(x)` |
| 27 | +2. `add(x, y)` |
| 28 | + |
9 | 29 | ## Dynamic expression code generation |
10 | 30 |
|
11 | 31 | ### On JVM |
12 | 32 |
|
13 | 33 | `kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a |
14 | 34 | special implementation of `Expression<T>` with implemented `invoke` function. |
15 | 35 |
|
16 | | -For example, the following builder: |
| 36 | +For example, the following code: |
17 | 37 |
|
18 | 38 | ```kotlin |
19 | | -import space.kscience.kmath.expressions.Symbol.Companion.x |
20 | | -import space.kscience.kmath.expressions.* |
21 | | -import space.kscience.kmath.operations.* |
22 | | -import space.kscience.kmath.asm.* |
| 39 | +import space.kscience.kmath.asm.compileToExpression |
| 40 | +import space.kscience.kmath.operations.DoubleField |
23 | 41 |
|
24 | | -MstField { x + 2 }.compileToExpression(DoubleField) |
25 | | -``` |
| 42 | +"x^3-x+3".parseMath().compileToExpression(DoubleField) |
| 43 | +``` |
26 | 44 |
|
27 | | -... leads to generation of bytecode, which can be decompiled to the following Java class: |
| 45 | +… leads to generation of bytecode, which can be decompiled to the following Java class: |
28 | 46 |
|
29 | 47 | ```java |
30 | | -package space.kscience.kmath.asm.generated; |
| 48 | +import java.util.*; |
| 49 | +import kotlin.jvm.functions.*; |
| 50 | +import space.kscience.kmath.asm.internal.*; |
| 51 | +import space.kscience.kmath.complex.*; |
| 52 | +import space.kscience.kmath.expressions.*; |
| 53 | + |
| 54 | +public final class CompiledExpression_45045_0 implements Expression<Complex> { |
| 55 | + private final Object[] constants; |
31 | 56 |
|
32 | | -import java.util.Map; |
| 57 | + public Complex invoke(Map<Symbol, ? extends Complex> arguments) { |
| 58 | + Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x"); |
| 59 | + return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]); |
| 60 | + } |
| 61 | +} |
| 62 | +``` |
33 | 63 |
|
34 | | -import kotlin.jvm.functions.Function2; |
35 | | -import space.kscience.kmath.asm.internal.MapIntrinsics; |
36 | | -import space.kscience.kmath.expressions.Expression; |
37 | | -import space.kscience.kmath.expressions.Symbol; |
| 64 | +For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: |
38 | 65 |
|
39 | | -public final class AsmCompiledExpression_45045_0 implements Expression<Double> { |
40 | | - private final Object[] constants; |
| 66 | +```java |
| 67 | +import java.util.*; |
| 68 | +import space.kscience.kmath.asm.internal.*; |
| 69 | +import space.kscience.kmath.expressions.*; |
41 | 70 |
|
42 | | - public final Double invoke(Map<Symbol, ? extends Double> arguments) { |
43 | | - return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2); |
| 71 | +public final class CompiledExpression_-386104628_0 implements DoubleExpression { |
| 72 | + private final SymbolIndexer indexer; |
| 73 | + |
| 74 | + public SymbolIndexer getIndexer() { |
| 75 | + return this.indexer; |
44 | 76 | } |
45 | 77 |
|
46 | | - public AsmCompiledExpression_45045_0(Object[] constants) { |
47 | | - this.constants = constants; |
| 78 | + public double invoke(double[] arguments) { |
| 79 | + double var2 = arguments[0]; |
| 80 | + return Math.pow(var2, 3.0D) - var2 + 3.0D; |
48 | 81 | } |
49 | | -} |
50 | 82 |
|
| 83 | + public final Double invoke(Map<Symbol, ? extends Double> arguments) { |
| 84 | + double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); |
| 85 | + return Math.pow(var2, 3.0D) - var2 + 3.0D; |
| 86 | + } |
| 87 | +} |
51 | 88 | ``` |
52 | 89 |
|
53 | | -#### Known issues |
| 90 | +Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. |
| 91 | + |
| 92 | +#### Limitations |
54 | 93 |
|
55 | | -- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class |
56 | | - loading overhead. |
57 | | -- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. |
| 94 | +- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead. |
| 95 | +- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders. |
58 | 96 |
|
59 | 97 | ### On JS |
60 | 98 |
|
@@ -100,7 +138,7 @@ An example of emitted Wasm IR in the form of WAT: |
100 | 138 | ) |
101 | 139 | ``` |
102 | 140 |
|
103 | | -#### Known issues |
| 141 | +#### Limitations |
104 | 142 |
|
105 | 143 | - ESTree expression compilation uses `eval` which can be unavailable in several environments. |
106 | 144 | - WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/). |
|
0 commit comments