import runtime.ScalaRunTime
object Test {
val p = new Pattern { }
import p._
implicit object IntOps extends NumericOps[Int] {
def zero = 0
def one = 1
def add(a: Int, b: Int): Int = a + b
def sub(a: Int, b: Int): Int = a - b
def mul(a: Int, b: Int): Int = a * b
def mul(a: Int, b: Double): Int = (a * b).toInt
def div(a: Int, b: Int): Int = a / b
def div(a: Int, b: Double): Int = (a / b).toInt
def similar(a: Int, b: Int): Boolean = a == b
def abs(a: Int): Double = math.abs(a).toDouble
def sqr(a: Int): Int = a * a
def sqrt(a: Int): Int = math.sqrt(a).toInt
def log(a: Int): Int = math.log(a).toInt
def exp(a: Int): Int = math.exp(a).toInt
def sin(a: Int): Int = math.sin(a).toInt
def cos(a: Int): Int = math.cos(a).toInt
def fromDouble(a: Double): Int = a.toInt
def fromInt(a: Int): Int = a
}
def main(args: Array[String]): Unit = {
println((5: Expr[Int]) + 10 + 15 * 20)
}
}
trait Pattern {
// For trying out 2.7.7
//
// type Numeric[T]
// import java.io.Serializable
//
// implicit def compat27a[T](x: Iterable[T]) = new {
// def iterator: Iterator[T] = x.elements
// def sum: Int = 5
// def collect[U](pf: PartialFunction[T, U]): Iterable[U] = x map pf
// }
/** Function that returns object of the same type it was passed */
trait EndoFunction[-A] {
def apply[B <: A](x: B): B
}
/** Allows for smart construction of EndoFunction from an ordinary function */
object EndoFunction {
def apply[A](f: A => A): EndoFunction[A] = new EndoFunction[A] {
def apply[B <: A](x: B): B = f(x).asInstanceOf[B]
}
}
trait NumericOps[T] extends Serializable {
def zero: T
def one: T
def two = add(one, one)
def three = add(two, one)
def add(a: T, b: T): T
def add(a: T, b: T, c: T): T = add(a, add(b, c))
def sub(a: T, b: T): T
def mul(a: T, b: T): T
def mul(a: T, b: Double): T
def div(a: T, b: T): T
def div(a: T, b: Double): T
def similar(a: T, b: T): Boolean
def neg(a: T) = sub(zero, a)
def abs(a: T): Double
def sqr(a: T): T
def sqrt(a: T): T
def log(a: T): T
def exp(a: T): T
def sin(a: T): T
def cos(a: T): T
def tan(a: T): T = div(sin(a), cos(a))
def fromDouble(a: Double): T
def fromInt(a: Int): T
def sum(terms: Iterable[T]) = terms.foldLeft(zero)(add)
def sum(terms: Iterator[T]) = terms.foldLeft(zero)(add)
def product(terms: Iterable[T]) = terms.foldLeft(one)(mul)
def product(terms: Iterator[T]) = terms.foldLeft(one)(mul)
def similar(a: Iterable[T], b: Iterable[T]): Boolean = {
val i1 = a.iterator
val i2 = b.iterator
while (i1.hasNext && i2.hasNext)
if (!similar(i1.next, i2.next))
return false;
true;
}
}
/**
* Simple expression interpreter with some basic symbolic manipulation.
* Able to evaluate derivatives.
*/
trait Expr[T] {
import Expr._
/** Evaluates value of the expression. */
def eval(context: Any => Any): T
/** Symbolically calculates derivative of this expression. Does not simplify it. */
def derivative(variable: Var[T]): Expr[T]
/** Returns arguments of this operator */
def args: Iterable[Expr[_]]
/** Transforms arguments of this operator by applying given function. */
def mapArgs(f: EndoFunction[Expr[_]]): Expr[T]
/** Transforms this operator and its arguments by applying given function */
def map(f: EndoFunction[Expr[_]]): Expr[T] =
f(mapArgs(EndoFunction[Expr[_]](x => x.map(f))))
/** Folds all subexpressions in this expression in depth-first order */
def fold[A](v: A)(f: (A, Expr[_]) => A): A =
f(args.foldLeft(v) { (a, b) => b.fold(a)(f) }, this)
/** Replaces all occurrences of one subexpression with another one */
def replace(from: Expr[_], to: Expr[_]): Expr[T] =
map(EndoFunction[Expr[_]](x => if (x == from) to else x))
/** Returns true if this expression contains given subexpression */
def contains(s: Expr[_]): Boolean =
this == s || args.exists(_ contains s)
/** Counts number of occurrences of the given subexpression. */
def count(condition: Expr[_] => Boolean): Int =
(if (condition(this)) 1 else 0) + args.map(_.count(condition)).sum
/** Executes some code for every subexpression in the depth-first order */
def foreach[U](block: Expr[_] => U): Unit = {
args.foreach(_.foreach(block))
block(this)
}
/** Collects subexpressions successfully transformed by the given partial function, in depth-first order. */
def collect[U](f: PartialFunction[Expr[_], U]): List[U] = {
val a = args.flatMap(_.collect(f)).toList
if (f.isDefinedAt(this)) (f(this) :: a) else a
}
def leaves: List[Leaf[T]] = collect { case l: Leaf[T] => l }
def + (other: Expr[T])(implicit n: NumericOps[T]) = Add(List(this, other))
def - (other: Expr[T])(implicit n: NumericOps[T]) = Sub(this, other)
def * (other: Expr[T])(implicit n: NumericOps[T]) = Mul(this, other)
def / (other: Expr[T])(implicit n: NumericOps[T]) = Div(this, other)
def unary_- (implicit n: NumericOps[T]) = Neg(this)
def sqr(implicit n: NumericOps[T]) = Sqr(this)
def < (other: Expr[T])(implicit n: NumericOps[T], o: Ordering[T]) = LT(this, other)
def <= (other: Expr[T])(implicit n: NumericOps[T], o: Ordering[T]) = LE(this, other)
def > (other: Expr[T])(implicit n: NumericOps[T], o: Ordering[T]) = GT(this, other)
def >= (other: Expr[T])(implicit n: NumericOps[T], o: Ordering[T]) = GE(this, other)
private def generalize(implicit num: NumericOps[T]): Expr[T] = {
this match {
case Add2(a, b) => Add(a :: b :: Nil)
case Add3(a, b, c) => Add(a :: b :: c :: Nil)
case Sub(a, b) => Add(a :: Neg(b) :: Nil)
case Add(x) => Add(x flatMap {
case Neg(Add(y)) => y.map(Neg(_))
case Add(y) => y
case y => y :: Nil
})
case x => x
}
}
private def specialize(implicit num: NumericOps[T]): Expr[T] = {
this match {
case Add(Seq(a, b)) => Add2(a, b)
case Add(Seq(a, b, c)) => Add3(a, b, c)
case x => x
}
}
/** Eliminates common negated components of a sum */
private def reduceComponents(components: List[Expr[T]])(implicit num: NumericOps[T]): List[Expr[T]] = {
val pairs =
for (a <- components; b <- components if Neg(a) == b || a == Neg(b))
yield (a, b)
pairs.foldLeft(components) { (c, pair) =>
if (c.contains(pair._1) && c.contains(pair._2))
c.diff(pair._1 :: pair._2 :: Nil)
else
c
}
}
/** Simplifies this expression to make evaluation faster and more accurate.
* Performs only one pass. */
private def reduce(implicit num: NumericOps[T]): Expr[T] = {
this match {
case Add(Seq(Neg(x), Neg(y), Neg(z))) => Neg(Add(List(x, y, z)))
case Add(Seq(Mul(x, y), z)) if (x == z) => Mul(x, Add(List(y, One[T])))
case Add(Seq(Mul(x, y), z)) if (y == z) => Mul(y, Add(List(z, One[T])))
case Add(Seq(Mul(x, y), Mul(u, w))) if (x == u) => Mul(x, Add(List(y, w)))
case Add(Seq(Mul(x, y), Mul(u, w))) if (y == w) => Mul(y, Add(List(x, u)))
case Add(Seq(Add(x), Add(y))) => Add(x.toList ::: y.toList).simplify
case Add(Seq(Add(x), y)) => Add(y :: x.toList).simplify
case Add(Seq(x, Add(y))) => Add(x :: y.toList).simplify
case Add(x) => {
val noZeros = x.filter(_ != Zero[T])
val noOnes = noZeros.map { case y: One[_] => Const(num.one); case y => y }
val constant = num.sum(noOnes.collect { case c: Const[T] => c.value })
val rest = noOnes.filter(x => !x.isInstanceOf[Const[_]]).toList
val reduced = reduceComponents(rest)
val args = if (num.similar(constant, num.zero)) reduced else reduced ::: Const(constant) :: Nil
args.size match {
case 0 => Zero[T]
case 1 => args.head
case 2 => Add2(args(0), args(1))
case 3 => Add3(args(0), args(1), args(2))
case _ => Add(args)
}
}
case Sub(x: Zero[_], y) => Neg(y)
case Sub(x, y: Zero[_]) => x
case Sub(x, y) if x == y => Zero[T]
case Sub(Mul(x, y), z) if (x == z) => Mul(x, Sub(y, One[T]))
case Sub(Mul(x, y), z) if (y == z) => Mul(y, Sub(z, One[T]))
case Sub(Mul(x, y), Mul(u, w)) if (x == u) => Mul(x, Sub(y, w))
case Sub(Mul(x, y), Mul(u, w)) if (y == w) => Mul(y, Sub(x, u))
case Mul(x: Zero[_], y) => Zero[T]
case Mul(x, y: Zero[_]) => Zero[T]
case Mul(x: One[_], y) => y
case Mul(x, y: One[_]) => x
case Mul(Neg(x: One[_]), y) => Neg(y)
case Mul(x, Neg(y: One[_])) => Neg(x)
case Mul(x, y) if (x == y) => Sqr(x)
case Div(x: Zero[_], y) => Zero[T] // warning: possibly extends domain
case Div(x, y: One[_]) => x
case Div(Sqr(x), y) if x == y => x
case Div(Mul(x, y), z) if (x == z) => y
case Div(Mul(x, y), z) if (y == z) => y
case Div(Mul(Mul(x, y), z), w) if (x == w) => Mul(y, z)
case Div(Mul(Mul(x, y), z), w) if (y == w) => Mul(x, z)
case Div(Mul(z, Mul(x, y)), w) if (x == w) => Mul(y, z)
case Div(Mul(z, Mul(x, y)), w) if (y == w) => Mul(x, z)
case Div(Mul(x, y), Mul(u, w)) if (x == u) => Div(y, w)
case Div(Mul(x, y), Mul(u, w)) if (y == w) => Div(x, u)
case Div(x: One[_], y) => Inv(y)
case Div(x, Sqr(y)) if x == y => Inv(y)
case Div(Mul(x, y), Sqr(Mul(u, w))) if x == u && y == w => Inv(Mul(x, y))
case Div(x, y) if x == y => One[T]
case Mul(Neg(a), Neg(b)) => Mul(a, b)
case Div(Neg(a), Neg(b)) => Div(a, b)
case Neg(x: Zero[_]) => Zero[T]
case Neg(x: One[_]) => Const(num.neg(num.one))
case Sub(Const(x), Const(y)) => const(num.sub(x, y))
case Mul(Const(x), Const(y)) => const(num.mul(x, y))
case Div(Const(x), Const(y)) => const(num.div(x, y))
case Neg(Const(x)) => const(num.neg(x))
case Sqr(Const(x)) => const(num.sqr(x))
case Mul(Const(x), Mul(Const(y), z)) => Mul(const(num.mul(x, y)), z)
case Mul(Const(x), Mul(y, Const(z))) => Mul(const(num.mul(x, z)), y)
case Mul(Mul(Const(y), z), Const(x)) => Mul(const(num.mul(x, y)), z)
case Mul(Mul(y, Const(z)), Const(x)) => Mul(const(num.mul(x, z)), y)
case Const(x) if x == num.one => One[T]
case Const(x) if x == num.zero => Zero[T]
case Sub(x, Neg(y)) => Add(List(x, y))
case Sub(Neg(x), y) => Neg(Add(List(x, y)))
case Neg(Neg(x)) => x
case Neg(Mul(a: Const[T], x)) => Mul(const(num.neg(a.value)), x)
case Neg(Mul(x, a: Const[T])) => Mul(const(num.neg(a.value)), x)
case Neg(Div(Neg(a), b)) => Div(a, b)
case Neg(Div(a, Neg(b))) => Div(a, b)
case Neg(Mul(Neg(a), b)) => Mul(a, b)
case Neg(Mul(a, Neg(b))) => Mul(a, b)
case Log(Exp(x)) => x
case x => x
}
}
private def optimizeWith(f: Expr[T] => Expr[T]): Expr[T] = {
f(mapArgs(EndoFunction[Expr[_]](
a => a match { case x: Expr[T] => x.optimizeWith(f) }
)))
}
/** Simplifies this expression to make evaluation faster and more accurate.*/
def simplify(implicit num: NumericOps[T]): Expr[T] = {
val a1 = optimizeWith(_.generalize)
val a2 = a1.optimizeWith(_.generalize)
val b = a2.optimizeWith(_.reduce)
val c = b.optimizeWith(_.reduce)
val d = c.optimizeWith(_.specialize)
d
}
}
trait Leaf[T] extends Expr[T] {
val args = List[Expr[T]]()
def mapArgs(f: EndoFunction[Expr[_]]) = this
}
trait OneArg[T] extends Expr[T] {
val expr: Expr[T]
val args = List(expr)
}
trait TwoArg[T] extends Expr[T] {
val left: Expr[T]
val right: Expr[T]
val args = List(left, right)
}
trait ManyArg[T] extends Expr[T]
/** Marker trait for specifying that you can safely divide by this */
trait NonZero[T] extends Expr[T]
case class Const[T](value: T)(implicit num: NumericOps[T]) extends Leaf[T] with NonZero[T] {
def derivative(variable: Var[T]) = Zero[T]
def eval(f: Any => Any) = value
override def toString = value.toString
}
case class Zero[T] (implicit num: NumericOps[T]) extends Leaf[T] {
def derivative(variable: Var[T]) = Zero[T]
def eval(f: Any => Any) = num.zero
override def toString = "0"
}
case class One[T] (implicit num: NumericOps[T]) extends Leaf[T] {
def derivative(variable: Var[T]) = Zero[T]
def eval(f: Any => Any) = num.one
override def toString = "1"
}
abstract class Var[T](implicit num: NumericOps[T]) extends Leaf[T] {
def derivative(variable: Var[T]) = if (variable == this) One[T] else Zero[T]
def eval(f: Any => Any) = f(this).asInstanceOf[T]
}
case class NamedVar[T](name: String)(implicit num: NumericOps[T]) extends Var[T] {
override lazy val hashCode = ScalaRunTime._hashCode(this)
override def toString = name
}
case class Add[T](args: Iterable[Expr[T]])(implicit num: NumericOps[T]) extends ManyArg[T] {
def eval(f: Any => Any) = num.sum(for (i <- args.iterator) yield i.eval(f))
def derivative(v: Var[T]) = Add(args.map(_.derivative(v)))
def mapArgs(f: EndoFunction[Expr[_]]) = Add(args map (x => f(x)))
override def toString = "(" + args.mkString(" + ") + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Add2[T](left: Expr[T], right: Expr[T])
(implicit num: NumericOps[T]) extends TwoArg[T] {
def eval(f: Any => Any) = num.add(left.eval(f), right.eval(f))
def derivative(v: Var[T]) = Add2(left.derivative(v), right.derivative(v))
def mapArgs(f: EndoFunction[Expr[_]]) = Add2(f(left), f(right))
override def toString = "(" + left + " + " + right + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Add3[T](a1: Expr[T], a2: Expr[T], a3: Expr[T])
(implicit num: NumericOps[T]) extends ManyArg[T] {
val args = List(a1, a2, a3)
def eval(f: Any => Any) = num.add(a1.eval(f), a2.eval(f), a3.eval(f))
def derivative(v: Var[T]) = Add3(a1.derivative(v), a2.derivative(v), a3.derivative(v))
def mapArgs(f: EndoFunction[Expr[_]]) = Add3(f(a1), f(a2), f(a3))
override def toString = "(" + a1 + " + " + a2 + " + " + a3 + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Sub[T](left: Expr[T], right: Expr[T])
(implicit num: NumericOps[T]) extends TwoArg[T] {
def derivative(v: Var[T]) = Sub(left.derivative(v), right.derivative(v))
def eval(f: Any => Any) = num.sub(left.eval(f), right.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Sub(f(left), f(right))
override def toString = "(" + left + " - " + right + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Neg[T](expr: Expr[T])
(implicit num: NumericOps[T]) extends OneArg[T] {
def derivative(v: Var[T]) = Neg(expr.derivative(v))
def eval(f: Any => Any) = num.neg(expr.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Neg(f(expr))
override def toString = "(-" + expr + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Mul[T](left: Expr[T], right: Expr[T])
(implicit num: NumericOps[T]) extends TwoArg[T] {
def derivative(v: Var[T]) =
Add(List(
Mul(left, right.derivative(v)),
Mul(right, left.derivative(v))))
def eval(f: Any => Any) = num.mul(left.eval(f), right.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Mul(f(left), f(right))
override def toString = "(" + left + " * " + right + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Div[T](left: Expr[T], right: Expr[T])
(implicit num: NumericOps[T]) extends TwoArg[T] {
// [f(x) / g(x)]' = [f(x) * 1 / g(x)]' = f'(x) * 1 / g(x) + f(x) * [1 / g(x)]' =
// f'(x) / g(x) + f(x) * [-1 / g(x) ^ 2] * g'(x) = (f'(x) * g(x) - f(x) * g'(x)) / g(x)^2
def derivative(v: Var[T]) =
Div(
Sub(
Mul(left.derivative(v), right),
Mul(left, right.derivative(v))),
Sqr(right)
)
def eval(f: Any => Any) = num.div(left.eval(f), right.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) =
Div(f(left), f(right))
override def toString = "(" + left + " / " + right + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Inv[T](expr: Expr[T])(implicit num: NumericOps[T]) extends OneArg[T] {
// [1 / f(x)]' = - f'(x) / f(x) ^ 2
def derivative(v: Var[T]) = Neg(Div(expr.derivative(v), Sqr(expr)))
def eval(f: Any => Any) = num.div(num.one, expr.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Inv(f(expr))
override def toString = "(1 / " + expr + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Sqr[T](expr: Expr[T])(implicit num: NumericOps[T]) extends OneArg[T] {
// [f(x) ^ 2]' = 2 * f(x) * f'(x)
def derivative(v: Var[T]) = Mul(Mul(Const(num.two), expr), expr.derivative(v))
def eval(f: Any => Any) = num.sqr(expr.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Sqr(f(expr))
override def toString = expr + " ^ 2"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Log[T](expr: Expr[T])(implicit num: NumericOps[T]) extends OneArg[T] {
def derivative(v: Var[T]) = Div(expr.derivative(v), expr)
def eval(f: Any => Any) = num.log(expr.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Log(f(expr))
override def toString = "log(" + expr + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Exp[T](expr: Expr[T])(implicit num: NumericOps[T]) extends OneArg[T] {
def derivative(v: Var[T]) = Mul(expr.derivative(v), Exp(expr))
def eval(f: Any => Any) = num.exp(expr.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Exp(f(expr))
override def toString = "exp(" + expr + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Sqrt[T](expr: Expr[T])(implicit num: NumericOps[T]) extends OneArg[T] {
def derivative(v: Var[T]) = Neg(Div(expr.derivative(v), Sqrt(expr)))
def eval(f: Any => Any) = num.sqrt(expr.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Sqrt(f(expr))
override def toString = "sqrt(" + expr + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Sin[T](expr: Expr[T])(implicit num: NumericOps[T]) extends OneArg[T] {
def derivative(v: Var[T]) = Mul(expr.derivative(v), Cos(expr))
def eval(f: Any => Any) = num.sin(expr.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Sin(f(expr))
override def toString = "sin(" + expr + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
case class Cos[T](expr: Expr[T])(implicit num: NumericOps[T]) extends OneArg[T] {
def derivative(v: Var[T]) = Neg(Mul(expr.derivative(v), Sin(expr)))
def eval(f: Any => Any) = num.cos(expr.eval(f))
def mapArgs(f: EndoFunction[Expr[_]]) = Cos(f(expr))
override def toString = "cos(" + expr + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
abstract class Compare[T](left: Expr[T], right: Expr[T], cmp: (T, T) => Boolean)(implicit num: NumericOps[T])
extends Expr[Boolean] {
def derivative(v: Var[Boolean]) = throw new IllegalStateException("Derivative of Boolean not allowed")
def eval(f: Any => Any) = cmp(left.eval(f), right.eval(f))
val args = List(left, right)
}
case class LE[T](left: Expr[T], right: Expr[T])(implicit num: NumericOps[T], ord: Ordering[T])
extends Compare[T](left, right, ord.compare(_, _) <= 0) {
def mapArgs(f: EndoFunction[Expr[_]]) = LE(
f(left), f(right))
override def toString = left.toString + " <= " + right.toString
}
case class LT[T](left: Expr[T], right: Expr[T])(implicit num: NumericOps[T], ord: Ordering[T])
extends Compare[T](left, right, ord.compare(_, _) < 0) {
def mapArgs(f: EndoFunction[Expr[_]]) = LT(
f(left), f(right))
override def toString = left.toString + " < " + right.toString
}
case class GE[T](left: Expr[T], right: Expr[T])(implicit num: NumericOps[T], ord: Ordering[T])
extends Compare[T](left, right, ord.compare(_, _) >= 0) {
def mapArgs(f: EndoFunction[Expr[_]]) = GE(
f(left), f(right))
override def toString = left.toString + " >= " + right.toString
}
case class GT[T](left: Expr[T], right: Expr[T])(implicit num: NumericOps[T], ord: Ordering[T])
extends Compare[T](left, right, ord.compare(_, _) > 0) {
def mapArgs(f: EndoFunction[Expr[_]]) = GT(
f(left), f(right))
override def toString = left.toString + " > " + right.toString
}
case class IfElse[T <: Numeric[T]]
(condition: Expr[Boolean], left: Expr[T], right: Expr[T])(implicit num: NumericOps[T]) extends Expr[T] {
val args = List(condition, left, right)
def derivative(v: Var[T]) = IfElse(condition, left.derivative(v), right.derivative(v))
def eval(f: Any => Any) = if (condition.eval(f)) left.eval(f) else right.eval(f)
def mapArgs(f: EndoFunction[Expr[_]]) = IfElse(
f(condition).asInstanceOf[Expr[Boolean]],
f(left),
f(right))
override def toString = "if (" + condition + ")(" + left + ") else (" + right + ")"
override lazy val hashCode = ScalaRunTime._hashCode(this);
}
object Expr {
/** Creates a constant expression */
def const[T](value: T)(implicit num: NumericOps[T]): Leaf[T] =
if (num.zero == value) Zero[T]
else Const(value)
implicit def double2Constant[T](d: Double)(implicit num: NumericOps[T]): Leaf[T] =
const(num.fromDouble(d))
implicit def float2Constant[T](f: Float)(implicit num: NumericOps[T]): Leaf[T] =
const(num.fromDouble(f.toDouble))
implicit def int2Constant[T](i: Int)(implicit num: NumericOps[T]): Leaf[T] =
const(num.fromDouble(i.toDouble))
implicit def long2Constant[T](l: Long)(implicit num: NumericOps[T]): Leaf[T] =
const(num.fromDouble(l.toDouble))
}
}