### Prelude

#### A (very) brief history lesson

• LISP

• A family of programming languages
• Very, very old
• Pioneered many features of modern languages
• Scheme

• One of the main dialects of LISP
• Invented in 1975 (Still very old)
• Minimalist design
• Reference is R5RS standard from 1998 (Still old – like Java)

#### Scheme: An Example

 1 2 3 4 5 6 7 ; This procedure computes the factorial ; of its parameter. (define factorial (lambda (x) (if (= x 1) x (* (factorial (- x 1)) x))))

### More on Parentheses

#### Pairs

Structured datatype with 2 fields

• car and cdr similar to left, right, 1st, 2nd…
• historical names, do not worry about it
(1 . 2)             Test

#### Lists

• A crucial datatype
• Defined as
• empty list
• pair with a list in cdr
(1 . 2)             Test
(1 2)               Test
(1 2 3)             Test

### Slang Examples

Merging

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 // #Sireum #Logika import org.sireum._ @pure def sorted(seq: ISZ[Z]): B = { Contract( Ensures(Res == All(1 until seq.size)(i => seq(i - 1) <= seq(i))) ) if (seq.size == 0) { return true } else { var res: B = true; var k: Z = 1; while (k < seq.size) { Invariant( Modifies(k, res), k >= 1, k <= seq.size, res == All(1 until k)(i => seq(i - 1) <= seq(i)), ) if (seq(k - 1) > seq(k)) { res = false } k = k + 1 } return res } } @pure def contained(s: ISZ[Z], t: ISZ[Z]): B = { Contract( Ensures(Res == All(0 until s.size)(i => Exists(0 until t.size)(j => s(i) == t(j)))) ) var res = true var m: Z = 0 while (m < s.size & res) { Invariant( Modifies (m, res), m >= 0, m <= s.size, res == All(0 until m)(i => Exists(0 until t.size)(j => s(i) == t(j))) ) var n: Z = 0 var found: B = false while (n < t.size) { Invariant( Modifies(n), n >= 0, n <= t.size, found == Exists(0 until n)(j => s(m) == t(j)) ) if (s(m) == t(n)) { found = true } n = n+1 } Deduce(|-(found == Exists(0 until t.size)(j => s(m) == t(j)))) if (!found) { Deduce(|-(!Exists(0 until t.size)(j => s(m) == t(j)))) res = false Deduce(|-(res == All(0 until m+1)(i => Exists(0 until t.size)(j => s(i) == t(j))))) } Deduce(|-(res == All(0 until m+1)(i => Exists(0 until t.size)(j => s(i) == t(j))))) m = m+1 Deduce(|-(res == All(0 until m)(i => Exists(0 until t.size)(j => s(i) == t(j))))) } return res } def merge(s: ISZ[Z], t: ISZ[Z]): ISZ[Z] = { Contract( Requires(sorted(s), sorted(t)), Ensures(contained(s, Res), contained(t, Res), sorted(Res)) ) var res = ISZ[Z]() var x = 0 var y = 0 while (x < s.size & y < t.size) { if (s(x) < t(y)) { res = res :+ s(x) x = x+1 } else { res = res :+ t(y) y = y+1 } } while (x < s.size) { res = res :+ s(x) x = x+1 } while (y < t.size) { res = res :+ t(y) y = y+1 } return res } def merge_with_proof(s: ISZ[Z], t: ISZ[Z]): ISZ[Z] = { Contract( Requires(sorted(s), sorted(t)), Ensures(contained(s, Res), contained(t, Res), sorted(Res)) ) var res = ISZ[Z]() var x = 0 var y = 0 var z = 0 while (x < s.size & y < t.size) { Invariant( Modifies(x, y, res), x >= 0, x <= s.size, y >= 0, y <= t.size, z == res.size, All(0 until x)(i => Exists(0 until z)(j => s(i) == res(j))), All(0 until y)(i => Exists(0 until z)(j => t(i) == res(j))), (z == 0 | x == s.size) || res(z-1) <= s(x), (z == 0 | y == t.size) || res(z-1) <= t(y), All(1 until z)(i => res(i - 1) <= res(i)) ) if (s(x) < t(y)) { res = res :+ s(x) Deduce(|- (s(x) == res(z))) Deduce(|- (Exists(0 until z+1)(j => s(x) == res(j)))) z = z + 1 Deduce(|- (All(0 until x+1)(i => Exists(0 until z)(j => s(i) == res(j))))) x = x+1 } else { res = res :+ t(y) Deduce(|- (t(y) == res(z))) Deduce(|- (Exists(0 until z+1)(j => t(y) == res(j)))) Deduce(|- (All(1 until z+1)(i => res(i - 1) <= res(i)))) z = z+1 Deduce(|- (All(0 until y+1)(i => Exists(0 until z)(j => t(i) == res(j))))) y = y+1 } Deduce(|- (All(0 until x)(i => Exists(0 until z)(j => s(i) == res(j))))) Deduce(|- (All(0 until y)(i => Exists(0 until z)(j => t(i) == res(j))))) //Deduce(|- (z == 0 || res(z-1) <= s(x))) } while (x < s.size) { Invariant( Modifies(x, res), x >= 0, x <= s.size, z == res.size, All(0 until x)(i => Exists(0 until z)(j => s(i) == res(j))) ) res = res :+ s(x) Deduce(|-(s(x) == res(z))) Deduce(|-(Exists(0 until z + 1)(j => s(x) == res(j)))) z = z+1 Deduce(|- (All(0 until x+1)(i => Exists(0 until z)(j => s(i) == res(j))))) x = x+1 } while (y < t.size) { Invariant( Modifies(y, res), y >= 0, y <= t.size, z == res.size, All(0 until y)(i => Exists(0 until z)(j => t(i) == res(j))) ) res = res :+ t(y) Deduce(|-(t(y) == res(z))) Deduce(|-(Exists(0 until z + 1)(j => t(y) == res(j)))) z = z+1 Deduce(|- (All(0 until y+1)(i => Exists(0 until z)(j => t(i) == res(j))))) y = y+1 } return res }

