packages feed

liquidhaskell-0.8.10.7: benchmarks/popl18/ple/pos/Fibonacci.hs

{-@ LIQUID "--higherorder"     @-}	
{-@ LIQUID "--ple" @-}

-- TAG: absref

module Fibonacci where
import Language.Haskell.Liquid.ProofCombinators


-- | Proves that the fibonacci function is increasing


-- | Definition of the function in Haskell
-- | the annotation axiomatize means that
-- | in the logic, the body of increase is known
-- | (each time the function fib is applied,
-- | there is an unfold in the logic)

{-@ reflect fib @-}

fib :: Int -> Int
{-@ fib :: i:Nat -> Nat @-}
fib i | i == 0    = 0
      | i == 1    = 1
      | otherwise = fib (i-1) + fib (i-2)

{-@ fib1 :: () -> {fib 16 == 987 } @-}
fib1 :: () -> Proof
fib1 _ = trivial

fibUp :: Int -> Proof
{-@ fibUp :: i:Nat -> {fib i <= fib (i+1)} @-}
fibUp i
  | i == 0
  =   [fib 0, fib 1] *** QED
  | i == 1
  =  [fib 1, fib 0, fib 2] *** QED
  | otherwise
  = [[fib (i+1), fib i] *** QED , fibUp (i-1), fibUp (i-2)] *** QED
{-
  | otherwise
  =   fibUp (i-1)
  &&& fibUp (i-2)
-}

-- 0, 1, 2, 3, 4, 5, 6, 7,   8,  9, 10, 11,  12, 13,   14,  15, 16
-- 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987


{-
FStar failing

val fib: x:int{x>=0} -> Tot int
let rec fib n =
  if n = 0 then 0
  else if n = 1 then 1 else fib (n-1) + fib (n-2)


val prop: x:int -> Tot (v:int {fib 15 = 610})
let prop x =  0

-}

-- | How to encode proofs:
-- | ==., <=., and <. stand for the logical ==, <=, < resp.
-- | If the proofs do not derive automatically, user can
-- | optionally provide the Proofean statements, after `?`
-- | Note, no inference occurs: logic only reasons about

{-
fibUp :: Int -> Proof
{-@ fibUp :: i:Nat -> {fib i <= fib (i+1)} @-}
fibUp i
  | i == 0
  =   trivial
  | i == 1
  =  trivial --  fib 2 *** QED
  | otherwise
  =   fibUp (i-1)
  &&& fibUp (i-2)
-}
{-
Explicit Proof
fibMonotonic x y
  | y == x + 1
  =   fib x
  <=. fib (x+1) ? fibUp x
  <=. fib y
  *** QED
  | x < y - 1
  =   fib x
  <=. fib (y-1) ? fibMonotonic x (y-1)
  <=. fib y     ? fibUp (y-1)
  *** QED

FStar Proof

val fibUp :i:int{0 <= i} -> Tot (v:int {fib i <= fib (i+1)})
let rec fibUp i =
    if i=0 then 0 else
    if i=1 then 1 else (fibUp (i-1) + fibUp (i-2))
-}


fibMonotonic :: Int -> Int -> Proof
{-@ fibMonotonic :: x:Nat -> y:{Nat | x < y }
     -> {fib x <= fib y}  / [y] @-}
fibMonotonic x y
  | y == x + 1
  =   fibUp x
  | x < y - 1
  =   fibMonotonic x (y-1)
  &&& fibUp (y-1)


fMono :: (Int -> Int)
      -> (Int -> Proof)
      -> Int -> Int -> Proof
{-@ fMono :: f:(Nat -> Int)
          -> fUp:(z:Nat -> {f z <= f (z+1)})
          -> x:Nat
          -> y:{Nat|x < y}
          -> {f x <= f y} / [y] @-}
fMono f fUp x y
  | x + 1 == y
  = fUp x
  | x + 1 < y
  =   fMono f fUp x (y-1)
  &&& fUp (y-1)


fibMonoHO :: Int -> Int -> Proof
{-@ fibMonoHO :: n:Nat -> m:{Nat | n < m }  -> {fib n <= fib m} @-}
fibMonoHO     = fMono fib fibUp

-- forall n:Nat. exists m: (n<m => exists m'. fib n <== m')
fibEx :: Int -> (Int, Proof) -> (Int, Proof)
{-@ fibEx :: n:Nat -> (m::Int, {v:Proof | n < m})
         -> (m'::Int, {v:Proof | fib n <= m' }) @-}
fibEx n (m, pf) = (fib m, fibMonoHO n m)