From f46615d3bc3e036bd33d59912ae8e3a82f6e1b9b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 12 Jun 2020 08:43:47 +0300 Subject: [PATCH] Left and right-side operations in Algebra --- .../kmath/expressions/MathSyntaxTree.kt | 61 +++++++++++++++++++ .../kmath/expressions/SyntaxTreeNode.kt | 52 ---------------- .../scientifik/kmath/operations/Algebra.kt | 16 ++++- .../kmath/operations/NumberAlgebra.kt | 28 ++++++++- .../kmath/operations/OptionalOperations.kt | 26 +++++--- 5 files changed, 120 insertions(+), 63 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/MathSyntaxTree.kt delete mode 100644 kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/SyntaxTreeNode.kt diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/MathSyntaxTree.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/MathSyntaxTree.kt new file mode 100644 index 000000000..fbc055f80 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/MathSyntaxTree.kt @@ -0,0 +1,61 @@ +package scientifik.kmath.expressions + +import scientifik.kmath.operations.NumericAlgebra +import scientifik.kmath.operations.RealField + +/** + * A syntax tree node for mathematical expressions + */ +sealed class MathSyntaxTree + +/** + * A node containing unparsed string + */ +data class SingularNode(val value: String) : MathSyntaxTree() + +/** + * A node containing a number + */ +data class NumberNode(val value: Number) : MathSyntaxTree() + +/** + * A node containing an unary operation + */ +data class UnaryNode(val operation: String, val value: MathSyntaxTree) : MathSyntaxTree() { + companion object { + const val ABS_OPERATION = "abs" + //TODO add operations + } +} + +/** + * A node containing binary operation + */ +data class BinaryNode(val operation: String, val left: MathSyntaxTree, val right: MathSyntaxTree) : MathSyntaxTree() { + companion object +} + +//TODO add a function with positional arguments + +//TODO add a function with named arguments + +fun NumericAlgebra.compile(node: MathSyntaxTree): T { + return when (node) { + is NumberNode -> number(node.value) + is SingularNode -> raw(node.value) + is UnaryNode -> unaryOperation(node.operation, compile(node.value)) + is BinaryNode -> when { + node.left is NumberNode && node.right is NumberNode -> { + val number = RealField.binaryOperation( + node.operation, + node.left.value.toDouble(), + node.right.value.toDouble() + ) + number(number) + } + node.left is NumberNode -> leftSideNumberOperation(node.operation, node.left.value, compile(node.right)) + node.right is NumberNode -> rightSideNumberOperation(node.operation, compile(node.left), node.right.value) + else -> binaryOperation(node.operation, compile(node.left), compile(node.right)) + } + } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/SyntaxTreeNode.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/SyntaxTreeNode.kt deleted file mode 100644 index e56165aad..000000000 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/SyntaxTreeNode.kt +++ /dev/null @@ -1,52 +0,0 @@ -package scientifik.kmath.expressions - -import scientifik.kmath.operations.NumericAlgebra - -/** - * A syntax tree node for mathematical expressions - */ -sealed class SyntaxTreeNode - -/** - * A node containing unparsed string - */ -data class SingularNode(val value: String) : SyntaxTreeNode() - -/** - * A node containing a number - */ -data class NumberNode(val value: Number) : SyntaxTreeNode() - -/** - * A node containing an unary operation - */ -data class UnaryNode(val operation: String, val value: SyntaxTreeNode) : SyntaxTreeNode() { - companion object { - const val ABS_OPERATION = "abs" - const val SIN_OPERATION = "sin" - const val COS_OPERATION = "cos" - const val EXP_OPERATION = "exp" - const val LN_OPERATION = "ln" - //TODO add operations - } -} - -/** - * A node containing binary operation - */ -data class BinaryNode(val operation: String, val left: SyntaxTreeNode, val right: SyntaxTreeNode) : SyntaxTreeNode() { - companion object -} - -//TODO add a function with positional arguments - -//TODO add a function with named arguments - -fun NumericAlgebra.compile(node: SyntaxTreeNode): T{ - return when (node) { - is NumberNode -> number(node.value) - is SingularNode -> raw(node.value) - is UnaryNode -> unaryOperation(node.operation, compile(node.value)) - is BinaryNode -> binaryOperation(node.operation, compile(node.left), compile(node.right)) - } -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt index c9fbc1c8b..166287ec7 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt @@ -31,6 +31,12 @@ interface NumericAlgebra : Algebra { * Wrap a number */ fun number(value: Number): T + + fun leftSideNumberOperation(operation: String, left: Number, right: T): T = + binaryOperation(operation, number(left), right) + + fun rightSideNumberOperation(operation: String, left: T, right: Number): T = + leftSideNumberOperation(operation, right, left) } /** @@ -128,8 +134,14 @@ interface Ring : Space, RingOperations, NumericAlgebra { override fun number(value: Number): T = one * value.toDouble() - // those operators are blocked by type conflict in RealField - // operator fun T.plus(b: Number) = this.plus(b * one) + override fun leftSideNumberOperation(operation: String, left: Number, right: T): T = when (operation) { + RingOperations.TIMES_OPERATION -> left * right + else -> super.leftSideNumberOperation(operation, left, right) + } + + //TODO those operators are blocked by type conflict in RealField + +// operator fun T.plus(b: Number) = this.plus(b * one) // operator fun Number.plus(b: T) = b + this // // operator fun T.minus(b: Number) = this.minus(b * one) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt index 9639e4c28..e844d404e 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt @@ -10,9 +10,30 @@ interface ExtendedFieldOperations : FieldOperations, TrigonometricOperations, PowerOperations, - ExponentialOperations + ExponentialOperations { -interface ExtendedField : ExtendedFieldOperations, Field + override fun tan(arg: T): T = sin(arg) / cos(arg) + + override fun unaryOperation(operation: String, arg: T): T = when (operation) { + TrigonometricOperations.COS_OPERATION -> cos(arg) + TrigonometricOperations.SIN_OPERATION -> sin(arg) + PowerOperations.SQRT_OPERATION -> sqrt(arg) + ExponentialOperations.EXP_OPERATION -> exp(arg) + ExponentialOperations.LN_OPERATION -> ln(arg) + else -> super.unaryOperation(operation, arg) + } + +} + +interface ExtendedField : ExtendedFieldOperations, Field { + override fun rightSideNumberOperation(operation: String, left: T, right: Number): T { + return when (operation) { + PowerOperations.POW_OPERATION -> power(left, right) + else -> super.rightSideNumberOperation(operation, left, right) + } + + } +} /** * Real field element wrapping double. @@ -44,6 +65,7 @@ object RealField : ExtendedField, Norm { override inline fun sin(arg: Double) = kotlin.math.sin(arg) override inline fun cos(arg: Double) = kotlin.math.cos(arg) + override inline fun tan(arg: Double) = kotlin.math.tan(arg) override inline fun power(arg: Double, pow: Number) = arg.kpow(pow.toDouble()) @@ -76,6 +98,8 @@ object FloatField : ExtendedField, Norm { override inline fun sin(arg: Float) = kotlin.math.sin(arg) override inline fun cos(arg: Float) = kotlin.math.cos(arg) + override inline fun tan(arg: Float): Float = kotlin.math.tan(arg) + override inline fun power(arg: Float, pow: Number) = arg.pow(pow.toFloat()) override inline fun exp(arg: Float) = kotlin.math.exp(arg) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt index bd83932e7..1b58b7254 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt @@ -10,30 +10,37 @@ package scientifik.kmath.operations * It also allows to override behavior for optional operations * */ -interface TrigonometricOperations : FieldOperations { +interface TrigonometricOperations { fun sin(arg: T): T fun cos(arg: T): T - fun tg(arg: T): T = sin(arg) / cos(arg) + fun tan(arg: T): T - fun ctg(arg: T): T = cos(arg) / sin(arg) + companion object { + const val SIN_OPERATION = "sin" + const val COS_OPERATION = "cos" + } } fun >> sin(arg: T): T = arg.context.sin(arg) fun >> cos(arg: T): T = arg.context.cos(arg) -fun >> tg(arg: T): T = arg.context.tg(arg) -fun >> ctg(arg: T): T = arg.context.ctg(arg) +fun >> tan(arg: T): T = arg.context.tan(arg) /* Power and roots */ /** * A context extension to include power operations like square roots, etc */ -interface PowerOperations : Algebra { +interface PowerOperations { fun power(arg: T, pow: Number): T fun sqrt(arg: T) = power(arg, 0.5) infix fun T.pow(pow: Number) = power(this, pow) + + companion object { + const val POW_OPERATION = "pow" + const val SQRT_OPERATION = "sqrt" + } } infix fun >> T.pow(power: Double): T = context.power(this, power) @@ -42,9 +49,14 @@ fun >> sqr(arg: T): T = arg pow 2.0 /* Exponential */ -interface ExponentialOperations: Algebra { +interface ExponentialOperations { fun exp(arg: T): T fun ln(arg: T): T + + companion object { + const val EXP_OPERATION = "exp" + const val LN_OPERATION = "ln" + } } fun >> exp(arg: T): T = arg.context.exp(arg)