mirror of
https://github.com/Jaxan/nominal-lstar.git
synced 2025-04-27 14:47:45 +02:00
Made NLStar simpler and 3x as fast
This commit is contained in:
parent
a3e6d0581c
commit
5f5b35bbc8
6 changed files with 50 additions and 56 deletions
18
app/Main.hs
18
app/Main.hs
|
@ -42,20 +42,18 @@ mainExample learnerName teacherName autName = do
|
||||||
EqDFA -> teacherWithTarget automaton
|
EqDFA -> teacherWithTarget automaton
|
||||||
EqNFA k -> teacherWithTargetNonDet k automaton
|
EqNFA k -> teacherWithTargetNonDet k automaton
|
||||||
EquivalenceIO -> teacherWithTargetAndIO automaton
|
EquivalenceIO -> teacherWithTargetAndIO automaton
|
||||||
let h = case read learnerName of
|
case read learnerName of
|
||||||
NomLStar -> learnAngluinRows teacher
|
NomLStar -> print $ learnAngluinRows teacher
|
||||||
NomLStarCol -> learnAngluin teacher
|
NomLStarCol -> print $ learnAngluin teacher
|
||||||
NomNLStar -> learnBollig 0 0 teacher
|
NomNLStar -> print $ learnBollig 0 0 teacher
|
||||||
print h
|
|
||||||
|
|
||||||
mainWithIO :: String -> IO ()
|
mainWithIO :: String -> IO ()
|
||||||
mainWithIO learnerName = do
|
mainWithIO learnerName = do
|
||||||
let t = teacherWithIO atoms
|
let t = teacherWithIO atoms
|
||||||
let h = case read learnerName of
|
case read learnerName of
|
||||||
NomLStar -> learnAngluinRows t
|
NomLStar -> print $ learnAngluinRows t
|
||||||
NomLStarCol -> learnAngluin t
|
NomLStarCol -> print $ learnAngluin t
|
||||||
NomNLStar -> learnBollig 0 0 t
|
NomNLStar -> print $ learnBollig 0 0 t
|
||||||
print h
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
|
|
@ -14,11 +14,10 @@ learn :: (Read i, Contextual i, NominalType i, Show i) => Set i -> IO ()
|
||||||
learn alphSet = do
|
learn alphSet = do
|
||||||
[learnerName] <- getArgs
|
[learnerName] <- getArgs
|
||||||
let t = teacherWithIO2 alphSet
|
let t = teacherWithIO2 alphSet
|
||||||
let h = case read learnerName of
|
case read learnerName of
|
||||||
NomLStar -> learnAngluinRows t
|
NomLStar -> hPrint stderr $ learnAngluinRows t
|
||||||
NomLStarCol -> learnAngluin t
|
NomLStarCol -> hPrint stderr $ learnAngluin t
|
||||||
NomNLStar -> learnBollig 0 0 t
|
NomNLStar -> hPrint stderr $ learnBollig 0 0 t
|
||||||
hPrint stderr h
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
|
|
@ -9,7 +9,7 @@ import NLambda
|
||||||
|
|
||||||
type TableCompletionHandler i = Teacher i -> State i -> State i
|
type TableCompletionHandler i = Teacher i -> State i -> State i
|
||||||
type CounterExampleHandler i = Teacher i -> State i -> Set [i] -> State i
|
type CounterExampleHandler i = Teacher i -> State i -> Set [i] -> State i
|
||||||
type HypothesisConstruction i = State i -> Automaton (BRow i) i
|
type HypothesisConstruction i hq = State i -> Automaton hq i
|
||||||
|
|
||||||
data TestResult i
|
data TestResult i
|
||||||
= Succes -- test succeeded, no changes required
|
= Succes -- test succeeded, no changes required
|
||||||
|
@ -39,13 +39,13 @@ makeCompleteWith tests teacher state0 = go tests state0
|
||||||
-- Simple general learning loop: 1. make the table complete 2. construct
|
-- Simple general learning loop: 1. make the table complete 2. construct
|
||||||
-- hypothesis 3. ask teacher. Repeat until done. If the teacher is adequate
|
-- hypothesis 3. ask teacher. Repeat until done. If the teacher is adequate
|
||||||
-- termination implies correctness.
|
-- termination implies correctness.
|
||||||
learn :: LearnableAlphabet i
|
learn :: (NominalType hq, Show hq, LearnableAlphabet i)
|
||||||
=> TableCompletionHandler i
|
=> TableCompletionHandler i
|
||||||
-> CounterExampleHandler i
|
-> CounterExampleHandler i
|
||||||
-> HypothesisConstruction i
|
-> HypothesisConstruction i hq
|
||||||
-> Teacher i
|
-> Teacher i
|
||||||
-> State i
|
-> State i
|
||||||
-> Automaton (BRow i) i
|
-> Automaton hq i
|
||||||
learn makeComplete handleCounterExample constructHypothesis teacher s =
|
learn makeComplete handleCounterExample constructHypothesis teacher s =
|
||||||
trace "##################" $
|
trace "##################" $
|
||||||
trace "1. Making it complete and consistent" $
|
trace "1. Making it complete and consistent" $
|
||||||
|
|
|
@ -8,7 +8,7 @@ import Teacher
|
||||||
import Data.List (inits, tails)
|
import Data.List (inits, tails)
|
||||||
import Debug.Trace
|
import Debug.Trace
|
||||||
import NLambda
|
import NLambda
|
||||||
import Prelude (Bool (..), Maybe (..), fst, id, show, ($), (++), (.))
|
import Prelude (Bool (..), Maybe (..), id, show, ($), (++), (.))
|
||||||
import qualified Prelude hiding ()
|
import qualified Prelude hiding ()
|
||||||
|
|
||||||
justOne :: (Contextual a, NominalType a) => Set a -> Set a
|
justOne :: (Contextual a, NominalType a) => Set a -> Set a
|
||||||
|
@ -95,7 +95,7 @@ consistencyTest2 State{..} = case solve (isEmpty defect) of
|
||||||
defect = triplesWithFilter (
|
defect = triplesWithFilter (
|
||||||
\s1 s2 a -> maybeIf (candidate s1 s2 a) ((s1, s2, a), discrepancy (rowa t s1 a) (rowa t s2 a))
|
\s1 s2 a -> maybeIf (candidate s1 s2 a) ((s1, s2, a), discrepancy (rowa t s1 a) (rowa t s2 a))
|
||||||
) ss ss aa
|
) ss ss aa
|
||||||
columns = sum $ map (\((s1,s2,a),es) -> map (a:) es) defect
|
columns = sum $ map (\((_,_,a),es) -> map (a:) es) defect
|
||||||
|
|
||||||
-- Some coauthor's faster version
|
-- Some coauthor's faster version
|
||||||
consistencyTest3 :: NominalType i => State i -> TestResult i
|
consistencyTest3 :: NominalType i => State i -> TestResult i
|
||||||
|
@ -109,4 +109,4 @@ consistencyTest3 State{..} = case solve (isEmpty defect) of
|
||||||
defect = pairsWithFilter (
|
defect = pairsWithFilter (
|
||||||
\(s1, s2) a -> maybeIf (candidate1 s1 s2 a) ((s1, s2, a), discrepancy (rowa t s1 a) (rowa t s2 a))
|
\(s1, s2) a -> maybeIf (candidate1 s1 s2 a) ((s1, s2, a), discrepancy (rowa t s1 a) (rowa t s2 a))
|
||||||
) rowPairs aa
|
) rowPairs aa
|
||||||
columns = sum $ map (\((s1,s2,a),es) -> map (a:) es) defect
|
columns = sum $ map (\((_,_,a),es) -> map (a:) es) defect
|
||||||
|
|
|
@ -11,34 +11,27 @@ import NLambda
|
||||||
import Prelude (Bool (..), Int, Maybe (..), fst, snd, ($), (++), (.), (<=))
|
import Prelude (Bool (..), Int, Maybe (..), fst, snd, ($), (++), (.), (<=))
|
||||||
import qualified Prelude hiding ()
|
import qualified Prelude hiding ()
|
||||||
|
|
||||||
rowUnion :: NominalType i => Set (BRow i) -> BRow i
|
-- Comparing two graphs of a function is inefficient in NLambda,
|
||||||
rowUnion set = Prelude.uncurry union . setTrueFalse . partition snd $ map (\is -> (is, exists fromBool (mapFilter (\(is2, b) -> maybeIf (is `eq` is2) b) flatSet))) allIs
|
-- because we do not have a map data structure. (So the only way
|
||||||
where
|
-- is by taking a product and filtering on equal inputs.)
|
||||||
flatSet = sum set
|
-- So instead of considering a row as E -> 2, we simply take it
|
||||||
allIs = map fst flatSet
|
-- as a subset.
|
||||||
setTrueFalse (trueSet, falseSet) = (map (setSecond True) trueSet, map (setSecond False) falseSet)
|
-- This does hinder generalisations to other nominal join semi-
|
||||||
setSecond a (x, _) = (x, a)
|
-- lattices than the Booleans.
|
||||||
|
brow :: (NominalType i) => Table i Bool -> [i] -> Set [i]
|
||||||
|
brow t is = mapFilter (\((a,b),c) -> maybeIf (eq is a /\ fromBool c) b) t
|
||||||
|
|
||||||
boolImplies :: Bool -> Bool -> Bool
|
rfsaClosednessTest3 :: LearnableAlphabet i => State i -> TestResult i
|
||||||
boolImplies = (<=)
|
rfsaClosednessTest3 State{..} = case solve (isEmpty defect) of
|
||||||
|
|
||||||
sublang :: NominalType i => BRow i -> BRow i -> Formula
|
|
||||||
sublang r1 r2 = forAll fromBool $ pairsWithFilter (\(i1, f1) (i2, f2) -> maybeIf (i1 `eq` i2) (f1 `boolImplies` f2)) r1 r2
|
|
||||||
|
|
||||||
sublangs :: NominalType i => BRow i -> Set (BRow i) -> Set (BRow i)
|
|
||||||
sublangs r = filter (`sublang` r)
|
|
||||||
|
|
||||||
rfsaClosednessTest2 :: LearnableAlphabet i => State i -> TestResult i
|
|
||||||
rfsaClosednessTest2 State{..} = case solve (isEmpty defect) of
|
|
||||||
Just True -> Succes
|
Just True -> Succes
|
||||||
Just False -> trace "Not closed" $ Failed defect empty
|
Just False -> trace "Not closed" $ Failed defect empty
|
||||||
Nothing -> trace "@@@ Unsolved Formula (rfsaClosednessTest) @@@" $
|
Nothing -> trace "@@@ Unsolved Formula (rfsaClosednessTest) @@@" $
|
||||||
Failed defect empty
|
Failed defect empty
|
||||||
where
|
where
|
||||||
defect = pairsWithFilter (\u a -> maybeIf (rowa t u a `neq` rowUnion (sublangs (rowa t u a) primesUpp)) (u ++ [a])) ss aa
|
defect = filter (\ua -> brow t ua `neq` sum (filter (`isSubsetOf` brow t ua) primesUpp)) ssa
|
||||||
primesUpp = filter (\r -> r `neq` rowUnion (sublangs r (allRows \\ orbit [] r))) allRowsUpp
|
primesUpp = filter (\r -> isNotEmpty r /\ r `neq` sum (filter (`isSubsetOf` r) (allRows \\ orbit [] r))) allRowsUpp
|
||||||
allRowsUpp = map (row t) ss
|
allRowsUpp = map (brow t) ss
|
||||||
allRows = allRowsUpp `union` map (row t) ssa
|
allRows = allRowsUpp `union` map (brow t) ssa
|
||||||
|
|
||||||
rfsaConsistencyTest :: LearnableAlphabet i => State i -> TestResult i
|
rfsaConsistencyTest :: LearnableAlphabet i => State i -> TestResult i
|
||||||
rfsaConsistencyTest State{..} = case solve (isEmpty defect) of
|
rfsaConsistencyTest State{..} = case solve (isEmpty defect) of
|
||||||
|
@ -47,26 +40,27 @@ rfsaConsistencyTest State{..} = case solve (isEmpty defect) of
|
||||||
Nothing -> trace "@@@ Unsolved Formula (rfsaConsistencyTest) @@@" $
|
Nothing -> trace "@@@ Unsolved Formula (rfsaConsistencyTest) @@@" $
|
||||||
Failed empty defect
|
Failed empty defect
|
||||||
where
|
where
|
||||||
candidates = pairsWithFilter (\u1 u2 -> maybeIf (row t u2 `sublang` row t u1) (u1, u2)) ss ss
|
candidates = pairsWithFilter (\u1 u2 -> maybeIf (brow t u2 `isSubsetOf` brow t u1) (u1, u2)) ss ss
|
||||||
defect = triplesWithFilter (\(u1, u2) a v -> maybeIf (not (tableAt t (u1 ++ [a]) v) /\ tableAt t (u2++[a]) v) (a:v)) candidates aa ee
|
defect = triplesWithFilter (\(u1, u2) a v -> maybeIf (not (tableAt t (u1 ++ [a]) v) /\ tableAt t (u2 ++ [a]) v) (a:v)) candidates aa ee
|
||||||
|
|
||||||
constructHypothesisBollig :: NominalType i => State i -> Automaton (BRow i) i
|
-- Note that we do not have the same type of states as the angluin algorithm.
|
||||||
|
-- We have Set [i] instead of BRow i. (However, They are isomorphic.)
|
||||||
|
constructHypothesisBollig :: NominalType i => State i -> Automaton (Set [i]) i
|
||||||
constructHypothesisBollig State{..} = automaton q a d i f
|
constructHypothesisBollig State{..} = automaton q a d i f
|
||||||
where
|
where
|
||||||
q = primesUpp
|
q = primesUpp
|
||||||
a = aa
|
a = aa
|
||||||
i = filter (\r -> r `sublang` row t []) q
|
i = filter (`isSubsetOf` brow t []) q
|
||||||
f = filter (\r -> singleton True `eq` mapFilter (\(i,b) -> maybeIf (i `eq` []) b) r) q
|
f = filter (`contains` []) q
|
||||||
d0 = triplesWithFilter (\s a s2 -> maybeIf (row t s2 `sublang` rowa t s a) (row t s, a, row t s2)) ss aa ss
|
d0 = triplesWithFilter (\s a s2 -> maybeIf (brow t s2 `isSubsetOf` brow t (s ++ [a])) (brow t s, a, brow t s2)) ss aa ss
|
||||||
d = filter (\(q1, _, q2) -> q1 `member` q /\ q2 `member` q) d0
|
d = filter (\(q1, _, q2) -> q1 `member` q /\ q2 `member` q) d0
|
||||||
primesUpp = filter (\r -> nonEmpty r /\ r `neq` rowUnion (sublangs r (allRows \\ orbit [] r))) allRowsUpp
|
primesUpp = filter (\r -> isNotEmpty r /\ r `neq` sum (filter (`isSubsetOf` r) (allRows \\ orbit [] r))) allRowsUpp
|
||||||
nonEmpty = isNotEmpty . filter (fromBool . Prelude.snd)
|
allRowsUpp = map (brow t) ss
|
||||||
allRowsUpp = map (row t) ss
|
allRows = allRowsUpp `union` map (brow t) ssa
|
||||||
allRows = allRowsUpp `union` map (row t) ssa
|
|
||||||
|
|
||||||
makeCompleteBollig :: LearnableAlphabet i => TableCompletionHandler i
|
makeCompleteBollig :: LearnableAlphabet i => TableCompletionHandler i
|
||||||
makeCompleteBollig = makeCompleteWith [rfsaClosednessTest2, rfsaConsistencyTest]
|
makeCompleteBollig = makeCompleteWith [rfsaClosednessTest3, rfsaConsistencyTest]
|
||||||
|
|
||||||
learnBollig :: LearnableAlphabet i => Int -> Int -> Teacher i -> Automaton (BRow i) i
|
learnBollig :: LearnableAlphabet i => Int -> Int -> Teacher i -> Automaton (Set [i]) i
|
||||||
learnBollig k n teacher = learn makeCompleteBollig useCounterExampleMP constructHypothesisBollig teacher initial
|
learnBollig k n teacher = learn makeCompleteBollig useCounterExampleMP constructHypothesisBollig teacher initial
|
||||||
where initial = constructEmptyState k n teacher
|
where initial = constructEmptyState k n teacher
|
||||||
|
|
|
@ -30,6 +30,8 @@ import Prelude hiding (and, curry, filter, lookup, map, not, sum)
|
||||||
|
|
||||||
-- We can determine its completeness with the following
|
-- We can determine its completeness with the following
|
||||||
-- It returns all witnesses (of the form sa) for incompleteness
|
-- It returns all witnesses (of the form sa) for incompleteness
|
||||||
|
|
||||||
|
{- Disabled, didn't work anymore, and I don't know what it does
|
||||||
nonDetClosednessTest :: NominalType i => State i -> TestResult i
|
nonDetClosednessTest :: NominalType i => State i -> TestResult i
|
||||||
nonDetClosednessTest State{..} = case solve (isEmpty defect) of
|
nonDetClosednessTest State{..} = case solve (isEmpty defect) of
|
||||||
Just True -> Succes
|
Just True -> Succes
|
||||||
|
@ -55,3 +57,4 @@ makeCompleteNonDet = makeCompleteWith [nonDetClosednessTest]
|
||||||
learnNonDet :: LearnableAlphabet i => Teacher i -> Automaton (BRow i) i
|
learnNonDet :: LearnableAlphabet i => Teacher i -> Automaton (BRow i) i
|
||||||
learnNonDet teacher = learn makeCompleteNonDet useCounterExampleMP constructHypothesisNonDet teacher initial
|
learnNonDet teacher = learn makeCompleteNonDet useCounterExampleMP constructHypothesisNonDet teacher initial
|
||||||
where initial = constructEmptyState 0 0 teacher
|
where initial = constructEmptyState 0 0 teacher
|
||||||
|
-}
|
||||||
|
|
Loading…
Add table
Reference in a new issue