Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 12 additions & 64 deletions src/main/scala/io/github/facaiy/math/expression/Expression.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.facaiy.math.expression

import io.github.facaiy.math.expression.compiler.parser._
import scala.reflect.ClassTag

/**
* Created by facai on 6/19/17.
Expand All @@ -13,20 +14,23 @@ case class Expression[A, B](eval: A => B) {
}

object Expression {
import FunctionRegister._
import Operations.Operators

def toExpression(ast: MathExpAST): Expression[String => Double, Double] = ast match {
case Constant(d: Double) => Expression(_ => d)
def toExpression[T: ClassTag : Operators](ast: MathExpAST): Expression[String => T, T] = ast match {
case Constant(d: T) => Expression(_ => d)
case c @ Constant(_) => throw new IllegalArgumentException(c.toString)
case Variable(n) => Expression(f => f(n))
case Operator2(op, v1, v2) =>
toExpression(v1).map2(toExpression(v2))(function2(op))
val a: Expression[(String) => T, T] = toExpression[T](v1)
a.map2[T, T](toExpression[T](v2))(implicitly[Operators[T]].binaryOps(op))

case f @ OperatorN(op, as) =>
val args = sequence(as.map(toExpression)).map(_.toArray)
args.map{ xs: Array[Double] =>
val a: Expression[(String) => T, List[T]] = sequence[(String) => T, T](as.map(toExpression[T] _))
val args: Expression[(String) => T, Array[T]] = a.map(d => d.toArray[T])
args.map{ xs: Array[T] =>
xs.size match {
case 1 => function1(op)(xs.head)
case 2 => function2(op)(xs.head, xs(2))
case 1 => implicitly[Operators[T]].unaryOps(op)(xs.head)
case 2 => implicitly[Operators[T]].binaryOps(op)(xs.head, xs(2))
case _ => throw new UnsupportedOperationException(f.toString)
}
}
Expand All @@ -39,59 +43,3 @@ object Expression {
(e, acc) => Expression(x => e.eval(x) :: acc.eval(x)))
}

object FunctionRegister {
val function1: Map[String, Double => Double] = Map(
// scala.math
// Rounding
"ceil" -> Math.ceil,
"floor" -> Math.floor,
"rint" -> Math.rint,
"round" -> ((x: Double) => Math.round(x)).andThen(_.toDouble),
// Exponential and Logarithmic
"exp" -> Math.exp,
"expm1" -> Math.expm1,
"log" -> Math.log,
"log10" -> Math.log10,
"log1p" -> Math.log1p,
// Trigonometric
"acos" -> Math.acos,
"asin" -> Math.asin,
"atan" -> Math.atan,
"cos" -> Math.cos,
"sin" -> Math.sin,
"tan" -> Math.tan,
// Angular Measurement Conversion
"toDegrees" -> Math.toDegrees,
"toRadians" -> Math.toRadians,
// Hyperbolic
"cosh" -> Math.cosh,
"sinh" -> Math.sinh,
"tanh" -> Math.tanh,
// Absolute Values
"abs" -> Math.abs,
// Signs
"signum" -> Math.signum,
// Root Extraction
"cbrt" -> Math.cbrt,
"sqrt" -> Math.sqrt,
// Unit of Least Precision
"ulp" -> Math.ulp
)

val function2: Map[String, (Double, Double) => Double] = Map(
"+" -> (_ + _),
"-" -> (_ - _),
"*" -> (_ * _),
"/" -> (_ / _),
// scala.math
// Minimum and Maximum
"max" -> Math.max,
"min" -> Math.min,
// Exponential and Logarithmic
"**" -> Math.pow,
"pow" -> Math.pow,
// Polar Coordinates
"atan2" -> Math.atan2,
"hypot" -> Math.hypot
)
}
7 changes: 5 additions & 2 deletions src/main/scala/io/github/facaiy/math/expression/MathExp.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.github.facaiy.math.expression

import io.github.facaiy.math.expression.Operations.Operators
import io.github.facaiy.math.expression.compiler.MathExpCompiler
import scala.reflect.ClassTag

/**
* Created by facai on 6/19/17.
Expand All @@ -10,9 +12,10 @@ case class MathExpScannerError(msg: String) extends MathExpError
case class MathExpParserError(msg: String) extends MathExpError

object MathExp {
def parse(s: String): Expression[String => Double, Double] =
def parse[T: ClassTag: Operators](s: String): Expression[String => T, T] = {
MathExpCompiler(s) match {
case Right(ts) => Expression.toExpression(ts)
case Right(ts) => Expression.toExpression[T](ts)
case Left(e) => throw new IllegalArgumentException(e.toString)
}
}
}
69 changes: 69 additions & 0 deletions src/main/scala/io/github/facaiy/math/expression/Operations.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.github.facaiy.math.expression

/**
* Created by fshao on 9/5/17.
*/
object Operations {
trait Operators[T] {
def unaryOps: Map[String, T => T]
def binaryOps: Map[String, (T, T) => T]
}
object Operators {
implicit object DoubleOps extends Operators[Double] {
val unaryOps: Map[String, Double => Double] = Map(
// scala.math
// Rounding
"ceil" -> Math.ceil,
"floor" -> Math.floor,
"rint" -> Math.rint,
"round" -> ((x: Double) => Math.round(x)).andThen(_.toDouble),
// Exponential and Logarithmic
"exp" -> Math.exp,
"expm1" -> Math.expm1,
"log" -> Math.log,
"log10" -> Math.log10,
"log1p" -> Math.log1p,
// Trigonometric
"acos" -> Math.acos,
"asin" -> Math.asin,
"atan" -> Math.atan,
"cos" -> Math.cos,
"sin" -> Math.sin,
"tan" -> Math.tan,
// Angular Measurement Conversion
"toDegrees" -> Math.toDegrees,
"toRadians" -> Math.toRadians,
// Hyperbolic
"cosh" -> Math.cosh,
"sinh" -> Math.sinh,
"tanh" -> Math.tanh,
// Absolute Values
"abs" -> Math.abs,
// Signs
"signum" -> Math.signum,
// Root Extraction
"cbrt" -> Math.cbrt,
"sqrt" -> Math.sqrt,
// Unit of Least Precision
"ulp" -> Math.ulp
)

val binaryOps: Map[String, (Double, Double) => Double] = Map(
"+" -> (_ + _),
"-" -> (_ - _),
"*" -> (_ * _),
"/" -> (_ / _),
// scala.math
// Minimum and Maximum
"max" -> Math.max,
"min" -> Math.min,
// Exponential and Logarithmic
"**" -> Math.pow,
"pow" -> Math.pow,
// Polar Coordinates
"atan2" -> Math.atan2,
"hypot" -> Math.hypot
)
}
}
}