diff --git a/testcases/web/demos/01_Compiler.scala b/testcases/web/demos/01_Compiler.scala new file mode 100644 index 0000000000000000000000000000000000000000..87b06b2c61473eb5c4172785ffc956a461d5fc04 --- /dev/null +++ b/testcases/web/demos/01_Compiler.scala @@ -0,0 +1,201 @@ +import leon.lang._ +import leon.annotation._ +import leon.collection._ +import leon._ + +object Tokens { + abstract class Token + case object TPlus extends Token + case object TTimes extends Token + case object TLT extends Token + case object TIf extends Token + case object TElse extends Token + case object TLAnd extends Token + case object TLOr extends Token + case object TLeftBrace extends Token + case object TRightBrace extends Token + case object TLeftPar extends Token + case object TRightPar extends Token + case class TInt(v: BigInt) extends Token + case class TId(name: BigInt) extends Token // All variables are : BigInt +} + +object Trees { + abstract class Expr + case class Times(lhs: Expr, rhs: Expr) extends Expr + case class Plus(lhs: Expr, rhs: Expr) extends Expr + case class And(lhs: Expr, rhs: Expr) extends Expr + case class Or(lhs: Expr, rhs: Expr) extends Expr + case class Var(id: BigInt) extends Expr + case class IntLiteral(v: BigInt) extends Expr + case class LessThan(lhs: Expr, rhs: Expr) extends Expr + case class Ite(cond: Expr, thn: Expr, els: Expr) extends Expr +} + +object Types { + abstract class Type + case object IntType extends Type + case object BoolType extends Type +} + +object Parser { + import Tokens._ + import Trees._ + + def parsePhrase(ts: List[Token]): Option[Expr] = { + parseGoal(ts) match { + case Some((res, Nil())) => Some(res) + case _ => None() + } + } + + def parseGoal(ts: List[Token]): Option[(Expr, List[Token])] = { + parseOr(ts) + } + + def parseOr(ts: List[Token]): Option[(Expr, List[Token])] = { + parseAnd(ts) match { + case Some((lhs, Cons(TLOr, r))) => + parseAnd(r) match { + case Some((rhs, ts2)) => Some((Or(lhs, rhs), ts2)) + case None() => None() + } + case r => r + } + } + + def parseAnd(ts: List[Token]): Option[(Expr, List[Token])] = { + parseLT(ts) match { + case Some((lhs, Cons(TLAnd, r))) => + parseLT(r) match { + case Some((rhs, ts2)) => Some((And(lhs, rhs), ts2)) + case None() => None() + } + case r => r + } + } + + def parseLT(ts: List[Token]): Option[(Expr, List[Token])] = { + parsePlus(ts) match { + case Some((lhs, Cons(TLT, r))) => + parsePlus(r) match { + case Some((rhs, ts2)) => Some((LessThan(lhs, rhs), ts2)) + case None() => None() + } + case r => r + } + } + + def parsePlus(ts: List[Token]): Option[(Expr, List[Token])] = { + parseTimes(ts) match { + case Some((lhs, Cons(TPlus, r))) => + parsePlus(r) match { + case Some((rhs, ts2)) => Some((Plus(lhs, rhs), ts2)) + case None() => None() + } + case r => r + } + } + + def parseTimes(ts: List[Token]): Option[(Expr, List[Token])] = { + parseLits(ts) match { + case Some((lhs, Cons(t, r))) if (t == TTimes) => + parseTimes(r) match { + case Some((rhs, ts2)) => Some((Plus(lhs, rhs), ts2)) + case None() => None() + } + case r => r + } + } + + def parseLits(ts: List[Token]): Option[(Expr, List[Token])] = ts match { + case Cons(TInt(v), r) => Some((IntLiteral(v), r)) + case Cons(TId(v), r) => Some((Var(v), r)) + case Cons(TLeftPar, r) => + parseGoal(r) match { + case Some((e, Cons(TRightPar, ts2))) => Some((e, ts2)) + case _ => None() + } + case Cons(TIf, Cons(TLeftPar, r)) => + parseGoal(r) match { + case Some((c, Cons(TRightPar, Cons(TLeftBrace, ts2)))) => + // Then + parseGoal(ts2) match { + case Some((th, Cons(TRightBrace, Cons(TElse, Cons(TLeftBrace, ts3))))) => + // Else + parseGoal(ts3) match { + case Some((el, Cons(TRightBrace, ts4))) => + Some((Ite(c, th, el), ts4)) + case _ => None() + } + case _ => None() + } + case _ => None() + } + case _ => None() + } +} + +object TypeChecker { + import Trees._ + import Types._ + + def typeChecks(e: Expr, exp: Option[Type]): Boolean = e match { + case Times(l, r) => (exp.getOrElse(IntType) == IntType) && typeChecks(l, Some(IntType)) && typeChecks(r, Some(IntType)) + case Plus(l, r) => (exp.getOrElse(IntType) == IntType) && typeChecks(l, Some(IntType)) && typeChecks(r, Some(IntType)) + case And(l, r) => (exp.getOrElse(BoolType) == BoolType) && typeChecks(l, Some(BoolType)) && typeChecks(r, Some(BoolType)) + case Or(l, r) => (exp.getOrElse(BoolType) == BoolType) && typeChecks(l, Some(BoolType)) && typeChecks(r, Some(BoolType)) + case LessThan(l, r) => (exp.getOrElse(BoolType) == BoolType) && typeChecks(l, Some(IntType)) && typeChecks(r, Some(IntType)) + case Ite(c, th, el) => typeChecks(c, Some(BoolType)) && typeChecks(th, exp) && typeChecks(el, exp) + case IntLiteral(_) => exp.getOrElse(IntType) == IntType + case Var(_) => exp.getOrElse(IntType) == IntType + } + + def typeChecks(e: Expr): Boolean = typeChecks(e, None()) +} + +object Simplifier { + import Trees._ + import Runtime._ + + // Constant folding + tautologies + def simplify(e: Expr)(implicit m: Map[BigInt, BigInt]): Expr = (e match { + // Special cases + case Plus(IntLiteral(a), IntLiteral(b)) => IntLiteral(a+b) + case LessThan(Var(id1), Var(id2)) if id1 == id2 => IntLiteral(0) + + // Recursion + case Times(lhs, rhs) => Times(simplify(lhs), simplify(rhs)) + case Plus(lhs, rhs) => Plus(simplify(lhs), simplify(rhs)) + case And(lhs, rhs) => And(simplify(lhs), simplify(rhs)) + case Or(lhs, rhs) => And(simplify(lhs), simplify(rhs)) + case LessThan(lhs, rhs) => LessThan(simplify(lhs), simplify(rhs)) + case Ite(cond, then, elze) => Ite(simplify(cond), simplify(then), simplify(elze)) + case _ => e + }) ensuring { + res => run(res)(m) == run(e)(m) + } + +} + +object Runtime { + import Trees._ + + def run(e: Expr)(implicit m: Map[BigInt, BigInt]): BigInt = e match { + case Times(lhs, rhs) => run(lhs) * run(rhs) + case Plus(lhs, rhs) => run(lhs) + run(rhs) + case And(lhs, rhs) => run(lhs) * run(rhs) + case Or(lhs, rhs) => if ((run(lhs) + run(rhs)) > 0) 1 else 0 + case IntLiteral(v) => v + case Var(id) => if (m contains id) m(id) else 0 + case LessThan(lhs, rhs) => if (run(lhs) < run(rhs)) 1 else 0 + case Ite(cond, then, elze) => if (run(cond) != 0) run(then) else run(elze) + } + + def test() = { + run(Plus(IntLiteral(42), Var(0)))(Map(0 -> 1)) + } +} + + + diff --git a/testcases/web/demos/02_Lists.scala b/testcases/web/demos/02_Lists.scala new file mode 100644 index 0000000000000000000000000000000000000000..f4abad115e3cc0f5e1908884f0088c3e21021010 --- /dev/null +++ b/testcases/web/demos/02_Lists.scala @@ -0,0 +1,46 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object List { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set() + case Cons(i, t) => Set(i) ++ content(t) + } + + + + def insertUnique(l: List, v: BigInt): List = (l match { + case Cons(h, t) => + if (h == v) { + l + } else { + Cons(h, insertUnique(t, v)) + } + case Nil => + Cons(v, Nil) + }) ensuring { (res: List) => + true + //content(res) == content(l) ++ Set(v) && + //size(res) >= size(l) + } + + + + + def delete(l: List, v: BigInt): List = { + choose{ (res: List) => + content(res) == content(l) -- Set(v) + } + } + +} diff --git a/testcases/web/demos/03_Splits.scala b/testcases/web/demos/03_Splits.scala new file mode 100644 index 0000000000000000000000000000000000000000..740dc34a8cf6ce680b3807779ee70fb97c3fa635 --- /dev/null +++ b/testcases/web/demos/03_Splits.scala @@ -0,0 +1,46 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object List { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def abs(i : BigInt) : BigInt = { + if(i < 0) -i else i + } ensuring(_ >= 0) + + def split1(list: List): (List,List) = { + choose { (res: (List,List)) => + (content(res._1) ++ content(res._2) == content(list)) + } + } + + def split2(list: List): (List,List) = { + choose { (res: (List,List)) => + (content(res._1) ++ content(res._2) == content(list)) && + abs(size(res._1) - size(res._2)) <= 1 + } + } + + def split3(list: List): (List,List) = { + choose { (res: (List,List)) => + (content(res._1) ++ content(res._2) == content(list)) && + abs(size(res._1) - size(res._2)) <= 1 && + size(res._1)+size(res._2) == size(list) + } + } + +} + diff --git a/testcases/web/demos/04_Sort.scala b/testcases/web/demos/04_Sort.scala new file mode 100644 index 0000000000000000000000000000000000000000..a53a8987055fe802e75aaadd602589ab47d074fd --- /dev/null +++ b/testcases/web/demos/04_Sort.scala @@ -0,0 +1,77 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ +object Sort { +/* + def sort2(x : BigInt, y : BigInt) = choose{(res: (BigInt,BigInt)) => + Set(x,y) == Set(res._1, res._2) && res._1 <= res._2 + } +*/ + +/* + sealed abstract class List + case object Nil extends List + case class Cons(head: BigInt, tail: List) extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(x, rest) => x + size(rest) + }) +*/ + // ensuring(res => res > 0) + + // def s1 = size(Cons(10, Cons(1000, Nil))) + +/* + def content(l: List): Set[BigInt] = l match { + case Nil => Set() + case Cons(i, t) => Set(i) ++ content(t) + } +*/ + +/* + def isSorted(l : List) : Boolean = l match { + case Nil => true + case Cons(_,Nil) => true + case Cons(x1, Cons(x2, rest)) => + x1 < x2 && isSorted(Cons(x2,rest)) + } +*/ + //def t1 = isSorted(Cons(10, Cons(20, Nil))) + //def t2 = isSorted(Cons(15, Cons(15, Nil))) + +/* + def sInsert(x : BigInt, l : List) : List = { + require(isSorted(l)) + l match { + case Nil => Cons(x, Nil) + case Cons(e, rest) if (x == e) => l + case Cons(e, rest) if (x < e) => Cons(x, Cons(e,rest)) + case Cons(e, rest) if (x > e) => Cons(e, sInsert(x,rest)) + } + } ensuring {(res:List) => + isSorted(res) && content(res) == content(l) ++ Set(x)} + + // size(res) == size(l) + 1 +*/ + +/* + def insertMagic(x: BigInt, l: List): List = { + require(isSorted(l)) + choose {(res: List) => + isSorted(res) && content(res) == content(l) ++ Set[BigInt](x) + } + } +*/ + + //def m = insertMagic(17, Cons(10, Cons(15, Cons(20, Nil)))) + +/* + def sortMagic(l : List) = choose{(res:List) => + isSorted(res) && content(res) == content(l) + } +*/ + + // def mm = sortMagic(Cons(20, Cons(5, Cons(50, Cons(2, Nil))))) + +} diff --git a/testcases/web/demos/05_OpenDays.scala b/testcases/web/demos/05_OpenDays.scala new file mode 100644 index 0000000000000000000000000000000000000000..9314e4b7585aa19fd66c4f736f81db05b9f3ee76 --- /dev/null +++ b/testcases/web/demos/05_OpenDays.scala @@ -0,0 +1,74 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object EpflOpenDays { + + sealed abstract class Liste + case object Vide extends Liste + case class Elem(e: BigInt, reste: Liste) extends Liste + + def taille(l: Liste): BigInt = (l match { + case Vide => 0 + case Elem(x, reste) => x + taille(reste) + }) + + //def s0 = taille(Elem(10, Elem(1000, Vide))) + + //ensuring(res => res >= 0) + + //def s1 = taille(Elem(10, Elem(1000, Vide))) + + def contenu(l: Liste): Set[BigInt] = l match { + case Vide => Set() + case Elem(e, reste) => Set(e) ++ contenu(reste) + } + +/* + def estTriée(l: Liste): Boolean = l match { + case Vide => true + case Elem(_, Vide) => true + case Elem(e1, Elem(e2, reste)) => + e1 < e2 && estTriée(Elem(e2, reste)) + } +*/ + + //def t1 = estTriée(Elem(10, Elem(14, Elem(20, Elem(25, Vide))))) + //def t2 = estTriée(Elem(10, Elem(14, Elem(1, Elem(2, Vide))))) + +/* + def insertion(x: BigInt, l: Liste): Liste = { + require(estTriée(l)) + l match { + case Vide => Elem(x, Vide) + case Elem(e, reste) if (x == e) => l + case Elem(e, reste) if (x < e) => Elem(x, Elem(e,reste)) + case Elem(e, reste) if (x > e) => Elem(e, insertion(x, reste)) + } + } ensuring { (res: Liste) => + estTriée(res) && + contenu(res) == contenu(l) ++ Set(x) + } +*/ +/* + def insertionMagique(x: BigInt, l: Liste): Liste = { + require(estTriée(l)) + choose { (res: Liste) => + estTriée(res) && + contenu(res) == contenu(l) ++ Set(x) + } + } +*/ + + //def m1 = insertionMagique(17, Elem(10, Elem(14, Elem(20, Elem(25, Vide))))) + +/* + def trier(l: Liste) = choose{ (res: Liste) => + estTriée(res) && contenu(res) == contenu(l) + } +*/ + + //def mm = trier(Elem(10, Elem(14, Elem(1, Elem(2, Vide))))) + +} + diff --git a/testcases/web/demos/05_OpenDays1.scala b/testcases/web/demos/05_OpenDays1.scala new file mode 100644 index 0000000000000000000000000000000000000000..6a08b6138710efc005e6127cf0d72cea1dbf44ce --- /dev/null +++ b/testcases/web/demos/05_OpenDays1.scala @@ -0,0 +1,24 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object EpflOpenDays { + + def max3(a: BigInt, b: BigInt, c: BigInt): BigInt = { + if (a > b) { + if (c > a) { + c + } else { + a + } + } else { + if (c > b) { + c + } else { + a + } + } + } ensuring { + res => res >= a && res >= b && res >= c + } +} diff --git a/testcases/web/demos/05_OpenDays2.scala b/testcases/web/demos/05_OpenDays2.scala new file mode 100644 index 0000000000000000000000000000000000000000..fe99ebb2c17e0473f0cec12c1b020dec4219f8d7 --- /dev/null +++ b/testcases/web/demos/05_OpenDays2.scala @@ -0,0 +1,83 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object EpflOpenDays { + @library + sealed abstract class Piece { + def valeur = this match { + case Cent5 => 5 + case Cent10 => 10 + case Cent20 => 20 + case Cent50 => 50 + case Fr1 => 100 + case Fr2 => 200 + case Fr5 => 500 + case Bi10 => 1000 + case Bi20 => 2000 + case Bi50 => 5000 + case Bi100 => 10000 + case Bi200 => 20000 + case Bi1000 => 100000 + } + + } + case object Cent5 extends Piece + case object Cent10 extends Piece + case object Cent20 extends Piece + case object Cent50 extends Piece + case object Fr1 extends Piece + case object Fr2 extends Piece + case object Fr5 extends Piece + case object Bi10 extends Piece + case object Bi20 extends Piece + case object Bi50 extends Piece + case object Bi100 extends Piece + case object Bi200 extends Piece + case object Bi1000 extends Piece + + + @library + sealed abstract class Liste { + def somme: BigInt = { + this match { + case Vide => 0 + case Elem(p, reste) => p.valeur + reste.somme + } + } ensuring { _ >= 0 } + } + case object Vide extends Liste + case class Elem(e: Piece, reste: Liste) extends Liste + + def pieceMax(v: BigInt): Piece = { + require(v > 0 && v%5 == 0) + if (v >= Bi1000.valeur) Bi1000 + else if (v >= Bi200.valeur ) Bi200 + else if (v >= Bi100.valeur ) Bi100 + else if (v >= Bi50.valeur ) Bi50 + else if (v >= Bi20.valeur ) Bi100 + else if (v >= Bi10.valeur ) Bi10 + else if (v >= Fr5.valeur ) Fr5 + else if (v >= Fr2.valeur ) Fr2 + else if (v >= Fr1.valeur ) Fr1 + else if (v >= Cent50.valeur ) Cent50 + else if (v >= Cent20.valeur ) Cent20 + else if (v >= Cent10.valeur ) Cent10 + else Cent5 + } ensuring { _.valeur <= v } + + def pieces(v: BigInt): Liste = { + require(v >= 0 && v%5 == 0) + if (v == 0) { + Vide + } else { + val p = pieceMax(v) + Elem(p, pieces(v - p.valeur)) + } + } ensuring { res => + res.somme == v + } + + + def t = pieces(18440) +} diff --git a/testcases/web/sav15/01_Exercise1.scala b/testcases/web/sav15/01_Exercise1.scala new file mode 100644 index 0000000000000000000000000000000000000000..2b5e433c01dae897db69a303f59500f215232b15 --- /dev/null +++ b/testcases/web/sav15/01_Exercise1.scala @@ -0,0 +1,19 @@ +object Bank1 { + case class Acc(checking : BigInt, savings : BigInt) + + def putAside(x: BigInt, a: Acc): Acc = { + require (notRed(a) && a.checking >= x) + Acc(a.checking - x, a.savings + x) + } ensuring { + r => notRed(r) && sameTotal(a, r) + } + + + def sameTotal(a1: Acc, a2: Acc): Boolean = { + a1.checking + a1.savings == a2.checking + a2.savings + } + + def notRed(a: Acc) : Boolean = { + a.checking >= 0 && a.savings >= 0 + } +} diff --git a/testcases/web/sav15/02_Exercise2.scala b/testcases/web/sav15/02_Exercise2.scala new file mode 100644 index 0000000000000000000000000000000000000000..b67ce260367e52ded82e3986d3ab1013a5695d7e --- /dev/null +++ b/testcases/web/sav15/02_Exercise2.scala @@ -0,0 +1,37 @@ +object PropositionalLogic { + + sealed abstract class Formula + case class And(lhs: Formula, rhs: Formula) extends Formula + case class Or(lhs: Formula, rhs: Formula) extends Formula + case class Implies(lhs: Formula, rhs: Formula) extends Formula + case class Not(f: Formula) extends Formula + case class Literal(id: BigInt) extends Formula + + + def nnf(formula: Formula): Formula = (formula match { + case And(lhs, rhs) => And(nnf(lhs), nnf(rhs)) + case Or(lhs, rhs) => Or(nnf(lhs), nnf(rhs)) + case Implies(lhs, rhs) => nnf(Or(Not(lhs), rhs)) + case Not(And(lhs, rhs)) => Or(nnf(Not(lhs)), nnf(Not(rhs))) + case Not(Or(lhs, rhs)) => And(nnf(Not(lhs)), nnf(Not(rhs))) + case Not(Implies(lhs, rhs)) => And(nnf(lhs), nnf(Not(rhs))) + case Not(Not(f)) => nnf(f) + case Not(Literal(_)) => formula + case Literal(_) => formula + }) ensuring(isNNF(_)) + + def isNNF(f: Formula): Boolean = f match { + /* TODO: Implement isNNF */ + } + + // Note that matching should be exhaustive due to precondition. + def vars(f: Formula): Set[BigInt] = { + require(isNNF(f)) + f match { + case And(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Or(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Not(Literal(i)) => Set[BigInt](i) + case Literal(i) => Set[BigInt](i) + } + } +} diff --git a/testcases/web/sav15/03_Exercise3.scala b/testcases/web/sav15/03_Exercise3.scala new file mode 100644 index 0000000000000000000000000000000000000000..4dff97756cb94f21b7379c2038d9d323eb14e6aa --- /dev/null +++ b/testcases/web/sav15/03_Exercise3.scala @@ -0,0 +1,100 @@ +import leon.lang._ +import leon.annotation._ + +object ListWithSize { + sealed abstract class List[T] { + def size: BigInt = { + this match { + case Cons(h, t) => 1 + t.size + case Nil() => 0 + } + } // TODO: Add appropriate post-condition + + def sizeTailRec: BigInt = sizeTailRec0(0) + + def sizeTailRec0(acc: BigInt): BigInt = { + require(acc >= 0) + this match { + case Cons(h, t) => t.sizeTailRec0(acc + 1) + case Nil() => acc + } + } // TODO: Add appropriate post-condition + + // Verify + def zip[U](that: List[U]): List[(T, U)] = { + // TODO: Add appropriate pre-condition + this match { + case Nil() => Nil() + case Cons(h1, t1) => that match { + case Cons(h2, t2) => Cons((h1, h2), t1.zip(t2)) + } + } + } ensuring(_.size == this.size) + + + def content: Set[T] = this match { + case Nil() => Set() + case Cons(h, t) => Set(h) ++ t.content + } + + // Verify + def reverse: List[T] = { + reverse0(Nil()) + } ensuring(_.content == this.content) + + def reverse0(acc: List[T]): List[T] = (this match { + case Nil() => acc + case Cons(h, t) => t.reverse0(Cons(h, acc)) + }) // TODO: Add appropriate post-condition + + + def append(that: List[T]): List[T] = (this match { + case Nil() => that + case Cons(h, t) => Cons(h, t.append(that)) + }) ensuring(_.content == this.content ++ that.content) + + + } + case class Cons[T](head: T, tail: List[T]) extends List[T] + case class Nil[T]() extends List[T] + + + // Verify + def sizesAreEquiv[T](l: List[T]): Boolean = { + l.size == l.sizeTailRec + }.holds + + + def sizeAndContent[T](l: List[T]): Boolean = { + l.size == 0 || l.content != Set[T]() + }.holds + + def drunk[T](l: List[T]): List[T] = (l match { + case Nil() => Nil() + case Cons(x,l1) => Cons(x,Cons(x,drunk(l1))) + }) ensuring { + res => true // TODO: find postcondition + } + + + def funnyCons[T](x: T, l: List[T]): List[T] = (l match { + case Nil() => Cons(x, Nil()) + case c @ Cons(_,_) => Cons(x, c) + }) ensuring(_.size > 0) + + + @induct + def nilAppend[T](l: List[T]): Boolean = { + l.append(Nil()) == l + }.holds + + @induct + def appendAssoc[T](xs: List[T], ys: List[T], zs: List[T]) : Boolean = { + false // find predicate + }.holds + + @induct + def sizeAppend[T](l1: List[T], l2 : List[T]) : Boolean = { + (l1.append(l2).size == l1.size + l2.size) + }.holds +} diff --git a/testcases/web/sav15/04_Exercise4.scala b/testcases/web/sav15/04_Exercise4.scala new file mode 100644 index 0000000000000000000000000000000000000000..411a731137072dc0da6d8ace59620e3ab4c9c63e --- /dev/null +++ b/testcases/web/sav15/04_Exercise4.scala @@ -0,0 +1,68 @@ +import leon.annotation._ +import leon.lang._ + +object InsertionSort { + + sealed abstract class Option[T] + case class Some[T](value: T) extends Option[T] + case class None[T]() extends Option[T] + + + sealed abstract class List { + def size: BigInt = (this match { + case Nil() => 0 + case Cons(_, t) => 1 + t.size + }) + + def content: Set[BigInt] = this match { + case Nil() => Set() + case Cons(h, t) => Set(h) ++ t.content + } + + def min: Option[BigInt] = this match { + case Nil() => None() + case Cons(h, t) => t.min match { + case None() => Some(h) + case Some(m) => if(h < m) Some(h) else Some(m) + } + } + + def isSorted: Boolean = this match { + case Nil() => true + case Cons(h, Nil()) => true + case Cons(h1, t1 @ Cons(h2, t2)) => h1 <= h2 && t1.isSorted + } + + + /* Inserting element 'e' into a sorted list 'l' produces a sorted list with + * the expected content and size */ + def insert(e: BigInt): List = { + require(isSorted) + this match { + case Nil() => Cons(e, Nil()) + case Cons(h, t) => + if (h <= e) { + Cons(h, t.insert(e)) + } else { + Cons(e, this) + } + } + } + + + /* Insertion sort yields a sorted list of same size and content as the input + * list */ + def sort: List = (this match { + case Nil() => Nil() + case Cons(h, t) => t.sort.insert(h) + }) ensuring(res => res.content == this.content + && res.isSorted + && res.size == this.size + ) + + } + case class Cons(h: BigInt, t: List) extends List + case class Nil() extends List + + +} diff --git a/testcases/web/sav15/05_Exercise5.scala b/testcases/web/sav15/05_Exercise5.scala new file mode 100644 index 0000000000000000000000000000000000000000..787ab6de2f8ce304734c0c31fda5ac22695606ba --- /dev/null +++ b/testcases/web/sav15/05_Exercise5.scala @@ -0,0 +1,67 @@ +import leon.lang._ +import leon.annotation._ + +object SearchList { + sealed abstract class List[T] { + def size: BigInt = { + this match { + case Nil() => 0 + case Cons(h, t) => 1 + t.size + } + } ensuring { _ >= 0 } + + def content: Set[T] = { + this match { + case Nil() => Set() + case Cons(h, t) => Set(h) ++ t.content + } + } + + def firstPosOf(v: T): BigInt = { + this match { + case Nil() => -1 + case Cons(h, t) if h == v => 0 + case Cons(h, t) => + val p = t.firstPosOf(v) + if (p >= 0) { + p + 1 + } else { + p + } + } + } ensuring { + res => false // TODO: Ensure that if (and only if) res is non-negative, the list contains v. + + } + + def take(n: BigInt): List[T] = { + require(n >= 0) + this match { + case Nil() => Nil() + case Cons(h, t) if n == 0 => Nil() + case Cons(h, t) => Cons(h, t.take(n - 1)) + } + } ensuring { + res => res.size <= n + } + + def contains(v: T): Boolean = { + this match { + case Nil() => false + case Cons(h, _) if h == v => true + case Cons(_, t) => t.contains(v) + } + } ensuring { + res => res == (content contains v) + } + } + + case class Cons[T](h: T, t: List[T]) extends List[T] + case class Nil[T]() extends List[T] + + @induct + def wtf[T](l: List[T], v: T): Boolean = { + !((l.contains(v)) && (l.take(l.firstPosOf(v)).contains(v))) // What is this function checking? Translate to english. Can you remove the l.contains(v) part? Why? + }.holds +} + diff --git a/testcases/web/sav15/06_Exercise6.scala b/testcases/web/sav15/06_Exercise6.scala new file mode 100644 index 0000000000000000000000000000000000000000..636abaca00477c95a0b0d195690f54f49ee0d1e1 --- /dev/null +++ b/testcases/web/sav15/06_Exercise6.scala @@ -0,0 +1,104 @@ +import leon.lang._ +import leon.collection._ +import leon._ +/** + * 1) Implement the isSearchTree property that checks bounds of elements in a + * search tree. Assume that the tree is strictly sorted (no dupplicates) + * + * 2) Implement operations on Binary Search Trees as efficiently as you can. + * These operations will likely not verify, but make sure that leon does not + * find counter-examples within a reasonnable timeout (e.g. --timeout=5 ) + * + * You do not need to change the pre-/post-conditions + * + * 3) Implement toList to return a sorted list from a search tree. + */ + +object BinaryTree { + + abstract class Tree { + def content: Set[BigInt] = { + this match { + case Empty => Set() + case Node(l, v, r) => l.content ++ Set(v) ++ r.content + } + } + + def size: BigInt = { + this match { + case Empty => 0 + case Node(l, _, r) => l.size + r.size + 1 + } + } ensuring { _ >= 0 } + + + def +(x: BigInt): Tree = { + require(isBT) + this // TODO + } ensuring { + res => res.isBT && + res.content == this.content ++ Set(x) && + res.size >= this.size && + res.size <= this.size + 1 + } + + def -(x: BigInt): Tree = { + require(isBT) + this // TODO + } ensuring { + res => res.isBT && + res.content == this.content -- Set(x) && + res.size <= this.size && + res.size >= this.size - 1 + } + + def ++(that: Tree): Tree = { + require(this.isBT && that.isBT) + this // TODO + } ensuring { + res => res.isBT && res.content == this.content ++ that.content + } + + def contains(x: BigInt): Boolean = { + require(isBT) + false // TODO + } ensuring { + res => res == (content contains x) + } + + def toList: List[BigInt] = { + require(isBT) + Nil() // TODO + } ensuring { + res => res.content == this.content && isSorted(res) + } + + // Properties + + def isBT: Boolean = { + isSearchTree(None(), None()) + } + + def isSearchTree(min: Option[BigInt], max: Option[BigInt]): Boolean = { + this match { + case Empty => true + case Node(l, v, r) => + true // TODO + } + } + } + + case object Empty extends Tree + case class Node(l: Tree, v: BigInt, r: Tree) extends Tree + + + def isSorted(l: List[BigInt]): Boolean = { + l match { + case Cons(v1, t @ Cons(v2, _)) if v1 >= v2 => false + case Cons(h, t) => isSorted(t) + case Nil() => true + } + } +} + + diff --git a/testcases/web/sav15/07_Exercise7.scala b/testcases/web/sav15/07_Exercise7.scala new file mode 100644 index 0000000000000000000000000000000000000000..dab1fcb5ea47b415810d5fddf1c72cf447c4a11d --- /dev/null +++ b/testcases/web/sav15/07_Exercise7.scala @@ -0,0 +1,32 @@ +import leon.lang._ + +/** + * 1) Implement operations on rationals: addition, substraction, multiplication and division + * Ensure that the results are rationals, add necessary preconditions. + * 2) Implement rational equivalence (~). + * 3) Write lemmas that show that if a1 ~ a2, and b1 ~ b2, then (a1 <op> b1) ~ (a2 <op> b2), for each <op> + */ +object Rationals { + // Represents n/d + case class Q(n: BigInt, d: BigInt) { + + def +(that: Q):Q = this // TODO + + def -(that: Q):Q = this // TODO + + def *(that: Q):Q = this // TODO + + def /(that: Q):Q = this // TODO + + // Equivalence of two rationals + def ~(that: Q): Boolean = false // TODO + + def isRational = !(d == 0) + def nonZero = !(n == 0) + } + + def lemma1(a1: Q, a2: Q, b1: Q, b2: Q): Boolean = { + true // TODO + }.holds +} + diff --git a/testcases/web/sav15/08_Exercise8.scala b/testcases/web/sav15/08_Exercise8.scala new file mode 100644 index 0000000000000000000000000000000000000000..1483670b6f5590daa43bc2cd1af9d3781155a823 --- /dev/null +++ b/testcases/web/sav15/08_Exercise8.scala @@ -0,0 +1,118 @@ +/** + * In this exercise, you will have to implement a packed representation of a set of numbers. + * This representation uses a chained list of sorted ranges to represent the stored values. + * + * [0, 10] :: [15, 15] :: Empty + * + * stores + * + * Set(0,1,2,3,4,5,6,7,8,9,10,15) + * + * You need to implement + and - that adds and deletes single elements from the set. + * Leon will not generally be able to verify everything, but it should give you + * counter-examples in case you do something wrong. + */ + +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object PackedSet { + case class Range(min: BigInt, max: BigInt) { + def size: BigInt = { + if (max >= min) max-min+1 + else 0 + } + + def content: Set[BigInt] = { + if (max == min) Set(min) + else if (max > min) Set(min) ++ Range(min+1, max).content + else Set() + } + + def contains(v: BigInt): Boolean = { + min <= v && max >= v + } + + def <(that: Range) = { + this.min < that.min + } + + def merge(that: Range): Range = { + require(this.min == that.min) + Range(min, if (this.max > that.max) this.max else that.max) + } ensuring { + res => res.content == this.content ++ that.content + } + } + + + abstract class PackedSet { + def size: BigInt = { + this match { + case Empty => 0 + case NonEmpty(r, t) => r.size + t.size + } + } + + def depth: BigInt = { + this match { + case Empty => 0 + case NonEmpty(_, t) => 1 + t.depth + } + } + + def content: Set[BigInt] = { + this match { + case Empty => Set() + case NonEmpty(r, t) => r.content ++ t.content + } + } + + def contains(v: BigInt): Boolean = { + this match { + case Empty => false + case NonEmpty(r, t) => + if (r.min > v) false + else r.contains(v) || t.contains(v) + } + } + + def isPackedSet = isSorted && isPacked + + def isSorted: Boolean = { + this match { + case NonEmpty(r1, t @ NonEmpty(r2, _)) => r1 < r2 && t.isSorted + case _ => true + } + } + + def isPacked: Boolean = { + this match { + case Empty => true + case NonEmpty(r, t) => r.size >= 1 && t.isPacked + } + } + + def +(v: BigInt): PackedSet = { + require(this.isPackedSet) + this // TODO + } ensuring { + res => res.content == this.content ++ Set(v) && + res.isPackedSet + } + + def -(v: BigInt): PackedSet = { + require(this.isPackedSet) + this // TODO + } ensuring { + res => res.content == this.content -- Set(v) && + res.isPackedSet + } + + } + case class NonEmpty(r: Range, tail: PackedSet) extends PackedSet + case object Empty extends PackedSet + + +} diff --git a/testcases/web/synthesis/01_List_Insert.scala b/testcases/web/synthesis/01_List_Insert.scala new file mode 100644 index 0000000000000000000000000000000000000000..62e91d9b92c1d87008d1192f2f9e5c68580ef1ec --- /dev/null +++ b/testcases/web/synthesis/01_List_Insert.scala @@ -0,0 +1,25 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Insert { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def insert(in1: List, v: BigInt) = { + choose { (out : List) => + content(out) == content(in1) ++ Set(v) + } + } +} diff --git a/testcases/web/synthesis/02_List_Delete.scala b/testcases/web/synthesis/02_List_Delete.scala new file mode 100644 index 0000000000000000000000000000000000000000..a548f46e2507bc4e95754bd1d512175260af1a49 --- /dev/null +++ b/testcases/web/synthesis/02_List_Delete.scala @@ -0,0 +1,25 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Delete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def delete(in1: List, v: BigInt) = { + choose { (out : List) => + content(out) == content(in1) -- Set(v) + } + } +} diff --git a/testcases/web/synthesis/03_List_Union.scala b/testcases/web/synthesis/03_List_Union.scala new file mode 100644 index 0000000000000000000000000000000000000000..0b21dc0375c63b438f810acb9bdcd4f04ef25b36 --- /dev/null +++ b/testcases/web/synthesis/03_List_Union.scala @@ -0,0 +1,25 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Union { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def union(in1: List, in2: List) = { + choose { (out : List) => + content(out) == content(in1) ++ content(in2) + } + } +} diff --git a/testcases/web/synthesis/04_List_Diff.scala b/testcases/web/synthesis/04_List_Diff.scala new file mode 100644 index 0000000000000000000000000000000000000000..0943955b170124ef788132a529ae0dd7ee9b55bb --- /dev/null +++ b/testcases/web/synthesis/04_List_Diff.scala @@ -0,0 +1,38 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Diff { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def delete(in1: List, v: BigInt): List = { + in1 match { + case Cons(h,t) => + if (h == v) { + delete(t, v) + } else { + Cons(h, delete(t, v)) + } + case Nil => + Nil + } + } ensuring { content(_) == content(in1) -- Set(v) } + + def diff(in1: List, in2: List) = { + choose { (out : List) => + content(out) == content(in1) -- content(in2) + } + } +} diff --git a/testcases/web/synthesis/05_List_Split1.scala b/testcases/web/synthesis/05_List_Split1.scala new file mode 100644 index 0000000000000000000000000000000000000000..facbda843c5a6349cc6efca052bf104ec63f7156 --- /dev/null +++ b/testcases/web/synthesis/05_List_Split1.scala @@ -0,0 +1,30 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object List { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def abs(i: BigInt) : BigInt = { + if(i < 0) -i else i + } ensuring(_ >= 0) + + def split(list: List): (List, List) = { + choose { (res: (List, List)) => + (content(res._1) ++ content(res._2) == content(list)) + } + } + +} diff --git a/testcases/web/synthesis/06_List_Split2.scala b/testcases/web/synthesis/06_List_Split2.scala new file mode 100644 index 0000000000000000000000000000000000000000..38c07caf52566eb6f599e2557900b1ed83a53c37 --- /dev/null +++ b/testcases/web/synthesis/06_List_Split2.scala @@ -0,0 +1,31 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object List { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def abs(i: BigInt) : BigInt = { + if(i < 0) -i else i + } ensuring(_ >= 0) + + def split(list: List): (List, List) = { + choose { (res : (List, List)) => + (content(res._1) ++ content(res._2) == content(list)) && + (abs(size(res._1) - size(res._2)) <= 1) + } + } + +} diff --git a/testcases/web/synthesis/07_List_Split3.scala b/testcases/web/synthesis/07_List_Split3.scala new file mode 100644 index 0000000000000000000000000000000000000000..15c74190e1839abb484b375b28fea1582d8d58ea --- /dev/null +++ b/testcases/web/synthesis/07_List_Split3.scala @@ -0,0 +1,36 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object List { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def abs(i: BigInt): BigInt = { + if(i < 0) -i else i + } ensuring(_ >= 0) + + def tcons(h1: BigInt, h2: BigInt, tl: (List, List)) = { + (Cons(h1, tl._1), Cons(h2, tl._2)) + } + + def split(list : List): (List,List) = { + choose { (res: (List,List)) => + (content(res._1) ++ content(res._2) == content(list)) && + (abs(size(res._1) - size(res._2)) <= 1) && + (size(res._1) + size(res._2) == size(list)) + } + } + +} diff --git a/testcases/web/synthesis/09_SortedList_Insert1.scala b/testcases/web/synthesis/09_SortedList_Insert1.scala new file mode 100644 index 0000000000000000000000000000000000000000..affc5b45512a0383b49d11ca2c008df3d28b8d06 --- /dev/null +++ b/testcases/web/synthesis/09_SortedList_Insert1.scala @@ -0,0 +1,34 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Complete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def isSorted(list : List) : Boolean = list match { + case Nil => true + case Cons(_, Nil) => true + case Cons(x1, Cons(x2, _)) if(x1 > x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def insert(in1: List, v: BigInt) = { + require(isSorted(in1)) + choose { (out: List) => + (content(out) == content(in1) ++ Set(v)) && isSorted(out) + } + } + +} diff --git a/testcases/web/synthesis/10_SortedList_Insert2.scala b/testcases/web/synthesis/10_SortedList_Insert2.scala new file mode 100644 index 0000000000000000000000000000000000000000..e44eac286849ac69c19991168398ffad67726f5d --- /dev/null +++ b/testcases/web/synthesis/10_SortedList_Insert2.scala @@ -0,0 +1,34 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Complete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def isSorted(list : List) : Boolean = list match { + case Nil => true + case Cons(_, Nil) => true + case Cons(x1, Cons(x2, _)) if(x1 > x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def insert(in1: List, v: BigInt) = { + require(isSorted(in1)) + choose { (out: List) => + (content(out) == content(in1) ++ Set(v)) && isSorted(out) && size(out) == size(in1) + 1 + } + } + +} diff --git a/testcases/web/synthesis/11_SortedList_Delete.scala b/testcases/web/synthesis/11_SortedList_Delete.scala new file mode 100644 index 0000000000000000000000000000000000000000..31305ca094ec78fa6896985fad04729879839baf --- /dev/null +++ b/testcases/web/synthesis/11_SortedList_Delete.scala @@ -0,0 +1,33 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Complete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def isSorted(list : List) : Boolean = list match { + case Nil => true + case Cons(_, Nil) => true + case Cons(x1, Cons(x2, _)) if(x1 > x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def delete(in1: List, v: BigInt) = { + require(isSorted(in1)) + choose { (out: List) => + (content(out) == content(in1) -- Set(v)) && isSorted(out) + } + } +} diff --git a/testcases/web/synthesis/12_SortedList_Diff.scala b/testcases/web/synthesis/12_SortedList_Diff.scala new file mode 100644 index 0000000000000000000000000000000000000000..9e4e32baeebb42ca25bd4dfec41e7b0303c80f53 --- /dev/null +++ b/testcases/web/synthesis/12_SortedList_Diff.scala @@ -0,0 +1,50 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Complete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def isSorted(list : List) : Boolean = list match { + case Nil => true + case Cons(_, Nil) => true + case Cons(x1, Cons(x2, _)) if(x1 > x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def delete(in1: List, v: BigInt): List = { + require(isSorted(in1)) + in1 match { + case Cons(h,t) => + if (h < v) { + Cons(h, delete(t, v)) + } else if (h == v) { + delete(t, v) + } else { + in1 + } + case Nil => + Nil + } + } ensuring { res => content(res) == content(in1) -- Set(v) && isSorted(res) } + + def diff(in1: List, in2: List) = { + require(isSorted(in1) && isSorted(in2)) + choose { (out: List) => + (content(out) == content(in1) -- content(in2)) && isSorted(out) + } + } + +} diff --git a/testcases/web/synthesis/13_SortedList_InsertSort.scala b/testcases/web/synthesis/13_SortedList_InsertSort.scala new file mode 100644 index 0000000000000000000000000000000000000000..8f5b78247b9877952f9a7e17cdf507f424d16b05 --- /dev/null +++ b/testcases/web/synthesis/13_SortedList_InsertSort.scala @@ -0,0 +1,51 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Complete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def isSorted(list : List) : Boolean = list match { + case Nil => true + case Cons(_, Nil) => true + case Cons(x1, Cons(x2, _)) if(x1 > x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def insert(in1: List, v: BigInt): List = { + require(isSorted(in1)) + in1 match { + case Cons(h, t) => + if (v < h) { + Cons(v, in1) + } else if (v == h) { + in1 + } else { + Cons(h, insert(t, v)) + } + case Nil => + Cons(v, Nil) + } + + } ensuring { res => (content(res) == content(in1) ++ Set(v)) && isSorted(res) } + + def sort(list: List): List = { + choose { (res: List) => + isSorted(res) && + content(list) == content(res) + } + } + +} diff --git a/testcases/web/synthesis/14_SortedList_Union.scala b/testcases/web/synthesis/14_SortedList_Union.scala new file mode 100644 index 0000000000000000000000000000000000000000..95d17bb61bb48927a2d189ccecf1b7330b4bb46e --- /dev/null +++ b/testcases/web/synthesis/14_SortedList_Union.scala @@ -0,0 +1,50 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Complete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def isSorted(list : List) : Boolean = list match { + case Nil => true + case Cons(_, Nil) => true + case Cons(x1, Cons(x2, _)) if(x1 > x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def insert(in1: List, v: BigInt): List = { + require(isSorted(in1)) + in1 match { + case Cons(h, t) => + if (v < h) { + Cons(v, in1) + } else if (v == h) { + in1 + } else { + Cons(h, insert(t, v)) + } + case Nil => + Cons(v, Nil) + } + + } ensuring { res => (content(res) == content(in1) ++ Set(v)) && isSorted(res) } + + def union(in1: List, in2: List) = { + require(isSorted(in1) && isSorted(in2)) + choose { (out: List) => + (content(out) == content(in1) ++ content(in2)) && isSorted(out) + } + } +} diff --git a/testcases/web/synthesis/15_StrictSortedList_Insert.scala b/testcases/web/synthesis/15_StrictSortedList_Insert.scala new file mode 100644 index 0000000000000000000000000000000000000000..6c7543ad3847671bfc8657dc5c99e2bbd236ed93 --- /dev/null +++ b/testcases/web/synthesis/15_StrictSortedList_Insert.scala @@ -0,0 +1,34 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Complete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def isSorted(list : List) : Boolean = list match { + case Nil => true + case Cons(_, Nil) => true + case Cons(x1, Cons(x2, _)) if(x1 >= x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def insert(in1: List, v: BigInt) = { + require(isSorted(in1)) + choose { (out : List) => + (content(out) == content(in1) ++ Set(v)) && isSorted(out) + } + } + +} diff --git a/testcases/web/synthesis/16_StrictSortedList_Delete.scala b/testcases/web/synthesis/16_StrictSortedList_Delete.scala new file mode 100644 index 0000000000000000000000000000000000000000..81827ed03b80beddf664e2b0c2beb62a43dad078 --- /dev/null +++ b/testcases/web/synthesis/16_StrictSortedList_Delete.scala @@ -0,0 +1,33 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Delete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def isSorted(list : List) : Boolean = list match { + case Nil => true + case Cons(_, Nil) => true + case Cons(x1, Cons(x2, _)) if(x1 >= x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def delete(in1: List, v: BigInt) = { + require(isSorted(in1)) + choose { (out : List) => + (content(out) == content(in1) -- Set(v)) && isSorted(out) + } + } +} diff --git a/testcases/web/synthesis/17_StrictSortedList_Union.scala b/testcases/web/synthesis/17_StrictSortedList_Union.scala new file mode 100644 index 0000000000000000000000000000000000000000..cf2fcd727323d6b5c705522f3d37b884bdfd896d --- /dev/null +++ b/testcases/web/synthesis/17_StrictSortedList_Union.scala @@ -0,0 +1,50 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Complete { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def content(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(i, t) => Set(i) ++ content(t) + } + + def isSorted(list : List) : Boolean = list match { + case Nil => true + case Cons(_, Nil) => true + case Cons(x1, Cons(x2, _)) if(x1 >= x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def insert(in1: List, v: BigInt): List = { + require(isSorted(in1)) + in1 match { + case Cons(h, t) => + if (v < h) { + Cons(v, in1) + } else if (v == h) { + in1 + } else { + Cons(h, insert(t, v)) + } + case Nil => + Cons(v, Nil) + } + + } ensuring { res => (content(res) == content(in1) ++ Set(v)) && isSorted(res) } + + def union(in1: List, in2: List) = { + require(isSorted(in1) && isSorted(in2)) + choose { (out : List) => + (content(out) == content(in1) ++ content(in2)) && isSorted(out) + } + } +} diff --git a/testcases/web/synthesis/18_UnaryNumerals_Add.scala b/testcases/web/synthesis/18_UnaryNumerals_Add.scala new file mode 100644 index 0000000000000000000000000000000000000000..694f76a15a00b1fc666b372336f3d7baaa6b77d7 --- /dev/null +++ b/testcases/web/synthesis/18_UnaryNumerals_Add.scala @@ -0,0 +1,22 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Numerals { + sealed abstract class Num + case object Z extends Num + case class S(pred: Num) extends Num + + def value(n: Num): BigInt = { + n match { + case Z => 0 + case S(p) => 1 + value(p) + } + } ensuring (_ >= 0) + + def add(x: Num, y: Num): Num = { + choose { (r: Num) => + value(r) == value(x) + value(y) + } + } +} diff --git a/testcases/web/synthesis/19_UnaryNumerals_Distinct.scala b/testcases/web/synthesis/19_UnaryNumerals_Distinct.scala new file mode 100644 index 0000000000000000000000000000000000000000..827d8d70f8f5a860447897e86f62d5f5f19d529d --- /dev/null +++ b/testcases/web/synthesis/19_UnaryNumerals_Distinct.scala @@ -0,0 +1,27 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Numerals { + sealed abstract class Num + case object Z extends Num + case class S(pred: Num) extends Num + + def value(n: Num): BigInt = { + n match { + case Z => 0 + case S(p) => 1 + value(p) + } + } ensuring (_ >= 0) + + def add(x: Num, y: Num): Num = (x match { + case Z => y + case S(p) => add(p, S(y)) + }) ensuring (value(_) == value(x) + value(y)) + + def distinct(x: Num, y: Num): Num = { + choose { (r : Num) => + r != x && r != y + } + } +} diff --git a/testcases/web/synthesis/20_UnaryNumerals_Mult.scala b/testcases/web/synthesis/20_UnaryNumerals_Mult.scala new file mode 100644 index 0000000000000000000000000000000000000000..1e58606d07d6bb78de617fa90d6129052007624b --- /dev/null +++ b/testcases/web/synthesis/20_UnaryNumerals_Mult.scala @@ -0,0 +1,27 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Numerals { + sealed abstract class Num + case object Z extends Num + case class S(pred: Num) extends Num + + def value(n: Num): BigInt = { + n match { + case Z => 0 + case S(p) => 1 + value(p) + } + } ensuring (_ >= 0) + + def add(x: Num, y: Num): Num = (x match { + case Z => y + case S(p) => add(p, S(y)) + }) ensuring (value(_) == value(x) + value(y)) + + def mult(x: Num, y: Num): Num = { + choose { (r: Num) => + value(r) == value(x) * value(y) + } + } +} diff --git a/testcases/web/synthesis/21_UnaryNumerals_Squared.scala b/testcases/web/synthesis/21_UnaryNumerals_Squared.scala new file mode 100644 index 0000000000000000000000000000000000000000..d660c247ea4c68993dd4d59a7fc0f61e913935bc --- /dev/null +++ b/testcases/web/synthesis/21_UnaryNumerals_Squared.scala @@ -0,0 +1,34 @@ +import leon.lang._ +import leon.lang.synthesis._ +import leon.annotation._ + +object Numerals { + sealed abstract class Num + case object Z extends Num + case class S(pred: Num) extends Num + + def value(n:Num) : BigInt = { + n match { + case Z => 0 + case S(p) => 1 + value(p) + } + } ensuring (_ >= 0) + + def add(x: Num, y: Num): Num = (x match { + case Z => y + case S(p) => add(p, S(y)) + }) ensuring (value(_) == value(x) + value(y)) + + def mult(x: Num, y: Num): Num = (y match { + case S(p) => + add(mult(x, p), x) + case Z => + Z + }) ensuring { value(_) == value(x) * value(y) } + + def squared(x: Num): Num = { + choose { (r: Num) => + value(r) == value(x) * value(x) + } + } +} diff --git a/testcases/web/tutorials/01_Introduction.scala b/testcases/web/tutorials/01_Introduction.scala new file mode 100644 index 0000000000000000000000000000000000000000..ffe5264617df6bdf3a019c3afd197b4b2d6f5093 --- /dev/null +++ b/testcases/web/tutorials/01_Introduction.scala @@ -0,0 +1,94 @@ +import leon.Utils._ + +/** + * Code should be contained in a single top-level object + */ +object Introduction { + + /** + * You can define Algebraic Data Types using abstract classes and case classes. + */ + abstract class Tree + case class Node(left: Tree, v: BigInt, right: Tree) extends Tree + case object Leaf extends Tree + + + /** + * You can define functions. Functions should be purely functionnal. Note + * that some imperative constructs such as 'var' or while loops will be handled. + */ + def content(t: Tree): Set[BigInt] = t match { + case Node(l, v, r) => content(l) ++ content(r) ++ Set(v) + case Leaf => Set() + } + + /** + * You can specify pre-conditions to a function using the "require" construct. + * You can use previously-defined functions in your precondition + */ + def head(t: Tree) = { + require(t != Leaf) + + val Node(_, v, _) = t + + v + } + + + /** + * The following function uses head in unsafe ways: + * + * To verify a function, click on its name and select "verify". You can also + * hit Alt+v while within the body of a function. + * + * Verify whether test1, test2 and test3 are safe. + */ + + def simpleSorted(t: Tree) = { + require(t != Leaf) + + val Node(l, v, r) = t + + (head(l) < v) && (v < head(r)) + } + + /** + * You can specify post-conditions using "ensuring". + */ + def contains(what: BigInt, t: Tree): Boolean = (t match { + case Leaf => + false + + case Node(l, v, r) => + (v == what) || contains(what, l) || contains(what, r) + + }) ensuring { res => res == (content(t) contains what) } + + /** + * Can you spot the bug in this implementation of contains? Leon can. + */ + def containsBuggy(what: BigInt, t: Tree): Boolean = (t match { + case Leaf => + false + + case Node(l, v, r) => + (v == what) || contains(what, l) || contains(v, r) + + }) ensuring { res => res == (content(t) contains what) } + + + /** + * Leon can also verify the completeness of the pattern matching: + */ + def unsafeMatch(t: Tree) = t match { + case Node(l, v, r) if v == 0 => + case Leaf => + } + + def unsafeHead(t: Tree) = { + val Node(_, v, _) = t // This translates to pattern matching + + v + } + +} diff --git a/testcases/web/tutorials/02_Ex1_Account.scala b/testcases/web/tutorials/02_Ex1_Account.scala new file mode 100644 index 0000000000000000000000000000000000000000..2001180737f5d0732fefb90ee8192d26165b6697 --- /dev/null +++ b/testcases/web/tutorials/02_Ex1_Account.scala @@ -0,0 +1,23 @@ +/* + Try to verify the toSavings function. + Use the returned counter-example to fix the precondition such that + Leon succeeds in showing the function correct. +*/ + +object Account2 { + sealed abstract class AccLike + case class Acc(checking : BigInt, savings : BigInt) extends AccLike + + def toSavings(x : BigInt, a : Acc) : Acc = { + require (notRed(a) && a.checking >= x) + Acc(a.checking - x, a.savings + x) + } ensuring (res => (notRed(res) && sameTotal(a, res))) + + + def sameTotal(a1 : Acc, a2 : Acc) : Boolean = { + a1.checking + a1.savings == a2.checking + a2.savings + } + def notRed(a : Acc) : Boolean = { + a.checking >= 0 && a.savings >= 0 + } +} diff --git a/testcases/web/tutorials/03_Ex2_Propositional_Logic.scala b/testcases/web/tutorials/03_Ex2_Propositional_Logic.scala new file mode 100644 index 0000000000000000000000000000000000000000..f5f1dd8eda867ec12166c5f461be928218d43a6a --- /dev/null +++ b/testcases/web/tutorials/03_Ex2_Propositional_Logic.scala @@ -0,0 +1,74 @@ +import leon.Utils._ +import leon.Annotations._ + + +/* + Complete the two function stubs so that the simplify and nnf functions verify. +*/ + +object PropositionalLogic { + + sealed abstract class Formula + case class And(lhs: Formula, rhs: Formula) extends Formula + case class Or(lhs: Formula, rhs: Formula) extends Formula + case class Implies(lhs: Formula, rhs: Formula) extends Formula + case class Not(f: Formula) extends Formula + case class Literal(id: BigInt) extends Formula + + + def simplify(f: Formula): Formula = (f match { + case And(lhs, rhs) => And(simplify(lhs), simplify(rhs)) + case Or(lhs, rhs) => Or(simplify(lhs), simplify(rhs)) + case Implies(lhs, rhs) => Or(Not(simplify(lhs)), simplify(rhs)) + case Not(f) => Not(simplify(f)) + case Literal(_) => f + }) ensuring(isSimplified(_)) + + def isSimplified(f: Formula): Boolean = f match { + + } + + def nnf(formula: Formula): Formula = (formula match { + case And(lhs, rhs) => And(nnf(lhs), nnf(rhs)) + case Or(lhs, rhs) => Or(nnf(lhs), nnf(rhs)) + case Implies(lhs, rhs) => Implies(nnf(lhs), nnf(rhs)) + case Not(And(lhs, rhs)) => Or(nnf(Not(lhs)), nnf(Not(rhs))) + case Not(Or(lhs, rhs)) => And(nnf(Not(lhs)), nnf(Not(rhs))) + case Not(Implies(lhs, rhs)) => And(nnf(lhs), nnf(Not(rhs))) + case Not(Not(f)) => nnf(f) + case Not(Literal(_)) => formula + case Literal(_) => formula + }) ensuring(isNNF(_)) + + def isNNF(f: Formula): Boolean = f match { + + } + + def evalLit(id : BigInt) : Boolean = (id == 42) // could be any function + def eval(f: Formula) : Boolean = f match { + case And(lhs, rhs) => eval(lhs) && eval(rhs) + case Or(lhs, rhs) => eval(lhs) || eval(rhs) + case Implies(lhs, rhs) => !eval(lhs) || eval(rhs) + case Not(f) => !eval(f) + case Literal(id) => evalLit(id) + } + + @induct + def simplifySemantics(f: Formula) : Boolean = { + eval(f) == eval(simplify(f)) + } holds + + // Note that matching is exhaustive due to precondition. + def vars(f: Formula): Set[BigInt] = { + require(isNNF(f)) + f match { + case And(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Or(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Implies(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Not(Literal(i)) => Set[BigInt](i) + case Literal(i) => Set[BigInt](i) + } + } + + +} diff --git a/testcases/web/tutorials/04_Ex3_List.scala b/testcases/web/tutorials/04_Ex3_List.scala new file mode 100644 index 0000000000000000000000000000000000000000..a49eba2cc66c1339a0d8e7a45448be801cb0ceed --- /dev/null +++ b/testcases/web/tutorials/04_Ex3_List.scala @@ -0,0 +1,123 @@ +import leon.Annotations._ +import leon.Utils._ + +/* + 1) Add pre- and postconditions, or fix the code such that the following + functions verify: + zip, sizesAreEquiv, reverse, concat0 + The postconditions on these functions give what should be checked, i.e. + they should not be changed. + + 2) find out what the function drunk does, and check provide a correct + postcondition that relates the sizes of the input list with the output list + + 3) the function appendAssoc is meant to prove that the appending lists is + associative. Formulate this predicate and make sure Leon can verify it. +*/ + +object ListWithSize { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case class Nil() extends List + + sealed abstract class IntPairList + case class IPCons(head: IntPair, tail: IntPairList) extends IntPairList + case class IPNil() extends IntPairList + + sealed abstract class IntPair + case class IP(fst: BigInt, snd: BigInt) extends IntPair + + + def size(l: List) : BigInt = (l match { + case Nil() => 0 + case Cons(_, t) => 1 + size(t) + }) + + def iplSize(l: IntPairList) : BigInt = (l match { + case IPNil() => 0 + case IPCons(_, xs) => 1 + iplSize(xs) + }) + + // Verify + def zip(l1: List, l2: List) : IntPairList = { + l1 match { + case Nil() => IPNil() + case Cons(x, xs) => l2 match { + case Cons(y, ys) => IPCons(IP(x, y), zip(xs, ys)) + } + } + } ensuring(iplSize(_) == size(l1)) + + def sizeTailRec(l: List) : BigInt = sizeTailRecAcc(l, 0) + def sizeTailRecAcc(l: List, acc: BigInt) : BigInt = { + l match { + case Nil() => acc + case Cons(_, xs) => sizeTailRecAcc(xs, acc+1) + } + } + + // Verify + def sizesAreEquiv(l: List) : Boolean = { + size(l) == sizeTailRec(l) + } holds + + def content(l: List) : Set[BigInt] = l match { + case Nil() => Set.empty[BigInt] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def sizeAndContent(l: List) : Boolean = { + size(l) == 0 || content(l) != Set.empty[BigInt] + } holds + + def drunk(l : List) : List = (l match { + case Nil() => Nil() + case Cons(x,l1) => Cons(x,Cons(x,drunk(l1))) + }) // TODO: find postcondition + + + def funnyCons(x: BigInt, l: List) : List = (l match { + case Nil() => Cons(x, Nil()) + case c @ Cons(_,_) => Cons(x, c) + }) ensuring(size(_) > 0) + + // Verify + 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)) + }) + + def append(l1 : List, l2 : List) : List = (l1 match { + case Nil() => l2 + case Cons(x,xs) => Cons(x, append(xs, l2)) + }) ensuring(content(_) == content(l1) ++ content(l2)) + + @induct + def nilAppend(l : List) : Boolean = (append(l, Nil()) == l) holds + + // TODO: find predicate + //@induct + //def appendAssoc(xs : List, ys : List, zs : List) : Boolean = + // (...) holds + + @induct + def sizeAppend(l1 : List, l2 : List) : Boolean = + (size(append(l1, l2)) == size(l1) + size(l2)) holds + + @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(l2) + case Cons(y, ys) => { + concat0(Nil(), ys, Cons(y, l3)) + } + } + case Cons(x, xs) => concat0(xs, l2, Cons(x, l3)) + }) ensuring(content(_) == content(l1) ++ content(l2) ++ content(l3)) + +} diff --git a/testcases/web/tutorials/05_Ex4_InsertionSort.scala b/testcases/web/tutorials/05_Ex4_InsertionSort.scala new file mode 100644 index 0000000000000000000000000000000000000000..4ce5d723fa283cb31b790476203d15701e67cadf --- /dev/null +++ b/testcases/web/tutorials/05_Ex4_InsertionSort.scala @@ -0,0 +1,62 @@ +import leon.Annotations._ +import leon.Utils._ + +/* + Complete the code such that the sort function verifies. +*/ + +object InsertionSort { + sealed abstract class List + case class Cons(head:BigInt,tail:List) extends List + case class Nil() extends List + + sealed abstract class OptInt + case class Some(value: BigInt) extends OptInt + case class None() extends OptInt + + def size(l : List) : BigInt = (l match { + case Nil() => 0 + case Cons(_, xs) => 1 + size(xs) + }) + + def contents(l: List): Set[BigInt] = l match { + case Nil() => Set.empty + case Cons(x,xs) => contents(xs) ++ Set(x) + } + + def min(l : List) : OptInt = l match { + case Nil() => None() + case Cons(x, xs) => min(xs) match { + case None() => Some(x) + case Some(x2) => if(x < x2) Some(x) else Some(x2) + } + } + + def isSorted(l: List): Boolean = l match { + case Nil() => true + case Cons(x, Nil()) => true + case Cons(x, Cons(y, ys)) => x <= y && isSorted(Cons(y, ys)) + } + + /* Inserting element 'e' into a sorted list 'l' produces a sorted list with + * the expected content and size */ + def sortedIns(e: BigInt, l: List): List = { + require(isSorted(l)) + l match { + case Nil() => Cons(e,Nil()) + case Cons(x,xs) => if (x <= e) Cons(x,sortedIns(e, xs)) else Cons(e, l) + } + } + + + /* Insertion sort yields a sorted list of same size and content as the input + * list */ + def sort(l: List): List = (l match { + case Nil() => Nil() + case Cons(x,xs) => sortedIns(x, sort(xs)) + }) ensuring(res => contents(res) == contents(l) + && isSorted(res) + && size(res) == size(l) + ) + +} diff --git a/testcases/web/tutorials/06_Ex5_Add.scala b/testcases/web/tutorials/06_Ex5_Add.scala new file mode 100644 index 0000000000000000000000000000000000000000..e7245480c10733d5b7148b351e815b3f0f5a9681 --- /dev/null +++ b/testcases/web/tutorials/06_Ex5_Add.scala @@ -0,0 +1,29 @@ +import leon.Utils._ + +/* VSTTE 2008 - Dafny paper */ + +/* + Add the loop invariants so that Leon can verify this function. +*/ + +object Add { + + def add(x : BigInt, y : BigInt): BigInt = ({ + var r = x + if(y < 0) { + var n = y + (while(n != 0) { + r = r - 1 + n = n + 1 + }) //invariant(...) + } else { + var n = y + (while(n != 0) { + r = r + 1 + n = n - 1 + }) //invariant(...) + } + r + }) ensuring(_ == x+y) + +} diff --git a/testcases/web/tutorials/07_Ex6_Mult.scala b/testcases/web/tutorials/07_Ex6_Mult.scala new file mode 100644 index 0000000000000000000000000000000000000000..04bbcae47f23975bbc1137e385a2d1a2d3b9687e --- /dev/null +++ b/testcases/web/tutorials/07_Ex6_Mult.scala @@ -0,0 +1,31 @@ +import leon.Utils._ + +/* VSTTE 2008 - Dafny paper */ + +/* + Add the loop invariants so that Leon can verify this function. +*/ + +object Mult { + + def mult(x : BigInt, y : BigInt): BigInt = ({ + var r = 0 + if(y < 0) { + var n = y + (while(n != 0) { + r = r - x + n = n + 1 + }) //invariant(...) + } else { + var n = y + (while(n != 0) { + r = r + x + n = n - 1 + }) //invariant(...) + } + r + }) ensuring(_ == x*y) + +} + + diff --git a/testcases/web/tutorials/08_Ex7_MaxSum.scala b/testcases/web/tutorials/08_Ex7_MaxSum.scala new file mode 100644 index 0000000000000000000000000000000000000000..272dcc56adbf1673f5c6f38891744085801d3e9b --- /dev/null +++ b/testcases/web/tutorials/08_Ex7_MaxSum.scala @@ -0,0 +1,43 @@ +import leon.Utils._ + +/* VSTTE 2010 challenge 1 */ + +/* + Find the loop invariant. +*/ + + +object MaxSum { + + def maxSum(a: Array[BigInt]): (BigInt, BigInt) = ({ + require(a.length >= 0 && isPositive(a)) + var sum = 0 + var max = 0 + var i = 0 + (while(i < a.length) { + if(max < a(i)) + max = a(i) + sum = sum + a(i) + i = i + 1 + }) //invariant (...) + (sum, max) + }) ensuring(res => res._1 <= a.length * res._2) + + + def isPositive(a: Array[BigInt]): Boolean = { + require(a.length >= 0) + def rec(i: BigInt): Boolean = { + require(i >= 0) + if(i >= a.length) + true + else { + if(a(i) < 0) + false + else + rec(i+1) + } + } + rec(0) + } + +} diff --git a/testcases/web/tutorials/09_Ex8_ListImp.scala b/testcases/web/tutorials/09_Ex8_ListImp.scala new file mode 100644 index 0000000000000000000000000000000000000000..4c10f9be1421f7c743d979ecb6b6163fdbc40371 --- /dev/null +++ b/testcases/web/tutorials/09_Ex8_ListImp.scala @@ -0,0 +1,53 @@ +import leon.Utils._ + +/* + Find the loop invariants. +*/ + +object ListImp { + + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case class Nil() extends List + + def content(l: List) : Set[BigInt] = l match { + case Nil() => Set.empty[BigInt] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def size(l: List) : BigInt = { + var r = 0 + (while(!l.isInstanceOf[Nil]) { + r = r+1 + }) //invariant(...) + r + } ensuring(res => res >= 0) + + def reverse(l: List): List = { + var r: List = Nil() + var l2: List = l + + (while(!l2.isInstanceOf[Nil]) { + val Cons(head, tail) = l2 + l2 = tail + r = Cons(head, r) + }) //invariant(...) + + r + } ensuring(res => content(res) == content(l)) + + def append(l1 : List, l2 : List) : List = { + var r: List = l2 + var tmp: List = reverse(l1) + + (while(!tmp.isInstanceOf[Nil]) { + val Cons(head, tail) = tmp + tmp = tail + r = Cons(head, r) + }) //invariant(...) + + r + } ensuring(content(_) == content(l1) ++ content(l2)) + + +} diff --git a/testcases/web/tutorials/10_Ex9_RedBlackTree.scala b/testcases/web/tutorials/10_Ex9_RedBlackTree.scala new file mode 100644 index 0000000000000000000000000000000000000000..9dd7ad92bfbcfd18fc629468cab0aa81b05baa06 --- /dev/null +++ b/testcases/web/tutorials/10_Ex9_RedBlackTree.scala @@ -0,0 +1,100 @@ +import leon.Annotations._ +import leon.Utils._ + +/* + You found an implementation of a Red-black tree and you want to verify that + the add method does the correct thing. + The only additional specification you should need is for the ins method. +*/ + +object RedBlackTree { + sealed abstract class Color + case class Red() extends Color + case class Black() extends Color + + sealed abstract class Tree + case class Empty() extends Tree + case class Node(color: Color, left: Tree, value: BigInt, right: Tree) extends Tree + + sealed abstract class OptionInt + case class Some(v : BigInt) extends OptionInt + case class None() extends OptionInt + + def content(t: Tree) : Set[BigInt] = t match { + case Empty() => Set.empty + case Node(_, l, v, r) => content(l) ++ Set(v) ++ content(r) + } + + def size(t: Tree) : BigInt = t match { + case Empty() => 0 + case Node(_, l, v, r) => size(l) + 1 + size(r) + } + + /* We consider leaves to be black by definition */ + def isBlack(t: Tree) : Boolean = t match { + case Empty() => true + case Node(Black(),_,_,_) => true + case _ => false + } + + def redNodesHaveBlackChildren(t: Tree) : Boolean = t match { + case Empty() => true + case Node(Black(), l, _, r) => redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r) + case Node(Red(), l, _, r) => isBlack(l) && isBlack(r) && redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r) + } + + def redDescHaveBlackChildren(t: Tree) : Boolean = t match { + case Empty() => true + case Node(_,l,_,r) => redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r) + } + + def blackBalanced(t : Tree) : Boolean = t match { + case Node(_,l,_,r) => blackBalanced(l) && blackBalanced(r) && blackHeight(l) == blackHeight(r) + case Empty() => true + } + + def blackHeight(t : Tree) : BigInt = t match { + case Empty() => 1 + case Node(Black(), l, _, _) => blackHeight(l) + 1 + case Node(Red(), l, _, _) => blackHeight(l) + } + + // <<insert element x into the tree t>> + def ins(x: BigInt, t: Tree): Tree = { + //require(...) + t match { + case Empty() => Node(Red(),Empty(),x,Empty()) + case Node(c,a,y,b) => + if (x < y) balance(c, ins(x, a), y, b) + else if (x == y) Node(c,a,y,b) + else balance(c,a,y,ins(x, b)) + } + } /*ensuring (res => )*/ + + def makeBlack(n: Tree): Tree = { + require(redDescHaveBlackChildren(n) && blackBalanced(n)) + n match { + case Node(Red(),l,v,r) => Node(Black(),l,v,r) + case _ => n + } + } ensuring(res => redNodesHaveBlackChildren(res) && blackBalanced(res)) + + def add(x: BigInt, t: Tree): Tree = { + require(redNodesHaveBlackChildren(t) && blackBalanced(t)) + makeBlack(ins(x, t)) + } ensuring (res => content(res) == content(t) ++ Set(x) && redNodesHaveBlackChildren(res) && blackBalanced(res)) + + + def balance(c: Color, a: Tree, x: BigInt, b: Tree): Tree = { + Node(c,a,x,b) match { + case Node(Black(),Node(Red(),Node(Red(),a,xV,b),yV,c),zV,d) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(Black(),Node(Red(),a,xV,Node(Red(),b,yV,c)),zV,d) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(Black(),a,xV,Node(Red(),Node(Red(),b,yV,c),zV,d)) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + case Node(Black(),a,xV,Node(Red(),b,yV,Node(Red(),c,zV,d))) => + Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d)) + } + } ensuring (res => content(res) == content(Node(c,a,x,b))) +} diff --git a/testcases/web/tutorials/11_Ex10_SearchLinkedList.scala b/testcases/web/tutorials/11_Ex10_SearchLinkedList.scala new file mode 100644 index 0000000000000000000000000000000000000000..f8ca2076af6f8803c986f1aaf0ef53e27fb15ea9 --- /dev/null +++ b/testcases/web/tutorials/11_Ex10_SearchLinkedList.scala @@ -0,0 +1,47 @@ +import leon.Utils._ +import leon.Annotations._ + +/* + Add the missing postcondition. +*/ + + +object SearchLinkedList { + sealed abstract class List + case class Cons(head : BigInt, tail : List) extends List + case class Nil() extends List + + def size(list : List) : BigInt = (list match { + case Nil() => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def contains(list : List, elem : BigInt) : Boolean = (list match { + case Nil() => false + case Cons(x, xs) => x == elem || contains(xs, elem) + }) + + def firstZero(list : List) : BigInt = (list match { + case Nil() => 0 + case Cons(x, xs) => if (x == 0) 0 else firstZero(xs) + 1 + }) /*ensuring (res => )*/ + + def firstZeroAtPos(list : List, pos : BigInt) : Boolean = { + list match { + case Nil() => false + case Cons(x, xs) => if (pos == 0) x == 0 else x != 0 && firstZeroAtPos(xs, pos - 1) + } + } + + def goal(list : List, i : BigInt) : Boolean = { + if(firstZero(list) == i) { + if(contains(list, 0)) { + firstZeroAtPos(list, i) + } else { + i == size(list) + } + } else { + true + } + } holds +} diff --git a/testcases/web/verification/01_Amortized_Queue.scala b/testcases/web/verification/01_Amortized_Queue.scala new file mode 100644 index 0000000000000000000000000000000000000000..e8190385a15d2bba453571671778d1e01850eeb0 --- /dev/null +++ b/testcases/web/verification/01_Amortized_Queue.scala @@ -0,0 +1,102 @@ +import leon.lang._ +import leon.annotation._ + +object AmortizedQueue { + sealed abstract class List + case class Cons(head : BigInt, tail : List) extends List + case object Nil extends List + + sealed abstract class AbsQueue + case class Queue(front : List, rear : List) extends AbsQueue + + def size(list : List) : BigInt = (list match { + case Nil => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def content(l: List) : Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def asList(queue : AbsQueue) : List = queue match { + case Queue(front, rear) => concat(front, reverse(rear)) + } + + def concat(l1 : List, l2 : List) : List = (l1 match { + case Nil => l2 + case Cons(x,xs) => Cons(x, concat(xs, l2)) + }) ensuring (res => size(res) == size(l1) + size(l2) && content(res) == content(l1) ++ content(l2)) + + def isAmortized(queue : AbsQueue) : Boolean = queue match { + case Queue(front, rear) => size(front) >= size(rear) + } + + def isEmpty(queue : AbsQueue) : Boolean = queue match { + case Queue(Nil, Nil) => true + case _ => false + } + + def reverse(l : List) : List = (l match { + case Nil => Nil + case Cons(x, xs) => concat(reverse(xs), Cons(x, Nil)) + }) ensuring (content(_) == content(l)) + + def amortizedQueue(front : List, rear : List) : AbsQueue = { + if (size(rear) <= size(front)) + Queue(front, rear) + else + Queue(concat(front, reverse(rear)), Nil) + } ensuring(isAmortized(_)) + + def enqueue(queue : AbsQueue, elem : BigInt) : AbsQueue = (queue match { + case Queue(front, rear) => amortizedQueue(front, Cons(elem, rear)) + }) ensuring(isAmortized(_)) + + def tail(queue : AbsQueue) : AbsQueue = { + require(isAmortized(queue) && !isEmpty(queue)) + queue match { + case Queue(Cons(f, fs), rear) => amortizedQueue(fs, rear) + } + } ensuring (isAmortized(_)) + + def front(queue : AbsQueue) : BigInt = { + require(isAmortized(queue) && !isEmpty(queue)) + queue match { + case Queue(Cons(f, _), _) => f + } + } + + @induct + def propFront(queue : AbsQueue, list : List, elem : BigInt) : Boolean = { + require(!isEmpty(queue) && isAmortized(queue)) + if (asList(queue) == list) { + list match { + case Cons(x, _) => front(queue) == x + } + } else + true + } holds + + def enqueueAndFront(queue : AbsQueue, elem : BigInt) : Boolean = { + if (isEmpty(queue)) + front(enqueue(queue, elem)) == elem + else + true + } holds + + def enqueueDequeueThrice(queue : AbsQueue, e1 : BigInt, e2 : BigInt, e3 : BigInt) : Boolean = { + if (isEmpty(queue)) { + val q1 = enqueue(queue, e1) + val q2 = enqueue(q1, e2) + val q3 = enqueue(q2, e3) + val e1prime = front(q3) + val q4 = tail(q3) + val e2prime = front(q4) + val q5 = tail(q4) + val e3prime = front(q5) + e1 == e1prime && e2 == e2prime && e3 == e3prime + } else + true + } holds +} diff --git a/testcases/web/verification/02_Associative_List.scala b/testcases/web/verification/02_Associative_List.scala new file mode 100644 index 0000000000000000000000000000000000000000..7dea8f3edb778457621606bb13907d6d5ac24977 --- /dev/null +++ b/testcases/web/verification/02_Associative_List.scala @@ -0,0 +1,49 @@ +import leon.lang._ +import leon.annotation._ + +object AssociativeList { + sealed abstract class KeyValuePairAbs + case class KeyValuePair(key: BigInt, value: BigInt) extends KeyValuePairAbs + + sealed abstract class List + case class Cons(head: KeyValuePairAbs, tail: List) extends List + case object Nil extends List + + sealed abstract class OptionInt + case class Some(i: BigInt) extends OptionInt + case object None extends OptionInt + + def domain(l: List): Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(KeyValuePair(k,_), xs) => Set(k) ++ domain(xs) + } + + def find(l: List, e: BigInt): OptionInt = l match { + case Nil => None + case Cons(KeyValuePair(k, v), xs) => if (k == e) Some(v) else find(xs, e) + } + + def noDuplicates(l: List): Boolean = l match { + case Nil => true + case Cons(KeyValuePair(k, v), xs) => find(xs, k) == None && noDuplicates(xs) + } + + def updateList(l1: List, l2: List): List = (l2 match { + case Nil => l1 + case Cons(x, xs) => updateList(updateElem(l1, x), xs) + }) ensuring(domain(_) == domain(l1) ++ domain(l2)) + + def updateElem(l: List, e: KeyValuePairAbs): List = (l match { + case Nil => Cons(e, Nil) + case Cons(KeyValuePair(k, v), xs) => e match { + case KeyValuePair(ek, ev) => if (ek == k) Cons(KeyValuePair(ek, ev), xs) else Cons(KeyValuePair(k, v), updateElem(xs, e)) + } + }) ensuring(res => e match { + case KeyValuePair(k, v) => domain(res) == domain(l) ++ Set[BigInt](k) + }) + + @induct + def readOverWrite(l: List, k1: BigInt, k2: BigInt, e: BigInt) : Boolean = { + find(updateElem(l, KeyValuePair(k2,e)), k1) == (if (k1 == k2) Some(e) else find(l, k1)) + } holds +} diff --git a/testcases/web/verification/03_Insertion_Sort.scala b/testcases/web/verification/03_Insertion_Sort.scala new file mode 100644 index 0000000000000000000000000000000000000000..a3a81d75338fdb5456664ce4e663101deb4cce02 --- /dev/null +++ b/testcases/web/verification/03_Insertion_Sort.scala @@ -0,0 +1,78 @@ +import leon.lang._ +import leon.annotation._ + +object InsertionSort { + sealed abstract class List + case class Cons(head:BigInt,tail:List) extends List + case object Nil extends List + + sealed abstract class OptInt + case class Some(value: BigInt) extends OptInt + case object None extends OptInt + + def size(l : List) : BigInt = (l match { + case Nil => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def contents(l: List): Set[BigInt] = l match { + case Nil => Set.empty + case Cons(x,xs) => contents(xs) ++ Set(x) + } + + def isSorted(l: List): Boolean = l match { + case Nil => true + case Cons(x, Nil) => true + case Cons(x, Cons(y, ys)) => x <= y && isSorted(Cons(y, ys)) + } + + /* Inserting element 'e' into a sorted list 'l' produces a sorted list with + * the expected content and size */ + def sortedIns(e: BigInt, l: List): List = { + require(isSorted(l)) + l match { + case Nil => Cons(e,Nil) + case Cons(x,xs) => if (x <= e) Cons(x,sortedIns(e, xs)) else Cons(e, l) + } + } ensuring(res => contents(res) == contents(l) ++ Set(e) + && isSorted(res) + && size(res) == size(l) + 1 + ) + + /* A counterexample is found when we forget to specify the precondition */ + def buggySortedIns(e: BigInt, l: List): List = { + l match { + case Nil => Cons(e,Nil) + case Cons(x,xs) => if (x <= e) Cons(x,buggySortedIns(e, xs)) else Cons(e, l) + } + } ensuring(res => contents(res) == contents(l) ++ Set(e) + && isSorted(res) + && size(res) == size(l) + 1 + ) + + /* Insertion sort yields a sorted list of same size and content as the input + * list */ + def sort(l: List): List = (l match { + case Nil => Nil + case Cons(x,xs) => sortedIns(x, sort(xs)) + }) ensuring(res => contents(res) == contents(l) + && isSorted(res) + && size(res) == size(l) + ) + + /* Merges one (unsorted) list into another, sorted, list. */ + def mergeInto(l1 : List, l2 : List) : List = { + require(isSorted(l2)) + l1 match { + case Nil => l2 + case Cons(x, xs) => mergeInto(xs, sortedIns(x, l2)) + } + } ensuring(res => contents(res) == contents(l1) ++ contents(l2) && isSorted(res)) + + def main(args: Array[String]): Unit = { + val ls: List = Cons(5, Cons(2, Cons(4, Cons(5, Cons(1, Cons(8,Nil)))))) + + println(ls) + println(sort(ls)) + } +} diff --git a/testcases/web/verification/04_List_Operations.scala b/testcases/web/verification/04_List_Operations.scala new file mode 100644 index 0000000000000000000000000000000000000000..f7e6d590c25882d51a51191547b03b3996dad8d1 --- /dev/null +++ b/testcases/web/verification/04_List_Operations.scala @@ -0,0 +1,106 @@ +import leon.lang._ +import leon.annotation._ + +object ListOperations { + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case object Nil extends List + + sealed abstract class IntPairList + case class IPCons(head: IntPair, tail: IntPairList) extends IntPairList + case object IPNil extends IntPairList + + sealed abstract class IntPair + case class IP(fst: BigInt, snd: BigInt) extends IntPair + + def size(l: List) : BigInt = (l match { + case Nil => 0 + case Cons(_, t) => 1 + size(t) + }) ensuring(res => res >= 0) + + def iplSize(l: IntPairList) : BigInt = (l match { + case IPNil => 0 + case IPCons(_, xs) => 1 + iplSize(xs) + }) ensuring(_ >= 0) + + def zip(l1: List, l2: List) : IntPairList = { + // try to comment this and see how pattern-matching becomes + // non-exhaustive and post-condition fails + require(size(l1) == size(l2)) + + l1 match { + case Nil => IPNil + case Cons(x, xs) => l2 match { + case Cons(y, ys) => IPCons(IP(x, y), zip(xs, ys)) + } + } + } ensuring(iplSize(_) == size(l1)) + + def sizeTailRec(l: List) : BigInt = sizeTailRecAcc(l, 0) + def sizeTailRecAcc(l: List, acc: BigInt) : BigInt = { + require(acc >= 0) + l match { + case Nil => acc + case Cons(_, xs) => sizeTailRecAcc(xs, acc+1) + } + } ensuring(res => res == size(l) + acc) + + def sizesAreEquiv(l: List) : Boolean = { + size(l) == sizeTailRec(l) + } holds + + def content(l: List) : Set[BigInt] = l match { + case Nil => Set.empty[BigInt] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def sizeAndContent(l: List) : Boolean = { + size(l) == 0 || content(l) != Set.empty[BigInt] + } holds + + def drunk(l : List) : List = (l match { + case Nil => Nil + case Cons(x,l1) => Cons(x,Cons(x,drunk(l1))) + }) ensuring (size(_) == 2 * size(l)) + + 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 + case Cons(x,xs) => Cons(x, append(xs, l2)) + }) ensuring(content(_) == content(l1) ++ content(l2)) + + @induct + def nilAppend(l : List) : Boolean = (append(l, Nil) == l) holds + + @induct + def appendAssoc(xs : List, ys : List, zs : List) : Boolean = + (append(append(xs, ys), zs) == append(xs, append(ys, zs))) holds + + def revAuxBroken(l1 : List, e : BigInt, l2 : List) : Boolean = { + (append(reverse(l1), Cons(e,l2)) == reverse0(l1, l2)) + } holds + + @induct + def sizeAppend(l1 : List, l2 : List) : Boolean = + (size(append(l1, l2)) == size(l1) + size(l2)) holds + + @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) + case Cons(y, ys) => { + concat0(Nil, ys, Cons(y, l3)) + } + } + case Cons(x, xs) => concat0(xs, l2, Cons(x, l3)) + }) ensuring(content(_) == content(l1) ++ content(l2) ++ content(l3)) +} diff --git a/testcases/web/verification/05_Propositional_Logic.scala b/testcases/web/verification/05_Propositional_Logic.scala new file mode 100644 index 0000000000000000000000000000000000000000..455cef7ec5201fd17edee71059dc38c9d7afa3d8 --- /dev/null +++ b/testcases/web/verification/05_Propositional_Logic.scala @@ -0,0 +1,99 @@ +import leon.lang._ +import leon.annotation._ + +object PropositionalLogic { + + sealed abstract class Formula + case class And(lhs: Formula, rhs: Formula) extends Formula + case class Or(lhs: Formula, rhs: Formula) extends Formula + case class Implies(lhs: Formula, rhs: Formula) extends Formula + case class Not(f: Formula) extends Formula + case class Literal(id: BigInt) extends Formula + + def simplify(f: Formula): Formula = (f match { + case And(lhs, rhs) => And(simplify(lhs), simplify(rhs)) + case Or(lhs, rhs) => Or(simplify(lhs), simplify(rhs)) + case Implies(lhs, rhs) => Or(Not(simplify(lhs)), simplify(rhs)) + case Not(f) => Not(simplify(f)) + case Literal(_) => f + }) ensuring(isSimplified(_)) + + def isSimplified(f: Formula): Boolean = f match { + case And(lhs, rhs) => isSimplified(lhs) && isSimplified(rhs) + case Or(lhs, rhs) => isSimplified(lhs) && isSimplified(rhs) + case Implies(_,_) => false + case Not(f) => isSimplified(f) + case Literal(_) => true + } + + def nnf(formula: Formula): Formula = (formula match { + case And(lhs, rhs) => And(nnf(lhs), nnf(rhs)) + case Or(lhs, rhs) => Or(nnf(lhs), nnf(rhs)) + case Implies(lhs, rhs) => nnf(Or(Not(lhs), rhs)) + case Not(And(lhs, rhs)) => Or(nnf(Not(lhs)), nnf(Not(rhs))) + case Not(Or(lhs, rhs)) => And(nnf(Not(lhs)), nnf(Not(rhs))) + case Not(Implies(lhs, rhs)) => And(nnf(lhs), nnf(Not(rhs))) + case Not(Not(f)) => nnf(f) + case Not(Literal(_)) => formula + case Literal(_) => formula + }) ensuring(isNNF(_)) + + def isNNF(f: Formula): Boolean = f match { + case And(lhs, rhs) => isNNF(lhs) && isNNF(rhs) + case Or(lhs, rhs) => isNNF(lhs) && isNNF(rhs) + case Implies(lhs, rhs) => false + case Not(Literal(_)) => true + case Not(_) => false + case Literal(_) => true + } + + def evalLit(id : BigInt) : Boolean = (id == 42) // could be any function + def eval(f: Formula) : Boolean = f match { + case And(lhs, rhs) => eval(lhs) && eval(rhs) + case Or(lhs, rhs) => eval(lhs) || eval(rhs) + case Implies(lhs, rhs) => !eval(lhs) || eval(rhs) + case Not(f) => !eval(f) + case Literal(id) => evalLit(id) + } + + @induct + def simplifySemantics(f: Formula) : Boolean = { + eval(f) == eval(simplify(f)) + } holds + + // Note that matching is exhaustive due to precondition. + def vars(f: Formula): Set[BigInt] = { + require(isNNF(f)) + f match { + case And(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Or(lhs, rhs) => vars(lhs) ++ vars(rhs) + case Not(Literal(i)) => Set[BigInt](i) + case Literal(i) => Set[BigInt](i) + } + } + + def fv(f : Formula) = { vars(nnf(f)) } + + @induct + def wrongCommutative(f: Formula) : Boolean = { + nnf(simplify(f)) == simplify(nnf(f)) + } holds + + @induct + def simplifyPreservesNNF(f: Formula) : Boolean = { + require(isNNF(f)) + isNNF(simplify(f)) + } holds + + @induct + def nnfIsStable(f: Formula) : Boolean = { + require(isNNF(f)) + nnf(f) == f + } holds + + @induct + def simplifyIsStable(f: Formula) : Boolean = { + require(isSimplified(f)) + simplify(f) == f + } holds +} diff --git a/testcases/web/verification/06_Red-Black_Tree.scala b/testcases/web/verification/06_Red-Black_Tree.scala new file mode 100644 index 0000000000000000000000000000000000000000..3adc6c8cb60135e6465d1f13da87a8baca24ce61 --- /dev/null +++ b/testcases/web/verification/06_Red-Black_Tree.scala @@ -0,0 +1,115 @@ +import leon.lang._ +import leon.annotation._ + +object RedBlackTree { + sealed abstract class Color + case object Red extends Color + case object Black extends Color + + sealed abstract class Tree + case object Empty extends Tree + case class Node(color: Color, left: Tree, value: BigInt, right: Tree) extends Tree + + sealed abstract class OptionInt + case class Some(v : BigInt) extends OptionInt + case object None extends OptionInt + + def content(t: Tree) : Set[BigInt] = t match { + case Empty => Set.empty + case Node(_, l, v, r) => content(l) ++ Set(v) ++ content(r) + } + + def size(t: Tree) : BigInt = t match { + case Empty => 0 + case Node(_, l, v, r) => size(l) + 1 + size(r) + } + + /* We consider leaves to be black by definition */ + def isBlack(t: Tree) : Boolean = t match { + case Empty => true + case Node(Black,_,_,_) => true + case _ => false + } + + def redNodesHaveBlackChildren(t: Tree) : Boolean = t match { + case Empty => true + case Node(Black, l, _, r) => redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r) + case Node(Red, l, _, r) => isBlack(l) && isBlack(r) && redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r) + } + + def redDescHaveBlackChildren(t: Tree) : Boolean = t match { + case Empty => true + case Node(_,l,_,r) => redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r) + } + + def blackBalanced(t : Tree) : Boolean = t match { + case Node(_,l,_,r) => blackBalanced(l) && blackBalanced(r) && blackHeight(l) == blackHeight(r) + case Empty => true + } + + def blackHeight(t : Tree) : BigInt = t match { + case Empty => 1 + case Node(Black, l, _, _) => blackHeight(l) + 1 + case Node(Red, l, _, _) => blackHeight(l) + } + + // <<insert element x into the tree t>> + def ins(x: BigInt, t: Tree): Tree = { + require(redNodesHaveBlackChildren(t) && blackBalanced(t)) + t match { + case Empty => Node(Red,Empty,x,Empty) + case Node(c,a,y,b) => + if (x < y) balance(c, ins(x, a), y, b) + else if (x == y) Node(c,a,y,b) + else balance(c,a,y,ins(x, b)) + } + } ensuring (res => content(res) == content(t) ++ Set(x) + && size(t) <= size(res) && size(res) <= size(t) + 1 + && redDescHaveBlackChildren(res) + && blackBalanced(res)) + + def makeBlack(n: Tree): Tree = { + require(redDescHaveBlackChildren(n) && blackBalanced(n)) + n match { + case Node(Red,l,v,r) => Node(Black,l,v,r) + case _ => n + } + } ensuring(res => redNodesHaveBlackChildren(res) && blackBalanced(res)) + + def add(x: BigInt, t: Tree): Tree = { + require(redNodesHaveBlackChildren(t) && blackBalanced(t)) + makeBlack(ins(x, t)) + } ensuring (res => content(res) == content(t) ++ Set(x) && redNodesHaveBlackChildren(res) && blackBalanced(res)) + + def buggyAdd(x: BigInt, t: Tree): Tree = { + require(redNodesHaveBlackChildren(t)) + ins(x, t) + } ensuring (res => content(res) == content(t) ++ Set(x) && redNodesHaveBlackChildren(res)) + + def balance(c: Color, a: Tree, x: BigInt, b: Tree): Tree = { + Node(c,a,x,b) match { + case Node(Black,Node(Red,Node(Red,a,xV,b),yV,c),zV,d) => + Node(Red,Node(Black,a,xV,b),yV,Node(Black,c,zV,d)) + case Node(Black,Node(Red,a,xV,Node(Red,b,yV,c)),zV,d) => + Node(Red,Node(Black,a,xV,b),yV,Node(Black,c,zV,d)) + case Node(Black,a,xV,Node(Red,Node(Red,b,yV,c),zV,d)) => + Node(Red,Node(Black,a,xV,b),yV,Node(Black,c,zV,d)) + case Node(Black,a,xV,Node(Red,b,yV,Node(Red,c,zV,d))) => + Node(Red,Node(Black,a,xV,b),yV,Node(Black,c,zV,d)) + case Node(c,a,xV,b) => Node(c,a,xV,b) + } + } ensuring (res => content(res) == content(Node(c,a,x,b))) + + def buggyBalance(c: Color, a: Tree, x: BigInt, b: Tree): Tree = { + Node(c,a,x,b) match { + case Node(Black,Node(Red,Node(Red,a,xV,b),yV,c),zV,d) => + Node(Red,Node(Black,a,xV,b),yV,Node(Black,c,zV,d)) + case Node(Black,Node(Red,a,xV,Node(Red,b,yV,c)),zV,d) => + Node(Red,Node(Black,a,xV,b),yV,Node(Black,c,zV,d)) + case Node(Black,a,xV,Node(Red,Node(Red,b,yV,c),zV,d)) => + Node(Red,Node(Black,a,xV,b),yV,Node(Black,c,zV,d)) + case Node(Black,a,xV,Node(Red,b,yV,Node(Red,c,zV,d))) => + Node(Red,Node(Black,a,xV,b),yV,Node(Black,c,zV,d)) + } + } ensuring (res => content(res) == content(Node(c,a,x,b))) +} diff --git a/testcases/web/verification/07_Search_Linked-List.scala b/testcases/web/verification/07_Search_Linked-List.scala new file mode 100644 index 0000000000000000000000000000000000000000..16f1c550e6c620bce328e2ec31e5312838af0cfc --- /dev/null +++ b/testcases/web/verification/07_Search_Linked-List.scala @@ -0,0 +1,47 @@ +import leon.lang._ +import leon.annotation._ + +object SearchLinkedList { + sealed abstract class List + case class Cons(head : BigInt, tail : List) extends List + case object Nil extends List + + def size(list : List) : BigInt = (list match { + case Nil => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def contains(list : List, elem : BigInt) : Boolean = (list match { + case Nil => false + case Cons(x, xs) => x == elem || contains(xs, elem) + }) + + def firstZero(list : List) : BigInt = (list match { + case Nil => 0 + case Cons(x, xs) => if (x == 0) 0 else firstZero(xs) + 1 + }) ensuring (res => + res >= 0 && (if (contains(list, 0)) { + firstZeroAtPos(list, res) + } else { + res == size(list) + })) + + def firstZeroAtPos(list : List, pos : BigInt) : Boolean = { + list match { + case Nil => false + case Cons(x, xs) => if (pos == 0) x == 0 else x != 0 && firstZeroAtPos(xs, pos - 1) + } + } + + def goal(list : List, i : BigInt) : Boolean = { + if(firstZero(list) == i) { + if(contains(list, 0)) { + firstZeroAtPos(list, i) + } else { + i == size(list) + } + } else { + true + } + } holds +} diff --git a/testcases/web/verification/08_Sum_and_Max.scala b/testcases/web/verification/08_Sum_and_Max.scala new file mode 100644 index 0000000000000000000000000000000000000000..24d279515cdbc7fe7d3e3f6f056be53d25df61eb --- /dev/null +++ b/testcases/web/verification/08_Sum_and_Max.scala @@ -0,0 +1,46 @@ +import leon.lang._ +import leon.annotation._ + +object SumAndMax { + sealed abstract class List + case class Cons(head : BigInt, tail : List) extends List + case object Nil extends List + + def max(list : List) : BigInt = { + require(list != Nil) + list match { + case Cons(x, Nil) => x + case Cons(x, xs) => { + val m2 = max(xs) + if(m2 > x) m2 else x + } + } + } + + def sum(list : List) : BigInt = list match { + case Nil => 0 + case Cons(x, xs) => x + sum(xs) + } + + def size(list : List) : BigInt = (list match { + case Nil => 0 + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def allPos(list : List) : Boolean = list match { + case Nil => true + case Cons(x, xs) => x >= 0 && allPos(xs) + } + + def prop0(list : List) : Boolean = { + require(list != Nil) + !allPos(list) || max(list) >= 0 + } holds + + @induct + def property(list : List) : Boolean = { + // This precondition was given in the problem but isn't actually useful :D + // require(allPos(list)) + sum(list) <= size(list) * (if(list == Nil) 0 else max(list)) + } holds +} diff --git a/testcases/web/verification/09_Heap.scala b/testcases/web/verification/09_Heap.scala new file mode 100644 index 0000000000000000000000000000000000000000..aa66ca2f2a5e40ce80165a9cf0f0db8e00aa4d43 --- /dev/null +++ b/testcases/web/verification/09_Heap.scala @@ -0,0 +1,147 @@ +/* Copyright 2009-2015 EPFL, Lausanne */ + +import leon.annotation._ +import leon.lang._ + +object Heaps { + /*~~~~~~~~~~~~~~~~~~~~~~~*/ + /* Data type definitions */ + /*~~~~~~~~~~~~~~~~~~~~~~~*/ + private case class Node(rank : BigInt, elem : Int, nodes : Heap) + + sealed abstract class Heap + private case class Nodes(head : Node, tail : Heap) extends Heap + private case object Empty extends Heap + + sealed abstract class OptInt + case class Some(value : Int) extends OptInt + case object None extends OptInt + + /*~~~~~~~~~~~~~~~~~~~~~~~*/ + /* Abstraction functions */ + /*~~~~~~~~~~~~~~~~~~~~~~~*/ + def heapContent(h : Heap) : Set[Int] = h match { + case Empty => Set.empty[Int] + case Nodes(n, ns) => nodeContent(n) ++ heapContent(ns) + } + + def nodeContent(n : Node) : Set[Int] = n match { + case Node(_, e, h) => Set(e) ++ heapContent(h) + } + + /*~~~~~~~~~~~~~~~~~~~~~~~~*/ + /* Helper/local functions */ + /*~~~~~~~~~~~~~~~~~~~~~~~~*/ + private def reverse(h : Heap) : Heap = reverse0(h, Empty) + private def reverse0(h : Heap, acc : Heap) : Heap = (h match { + case Empty => acc + case Nodes(n, ns) => reverse0(ns, Nodes(n, acc)) + }) ensuring(res => heapContent(res) == heapContent(h) ++ heapContent(acc)) + + private def link(t1 : Node, t2 : Node) = (t1, t2) match { + case (Node(r, e1, ns1), Node(_, e2, ns2)) => + if(e1 <= e2) { + Node(r + 1, e1, Nodes(t2, ns1)) + } else { + Node(r + 1, e2, Nodes(t1, ns2)) + } + } + + private def insertNode(t : Node, h : Heap) : Heap = (h match { + case Empty => Nodes(t, Empty) + case Nodes(t2, h2) => + if(t.rank < t2.rank) { + Nodes(t, h) + } else { + insertNode(link(t, t2), h2) + } + }) ensuring(res => heapContent(res) == nodeContent(t) ++ heapContent(h)) + + private def getMin(h : Heap) : (Node, Heap) = { + require(h != Empty) + h match { + case Nodes(t, Empty) => (t, Empty) + case Nodes(t, ts) => + val (t0, ts0) = getMin(ts) + if(t.elem < t0.elem) { + (t, ts) + } else { + (t0, Nodes(t, ts0)) + } + } + } ensuring(_ match { + case (n,h2) => nodeContent(n) ++ heapContent(h2) == heapContent(h) + }) + + /*~~~~~~~~~~~~~~~~*/ + /* Heap interface */ + /*~~~~~~~~~~~~~~~~*/ + def empty() : Heap = { + Empty + } ensuring(res => heapContent(res) == Set.empty[Int]) + + def isEmpty(h : Heap) : Boolean = { + (h == Empty) + } ensuring(res => res == (heapContent(h) == Set.empty[Int])) + + def insert(e : Int, h : Heap) : Heap = { + insertNode(Node(0, e, Empty), h) + } ensuring(res => heapContent(res) == heapContent(h) ++ Set(e)) + + def merge(h1 : Heap, h2 : Heap) : Heap = ((h1,h2) match { + case (_, Empty) => h1 + case (Empty, _) => h2 + case (Nodes(t1, ts1), Nodes(t2, ts2)) => + if(t1.rank < t2.rank) { + Nodes(t1, merge(ts1, h2)) + } else if(t2.rank < t1.rank) { + Nodes(t2, merge(h1, ts2)) + } else { + insertNode(link(t1, t2), merge(ts1, ts2)) + } + }) ensuring(res => heapContent(res) == heapContent(h1) ++ heapContent(h2)) + + def findMin(h : Heap) : OptInt = (h match { + case Empty => None + case Nodes(Node(_, e, _), ns) => + findMin(ns) match { + case None => Some(e) + case Some(e2) => Some(if(e < e2) e else e2) + } + }) ensuring(_ match { + case None => isEmpty(h) + case Some(v) => heapContent(h).contains(v) + }) + + def deleteMin(h : Heap) : Heap = (h match { + case Empty => Empty + case ts : Nodes => + val (Node(_, e, ns1), ns2) = getMin(ts) + merge(reverse(ns1), ns2) + }) ensuring(res => heapContent(res).subsetOf(heapContent(h))) + + def sanity0() : Boolean = { + val h0 : Heap = Empty + val h1 = insert(42, h0) + val h2 = insert(72, h1) + val h3 = insert(0, h2) + findMin(h0) == None && + findMin(h1) == Some(42) && + findMin(h2) == Some(42) && + findMin(h3) == Some(0) + }.holds + + def sanity1() : Boolean = { + val h0 = insert(42, Empty) + val h1 = insert(0, Empty) + val h2 = merge(h0, h1) + findMin(h2) == Some(0) + }.holds + + def sanity3() : Boolean = { + val h0 = insert(42, insert(0, insert(12, Empty))) + val h1 = deleteMin(h0) + findMin(h1) == Some(12) + }.holds +} + diff --git a/testcases/web/verification/10_FoldAssociative.scala b/testcases/web/verification/10_FoldAssociative.scala new file mode 100644 index 0000000000000000000000000000000000000000..ff0444f269dd6f9b2a2b7f2b54e13f54c6755ab2 --- /dev/null +++ b/testcases/web/verification/10_FoldAssociative.scala @@ -0,0 +1,103 @@ +/* Copyright 2009-2015 EPFL, Lausanne */ + +import leon._ +import leon.lang._ + +object FoldAssociative { + + sealed abstract class List + case class Cons(head: Int, tail: List) extends List + case class Nil() extends List + + sealed abstract class Option + case class Some(x: Int) extends Option + case class None() extends Option + + def foldRight[A](list: List, state: A, f: (Int, A) => A): A = list match { + case Cons(head, tail) => + val tailState = foldRight(tail, state, f) + f(head, tailState) + case Nil() => state + } + + def take(list: List, count: Int): List = { + require(count >= 0) + list match { + case Cons(head, tail) if count > 0 => Cons(head, take(tail, count - 1)) + case _ => Nil() + } + } + + def drop(list: List, count: Int): List = { + require(count >= 0) + list match { + case Cons(head, tail) if count > 0 => drop(tail, count - 1) + case _ => list + } + } + + def append(l1: List, l2: List): List = { + l1 match { + case Cons(head, tail) => Cons(head, append(tail, l2)) + case Nil() => l2 + } + } + + def lemma_split(list: List, x: Int): Boolean = { + require(x >= 0) + val f = (x: Int, s: Int) => x + s + val l1 = take(list, x) + val l2 = drop(list, x) + foldRight(list, 0, f) == foldRight(l1, foldRight(l2, 0, f), f) + } + + def lemma_split_induct(list: List, x: Int): Boolean = { + require(x >= 0) + val f = (x: Int, s: Int) => x + s + val l1 = take(list, x) + val l2 = drop(list, x) + lemma_split(list, x) && (list match { + case Cons(head, tail) if x > 0 => + lemma_split_induct(tail, x - 1) + case _ => true + }) + }.holds + + def lemma_reassociative(list: List, x: Int): Boolean = { + require(x >= 0) + val f = (x: Int, s: Int) => x + s + val l1 = take(list, x) + val l2 = drop(list, x) + + foldRight(list, 0, f) == foldRight(l1, 0, f) + foldRight(l2, 0, f) + } + + def lemma_reassociative_induct(list: List, x: Int): Boolean = { + require(x >= 0) + val f = (x: Int, s: Int) => x + s + val l1 = take(list, x) + val l2 = drop(list, x) + lemma_reassociative(list, x) && (list match { + case Cons(head, tail) if x > 0 => + lemma_reassociative_induct(tail, x - 1) + case _ => true + }) + }.holds + + def lemma_reassociative_presplit(l1: List, l2: List): Boolean = { + val f = (x: Int, s: Int) => x + s + val list = append(l1, l2) + foldRight(list, 0, f) == foldRight(l1, 0, f) + foldRight(l2, 0, f) + } + + def lemma_reassociative_presplit_induct(l1: List, l2: List): Boolean = { + val f = (x: Int, s: Int) => x + s + val list = append(l1, l2) + lemma_reassociative_presplit(l1, l2) && (l1 match { + case Cons(head, tail) => + lemma_reassociative_presplit_induct(tail, l2) + case Nil() => true + }) + }.holds + +} diff --git a/testcases/web/verification/11_MergeSort.scala b/testcases/web/verification/11_MergeSort.scala new file mode 100644 index 0000000000000000000000000000000000000000..9a1cb71fe0368c6b2ef6021b4f11a2eac961fea5 --- /dev/null +++ b/testcases/web/verification/11_MergeSort.scala @@ -0,0 +1,122 @@ +/* Copyright 2009-2015 EPFL, Lausanne */ + +import leon.annotation._ +import leon.lang._ + +object MergeSort { + // Data types + sealed abstract class List + case class Cons(head : Int, tail : List) extends List + case class Nil() extends List + + sealed abstract class LList + case class LCons(head : List, tail : LList) extends LList + case class LNil() extends LList + + def content(list : List) : Set[Int] = list match { + case Nil() => Set.empty[Int] + case Cons(x, xs) => Set(x) ++ content(xs) + } + + def lContent(llist : LList) : Set[Int] = llist match { + case LNil() => Set.empty[Int] + case LCons(x, xs) => content(x) ++ lContent(xs) + } + + def size(list : List) : BigInt = (list match { + case Nil() => BigInt(0) + case Cons(_, xs) => 1 + size(xs) + }) ensuring(_ >= 0) + + def isSorted(list : List) : Boolean = list match { + case Nil() => true + case Cons(_, Nil()) => true + case Cons(x1, Cons(x2, _)) if(x1 > x2) => false + case Cons(_, xs) => isSorted(xs) + } + + def lIsSorted(llist : LList) : Boolean = llist match { + case LNil() => true + case LCons(x, xs) => isSorted(x) && lIsSorted(xs) + } + + def abs(i : BigInt) : BigInt = { + if(i < 0) -i else i + } ensuring(_ >= 0) + + def mergeSpec(list1 : List, list2 : List, res : List) : Boolean = { + isSorted(res) && content(res) == content(list1) ++ content(list2) + } + + def mergeFast(list1 : List, list2 : List) : List = { + require(isSorted(list1) && isSorted(list2)) + + (list1, list2) match { + case (_, Nil()) => list1 + case (Nil(), _) => list2 + case (Cons(x, xs), Cons(y, ys)) => + if(x <= y) { + Cons(x, mergeFast(xs, list2)) + } else { + Cons(y, mergeFast(list1, ys)) + } + } + } ensuring(res => mergeSpec(list1, list2, res)) + + def splitSpec(list : List, res : (List,List)) : Boolean = { + val s1 = size(res._1) + val s2 = size(res._2) + abs(s1 - s2) <= 1 && s1 + s2 == size(list) && + content(res._1) ++ content(res._2) == content(list) + } + + def split(list : List) : (List,List) = (list match { + case Nil() => (Nil(), Nil()) + case Cons(x, Nil()) => (Cons(x, Nil()), Nil()) + case Cons(x1, Cons(x2, xs)) => + val (s1,s2) = split(xs) + (Cons(x1, s1), Cons(x2, s2)) + }) ensuring(res => splitSpec(list, res)) + + def sortSpec(in : List, out : List) : Boolean = { + content(out) == content(in) && isSorted(out) + } + + // Not really quicksort, neither mergesort. + def weirdSort(in : List) : List = (in match { + case Nil() => Nil() + case Cons(x, Nil()) => Cons(x, Nil()) + case _ => + val (s1,s2) = split(in) + mergeFast(weirdSort(s1), weirdSort(s2)) + }) ensuring(res => sortSpec(in, res)) + + def toLList(list : List) : LList = (list match { + case Nil() => LNil() + case Cons(x, xs) => LCons(Cons(x, Nil()), toLList(xs)) + }) ensuring(res => lContent(res) == content(list) && lIsSorted(res)) + + def mergeMap(llist : LList) : LList = { + require(lIsSorted(llist)) + + llist match { + case LNil() => LNil() + case o @ LCons(x, LNil()) => o + case LCons(x, LCons(y, ys)) => LCons(mergeFast(x, y), mergeMap(ys)) + } + } ensuring(res => lContent(res) == lContent(llist) && lIsSorted(res)) + + def mergeReduce(llist : LList) : List = { + require(lIsSorted(llist)) + + llist match { + case LNil() => Nil() + case LCons(x, LNil()) => x + case _ => mergeReduce(mergeMap(llist)) + } + } ensuring(res => content(res) == lContent(llist) && isSorted(res)) + + def mergeSort(in : List) : List = { + mergeReduce(toLList(in)) + } ensuring(res => sortSpec(in, res)) +} diff --git a/testcases/web/verification/12_ParBalance.scala b/testcases/web/verification/12_ParBalance.scala new file mode 100644 index 0000000000000000000000000000000000000000..d1ddfd3f69baee993c9e01a622217236e27226ca --- /dev/null +++ b/testcases/web/verification/12_ParBalance.scala @@ -0,0 +1,208 @@ +/* Copyright 2009-2015 EPFL, Lausanne */ + +import leon._ +import leon.lang._ + +object ParBalance { + + sealed abstract class List + case class Cons(head: BigInt, tail: List) extends List + case class Nil() extends List + + sealed abstract class Option + case class Some(x: BigInt) extends Option + case class None() extends Option + + val openPar : BigInt = BigInt(1) + val closePar : BigInt = BigInt(2) + + def balanced(list: List, counter: BigInt): Boolean = { + if (counter < 0) false else list match { + case Cons(head, tail) => + val c = if (head == openPar) counter + 1 + else if (head == closePar) counter - 1 + else counter + balanced(tail, c) + case Nil() => counter == 0 + } + } + + def balanced_nonEarly(list: List, counter: BigInt): Boolean = { + list match { + case Cons(head, tail) => + if (counter < 0) balanced_nonEarly(tail, counter) else { + val c = if (head == openPar) counter + 1 + else if (head == closePar) counter - 1 + else counter + balanced_nonEarly(tail, c) + } + case Nil() => counter == 0 + } + } ensuring { res => res == balanced(list, counter) } + + def balanced_withFailure(list: List, counter: BigInt, failed: Boolean): Boolean = { + require(counter >= 0 || failed) + list match { + case Cons(head, tail) => + val c = if (head == openPar) counter + 1 + else if (head == closePar) counter - 1 + else counter + balanced_withFailure(tail, c, failed || c < 0) + case Nil() => !failed && counter == 0 + } + } ensuring { res => + if (failed) { + res == balanced_nonEarly(list, -1) + } else { + res == balanced_nonEarly(list, counter) + } + } + + def balanced_withReduce(list: List, p: (BigInt, BigInt)): Boolean = { + require(p._1 >= 0 && p._2 >= 0) + list match { + case Cons(head, tail) => + val p2 = reduce(p, parPair(head)) + balanced_withReduce(tail, p2) + case Nil() => + p._1 == 0 && p._2 == 0 + } + } ensuring { res => res == balanced_withFailure(list, p._1 - p._2, p._2 > 0) } + + def balanced_foldLeft_equivalence(list: List, p: (BigInt, BigInt)): Boolean = { + require(p._1 >= 0 && p._2 >= 0) + val f = (s: (BigInt, BigInt), x: BigInt) => reduce(s, parPair(x)) + (foldLeft(list, p, f) == (BigInt(0), BigInt(0))) == balanced_withReduce(list, p) && (list match { + case Cons(head, tail) => + val p2 = f(p, head) + balanced_foldLeft_equivalence(tail, p2) + case Nil() => true + }) + }.holds + + def foldRight[A](list: List, state: A, f: (BigInt, A) => A): A = list match { + case Cons(head, tail) => + val tailState = foldRight(tail, state, f) + f(head, tailState) + case Nil() => state + } + + def foldLeft[A](list: List, state: A, f: (A, BigInt) => A): A = list match { + case Cons(head, tail) => + val nextState = f(state, head) + foldLeft(tail, nextState, f) + case Nil() => state + } + + def reduce(p1: (BigInt, BigInt), p2: (BigInt, BigInt)): (BigInt, BigInt) = { + if (p1._1 >= p2._2) { + (p1._1 - p2._2 + p2._1, p1._2) + } else { + (p2._1, p2._2 - p1._1 + p1._2) + } + } + + def reduce_associative(p1: (BigInt, BigInt), p2: (BigInt, BigInt), p3: (BigInt, BigInt)): Boolean = { + reduce(p1, reduce(p2, p3)) == reduce(reduce(p1, p2), p3) + }.holds + + def swap(p: (BigInt, BigInt)): (BigInt, BigInt) = (p._2, p._1) + + def reduce_inverse(p1: (BigInt, BigInt), p2: (BigInt, BigInt)): Boolean = { + reduce(p1, p2) == swap(reduce(swap(p2), swap(p1))) + }.holds + + def reduce_associative_inverse(p1: (BigInt, BigInt), p2: (BigInt, BigInt), p3: (BigInt, BigInt)): Boolean = { + reduce(p1, reduce(p2, p3)) == swap(reduce(reduce(swap(p3), swap(p2)), swap(p1))) + }.holds + + def reduce_associative_inverse2(p1: (BigInt, BigInt), p2: (BigInt, BigInt), p3: (BigInt, BigInt)): Boolean = { + reduce(reduce(p1, p2), p3) == swap(reduce(swap(p3), reduce(swap(p2), swap(p1)))) + }.holds + + def parPair(x: BigInt): (BigInt, BigInt) = { + if (x == openPar) (1, 0) else if (x == closePar) (0, 1) else (0, 0) + } + + def headOption(list: List): Option = list match { + case Cons(head, tail) => Some(head) + case Nil() => None() + } + + def lastOption(list: List): Option = list match { + case Cons(head, Nil()) => Some(head) + case Cons(head, tail) => lastOption(tail) + case Nil() => None() + } + + def init(list: List): List = list match { + case Cons(head, Nil()) => Nil() + case Cons(head, tail) => Cons(head, init(tail)) + case Nil() => Nil() + } + + def tail(list: List): List = list match { + case Cons(head, tail) => tail + case Nil() => Nil() + } + + def addLast(list: List, x: BigInt): List = { + list match { + case Cons(head, tail) => Cons(head, addLast(tail, x)) + case Nil() => Cons(x, Nil()) + } + } ensuring { res => lastOption(res) == Some(x) && init(res) == list } + + def reverse(list: List): List = { + list match { + case Cons(head, tail) => addLast(reverse(tail), head) + case Nil() => Nil() + } + } ensuring { res => + lastOption(res) == headOption(list) && + lastOption(list) == headOption(res) + } + + def reverse_tail_equivalence(list: List): Boolean = { + reverse(tail(list)) == init(reverse(list)) + }.holds + + def reverse_init_equivalence(list: List): Boolean = { + reverse(init(list)) == tail(reverse(list)) && (list match { + case Cons(head, tail) => reverse_init_equivalence(tail) + case Nil() => true + }) + }.holds + + def reverse_equality_equivalence(l1: List, l2: List): Boolean = { + (l1 == l2) == (reverse(l1) == reverse(l2)) && ((l1, l2) match { + case (Cons(h1, t1), Cons(h2, t2)) => reverse_equality_equivalence(t1, t2) + case _ => true + }) + }.holds + + def reverse_reverse_equivalence(list: List): Boolean = { + reverse(reverse(list)) == list && ((list, reverse(list)) match { + case (Cons(h1, t1), Cons(h2, t2)) => + reverse_reverse_equivalence(t1) && reverse_reverse_equivalence(t2) + case _ => true + }) + }.holds + + /* + def fold_equivalence(list: List): Boolean = { + val s = (0, 0) + val fl = (s: (BigInt, BigInt), x: BigInt) => reduce(s, parPair(x)) + val fr = (x: BigInt, s: (BigInt, BigInt)) => reduce(parPair(x), s) + + foldLeft(list, s, fl) == foldRight(list, s, fr) + }.holds + + def lemma(list: List): Boolean = { + val f = (x: BigInt, s: (BigInt, BigInt)) => reduce(parPair(x), s) + fold_equivalence(list) && balanced_foldLeft_equivalence(list, (0, 0)) && + (foldRight(list, (0, 0), f) == (0, 0)) == balanced(list, 0) + }.holds + */ + +} diff --git a/testcases/web/verification/13_Monads.scala b/testcases/web/verification/13_Monads.scala new file mode 100644 index 0000000000000000000000000000000000000000..05b46ceb0f02a96811b7ca8a4606b4b4b30de3e3 --- /dev/null +++ b/testcases/web/verification/13_Monads.scala @@ -0,0 +1,79 @@ +/* Copyright 2009-2015 EPFL, Lausanne */ + +import leon.lang._ +import leon.collection._ + +object Monads3 { + + def append[T](l1: List[T], l2: List[T]): List[T] = { + l1 match { + case Cons(head, tail) => Cons(head, append(tail, l2)) + case Nil() => l2 + } + } ensuring { res => (res == l1) || (l2 != Nil[T]()) } + + def flatMap[T,U](list: List[T], f: T => List[U]): List[U] = list match { + case Cons(head, tail) => append(f(head), flatMap(tail, f)) + case Nil() => Nil() + } + + def associative_lemma[T,U,V](list: List[T], f: T => List[U], g: U => List[V]): Boolean = { + flatMap(flatMap(list, f), g) == flatMap(list, (x: T) => flatMap(f(x), g)) + } + + def associative_lemma_induct[T,U,V](list: List[T], flist: List[U], glist: List[V], f: T => List[U], g: U => List[V]): Boolean = { + associative_lemma(list, f, g) && + append(glist, flatMap(append(flist, flatMap(list, f)), g)) == append(append(glist, flatMap(flist, g)), flatMap(list, (x: T) => flatMap(f(x), g))) && + (glist match { + case Cons(ghead, gtail) => + associative_lemma_induct(list, flist, gtail, f, g) + case Nil() => flist match { + case Cons(fhead, ftail) => + associative_lemma_induct(list, ftail, g(fhead), f, g) + case Nil() => list match { + case Cons(head, tail) => associative_lemma_induct(tail, f(head), Nil(), f, g) + case Nil() => true + } + } + }) + }.holds + + def left_unit_law[T,U](x: T, f: T => List[U]): Boolean = { + flatMap(Cons(x, Nil()), f) == f(x) + }.holds + + def right_unit_law[T](list: List[T]): Boolean = { + flatMap(list, (x: T) => Cons(x, Nil())) == list + } + + def right_unit_induct[T,U](list: List[T]): Boolean = { + right_unit_law(list) && (list match { + case Cons(head, tail) => right_unit_induct(tail) + case Nil() => true + }) + }.holds + + def flatMap_zero_law[T,U](f: T => List[U]): Boolean = { + flatMap(Nil[T](), f) == Nil[U]() + }.holds + + def flatMap_to_zero_law[T](list: List[T]): Boolean = { + flatMap(list, (x: T) => Nil[T]()) == Nil[T]() + } + + def flatMap_to_zero_induct[T,U](list: List[T]): Boolean = { + flatMap_to_zero_law(list) && (list match { + case Cons(head, tail) => flatMap_to_zero_induct(tail) + case Nil() => true + }) + }.holds + + def add_zero_law[T](list: List[T]): Boolean = { + append(list, Nil()) == list + }.holds + + def zero_add_law[T](list: List[T]): Boolean = { + append(Nil(), list) == list + }.holds + +}