Skip to content

Commit ef747f6

Browse files
authored
Merge pull request #458 from mipt-npm/commandertvis/no-evaluate
Remove Algebra.evaluate(MST) by inlining it into interpret
2 parents 53ab833 + e094f6e commit ef747f6

File tree

3 files changed

+59
-70
lines changed

3 files changed

+59
-70
lines changed

kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package space.kscience.kmath.ast
77

88
import space.kscience.kmath.complex.Complex
99
import space.kscience.kmath.complex.ComplexField
10-
import space.kscience.kmath.expressions.evaluate
10+
import space.kscience.kmath.expressions.interpret
1111
import space.kscience.kmath.operations.Algebra
1212
import space.kscience.kmath.operations.DoubleField
1313
import kotlin.test.Test
@@ -17,22 +17,22 @@ internal class TestParser {
1717
@Test
1818
fun evaluateParsedMst() {
1919
val mst = "2+2*(2+2)".parseMath()
20-
val res = ComplexField.evaluate(mst)
20+
val res = mst.interpret(ComplexField)
2121
assertEquals(Complex(10.0, 0.0), res)
2222
}
2323

2424
@Test
2525
fun evaluateMstSymbol() {
2626
val mst = "i".parseMath()
27-
val res = ComplexField.evaluate(mst)
27+
val res = mst.interpret(ComplexField)
2828
assertEquals(ComplexField.i, res)
2929
}
3030

3131

3232
@Test
3333
fun evaluateMstUnary() {
3434
val mst = "sin(0)".parseMath()
35-
val res = DoubleField.evaluate(mst)
35+
val res = mst.interpret(DoubleField)
3636
assertEquals(0.0, res)
3737
}
3838

@@ -53,7 +53,7 @@ internal class TestParser {
5353
}
5454

5555
val mst = "magic(a, b)".parseMath()
56-
val res = magicalAlgebra.evaluate(mst)
56+
val res = mst.interpret(magicalAlgebra)
5757
assertEquals("a ★ b", res)
5858
}
5959
}

kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,35 @@
55

66
package space.kscience.kmath.ast
77

8-
import space.kscience.kmath.expressions.evaluate
8+
import space.kscience.kmath.expressions.interpret
99
import space.kscience.kmath.operations.DoubleField
1010
import kotlin.test.Test
1111
import kotlin.test.assertEquals
1212

1313
internal class TestParserPrecedence {
1414
@Test
15-
fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath()))
15+
fun test1(): Unit = assertEquals(6.0, "2*2+2".parseMath().interpret(f))
1616

1717
@Test
18-
fun test2(): Unit = assertEquals(6.0, f.evaluate("2+2*2".parseMath()))
18+
fun test2(): Unit = assertEquals(6.0, "2+2*2".parseMath().interpret(f))
1919

2020
@Test
21-
fun test3(): Unit = assertEquals(10.0, f.evaluate("2^3+2".parseMath()))
21+
fun test3(): Unit = assertEquals(10.0, "2^3+2".parseMath().interpret(f))
2222

2323
@Test
24-
fun test4(): Unit = assertEquals(10.0, f.evaluate("2+2^3".parseMath()))
24+
fun test4(): Unit = assertEquals(10.0, "2+2^3".parseMath().interpret(f))
2525

2626
@Test
27-
fun test5(): Unit = assertEquals(16.0, f.evaluate("2^3*2".parseMath()))
27+
fun test5(): Unit = assertEquals(16.0, "2^3*2".parseMath().interpret(f))
2828

2929
@Test
30-
fun test6(): Unit = assertEquals(16.0, f.evaluate("2*2^3".parseMath()))
30+
fun test6(): Unit = assertEquals(16.0, "2*2^3".parseMath().interpret(f))
3131

3232
@Test
33-
fun test7(): Unit = assertEquals(18.0, f.evaluate("2+2^3*2".parseMath()))
33+
fun test7(): Unit = assertEquals(18.0, "2+2^3*2".parseMath().interpret(f))
3434

3535
@Test
36-
fun test8(): Unit = assertEquals(18.0, f.evaluate("2*2^3+2".parseMath()))
36+
fun test8(): Unit = assertEquals(18.0, "2*2^3+2".parseMath().interpret(f))
3737