Quantification

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // #Sireum #Logika import org.sireum._ assert(All(0 until 10)(i => i >= 0 & i < 10)) var x: Z = 0 while (x < 10) { assert(Exists(0 until 10)(i => i == x)) } def allex_seq(s: ISZ[B]) { Contract( Requires(!s.isEmpty) ) assert(!All(0 until s.size)(i => s(i)) | Exists(0 until s.size)(i => s(i))) }

Searching

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 // #Sireum #Logika import org.sireum._ @pure def sorted(seq: ISZ[Z]): B = { Contract( Ensures(Res == All(1 until seq.size)(i => seq(i - 1) <= seq(i))) ) if (seq.size == 0) { return true } else { var res: B = true; var k: Z = 1; while (k < seq.size) { Invariant( Modifies(k, res), k >= 1, k <= seq.size, res == All(1 until k)(i => seq(i - 1) <= seq(i)), ) if (seq(k - 1) > seq(k)) { res = false } k = k + 1 } return res } } @pure def sorted_upper_bound(seq: ISZ[Z], i: Z, b: Z): B = { Contract( Requires(sorted(seq), 0 <= i, i < seq.size, seq(i) <= b), Ensures(Res == All(0 until i)(k => seq(k) <= b) & Res == true) ) var j: Z = i while (j > 0) { Invariant( Modifies(j), 0 <= j, j < seq.size, seq(j) <= b, All(j until i)(k => seq(k) <= b) ) j = j-1 } return true } @pure def sorted_lower_bound(seq: ISZ[Z], i: Z, b: Z): B = { Contract( Requires(sorted(seq), 0 <= i, i < seq.size, b < seq(i)), Ensures(Res == All(i until seq.size)(k => b < seq(k)) & Res == true) ) var j: Z = i while (j < seq.size-1) { Invariant( Modifies(j), 0 <= j, j < seq.size, b < seq(j), All(i until j)(k => b < seq(k)) ) j = j+1 } return true } @pure def linsearch(seq: ISZ[Z], v: Z): Option[Z] = { Contract( Requires(sorted(seq)), Ensures( (Res == None[Z]()) | Exists(0 until seq.size)(i => seq(i) == v & Res == Some(i))) ) var res: Option[Z] = None() var k: Z = 0 while (k < seq.size) { Invariant( Modifies(res, k), k >= 0, k <= seq.size, (res == None[Z]()) | Exists(0 until k)(i => seq(i) == v & res == Some(i)) ) Deduce(|-((res == None[Z]()) | Exists(0 until k)(i => seq(i) == v & res == Some(i)))) if (seq(k) == v) { res = Some(k) Deduce(|-(res == None[Z]() | Exists(0 until k + 1)(i => seq(i) == v & res == Some(i)))) } else { Deduce(|-(res == None[Z]() | Exists(0 until k)(i => seq(i) == v & res == Some(i)))) } Deduce(|-(res == None[Z]() | Exists(0 until k + 1)(i => seq(i) == v & res == Some(i)))) k = k + 1 Deduce(|-(res == None[Z]() | Exists(0 until k)(i => seq(i) == v & res == Some(i)))) } return res } @pure def binsearch(seq: ISZ[Z], v: Z): Option[Z] = { Contract( Requires(sorted(seq)), Ensures( (Res == None[Z]()) | Exists(0 until seq.size)(i => seq(i) == v & Res == Some(i))) ) if (seq.isEmpty) { return None() } else { Deduce(|-(seq.size > 0)) if (seq.size == 1) { Deduce(|- (0 < seq.size)) if (seq(0) == v) { return Some(0) } else { return None() } } var x: Z = 0 var y: Z = seq.size - 1 if (v < seq(x) | seq(y) < v) { return None() } else { if (seq(y) == v) { return Some(y) } else { while (x + 1 != y) { Invariant( Modifies(x, y), x >= 0, y < seq.size, x < y, seq(x) <= v, v < seq(y), All(0 until x)(i => seq(i) <= v), All(y until seq.size)(i => v < seq(i)) ) Deduce(|- (All(0 until x)(i => seq(i) <= v))) val h: Z = (x + y) / 2 Deduce(|- (x <= h)) Deduce(|- (h < y)) if (seq(h) <= v) { Deduce(|- (sorted_upper_bound(seq, h, v))) Deduce(|- (All(0 until h)(i => seq(i) <= v))) x = h } else { Deduce(|- (sorted_lower_bound(seq, h, v))) Deduce(|- (All(y until seq.size)(i => v < seq(i)))) y = h } } if (seq(x) == v) { return Some(x) } else { return None() } } } } } def merge(s: ISZ[Z], t: ISZ[Z]): ISZ[Z] = { }

