Copyright | (c) Levent Erkok |
---|---|
License | BSD3 |
Maintainer | erkokl@gmail.com |
Stability | experimental |
Safe Haskell | None |
Language | Haskell2010 |
Data.SBV.Tools.KnuckleDragger
Contents
- Propositions and their proofs
- Adding axioms/definitions
- Basic proofs
- Reasoning via calculation
- Reasoning via regular induction
- Reasoning via strong induction
- Creating instances of proofs
- Faking proofs
- Running KnuckleDragger proofs
- Starting a calculation proof
- Sequence of calculation steps
- Supplying hints for a calculation step
- Case splits
- Finishing up a calculational proof
Description
A lightweight theorem proving like interface, built on top of SBV. Inspired by and modeled after Philip Zucker's tool with the same name, see http://github.com/philzook58/knuckledragger.
See the directory Documentation.SBV.Examples.KnuckleDragger 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
- axiom :: Proposition a => String -> a -> KD Proof
- lemma :: Proposition a => String -> a -> [Proof] -> KD Proof
- lemmaWith :: Proposition a => SMTConfig -> String -> a -> [Proof] -> KD Proof
- theorem :: Proposition a => String -> a -> [Proof] -> KD Proof
- theoremWith :: Proposition a => SMTConfig -> String -> a -> [Proof] -> KD Proof
- calc :: CalcLemma a steps => String -> a -> steps -> KD Proof
- calcWith :: CalcLemma a steps => SMTConfig -> String -> a -> steps -> KD Proof
- calcThm :: CalcLemma a steps => String -> a -> steps -> KD Proof
- calcThmWith :: CalcLemma a steps => SMTConfig -> String -> a -> steps -> KD Proof
- induct :: Inductive a steps => String -> a -> (Proof -> steps) -> KD Proof
- inductWith :: Inductive a steps => SMTConfig -> String -> a -> (Proof -> steps) -> KD Proof
- inductThm :: Inductive a steps => String -> a -> (Proof -> steps) -> KD Proof
- inductThmWith :: Inductive a steps => SMTConfig -> String -> a -> (Proof -> steps) -> KD Proof
- sInduct :: Inductive a steps => String -> a -> (Proof -> steps) -> KD Proof
- sInductWith :: Inductive a steps => SMTConfig -> String -> a -> (Proof -> steps) -> KD Proof
- sInductThm :: Inductive a steps => String -> a -> (Proof -> steps) -> KD Proof
- sInductThmWith :: Inductive a steps => SMTConfig -> String -> a -> (Proof -> steps) -> KD Proof
- at :: Instantiatable a => Proof -> a -> Proof
- newtype Inst (nm :: Symbol) a = Inst (SBV a)
- sorry :: Proof
- data KD a
- runKD :: KD a -> IO a
- runKDWith :: SMTConfig -> KD a -> IO a
- use :: IO Proof -> KD Proof
- (|-) :: [SBool] -> [ProofStep a] -> (SBool, [ProofStep a])
- (⊢) :: [SBool] -> [ProofStep a] -> (SBool, [ProofStep a])
- (=:) :: ChainStep a (ChainsTo a) => a -> ChainsTo a -> ChainsTo a
- (≡) :: ChainStep a (ChainsTo a) => a -> ChainsTo a -> ChainsTo a
- (??) :: ProofHint a b => a -> b -> ProofStep a
- (⁇) :: ProofHint a b => a -> b -> ProofStep a
- hprf :: Proof -> Helper
- hyp :: SBool -> Helper
- cases :: String -> [SBool] -> Helper
- qed :: [ProofStep a]
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 KnuckleDragger.
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 KnuckleDragger kernel itself. But this mechanism ensures we can't create proven things out of thin air, following the standard LCF methodology.)
Instances
Adding axioms/definitions
axiom :: Proposition a => String -> a -> KD Proof 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 -> [Proof] -> KD Proof Source #
Prove a given statement, using auxiliaries as helpers. Using the default solver.
lemmaWith :: Proposition a => SMTConfig -> String -> a -> [Proof] -> KD Proof Source #
Prove a given statement, using auxiliaries as helpers. Using the given solver.
theorem :: Proposition a => String -> a -> [Proof] -> KD Proof Source #
Prove a given statement, using auxiliaries as helpers. Essentially the same as lemma
, except for the name, using the default solver.
theoremWith :: Proposition a => SMTConfig -> String -> a -> [Proof] -> KD Proof Source #
Prove a given statement, using auxiliaries as helpers. Essentially the same as lemmaWith
, except for the name.
Reasoning via calculation
calc :: CalcLemma a steps => String -> a -> steps -> KD Proof 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
.
If H
is a singleton, then we bail out. A single step in H
indicates a usage mistake, since there's
no sequence of steps to reason about.
calcWith :: CalcLemma a steps => SMTConfig -> String -> a -> steps -> KD Proof Source #
Prove a property via a series of equality steps, using the given solver.
calcThm :: CalcLemma a steps => String -> a -> steps -> KD Proof Source #
Same as calc, except tagged as Theorem
calcThmWith :: CalcLemma a steps => SMTConfig -> String -> a -> steps -> KD Proof Source #
Same as calcWith, except tagged as Theorem
Reasoning via regular induction
induct :: Inductive a steps => String -> a -> (Proof -> steps) -> KD Proof 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 steps => SMTConfig -> String -> a -> (Proof -> steps) -> KD Proof 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.
inductThm :: Inductive a steps => String -> a -> (Proof -> steps) -> KD Proof Source #
Inductively prove a theorem. Same as induct
, but tagged as a theorem, 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.
inductThmWith :: Inductive a steps => SMTConfig -> String -> a -> (Proof -> steps) -> KD Proof Source #
Same as inductThm
, 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 strong induction
sInduct :: Inductive a steps => String -> a -> (Proof -> steps) -> KD Proof Source #
Inductively prove a lemma, using strong 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 :: Inductive a steps => SMTConfig -> String -> a -> (Proof -> steps) -> KD Proof 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.
sInductThm :: Inductive a steps => String -> a -> (Proof -> steps) -> KD Proof Source #
Inductively prove a theorem, using strong induction. Same as sInduct
, but tagged as a theorem, 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.
sInductThmWith :: Inductive a steps => SMTConfig -> String -> a -> (Proof -> steps) -> KD Proof Source #
Same as sInductThm
, 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 -> Proof Source #
Apply a universal proof to some arguments, creating an instance of the proof itself.
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. KnuckleDragger will keep
track of the uses of sorry
and will print them appropriately while printing proofs.
Running KnuckleDragger proofs
Monad for running KnuckleDragger proofs in.
Starting a calculation proof
(|-) :: [SBool] -> [ProofStep a] -> (SBool, [ProofStep 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] -> [ProofStep a] -> (SBool, [ProofStep 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
(??) :: ProofHint a b => a -> b -> ProofStep a infixl 2 Source #
Specify a helper for the given proof step
hprf :: Proof -> Helper Source #
Smart constructor for creating a helper from a boolean. This is hardly needed, unless you're mixing proofs and booleans in one group of hints.
hyp :: SBool -> Helper Source #
Smart constructor for creating a helper from a boolean. This is hardly needed, unless you're mixing proofs and booleans in one group of hints.