3838
private companion object {
3939
private val f = DoubleField

kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt

Lines changed: 45 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package space.kscience.kmath.expressions
77

88
import space.kscience.kmath.operations.Algebra
99
import space.kscience.kmath.operations.NumericAlgebra
10-
import space.kscience.kmath.operations.bindSymbol
10+
import space.kscience.kmath.operations.bindSymbolOrNull
1111

1212
/**
1313
* A Mathematical Syntax Tree (MST) node for mathematical expressions.
@@ -43,80 +43,69 @@ public sealed interface MST {
4343

4444
// TODO add a function with named arguments
4545

46+
4647
/**
47-
* Interprets the [MST] node with this [Algebra].
48-
*
49-
* @receiver the algebra that provides operations.
50-
* @param node the node to evaluate.
51-
* @return the value of expression.
52-
* @author Alexander Nozik
48+
* Interprets the [MST] node with this [Algebra] and optional [arguments]
5349
*/
54-
public fun <T> Algebra<T>.evaluate(node: MST): T = when (node) {
55-
is MST.Numeric -> (this as? NumericAlgebra<T>)?.number(node.value)
56-
?: error("Numeric nodes are not supported by $this")
50+
public fun <T> MST.interpret(algebra: Algebra<T>, arguments: Map<Symbol, T>): T = when (this) {
51+
is MST.Numeric -> (algebra as NumericAlgebra<T>?)?.number(value)
52+
?: error("Numeric nodes are not supported by $algebra")
5753

58-
is Symbol -> bindSymbol(node)
54+
is Symbol -> algebra.bindSymbolOrNull(this) ?: arguments.getValue(this)
5955

6056
is MST.Unary -> when {
61-
this is NumericAlgebra && node.value is MST.Numeric -> unaryOperationFunction(node.operation)(number(node.value.value))
62-
else -> unaryOperationFunction(node.operation)(evaluate(node.value))
57+
algebra is NumericAlgebra && this.value is MST.Numeric -> algebra.unaryOperation(
58+
this.operation,
59+
algebra.number(this.value.value),
60+
)
61+
else -> algebra.unaryOperationFunction(this.operation)(this.value.interpret(algebra, arguments))
6362
}
6463

6564
is MST.Binary -> when {
66-
this is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric ->
67-
binaryOperationFunction(node.operation)(number(node.left.value), number(node.right.value))
68-
69-
this is NumericAlgebra && node.left is MST.Numeric ->
70-
leftSideNumberOperationFunction(node.operation)(node.left.value, evaluate(node.right))
71-
72-
this is NumericAlgebra && node.right is MST.Numeric ->
73-
rightSideNumberOperationFunction(node.operation)(evaluate(node.left), node.right.value)
74-
75-
else -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right))
65+
algebra is NumericAlgebra && this.left is MST.Numeric && this.right is MST.Numeric -> algebra.binaryOperation(
66+
this.operation,
67+
algebra.number(this.left.value),
68+
algebra.number(this.right.value),
69+
)
70+
71+
algebra is NumericAlgebra && this.left is MST.Numeric -> algebra.leftSideNumberOperation(
72+
this.operation,
73+
this.left.value,
74+
this.right.interpret(algebra, arguments),
75+
)
76+
77+
algebra is NumericAlgebra && this.right is MST.Numeric -> algebra.rightSideNumberOperation(
78+
this.operation,
79+
left.interpret(algebra, arguments),
80+
right.value,
81+
)
82+
83+
else -> algebra.binaryOperation(
84+
this.operation,
85+
this.left.interpret(algebra, arguments),
86+
this.right.interpret(algebra, arguments),
87+
)
7688
}
7789
}
7890

79-
internal class InnerAlgebra<T>(val algebra: Algebra<T>, val arguments: Map<Symbol, T>) : NumericAlgebra<T> {
80-
override fun bindSymbolOrNull(value: String): T? = algebra.bindSymbolOrNull(value) ?: arguments[StringSymbol(value)]
81-
82-
override fun unaryOperation(operation: String, arg: T): T =
83-
algebra.unaryOperation(operation, arg)
84-
85-
override fun binaryOperation(operation: String, left: T, right: T): T =
86-
algebra.binaryOperation(operation, left, right)
87-
88-
override fun unaryOperationFunction(operation: String): (arg: T) -> T =
89-
algebra.unaryOperationFunction(operation)
90-
91-
override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T =
92-
algebra.binaryOperationFunction(operation)
93-
94-
@Suppress("UNCHECKED_CAST")
95-
override fun number(value: Number): T = if (algebra is NumericAlgebra<*>)
96-
(algebra as NumericAlgebra<T>).number(value)
97-
else
98-
error("Numeric nodes are not supported by $this")
99-
}
100-
101-
/**
102-
* Interprets the [MST] node with this [Algebra] and optional [arguments]
103-
*/
104-
public fun <T> MST.interpret(algebra: Algebra<T>, arguments: Map<Symbol, T>): T =
105-
InnerAlgebra(algebra, arguments).evaluate(this)
106-
10791
/**
10892
* Interprets the [MST] node with this [Algebra] and optional [arguments]
10993
*
11094
* @receiver the node to evaluate.
11195
* @param algebra the algebra that provides operations.
11296
* @return the value of expression.
11397
*/
114-
public fun <T> MST.interpret(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T =
115-
interpret(algebra, mapOf(*arguments))
98+
public fun <T> MST.interpret(algebra: Algebra<T>, vararg arguments: Pair<Symbol, T>): T = interpret(
99+
algebra,
100+
when (arguments.size) {
101+
0 -> emptyMap()
102+
1 -> mapOf(arguments[0])
103+
else -> hashMapOf(*arguments)
104+
},
105+
)
116106

117107
/**
118108
* Interpret this [MST] as expression.
119109
*/
120-
public fun <T : Any> MST.toExpression(algebra: Algebra<T>): Expression<T> = Expression { arguments ->
121-
interpret(algebra, arguments)
122-
}
110+
public fun <T : Any> MST.toExpression(algebra: Algebra<T>): Expression<T> =
111+
Expression { arguments -> interpret(algebra, arguments) }

0 commit comments

Comments
 (0)