Sequences

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 // #Sireum #Logika import org.sireum._ val empty: ISZ[Z] = ISZ() val seq1: ISZ[Z] = ISZ(1) val seq2: ISZ[Z] = ISZ(2) val seq12: ISZ[Z] = ISZ(1, 2) val seq21: ISZ[Z] = ISZ(2, 1) val seq23: ISZ[Z] = ISZ(2, 3) val seq123: ISZ[Z] = ISZ(1, 2, 3) val seq34: ISZ[Z] = ISZ(3, 4) val seq1234: ISZ[Z] = ISZ(1, 2, 3, 4) assert(empty.isEmpty) // empty / non empty assert(!seq1.isEmpty) // ... assert(seq1.nonEmpty) // ... assert(empty.size == 0) // size assert(seq1.size == 1) // size assert(seq12.size == 2) // size assert(empty :+ 1 == seq1) // append assert(seq2 :+ 1 == seq21) // append assert(1 +: seq2 == seq12) // prepend assert(seq12 ++ seq34 == seq1234) assert(seq12(0 ~> seq12(1), 1 ~> seq12(0)) == seq21) // simultaneoud update, here: "swap" def rev[E](s: ISZ[E]): ISZ[E] = { var k: Z = 0 var res = ISZ[E]() while (k < s.size) { res = s(k) +: res k = k + 1 } return res } // Using interprocedural check: //assert(rev(seq12) == seq21) // With quantification: def rev_contract[E](s: ISZ[E]): ISZ[E] = { Contract( Ensures(Res.size == s.size & All(0 until s.size)(i => Res(i) == s(s.size - i - 1))) ) var k: Z = 0 var res = ISZ[E]() while (k < s.size) { Invariant( Modifies(k, res), k >= 0, k <= s.size, res.size == k, All(0 until k)(i => res(i) == s(k - i - 1)) ) res = s(k) +: res Deduce(|- (res(0) == s(k))) Deduce(|- (All(1 until k+1)(i => res(i) == s(k - i)))) Deduce(|- (All(0 until k+1)(i => res(i) == s(k - i)))) k = k + 1 } return res } assert(rev_contract(seq12) == seq21)

### Summary

• So Far…

• Initial Scheme concepts
• Crash course on syntax