Commit e9b19182 authored by Arthur Bit-Monnot's avatar Arthur Bit-Monnot

Reintroduce model optimizations

parent e8ad3f70
......@@ -62,15 +62,17 @@ package object analysis {
}
/** Returns a set of fluent templates on which the given action has an effect. */
def affectedBy(a: ActionTemplate): Set[FluentTemplate] = { ???
def affectedBy(a: ActionTemplate): Set[FluentTemplate] = {
???
// val extractor = landscaper.pattern {
// case x: TimedAssertion with ProvidesChange => Seq(x.fluent.template)
// }
// landscaper.extract(extractor, a).toSet
// landscaper.extract(extractor, a).toSet
}
/** Returns a set of fluent templates on which the given action has a condition. */
def conditionedBy(a: ActionTemplate): Set[FluentTemplate] = { ???
def conditionedBy(a: ActionTemplate): Set[FluentTemplate] = {
???
// val extractor = landscaper.pattern {
// case x: TimedAssertion with RequiresSupport => Seq(x.fluent.template)
// }
......
......@@ -50,7 +50,7 @@ package object common {
else
parent match {
case Some(father) => father.lowestCommonAncestor(typ)
case None => None
case None => None
}
def asScope: Scope = id.scope + id.name
......@@ -63,6 +63,21 @@ package object common {
val Time = Integer //Type(Id(RootScope, "time"), Some(Integer))
val Float = Type(Id(RootScope, "float"), Some(Numeric))
val Boolean = Type(Id(RootScope, "boolean"), None)
val True = Instance(Id(RootScope, "true"), Boolean)
val False = Instance(Id(RootScope, "false"), Boolean)
sealed trait Top
sealed trait Obj extends Top
sealed trait Real extends Top
sealed trait Int extends Real
type Time = Int
trait Tpe[+T]
case class TObj(id: Id, parent: Option[Type]) extends Tpe[Obj]
// case class TReal(id: Id, parent: Option[TReal]) extends Tpe[Real]
case class TInt(id: Id, parent: Option[TInt], min: Option[Int], max: Option[Int])
extends Tpe[Int]
}
sealed trait Expr {
def typ: Type
......@@ -100,7 +115,7 @@ package object common {
case class Op2(op: BinaryOperator, lhs: Expr, rhs: Expr) extends Expr {
override def typ: Type = op.tpe(lhs.typ, rhs.typ) match {
case Right(t) => t
case Right(t) => t
case Left(err) => sys.error(err)
}
......@@ -108,15 +123,12 @@ package object common {
}
case class Op1(op: UnaryOperator, lhs: Expr) extends Expr {
override def typ: Type = op.tpe(lhs.typ) match {
case Right(t) => t
case Right(t) => t
case Left(err) => sys.error(err)
}
override def toString: String = s"(${op.op} $lhs)"
}
sealed trait FunctionTemplate {
def id: Id
def typ: Type
......
......@@ -175,8 +175,7 @@ package object full {
override def toString: String = expr.toString
}
case class StaticAssignmentAssertion(left: Constant, right: StaticExpr)
extends StaticAssertion {
case class StaticAssignmentAssertion(left: Constant, right: StaticExpr) extends StaticAssertion {
override def toString: String = s"$left := $right"
}
......@@ -309,7 +308,7 @@ package object full {
def findTimepoint(name: String): Option[LocalVar] =
findDeclaration(name).flatMap {
case LocalVarDeclaration(v @ LocalVar(_, tpe)) if tpe.isSubtypeOf(Type.Time) => Some(v)
case _ => None
case _ => None
}
def findType(name: String): Option[Type] =
......
......@@ -8,6 +8,7 @@ object ActionInstantiation {
private[this] object implicits {
trait IdRewrite[T] {
/** Transforms a type T, recursively replacing any id: Id in it with f(id) */
def map(a: T, f: Id => Id): T
}
......@@ -36,13 +37,13 @@ object ActionInstantiation {
implicit object ofConstantTemplate extends IdRewrite[ConstantTemplate] {
override def map(a: ConstantTemplate, f: Id => Id): ConstantTemplate = a match {
case ConstantTemplate(id, tpe, params) =>
ConstantTemplate(f(id), tpe, params.map { case Arg(id, tpe) => Arg(f(id), tpe)} )
ConstantTemplate(f(id), tpe, params.map { case Arg(id, tpe) => Arg(f(id), tpe) })
}
}
implicit object ofFluentTemplate extends IdRewrite[FluentTemplate] {
override def map(a: FluentTemplate, f: Id => Id): FluentTemplate = a match {
case FluentTemplate(id, tpe, params) =>
FluentTemplate(f(id), tpe, params.map { case Arg(id, tpe) => Arg(f(id), tpe)} )
FluentTemplate(f(id), tpe, params.map { case Arg(id, tpe) => Arg(f(id), tpe) })
}
}
implicit object ofFluent extends IdRewrite[Fluent] {
......
......@@ -52,7 +52,7 @@ object FullToCore {
r <- f2c(rhs)
} yield Op2(op, l, r)
case full.UnaryExprTree(op, e) =>
for {
for {
ec <- f2c(e)
} yield Op1(op, ec)
}
......@@ -107,7 +107,6 @@ object FullToCore {
throw new UnsupportedOperationException(
s"Assignment assertions on constant functions are only supported when all parameters are declared instances: $block")
case full.TemporallyQualifiedAssertion(qualifier, assertion) =>
val startEnd: CoreM[(Expr, Expr)] =
qualifier match {
......@@ -174,7 +173,7 @@ object FullToCore {
} yield ()
}
case full.LocalVarDeclaration(v) => CoreM.unit(core.LocalVarDeclaration(v))
case full.LocalVarDeclaration(v) => CoreM.unit(core.LocalVarDeclaration(v))
}
def trans(model: full.Model, config: Config = Config()): Seq[core.InModuleBlock] = {
......
......@@ -415,8 +415,8 @@ abstract class AnmlParser(val initialContext: Ctx) {
";")
.namedFilter({
case (_: Constant, Some(_)) => true
case (_, Some(_)) => false
case (_, None) => true
case (_, Some(_)) => false
case (_, None) => true
}, "assignment-to-const-func-only")
.namedFilter({
case (_, Some(_)) => true
......@@ -424,8 +424,8 @@ abstract class AnmlParser(val initialContext: Ctx) {
}, "boolean-if-not-assignment")
.map {
case (left: Constant, Some((":=", right))) => StaticAssignmentAssertion(left, right)
case (expr, None) => BooleanAssertion(expr)
case _ => sys.error("Something is wrong with this parser.")
case (expr, None) => BooleanAssertion(expr)
case _ => sys.error("Something is wrong with this parser.")
}
}
}
......@@ -626,8 +626,8 @@ object Parser {
TypeDeclaration(Type.Boolean),
TypeDeclaration(Type.Numeric),
TypeDeclaration(Type.Integer),
InstanceDeclaration(Instance(Id(RootScope, "true"), Type.Boolean)),
InstanceDeclaration(Instance(Id(RootScope, "false"), Type.Boolean)),
InstanceDeclaration(Type.True),
InstanceDeclaration(Type.False),
TimepointDeclaration(Id(RootScope, "start")),
TimepointDeclaration(Id(RootScope, "end")),
)).getOrElse(sys.error("Could not instantiate base model"))
......
......@@ -12,7 +12,8 @@ class AnmlParsingTest extends FunSuite {
println("AS:\n" + module + "\n\n")
case x: ParseFailure =>
fail(s"Could not parse anml string: $anml\n\n${x.format}")
case UnidentifiedError(err, _) => err.printStackTrace()
case UnidentifiedError(err, _) =>
err.printStackTrace()
fail(s"Exception raised while parsing")
}
}
......@@ -36,13 +37,14 @@ class AnmlParsingTest extends FunSuite {
/** Dummy text to facilitate testing. */
println(tmp)
Parser.parse(tmp) match {
case ParseSuccess(module) =>
println("PARSED:\n")
println("AS:\n" + module + "\n\n")
case x: ParseFailure =>
fail(s"Could not parse anml string:\n${x.format}")
case UnidentifiedError(err, _) => err.printStackTrace()
fail(s"Exception raised while parsing")
}
case ParseSuccess(module) =>
println("PARSED:\n")
println("AS:\n" + module + "\n\n")
case x: ParseFailure =>
fail(s"Could not parse anml string:\n${x.format}")
case UnidentifiedError(err, _) =>
err.printStackTrace()
fail(s"Exception raised while parsing")
}
}
}
......@@ -36,7 +36,8 @@ lazy val commonSettings = Seq(
// experimental option to speed up the build
"-Ycache-plugin-class-loader:last-modified",
"-Ycache-macro-class-loader:last-modified",
"-Ybackend-parallelism", "3"
"-Ybackend-parallelism",
"3"
// "-opt:simplify-jumps",
// "-opt:compact-locals",
// "-opt:copy-propagation",
......@@ -65,12 +66,13 @@ lazy val anml = project
.in(file("anml"))
.settings(name := "dahu-anml")
.settings(commonSettings: _*)
.settings(libraryDependencies ++= Seq(
"com.lihaoyi" %% "fastparse" % "1.0.0",
"com.github.scopt" %% "scopt" % "3.7.0",
"com.chuusai" %% "shapeless" % "2.3.3",
"org.scalatest" %% "scalatest" % "3.0.5" % "test"
))
.settings(
libraryDependencies ++= Seq(
"com.lihaoyi" %% "fastparse" % "1.0.0",
"com.github.scopt" %% "scopt" % "3.7.0",
"com.chuusai" %% "shapeless" % "2.3.3",
"org.scalatest" %% "scalatest" % "3.0.5" % "test"
))
lazy val utils = project
.in(file("utils"))
......
......@@ -23,6 +23,11 @@ abstract class Fun1[-I: Tag, O: Tag] extends Fun[O] {
def of(in: I): O
}
abstract class Reversible[A: Tag, B: Tag] extends Fun1[A, B] {
def reverse: Reversible[B, A]
}
object Fun1 {
def embed[A: Tag, B: Tag](f: A => B): Fun1[A, B] = new Fun1[A, B] {
override def of(in: A): B = f(in)
......
......@@ -8,6 +8,8 @@ trait Monoid[T] extends FunN[T, T] {
def tpe: Tag[T]
def combine(lhs: T, rhs: T): T
def combineUnsafe(lhs: Value, rhs: Value): Value =
Value(combine(lhs.asInstanceOf[T], rhs.asInstanceOf[T]))
val identity: T
final lazy val liftedIdentity: CstF[T] = CstF(Value(identity), tpe)
......@@ -16,3 +18,5 @@ trait Monoid[T] extends FunN[T, T] {
}
trait CommutativeMonoid[T] extends Monoid[T]
trait IdempotentMonoid[T] extends Monoid[T]
package dahu.model.math
import dahu.model.functions.{Fun1, Fun2, Fun3, FunN}
import dahu.model.functions._
import dahu.model.input.Cst
import dahu.model.ir.CstF
import dahu.model.types.{BoxedInt, Tag}
object obj {
......@@ -71,9 +72,10 @@ object int {
override val identity: Int = 0
}
object Negate extends Fun1[Int, Int] {
object Negate extends Reversible[Int, Int] {
override def name: String = "neg"
override def of(in: Int): Int = -in
override def reverse: Reversible[Int, Int] = this
}
object Min extends Fun2[Int, Int, Int] {
......@@ -93,13 +95,13 @@ object int {
object bool {
object And extends CommutativeMonoid[Boolean] {
object And extends CommutativeMonoid[Boolean] with IdempotentMonoid[Boolean] {
override def tpe: Tag[Boolean] = Tag.ofBoolean
override def name: String = "and"
override def combine(lhs: Boolean, rhs: Boolean): Boolean = lhs && rhs
override val identity: Boolean = true
}
object Or extends CommutativeMonoid[Boolean] {
object Or extends CommutativeMonoid[Boolean] with IdempotentMonoid[Boolean] {
override def tpe: Tag[Boolean] = Tag.ofBoolean
override def name: String = "or"
override def combine(lhs: Boolean, rhs: Boolean): Boolean = lhs || rhs
......@@ -110,12 +112,15 @@ object bool {
override def name: String = "xor"
}
object Not extends Fun1[Boolean, Boolean] {
object Not extends Reversible[Boolean, Boolean] {
override def name: String = "not"
override def of(in: Boolean): Boolean = !in
override def reverse: Reversible[Boolean, Boolean] = this
}
val True: Cst[Boolean] = Cst(true)
val TrueF: CstF[Any] = CstF(dahu.model.types.Value(true), Tag[Boolean])
val False: Cst[Boolean] = Cst(false)
val FalseF: CstF[Any] = CstF(dahu.model.types.Value(false), Tag[Boolean])
}
......@@ -145,6 +145,14 @@ class IntBoolSatisfactionProblem[X](val ast: RootedLazyTree[X, Total, cats.Id])
}
def cst(n: Int): CellOpt[K] = CompatibleConstant(CstF(Value(n), Tag.ofInt), Tag.ofInt)
def isUnbox(f: Fun[_]): Boolean = f match {
case fun: Fun1[_, _] =>
fun.inType match {
case t: TagIsoInt[_] => t.unbox == fun
case _ => false
}
case _ => false
}
node match {
case x @ CstF(v, Tag.ofBoolean) => SupportedConstant(x)
......@@ -155,6 +163,9 @@ class IntBoolSatisfactionProblem[X](val ast: RootedLazyTree[X, Total, cats.Id])
case x @ ComputationF(f, args, t: TagIsoInt[_])
if supportedFunctions.contains(f) && args.forall(x => sup(prev(x))) =>
IntermediateExpression(ComputationF(f, args, t))
case x @ ComputationF(f: Fun1[_, _], Vec1(arg), t: TagIsoInt[_])
if isUnbox(f) && sup(prev(arg)) => //TODO double check
prev(arg)
case x @ ComputationF(wf: WrappedFunction, args, t: TagIsoInt[_])
if supportedFunctions.contains(wf.f) && args.forall(x => sup(prev(x))) =>
TRANS(rec)(prev)(ComputationF(wf.f, args, t)) // unwrap and retry
......@@ -163,6 +174,7 @@ class IntBoolSatisfactionProblem[X](val ast: RootedLazyTree[X, Total, cats.Id])
prev(arg) // unbox operation, use the previous cell
case x =>
dahu.utils.debug.warning(s"unsupported: $x")
x.typ match {
case Tag.ofBoolean =>
SupportedInput(InputF(Anonymous(), Tag.ofBoolean))
......
......@@ -2,13 +2,16 @@ package dahu.model.problem
import cats.Functor
import cats.implicits._
import dahu.model.functions.Reversible
import dahu.utils._
import dahu.model.ir._
import dahu.model.math.bool
import dahu.model.math._
import dahu.model.types._
import dahu.recursion._
import dahu.utils.SFunctor
import dahu.utils.Vec._
import dahu.utils.errors._
import spire.syntax.cfor._
import scala.collection.mutable
import scala.reflect.ClassTag
......@@ -18,8 +21,164 @@ object SatisfactionProblem {
def satisfactionSubAST(ast: AST[_]): RootedLazyTree[ast.ID, Total, cats.Id] = {
encode(ast.root, ast.tree.asFunction)
}
type ID = Int
object Optimizations {
trait Optimizer {
self =>
def optim(retrieve: ID => Total[ID], record: Total[ID] => ID): Total[ID] => Total[ID]
def andThen(next: Optimizer): Optimizer = new Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] =
self.optim(retrieve, record) andThen next.optim(retrieve, record)
override def toString: String = s"self >> next"
}
}
object NoOpOptimizer extends Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] = identity[Total[ID]]
}
object ElimReversible extends Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] = {
case ComputationF(f: Reversible[_, _], Vec1(arg), _) =>
retrieve(arg) match {
case ComputationF(f2: Reversible[_, _], Vec1(arg2), _) if f2 == f.reverse =>
retrieve(arg2)
case x => x
}
case x => x
}
}
object ElimTautologies extends Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] = {
case ComputationF(int.EQ, Vec2(a1, a2), _) if a1 == a2 => bool.TrueF
case ComputationF(int.LEQ, Vec2(a1, a2), _) if a1 == a2 => bool.TrueF
case x => x
}
}
object ElimIdentity extends Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] = {
case x @ ComputationF(f: Monoid[_], args, tpe) =>
val identity = record(f.liftedIdentity)
if(args.contains(identity))
ComputationF(f, args.filter(_ != identity), tpe)
else
x
case x => x
}
}
object ElimEmptyAndSingletonMonoid extends Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] = {
case x @ ComputationF(f: Monoid[_], args, _) if args.isEmpty => f.liftedIdentity
case x @ ComputationF(_: Monoid[_], Vec1(arg), _) => retrieve(arg)
case x => x
}
}
object ElimDuplicationsIdempotentMonoids extends Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] = {
case ComputationF(f: IdempotentMonoid[_], args, tpe)
if f.isInstanceOf[CommutativeMonoid[_]] =>
ComputationF(f, args.distinct, tpe)
case x => x
}
}
object FlattenMonoids extends Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] = {
case x @ ComputationF(f: Monoid[_], args, tpe) =>
val buff = debox.Buffer[ID]()
cfor(0)(_ < args.length, _ + 1) { i =>
retrieve(args(i)) match {
case ComputationF(f2: Monoid[_], args2, _) if f2 == f =>
args2.foreach(buff += _)
case _ =>
buff += args(i)
}
}
if(buff.length != args.size)
ComputationF[ID](f, Vec.unsafe(buff.toArray()), tpe)
else
x
case x => x
}
}
object ConstantFolding extends Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] = o => {
val TRUE: ID = record(bool.TrueF)
val FALSE: ID = record(bool.FalseF)
o match {
case ComputationF(bool.And, args, _) if args.contains(FALSE) => retrieve(FALSE)
case ComputationF(bool.Or, args, _) if args.contains(TRUE) => retrieve(TRUE)
// commutative monoid, evaluate the combination of all constants args
// any function, evaluate if all args are constant
case ComputationF(f, args, t) if args.forall(retrieve(_).isInstanceOf[CstF[_]]) =>
val params = args.map(i =>
retrieve(i) match {
case CstF(value, _) => value
case _ => unexpected
})
CstF(Value(f.compute(params)), t)
case ComputationF(f: CommutativeMonoid[_], args, tpe)
if args.count(retrieve(_).isInstanceOf[CstF[_]]) >= 2 =>
val buff = debox.Buffer[ID]()
var acc: Value = Value(f.identity)
cfor(0)(_ < args.length, _ + 1) { i =>
retrieve(args(i)) match {
case CstF(value, _) => acc = f.combineUnsafe(acc, value)
case _ => buff += args(i)
}
}
buff += record(CstF(acc, f.outType))
ComputationF(f, Vec.unsafe(buff.toArray()), tpe)
case x => x
}
}
}
object OrderArgs extends Optimizer {
override def optim(retrieve: ID => Total[ID],
record: Total[ID] => ID): Total[ID] => Total[ID] = {
case x @ ComputationF(f: CommutativeMonoid[_], args, tpe) =>
if(args.isSorted)
x
else
ComputationF(f, args.sorted, tpe)
case x => x
}
}
private val optimizers = List(
ElimReversible,
ElimIdentity,
ElimEmptyAndSingletonMonoid,
FlattenMonoids,
ElimDuplicationsIdempotentMonoids,
ConstantFolding,
OrderArgs,
)
val optimizer: Optimizer = optimizers.foldLeft[Optimizer](NoOpOptimizer) {
case (acc, next) => acc.andThen(next)
}
}
trait TreeNode[N[_]] {
def children[K](n: N[K]): Iterable[K]
......@@ -101,7 +260,10 @@ object SatisfactionProblem {
def fullTree(implicit F: SFunctor[F], ct: ClassTag[F[Fix[F]]]): Fix[F] = tree.build(root)
}
final class Context(val rec: Total[ID] => ID) {
final class Context(val directRec: Total[ID] => ID, retrieve: ID => Total[ID]) {
def rec(expr: Total[ID]): ID =
directRec(Optimizations.optimizer.optim(retrieve, directRec)(expr))
val TRUE: ID = rec(CstF(Value(true), Tag.ofBoolean))
val FALSE: ID = rec(CstF(Value(false), Tag.ofBoolean))
......@@ -170,7 +332,7 @@ object SatisfactionProblem {
id
}
}
private val ctx: Context = new Context(getID)
private val ctx: Context = new Context(getID, get)
private val g2: ExprF[IR[ID]] => IR[ID] = g(ctx)
......
package dahu.model.types
import cats.Id
import dahu.model.functions.{Fun1, Reversible}
import dahu.utils._
import dahu.model.input.{ProductExpr, Tentative}
......@@ -13,6 +14,55 @@ trait Tag[+T] {
}
object Tag {
import scala.reflect.runtime.universe
type Type = universe.Type
def apply[T](implicit ev: Tag[T]): Tag[T] = ev
def typeOf[T](implicit ttag: universe.WeakTypeTag[T]): universe.Type = ttag.tpe
implicit case object ofInt extends BoxedInt[Int] {
override val typ: Type = typeOf[Int]
override def fromInt(i: Int): Int = i
override def toInt(t: Int): Int = t
override val min: Int = Integer.MIN_VALUE / 2 + 1
override val max: Int = Integer.MAX_VALUE / 2 - 1
}
implicit case object ofBoolean extends TagIsoInt[Boolean] {
override def typ: Type = typeOf[Boolean]
override def toInt(t: Boolean): Int = if(t) 1 else 0
def fromInt(i: Int): Boolean = (i: @switch) match {
case 0 => false
case 1 => true
case _ => ???
}
override val min: Int = 0
override val max: Int = 1
}
def tagInstance[T](implicit ttag: universe.WeakTypeTag[T]): Tag[T] = new Tag[T] {
override def typ: Type = ttag.tpe
}
implicit val ofDouble = tagInstance[Double]
implicit val ofString = tagInstance[String]
implicit def optionTag[T](implicit ev: universe.WeakTypeTag[Option[T]]): Tag[Option[T]] =
new Tag[Option[T]] {
override def typ: Type = ev.tpe
}
implicit def eitherTag[L, R](implicit ev: universe.WeakTypeTag[Either[L, R]]): Tag[Either[L, R]] =
new Tag[Either[L, R]] {
override def typ: Type = ev.tpe
}
def default[T: universe.WeakTypeTag]: Tag[T] = new Tag[T] {
override def typ: Type = typeOf[T]
}
}
/** A type for which an isomophism to a subset of integers is known. */
trait TagIsoInt[T] extends Tag[T] {
......@@ -24,6 +74,19 @@ trait TagIsoInt[T] extends Tag[T] {
val min: Int
val max: Int
def numInstances: Int = max - min + 1
private implicit def selfTag: TagIsoInt[T] = this
val box: Reversible[Int, T] = new Reversible[Int, T] { self =>
override val reverse: Reversible[T, Int] = new Reversible[T, Int] {
override def reverse: Reversible[Int, T] = self
override def of(in: T): Int = toInt(in)
override def name: String = "unbox"
}
override def of(in: Int): T = fromInt(in)
override def name: String = "box"
}
val unbox: Reversible[T, Int] = box.reverse
}
object TagIsoInt {
......@@ -45,7 +108,7 @@ object TagIsoInt {
}
/** Marker trait for a type that is a simple container of Int. */
trait BoxedInt[T] extends TagIsoInt[T]
trait BoxedInt[T] extends TagIsoInt[T] {}
trait ProductTag[P[_[_]]] extends Tag[P[cats.Id]] {
def exprProd: ProductExpr[P, Tentative]
......@@ -90,52 +153,3 @@ object ProductTag {
override def typ: Tag.Type = tt.tpe
}
}
object Tag {
import scala.reflect.runtime.universe
type Type = universe.Type
def apply[T](implicit ev: Tag[T]): Tag[T] = ev
def typeOf[T](implicit ttag: universe.WeakTypeTag[T]): universe.Type = ttag.tpe
implicit case object ofInt extends BoxedInt[Int] {
override val typ: Type = typeOf[Int]
override def fromInt(i: Int): Int = i
override def toInt(t: Int): Int = t
override val min: Int = Integer.MIN_VALUE / 2 + 1
override val max: Int = Integer.MAX_VALUE / 2 - 1
}