Skip to content
Snippets Groups Projects
Commit 944900ef authored by Hendrik Rassmann's avatar Hendrik Rassmann
Browse files

-* accepts + doesn't terminate

parent 99c32cd5
No related branches found
No related tags found
No related merge requests found
module Derv where
import Data.Maybe (isJust)
import Data.List (nub, sort)
import Data.Set (Set, singleton, empty, map, member, union, cartesianProduct, filter)
import Data.Set (Set, toList, singleton, empty, map, member, union, cartesianProduct, filter)
import Debug.Trace
data RegEx = Empty
......@@ -21,6 +22,9 @@ lang Pop = singleton "-"
-- this doesnt work, Seq Pop Pop -> emptylang (Seq l Pop) = lang (deriv Push l) -- ^-1 operation needed, to do this generaly, since Seq (_) (_ <+> Pop) doesn't work
lang (Seq l r) = Data.Set.map (merge_word) $ cartesianProduct (lang l) (lang r)
lang (Alt l r) = (lang l) `union` (lang r)
--TODO: get lang to work lazyly for *?
lang (Star x) = error "not for Star" --(singleton "") `union` {- ((Data.Set.map (Data.Set.map merge_word (lang x)) -} (lang (Star x))
lang_deriv :: RegEx -> Set String -> Set String
lang_deriv Push = Data.Set.map (init) . (
......@@ -68,34 +72,35 @@ derPush Empty = Zero
derPush Zero = Zero
derPush Push = Empty
derPush Pop = Zero
derPush (Alt l r) = (derPush l) <+> (derPush r) -- Alt (derPush l) (derPush r)
derPush (Seq l r) | final r = (l <.> (derPush r)) <+> (derPush l) -- Alt (Seq l (derPush r)) (derPush l)
| otherwise = l <.> (derPush r) -- Seq l (derPush r)
derPush (Star x) = (Star x) <.> (derPush x) --
derPush (Alt l r) = (derPush l) <+> (derPush r)
derPush (Seq l r) | final r = (l <.> (derPush r)) <+> (derPush l)
| otherwise = l <.> (derPush r) --
derPush (Star x) = (Star x) <.> (derPush x) -- hmm??
derPop :: RegEx -> RegEx
derPop Empty = Push
derPop Zero = Zero
derPop Push = Seq Push Push
derPop Pop = Empty
derPop (Alt l r) = (derPop l) <+> (derPop r) -- Alt (derPop l) (derPop r)
derPop (Seq l r) | final r = (l <.> (derPop r)) <+> (derPop l) -- Alt (Seq l (derPop r)) (derPop l)
| otherwise = l <.> (derPop r)-- Seq l (derPop r)
derPop (Star x) = (Star x) <.> (derPop x) -- is this correct?
derPop Pop = Empty <+> (Pop <.> Push) -- oof
derPop (Alt l r) = (derPop l) <+> (derPop r)
derPop (Seq l r) | final r = (l <.> (derPop r)) <+> (derPop l)
| otherwise = l <.> (derPop r)
derPop (Star x) = ((Star x) <.> (derPop x)) <+> (derPop Empty) -- expreiment (the addition?
-- problem: derPop (Star Push) = (Star Push) <.> (a.a) ... hmmm
--assumes norm
deriv :: RegEx -> (RegEx -> RegEx)
deriv Push = derPush
deriv Pop = derPop
deriv Empty = id
deriv Zero = const Zero
deriv (Seq l r) = \ word -> (deriv l word)<.>(deriv r word)
deriv (Alt l r) = const Zero -- doesn't ALLWAYS exist -- \ word -> (deriv l word)<+>(deriv r word) -- WONG, doesn't exist
deriv (Seq l r) = (deriv l).(deriv r)
deriv (Alt l r) = error "not thought about it enough" -- const Zero -- doesn't ALLWAYS exist -- \ word -> (deriv l word)<+>(deriv r word) -- WONG, doesn't exist
deriv _ = error "blub"
ends_in :: RegEx -> [RegEx]
ends_in Empty = []
ends_in Empty = [Pop] -- Push.Pop == 1
ends_in Zero = []
ends_in Push = [Push]
ends_in Pop = [Pop]
......@@ -103,41 +108,67 @@ ends_in (Alt l r ) = nub $ sort $ ends_in l ++ ends_in r
ends_in (Seq l r) = if (null rs) then ends_in l else rs where rs = ends_in r
ends_in (Star x) = ends_in x
to_check l r = ends_in (Alt (Alt l Pop) r)
to_check l r = ends_in (l <+> r)
--if lasts == [] then [Push] else lasts
-- where lasts = ends_in (Alt l r)
-- only works without *, otherwise wouldn't terminate
-- only works without *, otherwise wouldn't terminate, doesn't work with new derPop def
bisim l r = f (norm l) (norm r) where
f :: RegEx -> RegEx -> Bool
f (Star _) _ = error "doesn't work for star operator"
f _ (Star _) = error "doesn't work for star operator"
f l r | l == r = True
| final l /= final r = False
| otherwise = -- trace (show l <> " =?= " <> (show r)) $
all (uncurry f) [ (deriv a l, deriv a r) | a <- ends_in (Alt l r)]
| otherwise = trace (pp l <> " =?= " <> (pp r)) $
all (uncurry f) [ (deriv a l, deriv a r) | a <- to_check l r]
is_bisim :: [(RegEx, RegEx)] -> Bool
is_bisim pairs = all (\(l,r) -> all (flip elem pairs) [(deriv a l, deriv a r) | a <- ( [Pop] ++ ends_in (Alt l r)) ]) pairs
is_bisim pairs = all (\(l,r) -> all (flip elem pairs) [(deriv a l, deriv a r) | a <- (to_check l r) ]) pairs
closure :: [(RegEx, RegEx)] -> [(RegEx, RegEx)] -> Maybe [(RegEx, RegEx)]
closure rel [] = Just rel
closure rel ((x,y):todo)
| x == y = closure rel todo -- symmetry
| (final x) /= (final y) = trace ("finality diff: " <> (show (pp x,pp y)) <> "\nRel: " <> (show rel)) Nothing
| (x,y) `elem` (rel ++ todo) = closure rel todo
| length rel > 1000 = trace "non det?" $ Nothing
| otherwise = closure ((x,y):rel) ([(norm (deriv a x), norm (deriv a y)) | a <- to_check x y ] ++ todo)
naive :: RegEx -> RegEx -> Maybe [(RegEx, RegEx)]
naive l r = f [] [(l,r)] where
f :: [(RegEx, RegEx)] -> [(RegEx, RegEx)] -> Maybe [(RegEx, RegEx)]
f rel [] = Just rel
f rel ((x,y):todo) | x == y = f rel todo -- symmetry
| (final x) /= (final y) = trace (show rel) $ Nothing -- assuming final computation is easy, which I don't really know right now
| (x,y) `elem` (rel ++ todo) = f rel todo
| length rel > 5 = trace (show rel) $ Nothing
| otherwise = f ((x,y):rel) ([(norm (deriv a x), norm (deriv a y)) | a <- to_check x y ] ++ todo)
naive l r = closure [] [(l,r)] where
naive_bisim :: RegEx -> RegEx -> Bool
naive_bisim l r = isJust $ is_bisim <$> naive l r
-- assuming norm, else nondet
(<#) :: RegEx -> RegEx -> Bool
(<#) l r = naive_bisim (l <+> r) (r)
--seemingly sometimes nondet?
accepts :: RegEx -> RegEx -> Bool -- assuming . . .
expr `accepts` word = final (deriv word expr)
norm :: RegEx -> RegEx
norm Empty = Empty
norm Zero = Zero
norm Push = Push
norm Pop = Pop
norm (Alt l r) = norm l <+> norm r
norm (Alt l r) -- | (norm l) <# (norm r) = norm r -- nondet
-- | (norm r) <# (norm l) = norm l -- nondet
| otherwise = norm l <+> norm r
-- (a b)* a = a (b a)*
norm (Seq (Star l) r) | final (norm (l<.>r)) = (norm r) <+> (norm (Star l)) -- this prob. introduced a suitle bug TODO
-- norm (Seq (Star l) r) =
norm x@(Seq l r) = let normed = norm l <.> norm r in -- > only 1 evaluation step
if x == normed then x else norm normed
norm (Star x) = Star (norm x)
norm (Star (Star x)) = norm $ Star x
norm (Star x) | (norm x) == Empty = Empty
| (norm x) == Zero = Empty
| otherwise = Star $ norm $ x
class SemiRing a where
......@@ -146,6 +177,15 @@ class SemiRing a where
(<.>) :: a -> a -> a
(<+>) :: a -> a -> a
pp :: RegEx -> String
pp Empty = "1"
pp Zero = "0"
pp Pop = "-"
pp Push = "x"
pp (Seq l r) = "(" <> (pp l) <> " " <> (pp r) <> ")"
pp (Alt l r) = "(" <> (pp l) <> " | " <> (pp r) <> ")"
pp (Star x) = "(" <> (pp x) <> ")*"
instance SemiRing RegEx where
one = Empty
zero = Zero
......@@ -153,6 +193,7 @@ instance SemiRing RegEx where
_ <.> Zero = Zero
Empty <.> r = r
l <.> Empty = l
-- (Star l) <.> r = ----
Push <.> Pop = Empty -- my own simplification, not enough to do eval; Push <.> (Seq Pop _) doesn't get simplified
(Seq l Push) <.> Pop = l
r <.> (Seq s t) = Seq (r <.> s) t -- (Seq r s) <.> t = Seq r (s <.> t) -- old klammerung
......@@ -161,6 +202,8 @@ instance SemiRing RegEx where
l <.> r = Seq l r
Zero <+> r = r
l <+> Zero = l
Empty <+> (Star x) = (Star x)
(Star x) <+> Empty = (Star x)
(Alt r s) <+> t = r <+> (s <+> t)
r <+> (Alt s t) | (r == s) = (Alt s t)
| r <= s = Alt (r) (Alt s t)
......
......@@ -2,9 +2,13 @@
--module Test where
import Derv
import Debug.Trace
import Data.Set (member)
import Control.Applicative (liftA2)
import Control.Monad (when)
import Control.Monad.IO.Class (liftIO)
import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
......@@ -12,17 +16,35 @@ import qualified Hedgehog.Range as Range
single_expr :: Gen RegEx
single_expr = Gen.element [Empty, Zero, Push, Pop]
--seq_expr :: Gen RegEx
--alt_expr :: Gen RegEx
--star_expr :: Gen RegEx
expr :: Gen RegEx
expr = Gen.recursive Gen.choice
(Gen.constant <$> [Empty, Zero, Push, Pop]) -- nonrecursives
(Gen.subterm2 expr expr <$> [Seq, Alt]) -- recursives
prop_assoc :: Property
prop_assoc =
-- * means works with star expressions
star_expr :: Gen RegEx
star_expr = Gen.recursive Gen.choice
[expr] -- non-recs
[Gen.subterm expr Star]
rel :: Gen [(RegEx, RegEx)]
rel = Gen.list (Range.linear 0 5) (liftA2 (,) expr expr)
word :: Gen RegEx
word = foldl (<.>) Empty <$> Gen.list (Range.linear 0 2) (single_expr)
-- doesn't work for Star
prop_norm_idempotent :: Property
prop_norm_idempotent =
property $ do
a <- forAll $ expr -- star_expr
(norm a) === (norm (norm a))
-- - Alt Push (Star Push)
-- + Alt Empty (Alt Push (Star Push)) nont for star :(
prop_assoc_norm :: Property
prop_assoc_norm =
property $ do
a <- forAll $ expr
b <- forAll $ expr
......@@ -30,36 +52,49 @@ prop_assoc =
norm ((a <.> b) <.> c) === (norm (a <.> (b <.> c)))
norm ((a <+> b) <+> c) === (norm (a <+> (b <+> c)))
-- doesn't work with Star, if you replace <.> with `Seq`
prop_assoc_norm_bisim :: Property
prop_assoc_norm_bisim =
property $ do
a <- forAll $ star_expr
b <- forAll $ star_expr
c <- forAll $ star_expr
norm ((a <.> b) <.> c) `naive_bisim` (norm (a <.> (b <.> c))) === True
norm ((a <+> b) <+> c) `naive_bisim` (norm (a <+> (b <+> c))) === True
-- *
prop_comm :: Property
prop_comm =
property $ do
a <- forAll $ expr
b <- forAll $ expr
a <- forAll $ star_expr
b <- forAll $ star_expr
norm (a <+> b) === (norm (a <+> b))
-- *
prop_idem :: Property
prop_idem =
property $ do
a <- forAll $ expr
a <- forAll $ star_expr
norm (a <+> a) === (norm a)
-- *
prop_id :: Property
prop_id =
property $ do
a <- forAll $ expr
a <- forAll $ star_expr
norm (a <+> zero) === (norm a)
norm (zero <+> a) === (norm a)
norm (a <.> one) === (norm a)
norm (one <.> a) === (norm a)
-- no lang definition for stars yet
prop_norm :: Property
prop_norm =
property $ do
a <- forAll $ expr
lang a === (lang (norm a))
-- no lang for stars
prop_dist :: Property
prop_dist =
property $ do
......@@ -69,49 +104,74 @@ prop_dist =
lang (norm (a <.> (b <+> c))) === lang ((norm ((a <.> b) <+> (a <.> c))))
lang (norm ((a <+> b) <.> c)) === lang (norm ((a <.> c) <+> (b <.> c)))
-- *
prop_ann :: Property
prop_ann =
property $ do
a <- forAll $ expr
a <- forAll $ star_expr
norm (a <.> zero) === zero
norm (zero <.> a) === zero
-- no lang for stars
prop_final :: Property
prop_final =
property $ do
a <- forAll $ expr
final (norm a) === member "" (lang (norm a))
{-
--doesnt work for derPop Pop = Zero =?= Pop <.> Pop
prop_bisim :: Property
prop_bisim =
withTests 1000 $ property $ do
a <- forAll $ expr
b <- forAll $ expr
(lang a == (lang b)) === (bisim (norm a) (norm b))
-}
-- no lang for star
prop_lang_lang2 :: Property
prop_lang_lang2 =
property $ do
a <- forAll $ expr
lang (norm a) === (lang2 (norm a))
-- no lang for star
prop_lang_deriv_r_deriv_lang_r :: Property
prop_lang_deriv_r_deriv_lang_r =
property $ do
r <- forAll $ expr
(lang.derPush.norm) r === (((lang_deriv Push).lang.norm) r)
prop_bisim_is_bisim :: Property
prop_bisim_is_bisim =
-- feels like it's true, but i get problems with stars
-- (unexpected, if stars in l and rhs, both fail, so equivalence remains)
--prop_bisim_is_bisim :: Property
--prop_bisim_is_bisim =
-- property $ do
-- pairs <- forAll rel
-- when (is_bisim pairs) $ do
-- all (\(l,r) -> bisim l r) pairs === True
--prop_accepts_lang :: Property
--todo, generate words (== sequences of symbols)
--only to check that accepts terminates
prop_accepts_implies_includes :: Property
prop_accepts_implies_includes =
property $ do
pairs <- forAll $ Gen.list (Range.linear 0 5) (liftA2 (,) expr expr)
when (is_bisim pairs) $ do
all (\(l,r) -> bisim l r) pairs === True
matcher <- forAll star_expr
w <- forAll word
liftIO $ print (pp matcher <> " accepts " <> (pp w))
(if ((norm matcher) `accepts` (norm w)) then True else True) === True
tests :: IO Bool
tests =
checkParallel $$(discover)
main = tests
-- deriv Push ((Star Push) <.> (Pop)) => Zero
-- naive (Pop <+> (Star Push)) ((Star Push) <.> (Pop))
-- this gives the wrong answer
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment