packages feed

sbv-14.4: Documentation/SBV/Examples/TP/SumReverse.hs

-----------------------------------------------------------------------------
-- |
-- Module    : Documentation.SBV.Examples.TP.SumReverse
-- Copyright : (c) Levent Erkok
-- License   : BSD3
-- Maintainer: erkokl@gmail.com
-- Stability : experimental
--
-- Proves @sum (reverse xs) == sum xs@.
-----------------------------------------------------------------------------

{-# LANGUAGE CPP                 #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE OverloadedLists     #-}

{-# OPTIONS_GHC -Wall -Werror #-}

module Documentation.SBV.Examples.TP.SumReverse where

import Prelude hiding ((++), foldr, sum, reverse)

import Data.SBV
import Data.SBV.TP
import Data.SBV.List


#ifdef DOCTEST
-- $setup
-- >>> :set -XFlexibleContexts
-- >>> :set -XTypeApplications
#endif

-- | @sum (reverse xs) = sum xs@
--
-- >>> revSum @Integer
-- Inductive lemma: sumAppend
--   Step: Base                   Q.E.D.
--   Step: 1                      Q.E.D.
--   Step: 2                      Q.E.D.
--   Step: 3                      Q.E.D.
--   Step: 4 (associativity)      Q.E.D.
--   Step: 5                      Q.E.D.
--   Result:                      Q.E.D.
-- Inductive lemma: sumReverse
--   Step: Base                   Q.E.D.
--   Step: 1                      Q.E.D.
--   Step: 2                      Q.E.D.
--   Step: 3                      Q.E.D.
--   Step: 4 (commutativity)      Q.E.D.
--   Step: 5                      Q.E.D.
--   Result:                      Q.E.D.
-- Functions proven terminating: sbv.foldr, sbv.reverse
-- [Proven] sumReverse :: Ɐxs ∷ [Integer] → Bool
revSum :: forall a. (SymVal a, Num (SBV a)) => IO (Proof (Forall "xs" [a] -> SBool))
revSum = runTP $ do

  -- helper: sum distributes over append.
  sumAppend <- induct "sumAppend"
                      (\(Forall xs) (Forall ys) -> sum (xs ++ ys) .== sum xs + sum ys) $
                      \ih (x, xs) ys -> [] |- sum ((x .: xs) ++ ys)
                                           =: sum (x .: (xs ++ ys))
                                           =: x + sum (xs ++ ys)
                                           ?? ih
                                           =: x + (sum xs + sum ys)
                                           ?? "associativity"
                                           =: (x + sum xs) + sum ys
                                           =: sum (x .: xs) + sum ys
                                           =: qed

  -- Now prove the original theorem by induction
  induct "sumReverse"
         (\(Forall xs) -> sum (reverse xs) .== sum xs) $
         \ih (x, xs) -> [] |- sum (reverse (x .: xs))
                           =: sum (reverse xs ++ [x])
                           ?? sumAppend `at` (Inst @"xs" (reverse xs), Inst @"ys" [x])
                           =: sum (reverse xs) + sum [x]
                           ?? ih
                           =: sum xs + x
                           ?? "commutativity"
                           =: x + sum xs
                           =: sum (x .: xs)
                           =: qed