{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | -- Copyright : (c) 2012 Simon Meier -- License : GPL v3 (see LICENSE) -- -- Maintainer : Simon Meier -- Portability : portable -- -- Computate an under-approximation to the set of all facts with unique -- instances, i.e., fact whose instances never occur more than once in a -- state. We use this information to reason about protocols that exploit -- exclusivity of linear facts. module Theory.Tools.InjectiveFactInstances ( -- * Computing injective fact instances. simpleInjectiveFactInstances ) where import Extension.Prelude (sortednub) import Control.Applicative import Control.Monad.Fresh import Data.Label import qualified Data.Set as S import Safe (headMay) import Theory.Model -- | Compute a simple under-approximation to the set of facts with injective -- instances. A fact-tag is has injective instances, if there is no state of -- the protocol with more than one instance with the same term as a first -- argument of the fact-tag. -- -- We compute the under-approximation by checking that -- (1) the fact-tag is linear, -- (2) every introduction of such a fact-tag is protected by a Fr-fact of the -- first term, and -- (3) every rule has at most one copy of this fact-tag in the conlcusion and -- the first term arguments agree. -- -- We exclude facts that are not copied in a rule, as they are already handled -- properly by the naive backwards reasoning. simpleInjectiveFactInstances :: [ProtoRuleE] -> S.Set FactTag simpleInjectiveFactInstances rules = S.fromList $ do tag <- candidates guard (all (guardedSingletonCopy tag) rules) return tag where candidates = sortednub $ do ru <- rules tag <- factTag <$> get rConcs ru guard $ (factTagMultiplicity tag == Linear) && (tag `elem` (factTag <$> get rPrems ru)) return tag guardedSingletonCopy tag ru = length copies <= 1 && all guardedCopy copies where prems = get rPrems ru copies = filter ((tag ==) . factTag) (get rConcs ru) firstTerm = headMay . factTerms -- True if there is a first term and a premise guarding it guardedCopy faConc = case firstTerm faConc of Nothing -> False Just tConc -> freshFact tConc `elem` prems || guardedInPrems tConc -- True if there is a premise with the same tag and first term guardedInPrems tConc = (`any` prems) $ \faPrem -> factTag faPrem == tag && maybe False (tConc ==) (firstTerm faPrem)