Copyright | (c) Levent Erkok |
---|---|
License | BSD3 |
Maintainer | erkokl@gmail.com |
Stability | experimental |
Safe Haskell | None |
Language | Haskell2010 |
Data.SBV.TP
Contents
- Propositions and their proofs
- Getting the proof tree
- Adding axioms/definitions
- Basic proofs
- Reasoning via calculation
- Reasoning via regular induction
- Reasoning via measure-based strong induction
- Creating instances of proofs
- Faking proofs
- Running TP proofs
- Starting a calculation proof
- Sequence of calculation steps
- Supplying hints for a calculation step
- Using quickcheck
- Case splits
- Finishing up a calculational proof
- Displaying intermediate values of expressions
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
- 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)
- data Proof a
- proofOf :: Proof a -> ProofObj
- assumptionFromProof :: Proof a -> SBool
- rootOfTrust :: Proof a -> RootOfTrust
- newtype RootOfTrust = RootOfTrust (Maybe [ProofObj])
- data ProofTree = ProofTree ProofObj [ProofTree]
- showProofTree :: Bool -> Proof a -> String
- showProofTreeHTML :: Bool -> Maybe FilePath -> Proof a -> String
- axiom :: Proposition a => String -> a -> TP (Proof a)
- lemma :: Proposition a => String -> a -> [ProofObj] -> TP (Proof a)
- lemmaWith :: Proposition a => SMTConfig -> String -> a -> [ProofObj] -> TP (Proof a)
- calc :: (Calc a, Proposition a, SymVal t, EqSymbolic (SBV t)) => String -> a -> StepArgs a t -> TP (Proof a)
- calcWith :: (Calc a, Proposition a, SymVal t, EqSymbolic (SBV t)) => SMTConfig -> String -> a -> StepArgs a t -> TP (Proof a)
- induct :: (Inductive a, Proposition a, SymVal t, EqSymbolic (SBV t)) => String -> a -> (Proof (IHType a) -> IHArg a -> IStepArgs a t) -> TP (Proof a)
- inductWith :: (Inductive a, Proposition a, SymVal t, EqSymbolic (SBV t)) => SMTConfig -> String -> a -> (Proof (IHType a) -> IHArg a -> IStepArgs a t) -> TP (Proof a)
- 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)
- 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)
- at :: Instantiatable a => Proof a -> IArgs a -> Proof Bool
- newtype Inst (nm :: Symbol) a = Inst (SBV a)
- sorry :: ProofObj
- data TP a
- runTP :: TP a -> IO a
- runTPWith :: SMTConfig -> TP a -> IO a
- tpQuiet :: Bool -> SMTConfig -> SMTConfig
- tpRibbon :: Int -> SMTConfig -> SMTConfig
- tpStats :: SMTConfig -> SMTConfig
- tpCache :: SMTConfig -> SMTConfig
- (|-) :: [SBool] -> TPProofRaw a -> (SBool, TPProofRaw a)
- (⊢) :: [SBool] -> TPProofRaw a -> (SBool, TPProofRaw a)
- (=:) :: ChainStep a (ChainsTo a) => a -> ChainsTo a -> ChainsTo a
- (≡) :: ChainStep a (ChainsTo a) => a -> ChainsTo a -> ChainsTo a
- (??) :: HintsTo a b => a -> b -> Hinted a
- (∵) :: HintsTo a b => a -> b -> Hinted a
- qc :: Int -> Helper
- qcWith :: Args -> Helper
- split :: SymVal a => SList a -> TPProofRaw r -> (SBV a -> SList a -> TPProofRaw r) -> TPProofRaw r
- 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
- cases :: [(SBool, TPProofRaw a)] -> TPProofRaw a
- (⟹) :: SBool -> TPProofRaw a -> (SBool, TPProofRaw a)
- (==>) :: SBool -> TPProofRaw a -> (SBool, TPProofRaw a)
- qed :: TPProofRaw a
- trivial :: Trivial a => a
- contradiction :: Contradiction a => a
- disp :: String -> SBV a -> Helper
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.
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.)
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
Monoid RootOfTrust Source # | Trust forms a monoid |
Defined in Data.SBV.TP.Utils Methods mempty :: RootOfTrust # mappend :: RootOfTrust -> RootOfTrust -> RootOfTrust # mconcat :: [RootOfTrust] -> RootOfTrust # | |
Semigroup RootOfTrust Source # | Trust forms a semigroup |
Defined in Data.SBV.TP.Utils Methods (<>) :: RootOfTrust -> RootOfTrust -> RootOfTrust # sconcat :: NonEmpty RootOfTrust -> RootOfTrust # stimes :: Integral b => b -> RootOfTrust -> RootOfTrust # | |
Show RootOfTrust Source # | Show instance for |
Defined in Data.SBV.TP.Utils Methods showsPrec :: Int -> RootOfTrust -> ShowS # show :: RootOfTrust -> String # showList :: [RootOfTrust] -> ShowS # |
Dependencies of a proof, in a tree format.
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
Faking proofs
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
Monad for running TP proofs in.
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
Using quickcheck
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
(==>) :: SBool -> TPProofRaw a -> (SBool, TPProofRaw a) infix 0 Source #
Specifying a case-split, helps with the boolean case.
Finishing up 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