packages feed

sbv-9.0: Documentation/SBV/Examples/Misc/Definitions.hs

-----------------------------------------------------------------------------
-- |
-- Module    : Documentation.SBV.Examples.Misc.Definitions
-- Copyright : (c) Levent Erkok
-- License   : BSD3
-- Maintainer: erkokl@gmail.com
-- Stability : experimental
--
-- Demonstrates how we can add actual SMT-definitions for functions
-- that cannot otherwise be defined in SBV. Typically, these are used
-- for recursive definitions.
-----------------------------------------------------------------------------

{-# OPTIONS_GHC -Wall -Werror #-}

module Documentation.SBV.Examples.Misc.Definitions where

import Data.SBV

-- | Sum of numbers from 0 to the given number.
-- Note that this cannot be defined as a regular Haskell function, as
-- it wouldn't terminate as it recurses on a symbolic argument.
sumToN :: SInteger -> SInteger
sumToN = uninterpret "sumToN"

-- | Add the definition of sum to the SMT solver. Note that SBV
-- performs no checks on your definition, neither that it is
-- well formed, or even has the correct type!
defineSum :: Symbolic ()
defineSum = addSMTDefinition "sumToN"
                [ "(define-fun-rec sumToN ((x Int)) Int"
                , "                (ite (<= x 0)"
                , "                     0"
                , "                     (+ x (sumToN (- x 1)))))"
                ]

-- | A simple proof using 'sumToN'. We get a failure, because we haven't
-- given the solver the definition, and thus it goes completely uninterpreted.
--
-- We have:
--
-- >>> badExample
-- Falsifiable. Counter-example:
--   sumToN :: Integer -> Integer
--   sumToN _ = 0
--
-- Since 'sumToN' remains uninterpreted, the solver gave us a model that obviously
-- fails the property.
badExample :: IO ThmResult
badExample = prove $ do
        let check = sumToN 5 .== 15  -- Should fail, even though 5*6/2 = 15
        pure check :: Predicate

-- | Same example, except this time we give the solver the definition of the function,
-- and thus the proof goes through.
--
-- We have:
--
-- >>> goodExample
-- Q.E.D.
--
-- In this case, the solver has the definition, and proves the predicate as expected.
goodExample :: IO ThmResult
goodExample = prove $ do
        defineSum
        let check = sumToN 5 .== 15  -- Should fail, even though 5*6/2 = 15
        pure check :: Predicate