mirror of
https://github.com/Jaxan/nominal-lstar.git
synced 2025-04-27 14:47:45 +02:00
165 lines
6.5 KiB
Haskell
165 lines
6.5 KiB
Haskell
{-# LANGUAGE RecordWildCards #-}
|
|
|
|
import Bollig
|
|
import Examples
|
|
import Functions
|
|
import ObservationTable
|
|
import Teacher
|
|
import NLStar
|
|
|
|
import NLambda
|
|
|
|
import Control.DeepSeq
|
|
import Data.List (inits, tails)
|
|
import Debug.Trace
|
|
import Prelude hiding (and, curry, filter, lookup, map, not,
|
|
sum, uncurry)
|
|
|
|
|
|
-- We can determine its completeness with the following
|
|
-- It returns all witnesses (of the form sa) for incompleteness
|
|
incompleteness :: NominalType i => State i -> Set [i]
|
|
incompleteness State{..} = filter (not . hasEqRow) ssa
|
|
where
|
|
sss = map (row t) ss
|
|
-- true if the sequence sa has an equivalent row in ss
|
|
hasEqRow = contains sss . row t
|
|
|
|
-- We can determine its consistency with the following
|
|
-- Returns equivalent rows (fst) with all inequivalent extensions (snd)
|
|
inconsistencyJoshua :: NominalType i => State i -> Set (([i], [i], i), Set [i])
|
|
inconsistencyJoshua State{..} =
|
|
triplesWithFilter (
|
|
\s1 s2 a -> maybeIf (candidate s1 s2 a) ((s1, s2, a), discrepancy (rowa t s1 a) (rowa t s2 a))
|
|
) ss ss aa
|
|
where
|
|
-- true for equal rows, but unequal extensions
|
|
-- we can safely skip equal sequences
|
|
candidate s1 s2 a = s1 `neq` s2
|
|
/\ row t s1 `eq` row t s2
|
|
/\ rowa t s1 a `neq` rowa t s2 a
|
|
|
|
inconsistencyBartek :: NominalType i => State i -> Set (([i], [i], i), Set [i])
|
|
inconsistencyBartek State{..} =
|
|
pairsWithFilter (
|
|
\(s1, s2) a -> maybeIf (candidate1 s1 s2 a) ((s1, s2, a), discrepancy (rowa t s1 a) (rowa t s2 a))
|
|
) rowPairs aa
|
|
where
|
|
rowPairs = pairsWithFilter (\s1 s2 -> maybeIf (candidate0 s1 s2) (s1,s2)) ss ss
|
|
candidate0 s1 s2 = s1 `neq` s2 /\ row t s1 `eq` row t s2
|
|
candidate1 s1 s2 a = rowa t s1 a `neq` rowa t s2 a
|
|
|
|
inconsistency :: NominalType i => State i -> Set (([i], [i], i), Set [i])
|
|
inconsistency = inconsistencyBartek
|
|
|
|
-- This function will (recursively) make the table complete and consistent.
|
|
-- This is in the IO monad purely because I want some debugging information.
|
|
-- (Same holds for many other functions here)
|
|
makeCompleteConsistent :: LearnableAlphabet i => Teacher i -> State i -> State i
|
|
makeCompleteConsistent teacher state@State{..} =
|
|
-- inc is the set of rows witnessing incompleteness, that is the sequences
|
|
-- 's1 a' which do not have their equivalents of the form 's2'.
|
|
let inc = incompleteness state in
|
|
ite (isNotEmpty inc)
|
|
( -- If that set is non-empty, we should add new rows
|
|
trace "Incomplete! Adding rows:" $
|
|
-- These will be the new rows, ...
|
|
let ds = inc in
|
|
traceShow ds $
|
|
let state2 = addRows teacher ds state in
|
|
makeCompleteConsistent teacher state2
|
|
)
|
|
( -- inc2 is the set of inconsistencies.
|
|
let inc2 = inconsistency state in
|
|
ite (isNotEmpty inc2)
|
|
( -- If that set is non-empty, we should add new columns
|
|
trace "Inconsistent! Adding columns:" $
|
|
-- The extensions are in the second component
|
|
let de = sum $ map (\((s1,s2,a),es) -> map (a:) es) inc2 in
|
|
traceShow de $
|
|
let state2 = addColumns teacher de state in
|
|
makeCompleteConsistent teacher state2
|
|
)
|
|
( -- If both sets are empty, the table is complete and
|
|
-- consistent, so we are done.
|
|
trace " => Complete + Consistent :D!" $
|
|
state
|
|
)
|
|
)
|
|
|
|
-- Given a C&C table, constructs an automaton. The states are given by 2^E (not
|
|
-- necessarily equivariant functions)
|
|
constructHypothesis :: NominalType i => State i -> Automaton (BRow i) i
|
|
constructHypothesis State{..} = automaton q a d i f
|
|
where
|
|
q = map (row t) ss
|
|
a = aa
|
|
d = pairsWith (\s a -> (row t s, a, rowa t s a)) ss aa
|
|
i = singleton $ row t []
|
|
f = mapFilter (\s -> maybeIf (toform $ apply t (s, [])) (row t s)) ss
|
|
toform s = forAll id . map fromBool $ s
|
|
|
|
-- Extends the table with all prefixes of a set of counter examples.
|
|
useCounterExampleAngluin :: LearnableAlphabet i => Teacher i -> State i -> Set [i] -> State i
|
|
useCounterExampleAngluin teacher state@State{..} ces =
|
|
trace "Using ce:" $
|
|
traceShow ces $
|
|
let ds = sum . map (fromList . inits) $ ces in
|
|
trace " -> Adding rows:" $
|
|
traceShow ds $
|
|
addRows teacher ds state
|
|
|
|
-- I am not quite sure whether this variant is due to Rivest & Schapire or Maler & Pnueli.
|
|
useCounterExampleRS :: LearnableAlphabet i => Teacher i -> State i -> Set [i] -> State i
|
|
useCounterExampleRS teacher state@State{..} ces =
|
|
trace "Using ce:" $
|
|
traceShow ces $
|
|
let de = sum . map (fromList . tails) $ ces in
|
|
trace " -> Adding columns:" $
|
|
traceShow de $
|
|
addColumns teacher de state
|
|
|
|
useCounterExample :: LearnableAlphabet i => Teacher i -> State i -> Set [i] -> State i
|
|
useCounterExample = useCounterExampleRS
|
|
|
|
-- The main loop, which results in an automaton. Will stop if the hypothesis
|
|
-- 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
|
|
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 = useCounterExample teacher s2 ce
|
|
loop teacher s3
|
|
|
|
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{..}
|
|
|
|
learn :: LearnableAlphabet i => Teacher i -> Automaton (BRow i) i
|
|
learn teacher = loop teacher s
|
|
where s = constructEmptyState teacher
|
|
|
|
-- Initializes the table and runs the algorithm.
|
|
main :: IO ()
|
|
main = do
|
|
let h = learn (teacherWithTarget (Examples.fifoExample 3))
|
|
putStrLn "Finished! Final hypothesis ="
|
|
print h
|