From c344380120123c91aead15c4014512dfc84bfaf5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 25 Aug 2018 20:58:26 +0300 Subject: [PATCH] Expressions! --- README.md | 8 +-- .../kmath/expressions/Expression.kt | 62 +++++++++++++++++++ .../scientifik/kmath/operations/Fields.kt | 13 +++- .../expressions/FieldExpressionContextTest.kt | 18 ++++++ .../kmath/misc}/CumulativeKtTest.kt | 0 5 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 kmath-common/src/main/kotlin/scientifik/kmath/expressions/Expression.kt create mode 100644 kmath-common/src/test/kotlin/scientifik/kmath/expressions/FieldExpressionContextTest.kt rename kmath-common/src/test/kotlin/{scientifik.kmath.misc => scientifik/kmath/misc}/CumulativeKtTest.kt (100%) diff --git a/README.md b/README.md index ca7d1d09a..7defe0482 100644 --- a/README.md +++ b/README.md @@ -11,16 +11,16 @@ and `scipy` it is modular and has a lightweight core. * **Array-like structures** Full support of numpy-like ndarray including mixed arithmetic operations and function operations on arrays and numbers just like it works in python (with benefit of static type checking). +* **Expressions** Expressions are one of the ultimate goals of kmath. It is planned to be able to write some mathematical +expression once an then apply it to different types of objects by providing different context. Exception could be used +for a wide variety of purposes from high performance calculations to code generation. + ## Planned features * **Common mathematics** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/) library in kotlin code and maybe rewrite some parts to better suite kotlin programming paradigm. There is no fixed priority list for that. Feel free to submit a future request if you want something to be done first. -* **Expressions** Expressions are one of the ultimate goals of kmath. It is planned to be able to write some mathematical -expression once an then apply it to different types of objects by providing different context. Exception could be used -for a wide variety of purposes from high performance calculations to code generation. - * **Messaging** A mathematical notation to support multilanguage and multinod communication for mathematical tasks. ## Multi-platform support diff --git a/kmath-common/src/main/kotlin/scientifik/kmath/expressions/Expression.kt b/kmath-common/src/main/kotlin/scientifik/kmath/expressions/Expression.kt new file mode 100644 index 000000000..0a34b536c --- /dev/null +++ b/kmath-common/src/main/kotlin/scientifik/kmath/expressions/Expression.kt @@ -0,0 +1,62 @@ +package scientifik.kmath.expressions + +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.Space + + +interface Expression { + operator fun invoke(arguments: Map): T +} + +operator fun Expression.invoke(vararg pairs: Pair): T = invoke(mapOf(*pairs)) + +interface ExpressionContext { + fun variable(name: String, default: T? = null): Expression + + fun const(value: T): Expression +} + +internal class VariableExpression(val name: String, val default: T? = null) : Expression { + override fun invoke(arguments: Map): T { + return arguments[name] ?: default ?: error("The parameter not found: $name") + } +} + +internal class ConstantExpression(val value: T) : Expression { + override fun invoke(arguments: Map): T = value +} + +internal class SumExpression(val context: Space, val first: Expression, val second: Expression) : Expression { + override fun invoke(arguments: Map): T = context.add(first.invoke(arguments), second.invoke(arguments)) +} + +internal class ProductExpression(val context: Field, val first: Expression, val second: Expression) : Expression { + override fun invoke(arguments: Map): T = context.multiply(first.invoke(arguments), second.invoke(arguments)) +} + +internal class ConstProductExpession(val context: Field, val expr: Expression, val const: Double) : Expression { + override fun invoke(arguments: Map): T = context.multiply(expr.invoke(arguments), const) +} + +internal class DivExpession(val context: Field, val expr: Expression, val second: Expression) : Expression { + override fun invoke(arguments: Map): T = context.divide(expr.invoke(arguments), second.invoke(arguments)) +} + +class FieldExpressionContext(val field: Field) : Field>, ExpressionContext { + + override val zero: Expression = ConstantExpression(field.zero) + + override val one: Expression = ConstantExpression(field.one) + + override fun const(value: T): Expression = ConstantExpression(value) + + override fun variable(name: String, default: T?): Expression = VariableExpression(name, default) + + override fun add(a: Expression, b: Expression): Expression = SumExpression(field, a, b) + + override fun multiply(a: Expression, k: Double): Expression = ConstProductExpession(field, a, k) + + override fun multiply(a: Expression, b: Expression): Expression = ProductExpression(field, a, b) + + override fun divide(a: Expression, b: Expression): Expression = DivExpession(field, a, b) +} \ No newline at end of file diff --git a/kmath-common/src/main/kotlin/scientifik/kmath/operations/Fields.kt b/kmath-common/src/main/kotlin/scientifik/kmath/operations/Fields.kt index 2f3eb99ff..0d2600d82 100644 --- a/kmath-common/src/main/kotlin/scientifik/kmath/operations/Fields.kt +++ b/kmath-common/src/main/kotlin/scientifik/kmath/operations/Fields.kt @@ -29,7 +29,7 @@ object RealField : Field, TrigonometricOperations, PowerOperations { +data class Real(val value: Double) : Number(), FieldElement { /* * The class uses composition instead of inheritance since Double is final */ @@ -94,10 +94,19 @@ data class Complex(val re: Double, val im: Double) : FieldElement { +object DoubleField : Field, TrigonometricOperations, PowerOperations, ExponentialOperations { override val zero: Double = 0.0 override fun add(a: Double, b: Double): Double = a + b override fun multiply(a: Double, @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") b: Double): Double = a * b override val one: Double = 1.0 override fun divide(a: Double, b: Double): Double = a / b + + override fun sin(arg: Double): Double = kotlin.math.sin(arg) + override fun cos(arg: Double): Double = kotlin.math.cos(arg) + + override fun power(arg: Double, pow: Double): Double = arg.pow(pow) + + override fun exp(arg: Double): Double =kotlin.math.exp(arg) + + override fun ln(arg: Double): Double = kotlin.math.ln(arg) } \ No newline at end of file diff --git a/kmath-common/src/test/kotlin/scientifik/kmath/expressions/FieldExpressionContextTest.kt b/kmath-common/src/test/kotlin/scientifik/kmath/expressions/FieldExpressionContextTest.kt new file mode 100644 index 000000000..5e9832604 --- /dev/null +++ b/kmath-common/src/test/kotlin/scientifik/kmath/expressions/FieldExpressionContextTest.kt @@ -0,0 +1,18 @@ +package scientifik.kmath.expressions + +import scientifik.kmath.operations.DoubleField +import kotlin.test.Test +import kotlin.test.assertEquals + +class FieldExpressionContextTest { + @Test + fun testExpression() { + val context = FieldExpressionContext(DoubleField) + val expression = with(context) { + val x = variable("x", 2.0) + x * x + 2 * x + 1.0 * one + } + assertEquals(expression("x" to 1.0), 4.0) + assertEquals(expression(), 9.0) + } +} \ No newline at end of file diff --git a/kmath-common/src/test/kotlin/scientifik.kmath.misc/CumulativeKtTest.kt b/kmath-common/src/test/kotlin/scientifik/kmath/misc/CumulativeKtTest.kt similarity index 100% rename from kmath-common/src/test/kotlin/scientifik.kmath.misc/CumulativeKtTest.kt rename to kmath-common/src/test/kotlin/scientifik/kmath/misc/CumulativeKtTest.kt