module Data.LTL
( Atomic(..)
, Formula(..)
, subFormulas
, applySub
, applyAtomic
, fmlSignals
, fmlInputs
, fmlOutputs
, isBooleanFormula
, isBooleanNextFormula
, simplePrint
, fNot
, fAnd
, fOr
, fGlobally
, fFinally
) where
import qualified Data.Set as S
( toList
, insert
, empty
)
data Atomic =
Input String
| Output String
deriving (Eq)
instance Ord Atomic where
compare x y = case (x,y) of
(Input _, Output _) -> LT
(Output _, Input _) -> GT
(Input a, Input b) -> compare a b
(Output a, Output b) -> compare a b
instance Show Atomic where
show a = case a of
Input x -> x
Output x -> x
data Formula =
TTrue
| FFalse
| Atomic Atomic
| Not Formula
| Implies Formula Formula
| Equiv Formula Formula
| And [Formula]
| Or [Formula]
| Next Formula
| Globally Formula
| Finally Formula
| Until Formula Formula
| Release Formula Formula
| Weak Formula Formula
deriving (Eq, Show)
instance Ord Formula where
compare x y = case (x,y) of
(Atomic a, Atomic b) -> compare a b
(Not a, Not b) -> compare a b
(Next a, Next b) -> compare a b
(Globally a, Globally b) -> compare a b
(Finally a, Finally b) -> compare a b
(Implies a b, Implies c d) -> case compare a c of
EQ -> compare b d
v -> v
(Equiv a b, Equiv c d) -> case compare a c of
EQ -> compare b d
v -> v
(Until a b, Until c d) -> case compare a c of
EQ -> compare b d
v -> v
(Release a b, Release c d) -> case compare a c of
EQ -> compare b d
v -> v
(And xs, And ys) -> case foldl lexord EQ $ zip xs ys of
EQ -> compare (length xs) (length ys)
v -> v
(Or xs, Or ys) -> case foldl lexord EQ $ zip xs ys of
EQ -> compare (length xs) (length ys)
v -> v
_ -> compare (num x) (num y)
where
num :: Formula -> Int
num f = case f of
FFalse -> 0
TTrue -> 1
Atomic {} -> 2
Not {} -> 3
Implies {} -> 4
Equiv {} -> 5
And {} -> 6
Or {} -> 7
Next {} -> 8
Globally {} -> 9
Finally {} -> 10
Until {} -> 11
Release {} -> 12
Weak {} -> 13
lexord a (b,c) = case a of
EQ -> compare b c
v -> v
applySub
:: (Formula -> Formula) -> Formula -> Formula
applySub f fml = case fml of
Not x -> Not $ f x
Next x -> Next $ f x
Globally x -> Globally $ f x
Finally x -> Finally $ f x
And xs -> And $ map f xs
Or xs -> Or $ map f xs
Equiv x y -> Equiv (f x) (f y)
Implies x y -> Implies (f x) (f y)
Until x y -> Until (f x) (f y)
Release x y -> Release (f x) (f y)
Weak x y -> Weak (f x) (f y)
_ -> fml
applyAtomic
:: (Atomic -> Formula) -> Formula -> Formula
applyAtomic f fml = case fml of
Atomic x -> f x
_ -> applySub (applyAtomic f) fml
fmlSignals
:: Formula -> [Atomic]
fmlSignals = S.toList . signals' S.empty
where
signals' a fml = case fml of
Atomic x -> S.insert x a
_ -> foldl signals' a $ subFormulas fml
fmlInputs
:: Formula -> [String]
fmlInputs fml = map (\(Input x) -> x) $ filter isInput $ fmlSignals fml
where
isInput (Input _) = True
isInput (Output _) = False
fmlOutputs
:: Formula -> [String]
fmlOutputs fml = map (\(Output x) -> x) $ filter isOutput $ fmlSignals fml
where
isOutput (Output _) = True
isOutput (Input _) =False
subFormulas
:: Formula -> [Formula]
subFormulas fml = case fml of
TTrue -> []
FFalse -> []
Atomic _ -> []
Not x -> [x]
Next x -> [x]
Globally x -> [x]
Finally x -> [x]
Implies x y -> [x,y]
Equiv x y -> [x,y]
Until x y -> [x,y]
Release x y -> [x,y]
Weak x y -> [x,y]
And xs -> xs
Or xs -> xs
isBooleanFormula
:: Formula -> Bool
isBooleanFormula fml = case fml of
TTrue -> True
FFalse -> True
Atomic {} -> True
Not x -> isBooleanFormula x
And xs -> all isBooleanFormula xs
Or xs -> all isBooleanFormula xs
_ -> False
isBooleanNextFormula
:: Formula -> Bool
isBooleanNextFormula fml = case fml of
TTrue -> True
FFalse -> True
Atomic {} -> True
Not x -> isBooleanNextFormula x
And xs -> all isBooleanNextFormula xs
Or xs -> all isBooleanNextFormula xs
Next x -> isBooleanFormula x
_ -> False
fAnd
:: [Formula] -> Formula
fAnd xs =
case filter (/= TTrue) $ warp xs of
[] -> TTrue
[x] -> x
_ -> And xs
where
warp = concatMap wAnd
wAnd fml = case fml of
And x -> x
_ -> [fml]
fOr
:: [Formula] -> Formula
fOr xs =
case filter (/= FFalse) $ warp xs of
[] -> FFalse
[x] -> x
_ -> Or xs
where
warp = concatMap wOr
wOr fml = case fml of
Or x -> x
_ -> [fml]
fNot
:: Formula -> Formula
fNot fml = case fml of
TTrue -> FFalse
FFalse -> TTrue
Atomic x -> Not $ Atomic x
Not x -> x
Next x -> Next $ fNot x
Globally x -> Finally $ fNot x
Finally x -> Globally $ fNot x
Implies x y -> And [x, fNot y]
Equiv (Not x) y -> Equiv x y
Equiv x (Not y) -> Equiv x y
Equiv x y -> Equiv (fNot x) y
Until x y -> Release (fNot x) (fNot y)
Release x y -> Until (fNot x) (fNot y)
Weak x y -> Until (fNot y) (And [fNot x, fNot y])
And xs -> Or $ map fNot xs
Or xs -> And $ map fNot xs
fGlobally
:: Formula -> Formula
fGlobally fml = case fml of
Globally FFalse -> FFalse
Globally TTrue -> TTrue
Globally _ -> fml
_ -> Globally fml
fFinally
:: Formula -> Formula
fFinally fml = case fml of
Finally FFalse -> FFalse
Finally TTrue -> TTrue
Finally _ -> fml
_ -> Finally fml
simplePrint
:: Formula -> String
simplePrint fml = case fml of
TTrue -> "true"
FFalse -> "false"
Atomic x -> show x
Not x -> '!' : simplePrint x
Next x -> 'X' : ' ' : simplePrint x
Globally x -> 'G' : ' ' : simplePrint x
Finally x -> 'F' : ' ' : simplePrint x
Implies x y -> "(" ++ simplePrint x ++ " -> " ++ simplePrint y ++ ")"
Equiv x y -> "(" ++ simplePrint x ++ " <-> " ++ simplePrint y ++ ")"
Until x y -> "(" ++ simplePrint x ++ " U " ++ simplePrint y ++ ")"
Release x y -> "(" ++ simplePrint x ++ " R " ++ simplePrint y ++ ")"
Weak x y -> "(" ++ simplePrint x ++ " W " ++ simplePrint y ++ ")"
And [] -> simplePrint TTrue
And [x] -> simplePrint x
And (x:xr) -> "(" ++ simplePrint x ++
concatMap ((" && " ++) . simplePrint) xr ++ ")"
Or [] -> simplePrint FFalse
Or (x:xr) -> "(" ++ simplePrint x ++
concatMap ((" || " ++) . simplePrint) xr ++ ")"