Merge kmath-asm and kmath-ast modules, make all the ExpressionAlgebras concise and consistent, implement new-styled builders both for ASM and F. expressions

This commit is contained in:
Iaroslav 2020-06-13 02:26:12 +07:00
parent b902f3980a
commit 3ec1f7b5f1
No known key found for this signature in database
GPG Key ID: 46E15E4A31B3BCD7
17 changed files with 220 additions and 260 deletions

View File

@ -1,10 +0,0 @@
plugins {
id("scientifik.jvm")
}
dependencies {
api(project(path = ":kmath-core"))
implementation("org.ow2.asm:asm:8.0.1")
implementation("org.ow2.asm:asm-commons:8.0.1")
implementation(kotlin("reflect"))
}

View File

@ -1,74 +0,0 @@
package scientifik.kmath.expressions.asm
import scientifik.kmath.expressions.ExpressionAlgebra
import scientifik.kmath.operations.*
open class AsmExpressionAlgebra<T>(val algebra: Algebra<T>) :
Algebra<AsmExpression<T>>,
ExpressionAlgebra<T, AsmExpression<T>> {
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> =
AsmUnaryOperation(algebra, operation, arg)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, operation, left, right)
override fun const(value: T): AsmExpression<T> = AsmConstantExpression(value)
override fun variable(name: String, default: T?): AsmExpression<T> = AsmVariableExpression(name, default)
}
open class AsmExpressionSpace<T>(
val space: Space<T>
) : AsmExpressionAlgebra<T>(space), Space<AsmExpression<T>> {
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> =
AsmUnaryOperation(algebra, operation, arg)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, operation, left, right)
override val zero: AsmExpression<T> = AsmConstantExpression(space.zero)
override fun add(a: AsmExpression<T>, b: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(space, SpaceOperations.PLUS_OPERATION, a, b)
override fun multiply(a: AsmExpression<T>, k: Number): AsmExpression<T> = AsmConstProductExpression(space, a, k)
operator fun AsmExpression<T>.plus(arg: T): AsmExpression<T> = this + const(arg)
operator fun AsmExpression<T>.minus(arg: T): AsmExpression<T> = this - const(arg)
operator fun T.plus(arg: AsmExpression<T>): AsmExpression<T> = arg + this
operator fun T.minus(arg: AsmExpression<T>): AsmExpression<T> = arg - this
}
open class AsmExpressionRing<T>(private val ring: Ring<T>) : AsmExpressionSpace<T>(ring), Ring<AsmExpression<T>> {
override val one: AsmExpression<T>
get() = const(this.ring.one)
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> =
AsmUnaryOperation(algebra, operation, arg)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, operation, left, right)
override fun number(value: Number): AsmExpression<T> = const(ring { one * value })
override fun multiply(a: AsmExpression<T>, b: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(space, RingOperations.TIMES_OPERATION, a, b)
operator fun AsmExpression<T>.times(arg: T): AsmExpression<T> = this * const(arg)
operator fun T.times(arg: AsmExpression<T>): AsmExpression<T> = arg * this
}
open class AsmExpressionField<T>(private val field: Field<T>) :
AsmExpressionRing<T>(field),
Field<AsmExpression<T>> {
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> =
AsmUnaryOperation(algebra, operation, arg)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, operation, left, right)
override fun divide(a: AsmExpression<T>, b: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(field, FieldOperations.DIV_OPERATION, a, b)
operator fun AsmExpression<T>.div(arg: T): AsmExpression<T> = this / const(arg)
operator fun T.div(arg: AsmExpression<T>): AsmExpression<T> = arg / this
}

View File

