Left and right-side operations in Algebra
This commit is contained in:
parent
e8a6ecd5c3
commit
f46615d3bc
@ -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 <T> NumericAlgebra<T>.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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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 <T> NumericAlgebra<T>.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))
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,6 +31,12 @@ interface NumericAlgebra<T> : Algebra<T> {
|
|||||||
* Wrap a number
|
* Wrap a number
|
||||||
*/
|
*/
|
||||||
fun number(value: Number): T
|
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,7 +134,13 @@ interface Ring<T> : Space<T>, RingOperations<T>, NumericAlgebra<T> {
|
|||||||
|
|
||||||
override fun number(value: Number): T = one * value.toDouble()
|
override fun number(value: Number): T = one * value.toDouble()
|
||||||
|
|
||||||
// those operators are blocked by type conflict in RealField
|
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 T.plus(b: Number) = this.plus(b * one)
|
||||||
// operator fun Number.plus(b: T) = b + this
|
// operator fun Number.plus(b: T) = b + this
|
||||||
//
|
//
|
||||||
|
@ -10,9 +10,30 @@ interface ExtendedFieldOperations<T> :
|
|||||||
FieldOperations<T>,
|
FieldOperations<T>,
|
||||||
TrigonometricOperations<T>,
|
TrigonometricOperations<T>,
|
||||||
PowerOperations<T>,
|
PowerOperations<T>,
|
||||||
ExponentialOperations<T>
|
ExponentialOperations<T> {
|
||||||
|
|
||||||
interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T>
|
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<T> : ExtendedFieldOperations<T>, Field<T> {
|
||||||
|
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.
|
* Real field element wrapping double.
|
||||||
@ -44,6 +65,7 @@ object RealField : ExtendedField<Double>, Norm<Double, Double> {
|
|||||||
|
|
||||||
override inline fun sin(arg: Double) = kotlin.math.sin(arg)
|
override inline fun sin(arg: Double) = kotlin.math.sin(arg)
|
||||||
override inline fun cos(arg: Double) = kotlin.math.cos(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())
|
override inline fun power(arg: Double, pow: Number) = arg.kpow(pow.toDouble())
|
||||||
|
|
||||||
@ -76,6 +98,8 @@ object FloatField : ExtendedField<Float>, Norm<Float, Float> {
|
|||||||
override inline fun sin(arg: Float) = kotlin.math.sin(arg)
|
override inline fun sin(arg: Float) = kotlin.math.sin(arg)
|
||||||
override inline fun cos(arg: Float) = kotlin.math.cos(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 power(arg: Float, pow: Number) = arg.pow(pow.toFloat())
|
||||||
|
|
||||||
override inline fun exp(arg: Float) = kotlin.math.exp(arg)
|
override inline fun exp(arg: Float) = kotlin.math.exp(arg)
|
||||||
|
@ -10,30 +10,37 @@ package scientifik.kmath.operations
|
|||||||
* It also allows to override behavior for optional operations
|
* It also allows to override behavior for optional operations
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
interface TrigonometricOperations<T> : FieldOperations<T> {
|
interface TrigonometricOperations<T> {
|
||||||
fun sin(arg: T): T
|
fun sin(arg: T): T
|
||||||
fun cos(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 <T : MathElement<out TrigonometricOperations<T>>> sin(arg: T): T = arg.context.sin(arg)
|
fun <T : MathElement<out TrigonometricOperations<T>>> sin(arg: T): T = arg.context.sin(arg)
|
||||||
fun <T : MathElement<out TrigonometricOperations<T>>> cos(arg: T): T = arg.context.cos(arg)
|
fun <T : MathElement<out TrigonometricOperations<T>>> cos(arg: T): T = arg.context.cos(arg)
|
||||||
fun <T : MathElement<out TrigonometricOperations<T>>> tg(arg: T): T = arg.context.tg(arg)
|
fun <T : MathElement<out TrigonometricOperations<T>>> tan(arg: T): T = arg.context.tan(arg)
|
||||||
fun <T : MathElement<out TrigonometricOperations<T>>> ctg(arg: T): T = arg.context.ctg(arg)
|
|
||||||
|
|
||||||
/* Power and roots */
|
/* Power and roots */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A context extension to include power operations like square roots, etc
|
* A context extension to include power operations like square roots, etc
|
||||||
*/
|
*/
|
||||||
interface PowerOperations<T> : Algebra<T> {
|
interface PowerOperations<T> {
|
||||||
fun power(arg: T, pow: Number): T
|
fun power(arg: T, pow: Number): T
|
||||||
fun sqrt(arg: T) = power(arg, 0.5)
|
fun sqrt(arg: T) = power(arg, 0.5)
|
||||||
|
|
||||||
infix fun T.pow(pow: Number) = power(this, pow)
|
infix fun T.pow(pow: Number) = power(this, pow)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val POW_OPERATION = "pow"
|
||||||
|
const val SQRT_OPERATION = "sqrt"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun <T : MathElement<out PowerOperations<T>>> T.pow(power: Double): T = context.power(this, power)
|
infix fun <T : MathElement<out PowerOperations<T>>> T.pow(power: Double): T = context.power(this, power)
|
||||||
@ -42,9 +49,14 @@ fun <T : MathElement<out PowerOperations<T>>> sqr(arg: T): T = arg pow 2.0
|
|||||||
|
|
||||||
/* Exponential */
|
/* Exponential */
|
||||||
|
|
||||||
interface ExponentialOperations<T>: Algebra<T> {
|
interface ExponentialOperations<T> {
|
||||||
fun exp(arg: T): T
|
fun exp(arg: T): T
|
||||||
fun ln(arg: T): T
|
fun ln(arg: T): T
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val EXP_OPERATION = "exp"
|
||||||
|
const val LN_OPERATION = "ln"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : MathElement<out ExponentialOperations<T>>> exp(arg: T): T = arg.context.exp(arg)
|
fun <T : MathElement<out ExponentialOperations<T>>> exp(arg: T): T = arg.context.exp(arg)
|
||||||
|
Loading…
Reference in New Issue
Block a user