Skip to content

Commit

Permalink
Merge branch 'main' into sam/zipperFindLongestMatch
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelchassot authored Jan 24, 2025
2 parents 23a885d + 2c7a436 commit 4e77565
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lexers/regex/verifiedlexer/stainless.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

vc-cache = true
# debug = ["verification", "smt"]
timeout = 40
timeout = 80
check-models = false
print-ids = false
print-types = false
Expand Down
74 changes: 74 additions & 0 deletions tutorials/inductive-witnesses/TransitiveClosure.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import stainless.annotation.*
import stainless.lang.*

/* This example shows how to represent inductive definitions in
Stainless using algebraic data types with invariants and explicit
proof witnesses. This is in the style of Coq. It is often not
needed in Stainless, but can be useful for complex proofs.
*/

object TransitiveClosure:
/* R is an example relation. @opaque means it is not expanded. */
@opaque
def R(x: BigInt, y: BigInt): Boolean =
y == x + 2

/* We define proof witnesses for reflexive transitive closure R*(x,y).
We can think of this as an inductive definition. */

/* I would like ClosureProof to have two parameters, but Stainless does not support this yet.
Instead, we define two getters. */

sealed trait ClosureProof:
def x: BigInt
def y: BigInt

case class Equal(v: BigInt) extends ClosureProof:
override def x: BigInt = v
override def y: BigInt = v

case class ByBaseR(v1: BigInt, v2: BigInt) extends ClosureProof:
require(R(v1, v2))
override def x: BigInt = v1
override def y: BigInt = v2

case class ByTransitivity(p1: ClosureProof, p2: ClosureProof) extends ClosureProof:
require(p1.y == p2.x)
override def x: BigInt = p1.x
override def y: BigInt = p2.y

def Rstar(using proof: ClosureProof)(x: BigInt, y: BigInt): Boolean =
proof.x == x && proof.y == y

/* Let us prove that Rstar(x,y) implies y - x is even and non-negative. */
/* Proof of that fact is induction on the proof tree for R*(x,y). */

def soundnessRstar(using proof: ClosureProof)(x: BigInt, y: BigInt): Unit = {
require(Rstar(x, y))
proof match
case Equal(v) => ()
case ByBaseR(v1, v2) => unfold(R(v1, v2))
case ByTransitivity(p1, p2) =>
soundnessRstar(using p1)(p1.x, p1.y)
soundnessRstar(using p2)(p2.x, p2.y)
}.ensuring(_ => x <= y && (y - x) % 2 == 0)

/* Let us now prove the converse: if y - x is even and non-negative, then Rstar(x,y). */
/* Proof is induction on y-x. */

def completenessRstar(x: BigInt, y: BigInt): ClosureProof = {
require(x <= y && (y - x) % 2 == 0)
decreases(y - x)
if y - x == 0 then Equal(x)
else if y - x == 2 then
unfold(R(x, y))
ByBaseR(x, y)
else
val p1 = completenessRstar(x, x + 2)
val p2 = completenessRstar(x + 2, y)
ByTransitivity(p1, p2)

}.ensuring(proof => proof.x == x && proof.y == y)


end TransitiveClosure

0 comments on commit 4e77565

Please sign in to comment.