From 7f8abbdd206f41da85c834508efa53815e234183 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Thu, 29 Oct 2020 02:22:34 +0700 Subject: [PATCH] Fix typo, introduce KG protocol delegating to algebra --- .../kscience/kmath/ast/KotlingradSupport.kt | 8 +-- .../kmath/kotlingrad/ScalarsAdapters.kt | 57 ++++++++++++++----- .../kmath/kotlingrad/AdaptingTests.kt | 12 ++-- 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt b/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt index 366a2b4fd..c8478a631 100644 --- a/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt +++ b/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt @@ -2,10 +2,10 @@ package kscience.kmath.ast import edu.umontreal.kotlingrad.experimental.DoublePrecision import kscience.kmath.asm.compile -import kscience.kmath.kotlingrad.toMst -import kscience.kmath.kotlingrad.tSFun -import kscience.kmath.kotlingrad.toSVar import kscience.kmath.expressions.invoke +import kscience.kmath.kotlingrad.toMst +import kscience.kmath.kotlingrad.toSFun +import kscience.kmath.kotlingrad.toSVar import kscience.kmath.operations.RealField /** @@ -15,7 +15,7 @@ import kscience.kmath.operations.RealField fun main() { val proto = DoublePrecision.prototype val x by MstAlgebra.symbol("x").toSVar(proto) - val quadratic = "x^2-4*x-44".parseMath().tSFun(proto) + val quadratic = "x^2-4*x-44".parseMath().toSFun(proto) val actualDerivative = MstExpression(RealField, quadratic.d(x).toMst()).compile() val expectedDerivative = MstExpression(RealField, "2*x-4".parseMath()).compile() assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0)) diff --git a/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/ScalarsAdapters.kt b/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/ScalarsAdapters.kt index 99ab5e635..a9a8a14b2 100644 --- a/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/ScalarsAdapters.kt +++ b/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/ScalarsAdapters.kt @@ -2,8 +2,13 @@ package kscience.kmath.kotlingrad import edu.umontreal.kotlingrad.experimental.* import kscience.kmath.ast.MST +import kscience.kmath.ast.MstAlgebra +import kscience.kmath.ast.MstExpression import kscience.kmath.ast.MstExtendedField import kscience.kmath.ast.MstExtendedField.unaryMinus +import kscience.kmath.expressions.DifferentiableExpression +import kscience.kmath.expressions.Expression +import kscience.kmath.expressions.Symbol import kscience.kmath.operations.* /** @@ -80,28 +85,52 @@ public fun > MST.Symbolic.toSVar(proto: X): SVar = SVar(proto, va * @param proto the prototype instance. * @return a scalar function. */ -public fun > MST.tSFun(proto: X): SFun = when (this) { +public fun > MST.toSFun(proto: X): SFun = when (this) { is MST.Numeric -> toSConst() is MST.Symbolic -> toSVar(proto) is MST.Unary -> when (operation) { - SpaceOperations.PLUS_OPERATION -> value.tSFun(proto) - SpaceOperations.MINUS_OPERATION -> -value.tSFun(proto) - TrigonometricOperations.SIN_OPERATION -> sin(value.tSFun(proto)) - TrigonometricOperations.COS_OPERATION -> cos(value.tSFun(proto)) - TrigonometricOperations.TAN_OPERATION -> tan(value.tSFun(proto)) - PowerOperations.SQRT_OPERATION -> value.tSFun(proto).sqrt() - ExponentialOperations.EXP_OPERATION -> E() pow value.tSFun(proto) - ExponentialOperations.LN_OPERATION -> value.tSFun(proto).ln() + SpaceOperations.PLUS_OPERATION -> value.toSFun(proto) + SpaceOperations.MINUS_OPERATION -> -value.toSFun(proto) + TrigonometricOperations.SIN_OPERATION -> sin(value.toSFun(proto)) + TrigonometricOperations.COS_OPERATION -> cos(value.toSFun(proto)) + TrigonometricOperations.TAN_OPERATION -> tan(value.toSFun(proto)) + PowerOperations.SQRT_OPERATION -> value.toSFun(proto).sqrt() + ExponentialOperations.EXP_OPERATION -> E() pow value.toSFun(proto) + ExponentialOperations.LN_OPERATION -> value.toSFun(proto).ln() else -> error("Unary operation $operation not defined in $this") } is MST.Binary -> when (operation) { - SpaceOperations.PLUS_OPERATION -> left.tSFun(proto) + right.tSFun(proto) - SpaceOperations.MINUS_OPERATION -> left.tSFun(proto) - right.tSFun(proto) - RingOperations.TIMES_OPERATION -> left.tSFun(proto) * right.tSFun(proto) - FieldOperations.DIV_OPERATION -> left.tSFun(proto) / right.tSFun(proto) - PowerOperations.POW_OPERATION -> left.tSFun(proto) pow (right as MST.Numeric).toSConst() + SpaceOperations.PLUS_OPERATION -> left.toSFun(proto) + right.toSFun(proto) + SpaceOperations.MINUS_OPERATION -> left.toSFun(proto) - right.toSFun(proto) + RingOperations.TIMES_OPERATION -> left.toSFun(proto) * right.toSFun(proto) + FieldOperations.DIV_OPERATION -> left.toSFun(proto) / right.toSFun(proto) + PowerOperations.POW_OPERATION -> left.toSFun(proto) pow (right as MST.Numeric).toSConst() else -> error("Binary operation $operation not defined in $this") } } + +public class KMathNumber(public val algebra: A, value: T) : + RealNumber, T>(value) where T : Number, A : NumericAlgebra { + public override fun wrap(number: Number): SConst> = SConst(algebra.number(number)) + override val proto: KMathNumber by lazy { KMathNumber(algebra, algebra.number(Double.NaN)) } +} + +public class KMathProtocol(algebra: A) : + Protocol>(KMathNumber(algebra, algebra.number(Double.NaN))) + where T : Number, A : NumericAlgebra + +public class DifferentiableMstExpression(public val algebra: A, public val mst: MST) : + DifferentiableExpression where A : NumericAlgebra, T : Number { + public val proto by lazy { KMathProtocol(algebra).prototype } + public val expr by lazy { MstExpression(algebra, mst) } + + public override fun invoke(arguments: Map): T = expr(arguments) + + public override fun derivativeOrNull(orders: Map): Expression { + val sfun = mst.toSFun(proto) + val orders2 = orders.mapKeys { (k, _) -> MstAlgebra.symbol(k.identity).toSVar(proto) } + TODO() + } +} diff --git a/kmath-kotlingrad/src/test/kotlin/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/kscience/kmath/kotlingrad/AdaptingTests.kt index 25bdbf4be..682b0cf2e 100644 --- a/kmath-kotlingrad/src/test/kotlin/kscience/kmath/kotlingrad/AdaptingTests.kt +++ b/kmath-kotlingrad/src/test/kotlin/kscience/kmath/kotlingrad/AdaptingTests.kt @@ -19,7 +19,7 @@ internal class AdaptingTests { fun symbol() { val c1 = MstAlgebra.symbol("x") assertTrue(c1.toSVar(proto).name == "x") - val c2 = "kitten".parseMath().tSFun(proto) + val c2 = "kitten".parseMath().toSFun(proto) if (c2 is SVar) assertTrue(c2.name == "kitten") else fail() } @@ -27,15 +27,15 @@ internal class AdaptingTests { fun number() { val c1 = MstAlgebra.number(12354324) assertTrue(c1.toSConst().doubleValue == 12354324.0) - val c2 = "0.234".parseMath().tSFun(proto) + val c2 = "0.234".parseMath().toSFun(proto) if (c2 is SConst) assertTrue(c2.doubleValue == 0.234) else fail() - val c3 = "1e-3".parseMath().tSFun(proto) + val c3 = "1e-3".parseMath().toSFun(proto) if (c3 is SConst) assertEquals(0.001, c3.value) else fail() } @Test fun simpleFunctionShape() { - val linear = "2*x+16".parseMath().tSFun(proto) + val linear = "2*x+16".parseMath().toSFun(proto) if (linear !is Sum) fail() if (linear.left !is Prod) fail() if (linear.right !is SConst) fail() @@ -44,7 +44,7 @@ internal class AdaptingTests { @Test fun simpleFunctionDerivative() { val x = MstAlgebra.symbol("x").toSVar(proto) - val quadratic = "x^2-4*x-44".parseMath().tSFun(proto) + val quadratic = "x^2-4*x-44".parseMath().toSFun(proto) val actualDerivative = MstExpression(RealField, quadratic.d(x).toMst()).compile() val expectedDerivative = MstExpression(RealField, "2*x-4".parseMath()).compile() assertEquals(actualDerivative("x" to 123.0), expectedDerivative("x" to 123.0)) @@ -53,7 +53,7 @@ internal class AdaptingTests { @Test fun moreComplexDerivative() { val x = MstAlgebra.symbol("x").toSVar(proto) - val composition = "-sqrt(sin(x^2)-cos(x)^2-16*x)".parseMath().tSFun(proto) + val composition = "-sqrt(sin(x^2)-cos(x)^2-16*x)".parseMath().toSFun(proto) val actualDerivative = MstExpression(RealField, composition.d(x).toMst()).compile() val expectedDerivative = MstExpression(