From aa874f7b9e31206142fd12bd22c94e8fa5933968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Mayer?= <a-mikmay@microsoft.com> Date: Wed, 6 Jan 2016 16:11:46 +0100 Subject: [PATCH] Added input coverage. --- src/main/scala/leon/purescala/DefOps.scala | 27 ++--- .../disambiguation/InputCoverage.scala | 99 +++++++++++++++++++ 2 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 src/main/scala/leon/synthesis/disambiguation/InputCoverage.scala diff --git a/src/main/scala/leon/purescala/DefOps.scala b/src/main/scala/leon/purescala/DefOps.scala index 6b7bf67e0..5b70c2a35 100644 --- a/src/main/scala/leon/purescala/DefOps.scala +++ b/src/main/scala/leon/purescala/DefOps.scala @@ -97,17 +97,17 @@ object DefOps { } private def stripPrefix(off: List[String], from: List[String]): List[String] = { - val commonPrefix = (off zip from).takeWhile(p => p._1 == p._2) + val commonPrefix = (off zip from).takeWhile(p => p._1 == p._2) - val res = off.drop(commonPrefix.size) + val res = off.drop(commonPrefix.size) - if (res.isEmpty) { - if (off.isEmpty) List() - else List(off.last) - } else { - res + if (res.isEmpty) { + if (off.isEmpty) List() + else List(off.last) + } else { + res + } } - } def simplifyPath(namesOf: List[String], from: Definition, useUniqueIds: Boolean)(implicit pgm: Program) = { val pathFrom = pathFromRoot(from).dropWhile(_.isInstanceOf[Program]) @@ -356,8 +356,9 @@ object DefOps { fiMapF: (FunctionInvocation, FunDef) => Option[Expr] = defaultFiMap) : (Program, Map[Identifier, Identifier], Map[FunDef, FunDef], Map[ClassDef, ClassDef]) = { replaceDefs(p)(fdMapF, cd => None, fiMapF) - } + } + /** Replaces all function calls by an expression depending on the previous function invocation and the new mapped function */ def replaceFunCalls(e: Expr, fdMapF: FunDef => FunDef, fiMapF: (FunctionInvocation, FunDef) => Option[Expr] = defaultFiMap): Expr = { preMap { case me @ MatchExpr(scrut, cases) => @@ -606,9 +607,9 @@ object DefOps { case AsInstanceOf(e, ct) => Some(AsInstanceOf(e, tpMap(ct))) case MatchExpr(scrut, cases) => Some(MatchExpr(scrut, cases.map{ - case MatchCase(pattern, optGuard, rhs) => - MatchCase(replaceClassDefUse(pattern), optGuard, rhs) - })) + case MatchCase(pattern, optGuard, rhs) => + MatchCase(replaceClassDefUse(pattern), optGuard, rhs) + })) case fi @ FunctionInvocation(TypedFunDef(fd, tps), args) => defaultFiMap(fi, fdMap(fd)).map(_.setPos(fi)) case _ => @@ -662,7 +663,7 @@ object DefOps { p.definedFunctions.filter(f => f.id.name == after.id.name).map(fd => fd.id.name + " : " + fd) match { case Nil => case e => println("Did you mean " + e) - } + } println(Thread.currentThread().getStackTrace.map(_.toString).take(10).mkString("\n")) } diff --git a/src/main/scala/leon/synthesis/disambiguation/InputCoverage.scala b/src/main/scala/leon/synthesis/disambiguation/InputCoverage.scala new file mode 100644 index 000000000..c72416a93 --- /dev/null +++ b/src/main/scala/leon/synthesis/disambiguation/InputCoverage.scala @@ -0,0 +1,99 @@ +package leon +package synthesis.disambiguation + +import synthesis.RuleClosed +import synthesis.Solution +import evaluators.DefaultEvaluator +import purescala.Expressions._ +import purescala.ExprOps +import purescala.Constructors._ +import purescala.Extractors._ +import purescala.Types.{TypeTree, TupleType, BooleanType} +import purescala.Common.Identifier +import purescala.Definitions.{FunDef, Program} +import purescala.DefOps +import grammars.ValueGrammar +import bonsai.enumerators.MemoizedEnumerator +import solvers.Model +import solvers.ModelBuilder +import scala.collection.mutable.ListBuffer + +import leon.LeonContext + +/** + * @author Mikael + * If possible, synthesizes a set of inputs for the function so that they cover all parts of the function. + * + * @param fds The set of functions to cover + * @param fd The calling function + */ +class InputCoverage(fd: FunDef, fds: Set[FunDef])(implicit c: LeonContext, p: Program) { + var numToCoverForEachExample: Int = 1 + + /** The number of expressions is the same as the number of arguments. */ + def result(): Stream[Seq[Expr]] = { + /* Algorithm: + * 1) Consider only match/case and if/else statements. + * def f(x: Int, z: Boolean): Int = + * x match { + * case 0 | 1 => 1 + * case _ => + * if(z) x*f(x-1,!z) + * else f(x-1,!z)+f(x-2,!z) + * } + * 2) In innermost branches, replace each result by (result, bi) where bi is a boolean described later. + * def f(x: Int, z: Boolean): (Int, Boolean) = + * x match { + * case 0 | 1 => (1, b1) + * case _ => + * if(z) (x*f(x-1,!z), b2) + * else (f(x-1,!z)+f(x-2,!z), b3) + * } + * 3) If the function is recursive, recover the previous values and left-OR them with the returning bi. + * def f(x: Int, z: Boolean): (Int, Boolean) = + * x match { + * case 0 | 1 => (1, b1) + * case _ => + * if(z) { + * val (r, bf) = f(x-1,!z) + * (x*r, b2 || bf)} + * else { + * val (r, bf) = f(x-1,!z) + * val (r2, bf2) = f(x-2,!z) + * (r+r2, b3 || bf || bf2) + * } + * } + * 4) Add the post-condition + * ensuring { res => !res._2 } + * 5) Let B be the set of bi. + * For each b in B + * Set all b' in B to false except b to true + * Find a counter-example. + * yield it in the stream. + */ + + /* Change all return types to accommodate the new covering boolean */ + val changeReturnTypes = { (p: Program) => + val (program, idMap, fdMap, cdMap) = DefOps.replaceFunDefs(p)({ + (f: FunDef) => + if((fds contains f) || f == fd) { + Some(f.duplicate(returnType = TupleType(Seq(f.returnType, BooleanType)))) + } else + None + }, { + (fi: FunctionInvocation, newFd: FunDef) => + Some(TupleSelect(FunctionInvocation(newFd.typed, fi.args), 1)) + }) + (program, fdMap(fd), fds.map(fdMap)) + } + val addNewReturnVariables = { (p: Program, fd: FunDef, fds: Set[FunDef]) => + + } + + (changeReturnTypes andThen + addNewReturnVariables.tupled)(p) + + + ??? + } +} \ No newline at end of file -- GitLab