diff --git a/src/main/scala/inox/InoxContext.scala b/src/main/scala/inox/InoxContext.scala index f029a985b8f0449dfd1bd39d2c996dfdfb132ac2..fa49102840a559fbb0f3d30b827ac64547d902b4 100644 --- a/src/main/scala/inox/InoxContext.scala +++ b/src/main/scala/inox/InoxContext.scala @@ -12,7 +12,9 @@ case class InoxContext( reporter: Reporter, interruptManager: InterruptManager, options: Seq[InoxOption[Any]] = Seq(), - timers: TimerStorage = new TimerStorage) extends InoxOptions { + timers: TimerStorage = new TimerStorage) extends InoxOptions[InoxContext] { + + def build(opts: Seq[InoxOption[Any]]) = InoxContext(reporter, interruptManager, opts, timers) def toSolver: solvers.SolverOptions = ??? def toEvaluator: evaluators.EvaluatorOptions = ??? diff --git a/src/main/scala/inox/InoxOptions.scala b/src/main/scala/inox/InoxOptions.scala index 4ae72dcda50d9551e86411b0b28269729804cac3..151a60ba9d57856c060fb2684d1f421084808b04 100644 --- a/src/main/scala/inox/InoxOptions.scala +++ b/src/main/scala/inox/InoxOptions.scala @@ -154,14 +154,28 @@ object OptionsHelpers { } } -trait InoxOptions { +trait InoxOptions[Self <: InoxOptions[Self]] { val options: Seq[InoxOption[Any]] + protected def build(newOpts: Seq[InoxOption[Any]]): Self + def findOption[A: ClassTag](optDef: InoxOptionDef[A]): Option[A] = options.collectFirst { case InoxOption(`optDef`, value: A) => value } def findOptionOrDefault[A: ClassTag](optDef: InoxOptionDef[A]): A = findOption(optDef).getOrElse(optDef.default) + + def +(newOpt: InoxOption[Any]): Self = build { + options.filter(_.optionDef != newOpt.optionDef) :+ newOpt + } + + def ++(newOpts: Seq[InoxOption[Any]]): Self = build { + val defs = newOpts.map(_.optionDef).toSet + options.filter(opt => !defs(opt.optionDef)) ++ newOpts + } + + @inline + def ++(that: Self): Self = this ++ that.options } object InoxOptions { diff --git a/src/main/scala/inox/datagen/ModelEnumerator.scala b/src/main/scala/inox/datagen/ModelEnumerator.scala index 636ff3c16be236b17d6f2f6c46baf3652292afa5..6cfbc50d884955c874bd29db5eb1190f132b17c8 100644 --- a/src/main/scala/inox/datagen/ModelEnumerator.scala +++ b/src/main/scala/inox/datagen/ModelEnumerator.scala @@ -8,17 +8,16 @@ import solvers._ import utils._ trait ModelEnumerator { - val factory: SolverFactory - lazy val program: factory.program.type = factory.program + val program: Program + val factory: SolverFactory { val program: ModelEnumerator.this.program.type } + val evaluator: DeterministicEvaluator { val program: ModelEnumerator.this.program.type } + import program._ import program.trees._ import program.symbols._ import SolverResponses._ - protected val evaluator: RecursiveEvaluator { val program: ModelEnumerator.this.program.type } = - RecursiveEvaluator(program)(ctx.toEvaluator, ctx.toSolver) - def enumSimple(vs: Seq[ValDef], satisfying: Expr): FreeableIterator[Map[ValDef, Expr]] = { enumVarying0(vs, satisfying, None, -1) } @@ -203,7 +202,11 @@ trait ModelEnumerator { } object ModelEnumerator { - def apply(sf: SolverFactory): ModelEnumerator { val factory: sf.type } = new ModelEnumerator { + def apply(p: Program) + (sf: SolverFactory { val program: p.type }, ev: DeterministicEvaluator { val program: p.type }): + ModelEnumerator { val program: p.type; val factory: sf.type; val evaluator: ev.type } = new { + val program: p.type = p val factory: sf.type = sf - } + val evaluator: ev.type = ev + } with ModelEnumerator } diff --git a/src/main/scala/inox/datagen/SolverDataGen.scala b/src/main/scala/inox/datagen/SolverDataGen.scala index 072ec731d01af83a584d43da3768f3a97b3bd137..9a530c88bff663ba5ff4fe5086159db301bae540 100644 --- a/src/main/scala/inox/datagen/SolverDataGen.scala +++ b/src/main/scala/inox/datagen/SolverDataGen.scala @@ -3,6 +3,7 @@ package inox package datagen +import evaluators._ import solvers._ import utils._ @@ -12,6 +13,7 @@ trait SolverDataGen extends DataGenerator { self => import program.symbols._ def factory(p: Program { val trees: self.program.trees.type }): SolverFactory { val program: p.type } + def evaluator(p: Program { val trees: self.program.trees.type }): DeterministicEvaluator { val program: p.type } def generate(tpe: Type): FreeableIterator[Expr] = { generateFor(Seq(ValDef(FreshIdentifier("tmp"), tpe)), @@ -76,7 +78,7 @@ trait SolverDataGen extends DataGenerator { self => // We need to synthesize a size function for ins' types. val pgm1 = program.extend(functions = fds) - val modelEnum = ModelEnumerator(factory(pgm1)) + val modelEnum = ModelEnumerator(pgm1)(factory(pgm1), evaluator(pgm1)) val enum = modelEnum.enumVarying(ins, satisfying, sizeOf, 5) @@ -86,8 +88,9 @@ trait SolverDataGen extends DataGenerator { self => } object SolverDataGen { - def apply(p: Program): SolverDataGen { val program: p.type } = new SolverDataGen { + def apply(p: InoxProgram): SolverDataGen { val program: p.type } = new SolverDataGen { val program: p.type = p - def factory(p2: Program { val trees: p.trees.type }): SolverFactory { val program: p2.type } = SolverFactory(p2) + def factory(p: InoxProgram): SolverFactory { val program: p.type } = SolverFactory.default(p) + def evaluator(p: InoxProgram): RecursiveEvaluator { val program: p.type } = RecursiveEvaluator.default(p) } } diff --git a/src/main/scala/inox/evaluators/Evaluator.scala b/src/main/scala/inox/evaluators/Evaluator.scala index b9069f65f681a8c094c1bee6d5eeff7dbd92445f..c7f271d2769467e7b9d05852ee57adcfdb734ca2 100644 --- a/src/main/scala/inox/evaluators/Evaluator.scala +++ b/src/main/scala/inox/evaluators/Evaluator.scala @@ -3,7 +3,13 @@ package inox package evaluators -case class EvaluatorOptions(options: Seq[InoxOption[Any]]) extends InoxOptions +case class EvaluatorOptions(options: Seq[InoxOption[Any]]) extends InoxOptions[EvaluatorOptions] { + protected def build(opts: Seq[InoxOption[Any]]): EvaluatorOptions = EvaluatorOptions(opts) +} + +object EvaluatorOptions { + def empty = EvaluatorOptions(Seq()) +} trait Evaluator { val program: Program diff --git a/src/main/scala/inox/evaluators/RecursiveEvaluator.scala b/src/main/scala/inox/evaluators/RecursiveEvaluator.scala index c9f4da8f0328b98e8dca754fd14ec9318ca9cf61..66d4d3e1ed0fa428997b7542fea67529a67f31c5 100644 --- a/src/main/scala/inox/evaluators/RecursiveEvaluator.scala +++ b/src/main/scala/inox/evaluators/RecursiveEvaluator.scala @@ -529,15 +529,16 @@ trait RecursiveEvaluator } object RecursiveEvaluator { - def apply(p: Program) - (evOpts: EvaluatorOptions, solverOpts: solvers.SolverOptions): - RecursiveEvaluator { val program: p.type } = { + def apply(p: InoxProgram)(evOpts: EvaluatorOptions, solverOpts: solvers.SolverOptions): + RecursiveEvaluator { val program: p.type } = { new { val program: p.type = p } with RecursiveEvaluator with HasDefaultGlobalContext with HasDefaultRecContext { - val options = evOpts + val options = p.ctx.toEvaluator ++ evOpts val maxSteps = 50000 - def getSolver(opts: InoxOption[Any]*) = solvers.SolverFactory(p) + def getSolver(opts: InoxOption[Any]*) = solvers.SolverFactory(p)(p.ctx.toSolver ++ opts, options) } } + + def default(p: InoxProgram) = apply(p)(EvaluatorOptions.empty, solvers.SolverOptions.empty) } diff --git a/src/main/scala/inox/package.scala b/src/main/scala/inox/package.scala index ed98affade8896e911f05fbab1508dc25fa86e01..a35924d04e4d53721b0450b4464290091d1adcf7 100644 --- a/src/main/scala/inox/package.scala +++ b/src/main/scala/inox/package.scala @@ -1,15 +1,56 @@ /* Copyright 2009-2016 EPFL, Lausanne */ -import scala.language.implicitConversions - -/** Core package of the Leon system - * - * Provides the basic types and definitions for the Leon system. - */ +/** Core package of the Inox solving interface */ package object inox { implicit class BooleanToOption(cond: Boolean) { def option[A](v: => A) = if (cond) Some(v) else None } case class FatalError(msg: String) extends Exception(msg) + + type InoxProgram = Program { val trees: inox.trees.type } + + object InoxProgram { + def apply(ictx: InoxContext, + functions: Seq[inox.trees.FunDef], + classes: Seq[inox.trees.ClassDef]) = new Program { + val trees = inox.trees + val ctx = ictx + val symbols = new inox.trees.Symbols( + functions.map(fd => fd.id -> fd).toMap, + classes.map(cd => cd.id -> cd).toMap) + } + } + + object trees extends ast.Trees { + + class Symbols( + val functions: Map[Identifier, FunDef], + val classes: Map[Identifier, ClassDef] + ) extends AbstractSymbols { + + def transform(t: TreeTransformer) = new Symbols( + functions.mapValues(fd => new FunDef( + fd.id, + fd.tparams, // type parameters can't be transformed! + fd.params.map(vd => t.transform(vd)), + t.transform(fd.returnType), + fd.body.map(t.transform), + fd.flags)), + classes.mapValues { + case acd: AbstractClassDef => acd + case ccd: CaseClassDef => new CaseClassDef( + ccd.id, + ccd.tparams, + ccd.parent, + ccd.fields.map(t.transform), + ccd.flags) + }) + + def extend(functions: Seq[FunDef] = Seq.empty, classes: Seq[ClassDef] = Seq.empty) = new Symbols( + this.functions ++ functions.map(fd => fd.id -> fd), + this.classes ++ classes.map(cd => cd.id -> cd) + ) + } + } } diff --git a/src/main/scala/inox/solvers/GroundSolver.scala b/src/main/scala/inox/solvers/GroundSolver.scala deleted file mode 100644 index a50b3f814fac04474cbf0604583f3e4c05cea83c..0000000000000000000000000000000000000000 --- a/src/main/scala/inox/solvers/GroundSolver.scala +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright 2009-2016 EPFL, Lausanne */ - -package leon -package solvers - -import evaluators.DefaultEvaluator -import evaluators.EvaluationResults._ -import purescala.Common.Identifier -import purescala.Definitions.Program -import purescala.Expressions.{BooleanLiteral, Expr} -import purescala.ExprOps.isGround -import purescala.Constructors.andJoin -import utils.Interruptible -import utils.IncrementalSeq - -// This solver only "solves" ground terms by evaluating them -class GroundSolver(val sctx: SolverContext, val program: Program) extends Solver with NaiveAssumptionSolver { - - context.interruptManager.registerForInterrupts(this) - - val evaluator = new DefaultEvaluator(context, program) - val dbg: Any => Unit = context.reporter.debug(_) - - def name: String = "ground" - - private val assertions = new IncrementalSeq[Expr]() - - // Ground terms will always have the empty model - def getModel: Model = Model.empty - - def assertCnstr(expression: Expr): Unit = { - assertions += expression - } - - def check: Option[Boolean] = { - val expr = andJoin(assertions.toSeq) - - if (isGround(expr)) { - evaluator.eval(expr) match { - case Successful(BooleanLiteral(result)) => - Some(result) - case RuntimeError(message) => - dbg(s"Evaluation of $expr resulted in runtime error") - Some(false) - case _ => - dbg(s"Solver $name encountered error during evaluation.") - None - } - } else { - dbg(s"Non-ground expression $expr given to solver $name") - None - } - } - - def free(): Unit = { - assertions.clear() - } - - def push() = { - assertions.push() - } - - def pop() = { - assertions.pop() - } - - def reset() = { - assertions.reset() - } - - def interrupt(): Unit = {} - - def recoverInterrupt(): Unit = {} -} diff --git a/src/main/scala/inox/solvers/NaiveAssumptionSolver.scala b/src/main/scala/inox/solvers/NaiveAssumptionSolver.scala deleted file mode 100644 index a0dd48a7c80e3b04cd6336f27b60f9f0b0b78296..0000000000000000000000000000000000000000 --- a/src/main/scala/inox/solvers/NaiveAssumptionSolver.scala +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright 2009-2016 EPFL, Lausanne */ - -package leon -package solvers - -import purescala.Expressions._ -import purescala.Constructors._ - -trait NaiveAssumptionSolver { - self: Solver => - - var lastBs = Set[Expr]() - def checkAssumptions(bs: Set[Expr]): Option[Boolean] = { - push() - lastBs = bs - assertCnstr(andJoin(bs.toSeq)) - val res = check - pop() - - res - } - - def getUnsatCore: Set[Expr] = { - lastBs - } -} diff --git a/src/main/scala/inox/solvers/Solver.scala b/src/main/scala/inox/solvers/Solver.scala index e725331488bd38b29edabe4713b9f6c4aafff803..5b71c18546b5081263549438cd03167b684f5aa2 100644 --- a/src/main/scala/inox/solvers/Solver.scala +++ b/src/main/scala/inox/solvers/Solver.scala @@ -6,14 +6,12 @@ package solvers import utils._ import evaluators._ -case class SolverOptions(options: Seq[InoxOption[Any]]) extends InoxOptions { - def set(opts: Seq[InoxOption[Any]]): SolverOptions = { - val changed = opts.map(_.optionDef).toSet - val remainingOpts = options.filter { case InoxOption(optDef, _) => !changed(optDef) } - copy(options = remainingOpts ++ opts) - } +case class SolverOptions(options: Seq[InoxOption[Any]]) extends InoxOptions[SolverOptions] { + def build(opts: Seq[InoxOption[Any]]): SolverOptions = SolverOptions(opts) +} - def set(opt: InoxOption[Any], opts: InoxOption[Any]*): SolverOptions = set(opt +: opts) +object SolverOptions { + def empty = SolverOptions(Seq()) } case object DebugSectionSolver extends DebugSection("solver") diff --git a/src/main/scala/inox/solvers/SolverFactory.scala b/src/main/scala/inox/solvers/SolverFactory.scala index 6ef8140accbb15046c2069d0c8e7f03be12a256c..d1521868348716c30f6943575902a95e666b308a 100644 --- a/src/main/scala/inox/solvers/SolverFactory.scala +++ b/src/main/scala/inox/solvers/SolverFactory.scala @@ -33,5 +33,10 @@ object SolverFactory { } } - def apply(p: Program): SolverFactory { val program: p.type } = ??? + def apply(p: InoxProgram) + (solverOpts: SolverOptions, evOpts: evaluators.EvaluatorOptions): + SolverFactory { val program: p.type } = ??? + + def default(p: InoxProgram): SolverFactory { val program: p.type } = + apply(p)(SolverOptions.empty, evaluators.EvaluatorOptions.empty) }