mirror of
https://github.com/Jaxan/nominal-lstar.git
synced 2025-04-27 06:37:45 +02:00
Implemented NL* by Bollig et al (verbatim)
This commit is contained in:
parent
25d47a3550
commit
f24ed31ac8
4 changed files with 180 additions and 4 deletions
81
src/AbstractLStar.hs
Normal file
81
src/AbstractLStar.hs
Normal file
|
@ -0,0 +1,81 @@
|
|||
{-# LANGUAGE RecordWildCards #-}
|
||||
module AbstractLStar where
|
||||
|
||||
import ObservationTable
|
||||
import Teacher
|
||||
|
||||
import Control.DeepSeq (deepseq)
|
||||
import Debug.Trace
|
||||
import NLambda
|
||||
|
||||
type TableCompletionHandler i = Teacher i -> State i -> State i
|
||||
type CounterExampleHandler i = Teacher i -> State i -> Set [i] -> State i
|
||||
type HypothesisConstruction i = State i -> Automaton (BRow i) i
|
||||
|
||||
data TestResult i
|
||||
= Succes -- test succeeded, no changes required
|
||||
| Failed (Set [i]) (Set [i]) -- test failed, change: add rows + columns
|
||||
|
||||
-- Simple loop which performs tests such as closedness and consistency
|
||||
-- on the table and makes changes if needed. Will (hopefully) reach a
|
||||
-- fixed point, i.e. a complete table.
|
||||
makeCompleteWith :: LearnableAlphabet i
|
||||
=> [State i -> TestResult i]
|
||||
-> Teacher i -> State i -> State i
|
||||
makeCompleteWith tests teacher state0 = go tests state0
|
||||
where
|
||||
-- All tests succeeded, then the state is stable
|
||||
go [] state = state
|
||||
-- We still have tests to perform
|
||||
go (t:ts) state = case t state of
|
||||
-- If the test succeeded, we continue with the next one
|
||||
Succes -> go ts state
|
||||
-- Otherwise we add the changes
|
||||
Failed newRows newColumns ->
|
||||
let state2 = addRows teacher newRows state in
|
||||
let state3 = addColumns teacher newColumns state2 in
|
||||
-- restart the whole business
|
||||
makeCompleteWith tests teacher state3
|
||||
|
||||
-- Simple general learning loop: 1. make the table complete 2. construct
|
||||
-- hypothesis 3. ask teacher. Repeat until done. If the teacher is adequate
|
||||
-- termination implies correctness.
|
||||
learn :: LearnableAlphabet i
|
||||
=> TableCompletionHandler i
|
||||
-> CounterExampleHandler i
|
||||
-> HypothesisConstruction i
|
||||
-> Teacher i
|
||||
-> State i
|
||||
-> Automaton (BRow i) i
|
||||
learn makeComplete handleCounterExample constructHypothesis teacher s =
|
||||
deepseq s $ -- This helps ordering the traces somewhat.
|
||||
trace "##################" $
|
||||
trace "1. Making it complete and consistent" $
|
||||
let s2 = makeComplete teacher s in
|
||||
trace "2. Constructing hypothesis" $
|
||||
let h = constructHypothesis s2 in
|
||||
traceShow h $
|
||||
trace "3. Equivalent? " $
|
||||
let eq = equivalent teacher h in
|
||||
traceShow eq $
|
||||
case eq of
|
||||
Nothing -> h
|
||||
Just ce -> do
|
||||
let s3 = handleCounterExample teacher s2 ce
|
||||
learn makeComplete handleCounterExample constructHypothesis teacher s3
|
||||
|
||||
-- Initial state is always the same in our case
|
||||
constructEmptyState :: LearnableAlphabet i => Teacher i -> State i
|
||||
constructEmptyState teacher =
|
||||
let aa = Teacher.alphabet teacher in
|
||||
let ss = singleton [] in
|
||||
let ssa = pairsWith (\s a -> s ++ [a]) ss aa in
|
||||
let ee = singleton [] in
|
||||
let t = fillTable teacher (ss `union` ssa) ee in
|
||||
State{..}
|
||||
|
||||
--loopClassicalAngluin = loop makeCompleteConsistent useCounterExampleAngluin constructHypothesis
|
||||
--loopClassicalMP = loop makeCompleteConsistent useCounterExampleRS constructHypothesis
|
||||
--loopNonDet = loop makeCompleteConsistentNonDet useCounterExampleRS constructHypothesisNonDet
|
||||
|
||||
--learn loop teacher = loop teacher (constructEmptyState teacher)
|
83
src/Bollig.hs
Normal file
83
src/Bollig.hs
Normal file
|
@ -0,0 +1,83 @@
|
|||
{-# LANGUAGE RecordWildCards #-}
|
||||
module Bollig where
|
||||
|
||||
import AbstractLStar
|
||||
import ObservationTable
|
||||
import Teacher
|
||||
|
||||
import Data.List (tails)
|
||||
import Debug.Trace
|
||||
import NLambda
|
||||
import qualified Prelude hiding ()
|
||||
import Prelude (Bool(..), Maybe(..), ($), (.), (++), fst, show)
|
||||
|
||||
-- See also NLStar.hs for this hack
|
||||
hackApproximate :: NominalType a => Set a -> Set (Set a)
|
||||
hackApproximate set = empty
|
||||
`union` map singleton set
|
||||
`union` pairsWith (\x y -> singleton x `union` singleton y) set set
|
||||
`union` triplesWith (\x y z -> singleton x `union` singleton y `union` singleton z) set set set
|
||||
|
||||
rowUnion :: NominalType i => Set (BRow i) -> BRow i
|
||||
rowUnion set = Prelude.uncurry union . setTrueFalse . partition (\(_, f) -> f) $ map (\is -> (is, exists fromBool (mapFilter (\(is2, b) -> maybeIf (is `eq` is2) b) flatSet))) allIs
|
||||
where
|
||||
flatSet = sum set
|
||||
allIs = map fst flatSet
|
||||
setTrueFalse (trueSet, falseSet) = (map (setSecond True) trueSet, map (setSecond False) falseSet)
|
||||
setSecond a (x, _) = (x, a)
|
||||
|
||||
primes :: NominalType a => (Set a -> a) -> Set a -> Set a
|
||||
primes alg rows = filter (\r -> r `notMember` sumsWithout r) rows
|
||||
where
|
||||
sumsWithout r = map alg $ hackApproximate (rows \\ singleton r)
|
||||
|
||||
boolImplies :: Bool -> Bool -> Bool
|
||||
boolImplies True False = False
|
||||
boolImplies _ _ = True
|
||||
|
||||
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
|
||||
|
||||
rfsaClosednessTest :: LearnableAlphabet i => State i -> TestResult i
|
||||
rfsaClosednessTest State{..} = case solve (isEmpty defect) of
|
||||
Just True -> Succes
|
||||
Just False -> trace "Not closed" $ Failed defect empty
|
||||
Nothing -> trace "@@@ Unsolved Formula (rfsaClosednessTest) @@@" $
|
||||
Failed defect empty
|
||||
where
|
||||
defect = pairsWithFilter (\u a -> maybeIf (rowa t u a `member` primesDifference) (u ++ [a])) ss aa
|
||||
primesDifference = primes rowUnion (map (row t) $ ss `union` ssa) \\ map (row t) ss
|
||||
|
||||
rfsaConsistencyTest :: LearnableAlphabet i => State i -> TestResult i
|
||||
rfsaConsistencyTest State{..} = case solve (isEmpty defect) of
|
||||
Just True -> Succes
|
||||
Just False -> trace "Not consistent" $ Failed empty defect
|
||||
Nothing -> trace "@@@ Unsolved Formula (rfsaConsistencyTest) @@@" $
|
||||
Failed empty defect
|
||||
where
|
||||
candidates = pairsWithFilter (\u1 u2 -> maybeIf (row t u1 `sublang` row t u2) (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
|
||||
|
||||
constructHypothesisBollig :: NominalType i => State i -> Automaton (BRow i) i
|
||||
constructHypothesisBollig State{..} = automaton q a d i f
|
||||
where
|
||||
q = primes rowUnion (map (row t) ss)
|
||||
a = aa
|
||||
i = filter (\r -> r `sublang` row t []) q
|
||||
f = filter (\r -> singleton True `eq` mapFilter (\(i,b) -> maybeIf (i `eq` []) b) r) 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
|
||||
d = filter (\(q1,a,q2) -> q1 `member` q /\ q2 `member` q) d0
|
||||
|
||||
-- Copied from the classical DFA-algorithm, column version
|
||||
useCECopy :: LearnableAlphabet i => Teacher i -> State i -> Set [i] -> State i
|
||||
useCECopy teacher state@State{..} ces =
|
||||
trace ("Using ce:" ++ show ces) $
|
||||
let de = sum . map (fromList . tails) $ ces in
|
||||
addColumns teacher de state
|
||||
|
||||
makeCompleteBollig :: LearnableAlphabet i => TableCompletionHandler i
|
||||
makeCompleteBollig = makeCompleteWith [rfsaClosednessTest, rfsaConsistencyTest]
|
||||
|
||||
learnBollig :: LearnableAlphabet i => Teacher i -> Automaton (BRow i) i
|
||||
learnBollig teacher = learn makeCompleteBollig useCECopy constructHypothesisBollig teacher initial
|
||||
where initial = constructEmptyState teacher
|
|
@ -1,5 +1,6 @@
|
|||
{-# LANGUAGE RecordWildCards #-}
|
||||
|
||||
import Bollig
|
||||
import Examples
|
||||
import Functions
|
||||
import ObservationTable
|
||||
|
@ -8,6 +9,7 @@ import NLStar
|
|||
|
||||
import NLambda
|
||||
|
||||
import Control.DeepSeq
|
||||
import Data.List (inits, tails)
|
||||
import Debug.Trace
|
||||
import Prelude hiding (and, curry, filter, lookup, map, not,
|
||||
|
@ -124,6 +126,9 @@ useCounterExample = useCounterExampleRS
|
|||
-- exactly accepts the language we are learning.
|
||||
loop :: LearnableAlphabet i => Teacher i -> State i -> Automaton (BRow i) i
|
||||
loop teacher s =
|
||||
-- I put a deepseq here in order to let all traces be evaluated
|
||||
-- in a decent order. Also it will be used anyways.
|
||||
deepseq s $
|
||||
trace "##################" $
|
||||
trace "1. Making it complete and consistent" $
|
||||
let s2 = makeCompleteConsistent teacher s in
|
||||
|
|
|
@ -13,8 +13,9 @@ import Teacher
|
|||
|
||||
import Control.DeepSeq (NFData, force)
|
||||
import Data.Maybe (fromJust)
|
||||
import Debug.Trace (trace)
|
||||
import GHC.Generics (Generic)
|
||||
import Prelude (Bool (..), Eq, Ord, Show, ($), (++), (.), uncurry)
|
||||
import Prelude (Bool (..), Eq, Ord, Show (..), ($), (++), (.), uncurry)
|
||||
import qualified Prelude ()
|
||||
|
||||
|
||||
|
@ -36,6 +37,9 @@ row t is = mapFilter (\((a,b),c) -> maybeIf (eq is a) (b,c)) t
|
|||
rowa :: (NominalType i, NominalType o) => Table i o -> [i] -> i -> Fun [i] o
|
||||
rowa t is a = row t (is ++ [a])
|
||||
|
||||
tableAt :: NominalType i => Table i Bool -> [i] -> [i] -> Formula
|
||||
tableAt t s e = singleton True `eq` mapFilter (\((a,b),c) -> maybeIf (s `eq` a /\ b `eq` e) c) t
|
||||
|
||||
-- Teacher is restricted to Bools at the moment
|
||||
type BTable i = Table i Bool
|
||||
type BRow i = Row i Bool
|
||||
|
@ -68,7 +72,9 @@ instance NominalType i => Conditional (State i) where
|
|||
|
||||
-- Precondition: the set together with the current rows is prefix closed
|
||||
addRows :: LearnableAlphabet i => Teacher i -> Set [i] -> State i -> State i
|
||||
addRows teacher ds0 state@State{..} = state {t = t `union` dt, ss = ss `union` ds, ssa = ssa `union` dsa}
|
||||
addRows teacher ds0 state@State{..} =
|
||||
trace ("add rows: " ++ show ds) $
|
||||
state {t = t `union` dt, ss = ss `union` ds, ssa = ssa `union` dsa}
|
||||
where
|
||||
-- first remove redundancy
|
||||
ds = ds0 \\ ss
|
||||
|
@ -78,9 +84,10 @@ addRows teacher ds0 state@State{..} = state {t = t `union` dt, ss = ss `union` d
|
|||
-- note that `ds ee` is already filled
|
||||
dt = fillTable teacher dsa ee
|
||||
|
||||
|
||||
addColumns :: LearnableAlphabet i => Teacher i -> Set [i] -> State i -> State i
|
||||
addColumns teacher de0 state@State{..} = state {t = t `union` dt, ee = ee `union` de}
|
||||
addColumns teacher de0 state@State{..} =
|
||||
trace ("add columns: " ++ show de) $
|
||||
state {t = t `union` dt, ee = ee `union` de}
|
||||
where
|
||||
-- first remove redundancy
|
||||
de = de0 \\ ee
|
||||
|
|
Loading…
Add table
Reference in a new issue