From 5ccb8ebe0aeb76c117d21d3b031a0672c48f39fc Mon Sep 17 00:00:00 2001 From: Etienne Kneuss <ekneuss@gmail.com> Date: Fri, 23 Nov 2012 16:49:52 +0100 Subject: [PATCH] Prepare ground for parallel search --- .../scala/leon/synthesis/Complexity.scala | 34 ----------------- .../scala/leon/synthesis/Heuristics.scala | 24 ++++++------ src/main/scala/leon/synthesis/Problem.scala | 6 +-- src/main/scala/leon/synthesis/Rules.scala | 38 +++++++++---------- .../leon/synthesis/SynthesisContext.scala | 16 ++++++++ .../scala/leon/synthesis/Synthesizer.scala | 13 ++++--- .../synthesis/heuristics/ADTInduction.scala | 8 ++-- .../synthesis/heuristics/IntInduction.scala | 12 +++--- .../heuristics/OptimisticInjection.scala | 6 +-- .../heuristics/SelectiveInlining.scala | 6 +-- .../scala/leon/synthesis/rules/ADTDual.scala | 4 +- .../scala/leon/synthesis/rules/ADTSplit.scala | 10 ++--- .../scala/leon/synthesis/rules/Assert.scala | 6 +-- .../leon/synthesis/rules/CaseSplit.scala | 8 ++-- .../scala/leon/synthesis/rules/Cegis.scala | 26 ++++++------- .../leon/synthesis/rules/Disunification.scala | 4 +- .../leon/synthesis/rules/EqualitySplit.scala | 16 ++++---- .../scala/leon/synthesis/rules/Ground.scala | 6 +-- .../synthesis/rules/IntegerEquation.scala | 8 ++-- .../synthesis/rules/IntegerInequalities.scala | 6 +-- .../scala/leon/synthesis/rules/OnePoint.scala | 6 +-- .../synthesis/rules/OptimisticGround.scala | 10 ++--- .../synthesis/rules/UnconstrainedOutput.scala | 4 +- .../leon/synthesis/rules/Unification.scala | 8 ++-- .../leon/synthesis/rules/UnusedInput.scala | 6 +-- 25 files changed, 136 insertions(+), 155 deletions(-) delete mode 100644 src/main/scala/leon/synthesis/Complexity.scala create mode 100644 src/main/scala/leon/synthesis/SynthesisContext.scala diff --git a/src/main/scala/leon/synthesis/Complexity.scala b/src/main/scala/leon/synthesis/Complexity.scala deleted file mode 100644 index 2f09637d4..000000000 --- a/src/main/scala/leon/synthesis/Complexity.scala +++ /dev/null @@ -1,34 +0,0 @@ -package leon -package synthesis - -import purescala.Trees._ -import purescala.TreeOps._ - -abstract class Complexity[T <: Complexity[T]] extends Ordered[T] { - def compare(that: T) = this.value - that.value - - def value : Int -} - -abstract class AbsSolComplexity extends Complexity[AbsSolComplexity] { - def value: Int -} - -case class SolComplexity(s: Solution) extends AbsSolComplexity { - lazy val value = { - val chooses = collectChooses(s.toExpr) - val chooseCost = chooses.foldLeft(0)((i, c) => i + (1000 * math.pow(2, c.vars.size).toInt + formulaSize(c.pred))) - - formulaSize(s.toExpr) + chooseCost - } -} - -case class FixedSolComplexity(c: Int) extends AbsSolComplexity { - val value = c -} - -case class ProblemComplexity(p: Problem) extends Complexity[ProblemComplexity] { - lazy val value = { - math.pow(2, p.xs.size).toInt + formulaSize(p.phi) - } -} diff --git a/src/main/scala/leon/synthesis/Heuristics.scala b/src/main/scala/leon/synthesis/Heuristics.scala index 6787da103..decfdeffb 100644 --- a/src/main/scala/leon/synthesis/Heuristics.scala +++ b/src/main/scala/leon/synthesis/Heuristics.scala @@ -6,11 +6,11 @@ import purescala.Trees._ import heuristics._ object Heuristics { - def all = Set[Synthesizer => Rule]( - new IntInduction(_), + def all = Set[Rule]( + IntInduction, //new OptimisticInjection(_), //new SelectiveInlining(_), - new ADTInduction(_) + ADTInduction ) } @@ -22,20 +22,20 @@ trait Heuristic { } object HeuristicStep { - def verifyPre(synth: Synthesizer, problem: Problem)(s: Solution): Solution = { - synth.solver.solveSAT(And(Not(s.pre), problem.phi)) match { + def verifyPre(sctx: SynthesisContext, problem: Problem)(s: Solution): Solution = { + sctx.solver.solveSAT(And(Not(s.pre), problem.phi)) match { case (Some(true), model) => - synth.reporter.warning("Heuristic failed to produce weakest precondition:") - synth.reporter.warning(" - problem: "+problem) - synth.reporter.warning(" - precondition: "+s.pre) + sctx.reporter.warning("Heuristic failed to produce weakest precondition:") + sctx.reporter.warning(" - problem: "+problem) + sctx.reporter.warning(" - precondition: "+s.pre) s case _ => s } } - def apply(synth: Synthesizer, problem: Problem, subProblems: List[Problem], onSuccess: List[Solution] => Solution) = { - new RuleApplication(subProblems.size, onSuccess.andThen(verifyPre(synth, problem))) { + def apply(sctx: SynthesisContext, problem: Problem, subProblems: List[Problem], onSuccess: List[Solution] => Solution) = { + new RuleApplication(subProblems.size, onSuccess.andThen(verifyPre(sctx, problem))) { def apply() = RuleDecomposed(subProblems, onSuccess) } } @@ -43,8 +43,8 @@ object HeuristicStep { object HeuristicFastStep { - def apply(synth: Synthesizer, problem: Problem, subProblems: List[Problem], onSuccess: List[Solution] => Solution) = { - RuleResult(List(HeuristicStep(synth, problem, subProblems, onSuccess))) + def apply(sctx: SynthesisContext, problem: Problem, subProblems: List[Problem], onSuccess: List[Solution] => Solution) = { + RuleResult(List(HeuristicStep(sctx, problem, subProblems, onSuccess))) } } diff --git a/src/main/scala/leon/synthesis/Problem.scala b/src/main/scala/leon/synthesis/Problem.scala index 89b452873..0a43181e4 100644 --- a/src/main/scala/leon/synthesis/Problem.scala +++ b/src/main/scala/leon/synthesis/Problem.scala @@ -7,10 +7,8 @@ import leon.purescala.Common._ // Defines a synthesis triple of the form: // ⟦ as ⟨ C | phi ⟩ xs ⟧ -case class Problem(as: List[Identifier], c: Expr, phi: Expr, xs: List[Identifier]) { - override def toString = "⟦ "+as.mkString(";")+", "+c+" ᚒ ⟨ "+phi+" ⟩ "+xs.mkString(";")+" ⟧ " - - val complexity: ProblemComplexity = ProblemComplexity(this) +case class Problem(as: List[Identifier], pc: Expr, phi: Expr, xs: List[Identifier]) { + override def toString = "⟦ "+as.mkString(";")+", "+(if (pc != BooleanLiteral(true)) pc+" ᚒ " else "")+" ⟨ "+phi+" ⟩ "+xs.mkString(";")+" ⟧ " } object Problem { diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala index 85d20e1d7..750171b1d 100644 --- a/src/main/scala/leon/synthesis/Rules.scala +++ b/src/main/scala/leon/synthesis/Rules.scala @@ -7,23 +7,23 @@ import purescala.TreeOps._ import rules._ object Rules { - def all = Set[Synthesizer => Rule]( - new Unification.DecompTrivialClash(_), - new Unification.OccursCheck(_), // probably useless - new Disunification.Decomp(_), - new ADTDual(_), - new OnePoint(_), - new Ground(_), - new CaseSplit(_), - new UnusedInput(_), - new UnconstrainedOutput(_), - new OptimisticGround(_), - new EqualitySplit(_), - new CEGIS(_), - new Assert(_), - new ADTSplit(_), - new IntegerEquation(_), - new IntegerInequalities(_) + def all = Set[Rule]( + Unification.DecompTrivialClash, + Unification.OccursCheck, // probably useless + Disunification.Decomp, + ADTDual, + OnePoint, + Ground, + CaseSplit, + UnusedInput, + UnconstrainedOutput, + OptimisticGround, + EqualitySplit, + CEGIS, + Assert, + ADTSplit, + IntegerEquation, + IntegerInequalities ) } @@ -73,8 +73,8 @@ object RuleFastSuccess { } } -abstract class Rule(val name: String, val synth: Synthesizer, val priority: Priority) { - def attemptToApplyOn(problem: Problem): RuleResult +abstract class Rule(val name: String, val priority: Priority) { + def attemptToApplyOn(sctx: SynthesisContext, problem: Problem): RuleResult def subst(what: Tuple2[Identifier, Expr], in: Expr): Expr = replace(Map(Variable(what._1) -> what._2), in) def substAll(what: Map[Identifier, Expr], in: Expr): Expr = replace(what.map(w => Variable(w._1) -> w._2), in) diff --git a/src/main/scala/leon/synthesis/SynthesisContext.scala b/src/main/scala/leon/synthesis/SynthesisContext.scala new file mode 100644 index 000000000..0f085f52c --- /dev/null +++ b/src/main/scala/leon/synthesis/SynthesisContext.scala @@ -0,0 +1,16 @@ +package leon +package synthesis + +import solvers.Solver + +case class SynthesisContext( + synth: Synthesizer, + solver: Solver, + simpleSolver: Solver, + reporter: Reporter +) + +object SynthesisContext { + def fromSynthesizer(synth: Synthesizer) = SynthesisContext(synth, synth.solver, synth.solver, synth.reporter) +} + diff --git a/src/main/scala/leon/synthesis/Synthesizer.scala b/src/main/scala/leon/synthesis/Synthesizer.scala index ae3717d3c..a708ecf06 100644 --- a/src/main/scala/leon/synthesis/Synthesizer.scala +++ b/src/main/scala/leon/synthesis/Synthesizer.scala @@ -18,20 +18,18 @@ import synthesis.search._ class Synthesizer(val reporter: Reporter, val solver: Solver, val problem: Problem, - val ruleConstructors: Set[Synthesizer => Rule], + val rules: Set[Rule], generateDerivationTrees: Boolean = false, filterFuns: Option[Set[String]] = None, firstOnly: Boolean = false, timeoutMs: Option[Long] = None) { import reporter.{error,warning,info,fatalError} - val rules = ruleConstructors.map(_.apply(this)) - var continue = true def synthesize(): Solution = { - val search = new AOSearch(problem, rules) + val search = new AOSearch(this, problem, rules) val sigINT = new Signal("INT") var oldHandler: SignalHandler = null @@ -77,9 +75,12 @@ class Synthesizer(val reporter: Reporter, override def toString = p.toString } - class AOSearch(problem: Problem, + class AOSearch(synth: Synthesizer, + problem: Problem, rules: Set[Rule]) extends AndOrGraphSearch[TaskRunRule, TaskTryRules, Solution](new AndOrGraph(TaskTryRules(problem))) { + val sctx = SynthesisContext.fromSynthesizer(synth) + def processAndLeaf(t: TaskRunRule) = { val prefix = "[%-20s] ".format(Option(t.rule).getOrElse("?")) @@ -104,7 +105,7 @@ class Synthesizer(val reporter: Reporter, } def processOrLeaf(t: TaskTryRules) = { - val sub = rules.flatMap ( r => r.attemptToApplyOn(t.p).alternatives.map(TaskRunRule(t.p, r, _)) ) + val sub = rules.flatMap ( r => r.attemptToApplyOn(sctx, t.p).alternatives.map(TaskRunRule(t.p, r, _)) ) if (!sub.isEmpty) { Expanded(sub.toList) diff --git a/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala b/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala index 2117dc915..aec4b610b 100644 --- a/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala +++ b/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala @@ -9,8 +9,8 @@ import purescala.TreeOps._ import purescala.TypeTrees._ import purescala.Definitions._ -class ADTInduction(synth: Synthesizer) extends Rule("ADT Induction", synth, 80) with Heuristic { - def attemptToApplyOn(p: Problem): RuleResult = { +case object ADTInduction extends Rule("ADT Induction", 80) with Heuristic { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val candidates = p.as.collect { case IsTyped(origId, AbstractClassType(cd)) => (origId, cd) } @@ -38,7 +38,7 @@ class ADTInduction(synth: Synthesizer) extends Rule("ADT Induction", synth, 80) if (isRecursive) { val innerPhi = substAll(residualMap + (origId -> Variable(inductOn)), p.phi) - val innerPC = substAll(residualMap + (origId -> Variable(inductOn)), p.c) + val innerPC = substAll(residualMap + (origId -> Variable(inductOn)), p.pc) val subProblemsInfo = for (dcd <- cd.knownDescendents) yield dcd match { case ccd : CaseClassDef => @@ -97,7 +97,7 @@ class ADTInduction(synth: Synthesizer) extends Rule("ADT Induction", synth, 80) Solution(Or(globalPre), sols.flatMap(_.defs).toSet+newFun, FunctionInvocation(newFun, p.as.map(Variable(_)))) } - Some(HeuristicStep(synth, p, subProblemsInfo.map(_._1).toList, onSuccess)) + Some(HeuristicStep(sctx, p, subProblemsInfo.map(_._1).toList, onSuccess)) } else { None } diff --git a/src/main/scala/leon/synthesis/heuristics/IntInduction.scala b/src/main/scala/leon/synthesis/heuristics/IntInduction.scala index 28cb94845..9d708689a 100644 --- a/src/main/scala/leon/synthesis/heuristics/IntInduction.scala +++ b/src/main/scala/leon/synthesis/heuristics/IntInduction.scala @@ -9,8 +9,8 @@ import purescala.TreeOps._ import purescala.TypeTrees._ import purescala.Definitions._ -class IntInduction(synth: Synthesizer) extends Rule("Int Induction", synth, 50) with Heuristic { - def attemptToApplyOn(p: Problem): RuleResult = { +case object IntInduction extends Rule("Int Induction", 50) with Heuristic { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { p.as match { case List(IsTyped(origId, Int32Type)) => val tpe = TupleType(p.xs.map(_.getType)) @@ -25,9 +25,9 @@ class IntInduction(synth: Synthesizer) extends Rule("Int Induction", synth, 50) val postCondGT = substAll(postXsMap + (origId -> Minus(Variable(inductOn), IntLiteral(1))), p.phi) val postCondLT = substAll(postXsMap + (origId -> Plus(Variable(inductOn), IntLiteral(1))), p.phi) - val subBase = Problem(List(), p.c, subst(origId -> IntLiteral(0), p.phi), p.xs) - val subGT = Problem(inductOn :: postXs, And(Seq(GreaterThan(Variable(inductOn), IntLiteral(0)), postCondGT, p.c)), newPhi, p.xs) - val subLT = Problem(inductOn :: postXs, And(Seq(LessThan(Variable(inductOn), IntLiteral(0)), postCondLT, p.c)), newPhi, p.xs) + val subBase = Problem(List(), p.pc, subst(origId -> IntLiteral(0), p.phi), p.xs) + val subGT = Problem(inductOn :: postXs, And(Seq(GreaterThan(Variable(inductOn), IntLiteral(0)), postCondGT, p.pc)), newPhi, p.xs) + val subLT = Problem(inductOn :: postXs, And(Seq(LessThan(Variable(inductOn), IntLiteral(0)), postCondLT, p.pc)), newPhi, p.xs) val onSuccess: List[Solution] => Solution = { case List(base, gt, lt) => @@ -54,7 +54,7 @@ class IntInduction(synth: Synthesizer) extends Rule("Int Induction", synth, 50) Solution.none } - HeuristicFastStep(synth, p, List(subBase, subGT, subLT), onSuccess) + HeuristicFastStep(sctx, p, List(subBase, subGT, subLT), onSuccess) case _ => RuleInapplicable } diff --git a/src/main/scala/leon/synthesis/heuristics/OptimisticInjection.scala b/src/main/scala/leon/synthesis/heuristics/OptimisticInjection.scala index 85d5f34cc..1378649d4 100644 --- a/src/main/scala/leon/synthesis/heuristics/OptimisticInjection.scala +++ b/src/main/scala/leon/synthesis/heuristics/OptimisticInjection.scala @@ -9,8 +9,8 @@ import purescala.TreeOps._ import purescala.TypeTrees._ import purescala.Definitions._ -class OptimisticInjection(synth: Synthesizer) extends Rule("Opt. Injection", synth, 50) with Heuristic { - def attemptToApplyOn(p: Problem): RuleResult = { +case object OptimisticInjection extends Rule("Opt. Injection", 50) with Heuristic { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val TopLevelAnds(exprs) = p.phi val eqfuncalls = exprs.collect{ @@ -36,7 +36,7 @@ class OptimisticInjection(synth: Synthesizer) extends Rule("Opt. Injection", syn val sub = p.copy(phi = And(newExprs)) - HeuristicFastStep(synth, p, List(sub), forward) + HeuristicFastStep(sctx, p, List(sub), forward) } else { RuleInapplicable } diff --git a/src/main/scala/leon/synthesis/heuristics/SelectiveInlining.scala b/src/main/scala/leon/synthesis/heuristics/SelectiveInlining.scala index 4fe3f764d..5961d6777 100644 --- a/src/main/scala/leon/synthesis/heuristics/SelectiveInlining.scala +++ b/src/main/scala/leon/synthesis/heuristics/SelectiveInlining.scala @@ -9,8 +9,8 @@ import purescala.TreeOps._ import purescala.TypeTrees._ import purescala.Definitions._ -class SelectiveInlining(synth: Synthesizer) extends Rule("Sel. Inlining", synth, 20) with Heuristic { - def attemptToApplyOn(p: Problem): RuleResult = { +case object SelectiveInlining extends Rule("Sel. Inlining", 20) with Heuristic { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val TopLevelAnds(exprs) = p.phi val eqfuncalls = exprs.collect{ @@ -36,7 +36,7 @@ class SelectiveInlining(synth: Synthesizer) extends Rule("Sel. Inlining", synth, val sub = p.copy(phi = And(newExprs)) - HeuristicFastStep(synth, p, List(sub), forward) + HeuristicFastStep(sctx, p, List(sub), forward) } else { RuleInapplicable } diff --git a/src/main/scala/leon/synthesis/rules/ADTDual.scala b/src/main/scala/leon/synthesis/rules/ADTDual.scala index bb4753752..0660f87a8 100644 --- a/src/main/scala/leon/synthesis/rules/ADTDual.scala +++ b/src/main/scala/leon/synthesis/rules/ADTDual.scala @@ -6,8 +6,8 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -class ADTDual(synth: Synthesizer) extends Rule("ADTDual", synth, 200) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object ADTDual extends Rule("ADTDual", 200) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val xs = p.xs.toSet val as = p.as.toSet diff --git a/src/main/scala/leon/synthesis/rules/ADTSplit.scala b/src/main/scala/leon/synthesis/rules/ADTSplit.scala index 39e987c25..6a4d88c7a 100644 --- a/src/main/scala/leon/synthesis/rules/ADTSplit.scala +++ b/src/main/scala/leon/synthesis/rules/ADTSplit.scala @@ -9,16 +9,16 @@ import purescala.TreeOps._ import purescala.Extractors._ import purescala.Definitions._ -class ADTSplit(synth: Synthesizer) extends Rule("ADT Split.", synth, 70) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object ADTSplit extends Rule("ADT Split.", 70) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val candidates = p.as.collect { case IsTyped(id, AbstractClassType(cd)) => val optCases = for (dcd <- cd.knownDescendents) yield dcd match { case ccd : CaseClassDef => - val toSat = And(p.c, Not(CaseClassInstanceOf(ccd, Variable(id)))) + val toSat = And(p.pc, Not(CaseClassInstanceOf(ccd, Variable(id)))) - val isImplied = synth.solver.solveSAT(toSat) match { + val isImplied = sctx.solver.solveSAT(toSat) match { case (Some(false), _) => true case _ => false } @@ -50,7 +50,7 @@ class ADTSplit(synth: Synthesizer) extends Rule("ADT Split.", synth, 70) { val args = ccd.fieldsIds.map(id => FreshIdentifier(id.name, true).setType(id.getType)).toList val subPhi = subst(id -> CaseClass(ccd, args.map(Variable(_))), p.phi) - val subProblem = Problem(args ::: oas, p.c, subPhi, p.xs) + val subProblem = Problem(args ::: oas, p.pc, subPhi, p.xs) val subPattern = CaseClassPattern(None, ccd, args.map(id => WildcardPattern(Some(id)))) (ccd, subProblem, subPattern) diff --git a/src/main/scala/leon/synthesis/rules/Assert.scala b/src/main/scala/leon/synthesis/rules/Assert.scala index ab2e66d4b..04459435e 100644 --- a/src/main/scala/leon/synthesis/rules/Assert.scala +++ b/src/main/scala/leon/synthesis/rules/Assert.scala @@ -6,8 +6,8 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -class Assert(synth: Synthesizer) extends Rule("Assert", synth, 200) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object Assert extends Rule("Assert", 200) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { p.phi match { case TopLevelAnds(exprs) => val xsSet = p.xs.toSet @@ -18,7 +18,7 @@ class Assert(synth: Synthesizer) extends Rule("Assert", synth, 200) { if (others.isEmpty) { RuleFastSuccess(Solution(And(exprsA), Set(), Tuple(p.xs.map(id => simplestValue(Variable(id)))))) } else { - val sub = p.copy(c = And(p.c +: exprsA), phi = And(others)) + val sub = p.copy(pc = And(p.pc +: exprsA), phi = And(others)) RuleFastStep(List(sub), { case Solution(pre, defs, term) :: Nil => Solution(And(exprsA :+ pre), defs, term) diff --git a/src/main/scala/leon/synthesis/rules/CaseSplit.scala b/src/main/scala/leon/synthesis/rules/CaseSplit.scala index 44f0b7bad..50b769c70 100644 --- a/src/main/scala/leon/synthesis/rules/CaseSplit.scala +++ b/src/main/scala/leon/synthesis/rules/CaseSplit.scala @@ -6,12 +6,12 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -class CaseSplit(synth: Synthesizer) extends Rule("Case-Split", synth, 200) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object CaseSplit extends Rule("Case-Split", 200) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { p.phi match { case Or(o1 :: o2 :: _) => - val sub1 = Problem(p.as, p.c, o1, p.xs) - val sub2 = Problem(p.as, p.c, o2, p.xs) + val sub1 = Problem(p.as, p.pc, o1, p.xs) + val sub2 = Problem(p.as, p.pc, o2, p.xs) val onSuccess: List[Solution] => Solution = { case List(Solution(p1, d1, t1), Solution(p2, d2, t2)) => Solution(Or(p1, p2), d1++d2, IfExpr(p1, t1, t2)) diff --git a/src/main/scala/leon/synthesis/rules/Cegis.scala b/src/main/scala/leon/synthesis/rules/Cegis.scala index 6b56bcc00..23d8bf2a9 100644 --- a/src/main/scala/leon/synthesis/rules/Cegis.scala +++ b/src/main/scala/leon/synthesis/rules/Cegis.scala @@ -9,8 +9,8 @@ import purescala.TypeTrees._ import purescala.TreeOps._ import purescala.Extractors._ -class CEGIS(synth: Synthesizer) extends Rule("CEGIS", synth, 150) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object CEGIS extends Rule("CEGIS", 150) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { case class Generator(tpe: TypeTree, altBuilder: () => List[(Expr, Set[Identifier])]); var generators = Map[TypeTree, Generator]() @@ -40,7 +40,7 @@ class CEGIS(synth: Synthesizer) extends Rule("CEGIS", synth, 150) { { () => val alts: Seq[(Expr, Set[Identifier])] = cd.knownDescendents.flatMap(i => i match { case acd: AbstractClassDef => - synth.reporter.error("Unnexpected abstract class in descendants!") + sctx.reporter.error("Unnexpected abstract class in descendants!") None case cd: CaseClassDef => val ids = cd.fieldsIds.map(i => FreshIdentifier("c", true).setType(i.getType)) @@ -50,7 +50,7 @@ class CEGIS(synth: Synthesizer) extends Rule("CEGIS", synth, 150) { } case _ => - synth.reporter.error("Can't construct generator. Unsupported type: "+t+"["+t.getClass+"]"); + sctx.reporter.error("Can't construct generator. Unsupported type: "+t+"["+t.getClass+"]"); { () => Nil } } val g = Generator(t, alternatives) @@ -122,7 +122,7 @@ class CEGIS(synth: Synthesizer) extends Rule("CEGIS", synth, 150) { var ass = p.as.toSet var xss = p.xs.toSet - var lastF = TentativeFormula(p.c, p.phi, BooleanLiteral(true), Map(), Map() ++ p.xs.map(x => x -> Set(x))) + var lastF = TentativeFormula(p.pc, p.phi, BooleanLiteral(true), Map(), Map() ++ p.xs.map(x => x -> Set(x))) var currentF = lastF.unroll var unrolings = 0 val maxUnrolings = 3 @@ -138,12 +138,12 @@ class CEGIS(synth: Synthesizer) extends Rule("CEGIS", synth, 150) { var continue = true - while (result.isEmpty && continue && synth.continue) { + while (result.isEmpty && continue && sctx.synth.continue) { val basePhi = currentF.entireFormula val constrainedPhi = And(basePhi +: predicates) //println("-"*80) //println("To satisfy: "+constrainedPhi) - synth.solver.solveSAT(constrainedPhi) match { + sctx.solver.solveSAT(constrainedPhi) match { case (Some(true), satModel) => //println("Found candidate!: "+satModel.filterKeys(bss)) @@ -154,7 +154,7 @@ class CEGIS(synth: Synthesizer) extends Rule("CEGIS", synth, 150) { val counterPhi = And(Seq(currentF.pathcond, fixedBss, currentF.program, Not(currentF.phi))) //println("Formula to validate: "+counterPhi) - synth.solver.solveSAT(counterPhi) match { + sctx.solver.solveSAT(counterPhi) match { case (Some(true), invalidModel) => val fixedAss = And(ass.map(a => Equals(Variable(a), invalidModel(a))).toSeq) @@ -166,14 +166,14 @@ class CEGIS(synth: Synthesizer) extends Rule("CEGIS", synth, 150) { case BooleanLiteral(false) => Not(Variable(b)) }} - val unsatCore = synth.solver.solveSATWithCores(mustBeUnsat, bssAssumptions) match { + val unsatCore = sctx.solver.solveSATWithCores(mustBeUnsat, bssAssumptions) match { case ((Some(false), _, core)) => //println("Formula: "+mustBeUnsat) //println("Core: "+core) //println(synth.solver.solveSAT(And(mustBeUnsat +: bssAssumptions.toSeq))) //println("maxcore: "+bssAssumptions) if (core.isEmpty) { - synth.reporter.warning("Got empty core, must be unsat without assumptions!") + sctx.reporter.warning("Got empty core, must be unsat without assumptions!") Set() } else { core @@ -215,7 +215,7 @@ class CEGIS(synth: Synthesizer) extends Rule("CEGIS", synth, 150) { result = Some(RuleSuccess(Solution(BooleanLiteral(true), Set(), Tuple(p.xs.map(valuateWithModel(mapping))).setType(tpe)))) case _ => - synth.reporter.warning("Solver returned 'UNKNOWN' in a CEGIS iteration.") + sctx.reporter.warning("Solver returned 'UNKNOWN' in a CEGIS iteration.") continue = false } @@ -231,13 +231,13 @@ class CEGIS(synth: Synthesizer) extends Rule("CEGIS", synth, 150) { lastF = currentF currentF = currentF.unroll unrolings += 1 - } while(unrolings < maxUnrolings && lastF != currentF && result.isEmpty && synth.continue) + } while(unrolings < maxUnrolings && lastF != currentF && result.isEmpty && sctx.synth.continue) result.getOrElse(RuleApplicationImpossible) } catch { case e: Throwable => - synth.reporter.warning("CEGIS crashed: "+e.getMessage) + sctx.reporter.warning("CEGIS crashed: "+e.getMessage) RuleApplicationImpossible } diff --git a/src/main/scala/leon/synthesis/rules/Disunification.scala b/src/main/scala/leon/synthesis/rules/Disunification.scala index 9cf574acf..7bce9d378 100644 --- a/src/main/scala/leon/synthesis/rules/Disunification.scala +++ b/src/main/scala/leon/synthesis/rules/Disunification.scala @@ -8,8 +8,8 @@ import purescala.TreeOps._ import purescala.Extractors._ object Disunification { - class Decomp(synth: Synthesizer) extends Rule("Disunif. Decomp.", synth, 200) { - def attemptToApplyOn(p: Problem): RuleResult = { + case object Decomp extends Rule("Disunif. Decomp.", 200) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val TopLevelAnds(exprs) = p.phi val (toRemove, toAdd) = exprs.collect { diff --git a/src/main/scala/leon/synthesis/rules/EqualitySplit.scala b/src/main/scala/leon/synthesis/rules/EqualitySplit.scala index 76330d820..f74c9fc55 100644 --- a/src/main/scala/leon/synthesis/rules/EqualitySplit.scala +++ b/src/main/scala/leon/synthesis/rules/EqualitySplit.scala @@ -8,21 +8,21 @@ import purescala.TypeTrees._ import purescala.TreeOps._ import purescala.Extractors._ -class EqualitySplit(synth: Synthesizer) extends Rule("Eq. Split.", synth, 90) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object EqualitySplit extends Rule("Eq. Split.", 90) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val candidates = p.as.groupBy(_.getType).map(_._2.toList).filter { case List(a1, a2) => - val toValEQ = Implies(p.c, Equals(Variable(a1), Variable(a2))) + val toValEQ = Implies(p.pc, Equals(Variable(a1), Variable(a2))) - val impliesEQ = synth.solver.solveSAT(Not(toValEQ)) match { + val impliesEQ = sctx.solver.solveSAT(Not(toValEQ)) match { case (Some(false), _) => true case _ => false } if (!impliesEQ) { - val toValNE = Implies(p.c, Not(Equals(Variable(a1), Variable(a2)))) + val toValNE = Implies(p.pc, Not(Equals(Variable(a1), Variable(a2)))) - val impliesNE = synth.solver.solveSAT(Not(toValNE)) match { + val impliesNE = sctx.solver.solveSAT(Not(toValNE)) match { case (Some(false), _) => true case _ => false } @@ -38,8 +38,8 @@ class EqualitySplit(synth: Synthesizer) extends Rule("Eq. Split.", synth, 90) { val steps = candidates.map(_ match { case List(a1, a2) => - val sub1 = p.copy(c = And(Equals(Variable(a1), Variable(a2)), p.c)) - val sub2 = p.copy(c = And(Not(Equals(Variable(a1), Variable(a2))), p.c)) + val sub1 = p.copy(pc = And(Equals(Variable(a1), Variable(a2)), p.pc)) + val sub2 = p.copy(pc = And(Not(Equals(Variable(a1), Variable(a2))), p.pc)) val onSuccess: List[Solution] => Solution = { case List(s1, s2) => diff --git a/src/main/scala/leon/synthesis/rules/Ground.scala b/src/main/scala/leon/synthesis/rules/Ground.scala index ae2284294..f79af5afb 100644 --- a/src/main/scala/leon/synthesis/rules/Ground.scala +++ b/src/main/scala/leon/synthesis/rules/Ground.scala @@ -7,13 +7,13 @@ import purescala.TypeTrees._ import purescala.TreeOps._ import purescala.Extractors._ -class Ground(synth: Synthesizer) extends Rule("Ground", synth, 500) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object Ground extends Rule("Ground", 500) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { if (p.as.isEmpty) { val tpe = TupleType(p.xs.map(_.getType)) - synth.solver.solveSAT(p.phi) match { + sctx.solver.solveSAT(p.phi) match { case (Some(true), model) => RuleFastSuccess(Solution(BooleanLiteral(true), Set(), Tuple(p.xs.map(valuateWithModel(model))).setType(tpe))) case (Some(false), model) => diff --git a/src/main/scala/leon/synthesis/rules/IntegerEquation.scala b/src/main/scala/leon/synthesis/rules/IntegerEquation.scala index 1561520d5..9fc9be76c 100644 --- a/src/main/scala/leon/synthesis/rules/IntegerEquation.scala +++ b/src/main/scala/leon/synthesis/rules/IntegerEquation.scala @@ -11,8 +11,8 @@ import purescala.TypeTrees._ import purescala.Definitions._ import LinearEquations.elimVariable -class IntegerEquation(synth: Synthesizer) extends Rule("Integer Equation", synth, 600) { - def attemptToApplyOn(problem: Problem): RuleResult = if(!problem.xs.exists(_.getType == Int32Type)) RuleInapplicable else { +case object IntegerEquation extends Rule("Integer Equation", 600) { + def attemptToApplyOn(sctx: SynthesisContext, problem: Problem): RuleResult = if(!problem.xs.exists(_.getType == Int32Type)) RuleInapplicable else { val TopLevelAnds(exprs) = problem.phi @@ -51,7 +51,7 @@ class IntegerEquation(synth: Synthesizer) extends Rule("Integer Equation", synth if(normalizedEq.size == 1) { val eqPre = Equals(normalizedEq.head, IntLiteral(0)) - val newProblem = Problem(problem.as, And(eqPre, problem.c), And(allOthers), problem.xs) + val newProblem = Problem(problem.as, And(eqPre, problem.pc), And(allOthers), problem.xs) val onSuccess: List[Solution] => Solution = { case List(Solution(pre, defs, term)) => { @@ -88,7 +88,7 @@ class IntegerEquation(synth: Synthesizer) extends Rule("Integer Equation", synth val ys: List[Identifier] = problem.xs.filterNot(neqxs.contains(_)) val subproblemxs: List[Identifier] = freshxs ++ ys - val newProblem = Problem(problem.as ++ freshInputVariables, And(eqPre, problem.c), freshFormula, subproblemxs) + val newProblem = Problem(problem.as ++ freshInputVariables, And(eqPre, problem.pc), freshFormula, subproblemxs) val onSuccess: List[Solution] => Solution = { case List(Solution(pre, defs, term)) => { diff --git a/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala b/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala index d4cb134be..cf65cfffc 100644 --- a/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala +++ b/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala @@ -12,8 +12,8 @@ import purescala.Definitions._ import LinearEquations.elimVariable import leon.synthesis.Algebra.lcm -class IntegerInequalities(synth: Synthesizer) extends Rule("Integer Inequalities", synth, 600) { - def attemptToApplyOn(problem: Problem): RuleResult = { +case object IntegerInequalities extends Rule("Integer Inequalities", 600) { + def attemptToApplyOn(sctx: SynthesisContext, problem: Problem): RuleResult = { val TopLevelAnds(exprs) = problem.phi //assume that we only have inequalities @@ -168,7 +168,7 @@ class IntegerInequalities(synth: Synthesizer) extends Rule("Integer Inequalities newLowerBounds.map(lbound => LessEquals(Variable(k), Minus(b, lbound))) } ++ exprNotUsed)) val subProblemxs: List[Identifier] = quotientIds ++ otherVars - val subProblem = Problem(problem.as ++ remainderIds, problem.c, subProblemFormula, subProblemxs) + val subProblem = Problem(problem.as ++ remainderIds, problem.pc, subProblemFormula, subProblemxs) def onSuccess(sols: List[Solution]): Solution = sols match { diff --git a/src/main/scala/leon/synthesis/rules/OnePoint.scala b/src/main/scala/leon/synthesis/rules/OnePoint.scala index 50b3aa9e6..412796a98 100644 --- a/src/main/scala/leon/synthesis/rules/OnePoint.scala +++ b/src/main/scala/leon/synthesis/rules/OnePoint.scala @@ -6,8 +6,8 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -class OnePoint(synth: Synthesizer) extends Rule("One-point", synth, 300) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object OnePoint extends Rule("One-point", 300) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val TopLevelAnds(exprs) = p.phi val candidates = exprs.collect { @@ -23,7 +23,7 @@ class OnePoint(synth: Synthesizer) extends Rule("One-point", synth, 300) { val others = exprs.filter(_ != eq) val oxs = p.xs.filter(_ != x) - val newProblem = Problem(p.as, p.c, subst(x -> e, And(others)), oxs) + val newProblem = Problem(p.as, p.pc, subst(x -> e, And(others)), oxs) val onSuccess: List[Solution] => Solution = { case List(Solution(pre, defs, term)) => diff --git a/src/main/scala/leon/synthesis/rules/OptimisticGround.scala b/src/main/scala/leon/synthesis/rules/OptimisticGround.scala index 8225c7b6c..57e179ef3 100644 --- a/src/main/scala/leon/synthesis/rules/OptimisticGround.scala +++ b/src/main/scala/leon/synthesis/rules/OptimisticGround.scala @@ -7,8 +7,8 @@ import purescala.TypeTrees._ import purescala.TreeOps._ import purescala.Extractors._ -class OptimisticGround(synth: Synthesizer) extends Rule("Optimistic Ground", synth, 150) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object OptimisticGround extends Rule("Optimistic Ground", 150) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { if (!p.as.isEmpty && !p.xs.isEmpty) { val xss = p.xs.toSet val ass = p.as.toSet @@ -22,16 +22,16 @@ class OptimisticGround(synth: Synthesizer) extends Rule("Optimistic Ground", syn var predicates: Seq[Expr] = Seq() while (result.isEmpty && i < maxTries) { - val phi = And(p.c +: p.phi +: predicates) + val phi = And(p.pc +: p.phi +: predicates) //println("SOLVING " + phi + " ...") - synth.solver.solveSAT(phi) match { + sctx.solver.solveSAT(phi) match { case (Some(true), satModel) => val satXsModel = satModel.filterKeys(xss) val newPhi = valuateWithModelIn(phi, xss, satModel) //println("REFUTING " + Not(newPhi) + "...") - synth.solver.solveSAT(Not(newPhi)) match { + sctx.solver.solveSAT(Not(newPhi)) match { case (Some(true), invalidModel) => // Found as such as the xs break, refine predicates predicates = valuateWithModelIn(phi, ass, invalidModel) +: predicates diff --git a/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala b/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala index 3c0dc96b7..8adc96ba1 100644 --- a/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala +++ b/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala @@ -6,8 +6,8 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -class UnconstrainedOutput(synth: Synthesizer) extends Rule("Unconstr.Output", synth, 100) { - def attemptToApplyOn(p: Problem): RuleResult = { +case object UnconstrainedOutput extends Rule("Unconstr.Output", 100) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val unconstr = p.xs.toSet -- variablesOf(p.phi) if (!unconstr.isEmpty) { diff --git a/src/main/scala/leon/synthesis/rules/Unification.scala b/src/main/scala/leon/synthesis/rules/Unification.scala index 5315eee03..c5ee4c320 100644 --- a/src/main/scala/leon/synthesis/rules/Unification.scala +++ b/src/main/scala/leon/synthesis/rules/Unification.scala @@ -8,8 +8,8 @@ import purescala.TreeOps._ import purescala.Extractors._ object Unification { - class DecompTrivialClash(synth: Synthesizer) extends Rule("Unif Dec./Clash/Triv.", synth, 200) { - def attemptToApplyOn(p: Problem): RuleResult = { + case object DecompTrivialClash extends Rule("Unif Dec./Clash/Triv.", 200) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val TopLevelAnds(exprs) = p.phi val (toRemove, toAdd) = exprs.collect { @@ -36,8 +36,8 @@ object Unification { // This rule is probably useless; it never happens except in crafted // examples, and will be found by OptimisticGround anyway. - class OccursCheck(synth: Synthesizer) extends Rule("Unif OccursCheck", synth, 200) { - def attemptToApplyOn(p: Problem): RuleResult = { + case object OccursCheck extends Rule("Unif OccursCheck", 200) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { val TopLevelAnds(exprs) = p.phi val isImpossible = exprs.exists { diff --git a/src/main/scala/leon/synthesis/rules/UnusedInput.scala b/src/main/scala/leon/synthesis/rules/UnusedInput.scala index 18f633348..03f8aeef8 100644 --- a/src/main/scala/leon/synthesis/rules/UnusedInput.scala +++ b/src/main/scala/leon/synthesis/rules/UnusedInput.scala @@ -6,9 +6,9 @@ import purescala.Trees._ import purescala.TreeOps._ import purescala.Extractors._ -class UnusedInput(synth: Synthesizer) extends Rule("UnusedInput", synth, 100) { - def attemptToApplyOn(p: Problem): RuleResult = { - val unused = p.as.toSet -- variablesOf(p.phi) -- variablesOf(p.c) +case object UnusedInput extends Rule("UnusedInput", 100) { + def attemptToApplyOn(sctx: SynthesisContext, p: Problem): RuleResult = { + val unused = p.as.toSet -- variablesOf(p.phi) -- variablesOf(p.pc) if (!unused.isEmpty) { val sub = p.copy(as = p.as.filterNot(unused)) -- GitLab