From c5f704ebc3352844de17b45707c7ace4aad989b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Sinan=20K=C3=B6ksal?= <alisinan@gmail.com> Date: Fri, 19 Nov 2010 14:32:47 +0000 Subject: [PATCH] Size equivalence, concat and reverse proofs in ListWithSize --- evaluation_results | 42 ++++++++++++++++++----------- pldi2011-testcases/LambdaEval.scala | 38 +++++++++++++++----------- testcases/ListWithSize.scala | 30 ++++++++++++++++----- 3 files changed, 72 insertions(+), 38 deletions(-) diff --git a/evaluation_results b/evaluation_results index ced6b7199..c1d60e790 100644 --- a/evaluation_results +++ b/evaluation_results @@ -2,26 +2,36 @@ testcases/ListWithSize.scala verifies: associativity of append, size -size match. (11,34) valid Z3 0.266 -size postcond. valid Z3 0.031 -content match. (16,41) valid Z3 0.002 -sizeAndContent postcond. valid Z3 0.007 -drunk match. (25,37) valid Z3 0.002 -drunk postcond. valid Z3 0.406 -funnyCons match. (31,48) valid Z3 0.005 -funnyCons postcond. valid Z3 0.154 -reverse0 match. (38,50) valid Z3 0.004 -append match. (43,51) valid Z3 0.002 -nilAppend postcond. valid induction Z3 0.004 +size match. (11,34) valid Z3 0.383 +size postcond. valid Z3 0.036 +size2 precond. (16,40) valid Z3 0.003 +size2acc precond. (21,36) valid Z3 0.005 +size2acc match. (19,8) valid Z3 0.003 +size2acc postcond. valid Z3 0.026 +sizesAreEquiv postcond. valid Z3 0.010 +content match. (30,41) valid Z3 0.004 +sizeAndContent postcond. valid Z3 0.009 +drunk match. (39,37) valid Z3 0.002 +drunk postcond. valid Z3 0.671 +funnyCons match. (45,48) valid Z3 0.007 +funnyCons postcond. valid Z3 0.263 +reverse postcond. valid Z3 0.010 +reverse0 match. (52,51) valid Z3 0.002 +reverse0 postcond. valid Z3 0.023 +append match. (57,51) valid Z3 0.002 +nilAppend postcond. valid induction Z3 0.003 nilAppend postcond. valid induction Z3 0.003 appendFold postcond. valid Z3 0.006 appendAssoc postcond. valid induction Z3 0.005 -appendAssoc postcond. valid induction Z3 0.006 +appendAssoc postcond. valid induction Z3 0.007 sizeAppend postcond. valid induction Z3 0.006 -sizeAppend postcond. valid induction Z3 0.011 -concat0 match. (67,60) valid Z3 0.002 -concat0 match. (68,24) valid Z3 0.002 -property1 postcond. unknown +sizeAppend postcond. valid induction Z3 0.012 +concat postcond. valid induction Z3 0.010 +concat postcond. valid induction Z3 0.012 +concat0 match. (84,60) valid induction Z3 0.002 +concat0 match. (85,24) valid induction Z3 0.002 +concat0 postcond. valid induction Z3 0.054 +concat0 postcond. valid induction Z3 0.085 /* Appending a list 'l' to an empty list yields 'l' */ @induct diff --git a/pldi2011-testcases/LambdaEval.scala b/pldi2011-testcases/LambdaEval.scala index 9cdcb161f..889847edb 100644 --- a/pldi2011-testcases/LambdaEval.scala +++ b/pldi2011-testcases/LambdaEval.scala @@ -1,4 +1,5 @@ import scala.collection.immutable.Set +import funcheck.Annotations._ import funcheck.Utils._ object LambdaEval { @@ -55,11 +56,16 @@ object LambdaEval { case Cons(BindingPair(k, v), ss) => isValue(v) && storeHasValues(ss) } + def contains(store: List, key: Int): Boolean = store match { + case Nil() => false + case Cons(BindingPair(k, v), xs) => k == key || contains(xs, key) + } + // Find first element in list that has first component 'x' and return its // second component, analogous to List.assoc in OCaml def find(x: Int, l: List): Expr = { require( - storeElems(l).contains(x) && + contains(l, x) && storeHasValues(l) ) l match { @@ -68,18 +74,7 @@ object LambdaEval { } ensuring(res => isValue(res)) def wellFormed(store: List, expr: Expr): Boolean = expr match { - case App(l, _) => eval(store, l) match { - case StoreExprPair(_, Lam(_,_)) => true - case _ => false - } - case Fst(e) => eval(store, e) match { - case StoreExprPair(_,Pair(e1, e2)) => true - case _ => false - } - case Snd(e) => eval(store, e) match { - case StoreExprPair(_,Pair(e1, e2)) => true - case _ => false - } + case Const(_) => true case Plus(e1, e2) => wellFormed(store, e1) && wellFormed(store, e2) && (eval(store, e1) match { case StoreExprPair(_,Const(i1)) => eval(store, e2) match { @@ -88,13 +83,26 @@ object LambdaEval { } case _ => false }) - case _ => true + case Lam(x, body) => wellFormed(Cons(BindingPair(x, Const(0)), store), body) + case Pair(e1, e2) => wellFormed(store, e1) && wellFormed(store, e2) + case Var(x) => contains(store, x) + case App(l, r) => wellFormed(store, l) && wellFormed(store, r) && (eval(store, l) match { + case StoreExprPair(_, Lam(_,_)) => true + case _ => false + }) + case Fst(e) => wellFormed(store, e) && (eval(store, e) match { + case StoreExprPair(_,Pair(e1, e2)) => true + case _ => false + }) + case Snd(e) => wellFormed(store, e) && (eval(store, e) match { + case StoreExprPair(_,Pair(e1, e2)) => true + case _ => false + }) } // Evaluator def eval(store: List, expr: Expr): StoreExprPairAbs = { require( - freeVars(expr).subsetOf(storeElems(store)) && wellFormed(store, expr) && storeHasValues(store) ) diff --git a/testcases/ListWithSize.scala b/testcases/ListWithSize.scala index 684dfa806..5ee384786 100644 --- a/testcases/ListWithSize.scala +++ b/testcases/ListWithSize.scala @@ -13,6 +13,19 @@ object ListWithSize { case Cons(_, t) => 1 + size(t) }) ensuring(_ >= 0) + def size2(l: List) : Int = size2acc(l, 0) + def size2acc(l: List, acc: Int) : Int = { + require(acc >= 0) + l match { + case Nil() => acc + case Cons(_, xs) => size2acc(xs, acc+1) + } + } ensuring(res => res == size(l) + acc) + + def sizesAreEquiv(l: List) : Boolean = { + size(l) == size2(l) + } holds + def content(l: List) : Set[Int] = l match { case Nil() => Set.empty[Int] case Cons(x, xs) => Set(x) ++ content(xs) @@ -34,11 +47,11 @@ object ListWithSize { }) ensuring(size(_) > 0) // proved with unrolling=2 - def reverse(l: List) : List = reverse0(l, Nil()) // ensuring(content(_) == content(l)) - def reverse0(l1: List, l2: List) : List = l1 match { + def reverse(l: List) : List = reverse0(l, Nil()) ensuring(content(_) == content(l)) + def reverse0(l1: List, l2: List) : List = (l1 match { case Nil() => l2 case Cons(x, xs) => reverse0(xs, Cons(x, l2)) - } + }) ensuring(content(_) == content(l1) ++ content(l2)) def append(l1 : List, l2 : List) : List = (l1 match { case Nil() => l2 @@ -62,8 +75,11 @@ object ListWithSize { (size(append(l1, l2)) == size(l1) + size(l2)) holds // proved with unrolling=4 - def concat(l1: List, l2: List) : List = concat0(l1, l2, Nil()) - // ensuring(content(_) == content(l1) ++ content(l2)) + @induct + def concat(l1: List, l2: List) : List = + concat0(l1, l2, Nil()) ensuring(content(_) == content(l1) ++ content(l2)) + + @induct def concat0(l1: List, l2: List, l3: List) : List = (l1 match { case Nil() => l2 match { case Nil() => reverse(l3) @@ -72,10 +88,10 @@ object ListWithSize { } } case Cons(x, xs) => concat0(xs, l2, Cons(x, l3)) - }) //ensuring(content(_) == content(l1) ++ content(l2) ++ content(l3)) + }) ensuring(content(_) == content(l1) ++ content(l2) ++ content(l3)) // proved with unrolling=2 ??? def property1(l1: List, l2: List) : Boolean = { reverse(concat(l1, l2)) == concat(reverse(l2), reverse(l1)) - } ensuring(_ == true) + } // ensuring(_ == true) } -- GitLab