tamarin-prover-0.4.0.0: src/Theory/Proof/Types.hs
{-# LANGUAGE TypeOperators, StandaloneDeriving, DeriveDataTypeable, TemplateHaskell #-}
{-# LANGUAGE TemplateHaskell, ViewPatterns #-}
-- |
-- Copyright : (c) 2010-2012 Benedikt Schmidt & Simon Meier
-- License : GPL v3 (see LICENSE)
--
-- Maintainer : Simon Meier <iridcode@gmail.com>
-- Portability : GHC only
--
-- Common types for reasoning about sequents: Graph part of a sequent,
-- clauses, and equation store.
--
-- NOTE that sequents are what we call constraint systems in CSF'12 paper.
module Theory.Proof.Types (
-- * Graph part of a sequent
NodeId
, NodePrem
, NodeConc
, Edge(..)
, MsgEdge(..)
, Chain(..)
-- * The first-order logic part of a sequent
-- ** Typing and equation store
, SplitId
, EqStore(..)
, emptyEqStore
, eqsSubst
, eqsConj
-- ** Equalitiy constraint conjunctions
, falseEqConstrConj
-- ** Queries
, eqsIsFalse
-- * Goals
, Goal(..)
, isActionGoal
, isPremiseGoal
, isPremDnKGoal
, isPremUpKGoal
, isChainGoal
, isSplitGoal
, isDisjGoal
-- * Keeping track of typing
, CaseDistKind(..)
-- * Sequents
, Sequent(..)
, emptySequent
-- ** Accessors
, sNodes
, sEdges
, sMsgEdges
, sChains
, sEqStore
, sAtoms
, sFormulas
, sSolvedFormulas
, sLemmas
, sSubst
, sConjDisjEqs
, sCaseDistKind
-- ** Queries
, sLessAtoms
, sActionAtoms
, sLastAtoms
, sDedBeforeAtoms
, sActions
, sRawEdgeRel
, sRawLessRel
, sRawGreaterRel
, deducibleBefore
, happensBefore
, nodeRule
, nodeConcFact
, nodeConcNode
, nodePremNode
, nodePremFact
, resolveNodePremFact
-- , resolveNodePremMsg
, resolveNodeConcFact
-- , resolveNodeConcMsg
-- * Pretty-printing
, prettyNodeId
, prettyNode
, prettyNodePrem
, prettyNodeConc
, prettyEdge
, prettyMsgEdge
, prettyChain
, prettyEqStore
, prettyGoal
, prettySequent
, prettyNonGraphSequent
-- * Proof context
, ProofContext(..)
, InductionHint(..)
, SequentTraceQuantifier(..)
, pcSignature
, pcRules
, pcCaseDists
, pcCaseDistKind
, pcUseInduction
, pcTraceQuantifier
-- ** Classified rules
, ClassifiedRules(..)
, emptyClassifiedRules
, crConstruct
, crDestruct
, crProtocol
, joinAllRules
, nonSilentRules
-- ** Big-step case distinctions
-- | See the module "Theory.Proof.CaseDistinction" for ways
-- to construct case distinctions.
, CaseDistinction(..)
, cdGoal
, cdCases
-- * Convenience exports
, module Theory.Rule
, module Theory.Formula
, module Theory.Signature
, module Logic.Connectives
, module Theory.Proof.Guarded
) where
import Prelude hiding ( (.), id )
import Data.Maybe (mapMaybe, fromMaybe)
import qualified Data.Set as S
import qualified Data.Map as M
import qualified Data.DAG.Simple as D
import Data.Monoid (Monoid(..))
import Data.Generics
import qualified Data.Label as L
import Data.Label hiding (get)
import Data.DeriveTH
import Data.Binary
import Control.DeepSeq
import Control.Category
import Control.Basics
import Text.PrettyPrint.Class
import Logic.Connectives
import Theory.Pretty
import Theory.Rule
import Theory.Proof.Guarded
import Theory.Formula
import Theory.Signature
------------------------------------------------------------------------------
-- Graph part of a sequent --
------------------------------------------------------------------------------
-- | The graph part of our sequent consists of nodes labelled with instances of
-- rules modulo AC. We identify these nodes using 'NodeId's.
type NodeId = LVar
-- | A premise of a node.
type NodePrem = (NodeId, PremIdx)
-- | A conclusion of a node.
type NodeConc = (NodeId, ConcIdx)
-- | A labeled edge in a derivation graph.
data Edge = Edge {
eSrc :: NodeConc
, eTgt :: NodePrem
}
deriving (Show, Ord, Eq, Data, Typeable)
-- | A message edge.
data MsgEdge = MsgEdge {
meSrc :: NodeConc
, meTgt :: NodePrem
}
deriving (Show, Ord, Eq, Data, Typeable)
-- | A chain always starts at a rule with only one conclusion.
data Chain = Chain {
cSrc :: NodeConc
, cTgt :: NodePrem
}
deriving (Show, Ord, Eq, Data, Typeable)
-- Instances
------------
instance Apply Edge where
apply subst (Edge from to) = Edge (apply subst from) (apply subst to)
instance Apply MsgEdge where
apply subst (MsgEdge from to) = MsgEdge (apply subst from) (apply subst to)
instance Apply Chain where
apply subst (Chain from to) = Chain (apply subst from) (apply subst to)
instance HasFrees Edge where
foldFrees f (Edge x y) = foldFrees f x `mappend` foldFrees f y
mapFrees f (Edge x y) = Edge <$> mapFrees f x <*> mapFrees f y
instance HasFrees MsgEdge where
foldFrees f (MsgEdge x y) = foldFrees f x `mappend` foldFrees f y
mapFrees f (MsgEdge x y) = MsgEdge <$> mapFrees f x <*> mapFrees f y
instance HasFrees Chain where
foldFrees f (Chain x y) = foldFrees f x `mappend` foldFrees f y
mapFrees f (Chain x y) = Chain <$> mapFrees f x <*> mapFrees f y
------------------------------------------------------------------------------
-- The first-order logic part of a sequent --
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Typing and equation store --
------------------------------------------------------------------------------
-- | Index of disjunction in equation store
type SplitId = Int
-- FIXME: Make comment parse.
--
-- The semantics of an equation store
-- > EqStore sigma_free
-- > [ [sigma_i1,..,sigma_ik_i] | i <- [1..l] ]
-- where sigma_free = {t1/x1, .., tk/xk} is
-- > (x1 = t1 /\ .. /\ xk = tk)
-- > /\_{i in [1..l]}
-- > ([|sigma_i1|] \/ .. \/ [|sigma_ik_1|] \/ [|mtinfo_i|]
-- where @[|{t_1/x_1,..,t_l/x_l}|] = EX vars(t1,..,tl). x_1 = t1 /\ .. /\ x_l = t_l@.
-- Note that the 'LVar's in the range of a substitution are interpreted as
-- fresh variables, i.e., different by construction from the x_i which are
-- free variables.
--
-- The variables in the domain of the substitutions sigma_ij and all
-- variables in sigma_free are free (usually globally existentially quantified).
-- We use Conj [] as a normal form to denote True and Conj [Disj []]
-- as a normal form to denote False.
-- We say a variable @x@ is constrained by a disjunction if there is a substition
-- @s@ in the disjunction with @x `elem` dom s@.
data EqStore = EqStore {
_eqsSubst :: LNSubst
, _eqsConj :: Conj (S.Set LNSubstVFresh)
}
deriving( Eq, Ord )
$(mkLabels [''EqStore])
-- | @emptyEqStore@ is the empty equation store.
emptyEqStore :: EqStore
emptyEqStore = EqStore emptySubst (Conj [])
-- | @True@ iff the 'EqStore' is contradictory.
eqsIsFalse :: EqStore -> Bool
eqsIsFalse = (== falseEqConstrConj) . L.get eqsConj
-- | The false typing conjunction.
falseEqConstrConj :: Conj (S.Set (LNSubstVFresh))
falseEqConstrConj = Conj [S.empty]
-- Instances
------------
instance HasFrees EqStore where
foldFrees f (EqStore subst substs) = foldFrees f subst `mappend` foldFrees f substs
mapFrees f (EqStore subst substs) = EqStore <$> mapFrees f subst <*> mapFrees f substs
------------------------------------------------------------------------------
-- New goaling infrastructure
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Goals
------------------------------------------------------------------------------
-- | A 'Goal' denotes that a constraint reduction rule is applicable, which
-- might result in case splits. We either use a heuristic to decide what goal
-- to solve next or leave the choice to user (in case of the interactive UI).
data Goal =
ActionG LVar LNFact
-- ^ An action that must exist in the trace.
| PremiseG NodePrem LNFact Bool
-- ^ A premise that must have an incoming direct edge. The 'Bool'
-- argument is 'True' if this premise is marked as a loop-breaker;
-- i.e., if care must be taken to avoid solving such a premise too
-- often.
| PremDnKG NodePrem
-- ^ A KD goal that must be solved using a destruction chain.
| PremUpKG NodePrem LNTerm
-- ^ A KU goal requiring a term built using pairing, inversion, or
-- multiplication. 'PremUpKG p m' denotes that premise 'p' requires
-- the term 'm' as in input to construct its actual term.
| ChainG Chain
-- A destruction chain that does not start from a message variable.
| SplitG SplitId
-- ^ A case split over equalities.
| DisjG (Disj LNGuarded)
-- ^ A case split over a disjunction.
| ImplG LNGuarded
-- ^ The consequent of a universally quantified clause that could be
-- added to the sequent. For debugging mode only; currently commented
-- out.
deriving( Eq, Ord, Show )
-- Indicators
-------------
isActionGoal :: Goal -> Bool
isActionGoal (ActionG _ _) = True
isActionGoal _ = False
isPremiseGoal :: Goal -> Bool
isPremiseGoal (PremiseG _ _ _) = True
isPremiseGoal _ = False
isPremDnKGoal :: Goal -> Bool
isPremDnKGoal (PremDnKG _) = True
isPremDnKGoal _ = False
isPremUpKGoal :: Goal -> Bool
isPremUpKGoal (PremUpKG _ _) = True
isPremUpKGoal _ = False
isChainGoal :: Goal -> Bool
isChainGoal (ChainG _) = True
isChainGoal _ = False
isSplitGoal :: Goal -> Bool
isSplitGoal (SplitG _) = True
isSplitGoal _ = False
isDisjGoal :: Goal -> Bool
isDisjGoal (DisjG _) = True
isDisjGoal _ = False
-- Instances
------------
instance HasFrees Goal where
foldFrees f goal = case goal of
ActionG i fa -> foldFrees f i `mappend` foldFrees f fa
PremiseG p fa mayLoop -> foldFrees f p `mappend` foldFrees f fa `mappend` foldFrees f mayLoop
PremDnKG p -> foldFrees f p
PremUpKG p m -> foldFrees f p `mappend` foldFrees f m
ChainG ch -> foldFrees f ch
SplitG i -> foldFrees f i
DisjG x -> foldFrees f x
ImplG x -> foldFrees f x
mapFrees f goal = case goal of
ActionG i fa -> ActionG <$> mapFrees f i <*> mapFrees f fa
PremiseG p fa mayLoop -> PremiseG <$> mapFrees f p <*> mapFrees f fa <*> mapFrees f mayLoop
PremDnKG p -> PremDnKG <$> mapFrees f p
PremUpKG p m -> PremUpKG <$> mapFrees f p <*> mapFrees f m
ChainG ch -> ChainG <$> mapFrees f ch
SplitG i -> SplitG <$> mapFrees f i
DisjG x -> DisjG <$> mapFrees f x
ImplG x -> ImplG <$> mapFrees f x
instance Apply Goal where
apply subst goal = case goal of
ActionG i fa -> ActionG (apply subst i) (apply subst fa)
PremiseG p fa mayLoop -> PremiseG (apply subst p) (apply subst fa) (apply subst mayLoop)
PremDnKG p -> PremDnKG (apply subst p)
PremUpKG p m -> PremUpKG (apply subst p) (apply subst m)
ChainG ch -> ChainG (apply subst ch)
SplitG i -> SplitG (apply subst i)
DisjG x -> DisjG (apply subst x)
ImplG x -> ImplG (apply subst x)
------------------------------------------------------------------------------
-- Keeping track of what case distinctions are allowed.
------------------------------------------------------------------------------
-- | Case dinstinction kind that are allowed. The order of the kinds
-- corresponds to the subkinding relation: untyped < typed.
data CaseDistKind = UntypedCaseDist | TypedCaseDist
deriving( Eq, Ord )
instance Show CaseDistKind where
show UntypedCaseDist = "untyped"
show TypedCaseDist = "typed"
instance Apply CaseDistKind where
apply = const id
instance HasFrees CaseDistKind where
foldFrees = const mempty
mapFrees = const pure
------------------------------------------------------------------------------
-- Sequents --
------------------------------------------------------------------------------
-- | A sequent / constraint system.
--
data Sequent = Sequent {
_sNodes :: M.Map NodeId RuleACInst
, _sEdges :: S.Set Edge
, _sMsgEdges :: S.Set MsgEdge
, _sChains :: S.Set Chain
, _sEqStore :: EqStore
, _sAtoms :: S.Set LNAtom
, _sFormulas :: S.Set LNGuarded
, _sSolvedFormulas :: S.Set LNGuarded
, _sLemmas :: S.Set LNGuarded
, _sCaseDistKind :: CaseDistKind
}
deriving( Eq, Ord )
$(mkLabels [''Sequent])
-- | The empty sequent. Logically equivalent to true.
emptySequent :: CaseDistKind -> Sequent
emptySequent = Sequent
M.empty S.empty S.empty S.empty emptyEqStore S.empty S.empty S.empty S.empty
-- Custom accessors for atoms
-----------------------------
-- | All actions that hold in a sequent.
sActions :: Sequent -> [(NodeId, LNFact)]
sActions se =
sActionAtoms se <|> do (i, ru) <- M.toList $ L.get sNodes se
(,) i <$> L.get rActs ru
-- | The less-relation.
sLessAtoms :: Sequent -> [(NodeId, NodeId)]
-- | The actions.
sActionAtoms :: Sequent -> [(NodeId, LNFact)]
-- | The last nodes.
sLastAtoms :: Sequent -> [NodeId]
-- | The deduced before atoms.
sDedBeforeAtoms :: Sequent -> [(LNTerm, NodeId)]
(sLessAtoms, sActionAtoms, sLastAtoms, sDedBeforeAtoms) =
(accessor aLess, accessor aAction, accessor aLast, accessor aDedBefore)
where
accessor :: (LNAtom -> Maybe a) -> Sequent -> [a]
accessor f = mapMaybe f . S.toList . L.get sAtoms
malformed ato = error $ "malformed atom in sequent: " ++ show ato
aLess (Less (viewTerm -> Lit (Var from)) (viewTerm -> Lit (Var to))) = Just (from, to)
aLess ato@(Less _ _) = malformed ato
aLess _ = Nothing
aAction (Action (viewTerm -> Lit (Var i)) fa) = Just (i, fa)
aAction ato@(Action _ _) = malformed ato
aAction _ = Nothing
aLast (Last (viewTerm -> Lit (Var i))) = Just i
aLast ato@(Last _) = malformed ato
aLast _ = Nothing
aDedBefore (DedBefore t (viewTerm -> Lit (Var i))) = Just (t, i)
aDedBefore ato@(DedBefore _ _) = malformed ato
aDedBefore _ = Nothing
-- | @(from,to)@ is in @sRawEdgeRel se@ iff we can prove that there is an
-- edge-path from @from@ to @to@ in @se@ without appealing to transitivity.
sRawEdgeRel :: Sequent -> [(NodeId, NodeId)]
sRawEdgeRel se =
map (nodeConcNode *** nodePremNode)
([ (from, to) | Edge from to <- S.toList $ L.get sEdges se ] ++
[ (from, to) | MsgEdge from to <- S.toList $ L.get sMsgEdges se ] ++
[ (from, to) | Chain from to <- S.toList $ L.get sChains se ])
-- | @(from,to)@ is in @sRawLessRel se@ iff we can prove that there is a path
-- (possibly using the 'Less' relation) from @from@ to @to@ in @se@ without
-- appealing to transitivity.
sRawLessRel :: Sequent -> [(NodeId,NodeId)]
sRawLessRel se = sLessAtoms se ++ sRawEdgeRel se
-- | 'sRawGreaterRel' is the inverse of 'sRawLessRel'.
sRawGreaterRel :: Sequent -> [(NodeId,NodeId)]
sRawGreaterRel = map (\(x,y) -> (y,x)) . sRawLessRel
-- | Returns a predicate that is 'True' iff the first argument happens before
-- the second argument in all models of the sequent.
happensBefore :: Sequent -> (NodeId -> NodeId -> Bool)
happensBefore se =
check -- lessRel is cached for partial applications
where
lessRel = sRawLessRel se
check i j = j `S.member` D.reachableSet [i] lessRel
-- | Returns a predicate that is 'True' iff the given term is deducible
-- before the given node in all models of the sequent.
deducibleBefore :: Sequent -> (LNTerm -> NodeId -> Bool)
deducibleBefore se =
check -- lessRel is cached for partial applications
where
lessRel = sRawLessRel se
check t i =
i `S.member` D.reachableSet startNodes lessRel
where
startNodes =
[ j | (t', j) <- sDedBeforeAtoms se, t == t' ] ++
do (j, ru) <- M.toList $ L.get sNodes se
fa <- L.get rPrems ru
case kFactView fa of
Just (_, _, m) | t `elem` input m -> return j
_ -> []
-- Instances for sequents
-------------------------
instance HasFrees Sequent where
foldFrees fun (Sequent a b c d e f g h i j) =
foldFrees fun a `mappend`
foldFrees fun b `mappend`
foldFrees fun c `mappend`
foldFrees fun d `mappend`
foldFrees fun e `mappend`
foldFrees fun f `mappend`
foldFrees fun g `mappend`
foldFrees fun h `mappend`
foldFrees fun i `mappend`
foldFrees fun j
mapFrees fun (Sequent a b c d e f g h i j) =
Sequent <$> mapFrees fun a
<*> mapFrees fun b
<*> mapFrees fun c
<*> mapFrees fun d
<*> mapFrees fun e
<*> mapFrees fun f
<*> mapFrees fun g
<*> mapFrees fun h
<*> mapFrees fun i
<*> mapFrees fun j
-- Accessors
------------
-- | @nodeRule v@ accesses the rule label of node @v@ under the assumption that
-- it is present in the sequent.
nodeRule :: NodeId -> Sequent -> RuleACInst
nodeRule v se =
fromMaybe errMsg $ M.lookup v $ L.get sNodes se
where
errMsg = error $
"nodeRule: node '" ++ show v ++ "' does not exist in sequent\n" ++
render (nest 2 $ prettySequent se)
-- | @nodePremFact prem se@ computes the fact associated to premise @prem@ in
-- sequent @se@ under the assumption that premise @prem@ is a a premise in
-- @se@.
nodePremFact :: NodePrem -> Sequent -> LNFact
nodePremFact (v, i) se = L.get (rPrem i) $ nodeRule v se
-- | @nodePremNode prem@ is the node that this premise is referring to.
nodePremNode :: NodePrem -> NodeId
nodePremNode = fst
-- | All facts associated to this node premise.
resolveNodePremFact :: NodePrem -> Sequent -> Maybe LNFact
resolveNodePremFact (v, i) se = lookupPrem i =<< M.lookup v (L.get sNodes se)
{-
-- | All msg fact premises required by the sequent for the given node premise.
resolveNodePremMsg :: NodePrem -> Sequent -> Maybe LTerm
resolveNodePremMsg prem = msgFactTerm <=< resolveNodePremFact prem
-}
-- | The fact associated with this node conclusion, if there is one.
resolveNodeConcFact :: NodeConc -> Sequent -> Maybe LNFact
resolveNodeConcFact (v, i) se = lookupConc i =<< M.lookup v (L.get sNodes se)
{-
-- | The msg fact provided by the sequent for the given node conclusion
resolveNodeConcMsg :: NodeConc -> Sequent -> Maybe LTerm
resolveNodeConcMsg conc = msgFactTerm <=< resolveNodeConcFact conc
-}
-- | @nodeConcFact (NodeConc (v, i))@ accesses the @i@-th conclusion of the
-- rule associated with node @v@ under the assumption that @v@ is labeled with
-- a rule that has an @i@-th conclusion.
nodeConcFact :: NodeConc -> Sequent -> LNFact
nodeConcFact (v, i) = L.get (rConc i) . nodeRule v
-- | 'nodeConcNode' @c@ compute the node-id of the node conclusion @c@.
nodeConcNode :: NodeConc -> NodeId
nodeConcNode = fst
-- | Label to access the free substitution of the equation store.
sSubst :: Sequent :-> LNSubst
sSubst = eqsSubst . sEqStore
-- | Label to access the conjunction of disjunctions of fresh substutitution in
-- the equation store.
sConjDisjEqs :: Sequent :-> Conj (S.Set (LNSubstVFresh))
sConjDisjEqs = eqsConj . sEqStore
------------------------------------------------------------------------------
-- Pretty printing --
------------------------------------------------------------------------------
-- | Pretty print a node id
prettyNodeId :: Document d => NodeId -> d
prettyNodeId = text . show
-- | Pretty print a node.
prettyNode :: HighlightDocument d => (NodeId, RuleACInst) -> d
prettyNode (v,ru) = prettyNodeId v <> colon <-> prettyRuleACInst ru
-- | Pretty print a node conclusion.
prettyNodeConc :: HighlightDocument d => NodeConc -> d
prettyNodeConc (v, ConcIdx i) = parens (prettyNodeId v <> comma <-> int i)
-- | Pretty print a node premise.
prettyNodePrem :: HighlightDocument d => NodePrem -> d
prettyNodePrem (v, PremIdx i) = parens (prettyNodeId v <> comma <-> int i)
-- | Pretty print a edge as @src >-i--j-> tgt@.
prettyEdge :: HighlightDocument d => Edge -> d
prettyEdge (Edge c p) =
prettyNodeConc c <-> operator_ ">-->" <-> prettyNodePrem p
-- | Pretty print a edge as @src >-i--j-> tgt@.
prettyMsgEdge :: HighlightDocument d => MsgEdge -> d
prettyMsgEdge (MsgEdge c p) =
prettyNodeConc c <-> operator_ "-->>" <-> prettyNodePrem p
-- | Pretty print a chain as @src ~~> tgt@.
prettyChain :: HighlightDocument d => Chain -> d
prettyChain (Chain c p) =
prettyNodeConc c <-> operator_ "~~>" <-> prettyNodePrem p
-- | Pretty print a sequent
prettySequent :: HighlightDocument d => Sequent -> d
prettySequent se = vcat $
map combine
[ ("nodes", vcat $ map prettyNode $ M.toList $ L.get sNodes se)
, ("edges", commasep $ map prettyEdge $ S.toList $ L.get sEdges se)
, ("msg-edges", commasep $ map prettyMsgEdge $ S.toList $ L.get sMsgEdges se)
, ("chains", commasep $ map prettyChain $ S.toList $ L.get sChains se)
]
++ [prettyNonGraphSequent se]
where
combine (header, d) = fsep [keyword_ header <> colon, nest 2 d]
commasep = fsep . punctuate comma
-- | Pretty print the non-graph part of the sequent; i.e. equation store and
-- clauses.
prettyNonGraphSequent :: HighlightDocument d => Sequent -> d
prettyNonGraphSequent se = foldr ($--$) emptyDoc $ map combine
[ ("atoms", ppAtoms $ S.toList $ L.get sAtoms se)
, ("allowed cases", text $ show $ L.get sCaseDistKind se)
, ("formulas", foldr ($--$) emptyDoc $ map prettyGuarded $ S.toList $ L.get sFormulas se)
, ("equations", prettyEqStore $ L.get sEqStore se)
, ("solved formulas", foldr ($--$) emptyDoc $ map prettyGuarded $ S.toList $ L.get sSolvedFormulas se)
, ("lemmas", foldr ($--$) emptyDoc $ map prettyGuarded $ S.toList $ L.get sLemmas se)
]
where
combine (header, d) = fsep [keyword_ header <> colon, nest 2 d]
ppAtoms = fsep . punctuate comma . map prettyNAtom
-- | Pretty print an equation store
prettyEqStore :: HighlightDocument d => EqStore -> d
prettyEqStore eqs@(EqStore subst (Conj disjs)) = vcat $
[if eqsIsFalse eqs then text "CONTRADICTORY" else emptyDoc] ++
map combine
[ ("subst", vcat $ prettySubst (text . show) (text . show) subst)
, ("conj", numbered' $ map ppDisj disjs)
]
where
combine (header, d) = fsep [keyword_ header <> colon, nest 2 d]
ppDisj substs =
numbered' conjs
where
conjs = map ppConj (S.toList substs)
ppConj = vcat . map prettyEq . substToListVFresh
prettyEq (a,b) =
prettyNTerm (lit (Var a)) $$ nest (6::Int) (opEqual <-> prettyNTerm b)
-- | Pretty print a goal.
prettyGoal :: HighlightDocument d => Goal -> d
prettyGoal (ActionG i fa) = prettyNAtom (Action (varTerm i) fa)
prettyGoal (ChainG ch) = prettyChain ch
prettyGoal (PremiseG p fa mayLoop) =
prettyNodePrem p <> brackets (prettyLNFact fa) <->
(if mayLoop then comment_ "/* may loop */" else emptyDoc)
prettyGoal (PremDnKG p) = text "KD" <> parens (prettyNodePrem p)
prettyGoal (ImplG gf) =
(text "Consequent" <>) $ nest 1 $ parens $ prettyGuarded gf
prettyGoal (DisjG (Disj gfs)) = (text "Disj" <>) $ fsep $
punctuate (operator_ " |") (map (nest 1 . parens . prettyGuarded) gfs)
prettyGoal (PremUpKG p m) =
text "KU" <> parens (prettyNodePrem p <> comma <-> prettyLNTerm m)
prettyGoal (SplitG x) =
text "splitEqs" <> parens (text $ show (succ x))
-- Additional Show instances moved here due to TemplateHaskell splicing rules
-----------------------------------------------------------------------------
instance Show EqStore where
show = render . prettyEqStore
deriving instance Show Sequent
----------------------------------------------------------------------
-- ClassifiedRules
----------------------------------------------------------------------
data ClassifiedRules = ClassifiedRules
{ _crProtocol :: [RuleAC] -- all protocol rules
, _crDestruct :: [RuleAC] -- destruction rules
, _crConstruct :: [RuleAC] -- construction rules
}
deriving( Eq, Ord, Show )
$(mkLabels [''ClassifiedRules])
-- | The empty proof rule set.
emptyClassifiedRules :: ClassifiedRules
emptyClassifiedRules = ClassifiedRules [] [] []
-- | @joinAllRules rules@ computes the union of all rules classified in
-- @rules@.
joinAllRules :: ClassifiedRules -> [RuleAC]
joinAllRules (ClassifiedRules a b c) = a ++ b ++ c
-- | Extract all non-silent rules.
nonSilentRules :: ClassifiedRules -> [RuleAC]
nonSilentRules = filter (not . null . L.get rActs) . joinAllRules
------------------------------------------------------------------------------
-- Proof Context
------------------------------------------------------------------------------
-- | A big-step case distinction.
data CaseDistinction = CaseDistinction
{ _cdGoal :: LNFact -- start goal of case distinction
-- disjunction of named sequents with premise being solved; each name
-- being the path of proof steps required to arrive at these cases
, _cdCases :: Disj ([String], (NodeConc, Sequent))
}
deriving( Eq, Ord, Show )
-- | Whether we are checking for the existence of a trace satisfiying a the
-- current constraint system or whether we're checking that no traces
-- satisfies the current constraint system.
data SequentTraceQuantifier = ExistsSomeTrace | ExistsNoTrace
deriving( Eq, Ord, Show )
data InductionHint = UseInduction | AvoidInduction
deriving( Eq, Ord, Show )
-- | A proof context contains the globally fresh facts, classified rewrite
-- rules and the corresponding precomputed premise case distinction theorems.
data ProofContext = ProofContext
{ _pcSignature :: SignatureWithMaude
, _pcRules :: ClassifiedRules
, _pcCaseDistKind :: CaseDistKind
, _pcCaseDists :: [CaseDistinction]
, _pcUseInduction :: InductionHint
, _pcTraceQuantifier :: SequentTraceQuantifier
}
deriving( Eq, Ord, Show )
$(mkLabels [''ProofContext, ''CaseDistinction])
-- Instances
------------
instance HasFrees CaseDistinction where
foldFrees f th =
foldFrees f (L.get cdGoal th) `mappend`
foldFrees f (L.get cdCases th)
mapFrees f th = CaseDistinction <$> mapFrees f (L.get cdGoal th)
<*> mapFrees f (L.get cdCases th)
-- NFData
---------
$( derive makeBinary ''Goal)
$( derive makeBinary ''Chain)
$( derive makeBinary ''MsgEdge)
$( derive makeBinary ''Edge)
$( derive makeBinary ''EqStore)
$( derive makeBinary ''CaseDistKind)
$( derive makeBinary ''Sequent)
$( derive makeBinary ''CaseDistinction)
$( derive makeBinary ''ClassifiedRules)
$( derive makeBinary ''SequentTraceQuantifier)
$( derive makeBinary ''InductionHint)
$( derive makeNFData ''Goal)
$( derive makeNFData ''Chain)
$( derive makeNFData ''MsgEdge)
$( derive makeNFData ''Edge)
$( derive makeNFData ''EqStore)
$( derive makeNFData ''CaseDistKind)
$( derive makeNFData ''Sequent)
$( derive makeNFData ''CaseDistinction)
$( derive makeNFData ''ClassifiedRules)
$( derive makeNFData ''SequentTraceQuantifier)
$( derive makeNFData ''InductionHint)