forked from kscience/kmath
Fix minor problems, update README
This commit is contained in:
parent
c738fb1f2a
commit
d631c048c7
@ -38,7 +38,9 @@ This subproject implements the following features:
|
||||
> ```
|
||||
>
|
||||
|
||||
## Dynamic Expression Code Generation with ObjectWeb ASM
|
||||
## 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.
|
||||
@ -55,19 +57,20 @@ RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
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.operations.RealField;
|
||||
import kscience.kmath.expressions.Symbol;
|
||||
|
||||
public final class AsmCompiledExpression_1073786867_0 implements Expression<Double> {
|
||||
private final RealField algebra;
|
||||
public final class AsmCompiledExpression_45045_0 implements Expression<Double> {
|
||||
private final Object[] constants;
|
||||
|
||||
public final Double invoke(Map<String, ? extends Double> arguments) {
|
||||
return (Double)this.algebra.add(((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(), 2.0D);
|
||||
public final Double invoke(Map<Symbol, Double> arguments) {
|
||||
return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2);
|
||||
}
|
||||
|
||||
public AsmCompiledExpression_1073786867_0(RealField algebra) {
|
||||
this.algebra = algebra;
|
||||
public AsmCompiledExpression_45045_0(Object[] constants) {
|
||||
this.constants = constants;
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,10 +85,30 @@ RealField.mstInField { symbol("x") + 2 }.compile()
|
||||
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
|
||||
class loading overhead.
|
||||
- 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
|
||||
|
||||
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.
|
||||
|
@ -27,7 +27,9 @@ public object MstSpace : Space<MST>, NumericAlgebra<MST> {
|
||||
public override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION)(a, b)
|
||||
public override operator fun MST.unaryPlus(): MST.Unary = unaryOperation(SpaceOperations.PLUS_OPERATION)(this)
|
||||
public override operator fun MST.unaryMinus(): MST.Unary = unaryOperation(SpaceOperations.MINUS_OPERATION)(this)
|
||||
public override operator fun MST.minus(b: MST): MST.Binary = binaryOperation(SpaceOperations.MINUS_OPERATION)(this, b)
|
||||
|
||||
public override operator fun MST.minus(b: MST): MST.Binary =
|
||||
binaryOperation(SpaceOperations.MINUS_OPERATION)(this, b)
|
||||
|
||||
public override fun multiply(a: MST, k: Number): MST.Binary =
|
||||
binaryOperation(RingOperations.TIMES_OPERATION)(a, number(k))
|
||||
|
@ -2,13 +2,16 @@ package kscience.kmath.asm.internal
|
||||
|
||||
import kscience.kmath.asm.internal.AsmBuilder.ClassLoader
|
||||
import kscience.kmath.ast.MST
|
||||
import kscience.kmath.ast.mstInField
|
||||
import kscience.kmath.expressions.Expression
|
||||
import kscience.kmath.operations.RealField
|
||||
import org.objectweb.asm.*
|
||||
import org.objectweb.asm.Opcodes.*
|
||||
import org.objectweb.asm.Type.*
|
||||
import org.objectweb.asm.commons.InstructionAdapter
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.stream.Collectors.toMap
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
@ -82,7 +85,7 @@ internal class AsmBuilder<T>(
|
||||
ACC_PUBLIC or ACC_FINAL,
|
||||
"invoke",
|
||||
getMethodDescriptor(tType, MAP_TYPE),
|
||||
"(L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}",
|
||||
"(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}${if (Modifier.isFinal(classOfT.modifiers)) "" else "+"}${tType.descriptor}>;)${tType.descriptor}",
|
||||
null,
|
||||
).instructionAdapter {
|
||||
invokeMethodVisitor = this
|
||||
@ -159,7 +162,7 @@ internal class AsmBuilder<T>(
|
||||
"<init>",
|
||||
getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }),
|
||||
null,
|
||||
null
|
||||
null,
|
||||
).instructionAdapter {
|
||||
val l0 = label()
|
||||
load(0, classType)
|
||||
@ -190,6 +193,7 @@ internal class AsmBuilder<T>(
|
||||
}
|
||||
|
||||
val cls = classLoader.defineClass(className, classWriter.toByteArray())
|
||||
java.io.File("dump.class").writeBytes(classWriter.toByteArray())
|
||||
val l = MethodHandles.publicLookup()
|
||||
|
||||
if (hasConstants)
|
||||
@ -334,5 +338,10 @@ internal class AsmBuilder<T>(
|
||||
* ASM type for MapIntrinsics.
|
||||
*/
|
||||
val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("kscience/kmath/asm/internal/MapIntrinsics") }
|
||||
|
||||
/**
|
||||
* ASM Type for [kscience.kmath.expressions.Symbol].
|
||||
*/
|
||||
val SYMBOL_TYPE: Type by lazy { getObjectType("kscience/kmath/expressions/Symbol") }
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,6 @@ package kscience.kmath.ast
|
||||
|
||||
import kscience.kmath.asm.compile
|
||||
import kscience.kmath.asm.expression
|
||||
import kscience.kmath.ast.mstInField
|
||||
import kscience.kmath.ast.parseMath
|
||||
import kscience.kmath.expressions.invoke
|
||||
import kscience.kmath.operations.Complex
|
||||
import kscience.kmath.operations.ComplexField
|
||||
|
@ -1,7 +1,5 @@
|
||||
package kscience.kmath.ast
|
||||
|
||||
import kscience.kmath.ast.evaluate
|
||||
import kscience.kmath.ast.parseMath
|
||||
import kscience.kmath.operations.Field
|
||||
import kscience.kmath.operations.RealField
|
||||
import kotlin.test.Test
|
||||
|
@ -275,12 +275,12 @@ public interface SpaceOperations<T> : Algebra<T> {
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* The identifier of addition and unary positive.
|
||||
* The identifier of addition and unary positive operator.
|
||||
*/
|
||||
public const val PLUS_OPERATION: String = "+"
|
||||
|
||||
/**
|
||||
* The identifier of subtraction and unary negation.
|
||||
* The identifier of subtraction and unary negative operator.
|
||||
*/
|
||||
public const val MINUS_OPERATION: String = "-"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user