Skip to content

Commit 2b8efbf

Browse files
committed
reduced the spire languages to number languages
1 parent 2162bc3 commit 2b8efbf

14 files changed

+79
-185
lines changed

examples/src/main/scala/Readme.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
import mathParser.SpireImplicits.given
2-
31
object Readme extends App {
42
// your input, any string represesenting a function:
53
val string = "2*x*x + 1"
64

7-
import mathParser.SpireImplicits._
5+
import mathParser.number.DoubleLanguage.given
86

97
// define your language:
108
object X
11-
val language = mathParser.SpireLanguages.doubleLanguage.withVariables(List("x" -> X))
9+
val language = mathParser.BuildIn.doubleLanguage.withVariables(List("x" -> X))
1210

1311
// parsing: string => Option[AST]
1412
// .get only to demonstrate.

examples/src/main/scala/plotter/FunctionPlotterCli.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package plotter
22

33
import de.sciss.chart.api._
4-
import mathParser.SpireImplicits.given
4+
import mathParser.number.DoubleLanguage.given
55
import org.jfree.chart.ChartPanel
66

77
import java.io.File

math-parser-spire/src/main/scala/mathParser/SpireImplicits.scala

Lines changed: 0 additions & 3 deletions
This file was deleted.

math-parser-spire/src/main/scala/mathParser/SpireLanguages.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@ package mathParser
22

33
import mathParser.algebra.SpireLanguage
44
import mathParser.boolean.{BooleanBinaryOperator, BooleanLanguage, BooleanUnitaryOperator}
5+
import mathParser.number.{NumberBinaryOperator, NumberUnitaryOperator}
56
import spire.implicits._
67
import spire.math.{Complex, Real}
8+
import spire.algebra.Field
79

810
object SpireLanguages {
9-
val doubleLanguage: SpireLanguage[Double, Nothing] =
11+
val doubleLanguage: Language[NumberUnitaryOperator, NumberBinaryOperator, Double, Nothing] =
1012
SpireLanguage[Double]
1113

12-
val complexLanguage: SpireLanguage[Complex[Double], Nothing] =
14+
val complexLanguage: Language[NumberUnitaryOperator, NumberBinaryOperator, Complex[Double], Nothing] =
1315
SpireLanguage[Complex[Double]]
1416
.addConstant("i", Complex.i[Double])
1517

16-
val realLanguage: SpireLanguage[Real, Nothing] =
18+
val realLanguage: Language[NumberUnitaryOperator, NumberBinaryOperator, Real, Nothing] =
1719
SpireLanguage[Real]
1820
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package mathParser.algebra
2+
3+
import mathParser.Evaluate
4+
import mathParser.number.{NumberBinaryOperator, NumberUnitaryOperator}
5+
import mathParser.number.NumberBinaryOperator.*
6+
import mathParser.number.NumberUnitaryOperator.*
7+
import spire.algebra.{Field, NRoot, Trig}
8+
9+
class SpireEvaluate[A: Field: NRoot: Trig, V] extends Evaluate[NumberUnitaryOperator, NumberBinaryOperator, A, V] {
10+
def executeUnitary(uo: NumberUnitaryOperator, s: A): A = uo match {
11+
case Neg => Field[A].negate(s)
12+
case Sin => Trig[A].sin(s)
13+
case Cos => Trig[A].cos(s)
14+
case Tan => Trig[A].tan(s)
15+
case Asin => Trig[A].asin(s)
16+
case Acos => Trig[A].acos(s)
17+
case Atan => Trig[A].atan(s)
18+
case Sinh => Trig[A].sinh(s)
19+
case Cosh => Trig[A].cosh(s)
20+
case Tanh => Trig[A].tanh(s)
21+
case Exp => Trig[A].exp(s)
22+
case Log => Trig[A].log(s)
23+
}
24+
25+
def executeBinaryOperator(bo: NumberBinaryOperator, left: A, right: A): A = bo match {
26+
case Plus => Field[A].plus(left, right)
27+
case Minus => Field[A].minus(left, right)
28+
case Times => Field[A].times(left, right)
29+
case Divided => Field[A].div(left, right)
30+
case Power => NRoot[A].fpow(left, right)
31+
}
32+
}

math-parser-spire/src/main/scala/mathParser/algebra/SpireImplicits.scala

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 15 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,33 @@
11
package mathParser
22
package algebra
33

4+
import mathParser.number.{NumberBinaryOperator, NumberUnitaryOperator}
5+
import mathParser.number.NumberBinaryOperator.*
6+
import mathParser.number.NumberUnitaryOperator.*
7+
import mathParser.number.NumberSyntax.*
8+
import mathParser.AbstractSyntaxTree.*
49
import spire.algebra.{Field, NRoot, Trig}
510

611
import scala.util.Try
7-
import mathParser.AbstractSyntaxTree.*
12+
import mathParser.{AbstractSyntaxTree, Evaluate}
813

914
object SpireLanguage {
10-
11-
import syntax._
12-
13-
def apply[A: Field: NRoot: Trig]: SpireLanguage[A, Nothing] =
15+
def apply[A: Field: NRoot: Trig]: Language[NumberUnitaryOperator, NumberBinaryOperator, A, Nothing] =
1416
Language.emptyLanguage
1517
.withConstants[A](List("e" -> Trig[A].e, "pi" -> Trig[A].pi))
16-
.withBinaryOperators[SpireBinaryOperator](prefix = List.empty, infix = List(Plus, Minus, Times, Divided, Power).map(op => (op.name, op)))
18+
.withBinaryOperators[NumberBinaryOperator](prefix = List.empty, infix = List(Plus, Minus, Times, Divided, Power).map(op => (op.name, op)))
1719
.withUnitaryOperators(List(Neg, Sin, Cos, Tan, Asin, Acos, Atan, Sinh, Cosh, Tanh, Exp, Log).map(op => (op.name, op)))
1820

19-
def spireLiteralParser[A: Field]: LiteralParser[A] = s => Try(Field[A].fromDouble(s.toDouble)).toOption
20-
21-
def spireEvaluate[A: Field: NRoot: Trig, V]: Evaluate[SpireUnitaryOperator, SpireBinaryOperator, A, V] =
22-
new Evaluate[SpireUnitaryOperator, SpireBinaryOperator, A, V] {
23-
def executeUnitary(uo: SpireUnitaryOperator, s: A): A = uo match {
24-
case Neg => Field[A].negate(s)
25-
case Sin => Trig[A].sin(s)
26-
case Cos => Trig[A].cos(s)
27-
case Tan => Trig[A].tan(s)
28-
case Asin => Trig[A].asin(s)
29-
case Acos => Trig[A].acos(s)
30-
case Atan => Trig[A].atan(s)
31-
case Sinh => Trig[A].sinh(s)
32-
case Cosh => Trig[A].cosh(s)
33-
case Tanh => Trig[A].tanh(s)
34-
case Exp => Trig[A].exp(s)
35-
case Log => Trig[A].log(s)
36-
}
37-
38-
def executeBinaryOperator(bo: SpireBinaryOperator, left: A, right: A): A = bo match {
39-
case Plus => Field[A].plus(left, right)
40-
case Minus => Field[A].minus(left, right)
41-
case Times => Field[A].times(left, right)
42-
case Divided => Field[A].div(left, right)
43-
case Power => NRoot[A].fpow(left, right)
44-
}
45-
}
46-
47-
def spireOptimizer[A: Field: NRoot: Trig, V]: Optimizer[SpireUnitaryOperator, SpireBinaryOperator, A, V] =
48-
new Optimizer[SpireUnitaryOperator, SpireBinaryOperator, A, V] {
49-
override def rules: List[PartialFunction[SpireNode[A, V], SpireNode[A, V]]] = List(
50-
Optimize.replaceConstantsRule(using spireEvaluate), {
51-
case UnitaryNode(Neg, UnitaryNode(Neg, child)) => child
52-
case BinaryNode(Plus, left, ConstantNode(0d)) => left
53-
case BinaryNode(Plus, ConstantNode(0d), right) => right
54-
case BinaryNode(Times, ConstantNode(0d), _) => zero
55-
case BinaryNode(Times, _, ConstantNode(0d)) => zero
56-
case BinaryNode(Times, left, ConstantNode(1d)) => left
57-
case BinaryNode(Times, ConstantNode(1d), right) => right
58-
case BinaryNode(Power, left, ConstantNode(1d)) => left
59-
case BinaryNode(Power, _, ConstantNode(0d)) => one[A, V]
60-
case BinaryNode(Power, ConstantNode(1d), _) => one[A, V]
61-
case BinaryNode(Power, ConstantNode(0d), _) => zero[A, V]
62-
case UnitaryNode(Log, UnitaryNode(Exp, child)) => child
63-
case BinaryNode(Plus, left, UnitaryNode(Neg, child)) => left - child
64-
case BinaryNode(Minus, left, UnitaryNode(Neg, child)) => left + child
65-
case BinaryNode(Minus, left, right) if left == right => zero
66-
case BinaryNode(Divided, left, right) if left == right => one
67-
}
68-
)
69-
}
70-
71-
def spireDerive[A: Field: Trig: NRoot, V]: Derive[SpireUnitaryOperator, SpireBinaryOperator, A, V] =
72-
new Derive[SpireUnitaryOperator, SpireBinaryOperator, A, V] {
73-
def derive(term: SpireNode[A, V])(variable: V): SpireNode[A, V] = {
74-
def derive(term: SpireNode[A, V]): SpireNode[A, V] = term match {
75-
case VariableNode(`variable`) => one
76-
case VariableNode(_) | ConstantNode(_) => zero
77-
case UnitaryNode(op, f) =>
78-
op match {
79-
case Neg => neg(derive(f))
80-
case Sin => derive(f) * cos(f)
81-
case Cos => neg(derive(f) * sin(f))
82-
case Tan => derive(f) / (cos(f) * cos(f))
83-
case Asin => derive(f) / sqrt(one - (f * f))
84-
case Acos => neg(derive(f)) / sqrt(one - (f * f))
85-
case Atan => derive(f) / (one + (f * f))
86-
case Sinh => derive(f) * cosh(f)
87-
case Cosh => derive(f) * sinh(f)
88-
case Tanh => derive(f) / (cosh(f) * cosh(f))
89-
case Exp => exp(f) * derive(f)
90-
case Log => derive(f) / f
91-
}
92-
case BinaryNode(op, f, g) =>
93-
op match {
94-
case Plus => derive(f) + derive(g)
95-
case Minus => derive(f) - derive(g)
96-
case Times => (derive(f) * g) + (derive(g) * f)
97-
case Divided => ((f * derive(g)) - (g * derive(f))) / (g * g)
98-
case Power => (f ^ (g - one)) * ((g * derive(f)) + (f * log(f) * derive(g)))
99-
}
100-
}
21+
given[A] (using field: Field[A]): mathParser.number.Number[A] = mathParser.number.Number.contraMap(field.fromDouble)
10122

102-
derive(term)
103-
}
104-
}
23+
given spireLiteralParser[A: Field]: LiteralParser[A] = s => s.toDoubleOption.map(Field[A].fromDouble)
10524

106-
object syntax {
107-
def neg[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Neg, t)
108-
def sin[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Sin, t)
109-
def cos[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Cos, t)
110-
def tan[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Tan, t)
111-
def asin[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Asin, t)
112-
def acos[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Acos, t)
113-
def atan[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Atan, t)
114-
def sinh[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Sinh, t)
115-
def cosh[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Cosh, t)
116-
def tanh[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Tanh, t)
117-
def exp[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Exp, t)
118-
def log[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = UnitaryNode(Log, t)
25+
given [A: Field: NRoot: Trig, V]: Evaluate[NumberUnitaryOperator, NumberBinaryOperator, A, V] = SpireEvaluate()
11926

120-
def sqrt[A: Field: Trig: NRoot, V](t: SpireNode[A, V]): SpireNode[A, V] = BinaryNode(Power, t, ConstantNode(Field[A].fromDouble(0.5)))
27+
given [A: Field: NRoot: Trig, V]: Optimizer[NumberUnitaryOperator, NumberBinaryOperator, A, V] =
28+
mathParser.number.NumberOptimizer()
12129

122-
extension [A: Field: Trig: NRoot, V](t1: SpireNode[A, V]) {
123-
def +(t2: SpireNode[A, V]): SpireNode[A, V] = BinaryNode(Plus, t1, t2)
124-
def -(t2: SpireNode[A, V]): SpireNode[A, V] = BinaryNode(Minus, t1, t2)
125-
def *(t2: SpireNode[A, V]): SpireNode[A, V] = BinaryNode(Times, t1, t2)
126-
def /(t2: SpireNode[A, V]): SpireNode[A, V] = BinaryNode(Divided, t1, t2)
127-
def ^(t2: SpireNode[A, V]): SpireNode[A, V] = BinaryNode(Power, t1, t2)
128-
}
30+
given [A:Field:NRoot:Trig, V]: Derive[NumberUnitaryOperator, NumberBinaryOperator, A, V] =
31+
mathParser.number.NumberDerive()
12932

130-
def zero[A: Field: Trig: NRoot, V]: SpireNode[A, V] = ConstantNode(Field[A].zero)
131-
def one[A: Field: Trig: NRoot, V]: SpireNode[A, V] = ConstantNode(Field[A].one)
132-
def two[A: Field: Trig: NRoot, V]: SpireNode[A, V] = ConstantNode(Field[A].fromInt(2))
133-
}
13433
}

math-parser-spire/src/main/scala/mathParser/algebra/SpireOperators.scala

Lines changed: 0 additions & 23 deletions
This file was deleted.

math-parser-spire/src/main/scala/mathParser/algebra/package.scala

Lines changed: 0 additions & 6 deletions
This file was deleted.

math-parser-spire/src/test/scala/mathParser/algebra/DeriveSpec.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package mathParser.algebra
22

3-
import mathParser.SpireImplicits.given
4-
import mathParser.SpireLanguages
3+
import mathParser.Language
4+
import mathParser.number.{NumberBinaryOperator, NumberUnitaryOperator}
5+
import spire.implicits.given
6+
import mathParser.algebra.SpireLanguage.given
57
import org.scalatest.funsuite.AnyFunSuite
68
import org.scalatest.matchers.should.Matchers
79
import spire.algebra.{Field, NRoot, Trig}
10+
import mathParser.SpireLanguages
811

912
class DeriveSpec extends AnyFunSuite with Matchers {
1013
case object X
@@ -14,7 +17,7 @@ class DeriveSpec extends AnyFunSuite with Matchers {
1417
testTemplate(SpireLanguages.realLanguage, "real language")
1518
testTemplate(SpireLanguages.complexLanguage, "complex language")
1619

17-
def testTemplate[A: Field: Trig: NRoot](_lang: SpireLanguage[A, Nothing], langName: String) = {
20+
def testTemplate[A: Field: Trig: NRoot](_lang: Language[NumberUnitaryOperator, NumberBinaryOperator, A, Nothing], langName: String) = {
1821
val lang = _lang.withVariables[X.type](List("x" -> X))
1922

2023
import lang.{derive, parse}

math-parser-spire/src/test/scala/mathParser/algebra/OptimizationSpec.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package mathParser.algebra
22

3-
import mathParser.SpireImplicits.given
3+
import mathParser.Language
4+
import mathParser.number.{NumberBinaryOperator, NumberUnitaryOperator}
5+
import spire.implicits.given
6+
import mathParser.algebra.SpireLanguage.given
47
import mathParser.{LiteralParser, SpireLanguages}
58
import org.scalatest.funsuite.AnyFunSuite
69
import org.scalatest.matchers.should.Matchers
@@ -14,7 +17,7 @@ class OptimizationSpec extends AnyFunSuite with Matchers {
1417
testLanguage(SpireLanguages.realLanguage, "real language")
1518
testLanguage(SpireLanguages.complexLanguage, "complex language")
1619

17-
def testLanguage[A: Field: Trig: NRoot: LiteralParser](_lang: SpireLanguage[A, Nothing], langName: String) = {
20+
def testLanguage[A: Field: Trig: NRoot: LiteralParser](_lang: Language[NumberUnitaryOperator, NumberBinaryOperator, A, Nothing], langName: String) = {
1821
val lang = _lang.withVariables[X.type](List("x" -> X))
1922

2023
val identities = Seq(

math-parser-spire/src/test/scala/mathParser/algebra/ParseComplexSpec.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package mathParser.algebra
22

3-
import mathParser.SpireImplicits.given
43
import mathParser.SpireLanguages
4+
import mathParser.algebra.SpireLanguage.given
5+
import spire.implicits._
56
import org.scalatest.funsuite.AnyFunSuite
67
import org.scalatest.matchers.should.Matchers
78
import spire.math.Complex

math-parser-spire/src/test/scala/mathParser/algebra/ParseSpec.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package mathParser.algebra
22

3-
import mathParser.SpireImplicits.given
4-
import mathParser.algebra.SpireLanguage.syntax._
3+
import spire.implicits.given
4+
import mathParser.algebra.SpireLanguage.given
5+
import mathParser.Language
6+
import mathParser.number.NumberSyntax._
7+
import mathParser.number.{NumberBinaryOperator, NumberUnitaryOperator}
58
import mathParser.{ConstantNode, LiteralParser, SpireLanguages}
69
import org.scalatest.funsuite.AnyFunSuite
710
import org.scalatest.matchers.should.Matchers
@@ -21,7 +24,7 @@ class ParseSpec extends AnyFunSuite with Matchers {
2124
testTemplate(SpireLanguages.realLanguage.withVariables[V](vList), "real language")
2225
testTemplate(SpireLanguages.complexLanguage.withVariables[V](vList), "complex language")
2326

24-
def testTemplate[A: Field: Trig: NRoot: LiteralParser](lang: SpireLanguage[A, V], langName: String) = {
27+
def testTemplate[A: Field: Trig: NRoot: LiteralParser](lang: Language[NumberUnitaryOperator, NumberBinaryOperator,A, V], langName: String) = {
2528
test(s"$langName: parsing constants, literals and variables") {
2629
for ((name, value) <- lang.constants)
2730
lang.parse(name) shouldEqual Some(lang.constantNode(value))

math-parser-spire/src/test/scala/mathParser/algebra/TimedParseSpec.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package mathParser.algebra
22

3-
import mathParser.SpireImplicits.given
43
import mathParser.{LiteralParser, SpireLanguages}
4+
import spire.implicits._
5+
import mathParser.algebra.SpireLanguage.spireLiteralParser
56
import org.scalatest.concurrent.TimeLimitedTests
67
import org.scalatest.funsuite.AnyFunSuite
78
import org.scalatest.matchers.should.Matchers
89
import org.scalatest.time.{Millis, Span}
910
import spire.algebra.{Field, NRoot, Trig}
11+
import mathParser.Language
12+
import mathParser.number.{NumberBinaryOperator, NumberUnitaryOperator}
1013

1114
class TimedParseSpec extends AnyFunSuite with Matchers with TimeLimitedTests {
1215

@@ -22,7 +25,7 @@ class TimedParseSpec extends AnyFunSuite with Matchers with TimeLimitedTests {
2225
testTemplate(SpireLanguages.realLanguage.withVariables[V](vList), "real language")
2326
testTemplate(SpireLanguages.complexLanguage.withVariables[V](vList), "complex language")
2427

25-
def testTemplate[A: Field: Trig: NRoot: LiteralParser](lang: SpireLanguage[A, V], langName: String) = {
28+
def testTemplate[A: Field: Trig: NRoot: LiteralParser](lang: Language[NumberUnitaryOperator, NumberBinaryOperator, A, V], langName: String) = {
2629
test(s"$langName: parse expressions with many parenthesis") {
2730
val expr =
2831
"((((x * x + a) * (x * x + a) + a) * ((x * x + a) * (x * x + a) + a) + a) * (((x * x + a) * (x * x + a) + a) * ((x * x + a) * (x * x + a) + a) + a) + a)"

0 commit comments

Comments
 (0)