Expressions!

This commit is contained in:
Alexander Nozik 2018-08-25 20:58:26 +03:00
parent 8da54786a0
commit c344380120
5 changed files with 95 additions and 6 deletions

View File

@ -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 * **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). 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 ## Planned features
* **Common mathematics** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/) * **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 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. 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. * **Messaging** A mathematical notation to support multilanguage and multinod communication for mathematical tasks.
## Multi-platform support ## Multi-platform support

View File

@ -0,0 +1,62 @@
package scientifik.kmath.expressions
import scientifik.kmath.operations.Field
import scientifik.kmath.operations.Space
interface Expression<T> {
operator fun invoke(arguments: Map<String, T>): T
}
operator fun <T> Expression<T>.invoke(vararg pairs: Pair<String, T>): T = invoke(mapOf(*pairs))
interface ExpressionContext<T> {
fun variable(name: String, default: T? = null): Expression<T>
fun const(value: T): Expression<T>
}
internal class VariableExpression<T>(val name: String, val default: T? = null) : Expression<T> {
override fun invoke(arguments: Map<String, T>): T {
return arguments[name] ?: default ?: error("The parameter not found: $name")
}
}
internal class ConstantExpression<T>(val value: T) : Expression<T> {
override fun invoke(arguments: Map<String, T>): T = value
}
internal class SumExpression<T>(val context: Space<T>, val first: Expression<T>, val second: Expression<T>) : Expression<T> {
override fun invoke(arguments: Map<String, T>): T = context.add(first.invoke(arguments), second.invoke(arguments))
}
internal class ProductExpression<T>(val context: Field<T>, val first: Expression<T>, val second: Expression<T>) : Expression<T> {
override fun invoke(arguments: Map<String, T>): T = context.multiply(first.invoke(arguments), second.invoke(arguments))
}
internal class ConstProductExpession<T>(val context: Field<T>, val expr: Expression<T>, val const: Double) : Expression<T> {
override fun invoke(arguments: Map<String, T>): T = context.multiply(expr.invoke(arguments), const)
}
internal class DivExpession<T>(val context: Field<T>, val expr: Expression<T>, val second: Expression<T>) : Expression<T> {
override fun invoke(arguments: Map<String, T>): T = context.divide(expr.invoke(arguments), second.invoke(arguments))
}
class FieldExpressionContext<T>(val field: Field<T>) : Field<Expression<T>>, ExpressionContext<T> {
override val zero: Expression<T> = ConstantExpression(field.zero)
override val one: Expression<T> = ConstantExpression(field.one)
override fun const(value: T): Expression<T> = ConstantExpression(value)
override fun variable(name: String, default: T?): Expression<T> = VariableExpression(name, default)
override fun add(a: Expression<T>, b: Expression<T>): Expression<T> = SumExpression(field, a, b)
override fun multiply(a: Expression<T>, k: Double): Expression<T> = ConstProductExpession(field, a, k)
override fun multiply(a: Expression<T>, b: Expression<T>): Expression<T> = ProductExpression(field, a, b)
override fun divide(a: Expression<T>, b: Expression<T>): Expression<T> = DivExpession(field, a, b)
}

View File

@ -29,7 +29,7 @@ object RealField : Field<Real>, TrigonometricOperations<Real>, PowerOperations<R
* *
* TODO could be replaced by inline class in kotlin 1.3 if it would allow to avoid boxing * TODO could be replaced by inline class in kotlin 1.3 if it would allow to avoid boxing
*/ */
class Real(val value: Double) : Number(), FieldElement<Real, RealField> { data class Real(val value: Double) : Number(), FieldElement<Real, RealField> {
/* /*
* The class uses composition instead of inheritance since Double is final * 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<Complex, Compl
/** /**
* A field for double without boxing. Does not produce appropriate field element * A field for double without boxing. Does not produce appropriate field element
*/ */
object DoubleField : Field<Double> { object DoubleField : Field<Double>, TrigonometricOperations<Double>, PowerOperations<Double>, ExponentialOperations<Double> {
override val zero: Double = 0.0 override val zero: Double = 0.0
override fun add(a: Double, b: Double): Double = a + b 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 fun multiply(a: Double, @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") b: Double): Double = a * b
override val one: Double = 1.0 override val one: Double = 1.0
override fun divide(a: Double, b: Double): Double = a / b 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)
} }

View File

@ -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)
}
}