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
|
||||
*/
|
||||
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<T> : Space<T>, RingOperations<T>, NumericAlgebra<T> {
|
||||
|
||||
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)
|
||||
|
@ -10,9 +10,30 @@ interface ExtendedFieldOperations<T> :
|
||||
FieldOperations<T>,
|
||||
TrigonometricOperations<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.
|
||||
@ -44,6 +65,7 @@ object RealField : ExtendedField<Double>, Norm<Double, Double> {
|
||||
|
||||
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<Float>, Norm<Float, Float> {
|
||||
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)
|
||||
|
@ -10,30 +10,37 @@ package scientifik.kmath.operations
|
||||
* It also allows to override behavior for optional operations
|
||||
*
|
||||
*/
|
||||
interface TrigonometricOperations<T> : FieldOperations<T> {
|
||||
interface TrigonometricOperations<T> {
|
||||
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 <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>>> tg(arg: T): T = arg.context.tg(arg)
|
||||
fun <T : MathElement<out TrigonometricOperations<T>>> ctg(arg: T): T = arg.context.ctg(arg)
|
||||
fun <T : MathElement<out TrigonometricOperations<T>>> tan(arg: T): T = arg.context.tan(arg)
|
||||
|
||||
/* Power and roots */
|
||||
|
||||
/**
|
||||
* 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 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 : 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 */
|
||||
|
||||
interface ExponentialOperations<T>: Algebra<T> {
|
||||
interface ExponentialOperations<T> {
|
||||
fun exp(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)
|
||||
|
Loading…
Reference in New Issue
Block a user