ideas-0.5.8: src/Common/Rewriting/Confluence.hs
-----------------------------------------------------------------------------
-- Copyright 2009, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer : bastiaan.heeren@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-----------------------------------------------------------------------------
module Common.Rewriting.Confluence
( isConfluent, confluence, confluenceWith, confluentFunction
, testConfluence, testConfluenceWith, testConfluentFunction
) where
import Common.Rewriting.AC
import Common.Rewriting.MetaVar
import Common.Rewriting.RewriteRule
import Common.Rewriting.Substitution
import Common.Rewriting.Unification
import Common.Uniplate (subtermsAt, applyAtM, somewhereM)
import Data.List
import Data.Maybe
----------------------------------------------------
superImpose :: Rewrite a => RewriteRule a -> RewriteRule a -> [([Int], a)]
superImpose r1 r2 =
[ (loc, s |-> lhs2) | (loc, a) <- subtermsAt lhs2, s <- make a ]
where
lhs1 = lhs (rulePair r1 0)
lhs2 = lhs (rulePair r2 (nrOfMetaVars r1))
make a
| isJust (isMetaVar a) = []
| otherwise = unifyM lhs1 a
criticalPairs :: (Rewrite a, Eq a) => [RewriteRule a] -> [(a, (RewriteRule a, a), (RewriteRule a, a))]
criticalPairs rs =
[ (a, (r1, b1), (r2, b2))
| r1 <- rs
, r2 <- rs
, (loc, a) <- superImpose r1 r2
, b1 <- rewriteM r1 a
, b2 <- applyAtM loc (rewriteM r2) a
, b1 /= b2
]
noDiamondPairs :: (Rewrite a, Eq a) => (a -> a) -> [RewriteRule a] -> [(a, (RewriteRule a, a, a), (RewriteRule a, a, a))]
noDiamondPairs f rs =
[ (a, (r1, e1, nf1), (r2, e2, nf2))
| (a, (r1, e1), (r2, e2)) <- criticalPairs rs
, let (nf1, nf2) = (f e1, f e2)
, nf1 /= nf2
]
reportPairs :: (Show a, Eq a) => [(a, (RewriteRule a, a, a), (RewriteRule a, a, a))] -> IO ()
reportPairs = putStrLn . unlines . zipWith f [1::Int ..]
where
f i (a, (r1, e1, nf1), (r2, e2, nf2)) = unlines
[ show i ++ ") " ++ show a
, " " ++ show r1
, " " ++ show e1 ++ if e1==nf1 then "" else " --> " ++ show nf1
, " " ++ show r2
, " " ++ show e2 ++ if e2==nf2 then "" else " --> " ++ show nf2
]
----------------------------------------------------
isConfluent :: (Eq a, Show a, Rewrite a) => (a -> a) -> [RewriteRule a] -> Bool
isConfluent f = null . noDiamondPairs f
confluentFunction :: (Eq a, Show a, Rewrite a) => (a -> a) -> [RewriteRule a] -> IO ()
confluentFunction f = reportPairs . noDiamondPairs f
confluenceWith :: (Ord a, Show a, Rewrite a) => [Operator a] -> [RewriteRule a] -> IO ()
confluenceWith ops rs = confluentFunction (normalizeWith ops . normalFormWith ops rs) rs
confluence :: (Ord a, Show a, Rewrite a) => [RewriteRule a] -> IO ()
confluence = confluenceWith operators
----------------------------------------------------
testConfluentFunction :: (Eq a, Rewrite a) => (a -> a) -> [RewriteRule a] -> a -> Bool
testConfluentFunction f rs a =
case nub [ f b | r <- rs, b <- somewhereM (rewriteM r) a ] of
_:_:_ -> False
_ -> True
testConfluenceWith :: (Ord a, Rewrite a) => [Operator a] -> [RewriteRule a] -> a -> Bool
testConfluenceWith ops rs = testConfluentFunction (normalFormWith ops rs) rs
testConfluence :: (Ord a, Rewrite a) => [RewriteRule a] -> a -> Bool
testConfluence = testConfluenceWith operators