@ -1,50 +0,0 @@
package scientifik.kmath.expressions.asm
import scientifik.kmath.expressions.Expression
import scientifik.kmath.expressions.ExpressionAlgebra
import scientifik.kmath.operations.*
@PublishedApi
internal fun buildName(expression: AsmExpression<*>, collision: Int = 0): String {
val name = "scientifik.kmath.expressions.generated.AsmCompiledExpression_${expression.hashCode()}_$collision"
try {
Class.forName(name)
} catch (ignored: ClassNotFoundException) {
return name
}
return buildName(expression, collision + 1)
}
inline fun <reified T, E : ExpressionAlgebra<T, AsmExpression<T>>> asm(
i: E,
algebra: Algebra<T>,
block: E.() -> AsmExpression<T>
): Expression<T> {
val expression = i.block().optimize()
val ctx = AsmGenerationContext(T::class.java, algebra, buildName(expression))
expression.invoke(ctx)
return ctx.generate()
}
inline fun <reified T> buildAsmAlgebra(
algebra: Algebra<T>,
block: AsmExpressionAlgebra<T>.() -> AsmExpression<T>
): Expression<T> = asm(AsmExpressionAlgebra(algebra), algebra, block)
inline fun <reified T> buildAsmSpace(
algebra: Space<T>,
block: AsmExpressionSpace<T>.() -> AsmExpression<T>
): Expression<T> = asm(AsmExpressionSpace(algebra), algebra, block)
inline fun <reified T> buildAsmRing(
algebra: Ring<T>,
block: AsmExpressionRing<T>.() -> AsmExpression<T>
): Expression<T> = asm(AsmExpressionRing(algebra), algebra, block)
inline fun <reified T> buildAsmField(
algebra: Field<T>,
block: AsmExpressionField<T>.() -> AsmExpression<T>
): Expression<T> = asm(AsmExpressionField(algebra), algebra, block)

View File

@ -1,43 +0,0 @@
package scientifik.kmath.expressions
import scientifik.kmath.expressions.asm.AsmExpression
import scientifik.kmath.expressions.asm.AsmExpressionField
import scientifik.kmath.expressions.asm.buildAsmField
import scientifik.kmath.operations.RealField
import kotlin.test.Test
import kotlin.test.assertEquals
class AsmTest {
private fun testDoubleExpression(
expected: Double?,
arguments: Map<String, Double> = emptyMap(),
block: AsmExpressionField<Double>.() -> AsmExpression<Double>
): Unit = assertEquals(expected = expected, actual = buildAsmField(RealField, block)(arguments))
@Test
fun testConstantsSum(): Unit = testDoubleExpression(16.0) { const(8.0) + 8.0 }
@Test
fun testVarsSum(): Unit = testDoubleExpression(1000.0, mapOf("x" to 500.0)) { variable("x") + 500.0 }
@Test
fun testProduct(): Unit = testDoubleExpression(24.0) { const(4.0) * const(6.0) }
@Test
fun testConstantProduct(): Unit = testDoubleExpression(984.0) { const(8.0) * 123 }
@Test
fun testVarsConstantProductVar(): Unit = testDoubleExpression(984.0, mapOf("x" to 8.0)) { variable("x") * 123 }
@Test
fun testSubtraction(): Unit = testDoubleExpression(2.0) { const(4.0) - 2.0 }
@Test
fun testDivision(): Unit = testDoubleExpression(64.0) { const(128.0) / 2 }
@Test
fun testDirectUnaryCall(): Unit = testDoubleExpression(64.0) { unaryOperation("+", const(64.0)) }
@Test
fun testDirectBinaryCall(): Unit = testDoubleExpression(4096.0) { binaryOperation("*", const(64.0), const(64.0)) }
}

View File

