Skip to content
Snippets Groups Projects
Commit 438e46ed authored by Régis Blanc's avatar Régis Blanc
Browse files

path dependent constraints

parent 74ba19c7
Branches
Tags
No related merge requests found
...@@ -3,9 +3,8 @@ import leon.Utils._ ...@@ -3,9 +3,8 @@ import leon.Utils._
object Abs { object Abs {
def abs(tab: Map[Int, Int], size: Int, j: Int): Map[Int, Int] = ({ def abs(tab: Map[Int, Int], size: Int): Map[Int, Int] = ({
require(size <= 5 && /*) require(size <= 5 && isArray(tab, size))
require(*/isArray(tab, size) && j >= 0 && j < size)
var k = 0 var k = 0
var tabres = Map.empty[Int, Int] var tabres = Map.empty[Int, Int]
(while(k < size) { (while(k < size) {
...@@ -14,9 +13,17 @@ object Abs { ...@@ -14,9 +13,17 @@ object Abs {
else else
tabres = tabres.updated(k, tab(k)) tabres = tabres.updated(k, tab(k))
k = k + 1 k = k + 1
}) invariant(k >= 0 && k <= size && (if(j < k) tabres(j) >= 0 else true)) }) invariant(isArray(tabres, k) && k >= 0 && k <= size && isPositive(tabres, k))
tabres tabres
}) ensuring(res => res(j) >= 0) }) ensuring(res => isArray(res, size) && isPositive(res, size))
def isPositive(a: Map[Int, Int], size: Int): Boolean = {
require(isArray(a, size))
def rec(i: Int): Boolean = if(i >= size) true else {
if(a(i) < 0) false else rec(i+1)
}
rec(0)
}
def isArray(a: Map[Int, Int], size: Int): Boolean = { def isArray(a: Map[Int, Int], size: Int): Boolean = {
if(size < 0) if(size < 0)
......
...@@ -2,8 +2,8 @@ import leon.Utils._ ...@@ -2,8 +2,8 @@ import leon.Utils._
object Bubble { object Bubble {
def sort(a: Map[Int, Int], size: Int, k: Int, l1: Int, l2: Int): Map[Int, Int] = ({ def sort(a: Map[Int, Int], size: Int): Map[Int, Int] = ({
require(size <= 5 && size > 0 && k < size - 1 && k >= 0 && l1 < size && l1 >= 0 && l2 < size && l2 >= 0 && isArray(a, size)) require(size <= 5 && isArray(a, size))
var i = size - 1 var i = size - 1
var j = 0 var j = 0
var sortedArray = a var sortedArray = a
...@@ -17,35 +17,49 @@ object Bubble { ...@@ -17,35 +17,49 @@ object Bubble {
} }
j = j + 1 j = j + 1
}) invariant( }) invariant(
isArray(sortedArray, size) &&
j >= 0 &&
j <= i && j <= i &&
(if(k >= i) sortedArray(k) <= sortedArray(k+1) else true) && isArray(sortedArray, size) &&
(if(l1 <= i && l2 > i) sortedArray(l1) <= sortedArray(l2) else true) partitioned(sortedArray, size, 0, i, i+1, size-1) &&
partitioned(sortedArray, size, 0, j-1, j, j) &&
sorted(sortedArray, size, i, size-1)
) )
i = i - 1 i = i - 1
}) invariant( }) invariant(
i >= 0 &&
isArray(sortedArray, size) && isArray(sortedArray, size) &&
i >= 0 && partitioned(sortedArray, size, 0, i, i+1, size-1) &&
i < size && sorted(sortedArray, size, i, size-1)
(if(k >= i) sortedArray(k) <= sortedArray(k+1) else true) &&
(if(l1 <= i && l2 > i) sortedArray(l1) <= sortedArray(l2) else true)
) )
sortedArray sortedArray
}) ensuring(res => res(k) <= res(k+1)) }) ensuring(res => sorted(res, size, 0, size-1))
//ensuring(res => sorted(res, 0, size-1))
//def sorted(a: Map[Int, Int], l: Int, u: Int): Boolean = { def sorted(a: Map[Int, Int], size: Int, l: Int, u: Int): Boolean = {
// require(isArray(a, u+1)) require(isArray(a, size) && l >= 0 && u < size && l <= u)
// var k = l var k = l
// var isSorted = true var isSorted = true
// while(k < u) { while(k <= u) {
// if(a(k) > a(k+1)) if(a(k) > a(k+1))
// isSorted = false isSorted = false
// k = k + 1 k = k + 1
// } }
// isSorted isSorted
//} }
def partitioned(a: Map[Int, Int], size: Int, l1: Int, u1: Int, l2: Int, u2: Int): Boolean = {
require(l1 >= 0 && l1 <= u1 && u1 < l2 && l2 <= u2 && u2 < size && isArray(a, size))
var i = l1
var j = l2
var isPartitionned = true
while(i <= u1) {
while(j <= u2) {
if(a(i) > a(j))
isPartitionned = false
j = j+1
}
i = i + 1
}
isPartitionned
}
def isArray(a: Map[Int, Int], size: Int): Boolean = { def isArray(a: Map[Int, Int], size: Int): Boolean = {
......
...@@ -11,10 +11,16 @@ object FunctionClosure extends Pass { ...@@ -11,10 +11,16 @@ object FunctionClosure extends Pass {
private var enclosingPreconditions: List[Expr] = Nil private var enclosingPreconditions: List[Expr] = Nil
private var pathConstraints: List[Expr] = Nil
private var newFunDefs: Map[FunDef, FunDef] = Map()
//private var
def apply(program: Program): Program = { def apply(program: Program): Program = {
newFunDefs = Map()
val funDefs = program.definedFunctions val funDefs = program.definedFunctions
funDefs.foreach(fd => { funDefs.foreach(fd => {
enclosingPreconditions = fd.precondition.toList enclosingPreconditions = fd.precondition.toList
pathConstraints = fd.precondition.toList
fd.body = Some(functionClosure(fd.getBody, fd.args.map(_.id).toSet)) fd.body = Some(functionClosure(fd.getBody, fd.args.map(_.id).toSet))
}) })
program program
...@@ -22,52 +28,64 @@ object FunctionClosure extends Pass { ...@@ -22,52 +28,64 @@ object FunctionClosure extends Pass {
private def functionClosure(expr: Expr, bindedVars: Set[Identifier]): Expr = expr match { private def functionClosure(expr: Expr, bindedVars: Set[Identifier]): Expr = expr match {
case l @ LetDef(fd, rest) => { case l @ LetDef(fd, rest) => {
val id = fd.id val id = fd.id
val rt = fd.returnType val rt = fd.returnType
val varDecl = fd.args val varDecl = fd.args
val funBody = fd.getBody val funBody = fd.getBody
val previousEnclosingPreconditions = enclosingPreconditions val precondition = fd.precondition
enclosingPreconditions = fd.precondition match { val postcondition = fd.postcondition
case Some(pre) => pre :: enclosingPreconditions
case None => enclosingPreconditions val bodyVars: Set[Identifier] = variablesOf(funBody) ++ variablesOf(precondition.getOrElse(BooleanLiteral(true)))
} val capturedVars = bodyVars.intersect(bindedVars)// this should be the variable used that are in the scope
val bodyVars: Set[Identifier] = variablesOf(funBody) val (constraints, allCapturedVars) = filterConstraints(capturedVars) //all relevant path constraints
val preconditionVars: Set[Identifier] = enclosingPreconditions.foldLeft(Set[Identifier]())((s, pre) => s ++ variablesOf(pre)) val capturedVarsWithConstraints = allCapturedVars.toSeq
val vars = bodyVars ++ preconditionVars
val capturedVars = vars.intersect(bindedVars).toSeq // this should be the variable used that are in the scope val freshVars: Map[Identifier, Identifier] = capturedVarsWithConstraints.map(v => (v, FreshIdentifier(v.name).setType(v.getType))).toMap
val freshVars: Map[Identifier, Identifier] = capturedVars.map(v => (v, FreshIdentifier(v.name).setType(v.getType))).toMap
val freshVarsExpr: Map[Expr, Expr] = freshVars.map(p => (p._1.toVariable, p._2.toVariable)) val freshVarsExpr: Map[Expr, Expr] = freshVars.map(p => (p._1.toVariable, p._2.toVariable))
val freshBody = replace(freshVarsExpr, funBody)
val extraVarDecls = freshVars.map{ case (_, v2) => VarDecl(v2, v2.getType) } val extraVarDecls = freshVars.map{ case (_, v2) => VarDecl(v2, v2.getType) }
val newVarDecls = varDecl ++ extraVarDecls val newVarDecls = varDecl ++ extraVarDecls
val newFunId = FreshIdentifier(id.name) val newFunId = FreshIdentifier(id.name)
val newFunDef = new FunDef(newFunId, rt, newVarDecls) val newFunDef = new FunDef(newFunId, rt, newVarDecls)
enclosingPreconditions = enclosingPreconditions.map(pre => replace(freshVarsExpr, pre)) //introduce the new variables name for the list of preconditions
newFunDef.precondition = enclosingPreconditions match { val freshPrecondition = precondition.map(expr => replace(freshVarsExpr, expr))
case List() => None val freshConstraints = constraints.map(expr => replace(freshVarsExpr, expr))
case precs => Some(And(precs)) newFunDef.precondition = freshConstraints match {
case List() => freshPrecondition
case precs => Some(And(freshPrecondition.getOrElse(BooleanLiteral(true)) +: precs))
} }
newFunDef.postcondition = fd.postcondition.map(expr => replace(freshVarsExpr, expr)) newFunDef.postcondition = postcondition.map(expr => replace(freshVarsExpr, expr))
def substFunInvocInDef(expr: Expr): Option[Expr] = expr match { def substFunInvocInDef(expr: Expr): Option[Expr] = expr match {
case FunctionInvocation(fd, args) if fd.id == id => Some(FunctionInvocation(newFunDef, args ++ extraVarDecls.map(_.id.toVariable))) case FunctionInvocation(fd, args) if fd.id == id => Some(FunctionInvocation(newFunDef, args ++ extraVarDecls.map(_.id.toVariable)))
case _ => None case _ => None
} }
val freshBody = replace(freshVarsExpr, funBody)
val oldPathConstraints = pathConstraints
pathConstraints = (precondition.getOrElse(BooleanLiteral(true)) :: pathConstraints).map(e => replace(freshVarsExpr, e))
val recBody = functionClosure(freshBody, bindedVars ++ newVarDecls.map(_.id)) val recBody = functionClosure(freshBody, bindedVars ++ newVarDecls.map(_.id))
pathConstraints = oldPathConstraints
val recBody2 = searchAndReplaceDFS(substFunInvocInDef)(recBody) val recBody2 = searchAndReplaceDFS(substFunInvocInDef)(recBody)
newFunDef.body = Some(recBody2) newFunDef.body = Some(recBody2)
def substFunInvocInRest(expr: Expr): Option[Expr] = expr match { def substFunInvocInRest(expr: Expr): Option[Expr] = expr match {
case FunctionInvocation(fd, args) if fd.id == id => Some(FunctionInvocation(newFunDef, args ++ capturedVars.map(_.toVariable))) case FunctionInvocation(fd, args) if fd.id == id => Some(FunctionInvocation(newFunDef, args ++ capturedVarsWithConstraints.map(_.toVariable)))
case _ => None case _ => None
} }
//need to remove the enclosing precondition before considering the rest
enclosingPreconditions = previousEnclosingPreconditions
val recRest = functionClosure(rest, bindedVars) val recRest = functionClosure(rest, bindedVars)
val recRest2 = searchAndReplaceDFS(substFunInvocInRest)(recRest) val recRest2 = searchAndReplaceDFS(substFunInvocInRest)(recRest)
LetDef(newFunDef, recRest2).setType(l.getType) LetDef(newFunDef, recRest2).setType(l.getType)
} }
//case fi @ FunctionInvocation(fd, args) => {
//}
case l @ Let(i,e,b) => { case l @ Let(i,e,b) => {
val re = functionClosure(e, bindedVars) val re = functionClosure(e, bindedVars)
pathConstraints ::= Equals(Variable(i), re)
val rb = functionClosure(b, bindedVars + i) val rb = functionClosure(b, bindedVars + i)
pathConstraints = pathConstraints.tail
Let(i, re, rb).setType(l.getType) Let(i, re, rb).setType(l.getType)
} }
case n @ NAryOperator(args, recons) => { case n @ NAryOperator(args, recons) => {
...@@ -84,44 +102,40 @@ object FunctionClosure extends Pass { ...@@ -84,44 +102,40 @@ object FunctionClosure extends Pass {
val r = functionClosure(t, bindedVars) val r = functionClosure(t, bindedVars)
recons(r).setType(u.getType) recons(r).setType(u.getType)
} }
case i @ IfExpr(t1,t2,t3) => { case i @ IfExpr(cond,then,elze) => {
val r1 = functionClosure(t1, bindedVars) val rCond = functionClosure(cond, bindedVars)
val r2 = functionClosure(t2, bindedVars) pathConstraints ::= rCond
val r3 = functionClosure(t3, bindedVars) val rThen = functionClosure(then, bindedVars)
IfExpr(r1, r2, r3).setType(i.getType) pathConstraints = pathConstraints.tail
pathConstraints ::= Not(rCond)
val rElze = functionClosure(elze, bindedVars)
pathConstraints = pathConstraints.tail
IfExpr(rCond, rThen, rElze).setType(i.getType)
} }
case m @ MatchExpr(scrut,cses) => sys.error("Will see")//MatchExpr(rec(scrut), cses.map(inCase(_))).setType(m.getType).setPosInfo(m) case m @ MatchExpr(scrut,cses) => sys.error("Will see")//MatchExpr(rec(scrut), cses.map(inCase(_))).setType(m.getType).setPosInfo(m)
case t if t.isInstanceOf[Terminal] => t case t if t.isInstanceOf[Terminal] => t
case unhandled => scala.sys.error("Non-terminal case should be handled in searchAndReplace: " + unhandled) case unhandled => scala.sys.error("Non-terminal case should be handled in searchAndReplace: " + unhandled)
} }
//def collectWithPathCondition(matcher: Expr=>Boolean, expression: Expr) : Set[(Seq[Expr],Expr)] = { //filter the list of constraints, only keeping those relevant to the set of variables
// var collected : Set[(Seq[Expr],Expr)] = Set.empty def filterConstraints(vars: Set[Identifier]): (List[Expr], Set[Identifier]) = {
var allVars = vars
// def rec(expr: Expr, path: List[Expr]) : Unit = { var newVars: Set[Identifier] = Set()
// if(matcher(expr)) { var constraints = pathConstraints
// collected = collected + ((path.reverse, expr)) var filteredConstraints: List[Expr] = Nil
// } do {
allVars ++= newVars
// expr match { newVars = Set()
// case Let(i,e,b) => { constraints = pathConstraints.filterNot(filteredConstraints.contains(_))
// rec(e, path) constraints.foreach(expr => {
// rec(b, Equals(Variable(i), e) :: path) val vs = variablesOf(expr)
// } if(!vs.intersect(allVars).isEmpty) {
// case IfExpr(cond, then, elze) => { filteredConstraints ::= expr
// rec(cond, path) newVars ++= vs.diff(allVars)
// rec(then, cond :: path) }
// rec(elze, Not(cond) :: path) })
// } } while(newVars != Set())
// case NAryOperator(args, _) => args.foreach(rec(_, path)) (filteredConstraints, allVars)
// case BinaryOperator(t1, t2, _) => rec(t1, path); rec(t2, path) }
// case UnaryOperator(t, _) => rec(t, path)
// case t : Terminal => ;
// case _ => scala.sys.error("Unhandled tree in collectWithPathCondition : " + expr)
// }
// }
// rec(expression, Nil)
// collected
//}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment