sbv-12.1: SMT Based Verification: Symbolic Haskell theorem prover using SMT solving.
Copyright(c) Levent Erkok
LicenseBSD3
Maintainererkokl@gmail.com
Stabilityexperimental
Safe HaskellNone
LanguageHaskell2010

Data.SBV.TP

Description

A lightweight theorem proving like interface, built on top of SBV. Originally inspired by Philip Zucker's tool KnuckleDragger see http://github.com/philzook58/knuckledragger, though SBV's version is different in its scope and design significantly.

See the directory Documentation.SBV.Examples.TP for various examples.

Synopsis

Propositions and their proofs

type Proposition a = (QNot a, QuantifiedBool a, QSaturate Symbolic a, Skolemize (NegatesTo a), Satisfiable (Symbolic (SkolemsTo (NegatesTo a))), Constraint Symbolic (SkolemsTo (NegatesTo a)), Typeable a) Source #

A proposition is something SBV is capable of proving/disproving in TP.

data Proof a Source #

Proof for a property. This type is left abstract, i.e., the only way to create on is via a call to lemma/theorem etc., ensuring soundness. (Note that the trusted-code base here is still large: The underlying solver, SBV, and TP kernel itself. But this mechanism ensures we can't create proven things out of thin air, following the standard LCF methodology.)

Instances

Instances details
Typeable a => Show (Proof a) Source #

Show instance for Proof

Instance details

Defined in Data.SBV.TP.Utils

Methods

showsPrec :: Int -> Proof a -> ShowS #

show :: Proof a -> String #

showList :: [Proof a] -> ShowS #

proofOf :: Proof a -> ProofObj Source #

Get the underlying proof object

assumptionFromProof :: Proof a -> SBool Source #

Grab the underlying boolean in a proof. Useful in assumption contexts where we need a boolean

Getting the proof tree

rootOfTrust :: Proof a -> RootOfTrust Source #

Calculate the root of trust. The returned list of proofs, if any, will need to be sorry and quickcheck free to have the given proof to be sorry-free.

newtype RootOfTrust Source #

Keeping track of where the sorry originates from. Used in displaying dependencies.

Constructors

RootOfTrust (Maybe [ProofObj]) 

Instances

Instances details
Monoid RootOfTrust Source #

Trust forms a monoid

Instance details

Defined in Data.SBV.TP.Utils

Semigroup RootOfTrust Source #

Trust forms a semigroup

Instance details

Defined in Data.SBV.TP.Utils

Show RootOfTrust Source #

Show instance for RootOfTrust

Instance details

Defined in Data.SBV.TP.Utils

data ProofTree Source #

Dependencies of a proof, in a tree format.

Constructors

ProofTree ProofObj [ProofTree] 

showProofTree :: Bool -> Proof a -> String Source #

Display the proof tree as ASCII text. The first argument is if we should compress the tree, showing only the first use of any sublemma.

showProofTreeHTML :: Bool -> Maybe FilePath -> Proof a -> String Source #

Display the tree as an html doc for rendering purposes. The first argument is if we should compress the tree, showing only the first use of any sublemma. Second is the path (or URL) to external CSS file, if needed.

Adding axioms/definitions

axiom :: Proposition a => String -> a -> TP (Proof a) Source #

Accept the given definition as a fact. Usually used to introduce definitial axioms, giving meaning to uninterpreted symbols. Note that we perform no checks on these propositions, if you assert nonsense, then you get nonsense back. So, calls to axiom should be limited to definitions, or basic axioms (like commutativity, associativity) of uninterpreted function symbols.

Basic proofs

lemma :: Proposition a => String -> a -> [ProofObj] -> TP (Proof a) Source #

Prove a given statement, using auxiliaries as helpers. Using the default solver.

lemmaWith :: Proposition a => SMTConfig -> String -> a -> [ProofObj] -> TP (Proof a) Source #

Prove a lemma, using the given configuration

Reasoning via calculation

calc :: (Calc a, Proposition a, SymVal t, EqSymbolic (SBV t)) => String -> a -> StepArgs a t -> TP (Proof a) Source #

Prove a property via a series of equality steps, using the default solver. Let H be a list of already established lemmas. Let P be a property we wanted to prove, named name. Consider a call of the form calc name P (cond, [A, B, C, D]) H. Note that H is a list of already proven facts, ensured by the type signature. We proceed as follows:

  • Prove: (H && cond) -> (A == B)
  • Prove: (H && cond && A == B) -> (B == C)
  • Prove: (H && cond && A == B && B == C) -> (C == D)
  • Prove: (H && (cond -> (A == B && B == C && C == D))) -> P
  • If all of the above steps succeed, conclude P.

cond acts as the context. Typically, if you are trying to prove Y -> Z, then you want cond to be Y. (This is similar to intros commands in theorem provers.)

So, calc-lemma is essentially modus-ponens, applied in a sequence of stepwise equality reasoning in the case of non-boolean steps.

If there are no helpers given (i.e., if H is empty), then this call is equivalent to lemmaWith.

calcWith :: (Calc a, Proposition a, SymVal t, EqSymbolic (SBV t)) => SMTConfig -> String -> a -> StepArgs a t -> TP (Proof a) Source #

Prove a property via a series of equality steps, using the given solver.

Reasoning via regular induction

induct :: (Inductive a, Proposition a, SymVal t, EqSymbolic (SBV t)) => String -> a -> (Proof (IHType a) -> IHArg a -> IStepArgs a t) -> TP (Proof a) Source #

Inductively prove a lemma, using the default config. Inductive proofs over lists only hold for finite lists. We also assume that all functions involved are terminating. SBV does not prove termination, so only partial correctness is guaranteed if non-terminating functions are involved.

inductWith :: (Inductive a, Proposition a, SymVal t, EqSymbolic (SBV t)) => SMTConfig -> String -> a -> (Proof (IHType a) -> IHArg a -> IStepArgs a t) -> TP (Proof a) Source #

Same as induct, but with the given solver configuration. Inductive proofs over lists only hold for finite lists. We also assume that all functions involved are terminating. SBV does not prove termination, so only partial correctness is guaranteed if non-terminating functions are involved.

Reasoning via measure-based strong induction

sInduct :: (SInductive a, Proposition a, Zero m, SymVal t, EqSymbolic (SBV t)) => String -> a -> MeasureArgs a m -> (Proof a -> StepArgs a t) -> TP (Proof a) Source #

Inductively prove a lemma, using measure based induction, using the default config. Inductive proofs over lists only hold for finite lists. We also assume that all functions involved are terminating. SBV does not prove termination, so only partial correctness is guaranteed if non-terminating functions are involved.

sInductWith :: (SInductive a, Proposition a, Zero m, SymVal t, EqSymbolic (SBV t)) => SMTConfig -> String -> a -> MeasureArgs a m -> (Proof a -> StepArgs a t) -> TP (Proof a) Source #

Same as sInduct, but with the given solver configuration. Inductive proofs over lists only hold for finite lists. We also assume that all functions involved are terminating. SBV does not prove termination, so only partial correctness is guaranteed if non-terminating functions are involved.

Creating instances of proofs

at :: Instantiatable a => Proof a -> IArgs a -> Proof Bool Source #

Apply a universal proof to some arguments, creating a boolean expression guaranteed to be true

newtype Inst (nm :: Symbol) a Source #

Instantiation for a universally quantified variable

Constructors

Inst (SBV a) 

Instances

Instances details
KnownSymbol nm => Show (Inst nm a) Source # 
Instance details

Defined in Data.SBV.TP.TP

Methods

showsPrec :: Int -> Inst nm a -> ShowS #

show :: Inst nm a -> String #

showList :: [Inst nm a] -> ShowS #

Faking proofs

sorry :: ProofObj Source #

A manifestly false theorem. This is useful when we want to prove a theorem that the underlying solver cannot deal with, or if we want to postpone the proof for the time being. TP will keep track of the uses of sorry and will print them appropriately while printing proofs. NB. We keep this as a ProofObj as opposed to a Proof as it is then easier to use it as a lemma helper.

Running TP proofs

data TP a Source #

Monad for running TP proofs in.

Instances

Instances details
MonadFail TP Source # 
Instance details

Defined in Data.SBV.TP.Utils

Methods

fail :: String -> TP a #

MonadIO TP Source # 
Instance details

Defined in Data.SBV.TP.Utils

Methods

liftIO :: IO a -> TP a #

Applicative TP Source # 
Instance details

Defined in Data.SBV.TP.Utils

Methods

pure :: a -> TP a #

(<*>) :: TP (a -> b) -> TP a -> TP b #

liftA2 :: (a -> b -> c) -> TP a -> TP b -> TP c #

(*>) :: TP a -> TP b -> TP b #

(<*) :: TP a -> TP b -> TP a #

Functor TP Source # 
Instance details

Defined in Data.SBV.TP.Utils

Methods

fmap :: (a -> b) -> TP a -> TP b #

(<$) :: a -> TP b -> TP a #

Monad TP Source # 
Instance details

Defined in Data.SBV.TP.Utils

Methods

(>>=) :: TP a -> (a -> TP b) -> TP b #

(>>) :: TP a -> TP b -> TP b #

return :: a -> TP a #

runTP :: TP a -> IO a Source #

Run a TP proof, using the default configuration.

runTPWith :: SMTConfig -> TP a -> IO a Source #

Run a TP proof, using the given configuration.

tpQuiet :: Bool -> SMTConfig -> SMTConfig Source #

Make TP proofs quiet. Note that this setting will be effective with the call to runTP/runTPWith, i.e., if you change the solver in a call to lemmaWith/theoremWith, we will inherit the quiet settings from the surrounding environment.

tpRibbon :: Int -> SMTConfig -> SMTConfig Source #

Change the size of the ribbon for TP proofs. Note that this setting will be effective with the call to runTP/runTPWith, i.e., if you change the solver in a call to lemmaWith/theoremWith, we will inherit the ribbon settings from the surrounding environment.

tpStats :: SMTConfig -> SMTConfig Source #

Make TP proofs produce statistics. Note that this setting will be effective with the call to runTP/runTPWith, i.e., if you change the solver in a call to lemmaWith/theoremWith, we will inherit the statistics settings from the surrounding environment.

tpCache :: SMTConfig -> SMTConfig Source #

Make TP proofs use proof-cache. Note that if you use this option then you are obligated to ensure all lemma/theorem names/type pairs you use are unique for the whole run. (That is, we will reuse proofs if they have the same name and type; hence if you prove two theorems that share name and type will be considered the same.) If you don't ensure this uniqueness, the results are not guaranteed to be sound. A good tip is to run the proof at least once to completion, and use cache for regression purposes to avoid re-runs. Also, this setting will be effective with the call to runTP/runTPWith, i.e., if you -- the solver in a call to lemmaWith/theoremWith, we will inherit the caching behavior settings from the surrounding environment.

Starting a calculation proof

(|-) :: [SBool] -> TPProofRaw a -> (SBool, TPProofRaw a) infixl 0 Source #

Start a calculational proof, with the given hypothesis. Use [] as the first argument if the calculation holds unconditionally. The first argument is typically used to introduce hypotheses in proofs of implications such as A .=> B .=> C, where we would put [A, B] as the starting assumption. You can name these and later use in the derivation steps.

(⊢) :: [SBool] -> TPProofRaw a -> (SBool, TPProofRaw a) infixl 0 Source #

Alternative unicode for |-.

Sequence of calculation steps

(=:) :: ChainStep a (ChainsTo a) => a -> ChainsTo a -> ChainsTo a infixr 1 Source #

Chain steps in a calculational proof.

(≡) :: ChainStep a (ChainsTo a) => a -> ChainsTo a -> ChainsTo a infixr 1 Source #

Unicode alternative for =:.

Supplying hints for a calculation step

(??) :: HintsTo a b => a -> b -> Hinted a infixl 2 Source #

Attaching a hint

(∵) :: HintsTo a b => a -> b -> Hinted a infixl 2 Source #

Alternative unicode for ??.

Using quickcheck

qc :: Int -> Helper Source #

A quick-check step, taking number of tests.

qcWith :: Args -> Helper Source #

A quick-check step, with specific quick-check args.

Case splits

split :: SymVal a => SList a -> TPProofRaw r -> (SBV a -> SList a -> TPProofRaw r) -> TPProofRaw r Source #

Case splitting over a list; empty and full cases

split2 :: (SymVal a, SymVal b) => (SList a, SList b) -> TPProofRaw r -> ((SBV b, SList b) -> TPProofRaw r) -> ((SBV a, SList a) -> TPProofRaw r) -> ((SBV a, SList a) -> (SBV b, SList b) -> TPProofRaw r) -> TPProofRaw r Source #

Case splitting over two lists; empty and full cases for each

cases :: [(SBool, TPProofRaw a)] -> TPProofRaw a Source #

The boolean case-split

(⟹) :: SBool -> TPProofRaw a -> (SBool, TPProofRaw a) infix 0 Source #

Alternative unicode for ==>

(==>) :: SBool -> TPProofRaw a -> (SBool, TPProofRaw a) infix 0 Source #

Specifying a case-split, helps with the boolean case.

Finishing up a calculational proof

qed :: TPProofRaw a Source #

Mark the end of a calculational proof.

trivial :: Trivial a => a Source #

Mark a proof as trivial, i.e., the solver should be able to deduce it without any help.

contradiction :: Contradiction a => a Source #

Mark a proof as contradiction, i.e., the solver should be able to conclude it by reasoning that the current path is infeasible

Displaying intermediate values of expressions

disp :: String -> SBV a -> Helper Source #

Observing values in case of failure.