Abstract Refinements {#induction}
=================================
Induction
---------
Encoding *induction* with Abstract refinements
\begin{code}
module Loop where
import Prelude hiding ((!!), foldr, length, (++))
-- import Measures
import Language.Haskell.Liquid.Prelude
{-@ LIQUID "--no-termination" @-}
{-@ measure llen  :: (L a) -> Int
    llen (N)      = 0
    llen (C x xs) = 1 + (llen xs)  @-}
size  :: L a -> Int
add   :: Int -> Int -> Int
loop  :: Int -> Int -> α -> (Int -> α -> α) -> α
foldr :: (L a -> a -> b -> b) -> b -> L a -> b
\end{code}
Induction
=========
Example: `loop` redux 
---------------------
Recall the *higher-order* `loop` 
\begin{code}
loop lo hi base f = go lo base
  where 
    go i acc 
      | i < hi    = go (i+1) (f i acc)
      | otherwise = acc
\end{code}
Iteration Dependence
--------------------
We used `loop` to write 
\begin{code} 
{-@ add :: n:Nat -> m:Nat -> {v:Nat|v=m+n} @-}
add n m = loop 0 m n (\_ i -> i + 1)
\end{code}
**Problem**
- As property only holds after *last* loop iteration...
- ... cannot instantiate `α` with `{v:Int | v = n + m}`
Iteration Dependence
--------------------
We used `loop` to write 
\begin{code} 
{-@ add :: n:Nat -> m:Nat -> {v:Nat|v=m+n} @-}
add n m = loop 0 m n (\_ i -> i + 1)
\end{code}
**Problem** 
Need invariant relating *iteration* `i` with *accumulator* `acc`
Iteration Dependence
--------------------
We used `loop` to write 
\begin{code} 
{-@ add :: n:Nat -> m:Nat -> {v:Nat|v=m+n} @-}
add n m = loop 0 m n (\_ i -> i + 1)
\end{code}
**Solution** 
- Abstract Refinement `p :: Int -> a -> Prop`
- `(p i acc)` relates *iteration* `i` with *accumulator* `acc`
Induction in `loop` (by hand)
-----------------------------
\begin{code} 
 
loop lo hi base f = go lo base
  where 
    go i acc 
      | i < hi    = go (i+1) (f i acc)
      | otherwise = acc
\end{code}
------------  ---   ----------------------------
  **Assume**   :    `out = loop lo hi base f` 
   **Prove**   :    `(p hi out)`
------------  ---   ----------------------------
 
Induction in `loop` (by hand)
-----------------------------
\begin{code} 
 
loop lo hi base f = go lo base
  where 
    go i acc 
      | i < hi    = go (i+1) (f i acc)
      | otherwise = acc
\end{code}
**Base Case** Initial accumulator `base` satisfies invariant
`(p base lo)`   
Induction in `loop` (by hand)
-----------------------------
\begin{code} 
 
loop lo hi base f = go lo base
  where 
    go i acc 
      | i < hi    = go (i+1) (f i acc)
      | otherwise = acc
\end{code}
**Inductive Step** `f` *preserves* invariant at `i`
`(p acc i) => (p (f i acc) (i + 1))`
Induction in `loop` (by hand)
-----------------------------
\begin{code} 
 
loop lo hi base f = go lo base
  where 
    go i acc 
      | i < hi    = go (i+1) (f i acc)
      | otherwise = acc
\end{code}
**"By Induction"** `out` satisfies invariant at `hi` 
`(p out hi)`
Induction in `loop` (by type)
-----------------------------
Induction is an **abstract refinement type** for `loop` 
\begin{code}
{-@ loop :: forall a  a -> Prop>.
        lo:Int 
     -> hi:{v:Int|lo <= v}
     -> base:a
                      
     -> f:(i:Int -> a
 -> a
) 
     -> a
                           @-}
\end{code}
Induction in `loop` (by type)
-----------------------------
`p` is the *index dependent* invariant!
\begin{code}
 
p    :: Int -> a -> Prop             -- invt 
base :: a
                      -- base 
f    :: i:Int -> a
 -> a
 -- step
out  :: a
                      -- goal
\end{code}
Using Induction
---------------
\begin{code}
{-@ add :: n:Nat -> m:Nat -> {v:Nat| v=m+n} @-}
add n m = loop 0 m n (\_ z -> z + 1)
\end{code}
**Verified** by instantiating the abstract refinement of `loop`
`p := \i acc -> acc = i + n`
Using Induction
---------------
\begin{code} 
{-@ add :: n:Nat -> m:Nat -> {v:Nat| v=m+n} @-}
add n m = loop 0 m n (\_ z -> z + 1)
\end{code}
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
--------------
\begin{code}
data L a = N 
         | C a (L a)
\end{code}
Lets write a generic loop over such lists ...
Example: `foldr`
----------------
\begin{code} 
foldr f b N        = b
foldr f b (C x xs) = f xs x (foldr f b xs)
\end{code}
Lets brace ourselves for the type...
Example: `foldr`
----------------
\begin{code}
{-@ foldr :: 
    forall a b  b -> Prop>. 
      (xs:_ -> x:_ -> b
 -> b
) 
    -> b
 
    -> ys:L a
    -> b
                            @-}
foldr f b N        = b
foldr f b (C x xs) = f xs x (foldr f b xs)
\end{code}
Lets step through the type...
`foldr`: Abstract Refinement
----------------------------
\begin{code} 
p    :: L a -> b -> Prop   
step :: xs:_ -> x:_ -> b -> b
 
base :: b
 
ys   :: L a
out  ::  b
                            
\end{code}
`(p xs b)` relates `b` with folded `xs`
`p :: L a -> b -> Prop`
`foldr`: Base Case
------------------
\begin{code} 
p    :: L a -> b -> Prop   
step :: xs:_ -> x:_ -> b -> b
 
base :: b
 
ys   :: L a
out  :: b
                            
\end{code}
`base` is related to empty list `N`
`base :: b
` states 
`foldr`: Ind. Step 
------------------
\begin{code} 
p    :: L a -> b -> Prop   
step :: xs:_ -> x:_ -> b -> b
 
base :: b
 
ys   :: L a
out  :: b
                            
\end{code}
`step` extends relation from `xs` to `C x xs`
`step :: xs:L a -> x:a -> b
 -> b
`
`foldr`: Output
---------------
\begin{code} 
p    :: L a -> b -> Prop   
step :: xs:_ -> x:_ -> b -> b
 
base :: b
 
ys   :: L a
out  :: b
                            
\end{code}
Relation holds between `out` and input list `ys`
`out :: b
`
Using `foldr`: Size
-------------------
We can now verify 
\begin{code}
{-@ size :: xs:_ -> {v:Int| v = (llen xs)} @-}
size     = foldr (\_ _ n -> n + 1) 0
\end{code}
Verified by automatically instantiating 
`p := \xs acc -> acc = (llen xs)`
Using `foldr`: Append
---------------------
\begin{code}
{-@ (++) :: xs:_ -> ys:_ -> (Cat a xs ys) @-} 
xs ++ ys = foldr (\_ -> C) ys xs 
\end{code}
where the alias `Cat` is:
\begin{code}
{-@ type Cat a X Y = 
    {v:L a|(llen v) = (llen X) + (llen Y)} @-}
\end{code}
Using `foldr`: Append
---------------------
\begin{code} 
{-@ (++) :: xs:_ -> ys:_ -> (Cat a xs ys) @-} 
xs ++ ys = foldr (\_ -> C) ys xs 
\end{code}
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*