diff --git a/build.gradle.kts b/build.gradle.kts index 51ce48d84..095697bc4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,10 +9,15 @@ internal val githubProject: String by extra("kmath") allprojects { repositories { jcenter() + maven("https://clojars.org/repo") + maven("https://dl.bintray.com/egor-bogomolov/astminer/") + maven("https://dl.bintray.com/hotkeytlt/maven") maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("https://dl.bintray.com/kotlin/kotlinx") - maven("https://dl.bintray.com/hotkeytlt/maven") + maven("https://dl.bintray.com/mipt-npm/dev") + maven("https://dl.bintray.com/mipt-npm/kscience") maven("https://jitpack.io") + mavenCentral() } group = "kscience.kmath" diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 3ca9bbb47..33018976d 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -8,14 +8,6 @@ plugins { } allOpen.annotation("org.openjdk.jmh.annotations.State") - -repositories { - maven("https://dl.bintray.com/mipt-npm/kscience") - maven("https://dl.bintray.com/mipt-npm/dev") - maven("https://dl.bintray.com/kotlin/kotlin-dev/") - mavenCentral() -} - sourceSets.register("benchmarks") dependencies { diff --git a/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt b/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt index b25a61e96..a4806ed68 100644 --- a/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt +++ b/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt @@ -13,7 +13,7 @@ internal class ExpressionsInterpretersBenchmark { private val algebra: Field = RealField fun functionalExpression() { val expr = algebra.expressionInField { - variable("x") * const(2.0) + const(2.0) / variable("x") - const(16.0) + symbol("x") * const(2.0) + const(2.0) / symbol("x") - const(16.0) } invokeAndSum(expr) diff --git a/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt b/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt index c8478a631..7b5e1565d 100644 --- a/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt +++ b/examples/src/main/kotlin/kscience/kmath/ast/KotlingradSupport.kt @@ -1,11 +1,9 @@ package kscience.kmath.ast -import edu.umontreal.kotlingrad.experimental.DoublePrecision import kscience.kmath.asm.compile import kscience.kmath.expressions.invoke -import kscience.kmath.kotlingrad.toMst -import kscience.kmath.kotlingrad.toSFun -import kscience.kmath.kotlingrad.toSVar +import kscience.kmath.expressions.symbol +import kscience.kmath.kotlingrad.DifferentiableMstExpression import kscience.kmath.operations.RealField /** @@ -13,10 +11,12 @@ import kscience.kmath.operations.RealField * valid derivative. */ fun main() { - val proto = DoublePrecision.prototype - val x by MstAlgebra.symbol("x").toSVar(proto) - val quadratic = "x^2-4*x-44".parseMath().toSFun(proto) - val actualDerivative = MstExpression(RealField, quadratic.d(x).toMst()).compile() + val x by symbol + + val actualDerivative = DifferentiableMstExpression(RealField, "x^2-4*x-44".parseMath()) + .derivativeOrNull(listOf(x)) + .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-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt index 5ca75e993..f68e3f5f8 100644 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt +++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt @@ -13,7 +13,7 @@ import kotlin.contracts.contract * @property mst the [MST] node. * @author Alexander Nozik */ -public class MstExpression(public val algebra: Algebra, public val mst: MST) : Expression { +public class MstExpression>(public val algebra: A, public val mst: MST) : Expression { private inner class InnerAlgebra(val arguments: Map) : NumericAlgebra { override fun symbol(value: String): T = arguments[StringSymbol(value)] ?: algebra.symbol(value) override fun unaryOperation(operation: String, arg: T): T = algebra.unaryOperation(operation, arg) @@ -21,8 +21,9 @@ public class MstExpression(public val algebra: Algebra, public val mst: MS override fun binaryOperation(operation: String, left: T, right: T): T = algebra.binaryOperation(operation, left, right) - override fun number(value: Number): T = if (algebra is NumericAlgebra) - algebra.number(value) + @Suppress("UNCHECKED_CAST") + override fun number(value: Number): T = if (algebra is NumericAlgebra<*>) + (algebra as NumericAlgebra).number(value) else error("Numeric nodes are not supported by $this") } @@ -38,14 +39,14 @@ public class MstExpression(public val algebra: Algebra, public val mst: MS public inline fun , E : Algebra> A.mst( mstAlgebra: E, block: E.() -> MST, -): MstExpression = MstExpression(this, mstAlgebra.block()) +): MstExpression = MstExpression(this, mstAlgebra.block()) /** * Builds [MstExpression] over [Space]. * * @author Alexander Nozik */ -public inline fun Space.mstInSpace(block: MstSpace.() -> MST): MstExpression { +public inline fun > A.mstInSpace(block: MstSpace.() -> MST): MstExpression { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return MstExpression(this, MstSpace.block()) } @@ -55,7 +56,7 @@ public inline fun Space.mstInSpace(block: MstSpace.() -> MS * * @author Alexander Nozik */ -public inline fun Ring.mstInRing(block: MstRing.() -> MST): MstExpression { +public inline fun > A.mstInRing(block: MstRing.() -> MST): MstExpression { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return MstExpression(this, MstRing.block()) } @@ -65,7 +66,7 @@ public inline fun Ring.mstInRing(block: MstRing.() -> MST): * * @author Alexander Nozik */ -public inline fun Field.mstInField(block: MstField.() -> MST): MstExpression { +public inline fun > A.mstInField(block: MstField.() -> MST): MstExpression { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return MstExpression(this, MstField.block()) } @@ -75,7 +76,7 @@ public inline fun Field.mstInField(block: MstField.() -> MS * * @author Iaroslav Postovalov */ -public inline fun Field.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression { +public inline fun > A.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return MstExpression(this, MstExtendedField.block()) } @@ -85,7 +86,7 @@ public inline fun Field.mstInExtendedField(block: MstExtend * * @author Alexander Nozik */ -public inline fun > FunctionalExpressionSpace.mstInSpace(block: MstSpace.() -> MST): MstExpression { +public inline fun > FunctionalExpressionSpace.mstInSpace(block: MstSpace.() -> MST): MstExpression { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return algebra.mstInSpace(block) } @@ -95,7 +96,7 @@ public inline fun > FunctionalExpressionSpace> FunctionalExpressionRing.mstInRing(block: MstRing.() -> MST): MstExpression { +public inline fun > FunctionalExpressionRing.mstInRing(block: MstRing.() -> MST): MstExpression { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return algebra.mstInRing(block) } @@ -105,7 +106,7 @@ public inline fun > FunctionalExpressionRing. * * @author Alexander Nozik */ -public inline fun > FunctionalExpressionField.mstInField(block: MstField.() -> MST): MstExpression { +public inline fun > FunctionalExpressionField.mstInField(block: MstField.() -> MST): MstExpression { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return algebra.mstInField(block) } @@ -117,7 +118,7 @@ public inline fun > FunctionalExpressionField> FunctionalExpressionExtendedField.mstInExtendedField( block: MstExtendedField.() -> MST, -): MstExpression { +): MstExpression { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return algebra.mstInExtendedField(block) } diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/extensions.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/extensions.kt deleted file mode 100644 index b790a3a88..000000000 --- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/extensions.kt +++ /dev/null @@ -1,12 +0,0 @@ -package kscience.kmath.ast - -import kscience.kmath.operations.Algebra -import kotlin.properties.PropertyDelegateProvider -import kotlin.properties.ReadOnlyProperty - -/** - * Returns [PropertyDelegateProvider] providing [ReadOnlyProperty] of [MST.Symbolic] with its value equal to the name - * of the property. - */ -public val Algebra.symbol: PropertyDelegateProvider, ReadOnlyProperty, MST.Symbolic>> - get() = PropertyDelegateProvider { _, _ -> ReadOnlyProperty { _, p -> MST.Symbolic(p.name) } } diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt index 2b6fa6247..9ccfa464c 100644 --- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt +++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt @@ -69,4 +69,5 @@ public inline fun Algebra.expression(mst: MST): Expression< * * @author Alexander Nozik. */ -public inline fun MstExpression.compile(): Expression = mst.compileWith(T::class.java, algebra) +public inline fun MstExpression>.compile(): Expression = + mst.compileWith(T::class.java, algebra) diff --git a/kmath-kotlingrad/build.gradle.kts b/kmath-kotlingrad/build.gradle.kts index f2245c3d5..027a03bc9 100644 --- a/kmath-kotlingrad/build.gradle.kts +++ b/kmath-kotlingrad/build.gradle.kts @@ -3,6 +3,7 @@ plugins { } dependencies { - api("com.github.breandan:kotlingrad:0.3.7") + implementation("com.github.breandan:kaliningraph:0.1.2") + implementation("com.github.breandan:kotlingrad:0.3.7") api(project(":kmath-ast")) } diff --git a/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt b/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt new file mode 100644 index 000000000..88cc20639 --- /dev/null +++ b/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt @@ -0,0 +1,53 @@ +package kscience.kmath.kotlingrad + +import edu.umontreal.kotlingrad.experimental.SFun +import kscience.kmath.ast.MST +import kscience.kmath.ast.MstAlgebra +import kscience.kmath.ast.MstExpression +import kscience.kmath.expressions.DifferentiableExpression +import kscience.kmath.expressions.Symbol +import kscience.kmath.operations.NumericAlgebra + +/** + * Represents wrapper of [MstExpression] implementing [DifferentiableExpression]. + * + * The principle of this API is converting the [mst] to an [SFun], differentiating it with Kotlin∇, then converting + * [SFun] back to [MST]. + * + * @param T the type of number. + * @param A the [NumericAlgebra] of [T]. + * @property expr the underlying [MstExpression]. + */ +public inline class DifferentiableMstExpression(public val expr: MstExpression) : + DifferentiableExpression where A : NumericAlgebra, T : Number { + public constructor(algebra: A, mst: MST) : this(MstExpression(algebra, mst)) + + /** + * The [MstExpression.algebra] of [expr]. + */ + public val algebra: A + get() = expr.algebra + + /** + * The [MstExpression.mst] of [expr]. + */ + public val mst: MST + get() = expr.mst + + public override fun invoke(arguments: Map): T = expr(arguments) + + public override fun derivativeOrNull(symbols: List): MstExpression = MstExpression( + algebra, + symbols.map(Symbol::identity) + .map(MstAlgebra::symbol) + .map { it.toSVar>() } + .fold(mst.toSFun(), SFun>::d) + .toMst(), + ) +} + +/** + * Wraps this [MstExpression] into [DifferentiableMstExpression]. + */ +public fun > MstExpression.differentiable(): DifferentiableMstExpression = + DifferentiableMstExpression(this) diff --git a/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/KMathNumber.kt b/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/KMathNumber.kt new file mode 100644 index 000000000..ce5658137 --- /dev/null +++ b/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/KMathNumber.kt @@ -0,0 +1,18 @@ +package kscience.kmath.kotlingrad + +import edu.umontreal.kotlingrad.experimental.RealNumber +import edu.umontreal.kotlingrad.experimental.SConst +import kscience.kmath.operations.NumericAlgebra + +/** + * Implements [RealNumber] by delegating its functionality to [NumericAlgebra]. + * + * @param T the type of number. + * @param A the [NumericAlgebra] of [T]. + * @property algebra the algebra. + * @param value the value of this number. + */ +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)) +} 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 24e8377bd..b6effab4b 100644 --- a/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/ScalarsAdapters.kt +++ b/kmath-kotlingrad/src/main/kotlin/kscience/kmath/kotlingrad/ScalarsAdapters.kt @@ -3,14 +3,26 @@ 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.* +/** + * Maps [SVar] to [MST.Symbolic] directly. + * + * @receiver the variable. + * @return a node. + */ +public fun > SVar.toMst(): MST.Symbolic = MstAlgebra.symbol(name) + +/** + * Maps [SVar] to [MST.Numeric] directly. + * + * @receiver the constant. + * @return a node. + */ +public fun > SConst.toMst(): MST.Numeric = MstAlgebra.number(doubleValue) + /** * Maps [SFun] objects to [MST]. Some unsupported operations like [Derivative] are bound and converted then. * [Power] operation is limited to constant right-hand side arguments. @@ -37,8 +49,8 @@ import kscience.kmath.operations.* */ public fun > SFun.toMst(): MST = MstExtendedField { when (this@toMst) { - is SVar -> symbol(name) - is SConst -> number(doubleValue) + is SVar -> toMst() + is SConst -> toMst() is Sum -> left.toMst() + right.toMst() is Prod -> left.toMst() * right.toMst() is Power -> left.toMst() pow ((right as? SConst<*>)?.doubleValue ?: (right() as SConst<*>).doubleValue) @@ -69,7 +81,7 @@ public fun > MST.Numeric.toSConst(): SConst = SConst(value) * @param proto the prototype instance. * @return a new variable. */ -public fun > MST.Symbolic.toSVar(): SVar = SVar(value) +internal fun > MST.Symbolic.toSVar(): SVar = SVar(value) /** * Maps [MST] objects to [SFun]. Unsupported operations throw [IllegalStateException]. @@ -90,12 +102,12 @@ public fun > MST.toSFun(): SFun = when (this) { is MST.Symbolic -> toSVar() is MST.Unary -> when (operation) { - SpaceOperations.PLUS_OPERATION -> value.toSFun() - SpaceOperations.MINUS_OPERATION -> (-value).toSFun() + SpaceOperations.PLUS_OPERATION -> +value.toSFun() + SpaceOperations.MINUS_OPERATION -> -value.toSFun() TrigonometricOperations.SIN_OPERATION -> sin(value.toSFun()) TrigonometricOperations.COS_OPERATION -> cos(value.toSFun()) TrigonometricOperations.TAN_OPERATION -> tan(value.toSFun()) - PowerOperations.SQRT_OPERATION -> value.toSFun().sqrt() + PowerOperations.SQRT_OPERATION -> sqrt(value.toSFun()) ExponentialOperations.EXP_OPERATION -> exp(value.toSFun()) ExponentialOperations.LN_OPERATION -> value.toSFun().ln() else -> error("Unary operation $operation not defined in $this") @@ -110,27 +122,3 @@ public fun > MST.toSFun(): SFun = when (this) { 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)) -} - -public class DifferentiableMstExpression(public val algebra: A, public val mst: MST) : - DifferentiableExpression where A : NumericAlgebra, T : Number { - public val expr by lazy { MstExpression(algebra, mst) } - - public override fun invoke(arguments: Map): T = expr(arguments) - - public override fun derivativeOrNull(orders: Map): Expression { - TODO() - } - - public fun derivativeOrNull(orders: List): Expression { - orders.map { MstAlgebra.symbol(it.identity).toSVar>() } - .fold>, SFun>>(mst.toSFun()) { result, sVar -> result.d(sVar) } - .toMst() - - TODO() - } -}