sbv-13.4: Documentation/SBV/Examples/TP/Reverse.hs
-----------------------------------------------------------------------------
-- |
-- Module : Documentation.SBV.Examples.TP.Reverse
-- Copyright : (c) Levent Erkok
-- License : BSD3
-- Maintainer: erkokl@gmail.com
-- Stability : experimental
--
-- Can we define the reverse function using no auxiliary functions, i.e., only
-- in terms of cons, head, tail, and itself (recursively)? This example
-- shows such a definition and proves that it is correct.
--
-- See Zohar Manna's 1974 "Mathematical Theory of Computation" book, where this
-- definition and its proof is presented as Example 5.36.
-----------------------------------------------------------------------------
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -Wall -Werror #-}
module Documentation.SBV.Examples.TP.Reverse where
import Prelude hiding (head, tail, null, reverse, length, init, last, (++))
import Data.SBV
import Data.SBV.List hiding (partition)
import Data.SBV.TP
import qualified Documentation.SBV.Examples.TP.Lists as TP
#ifdef DOCTEST
-- $setup
-- >>> :set -XTypeApplications
-- >>> import Data.SBV.TP
#endif
-- * Reversing with no auxiliaries
-- | This definition of reverse uses no helper functions, other than the usual
-- head, tail, cons, and uncons to reverse a given list. Note that efficiency
-- is not our concern here, we call 'rev' itself three times in the body.
rev :: SymVal a => SList a -> SList a
rev = smtFunction "rev" $ \xs -> ite (null xs .|| null (tail xs)) xs
(let (x, as) = uncons xs
(hras, tas) = uncons (rev as)
in hras .: rev (x .: rev tas))
-- * Correctness proof
-- | Correctness the function 'rev'. We have:
--
-- >>> runTP $ correctness @Integer
-- Lemma: revLen Q.E.D.
-- Lemma: revApp Q.E.D.
-- Lemma: revSnoc Q.E.D.
-- Lemma: revRev Q.E.D.
-- Inductive lemma (strong): revCorrect
-- Step: Measure is non-negative Q.E.D.
-- Step: 1 (2 way full case split)
-- Step: 1.1 Q.E.D.
-- Step: 1.2 (2 way full case split)
-- Step: 1.2.1 Q.E.D.
-- Step: 1.2.2.1 Q.E.D.
-- Step: 1.2.2.2 Q.E.D.
-- Step: 1.2.2.3 Q.E.D.
-- Step: 1.2.2.4 Q.E.D.
-- Step: 1.2.2.5 Q.E.D.
-- Step: 1.2.2.6 (simplify head) Q.E.D.
-- Step: 1.2.2.7 Q.E.D.
-- Step: 1.2.2.8 (simplify tail) Q.E.D.
-- Step: 1.2.2.9 Q.E.D.
-- Step: 1.2.2.10 Q.E.D.
-- Step: 1.2.2.11 Q.E.D.
-- Step: 1.2.2.12 (substitute) Q.E.D.
-- Step: 1.2.2.13 Q.E.D.
-- Step: 1.2.2.14 Q.E.D.
-- Step: 1.2.2.15 Q.E.D.
-- Result: Q.E.D.
-- [Proven] revCorrect :: Ɐxs ∷ [Integer] → Bool
correctness :: forall a. SymVal a => TP (Proof (Forall "xs" [a] -> SBool))
correctness = do
-- Quietly import a few helpers from "Data.SBV.TP.List"
revLen <- recall "revLen" $ TP.revLen @a
revApp <- recall "revApp" $ TP.revApp @a
revSnoc <- recall "revSnoc" $ TP.revSnoc @a
revRev <- recall "revRev" $ TP.revRev @a
sInductWith cvc5 "revCorrect"
(\(Forall xs) -> rev xs .== reverse xs)
(length, []) $
\ih xs -> [] |- rev xs
=: split xs trivial
(\a as -> split as trivial
(\_ _ -> head (rev as) .: rev (a .: rev (tail (rev as)))
?? ih `at` Inst @"xs" as
=: head (reverse as) .: rev (a .: rev (tail (rev as)))
?? ih `at` Inst @"xs" as
=: head (reverse as) .: rev (a .: rev (tail (reverse as)))
?? ih `at` Inst @"xs" (tail (rev as))
=: head (reverse as) .: rev (a .: rev (tail (reverse as)))
?? revSnoc `at` (Inst @"x" (last as), Inst @"xs" (init as))
=: let w = init as
b = last as
in head (b .: reverse w) .: rev (a .: rev (tail (reverse as)))
?? "simplify head"
=: b .: rev (a .: rev (tail (reverse as)))
?? revSnoc `at` (Inst @"x" (last xs), Inst @"xs" (init as))
=: b .: rev (a .: rev (tail (b .: reverse w)))
?? "simplify tail"
=: b .: rev (a .: rev (reverse w))
?? ih `at` Inst @"xs" (reverse w)
?? revLen `at` Inst @"xs" w
=: b .: rev (a .: reverse (reverse w))
?? revRev `at` Inst @"xs" w
=: b .: rev (a .: w)
?? ih
=: b .: reverse (a .: w)
?? "substitute"
=: last as .: reverse (a .: init as)
?? revApp `at` (Inst @"xs" (a .: init as), Inst @"ys" [last as])
=: reverse (a .: init as ++ [last as])
=: reverse (a .: as)
=: reverse xs
=: qed))
{- HLint ignore correctness "Use last" -}
{- HLint ignore correctness "Redundant reverse" -}