Abstract Refinements {#induction} ================================= Induction --------- Encoding *induction* with Abstract refinements Induction ========= Example: `loop` redux --------------------- Recall the *higher-order* `loop`
40: forall a <p :: (GHC.Types.Int)-> a-> Bool>.
lo:(Int)
-> hi:{VV : (Int) | (lo <= VV)}
-> {VV : a<p lo> | true}
-> (i:(Int)
    -> {VV : a<p i> | true}
    -> forall [ex:{VV : (Int) | (VV == (i + 1))}].{VV : a<p ex> | true})
-> {VV : a<p hi> | true}loop (Int)lo {VV : (Int) | (lo <= VV)}hi {VV : a | ((papp2 p VV lo))}base i:(Int)
-> {VV : a | ((papp2 p VV i))}
-> forall [ex:{VV : (Int) | (VV == (i + 1))}].{VV : a | ((papp2 p VV ex))}f = x1:{x4 : (Int) | (x4 >= lo) && (lo <= x4) && (x4 <= hi)}
-> {VV : a | ((papp2 p VV x1))} -> {VV : a | ((papp2 p VV hi))}go {x2 : (Int) | (x2 == lo)}lo {VV : a | ((papp2 p VV lo)) && (VV == base)}base
41:   where 
42:     i:{VV : (Int) | (VV >= lo) && (VV <= hi) && (lo <= VV)}
-> {VV : a | ((papp2 p VV i))} -> {VV : a | ((papp2 p VV hi))}go {VV : (Int) | (VV >= lo) && (VV <= hi) && (lo <= VV)}i {VV : a | ((papp2 p VV i))}acc 
43:       | {x5 : (Int) | (x5 == i) && (x5 >= lo) && (lo <= x5) && (x5 <= hi)}i x1:{x14 : (Int) | (x14 >= i) && (x14 >= lo) && (i <= x14) && (lo <= x14) && (x14 <= hi)}
-> x2:{x14 : (Int) | (x14 >= i) && (x14 >= lo) && (i <= x14) && (lo <= x14) && (x14 <= hi)}
-> {x2 : (Bool) | (((Prop x2)) <=> (x1 < x2))}< {x3 : (Int) | (x3 == hi) && (lo <= x3)}hi    = i:{VV : (Int) | (VV >= lo) && (VV <= hi) && (lo <= VV)}
-> {VV : a | ((papp2 p VV i))} -> {VV : a | ((papp2 p VV hi))}go ({x5 : (Int) | (x5 == i) && (x5 >= lo) && (lo <= x5) && (x5 <= hi)}ix1:(Int) -> x2:(Int) -> {x4 : (Int) | (x4 == (x1 + x2))}+{x2 : (Int) | (x2 == (1  :  int))}1) (x1:(Int)
-> {VV : a | ((papp2 p VV x1))}
-> forall [ex:{VV : (Int) | (VV == (x1 + 1))}].{VV : a | ((papp2 p VV ex))}f {x5 : (Int) | (x5 == i) && (x5 >= lo) && (lo <= x5) && (x5 <= hi)}i {VV : a | ((papp2 p VV i)) && (VV == acc)}acc)
44:       | otherwise = {VV : a | ((papp2 p VV i)) && (VV == acc)}acc
Iteration Dependence -------------------- We used `loop` to write
53: {-@ add :: n:Nat -> m:Nat -> {v:Nat|v=m+n} @-}
54: add n m = loop 0 m n (\_ i -> i + 1)

**Problem** - As property only holds after *last* loop iteration... - ... cannot instantiate `α` with `{v:Int | v = n + m}`
Iteration Dependence -------------------- We used `loop` to write
75: {-@ add :: n:Nat -> m:Nat -> {v:Nat|v=m+n} @-}
76: add n m = loop 0 m n (\_ i -> i + 1)

**Problem** Need invariant relating *iteration* `i` with *accumulator* `acc` Iteration Dependence -------------------- We used `loop` to write
92: {-@ add :: n:Nat -> m:Nat -> {v:Nat|v=m+n} @-}
93: add n m = loop 0 m n (\_ i -> i + 1)

**Solution** - Abstract Refinement `p :: Int -> a -> Prop` - `(p i acc)` relates *iteration* `i` with *accumulator* `acc` Induction in `loop` (by hand) -----------------------------
110: loop lo hi base f = go lo base
111:   where 
112:     go i acc 
113:       | i < hi    = go (i+1) (f i acc)
114:       | otherwise = acc

------------ --- ---------------------------- **Assume** : `out = loop lo hi base f` **Prove** : `(p hi out)` ------------ --- ----------------------------
Induction in `loop` (by hand) -----------------------------
136: loop lo hi base f = go lo base
137:   where 
138:     go i acc 
139:       | i < hi    = go (i+1) (f i acc)
140:       | otherwise = acc

**Base Case** Initial accumulator `base` satisfies invariant `(p base lo)` Induction in `loop` (by hand) -----------------------------
155: loop lo hi base f = go lo base
156:   where 
157:     go i acc 
158:       | i < hi    = go (i+1) (f i acc)
159:       | otherwise = acc

**Inductive Step** `f` *preserves* invariant at `i` `(p acc i) => (p (f i acc) (i + 1))` Induction in `loop` (by hand) -----------------------------
173: loop lo hi base f = go lo base
174:   where 
175:     go i acc 
176:       | i < hi    = go (i+1) (f i acc)
177:       | otherwise = acc

**"By Induction"** `out` satisfies invariant at `hi` `(p out hi)` Induction in `loop` (by type) ----------------------------- Induction is an **abstract refinement type** for `loop`
195: {-@ loop :: forall a <p :: Int -> a -> Prop>.
196:         lo:Int 
197:      -> hi:{v:Int|lo <= v}
198:      -> base:a<p lo>                      
199:      -> f:(i:Int -> a<p i> -> a<p (i+1)>) 
200:      -> a<p hi>                           @-}

Induction in `loop` (by type) ----------------------------- `p` is the *index dependent* invariant!
212: p    :: Int -> a -> Prop             -- invt 
213: base :: a<p lo>                      -- base 
214: f    :: i:Int -> a<p i> -> a<p(i+1)> -- step
215: out  :: a<p hi>                      -- goal
Using Induction ---------------
224: {-@ add :: n:Nat -> m:Nat -> {v:Nat| v=m+n} @-}
225: n:{VV : (Int) | (VV >= 0)}
-> m:{VV : (Int) | (VV >= 0)}
-> {VV : (Int) | (VV == (m + n)) && (VV >= 0)}add {VV : (Int) | (VV >= 0)}n {VV : (Int) | (VV >= 0)}m = forall <p :: (GHC.Types.Int)-> (GHC.Types.Int)-> Bool>.
x1:(Int)
-> x2:{x21 : (Int) | (x1 <= x21)}
-> {x19 : (Int)<p x1> | (x19 >= 0) && (x19 >= n) && (n <= x19)}
-> (i:(Int)
    -> {x19 : (Int)<p i> | (x19 >= 0) && (x19 >= n) && (n <= x19)}
    -> forall [ex:{VV : (Int) | (VV == (i + 1))}].{x19 : (Int)<p ex> | (x19 >= 0) && (x19 >= n) && (n <= x19)})
-> {x19 : (Int)<p x2> | (x19 >= 0) && (x19 >= n) && (n <= x19)}loop {x2 : (Int) | (x2 == (0  :  int))}0 {x3 : (Int) | (x3 == m) && (x3 >= 0)}m {x3 : (Int) | (x3 == n) && (x3 >= 0)}n (x1:(Int)
-> x2:{x17 : (Int) | (x17 == (x1 + n)) && (x17 == (n + x1)) && (x17 >= 0) && (x17 >= x1) && (x17 >= n) && (x1 <= x17) && (n <= x17)}
-> {x9 : (Int) | (x9 == (x2 + 1)) && (x9 > 0) && (x9 > x1) && (x9 > x2) && (x9 > n) && (x9 >= 0) && (x1 <= x9) && (n <= x9)}\_ {VV : (Int) | (VV >= 0) && (VV >= n) && (n <= VV)}z -> {x5 : (Int) | (x5 == z) && (x5 >= 0) && (x5 >= n) && (n <= x5)}z x1:(Int) -> x2:(Int) -> {x4 : (Int) | (x4 == (x1 + x2))}+ {x2 : (Int) | (x2 == (1  :  int))}1)

**Verified** by instantiating the abstract refinement of `loop` `p := \i acc -> acc = i + n` Using Induction ---------------
239: {-@ add :: n:Nat -> m:Nat -> {v:Nat| v=m+n} @-}
240: add n m = loop 0 m n (\_ z -> z + 1)

Verified by instantiating `p := \i acc -> acc = i + n` -
**Base:** `n = 0 + n`
-
**Step:** `acc = i + n => acc + 1 = (i + 1) + n`
-
**Goal:** `out = m + n`
Generalizes To Structures ------------------------- Same idea applies for induction over *structures* ... Structural Induction ==================== Example: Lists --------------
269: data L a = N 
270:          | C a (L a)

Lets write a generic loop over such lists ...
Example: `foldr` ----------------
283: foldr f b N        = b
284: foldr f b (C x xs) = f xs x (foldr f b xs)

Lets brace ourselves for the type...
Example: `foldr` ----------------
297: {-@ foldr :: 
298:     forall a b <p :: L a -> b -> Prop>. 
299:       (xs:_ -> x:_ -> b<p xs> -> b<p(C x xs)>) 
300:     -> b<p N> 
301:     -> ys:L a
302:     -> b<p ys>                            @-}
303: forall a b <p :: (Loop.L a)-> b-> Bool>.
(xs:(L a)
 -> x:a
 -> {VV : b<p xs> | true}
 -> forall [ex:{VV : (L a) | (VV == (Loop.C x xs))}].{VV : b<p ex> | true})
-> forall [ex:{VV : (L a) | (VV == (Loop.N))}].{VV : b<p ex> | true}
-> ys:(L a)
-> {VV : b<p ys> | true}foldr xs:(L a)
-> x:a
-> {VV : b | ((papp2 p VV xs))}
-> forall [ex:{VV : (L a) | (VV == (Loop.C x xs))}].{VV : b | ((papp2 p VV ex))}f forall [ex:{VV : (L a) | (VV == (Loop.N))}].{VV : a | ((papp2 p VV ex))}b N        = forall [ex:{VV : (L a) | (VV == (Loop.N))}].{VV : a | ((papp2 p VV ex))}b
304: foldr f b (C x xs) = x1:(L a)
-> x2:a
-> {VV : b | ((papp2 p VV x1))}
-> forall [ex:{VV : (L a) | (VV == (Loop.C x2 x1))}].{VV : b | ((papp2 p VV ex))}f {x2 : (L a) | (x2 == xs)}xs {VV : a | (VV == x)}x (forall <p :: (Loop.L a)-> b-> Bool>.
(xs:(L a)
 -> x:a
 -> {VV : b<p xs> | true}
 -> forall [ex:{VV : (L a) | (VV == (Loop.C x xs))}].{VV : b<p ex> | true})
-> forall [ex:{VV : (L a) | (VV == (Loop.N))}].{VV : b<p ex> | true}
-> x4:(L a)
-> {VV : b<p x4> | true}foldr x1:(L a)
-> x2:a
-> {VV : b | ((papp2 p VV x1))}
-> forall [ex:{VV : (L a) | (VV == (Loop.C x2 x1))}].{VV : b | ((papp2 p VV ex))}f forall [ex:{VV : (L a) | (VV == (Loop.N))}].{VV : a | ((papp2 p VV ex))}b {x2 : (L a) | (x2 == xs)}xs)

Lets step through the type...
`foldr`: Abstract Refinement ----------------------------
318: p    :: L a -> b -> Prop   
319: step :: xs:_ -> x:_ -> b<p xs> -> b<p(C x xs)> 
320: base :: b<p N> 
321: ys   :: L a
322: out  ::  b<p ys>                            

`(p xs b)` relates `b` with folded `xs` `p :: L a -> b -> Prop` `foldr`: Base Case ------------------
336: p    :: L a -> b -> Prop   
337: step :: xs:_ -> x:_ -> b<p xs> -> b<p(C x xs)> 
338: base :: b<p N> 
339: ys   :: L a
340: out  :: b<p ys>                            

`base` is related to empty list `N` `base :: b

` states `foldr`: Ind. Step ------------------

355: p    :: L a -> b -> Prop   
356: step :: xs:_ -> x:_ -> b<p xs> -> b<p(C x xs)> 
357: base :: b<p N> 
358: ys   :: L a
359: out  :: b<p ys>                            

`step` extends relation from `xs` to `C x xs` `step :: xs:L a -> x:a -> b

-> b` `foldr`: Output ---------------

373: p    :: L a -> b -> Prop   
374: step :: xs:_ -> x:_ -> b<p xs> -> b<p(C x xs)> 
375: base :: b<p N> 
376: ys   :: L a
377: out  :: b<p ys>                            

Relation holds between `out` and input list `ys` `out :: b

` Using `foldr`: Size ------------------- We can now verify

392: {-@ size :: xs:_ -> {v:Int| v = (llen xs)} @-}
393: forall a. xs:(L a) -> {VV : (Int) | (VV == (llen xs))}size     = forall <p :: (Loop.L a)-> (GHC.Types.Int)-> Bool>.
(xs:(L a)
 -> x:a
 -> {x12 : (Int)<p xs> | (x12 >= 0)}
 -> forall [ex:{VV : (L a) | (VV == (Loop.C x xs))}].{x12 : (Int)<p ex> | (x12 >= 0)})
-> forall [ex:{VV : (L a) | (VV == (Loop.N))}].{x12 : (Int)<p ex> | (x12 >= 0)}
-> x4:(L a)
-> {x12 : (Int)<p x4> | (x12 >= 0)}foldr (x1:(L a)
-> a
-> x3:{x8 : (Int) | (x8 == (llen x1)) && (x8 >= 0)}
-> {x5 : (Int) | (x5 == (x3 + 1)) && (x5 > 0) && (x5 > x3) && (x5 >= 0)}\_ _ {VV : (Int) | (VV >= 0)}n -> {x3 : (Int) | (x3 == n) && (x3 >= 0)}n x1:(Int) -> x2:(Int) -> {x4 : (Int) | (x4 == (x1 + x2))}+ {x2 : (Int) | (x2 == (1  :  int))}1) {x2 : (Int) | (x2 == (0  :  int))}0

Verified by automatically instantiating `p := \xs acc -> acc = (llen xs)`
Using `foldr`: Append ---------------------
408: {-@ (++) :: xs:_ -> ys:_ -> (Cat a xs ys) @-} 
409: (L a)xs forall a.
xs:(L a)
-> ys:(L a)
-> {VV : (L a) | ((llen VV) == ((llen xs) + (llen ys)))}++ (L a)ys = forall <p :: (Loop.L a)-> (Loop.L a)-> Bool>.
(xs:(L a)
 -> x:a
 -> {x8 : (L a)<p xs> | true}
 -> forall [ex:{VV : (L a) | (VV == (Loop.C x xs))}].{x8 : (L a)<p ex> | true})
-> forall [ex:{VV : (L a) | (VV == (Loop.N))}].{x8 : (L a)<p ex> | true}
-> x4:(L a)
-> {x8 : (L a)<p x4> | true}foldr ((L a)
-> a -> x3:(L a) -> {x2 : (L a) | ((llen x2) == (1 + (llen x3)))}\_ -> a -> x2:(L a) -> {x2 : (L a) | ((llen x2) == (1 + (llen x2)))}C) {x2 : (L a) | (x2 == ys)}ys {x2 : (L a) | (x2 == xs)}xs 

where the alias `Cat` is:
421: {-@ type Cat a X Y = 
422:     {v:L a|(llen v) = (llen X) + (llen Y)} @-}
Using `foldr`: Append ---------------------
431: {-@ (++) :: xs:_ -> ys:_ -> (Cat a xs ys) @-} 
432: xs ++ ys = foldr (\_ -> C) ys xs 

Verified by automatically instantiating `p := \xs acc -> llen acc = llen xs + llen ys`
Recap ----- Abstract refinements decouple *invariant* from *traversal*
+
*reusable* specifications for higher-order functions.
+
*automatic* checking and instantiation by SMT.
Recap ----- 1. **Refinements:** Types + Predicates 2. **Subtyping:** SMT Implication 3. **Measures:** Strengthened Constructors 4. **Abstract:** Refinements over Type Signatures + *Dependencies* +
*Induction*