1
Fork 0
mirror of https://github.com/Jaxan/nominal-lstar.git synced 2025-04-27 14:47:45 +02:00

Adds a teacher for NFAs (bounded to a depth).

Also includes a variation of the up-to technique found in the 'hacking
non-determinism' paper by Bonchi and Pous.
This commit is contained in:
Joshua Moerman 2016-06-27 14:50:57 +02:00
parent a9b3738cd3
commit 8998042874

View file

@ -6,13 +6,14 @@ module Teacher where
import NLambda hiding (alphabet) import NLambda hiding (alphabet)
import qualified NLambda (alphabet) import qualified NLambda (alphabet)
import Debug.Trace
-- Explicit Prelude, as NLambda has quite some clashes -- Explicit Prelude, as NLambda has quite some clashes
import Data.Function (fix) import Data.Function (fix)
import Data.List (zip, (!!), reverse) import Data.List (zip, (!!), reverse)
import Data.Maybe (Maybe (..)) import Data.Maybe (Maybe (..))
import Prelude (Bool (..), Int, Read, Show, error, import Prelude (Bool (..), Int, Read, Show, error,
length, return, ($), (++), (-), (<), length, return, ($), (++), (-), (<),
(==)) (==), (.), (<=))
import qualified Prelude import qualified Prelude
import Control.Monad.Identity (Identity(..)) import Control.Monad.Identity (Identity(..))
@ -45,7 +46,16 @@ data Teacher i = Teacher
teacherWithTarget :: (NominalType i, NominalType q) => Automaton q i -> Teacher i teacherWithTarget :: (NominalType i, NominalType q) => Automaton q i -> Teacher i
teacherWithTarget aut = Teacher teacherWithTarget aut = Teacher
{ membership = automaticMembership aut { membership = automaticMembership aut
, equivalent = automaticEquivalent aut , equivalent = automaticEquivalent bisim aut
, alphabet = automaticAlphabet aut
}
-- 1b. This is a fully automatic teacher, which has an internal automaton
-- Might work for NFAs, not really tested
teacherWithTargetNonDet :: (Show i, Show q, NominalType i, NominalType q) => Int -> Automaton q i -> Teacher i
teacherWithTargetNonDet n aut = Teacher
{ membership = automaticMembership aut
, equivalent = automaticEquivalent (bisimNonDet n) aut
, alphabet = automaticAlphabet aut , alphabet = automaticAlphabet aut
} }
@ -73,12 +83,12 @@ teacherWithTargetAndIO aut = Teacher
-- Implementations of above functions -- Implementations of above functions
automaticMembership aut input = accepts aut input automaticMembership aut input = accepts aut input
automaticEquivalent aut hypo = case solve isEq of automaticEquivalent bisimlator aut hypo = case solve isEq of
Nothing -> error "should be solved" Nothing -> error "should be solved"
Just True -> Nothing Just True -> Nothing
Just False -> Just bisimRes Just False -> Just bisimRes
where where
bisimRes = bisim aut hypo bisimRes = bisimlator aut hypo
isEq = isEmpty bisimRes isEq = isEmpty bisimRes
automaticAlphabet aut = NLambda.alphabet aut automaticAlphabet aut = NLambda.alphabet aut
@ -115,6 +125,49 @@ bisim aut1 aut2 = runIdentity $ go empty (pairsWith addEmptyWord (initialStates
getRevWord (w, _, _) = reverse w getRevWord (w, _, _) = reverse w
addEmptyWord x y = ([], x, y) addEmptyWord x y = ([], x, y)
-- Attempt at using a bisimlution up to to proof bisimulation between NFAs
-- Because why not? Inspired by the Hacking non-determinism paper
-- But they only consider finite sums (which is enough for finite sets)
-- Here I have to do a bit of trickery, which is hopefully correct.
-- I think it is correct, but not yet complete enough, we need more up-to.
bisimNonDet :: (Show i, Show q1, Show q2, NominalType i, NominalType q1, NominalType q2) => Int -> Automaton q1 i -> Automaton q2 i -> Set [i]
bisimNonDet n aut1 aut2 = runIdentity $ go empty (singleton ([], initialStates aut1, initialStates aut2))
where
go rel todo0 = do
-- if elements are too long, we ignore them
let todo0b = filter (\(w,_,_) -> fromBool (length w <= n)) todo0
-- if elements are already in R, we can skip them
let todo1 = filter (\(_, x, y) -> (x, y) `notMember` rel) todo0b
-- now we are going to do a up-to thingy
-- we look at all subsets x2 of x occuring in R (similarly for y)
let xbar x = mapFilter (\(x2, _) -> maybeIf (x2 `isSubsetOf` x) x2) rel
let ybar y = mapFilter (\(_, y2) -> maybeIf (y2 `isSubsetOf` y) y2) rel
-- and then the sums are expressed by these formulea kind of
let xform x y = x `eq` sum (xbar x) /\ forAll (\x2 -> exists (\y2 -> rel `contains` (x2, y2)) (ybar y)) (xbar x)
let yform x y = y `eq` sum (ybar y) /\ forAll (\y2 -> exists (\x2 -> rel `contains` (x2, y2)) (xbar x)) (ybar y)
let notSums x y = not (xform x y /\ yform x y)
-- filter out things expressed as sums
let todo2 = filter (\(_, x, y) -> notSums x y) todo1
-- split into correct pairs and wrong pairs
let (cont, ces) = partition (\(_, x, y) -> (x `intersect` (finalStates aut1)) <==> (y `intersect` (finalStates aut2))) todo2
let aa = NLambda.alphabet aut1
-- the good pairs should make one step
let dtodo = pairsWith (\(w, x, y) a -> (a:w, sumMap (d aut1 a) x, sumMap (d aut2 a) y)) cont aa
-- if there are wrong pairs
--trace "go" $ traceShow rel $ traceShow todo0 $ traceShow todo1 $ traceShow todo2 $ traceShow cont $
ite (isNotEmpty ces)
-- then return counter examples
(return $ map getRevWord ces)
-- else continue with good pairs
(ite (isEmpty dtodo)
(return empty)
(go (rel `union` map stripWord cont) (dtodo))
)
d aut a x = mapFilter (\(s, l, t) -> maybeIf (s `eq` x /\ l `eq` a) t) (delta aut)
stripWord (_, x, y) = (x, y)
getRevWord (w, _, _) = reverse w
addEmptyWord x y = ([], x, y)
sumMap f = sum . (map f)
ioMembership :: (Show i, NominalType i) => [i] -> Formula ioMembership :: (Show i, NominalType i) => [i] -> Formula
ioMembership input = unsafePerformIO $ do ioMembership input = unsafePerformIO $ do