@ -1,10 +1,5 @@
plugins { plugins { id("scientifik.mpp") }
id("scientifik.mpp") repositories { maven("https://dl.bintray.com/hotkeytlt/maven") }
}
repositories{
maven("https://dl.bintray.com/hotkeytlt/maven")
}
kotlin.sourceSets { kotlin.sourceSets {
commonMain { commonMain {
@ -13,9 +8,22 @@ kotlin.sourceSets {
implementation("com.github.h0tk3y.betterParse:better-parse-multiplatform:0.4.0-alpha-3") implementation("com.github.h0tk3y.betterParse:better-parse-multiplatform:0.4.0-alpha-3")
} }
} }
jvmMain { jvmMain {
dependencies { dependencies {
implementation("com.github.h0tk3y.betterParse:better-parse-jvm:0.4.0-alpha-3") implementation("com.github.h0tk3y.betterParse:better-parse-jvm:0.4.0-alpha-3")
implementation("org.ow2.asm:asm:8.0.1")
implementation("org.ow2.asm:asm-commons:8.0.1")
implementation(kotlin("reflect"))
}
}
jvmTest {
dependencies {
implementation(kotlin("test"))
implementation(kotlin("test-junit5"))
} }
} }
} }
tasks.withType<Test> { useJUnitPlatform() }

View File

@ -1,9 +1,8 @@
package scientifik.kmath.expressions.asm package scientifik.kmath.asm
import scientifik.kmath.expressions.Expression import scientifik.kmath.expressions.Expression
import scientifik.kmath.operations.Algebra import scientifik.kmath.expressions.ExpressionAlgebra
import scientifik.kmath.operations.Space import scientifik.kmath.operations.*
import scientifik.kmath.operations.invoke
import kotlin.reflect.full.memberFunctions import kotlin.reflect.full.memberFunctions
import kotlin.reflect.jvm.jvmName import kotlin.reflect.jvm.jvmName
@ -109,11 +108,13 @@ internal class AsmBinaryOperation<T>(
} }
} }
internal class AsmVariableExpression<T>(private val name: String, private val default: T? = null) : AsmExpression<T> { internal class AsmVariableExpression<T>(private val name: String, private val default: T? = null) :
AsmExpression<T> {
override fun invoke(gen: AsmGenerationContext<T>): Unit = gen.visitLoadFromVariables(name, default) override fun invoke(gen: AsmGenerationContext<T>): Unit = gen.visitLoadFromVariables(name, default)
} }
internal class AsmConstantExpression<T>(private val value: T) : AsmExpression<T> { internal class AsmConstantExpression<T>(private val value: T) :
AsmExpression<T> {
override fun tryEvaluate(): T = value override fun tryEvaluate(): T = value
override fun invoke(gen: AsmGenerationContext<T>): Unit = gen.visitLoadFromConstants(value) override fun invoke(gen: AsmGenerationContext<T>): Unit = gen.visitLoadFromConstants(value)
} }
@ -141,9 +142,88 @@ internal class AsmConstProductExpression<T>(
} }
} }
internal class AsmNumberExpression<T>(private val context: NumericAlgebra<T>, private val value: Number) : AsmExpression<T> {
override fun tryEvaluate(): T? = context.number(value)
override fun invoke(gen: AsmGenerationContext<T>): Unit = gen.visitNumberConstant(value)
}
internal abstract class FunctionalCompiledExpression<T> internal constructor( internal abstract class FunctionalCompiledExpression<T> internal constructor(
@JvmField protected val algebra: Algebra<T>, @JvmField protected val algebra: Algebra<T>,
@JvmField protected val constants: Array<Any> @JvmField protected val constants: Array<Any>
) : Expression<T> { ) : Expression<T> {
abstract override fun invoke(arguments: Map<String, T>): T abstract override fun invoke(arguments: Map<String, T>): T
} }
interface AsmExpressionAlgebra<T, A : NumericAlgebra<T>> : NumericAlgebra<AsmExpression<T>>,
ExpressionAlgebra<T, AsmExpression<T>> {
val algebra: A
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, operation, left, right)
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> =
AsmUnaryOperation(algebra, operation, arg)
override fun number(value: Number): AsmExpression<T> = AsmNumberExpression(algebra, value)
override fun const(value: T): AsmExpression<T> = AsmConstantExpression(value)
override fun variable(name: String, default: T?): AsmExpression<T> = AsmVariableExpression(name, default)
}
open class AsmExpressionSpace<T, A>(override val algebra: A) : AsmExpressionAlgebra<T, A>,
Space<AsmExpression<T>> where A : Space<T>, A : NumericAlgebra<T> {
override val zero: AsmExpression<T>
get() = const(algebra.zero)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, operation, left, right)
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> =
AsmUnaryOperation(algebra, operation, arg)
override fun add(a: AsmExpression<T>, b: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, SpaceOperations.PLUS_OPERATION, a, b)
override fun multiply(a: AsmExpression<T>, k: Number): AsmExpression<T> = AsmConstProductExpression(algebra, a, k)
operator fun AsmExpression<T>.plus(arg: T): AsmExpression<T> = this + const(arg)
operator fun AsmExpression<T>.minus(arg: T): AsmExpression<T> = this - const(arg)
operator fun T.plus(arg: AsmExpression<T>): AsmExpression<T> = arg + this
operator fun T.minus(arg: AsmExpression<T>): AsmExpression<T> = arg - this
}
open class AsmExpressionRing<T, A>(override val algebra: A) : AsmExpressionSpace<T, A>(algebra),
Ring<AsmExpression<T>> where A : Ring<T>, A : NumericAlgebra<T> {
override val one: AsmExpression<T>
get() = const(algebra.one)
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> =
AsmUnaryOperation(algebra, operation, arg)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, operation, left, right)
override fun number(value: Number): AsmExpression<T> = const(algebra { one * value })
override fun multiply(a: AsmExpression<T>, b: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, RingOperations.TIMES_OPERATION, a, b)
operator fun AsmExpression<T>.times(arg: T): AsmExpression<T> = this * const(arg)
operator fun T.times(arg: AsmExpression<T>): AsmExpression<T> = arg * this
}
open class AsmExpressionField<T, A>(override val algebra: A) :
AsmExpressionRing<T, A>(algebra),
Field<AsmExpression<T>> where A : Field<T>, A : NumericAlgebra<T> {
override fun unaryOperation(operation: String, arg: AsmExpression<T>): AsmExpression<T> =
AsmUnaryOperation(algebra, operation, arg)
override fun binaryOperation(operation: String, left: AsmExpression<T>, right: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, operation, left, right)
override fun divide(a: AsmExpression<T>, b: AsmExpression<T>): AsmExpression<T> =
AsmBinaryOperation(algebra, FieldOperations.DIV_OPERATION, a, b)
operator fun AsmExpression<T>.div(arg: T): AsmExpression<T> = this / const(arg)
operator fun T.div(arg: AsmExpression<T>): AsmExpression<T> = arg / this
}

