From 0b108395d330aa459ba55b6ecfbeea13717d7e80 Mon Sep 17 00:00:00 2001 From: Nicolas Voirol <voirol.nicolas@gmail.com> Date: Sat, 6 Aug 2016 14:40:47 +0200 Subject: [PATCH] Finished up SolverDataGen --- src/main/scala/inox/InoxContext.scala | 6 +- src/main/scala/inox/Program.scala | 2 +- src/main/scala/inox/ast/Definitions.scala | 3 + .../scala/inox/datagen/DataGenerator.scala | 2 +- .../scala/inox/datagen/ModelEnumerator.scala | 97 ++++++++++--------- .../scala/inox/datagen/SolverDataGen.scala | 23 +++-- .../scala/inox/evaluators/Evaluator.scala | 2 - .../inox/evaluators/RecursiveEvaluator.scala | 14 ++- .../inox/evaluators/SolvingEvaluator.scala | 14 +-- .../scala/inox/grammars/AllGrammars.scala | 4 +- .../inox/grammars/GrammarsUniverse.scala | 20 ++-- .../scala/inox/solvers/SimpleSolverAPI.scala | 5 +- .../scala/inox/solvers/SolverFactory.scala | 4 +- 13 files changed, 112 insertions(+), 84 deletions(-) diff --git a/src/main/scala/inox/InoxContext.scala b/src/main/scala/inox/InoxContext.scala index 6abc7d3e1..f029a985b 100644 --- a/src/main/scala/inox/InoxContext.scala +++ b/src/main/scala/inox/InoxContext.scala @@ -12,7 +12,11 @@ case class InoxContext( reporter: Reporter, interruptManager: InterruptManager, options: Seq[InoxOption[Any]] = Seq(), - timers: TimerStorage = new TimerStorage) extends InoxOptions + timers: TimerStorage = new TimerStorage) extends InoxOptions { + + def toSolver: solvers.SolverOptions = ??? + def toEvaluator: evaluators.EvaluatorOptions = ??? +} object InoxContext { def empty = { diff --git a/src/main/scala/inox/Program.scala b/src/main/scala/inox/Program.scala index 549c4b22b..7c978b1ca 100644 --- a/src/main/scala/inox/Program.scala +++ b/src/main/scala/inox/Program.scala @@ -18,7 +18,7 @@ trait Program { val ctx = Program.this.ctx } - def extend(functions: Seq[FunDef] = Seq.empty, classes: Seq[ClassDef] = Seq.empty): + def extend(functions: Seq[trees.FunDef] = Seq.empty, classes: Seq[trees.ClassDef] = Seq.empty): Program { val trees: Program.this.trees.type } = new Program { val trees: Program.this.trees.type = Program.this.trees val symbols = Program.this.symbols.extend(functions, classes) diff --git a/src/main/scala/inox/ast/Definitions.scala b/src/main/scala/inox/ast/Definitions.scala index 625136266..e29fa2762 100644 --- a/src/main/scala/inox/ast/Definitions.scala +++ b/src/main/scala/inox/ast/Definitions.scala @@ -47,6 +47,9 @@ trait Definitions { self: Trees => override def hashCode: Int = 61 * id.hashCode + tpe.hashCode } + implicit def variableSymbolOrdering[VS <: VariableSymbol]: Ordering[VS] = + Ordering.by(e => e.id) + sealed abstract class VariableConverter[B <: VariableSymbol] { def convert(a: VariableSymbol): B } diff --git a/src/main/scala/inox/datagen/DataGenerator.scala b/src/main/scala/inox/datagen/DataGenerator.scala index 1b5583fdf..d8a80bed6 100644 --- a/src/main/scala/inox/datagen/DataGenerator.scala +++ b/src/main/scala/inox/datagen/DataGenerator.scala @@ -15,7 +15,7 @@ trait DataGenerator extends Interruptible { implicit val debugSection = DebugSectionDataGen - def generateFor(ins: Seq[Variable], satisfying: Expr, maxValid: Int, maxEnumerated: Int): Iterator[Seq[Expr]] + def generateFor(ins: Seq[ValDef], satisfying: Expr, maxValid: Int, maxEnumerated: Int): Iterator[Seq[Expr]] protected val interrupted: AtomicBoolean = new AtomicBoolean(false) diff --git a/src/main/scala/inox/datagen/ModelEnumerator.scala b/src/main/scala/inox/datagen/ModelEnumerator.scala index 3d433936d..636ff3c16 100644 --- a/src/main/scala/inox/datagen/ModelEnumerator.scala +++ b/src/main/scala/inox/datagen/ModelEnumerator.scala @@ -5,17 +5,21 @@ package datagen import evaluators._ import solvers._ +import utils._ -class ModelEnumerator(factory: SolverFactory[Solver]) { - val program: factory.program.type = factory.program +trait ModelEnumerator { + val factory: SolverFactory + lazy val program: factory.program.type = factory.program import program._ import program.trees._ import program.symbols._ + import SolverResponses._ + protected val evaluator: RecursiveEvaluator { val program: ModelEnumerator.this.program.type } = - RecursiveEvaluator(program) + RecursiveEvaluator(program)(ctx.toEvaluator, ctx.toSolver) - def enumSimple(vs: Seq[Variable], satisfying: Expr): FreeableIterator[Map[Variable, Expr]] = { + def enumSimple(vs: Seq[ValDef], satisfying: Expr): FreeableIterator[Map[ValDef, Expr]] = { enumVarying0(vs, satisfying, None, -1) } @@ -26,52 +30,53 @@ class ModelEnumerator(factory: SolverFactory[Solver]) { * Note: there is no guarantee that the models enumerated consecutively share the * same `caracteristic`. */ - def enumVarying(ids: Seq[Identifier], satisfying: Expr, measure: Expr, nPerMeasure: Int = 1) = { - enumVarying0(ids, satisfying, Some(measure), nPerMeasure) + def enumVarying(vs: Seq[ValDef], satisfying: Expr, measure: Expr, nPerMeasure: Int = 1) = { + enumVarying0(vs, satisfying, Some(measure), nPerMeasure) } - private[this] def enumVarying0(ids: Seq[Identifier], satisfying: Expr, measure: Option[Expr], nPerMeasure: Int = 1): FreeableIterator[Map[Identifier, Expr]] = { + private[this] def enumVarying0(vs: Seq[ValDef], satisfying: Expr, measure: Option[Expr], nPerMeasure: Int = 1): FreeableIterator[Map[ValDef, Expr]] = { val s = factory.getNewSolver s.assertCnstr(satisfying) val m = measure match { case Some(ms) => - val m = FreshIdentifier("measure", ms.getType) - s.assertCnstr(Equals(m.toVariable, ms)) + val m = Variable(FreshIdentifier("measure"), ms.getType) + s.assertCnstr(Equals(m, ms)) m case None => - FreshIdentifier("noop", BooleanType) + Variable(FreshIdentifier("noop"), BooleanType) } var perMeasureRem = Map[Expr, Int]().withDefaultValue(nPerMeasure) - new FreeableIterator[Map[Identifier, Expr]] { + new FreeableIterator[Map[ValDef, Expr]] { def computeNext() = { - s.check match { - case Some(true) => - val model = s.getModel - val idsModel = ids.map { id => - id -> model.getOrElse(id, simplestValue(id.getType)) + s.check(Model) match { + case SatWithModel(model) => + val fullModel = vs.map { v => + v -> model.getOrElse(v, simplestValue(v.getType)) }.toMap // Vary the model - s.assertCnstr(not(andJoin(idsModel.toSeq.sortBy(_._1).map { case (k, v) => equality(k.toVariable, v) }))) + s.assertCnstr(not(andJoin(fullModel.toSeq.sortBy(_._1).map { + case (k, v) => equality(k.toVariable, v) + }))) measure match { case Some(ms) => - val mValue = evaluator.eval(ms, idsModel).result.get + val mValue = evaluator.eval(ms, fullModel).result.get perMeasureRem += (mValue -> (perMeasureRem(mValue) - 1)) if (perMeasureRem(mValue) <= 0) { - s.assertCnstr(not(equality(m.toVariable, mValue))) + s.assertCnstr(not(equality(m, mValue))) } case None => } - Some(idsModel) + Some(fullModel) case _ => None @@ -84,27 +89,27 @@ class ModelEnumerator(factory: SolverFactory[Solver]) { } } - def enumMinimizing(ids: Seq[Identifier], cnstr: Expr, measure: Expr) = { - enumOptimizing(ids, cnstr, measure, Down) + def enumMinimizing(vs: Seq[ValDef], cnstr: Expr, measure: Expr) = { + enumOptimizing(vs, cnstr, measure, Down) } - def enumMaximizing(ids: Seq[Identifier], cnstr: Expr, measure: Expr) = { - enumOptimizing(ids, cnstr, measure, Up) + def enumMaximizing(vs: Seq[ValDef], cnstr: Expr, measure: Expr) = { + enumOptimizing(vs, cnstr, measure, Up) } abstract class SearchDirection case object Up extends SearchDirection case object Down extends SearchDirection - private[this] def enumOptimizing(ids: Seq[Identifier], satisfying: Expr, measure: Expr, dir: SearchDirection): FreeableIterator[Map[Identifier, Expr]] = { + private[this] def enumOptimizing(vs: Seq[ValDef], satisfying: Expr, measure: Expr, dir: SearchDirection): FreeableIterator[Map[ValDef, Expr]] = { assert(measure.getType == IntegerType) - val s = sf.getNewSolver + val s = factory.getNewSolver s.assertCnstr(satisfying) - val mId = FreshIdentifier("measure", measure.getType) - s.assertCnstr(Equals(mId.toVariable, measure)) + val m = Variable(FreshIdentifier("measure"), measure.getType) + s.assertCnstr(Equals(m, measure)) // Search Range var ub: Option[BigInt] = None @@ -130,8 +135,8 @@ class ModelEnumerator(factory: SolverFactory[Solver]) { case _ => None } - new FreeableIterator[Map[Identifier, Expr]] { - def computeNext(): Option[Map[Identifier, Expr]] = { + new FreeableIterator[Map[ValDef, Expr]] { + def computeNext(): Option[Map[ValDef, Expr]] = { if (rangeEmpty()) { None } else { @@ -140,37 +145,35 @@ class ModelEnumerator(factory: SolverFactory[Solver]) { s.push() dir match { case Up => - s.assertCnstr(GreaterThan(mId.toVariable, InfiniteIntegerLiteral(t))) + s.assertCnstr(GreaterThan(m, IntegerLiteral(t))) case Down => - s.assertCnstr(LessThan(mId.toVariable, InfiniteIntegerLiteral(t))) + s.assertCnstr(LessThan(m, IntegerLiteral(t))) } t } - s.check match { - case Some(true) => - val sm = s.getModel - val m = ids.map { id => - id -> sm.getOrElse(id, simplestValue(id.getType)) + s.check(Model) match { + case SatWithModel(model) => + val fullModel = vs.map { v => + v -> model.getOrElse(v, simplestValue(v.getType)) }.toMap - evaluator.eval(measure, m).result match { - case Some(InfiniteIntegerLiteral(measureVal)) => + evaluator.eval(measure, fullModel).result match { + case Some(IntegerLiteral(measureVal)) => // Positive result dir match { case Up => lb = Some(measureVal) case Down => ub = Some(measureVal) } - Some(m) + Some(fullModel) case _ => ctx.reporter.warning("Evaluator failed to evaluate measure!") None } - - case Some(false) => + case Unsat => // Negative result thisTry match { case Some(t) => @@ -186,15 +189,21 @@ class ModelEnumerator(factory: SolverFactory[Solver]) { None } - case None => + case Unknown => None } } } def free() { - sf.reclaim(s) + factory.reclaim(s) } } } } + +object ModelEnumerator { + def apply(sf: SolverFactory): ModelEnumerator { val factory: sf.type } = new ModelEnumerator { + val factory: sf.type = sf + } +} diff --git a/src/main/scala/inox/datagen/SolverDataGen.scala b/src/main/scala/inox/datagen/SolverDataGen.scala index f3eff883b..072ec731d 100644 --- a/src/main/scala/inox/datagen/SolverDataGen.scala +++ b/src/main/scala/inox/datagen/SolverDataGen.scala @@ -6,19 +6,19 @@ package datagen import solvers._ import utils._ -trait SolverDataGen extends DataGenerator { +trait SolverDataGen extends DataGenerator { self => import program._ import program.trees._ import program.symbols._ - def factory(p: Program): SolverFactory { val program: p.type } + def factory(p: Program { val trees: self.program.trees.type }): SolverFactory { val program: p.type } def generate(tpe: Type): FreeableIterator[Expr] = { - generateFor(Seq(Variable(FreshIdentifier("tmp"), tpe)), + generateFor(Seq(ValDef(FreshIdentifier("tmp"), tpe)), BooleanLiteral(true), 20, 20).map(_.head).takeWhile(_ => !interrupted.get) } - def generateFor(ins: Seq[Variable], satisfying: Expr, maxValid: Int, maxEnumerated: Int): FreeableIterator[Seq[Expr]] = { + def generateFor(ins: Seq[ValDef], satisfying: Expr, maxValid: Int, maxEnumerated: Int): FreeableIterator[Seq[Expr]] = { if (ins.isEmpty) { FreeableIterator.empty } else { @@ -31,6 +31,8 @@ trait SolverDataGen extends DataGenerator { val tcd = ct.tcd val root = tcd.cd.root val id = cdToId.getOrElse(root, { + import dsl._ + val id = FreshIdentifier("sizeOf", true) val tparams = root.tparams.map(_.freshen) cdToId += root -> id @@ -41,7 +43,6 @@ trait SolverDataGen extends DataGenerator { plus(i, sizeFor(expr.getField(f.id))) } - import dsl._ val x = Variable(FreshIdentifier("x", true), tcd.root.toType) fds +:= new FunDef(id, tparams, Seq(x.toVal), IntegerType, Some(root match { case acd: AbstractClassDef => @@ -54,6 +55,8 @@ trait SolverDataGen extends DataGenerator { case ccd: CaseClassDef => sizeOfCaseClass(ccd, x) }), Set.empty) + + id }) FunctionInvocation(id, ct.tps, Seq(of)) @@ -69,16 +72,22 @@ trait SolverDataGen extends DataGenerator { IntegerLiteral(1) } - val sizeOf = sizeFor(tupleWrap(ins)) + val sizeOf = sizeFor(tupleWrap(ins.map(_.toVariable))) // We need to synthesize a size function for ins' types. val pgm1 = program.extend(functions = fds) - val modelEnum = new ModelEnumerator(factory(pgm1)) + val modelEnum = ModelEnumerator(factory(pgm1)) val enum = modelEnum.enumVarying(ins, satisfying, sizeOf, 5) enum.take(maxValid).map(model => ins.map(model)).takeWhile(_ => !interrupted.get) } } +} +object SolverDataGen { + def apply(p: Program): 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) + } } diff --git a/src/main/scala/inox/evaluators/Evaluator.scala b/src/main/scala/inox/evaluators/Evaluator.scala index ab9166748..b9069f65f 100644 --- a/src/main/scala/inox/evaluators/Evaluator.scala +++ b/src/main/scala/inox/evaluators/Evaluator.scala @@ -5,8 +5,6 @@ package evaluators case class EvaluatorOptions(options: Seq[InoxOption[Any]]) extends InoxOptions - - trait Evaluator { val program: Program val options: EvaluatorOptions diff --git a/src/main/scala/inox/evaluators/RecursiveEvaluator.scala b/src/main/scala/inox/evaluators/RecursiveEvaluator.scala index c62f0cff8..c9f4da8f0 100644 --- a/src/main/scala/inox/evaluators/RecursiveEvaluator.scala +++ b/src/main/scala/inox/evaluators/RecursiveEvaluator.scala @@ -529,9 +529,15 @@ trait RecursiveEvaluator } object RecursiveEvaluator { - def apply(p: Program)(opts: EvaluatorOptions): RecursiveEvaluator { val program: p.type } = new { - val program: p.type = p - } with RecursiveEvaluator with HasDefaultGlobalContext with HasDefaultRecContext { - val maxSteps = 50000 + def apply(p: Program) + (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 maxSteps = 50000 + def getSolver(opts: InoxOption[Any]*) = solvers.SolverFactory(p) + } } } diff --git a/src/main/scala/inox/evaluators/SolvingEvaluator.scala b/src/main/scala/inox/evaluators/SolvingEvaluator.scala index 09a479e94..6b84839cf 100644 --- a/src/main/scala/inox/evaluators/SolvingEvaluator.scala +++ b/src/main/scala/inox/evaluators/SolvingEvaluator.scala @@ -20,7 +20,7 @@ trait SolvingEvaluator extends Evaluator { def default = MutableMap.empty } - def getSolver(opts: InoxOption[Any]*): Solver { val program: SolvingEvaluator.this.program.type } + def getSolver(opts: InoxOption[Any]*): SolverFactory { val program: SolvingEvaluator.this.program.type } private val specCache: MutableMap[Expr, Expr] = MutableMap.empty private val forallCache: MutableMap[Forall, Expr] = MutableMap.empty @@ -29,14 +29,14 @@ trait SolvingEvaluator extends Evaluator { val Lambda(Seq(vd), body) = specs val timer = ctx.timers.evaluators.specs.start() - val solver = getSolver(options.options.collect { + val sf = getSolver(options.options.collect { case o @ InoxOption(opt, _) if opt == optForallCache => o }.toSeq : _*) import SolverResponses._ - solver.assertCnstr(body) - val res = solver.check(Model) + val api = SimpleSolverAPI(sf) + val res = api.solveSAT(body) timer.stop() res match { @@ -56,7 +56,7 @@ trait SolvingEvaluator extends Evaluator { BooleanLiteral(cache.getOrElse(forall, { val timer = ctx.timers.evaluators.forall.start() - val solver = getSolver( + val sf = getSolver( InoxOption(optSilentErrors)(true), InoxOption(optCheckModels)(false), InoxOption(optForallCache)(cache) @@ -64,8 +64,8 @@ trait SolvingEvaluator extends Evaluator { import SolverResponses._ - solver.assertCnstr(Not(forall.body)) - val res = solver.check(Model) + val api = SimpleSolverAPI(sf) + val res = api.solveSAT(Not(forall.body)) timer.stop() res match { diff --git a/src/main/scala/inox/grammars/AllGrammars.scala b/src/main/scala/inox/grammars/AllGrammars.scala index 265892bfb..d999404ac 100644 --- a/src/main/scala/inox/grammars/AllGrammars.scala +++ b/src/main/scala/inox/grammars/AllGrammars.scala @@ -6,6 +6,6 @@ trait AllGrammars extends ElementaryGrammars with ConstantGrammars with ClosureGrammars with EqualityGrammars - with FunctionCallsGrammars -{ self: GrammarsUniverse => + with FunctionCallsGrammars { + self: GrammarsUniverse => } diff --git a/src/main/scala/inox/grammars/GrammarsUniverse.scala b/src/main/scala/inox/grammars/GrammarsUniverse.scala index 74971a28e..961452010 100644 --- a/src/main/scala/inox/grammars/GrammarsUniverse.scala +++ b/src/main/scala/inox/grammars/GrammarsUniverse.scala @@ -1,15 +1,15 @@ package inox package grammars -trait GrammarsUniverse extends Tags - with Productions - with Aspects - with aspects.PersistentAspects - with aspects.AllAspects - with Labels - with ExpressionGrammars - with SimpleExpressionGrammars - with AllGrammars -{ +trait GrammarsUniverse + extends Tags + with Productions + with Aspects + with aspects.PersistentAspects + with aspects.AllAspects + with Labels + with ExpressionGrammars + with SimpleExpressionGrammars + with AllGrammars { val program: Program } diff --git a/src/main/scala/inox/solvers/SimpleSolverAPI.scala b/src/main/scala/inox/solvers/SimpleSolverAPI.scala index deb96092b..cd96dca50 100644 --- a/src/main/scala/inox/solvers/SimpleSolverAPI.scala +++ b/src/main/scala/inox/solvers/SimpleSolverAPI.scala @@ -11,7 +11,6 @@ trait SimpleSolverAPI { def solveVALID(expression: Expr): Option[Boolean] = { val s = factory.getNewSolver() - import s._ try { s.assertCnstr(Not(expression)) s.check(Simple) match { @@ -25,7 +24,6 @@ trait SimpleSolverAPI { def solveSAT(expression: Expr): ResponseWithModel[Map[ValDef, Expr]] = { val s = factory.getNewSolver() - import s._ try { s.assertCnstr(expression) s.check(Model) @@ -37,7 +35,6 @@ trait SimpleSolverAPI { def solveSATWithCores(expression: Expr, assumptions: Set[Expr]): ResponseWithModelAndCores[Map[ValDef, Expr], Set[Expr]] = { val s = factory.getNewSolver() - import s._ try { s.assertCnstr(expression) s.checkAssumptions(All)(assumptions) @@ -48,7 +45,7 @@ trait SimpleSolverAPI { } object SimpleSolverAPI { - def apply(sf: SolverFactory) = new SimpleSolverAPI { + def apply(sf: SolverFactory): SimpleSolverAPI { val factory: sf.type } = new SimpleSolverAPI { val factory: sf.type = sf } } diff --git a/src/main/scala/inox/solvers/SolverFactory.scala b/src/main/scala/inox/solvers/SolverFactory.scala index fc36dd3ff..6ef8140ac 100644 --- a/src/main/scala/inox/solvers/SolverFactory.scala +++ b/src/main/scala/inox/solvers/SolverFactory.scala @@ -22,7 +22,7 @@ trait SolverFactory { } object SolverFactory { - def apply[S1 <: Solver : TypeTag](p: Program)(nme: String, builder: () => S1 { val program: p.type }): + def create[S1 <: Solver : TypeTag](p: Program)(nme: String, builder: () => S1 { val program: p.type }): SolverFactory { val program: p.type; type S = S1 { val program: p.type } } = { new SolverFactory { val program: p.type = p @@ -32,4 +32,6 @@ object SolverFactory { def getNewSolver() = builder() } } + + def apply(p: Program): SolverFactory { val program: p.type } = ??? } -- GitLab