From a38d80a8e85d085bb2e778fc8dc7668808cd6589 Mon Sep 17 00:00:00 2001 From: mario-bucev Date: Mon, 22 Jul 2024 15:25:18 +0200 Subject: [PATCH] Add more specs to List functions using bitvector indexing (#1541) --- .../library/stainless/collection/List.scala | 17 ++++++++++++++--- .../stainless/collection/ListSpecs.scala | 11 +++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/frontends/library/stainless/collection/List.scala b/frontends/library/stainless/collection/List.scala index 29d53f9ec2..9459f1d2b0 100644 --- a/frontends/library/stainless/collection/List.scala +++ b/frontends/library/stainless/collection/List.scala @@ -67,6 +67,7 @@ sealed abstract class List[T] { @isabelle.fullBody def apply(index: BigInt): T = { require(0 <= index && index < size) + decreases(index) if (index == BigInt(0)) { head } else { @@ -76,6 +77,7 @@ sealed abstract class List[T] { def iapply(index: Int): T = { require(0 <= index && index < isize) + decreases(index) if (index == 0) { head } else { @@ -92,7 +94,7 @@ sealed abstract class List[T] { case Nil() => Cons(t, this) case Cons(x, xs) => Cons(x, xs :+ (t)) } - } ensuring(res => (res.size == size + 1) && (res.content == content ++ Set(t)) && res == this ++ Cons(t, Nil[T]())) + } ensuring(res => (res.size == size + 1) && (if (isize < Int.MaxValue) res.isize == isize + 1 else res.isize == isize) && (res.content == content ++ Set(t)) && res == this ++ Cons(t, Nil[T]())) @isabelle.function(term = "List.rev") def reverse: List[T] = { @@ -100,7 +102,7 @@ sealed abstract class List[T] { case Nil() => this case Cons(x,xs) => xs.reverse :+ x } - } ensuring (res => (res.size == size) && (res.content == content)) + } ensuring (res => (res.size == size) && (res.isize == isize) && (res.content == content)) def take(i: BigInt): List[T] = { (this, i) match { case (Nil(), _) => Nil[T]() @@ -412,7 +414,7 @@ sealed abstract class List[T] { case Cons(x, tail) => Cons[T](x, tail.iupdated(i - 1, y)) } - } + }.ensuring(res => res.isize == this.isize && res.iapply(i) == y) private def insertAtImpl(pos: BigInt, l: List[T]): List[T] = { require(0 <= pos && pos <= size) @@ -672,11 +674,20 @@ object List { @library def fill[T](n: BigInt)(x: T) : List[T] = { + decreases(if (n <= BigInt(0)) BigInt(0) else n) if (n <= 0) Nil[T]() else Cons[T](x, fill[T](n-1)(x)) } ensuring(res => (res.content == (if (n <= BigInt(0)) Set.empty[T] else Set(x))) && res.size == (if (n <= BigInt(0)) BigInt(0) else n)) + @library + def ifill[T](n: Int)(x: T) : List[T] = { + decreases(if (n <= 0) 0 else n) + if (n <= 0) Nil[T]() + else Cons[T](x, ifill[T](n - 1)(x)) + } ensuring(res => (res.content == (if (n <= 0) Set.empty[T] else Set(x))) && + res.isize == (if (n <= 0) 0 else n)) + /* Range from start (inclusive) to until (exclusive) */ @library def range(start: BigInt, until: BigInt): List[BigInt] = { diff --git a/frontends/library/stainless/collection/ListSpecs.scala b/frontends/library/stainless/collection/ListSpecs.scala index e1180ba616..e016c13171 100644 --- a/frontends/library/stainless/collection/ListSpecs.scala +++ b/frontends/library/stainless/collection/ListSpecs.scala @@ -21,6 +21,17 @@ object ListSpecs { ((l :+ t).apply(i) == (if (i < l.size) l(i) else t)) }.holds + def isnocIndex[T](l: List[T], t: T, i: Int): Boolean = { + require(l.isize < Int.MaxValue) + require(0 <= i && i < l.isize + 1) + decreases(l) + l match { + case Nil() => true + case Cons(x, xs) => if (i > 0) isnocIndex[T](xs, t, i - 1) else true + } + ((l :+ t).iapply(i) == (if (i < l.isize) l.iapply(i) else t)) + }.holds + @isabelle.lemma(about = "stainless.collection.List.apply") def consIndex[T](h: T, t: List[T], i: BigInt): Boolean = { require(0 <= i && i < t.size + 1)