View File

@ -1,4 +1,4 @@
package scientifik.kmath.expressions.asm package scientifik.kmath.asm
import org.objectweb.asm.ClassWriter import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Label import org.objectweb.asm.Label
@ -15,7 +15,8 @@ class AsmGenerationContext<T>(
internal fun defineClass(name: String?, b: ByteArray): Class<*> = defineClass(name, b, 0, b.size) internal fun defineClass(name: String?, b: ByteArray): Class<*> = defineClass(name, b, 0, b.size)
} }
private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader) private val classLoader: ClassLoader =
ClassLoader(javaClass.classLoader)
@Suppress("PrivatePropertyName") @Suppress("PrivatePropertyName")
private val T_ALGEBRA_CLASS: String = algebra.javaClass.name.replace(oldChar = '.', newChar = '/') private val T_ALGEBRA_CLASS: String = algebra.javaClass.name.replace(oldChar = '.', newChar = '/')
@ -236,7 +237,8 @@ class AsmGenerationContext<T>(
} }
visitLdcInsn(name) visitLdcInsn(name)
visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_CLASS, "get", "(L$OBJECT_CLASS;)L$OBJECT_CLASS;", true) visitMethodInsn(Opcodes.INVOKEINTERFACE,
MAP_CLASS, "get", "(L$OBJECT_CLASS;)L$OBJECT_CLASS;", true)
visitCastToT() visitCastToT()
} }
@ -275,7 +277,7 @@ class AsmGenerationContext<T>(
) )
internal const val FUNCTIONAL_COMPILED_EXPRESSION_CLASS = internal const val FUNCTIONAL_COMPILED_EXPRESSION_CLASS =
"scientifik/kmath/expressions/asm/FunctionalCompiledExpression" "scientifik/kmath/asm/FunctionalCompiledExpression"
internal const val MAP_CLASS = "java/util/Map" internal const val MAP_CLASS = "java/util/Map"
internal const val OBJECT_CLASS = "java/lang/Object" internal const val OBJECT_CLASS = "java/lang/Object"

