From a6259e94c5cd154b440a2e8bf248d855306520be Mon Sep 17 00:00:00 2001 From: Etienne Kneuss <ekneuss@gmail.com> Date: Thu, 10 Dec 2015 16:44:49 +0100 Subject: [PATCH] Introduce new synthesis rules (InputSplit & IndependentSplit) - InputSplit splits by a boolean input variable - IndependentSplit splits output variables that are unrelated --- .../leon/synthesis/ConversionPhase.scala | 2 + src/main/scala/leon/synthesis/Rules.scala | 2 + .../synthesis/rules/IndependentSplit.scala | 80 ++++++++++++++++++ .../leon/synthesis/rules/InputSplit.scala | 49 +++++++++++ .../invalid/PropositionalLogic.scala | 46 +---------- .../etienne-thesis/AddressBook/Make.scala | 53 ++++++++++++ .../etienne-thesis/AddressBook/Merge.scala | 69 ++++++++++++++++ .../etienne-thesis/BatchedQueue/Dequeue.scala | 80 ++++++++++++++++++ .../etienne-thesis/BatchedQueue/Enqueue.scala | 82 +++++++++++++++++++ .../etienne-thesis/List/Delete.scala | 25 ++---- .../etienne-thesis/SortedList/Delete.scala | 34 ++++++++ .../etienne-thesis/SortedList/Diff.scala | 53 ++++++++++++ .../etienne-thesis/SortedList/Insert.scala | 34 ++++++++ .../SortedList/InsertAlways.scala | 34 ++++++++ .../SortedList/InsertionSort.scala | 49 +++++++++++ .../etienne-thesis/SortedList/Union.scala | 51 ++++++++++++ .../StrictSortedList/Delete.scala | 34 ++++++++ .../StrictSortedList/Insert.scala | 34 ++++++++ .../StrictSortedList/Union.scala | 51 ++++++++++++ .../etienne-thesis/UnaryNumerals/Add.scala | 21 +++++ .../UnaryNumerals/Distinct.scala | 30 +++++++ .../etienne-thesis/UnaryNumerals/Mult.scala | 30 +++++++ testcases/synthesis/etienne-thesis/run.sh | 43 ++++++++++ 23 files changed, 923 insertions(+), 63 deletions(-) create mode 100644 src/main/scala/leon/synthesis/rules/IndependentSplit.scala create mode 100644 src/main/scala/leon/synthesis/rules/InputSplit.scala create mode 100644 testcases/synthesis/etienne-thesis/AddressBook/Make.scala create mode 100644 testcases/synthesis/etienne-thesis/AddressBook/Merge.scala create mode 100644 testcases/synthesis/etienne-thesis/BatchedQueue/Dequeue.scala create mode 100644 testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala create mode 100644 testcases/synthesis/etienne-thesis/SortedList/Delete.scala create mode 100644 testcases/synthesis/etienne-thesis/SortedList/Diff.scala create mode 100644 testcases/synthesis/etienne-thesis/SortedList/Insert.scala create mode 100644 testcases/synthesis/etienne-thesis/SortedList/InsertAlways.scala create mode 100644 testcases/synthesis/etienne-thesis/SortedList/InsertionSort.scala create mode 100644 testcases/synthesis/etienne-thesis/SortedList/Union.scala create mode 100644 testcases/synthesis/etienne-thesis/StrictSortedList/Delete.scala create mode 100644 testcases/synthesis/etienne-thesis/StrictSortedList/Insert.scala create mode 100644 testcases/synthesis/etienne-thesis/StrictSortedList/Union.scala create mode 100644 testcases/synthesis/etienne-thesis/UnaryNumerals/Add.scala create mode 100644 testcases/synthesis/etienne-thesis/UnaryNumerals/Distinct.scala create mode 100644 testcases/synthesis/etienne-thesis/UnaryNumerals/Mult.scala create mode 100755 testcases/synthesis/etienne-thesis/run.sh diff --git a/src/main/scala/leon/synthesis/ConversionPhase.scala b/src/main/scala/leon/synthesis/ConversionPhase.scala index d5f4e842f..a2fa94ea9 100644 --- a/src/main/scala/leon/synthesis/ConversionPhase.scala +++ b/src/main/scala/leon/synthesis/ConversionPhase.scala @@ -188,6 +188,8 @@ object ConversionPhase extends UnitPhase[Program] { // extract spec from chooses at the top-level fullBody match { + case Require(_, Choose(spec)) => + withPostcondition(fullBody, Some(spec)) case Choose(spec) => withPostcondition(fullBody, Some(spec)) case _ => diff --git a/src/main/scala/leon/synthesis/Rules.scala b/src/main/scala/leon/synthesis/Rules.scala index 51a5a15ec..02a04e270 100644 --- a/src/main/scala/leon/synthesis/Rules.scala +++ b/src/main/scala/leon/synthesis/Rules.scala @@ -44,7 +44,9 @@ object Rules { //OnePoint, Ground, CaseSplit, + IndependentSplit, IfSplit, + InputSplit, UnusedInput, EquivalentInputs, UnconstrainedOutput, diff --git a/src/main/scala/leon/synthesis/rules/IndependentSplit.scala b/src/main/scala/leon/synthesis/rules/IndependentSplit.scala new file mode 100644 index 000000000..72be06b9c --- /dev/null +++ b/src/main/scala/leon/synthesis/rules/IndependentSplit.scala @@ -0,0 +1,80 @@ +/* Copyright 2009-2015 EPFL, Lausanne */ + +package leon +package synthesis +package rules + +import leon.utils._ +import purescala.Expressions._ +import purescala.ExprOps._ +import purescala.Extractors._ +import purescala.Constructors._ +import purescala.Common._ +import purescala.Types.CaseClassType + +case object IndependentSplit extends NormalizingRule("IndependentSplit") { + def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = { + val TopLevelAnds(clauses) = and(p.pc, p.phi) + + var independentClasses = Set[Set[Identifier]]() + + // We group connect variables together + for(c <- clauses) { + val vs = variablesOf(c) + + var newClasses = Set[Set[Identifier]]() + + var thisClass = vs + + for (cl <- independentClasses) { + if ((cl & vs).nonEmpty) { + thisClass ++= cl + } else { + newClasses += cl + } + } + + independentClasses = newClasses + thisClass + } + + val outClasses = independentClasses.map(cl => cl & p.xs.toSet).filter(_.nonEmpty) + + if (outClasses.size > 1) { + + val TopLevelAnds(phiClauses) = p.phi + + val subs = (for (cl <- outClasses.toList) yield { + val xs = p.xs.filter(cl) + + if (xs.nonEmpty) { + val phi = andJoin(phiClauses.filter(c => (variablesOf(c) & cl).nonEmpty)) + + val xsToRemove = p.xs.filterNot(cl).toSet + + val eb = p.qeb.removeOuts(xsToRemove) + + Some(p.copy(phi = phi, xs = xs, eb = eb)) + } else { + None + } + }).flatten + + val onSuccess: List[Solution] => Option[Solution] = { sols => + + val infos = subs.map(_.xs).zip(sols.map(_.term)) + + val term = infos.foldLeft(tupleWrap(p.xs.map(_.toVariable))) { + case (expr, (xs, term)) => + letTuple(xs, term, expr) + } + + Some(Solution(andJoin(sols.map(_.pre)), sols.map(_.defs).flatten.toSet, term, sols.forall(_.isTrusted))) + } + + + List(decomp(subs, onSuccess, "Independent Clusters")) + } else { + Nil + } + } +} diff --git a/src/main/scala/leon/synthesis/rules/InputSplit.scala b/src/main/scala/leon/synthesis/rules/InputSplit.scala new file mode 100644 index 000000000..4b9ffef53 --- /dev/null +++ b/src/main/scala/leon/synthesis/rules/InputSplit.scala @@ -0,0 +1,49 @@ +/* Copyright 2009-2015 EPFL, Lausanne */ + +package leon +package synthesis +package rules + +import leon.purescala.Common.Identifier +import purescala.Expressions._ +import purescala.Extractors._ +import purescala.ExprOps._ +import purescala.Constructors._ +import purescala.Types._ + +import solvers._ + +import scala.concurrent.duration._ + +case object InputSplit extends Rule("In. Split") { + def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = { + p.as.filter(_.getType == BooleanType).flatMap { a => + def getProblem(v: Boolean): Problem = { + def replaceA(e: Expr) = replaceFromIDs(Map(a -> BooleanLiteral(v)), e) + + p.copy( + as = p.as.filterNot(_ == a), + ws = replaceA(p.ws), + pc = replaceA(p.pc), + phi = replaceA(p.phi), + eb = p.qeb.removeIns(Set(a)) + ) + } + + val sub1 = getProblem(true) + val sub2 = getProblem(false) + + val onSuccess: List[Solution] => Option[Solution] = { + case List(s1, s2) => + Some(Solution(or(and(Equals(Variable(a), BooleanLiteral(true)), s1.pre), + and(Equals(Variable(a), BooleanLiteral(false)), s2.pre)), + s1.defs ++ s2.defs, + IfExpr(Variable(a), s1.term, s2.term), s1.isTrusted && s2.isTrusted)) + case _ => + None + } + + Some(decomp(List(sub1, sub2), onSuccess, s"Split on '$a'")) + } + } +} diff --git a/src/test/resources/regression/verification/purescala/invalid/PropositionalLogic.scala b/src/test/resources/regression/verification/purescala/invalid/PropositionalLogic.scala index a8927f360..aa00e12d4 100644 --- a/src/test/resources/regression/verification/purescala/invalid/PropositionalLogic.scala +++ b/src/test/resources/regression/verification/purescala/invalid/PropositionalLogic.scala @@ -10,14 +10,11 @@ object PropositionalLogic { 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: Int) 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 + case _ => f }) ensuring(isSimplified(_)) def isSimplified(f: Formula): Boolean = f match { @@ -28,18 +25,6 @@ object PropositionalLogic { 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) => 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 { case And(lhs, rhs) => isNNF(lhs) && isNNF(rhs) case Or(lhs, rhs) => isNNF(lhs) && isNNF(rhs) @@ -49,39 +34,14 @@ object PropositionalLogic { case Literal(_) => true } - def vars(f: Formula): Set[Int] = { - 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[Int](i) - case Literal(i) => Set[Int](i) - } - } - - def fv(f : Formula) = { vars(nnf(f)) } // @induct // def wrongCommutative(f: Formula) : Boolean = { // nnf(simplify(f)) == simplify(nnf(f)) // }.holds - @induct - def simplifyBreaksNNF(f: Formula) : Boolean = { + def simplifyBreaksNNF(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/synthesis/etienne-thesis/AddressBook/Make.scala b/testcases/synthesis/etienne-thesis/AddressBook/Make.scala new file mode 100644 index 000000000..1fd12466c --- /dev/null +++ b/testcases/synthesis/etienne-thesis/AddressBook/Make.scala @@ -0,0 +1,53 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object AddressBookMake { + + case class Address[A](info: A, priv: Boolean) + + sealed abstract class AddressList[A] { + def size: BigInt = { + this match { + case Nil() => BigInt(0) + case Cons(head, tail) => BigInt(1) + tail.size + } + } ensuring { res => res >= 0 } + + def content: Set[Address[A]] = this match { + case Nil() => Set[Address[A]]() + case Cons(addr, l1) => Set(addr) ++ l1.content + } + } + + case class Cons[A](a: Address[A], tail: AddressList[A]) extends AddressList[A] + case class Nil[A]() extends AddressList[A] + + def allPersonal[A](l: AddressList[A]): Boolean = l match { + case Nil() => true + case Cons(a, l1) => + if (a.priv) allPersonal(l1) + else false + } + + def allBusiness[A](l: AddressList[A]): Boolean = l match { + case Nil() => true + case Cons(a, l1) => + if (a.priv) false + else allBusiness(l1) + } + + case class AddressBook[A](business: AddressList[A], personal: AddressList[A]) { + def size: BigInt = business.size + personal.size + + def content: Set[Address[A]] = business.content ++ personal.content + + def invariant = { + allPersonal(personal) && allBusiness(business) + } + } + + def makeAddressBook[A](as: AddressList[A]): AddressBook[A] = { + choose( (res: AddressBook[A]) => res.content == as.content && res.invariant ) + } +} diff --git a/testcases/synthesis/etienne-thesis/AddressBook/Merge.scala b/testcases/synthesis/etienne-thesis/AddressBook/Merge.scala new file mode 100644 index 000000000..92a5b5bfe --- /dev/null +++ b/testcases/synthesis/etienne-thesis/AddressBook/Merge.scala @@ -0,0 +1,69 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object AddressBookMake { + + case class Address[A](info: A, priv: Boolean) + + sealed abstract class AddressList[A] { + def size: BigInt = { + this match { + case Nil() => BigInt(0) + case Cons(head, tail) => BigInt(1) + tail.size + } + } ensuring { res => res >= 0 } + + def content: Set[Address[A]] = this match { + case Nil() => Set[Address[A]]() + case Cons(addr, l1) => Set(addr) ++ l1.content + } + + def ++(that: AddressList[A]): AddressList[A] = { + this match { + case Cons(h, t) => Cons(h, t ++ that) + case Nil() => that + } + } ensuring { + res => res.content == this.content ++ that.content + } + } + + case class Cons[A](a: Address[A], tail: AddressList[A]) extends AddressList[A] + case class Nil[A]() extends AddressList[A] + + def allPersonal[A](l: AddressList[A]): Boolean = l match { + case Nil() => true + case Cons(a, l1) => + if (a.priv) allPersonal(l1) + else false + } + + def allBusiness[A](l: AddressList[A]): Boolean = l match { + case Nil() => true + case Cons(a, l1) => + if (a.priv) false + else allBusiness(l1) + } + + case class AddressBook[A](business: AddressList[A], personal: AddressList[A]) { + def size: BigInt = business.size + personal.size + + def content: Set[Address[A]] = business.content ++ personal.content + + @inline + def invariant = { + allPersonal(personal) && allBusiness(business) + } + } + + def merge[A](a1: AddressBook[A], a2: AddressBook[A]): AddressBook[A] = { + require(a1.invariant && a2.invariant) + + choose( (res: AddressBook[A]) => + res.personal.content == (a1.personal.content ++ a2.personal.content) && + res.business.content == (a1.business.content ++ a2.business.content) && + res.invariant + ) + } +} diff --git a/testcases/synthesis/etienne-thesis/BatchedQueue/Dequeue.scala b/testcases/synthesis/etienne-thesis/BatchedQueue/Dequeue.scala new file mode 100644 index 000000000..c44fc0628 --- /dev/null +++ b/testcases/synthesis/etienne-thesis/BatchedQueue/Dequeue.scala @@ -0,0 +1,80 @@ +import leon.lang._ +import leon.lang.synthesis._ + +object BatchedQueue { + sealed abstract class List[T] { + def content: Set[T] = { + this match { + case Cons(h, t) => Set(h) ++ t.content + case Nil() => Set() + } + } + + def size: BigInt = { + this match { + case Cons(h, t) => BigInt(1) + t.size + case Nil() => BigInt(0) + } + } ensuring { _ >= 0 } + + def reverse: List[T] = { + this match { + case Cons(h, t) => t.reverse.append(Cons(h, Nil[T]())) + case Nil() => Nil[T]() + } + } ensuring { res => + this.content == res.content + } + + def append(r: List[T]): List[T] = { + this match { + case Cons(h, t) => Cons(h, t.append(r)) + case Nil() => r + } + } + + def isEmpty: Boolean = { + this == Nil[T]() + } + + def tail: List[T] = { + require(this != Nil[T]()) + this match { + case Cons(h, t) => t + } + } + + def head: T = { + require(this != Nil[T]()) + this match { + case Cons(h, t) => h + } + } + } + + case class Cons[T](h: T, t: List[T]) extends List[T] + case class Nil[T]() extends List[T] + + case class Queue[T](f: List[T], r: List[T]) { + def content: Set[T] = f.content ++ r.content + def size: BigInt = f.size + r.size + + def isEmpty: Boolean = f.isEmpty && r.isEmpty + + def invariant: Boolean = { + (f.isEmpty) ==> (r.isEmpty) + } + + def toList: List[T] = f.append(r.reverse) + + def dequeue: Queue[T] = { + require(invariant && !isEmpty) + + choose { (res: Queue[T]) => + res.size == size-1 && res.toList == this.toList.tail && res.invariant + } + } + } + + val test = Queue[BigInt](Cons(42, Nil()), Nil()).dequeue +} diff --git a/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala b/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala new file mode 100644 index 000000000..87e030915 --- /dev/null +++ b/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala @@ -0,0 +1,82 @@ +import leon.lang._ +import leon.lang.synthesis._ + +object BatchedQueue { + sealed abstract class List[T] { + def content: Set[T] = { + this match { + case Cons(h, t) => Set(h) ++ t.content + case Nil() => Set() + } + } + + def size: BigInt = { + this match { + case Cons(h, t) => BigInt(1) + t.size + case Nil() => BigInt(0) + } + } ensuring { _ >= 0 } + + def reverse: List[T] = { + this match { + case Cons(h, t) => t.reverse.append(Cons(h, Nil[T]())) + case Nil() => Nil[T]() + } + } ensuring { res => + this.content == res.content + } + + def append(r: List[T]): List[T] = { + this match { + case Cons(h, t) => Cons(h, t.append(r)) + case Nil() => r + } + } + + def tail: List[T] = { + require(this != Nil[T]()) + this match { + case Cons(h, t) => t + } + } + + def head: T = { + require(this != Nil[T]()) + this match { + case Cons(h, t) => h + } + } + + def last: T = { + require(this != Nil[T]()) + this match { + case Cons(h, Nil()) => h + case Cons(h, t) => t.last + } + } + } + + case class Cons[T](h: T, t: List[T]) extends List[T] + case class Nil[T]() extends List[T] + + case class Queue[T](f: List[T], r: List[T]) { + def content: Set[T] = f.content ++ r.content + def size: BigInt = f.size + r.size + + def invariant: Boolean = { + (f == Nil[T]()) ==> (r == Nil[T]()) + } + + def toList: List[T] = f.append(r.reverse) + + def enqueue(v: T): Queue[T] = { + require(invariant) + + choose { (res: Queue[T]) => + res.invariant && + res.toList.last == v && + res.content == this.content ++ Set(v) + } + } + } +} diff --git a/testcases/synthesis/etienne-thesis/List/Delete.scala b/testcases/synthesis/etienne-thesis/List/Delete.scala index 46f071087..30716c591 100644 --- a/testcases/synthesis/etienne-thesis/List/Delete.scala +++ b/testcases/synthesis/etienne-thesis/List/Delete.scala @@ -7,7 +7,7 @@ object Delete { case class Cons(head: BigInt, tail: List) extends List case object Nil extends List - def size(l: List) : BigInt = (l match { + def size(l: List): BigInt = (l match { case Nil => BigInt(0) case Cons(_, t) => BigInt(1) + size(t) }) ensuring(res => res >= 0) @@ -17,25 +17,10 @@ object Delete { case Cons(i, t) => Set(i) ++ content(t) } - def insert(in1: List, v: BigInt): List = { - Cons(v, in1) - } ensuring { content(_) == content(in1) ++ Set(v) } - - //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 delete(in1: List, v: BigInt) = choose { + def delete(in: List, v: BigInt) = { + ???[List] + } ensuring { (out : List) => - content(out) == content(in1) -- Set(v) + content(out) == content(in) -- Set(v) } } diff --git a/testcases/synthesis/etienne-thesis/SortedList/Delete.scala b/testcases/synthesis/etienne-thesis/SortedList/Delete.scala new file mode 100644 index 000000000..788f232d3 --- /dev/null +++ b/testcases/synthesis/etienne-thesis/SortedList/Delete.scala @@ -0,0 +1,34 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object SortedListDelete { + 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 => BigInt(0) + case Cons(_, t) => BigInt(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(in: List, v: BigInt) = { + require(isSorted(in)) + + choose( (res : List) => + (content(res) == content(in) -- Set(v)) && isSorted(res) + ) + } +} diff --git a/testcases/synthesis/etienne-thesis/SortedList/Diff.scala b/testcases/synthesis/etienne-thesis/SortedList/Diff.scala new file mode 100644 index 000000000..d391b85ba --- /dev/null +++ b/testcases/synthesis/etienne-thesis/SortedList/Diff.scala @@ -0,0 +1,53 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object SortedListDiff { + 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 => BigInt(0) + case Cons(_, t) => BigInt(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/synthesis/etienne-thesis/SortedList/Insert.scala b/testcases/synthesis/etienne-thesis/SortedList/Insert.scala new file mode 100644 index 000000000..0bf80d1e9 --- /dev/null +++ b/testcases/synthesis/etienne-thesis/SortedList/Insert.scala @@ -0,0 +1,34 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object SortedListInsert { + 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 => BigInt(0) + case Cons(_, t) => BigInt(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)) + + choose { (out : List) => + (content(out) == content(in1) ++ Set(v)) && isSorted(out) + } + } +} diff --git a/testcases/synthesis/etienne-thesis/SortedList/InsertAlways.scala b/testcases/synthesis/etienne-thesis/SortedList/InsertAlways.scala new file mode 100644 index 000000000..73e0b240d --- /dev/null +++ b/testcases/synthesis/etienne-thesis/SortedList/InsertAlways.scala @@ -0,0 +1,34 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object SortedListInsertAlways { + 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 => BigInt(0) + case Cons(_, t) => BigInt(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 insertAlways(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/synthesis/etienne-thesis/SortedList/InsertionSort.scala b/testcases/synthesis/etienne-thesis/SortedList/InsertionSort.scala new file mode 100644 index 000000000..0752ad33f --- /dev/null +++ b/testcases/synthesis/etienne-thesis/SortedList/InsertionSort.scala @@ -0,0 +1,49 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object SortedListInsertionSort { + 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 => BigInt(0) + case Cons(_, t) => BigInt(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 insertionSort(in1: List): List = { + choose { (out: List) => + content(out) == content(in1) && isSorted(out) + } + } +} diff --git a/testcases/synthesis/etienne-thesis/SortedList/Union.scala b/testcases/synthesis/etienne-thesis/SortedList/Union.scala new file mode 100644 index 000000000..d3f11adcc --- /dev/null +++ b/testcases/synthesis/etienne-thesis/SortedList/Union.scala @@ -0,0 +1,51 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object SortedListUnion { + 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 => BigInt(0) + case Cons(_, t) => BigInt(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/synthesis/etienne-thesis/StrictSortedList/Delete.scala b/testcases/synthesis/etienne-thesis/StrictSortedList/Delete.scala new file mode 100644 index 000000000..23999d96c --- /dev/null +++ b/testcases/synthesis/etienne-thesis/StrictSortedList/Delete.scala @@ -0,0 +1,34 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object StrictSortedListDelete { + 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 => BigInt(0) + case Cons(_, t) => BigInt(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(in: List, v: BigInt) = { + require(isSorted(in)) + + choose( (res : List) => + (content(res) == content(in) -- Set(v)) && isSorted(res) + ) + } +} diff --git a/testcases/synthesis/etienne-thesis/StrictSortedList/Insert.scala b/testcases/synthesis/etienne-thesis/StrictSortedList/Insert.scala new file mode 100644 index 000000000..65f3c01f9 --- /dev/null +++ b/testcases/synthesis/etienne-thesis/StrictSortedList/Insert.scala @@ -0,0 +1,34 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object StrictSortedListInsert { + 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 => BigInt(0) + case Cons(_, t) => BigInt(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)) + + choose { (out : List) => + (content(out) == content(in1) ++ Set(v)) && isSorted(out) + } + } +} diff --git a/testcases/synthesis/etienne-thesis/StrictSortedList/Union.scala b/testcases/synthesis/etienne-thesis/StrictSortedList/Union.scala new file mode 100644 index 000000000..c10ed419d --- /dev/null +++ b/testcases/synthesis/etienne-thesis/StrictSortedList/Union.scala @@ -0,0 +1,51 @@ +import leon.annotation._ +import leon.lang._ +import leon.lang.synthesis._ + +object StrictSortedListUnion { + 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 => BigInt(0) + case Cons(_, t) => BigInt(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/synthesis/etienne-thesis/UnaryNumerals/Add.scala b/testcases/synthesis/etienne-thesis/UnaryNumerals/Add.scala new file mode 100644 index 000000000..a34d1834f --- /dev/null +++ b/testcases/synthesis/etienne-thesis/UnaryNumerals/Add.scala @@ -0,0 +1,21 @@ +import leon.lang._ +import leon.lang.synthesis._ + +object UnaryNumeralsAdd { + 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 => BigInt(0) + case S(p) => BigInt(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/synthesis/etienne-thesis/UnaryNumerals/Distinct.scala b/testcases/synthesis/etienne-thesis/UnaryNumerals/Distinct.scala new file mode 100644 index 000000000..4287378d1 --- /dev/null +++ b/testcases/synthesis/etienne-thesis/UnaryNumerals/Distinct.scala @@ -0,0 +1,30 @@ +import leon.lang._ +import leon.lang.synthesis._ + +object UnaryNumeralsDistinct { + 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 => BigInt(0) + case S(p) => BigInt(1) + value(p) + } + } ensuring (_ >= 0) + + def add(x: Num, y: Num): Num = { + x match { + case S(p) => S(add(p, y)) + case Z => y + } + } ensuring { (r : Num) => + value(r) == value(x) + value(y) + } + + def distinct(x: Num, y: Num): Num = { + choose { (r : Num) => + r != x && r != y + } + } +} diff --git a/testcases/synthesis/etienne-thesis/UnaryNumerals/Mult.scala b/testcases/synthesis/etienne-thesis/UnaryNumerals/Mult.scala new file mode 100644 index 000000000..bfa39365e --- /dev/null +++ b/testcases/synthesis/etienne-thesis/UnaryNumerals/Mult.scala @@ -0,0 +1,30 @@ +import leon.lang._ +import leon.lang.synthesis._ + +object UnaryNumeralsMult { + 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 => BigInt(0) + case S(p) => BigInt(1) + value(p) + } + } ensuring (_ >= 0) + + def add(x: Num, y: Num): Num = { + x match { + case S(p) => S(add(p, y)) + case Z => y + } + } ensuring { (r : Num) => + value(r) == value(x) + value(y) + } + + def mult(x: Num, y: Num): Num = { + choose { (r : Num) => + value(r) == value(x) * value(y) + } + } +} diff --git a/testcases/synthesis/etienne-thesis/run.sh b/testcases/synthesis/etienne-thesis/run.sh new file mode 100755 index 000000000..ee64d8670 --- /dev/null +++ b/testcases/synthesis/etienne-thesis/run.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +function run { + cmd="./leon --debug=report --timeout=30 --synthesis $1" + echo "Running " $cmd + echo "------------------------------------------------------------------------------------------------------------------" + $cmd; +} + +echo "==================================================================================================================" >> synthesis-report.txt +# These are all the benchmarks included in my thesis +# List +run testcases/synthesis/etienne-thesis/List/Insert.scala +run testcases/synthesis/etienne-thesis/List/Delete.scala +run testcases/synthesis/etienne-thesis/List/Union.scala +run testcases/synthesis/etienne-thesis/List/Diff.scala +run testcases/synthesis/etienne-thesis/List/Split.scala + +# SortedList +run testcases/synthesis/etienne-thesis/SortedList/Insert.scala +run testcases/synthesis/etienne-thesis/SortedList/InsertAlways.scala +run testcases/synthesis/etienne-thesis/SortedList/Delete.scala +run testcases/synthesis/etienne-thesis/SortedList/Union.scala +run testcases/synthesis/etienne-thesis/SortedList/Diff.scala +run testcases/synthesis/etienne-thesis/SortedList/InsertionSort.scala + +# StrictSortedList +run testcases/synthesis/etienne-thesis/StrictSortedList/Insert.scala +run testcases/synthesis/etienne-thesis/StrictSortedList/Delete.scala +run testcases/synthesis/etienne-thesis/StrictSortedList/Union.scala + +# UnaryNumerals +run testcases/synthesis/etienne-thesis/UnaryNumerals/Add.scala +run testcases/synthesis/etienne-thesis/UnaryNumerals/Distinct.scala +run testcases/synthesis/etienne-thesis/UnaryNumerals/Mult.scala + +# BatchedQueue +#run testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala +run testcases/synthesis/etienne-thesis/BatchedQueue/Dequeue.scala + +# AddressBook +#run testcases/synthesis/etienne-thesis/AddressBook/Make.scala +run testcases/synthesis/etienne-thesis/AddressBook/Merge.scala -- GitLab