module HyLo.Formula.Rewrite ( Rewr(..),
pnf, simplify )
where
import HyLo.Formula
import Data.List
import Control.Monad.State
import Text.Read ( Read(..) )
import qualified Text.ParserCombinators.ReadPrec as RP
import Text.ParserCombinators.ReadP ( string )
import qualified Data.Generics.Uniplate.Operations as Uniplate
data Rewr prop = Orig prop | Rewr Int
deriving (Eq, Ord)
instance Show prop => Show (Rewr prop) where
showsPrec n (Orig prop) = showChar 'O' . showsPrec n prop
showsPrec _ (Rewr i) = showString "RW_" . shows i
instance Read prop => Read (Rewr prop) where
readPrec = RP.choice [do 'O' <- RP.get; Orig `liftM` readPrec,
do _ <- RP.lift (string "RW_"); Rewr `liftM` readPrec]
wrapProps :: Formula n p r -> Formula n (Rewr p) r
wrapProps = mapSig id Orig id
data BndInfo nom = Free nom | Bound nom
deriving (Eq, Ord, Read, Show)
addBndInfo :: Eq n => Formula n p r -> Formula (BndInfo n) p r
addBndInfo = go Free
where go bnd (Down i f) = Down (Bound i) $ go (record i bnd) f
go bnd f = onShape bnd id id (go bnd) f
record i bnd = \n -> if n == i then Bound i else bnd n
removeBndInfo :: Formula (BndInfo n) p r -> Formula n p r
removeBndInfo = mapSig unBnd id id
where unBnd (Free i) = i
unBnd (Bound i) = i
type RewrFormula n p r = Formula (BndInfo n) (Rewr p) r
type Rewriter p = State [Rewr p]
runRewriter :: Rewriter p a -> a
runRewriter r = evalState r new_props
where new_props = map Rewr [0..]
pnf :: Eq n => [Formula n p r] -> [Formula n (Rewr p) r]
pnf = runRewriter
. fmap (map removeBndInfo . concat)
. mapM (toPNF . addBndInfo . wrapProps . listerize . nnf)
freshProp :: Rewriter p (RewrFormula n p r)
freshProp = do pps <- get
case pps of
(p:ps) -> put ps >> return (Prop p)
_ -> error "freshProp pattern matching"
listerize :: Formula n p r -> Formula n p r
listerize (f :|: g) = orify . concatMap (orList . listerize) $ [f,g]
listerize (f :&: g) = andify . concatMap (andList . listerize) $ [f,g]
listerize f = composeMap id listerize f
toPNF :: RewrFormula n p r -> Rewriter p [RewrFormula n p r]
toPNF f
| isDisj f = removeDisCon =<< mapM toPNF (orList f)
| isConj f = concat `fmap` mapM toPNF (andList f)
| Just (m,f') <- modality f = addModalOp m =<< toPNF f'
| isAtomic f = return [f]
| otherwise = error $ "toPNF - unhandled case..." ++ shape f
shape :: Formula n p r -> String
shape = show . mapSig (const ()) (const ()) (const ())
removeDisCon :: [[RewrFormula n p r]] -> Rewriter p [RewrFormula n p r]
removeDisCon fs = mk_result `fmap` mapM (\_ -> freshProp) conjs
where (lits, conjs)= partition isLit fs
where isLit [f] = not (isDisj f)
isLit _ = False
mk_result fresh_props = big_dis:lil_diss
where big_dis = orify $ concat (fresh_props:lits)
lil_diss = [(Neg p :|: f) | (p,conj) <- zip fresh_props conjs,
f <- conj]
addModalOp :: RewrModality n p r
-> [RewrFormula n p r]
-> Rewriter p [RewrFormula n p r]
addModalOp m fs = case (isABox m, isADia m) of
(True, False) -> return $ map (addBoxToCl m) fs
(False, True) -> addDiaRemoveDis m fs
(True, True) -> return $ map (addDiaToCl m) fs
_ -> error "addModalOp: unknown modal op"
addBoxToCl :: RewrModality n p r -> RewrFormula n p r -> RewrFormula n p r
addBoxToCl m = orify . addBoxToF . partition isGlobalF . orList
where addBoxToF (globals, locals) = (apply m $ orify locals) : globals
addDiaToCl :: RewrModality n p r -> RewrFormula n p r -> RewrFormula n p r
addDiaToCl m = orify . addDiaToF . partition isGlobalF . orList
where addDiaToF (globals, locals) = globals ++ map (apply m) locals
addDiaRemoveDis :: RewrModality n p r
-> [RewrFormula n p r]
-> Rewriter p [RewrFormula n p r]
addDiaRemoveDis m l = mk_res `fmap` mapM (\_ -> freshProp) disjs
where (disjs, non_disjs) = partition isDisj l
(globs, lits) = partition isGlobalF non_disjs
mk_res fresh_props = concat [
[apply m $ andify (fresh_props ++ lits)],
[addBoxToCl (dual m) (Neg p :|: f) |
(p,f) <- zip fresh_props disjs],
globs
]
orList :: Formula n p r -> [Formula n p r]
orList = unfoldr next . Just
where next (Just (a :|: b)) = Just (a, Just b)
next (Just f) = Just (f, Nothing)
next Nothing = Nothing
orify :: [Formula n p r] -> Formula n p r
orify [] = Bot
orify fs = foldr1 (:|:) fs
andList :: Formula n p r -> [Formula n p r]
andList = unfoldr next . Just
where next (Just (a :&: b)) = Just (a, Just b)
next (Just f) = Just (f, Nothing)
next Nothing = Nothing
andify :: [Formula n p r] -> Formula n p r
andify [] = Top
andify fs = foldr1 (:&:) fs
isConj :: Formula n p r -> Bool
isConj (_ :&: _) = True
isConj _ = False
isDisj :: Formula n p r -> Bool
isDisj (_ :|: _) = True
isDisj _ = False
isAtomic :: Formula n p r -> Bool
isAtomic Top = True
isAtomic Bot = True
isAtomic (Nom _) = True
isAtomic (Prop _) = True
isAtomic (Neg f) = isAtomic f
isAtomic _ = False
isGlobalF :: RewrFormula n p r -> Bool
isGlobalF = maybe False (isGlobal . fst) . modality
data Modality n p r = M_Box r | M_Dia r
| M_IBox r | M_IDia r
| M_A | M_E
| M_D | M_B
| M_At n
| M_Down n
| M_Count CountOp (Where r) Int
type RewrModality n p r = Modality (BndInfo n) (Rewr p) r
isABox :: Modality n p r -> Bool
isABox M_Box {} = True
isABox M_IBox {}= True
isABox M_At {} = True
isABox M_Down{} = True
isABox M_A = True
isABox M_D = True
isABox _ = False
isADia :: Modality n p r -> Bool
isADia M_At {} = True
isADia M_Down{} = True
isADia m = not $ isABox m
isGlobal :: Modality (BndInfo n) p r -> Bool
isGlobal M_Box {} = False
isGlobal M_Dia {} = False
isGlobal M_IBox {} = False
isGlobal M_IDia {} = False
isGlobal M_Down{} = False
isGlobal (M_At (Bound _)) = False
isGlobal M_D{} = False
isGlobal M_B{} = False
isGlobal _ = True
apply :: Modality n p r -> Formula n p r -> Formula n p r
apply (M_Box r) = Box r
apply (M_Dia r) = Diam r
apply (M_IBox r) = IBox r
apply (M_IDia r) = IDiam r
apply (M_At i) = At i
apply (M_Down x) = Down x
apply (M_Count c w i) = Count c w i
apply M_A = A
apply M_E = E
apply M_D = D
apply M_B = B
dual :: Modality n p r -> Modality n p r
dual (M_Box r) = M_Dia r
dual (M_Dia r) = M_Box r
dual (M_IBox r) = M_IDia r
dual (M_IDia r) = M_IBox r
dual m@M_At {} = m
dual m@M_Down{} = m
dual M_A = M_E
dual M_E = M_A
dual M_D = M_B
dual M_B = M_D
dual (M_Count c w i) = M_Count (negCount c) w i
modality :: Formula n p r -> Maybe (Modality n p r, Formula n p r)
modality (Diam r f) = Just (M_Dia r, f)
modality (Box r f) = Just (M_Box r, f)
modality (At i f) = Just (M_At i, f)
modality (Down x f) = Just (M_Down x, f)
modality (IDiam r f) = Just (M_IDia r, f)
modality (IBox r f) = Just (M_IBox r, f)
modality (A f) = Just (M_A , f)
modality (E f) = Just (M_E , f)
modality (D f) = Just (M_D , f)
modality (B f) = Just (M_B , f)
modality (Count c w i f) = Just (M_Count c w i, f)
modality _ = Nothing
simplify :: (Ord n, Ord p, Ord r) => Formula n p r -> Formula n p r
simplify = Uniplate.rewrite simpl
where simpl (Neg Top) = Just Bot
simpl (Neg Bot) = Just Top
simpl (At _ Top) = Just Top
simpl (At _ Bot) = Just Bot
simpl (Box _ Top) = Just Top
simpl (Diam _ Bot) = Just Bot
simpl (IBox _ Top) = Just Top
simpl (IDiam _ Bot) = Just Bot
simpl (Bot :&: _) = Just Bot
simpl (Top :&: f) = Just f
simpl (f :&: Neg g)| f == g = Just Bot
simpl (Neg f :&: g)| f == g = Just Bot
simpl (f :&: g) | f == g = Just f
simpl (Top :|: _) = Just Top
simpl (Bot :|: f) = Just f
simpl (f :|: g) | f == g = Just f
simpl (f :|: Neg g)| f == g = Just Top
simpl (f :<-->: g) | f == g = Just Top
simpl (Top :<-->: f) = Just f
simpl (Bot :<-->: f) = Just (Neg f)
simpl (Top :-->: f) = Just f
simpl (Bot :-->: _) = Just Top
simpl (_ :-->: Top) = Just Top
simpl (f :-->: Bot) = Just (Neg f)
simpl (f :-->: g) | f == g = Just Top
simpl f = orient f
orient (f :&: g) | f > g = Just (g :&: f)
orient (f :|: g) | f > g = Just (g :|: f)
orient (f :<-->: g) | f > g = Just (g :<-->: f)
orient _ = Nothing