View File

@ -0,0 +1,53 @@
package scientifik.kmath.asm
import scientifik.kmath.ast.MST
import scientifik.kmath.ast.evaluate
import scientifik.kmath.expressions.Expression
import scientifik.kmath.operations.*
@PublishedApi
internal fun buildName(expression: AsmExpression<*>, collision: Int = 0): String {
val name = "scientifik.kmath.expressions.generated.AsmCompiledExpression_${expression.hashCode()}_$collision"
try {
Class.forName(name)
} catch (ignored: ClassNotFoundException) {
return name
}
return buildName(expression, collision + 1)
}
inline fun <reified T> AsmExpression<T>.compile(algebra: Algebra<T>): Expression<T> {
val ctx = AsmGenerationContext(T::class.java, algebra, buildName(this))
invoke(ctx)
return ctx.generate()
}
inline fun <reified T, A : NumericAlgebra<T>, E : AsmExpressionAlgebra<T, A>> A.asm(
expressionAlgebra: E,
block: E.() -> AsmExpression<T>
): Expression<T> = expressionAlgebra.block().compile(expressionAlgebra.algebra)
inline fun <reified T, A : NumericAlgebra<T>, E : AsmExpressionAlgebra<T, A>> A.asm(
expressionAlgebra: E,
ast: MST
): Expression<T> = asm(expressionAlgebra) { evaluate(ast) }
inline fun <reified T, A> A.asmSpace(block: AsmExpressionSpace<T, A>.() -> AsmExpression<T>): Expression<T> where A : NumericAlgebra<T>, A : Space<T> =
AsmExpressionSpace(this).let { it.block().compile(it.algebra) }
inline fun <reified T, A> A.asmSpace(ast: MST): Expression<T> where A : NumericAlgebra<T>, A : Space<T> =
asmSpace { evaluate(ast) }
inline fun <reified T, A> A.asmRing(block: AsmExpressionRing<T, A>.() -> AsmExpression<T>): Expression<T> where A : NumericAlgebra<T>, A : Ring<T> =
AsmExpressionRing(this).let { it.block().compile(it.algebra) }
inline fun <reified T, A> A.asmRing(ast: MST): Expression<T> where A : NumericAlgebra<T>, A : Ring<T> =
asmRing { evaluate(ast) }
inline fun <reified T, A> A.asmField(block: AsmExpressionField<T, A>.() -> AsmExpression<T>): Expression<T> where A : NumericAlgebra<T>, A : Field<T> =
AsmExpressionField(this).let { it.block().compile(it.algebra) }
inline fun <reified T, A> A.asmField(ast: MST): Expression<T> where A : NumericAlgebra<T>, A : Field<T> =
asmRing { evaluate(ast) }

View File

@ -1,4 +1,4 @@
package scientifik.kmath.expressions.asm package scientifik.kmath.asm
import org.objectweb.asm.MethodVisitor import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes.* import org.objectweb.asm.Opcodes.*

View File

