----------------------------------------------------------------------------- -- | -- Module : Documentation.SBV.Examples.Uninterpreted.Deduce -- Copyright : (c) Levent Erkok -- License : BSD3 -- Maintainer: erkokl@gmail.com -- Stability : experimental -- -- Demonstrates uninterpreted sorts and how they can be used for deduction. -- This example is inspired by the discussion at <http://stackoverflow.com/questions/10635783/using-axioms-for-deductions-in-z3>, -- essentially showing how to show the required deduction using SBV. ----------------------------------------------------------------------------- {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_GHC -Wall -Werror #-} module Documentation.SBV.Examples.Uninterpreted.Deduce where import Data.SBV -- we will have our own "uninterpreted" functions corresponding -- to not/or/and, so hide their Prelude counterparts. import Prelude hiding (not, or, and) ----------------------------------------------------------------------------- -- * Representing uninterpreted booleans ----------------------------------------------------------------------------- -- | The uninterpreted sort 'B', corresponding to the carrier. data B -- | Make this sort uninterpreted. This splice will automatically introduce -- the type 'SB' into the environment, as a synonym for 'SBV' 'B'. mkUninterpretedSort ''B ----------------------------------------------------------------------------- -- * Uninterpreted connectives over 'B' ----------------------------------------------------------------------------- -- | Uninterpreted logical connective 'and' and :: SB -> SB -> SB and :: SB -> SB -> SB and = forall a. Uninterpreted a => String -> a uninterpret String "AND" -- | Uninterpreted logical connective 'or' or :: SB -> SB -> SB or :: SB -> SB -> SB or = forall a. Uninterpreted a => String -> a uninterpret String "OR" -- | Uninterpreted logical connective 'not' not :: SB -> SB not :: SB -> SB not = forall a. Uninterpreted a => String -> a uninterpret String "NOT" ----------------------------------------------------------------------------- -- * Axioms of the logical system ----------------------------------------------------------------------------- -- | Distributivity of OR over AND, as an axiom in terms of -- the uninterpreted functions we have introduced. Note how -- variables range over the uninterpreted sort 'B'. ax1 :: [String] ax1 :: [String] ax1 = [ String "(assert (forall ((p B) (q B) (r B))" , String " (= (AND (OR p q) (OR p r))" , String " (OR p (AND q r)))))" ] -- | One of De Morgan's laws, again as an axiom in terms -- of our uninterpeted logical connectives. ax2 :: [String] ax2 :: [String] ax2 = [ String "(assert (forall ((p B) (q B))" , String " (= (NOT (OR p q))" , String " (AND (NOT p) (NOT q)))))" ] -- | Double negation axiom, similar to the above. ax3 :: [String] ax3 :: [String] ax3 = [String "(assert (forall ((p B)) (= (NOT (NOT p)) p)))"] ----------------------------------------------------------------------------- -- * Demonstrated deduction ----------------------------------------------------------------------------- -- | Proves the equivalence @NOT (p OR (q AND r)) == (NOT p AND NOT q) OR (NOT p AND NOT r)@, -- following from the axioms we have specified above. We have: -- -- >>> test -- Q.E.D. test :: IO ThmResult test :: IO ThmResult test = forall a. Provable a => a -> IO ThmResult prove forall a b. (a -> b) -> a -> b $ do forall (m :: * -> *). SolverContext m => String -> [String] -> m () addAxiom String "OR distributes over AND" [String] ax1 forall (m :: * -> *). SolverContext m => String -> [String] -> m () addAxiom String "de Morgan" [String] ax2 forall (m :: * -> *). SolverContext m => String -> [String] -> m () addAxiom String "double negation" [String] ax3 SB p <- forall a. SymVal a => String -> Symbolic (SBV a) free String "p" SB q <- forall a. SymVal a => String -> Symbolic (SBV a) free String "q" SB r <- forall a. SymVal a => String -> Symbolic (SBV a) free String "r" forall (m :: * -> *) a. Monad m => a -> m a return forall a b. (a -> b) -> a -> b $ SB -> SB not (SB p SB -> SB -> SB `or` (SB q SB -> SB -> SB `and` SB r)) forall a. EqSymbolic a => a -> a -> SBool .== (SB -> SB not SB p SB -> SB -> SB `and` SB -> SB not SB q) SB -> SB -> SB `or` (SB -> SB not SB p SB -> SB -> SB `and` SB -> SB not SB r)