From bfd09b853b9ac62d47d89f612f08c5a11a578d7d Mon Sep 17 00:00:00 2001 From: Etienne Kneuss <ekneuss@gmail.com> Date: Tue, 17 Nov 2015 18:42:09 +0100 Subject: [PATCH] Remove dependencies on solvers --- .../scala/leon/synthesis/rules/ADTSplit.scala | 39 +++++++----- .../leon/synthesis/rules/EqualitySplit.scala | 45 +++++++------- .../synthesis/rules/InequalitySplit.scala | 62 +++++++------------ 3 files changed, 72 insertions(+), 74 deletions(-) diff --git a/src/main/scala/leon/synthesis/rules/ADTSplit.scala b/src/main/scala/leon/synthesis/rules/ADTSplit.scala index 294c6e137..7ed086087 100644 --- a/src/main/scala/leon/synthesis/rules/ADTSplit.scala +++ b/src/main/scala/leon/synthesis/rules/ADTSplit.scala @@ -11,32 +11,43 @@ import purescala.ExprOps._ import purescala.Extractors._ import purescala.Constructors._ import purescala.Definitions._ -import solvers._ case object ADTSplit extends Rule("ADT Split.") { def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = { - val solver = SimpleSolverAPI(hctx.sctx.solverFactory.withTimeout(200L)) + // We approximate knowledge of types based on facts found at the top-level + // we don't care if the variables are known to be equal or not, we just + // don't want to split on two variables for which only one split + // alternative is viable. This should be much less expensive than making + // calls to a solver for each pair. + var facts = Map[Identifier, CaseClassType]() + + def addFacts(e: Expr): Unit = e match { + case Equals(Variable(a), CaseClass(cct, _)) => facts += a -> cct + case IsInstanceOf(Variable(a), cct: CaseClassType) => facts += a -> cct + case _ => + } + + val TopLevelAnds(as) = and(p.pc, p.phi) + for (e <- as) { + addFacts(e) + } val candidates = p.as.collect { case IsTyped(id, act @ AbstractClassType(cd, tpes)) => - val optCases = for (dcd <- cd.knownDescendants.sortBy(_.id.name)) yield dcd match { + val optCases = cd.knownDescendants.sortBy(_.id.name).collect { case ccd : CaseClassDef => val cct = CaseClassType(ccd, tpes) - val toSat = and(p.pc, IsInstanceOf(Variable(id), cct)) - val isImplied = solver.solveSAT(toSat) match { - case (Some(false), _) => true - case _ => false - } - - if (!isImplied) { - Some(ccd) + if (facts contains id) { + if (cct == facts(id)) { + Seq(ccd) + } else { + Nil + } } else { - None + Seq(ccd) } - case _ => - None } val cases = optCases.flatten diff --git a/src/main/scala/leon/synthesis/rules/EqualitySplit.scala b/src/main/scala/leon/synthesis/rules/EqualitySplit.scala index bc62dbba8..132ea9f76 100644 --- a/src/main/scala/leon/synthesis/rules/EqualitySplit.scala +++ b/src/main/scala/leon/synthesis/rules/EqualitySplit.scala @@ -6,6 +6,7 @@ package rules import leon.purescala.Common.Identifier import purescala.Expressions._ +import purescala.Extractors._ import purescala.Constructors._ import solvers._ @@ -14,31 +15,31 @@ import scala.concurrent.duration._ case object EqualitySplit extends Rule("Eq. Split") { def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = { - val solver = SimpleSolverAPI(hctx.sctx.solverFactory.withTimeout(50.millis)) + // We approximate knowledge of equality based on facts found at the top-level + // we don't care if the variables are known to be equal or not, we just + // don't want to split on two variables for which only one split + // alternative is viable. This should be much less expensive than making + // calls to a solver for each pair. + var facts = Set[Set[Identifier]]() - val candidates = p.as.groupBy(_.getType).mapValues(_.combinations(2).filter { - case List(a1, a2) => - val toValEQ = implies(p.pc, Equals(Variable(a1), Variable(a2))) - - val impliesEQ = solver.solveSAT(Not(toValEQ)) match { - case (Some(false), _) => true - case _ => false - } - - if (!impliesEQ) { - val toValNE = implies(p.pc, not(Equals(Variable(a1), Variable(a2)))) + def addFacts(e: Expr): Unit = e match { + case Not(e) => addFacts(e) + case LessThan(Variable(a), Variable(b)) => facts += Set(a,b) + case LessEquals(Variable(a), Variable(b)) => facts += Set(a,b) + case GreaterThan(Variable(a), Variable(b)) => facts += Set(a,b) + case GreaterEquals(Variable(a), Variable(b)) => facts += Set(a,b) + case Equals(Variable(a), Variable(b)) => facts += Set(a,b) + case _ => + } - val impliesNE = solver.solveSAT(Not(toValNE)) match { - case (Some(false), _) => true - case _ => false - } + val TopLevelAnds(as) = and(p.pc, p.phi) + for (e <- as) { + addFacts(e) + } - !impliesNE - } else { - false - } - case _ => false - }).values.flatten + val candidates = p.as.groupBy(_.getType).mapValues{ as => + as.combinations(2).filterNot(facts contains _.toSet) + }.values.flatten candidates.flatMap { case List(a1, a2) => diff --git a/src/main/scala/leon/synthesis/rules/InequalitySplit.scala b/src/main/scala/leon/synthesis/rules/InequalitySplit.scala index 292e99de8..8925276af 100644 --- a/src/main/scala/leon/synthesis/rules/InequalitySplit.scala +++ b/src/main/scala/leon/synthesis/rules/InequalitySplit.scala @@ -7,53 +7,39 @@ package rules import purescala.Expressions._ import purescala.Types._ import purescala.Constructors._ - -import solvers._ +import purescala.Extractors._ +import purescala.Common._ import scala.concurrent.duration._ case object InequalitySplit extends Rule("Ineq. Split.") { def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = { - val solver = SimpleSolverAPI(hctx.sctx.solverFactory.withTimeout(50.millis)) + // We approximate knowledge of equality based on facts found at the top-level + // we don't care if the variables are known to be equal or not, we just + // don't want to split on two variables for which only one split + // alternative is viable. This should be much less expensive than making + // calls to a solver for each pair. + var facts = Set[Set[Identifier]]() + + def addFacts(e: Expr): Unit = e match { + case Not(e) => addFacts(e) + case LessThan(Variable(a), Variable(b)) => facts += Set(a,b) + case LessEquals(Variable(a), Variable(b)) => facts += Set(a,b) + case GreaterThan(Variable(a), Variable(b)) => facts += Set(a,b) + case GreaterEquals(Variable(a), Variable(b)) => facts += Set(a,b) + case Equals(Variable(a), Variable(b)) => facts += Set(a,b) + case _ => + } + + val TopLevelAnds(as) = and(p.pc, p.phi) + for (e <- as) { + addFacts(e) + } val argsPairs = p.as.filter(_.getType == IntegerType).combinations(2) ++ p.as.filter(_.getType == Int32Type).combinations(2) - val candidates = argsPairs.toList.filter { - case List(a1, a2) => - val toValLT = implies(p.pc, LessThan(Variable(a1), Variable(a2))) - - val impliesLT = solver.solveSAT(not(toValLT)) match { - case (Some(false), _) => true - case _ => false - } - - if (!impliesLT) { - val toValGT = implies(p.pc, GreaterThan(Variable(a1), Variable(a2))) - - val impliesGT = solver.solveSAT(not(toValGT)) match { - case (Some(false), _) => true - case _ => false - } - - if (!impliesGT) { - val toValEQ = implies(p.pc, Equals(Variable(a1), Variable(a2))) - - val impliesEQ = solver.solveSAT(not(toValEQ)) match { - case (Some(false), _) => true - case _ => false - } - - !impliesEQ - } else { - false - } - } else { - false - } - case _ => false - } - + val candidates = argsPairs.toList.filter { case List(a1, a2) => !(facts contains Set(a1, a2)) } candidates.flatMap { case List(a1, a2) => -- GitLab