@ -1,4 +1,4 @@
package scientifik.kmath.expressions.asm package scientifik.kmath.asm
@PublishedApi @PublishedApi
internal fun <T> AsmExpression<T>.optimize(): AsmExpression<T> { internal fun <T> AsmExpression<T>.optimize(): AsmExpression<T> {

View File

@ -1,23 +0,0 @@
package scientifik.kmath.ast
import scientifik.kmath.expressions.Expression
import scientifik.kmath.operations.Algebra
import scientifik.kmath.operations.NumericAlgebra
//TODO stubs for asm generation
interface AsmExpression<T>
interface AsmExpressionAlgebra<T, A : Algebra<T>> : NumericAlgebra<AsmExpression<T>> {
val algebra: A
}
fun <T> AsmExpression<T>.compile(): Expression<T> = TODO()
//TODO add converter for functional expressions
inline fun <reified T : Any, A : Algebra<T>> A.asm(
block: AsmExpressionAlgebra<T, A>.() -> AsmExpression<T>
): Expression<T> = TODO()
inline fun <reified T : Any, A : Algebra<T>> A.asm(ast: MST): Expression<T> = asm { evaluate(ast) }

View File

@ -0,0 +1,18 @@
package scietifik.kmath.ast
import org.junit.jupiter.api.Test
import scientifik.kmath.asm.asmField
import scientifik.kmath.ast.parseMath
import scientifik.kmath.expressions.invoke
import scientifik.kmath.operations.Complex
import scientifik.kmath.operations.ComplexField
import kotlin.test.assertEquals
class AsmTest {
@Test
fun parsedExpression() {
val mst = "2+2*(2+2)".parseMath()
val res = ComplexField.asmField(mst)()
assertEquals(Complex(10.0, 0.0), res)
}
}

View File

@ -1,11 +1,11 @@
package scietifik.kmath.ast package scietifik.kmath.ast
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import scientifik.kmath.ast.evaluate import scientifik.kmath.ast.evaluate
import scientifik.kmath.ast.parseMath import scientifik.kmath.ast.parseMath
import scientifik.kmath.operations.Complex import scientifik.kmath.operations.Complex
import scientifik.kmath.operations.ComplexField import scientifik.kmath.operations.ComplexField
import kotlin.test.assertEquals
internal class ParserTest { internal class ParserTest {
@Test @Test

View File

@ -1,30 +1,23 @@
package scientifik.kmath.expressions package scientifik.kmath.expressions
import scientifik.kmath.operations.Algebra
import scientifik.kmath.operations.Field import scientifik.kmath.operations.Field
import scientifik.kmath.operations.Ring import scientifik.kmath.operations.Ring
import scientifik.kmath.operations.Space import scientifik.kmath.operations.Space
/**
* Create a functional expression on this [Algebra]
*/
fun <T> Algebra<T>.buildExpression(block: FunctionalExpressionAlgebra<T>.() -> Expression<T>): Expression<T> =
FunctionalExpressionAlgebra(this).run(block)
/** /**
* Create a functional expression on this [Space] * Create a functional expression on this [Space]
*/ */
fun <T> Space<T>.buildExpression(block: FunctionalExpressionSpace<T>.() -> Expression<T>): Expression<T> = fun <T> Space<T>.buildExpression(block: FunctionalExpressionSpace<T, Space<T>>.() -> Expression<T>): Expression<T> =
FunctionalExpressionSpace(this).run(block) FunctionalExpressionSpace(this).run(block)
/** /**
* Create a functional expression on this [Ring] * Create a functional expression on this [Ring]
*/ */
fun <T> Ring<T>.buildExpression(block: FunctionalExpressionRing<T>.() -> Expression<T>): Expression<T> = fun <T> Ring<T>.buildExpression(block: FunctionalExpressionRing<T, Ring<T>>.() -> Expression<T>): Expression<T> =
FunctionalExpressionRing(this).run(block) FunctionalExpressionRing(this).run(block)
/** /**
* Create a functional expression on this [Field] * Create a functional expression on this [Field]
*/ */
fun <T> Field<T>.buildExpression(block: FunctionalExpressionField<T>.() -> Expression<T>): Expression<T> = fun <T> Field<T>.buildExpression(block: FunctionalExpressionField<T, Field<T>>.() -> Expression<T>): Expression<T> =
FunctionalExpressionField(this).run(block) FunctionalExpressionField(this).run(block)

View File

@ -26,48 +26,55 @@ internal class FunctionalConstantExpression<T>(val value: T) : Expression<T> {
override fun invoke(arguments: Map<String, T>): T = value override fun invoke(arguments: Map<String, T>): T = value
} }
internal class FunctionalConstProductExpression<T>(val context: Space<T>, val expr: Expression<T>, val const: Number) : internal class FunctionalConstProductExpression<T>(
val context: Space<T>,
val expr: Expression<T>,
val const: Number
) :
Expression<T> { Expression<T> {
override fun invoke(arguments: Map<String, T>): T = context.multiply(expr.invoke(arguments), const) override fun invoke(arguments: Map<String, T>): T = context.multiply(expr.invoke(arguments), const)
} }
open class FunctionalExpressionAlgebra<T>(val algebra: Algebra<T>) : interface FunctionalExpressionAlgebra<T, A : Algebra<T>> : ExpressionAlgebra<T, Expression<T>> {
Algebra<Expression<T>>, val algebra: A
ExpressionAlgebra<T, Expression<T>> {
override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> =
FunctionalUnaryOperation(algebra, operation, arg)
override fun binaryOperation(operation: String, left: Expression<T>, right: Expression<T>): Expression<T> = override fun binaryOperation(operation: String, left: Expression<T>, right: Expression<T>): Expression<T> =
FunctionalBinaryOperation(algebra, operation, left, right) FunctionalBinaryOperation(algebra, operation, left, right)
override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> =
FunctionalUnaryOperation(algebra, operation, arg)
override fun const(value: T): Expression<T> = FunctionalConstantExpression(value) override fun const(value: T): Expression<T> = FunctionalConstantExpression(value)
override fun variable(name: String, default: T?): Expression<T> = FunctionalVariableExpression(name, default) override fun variable(name: String, default: T?): Expression<T> = FunctionalVariableExpression(name, default)
} }
open class FunctionalExpressionSpace<T>(val space: Space<T>) : open class FunctionalExpressionSpace<T, A>(override val algebra: A) : FunctionalExpressionAlgebra<T, A>,
FunctionalExpressionAlgebra<T>(space), Space<Expression<T>> where A : Space<T> {
Space<Expression<T>> { override val zero: Expression<T>
override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> = get() = const(algebra.zero)
FunctionalUnaryOperation(algebra, operation, arg)
override fun binaryOperation(operation: String, left: Expression<T>, right: Expression<T>): Expression<T> = override fun binaryOperation(operation: String, left: Expression<T>, right: Expression<T>): Expression<T> =
FunctionalBinaryOperation(algebra, operation, left, right) FunctionalBinaryOperation(algebra, operation, left, right)
override val zero: Expression<T> = FunctionalConstantExpression(space.zero) override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> =
FunctionalUnaryOperation(algebra, operation, arg)
override fun add(a: Expression<T>, b: Expression<T>): Expression<T> = override fun add(a: Expression<T>, b: Expression<T>): Expression<T> =
FunctionalBinaryOperation(space, SpaceOperations.PLUS_OPERATION, a, b) FunctionalBinaryOperation(algebra, SpaceOperations.PLUS_OPERATION, a, b)
override fun multiply(a: Expression<T>, k: Number): Expression<T> =
FunctionalConstProductExpression(algebra, a, k)
override fun multiply(a: Expression<T>, k: Number): Expression<T> = FunctionalConstProductExpression(space, a, k)
operator fun Expression<T>.plus(arg: T): Expression<T> = this + const(arg) operator fun Expression<T>.plus(arg: T): Expression<T> = this + const(arg)
operator fun Expression<T>.minus(arg: T): Expression<T> = this - const(arg) operator fun Expression<T>.minus(arg: T): Expression<T> = this - const(arg)
operator fun T.plus(arg: Expression<T>): Expression<T> = arg + this operator fun T.plus(arg: Expression<T>): Expression<T> = arg + this
operator fun T.minus(arg: Expression<T>): Expression<T> = arg - this operator fun T.minus(arg: Expression<T>): Expression<T> = arg - this
} }
open class FunctionalExpressionRing<T>(val ring: Ring<T>) : FunctionalExpressionSpace<T>(ring), Ring<Expression<T>> { open class FunctionalExpressionRing<T, A>(override val algebra: A) : FunctionalExpressionSpace<T, A>(algebra),
Ring<Expression<T>> where A : Ring<T>, A : NumericAlgebra<T> {
override val one: Expression<T> override val one: Expression<T>
get() = const(this.ring.one) get() = const(algebra.one)
override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> = override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> =
FunctionalUnaryOperation(algebra, operation, arg) FunctionalUnaryOperation(algebra, operation, arg)
@ -75,18 +82,18 @@ open class FunctionalExpressionRing<T>(val ring: Ring<T>) : FunctionalExpression
override fun binaryOperation(operation: String, left: Expression<T>, right: Expression<T>): Expression<T> = override fun binaryOperation(operation: String, left: Expression<T>, right: Expression<T>): Expression<T> =
FunctionalBinaryOperation(algebra, operation, left, right) FunctionalBinaryOperation(algebra, operation, left, right)
override fun number(value: Number): Expression<T> = const(ring { one * value }) override fun number(value: Number): Expression<T> = const(algebra { one * value })
override fun multiply(a: Expression<T>, b: Expression<T>): Expression<T> = override fun multiply(a: Expression<T>, b: Expression<T>): Expression<T> =
FunctionalBinaryOperation(space, RingOperations.TIMES_OPERATION, a, b) FunctionalBinaryOperation(algebra, RingOperations.TIMES_OPERATION, a, b)
operator fun Expression<T>.times(arg: T): Expression<T> = this * const(arg) operator fun Expression<T>.times(arg: T): Expression<T> = this * const(arg)
operator fun T.times(arg: Expression<T>): Expression<T> = arg * this operator fun T.times(arg: Expression<T>): Expression<T> = arg * this
} }
open class FunctionalExpressionField<T>(val field: Field<T>) : open class FunctionalExpressionField<T, A>(override val algebra: A) :
FunctionalExpressionRing<T>(field), FunctionalExpressionRing<T, A>(algebra),
Field<Expression<T>> { Field<Expression<T>> where A : Field<T>, A : NumericAlgebra<T> {
override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> = override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> =
FunctionalUnaryOperation(algebra, operation, arg) FunctionalUnaryOperation(algebra, operation, arg)
@ -95,7 +102,7 @@ open class FunctionalExpressionField<T>(val field: Field<T>) :
FunctionalBinaryOperation(algebra, operation, left, right) FunctionalBinaryOperation(algebra, operation, left, right)
override fun divide(a: Expression<T>, b: Expression<T>): Expression<T> = override fun divide(a: Expression<T>, b: Expression<T>): Expression<T> =
FunctionalBinaryOperation(space, FieldOperations.DIV_OPERATION, a, b) FunctionalBinaryOperation(algebra, FieldOperations.DIV_OPERATION, a, b)
operator fun Expression<T>.div(arg: T): Expression<T> = this / const(arg) operator fun Expression<T>.div(arg: T): Expression<T> = this / const(arg)
operator fun T.div(arg: Expression<T>): Expression<T> = arg / this operator fun T.div(arg: Expression<T>): Expression<T> = arg / this

View File

@ -45,6 +45,5 @@ include(
":kmath-for-real", ":kmath-for-real",
":kmath-geometry", ":kmath-geometry",
":kmath-ast", ":kmath-ast",
":kmath-asm",
":examples" ":examples"
) )