haal 0.1.0.0 → 0.2.0.0
raw patch · 17 files changed
+204/−110 lines, 17 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Haal.Automaton.MealyAutomaton: MealyAutomaton :: (state -> input -> state) -> (state -> input -> output) -> state -> state -> Set state -> MealyAutomaton state input output
- Haal.Automaton.MealyAutomaton: [mealyCurrentS] :: MealyAutomaton state input output -> state
- Haal.Automaton.MealyAutomaton: [mealyDelta] :: MealyAutomaton state input output -> state -> input -> state
- Haal.Automaton.MealyAutomaton: [mealyInitialS] :: MealyAutomaton state input output -> state
- Haal.Automaton.MealyAutomaton: [mealyLambda] :: MealyAutomaton state input output -> state -> input -> output
- Haal.Automaton.MealyAutomaton: [mealyStates] :: MealyAutomaton state input output -> Set state
- Haal.Automaton.MealyAutomaton: mealyReset :: MealyAutomaton s i o -> MealyAutomaton s i o
- Haal.Automaton.MealyAutomaton: mealyStep :: MealyAutomaton s i o -> i -> (MealyAutomaton s i o, o)
- Haal.Automaton.MooreAutomaton: mooreStep :: MooreAutomaton s i o -> i -> (MooreAutomaton s i o, o)
- Haal.EquivalenceOracle.CombinedOracle: CombinedOracle :: a -> b -> CombinedOracle a b
- Haal.EquivalenceOracle.RandomWalk: RandomWalk :: RandomWalkConfig -> RandomWalk
- Haal.EquivalenceOracle.RandomWalk: newtype RandomWalk
- Haal.EquivalenceOracle.RandomWords: RandomWords :: RandomWordsConfig -> RandomWords
- Haal.EquivalenceOracle.RandomWords: newtype RandomWords
- Haal.EquivalenceOracle.WMethod: RandomWMethod :: RandomWMethodConfig -> RandomWMethod
- Haal.EquivalenceOracle.WMethod: WMethod :: Int -> WMethod
- Haal.EquivalenceOracle.WMethod: newtype RandomWMethod
- Haal.EquivalenceOracle.WMethod: newtype WMethod
- Haal.EquivalenceOracle.WpMethod: RandomWpMethod :: RandomWpMethodConfig -> RandomWpMethod
- Haal.EquivalenceOracle.WpMethod: WpMethod :: Int -> WpMethod
- Haal.EquivalenceOracle.WpMethod: newtype RandomWpMethod
- Haal.EquivalenceOracle.WpMethod: newtype WpMethod
- Haal.EquivalenceOracle.WpMethod: randomWpMethodSuite :: forall aut i o s. (Automaton aut s i o, FiniteOrd i, FiniteOrd s, Eq o) => RandomWpMethod -> aut s i o -> (RandomWpMethod, [[i]])
- Haal.Learning.LMstar: LMplus :: ObservationTable i o -> LMstar i o
- Haal.Learning.LMstar: LMstar :: ObservationTable i o -> LMstar i o
+ Haal.Automaton.MealyAutomaton: mealyDelta :: MealyAutomaton state input output -> state -> input -> state
+ Haal.Automaton.MealyAutomaton: mealyLambda :: MealyAutomaton state input output -> state -> input -> output
+ Haal.BlackBox: resetPure :: SUL sul Identity i o => sul i o -> sul i o
+ Haal.BlackBox: stepPure :: SUL sul Identity i o => sul i o -> i -> (sul i o, o)
+ Haal.BlackBox: walkPure :: SUL sul Identity i o => sul i o -> [i] -> (sul i o, [o])
+ Haal.EquivalenceOracle.CombinedOracle: mkCombinedOracle :: a -> b -> CombinedOracle a b
+ Haal.EquivalenceOracle.RandomWalk: data RandomWalk
+ Haal.EquivalenceOracle.RandomWords: data RandomWords
+ Haal.EquivalenceOracle.RandomWords: randomWordsConfig :: RandomWords -> RandomWordsConfig
+ Haal.EquivalenceOracle.WMethod: WMethodConfig :: Int -> WMethodConfig
+ Haal.EquivalenceOracle.WMethod: [wmDepth] :: WMethodConfig -> Int
+ Haal.EquivalenceOracle.WMethod: data RandomWMethod
+ Haal.EquivalenceOracle.WMethod: data WMethod
+ Haal.EquivalenceOracle.WMethod: data WMethodConfig
+ Haal.EquivalenceOracle.WMethod: instance GHC.Classes.Eq Haal.EquivalenceOracle.WMethod.WMethodConfig
+ Haal.EquivalenceOracle.WMethod: instance GHC.Show.Show Haal.EquivalenceOracle.WMethod.WMethodConfig
+ Haal.EquivalenceOracle.WpMethod: WpMethodConfig :: Int -> WpMethodConfig
+ Haal.EquivalenceOracle.WpMethod: [wpmDepth] :: WpMethodConfig -> Int
+ Haal.EquivalenceOracle.WpMethod: data RandomWpMethod
+ Haal.EquivalenceOracle.WpMethod: data WpMethod
+ Haal.EquivalenceOracle.WpMethod: data WpMethodConfig
+ Haal.EquivalenceOracle.WpMethod: instance GHC.Classes.Eq Haal.EquivalenceOracle.WpMethod.WpMethodConfig
+ Haal.EquivalenceOracle.WpMethod: instance GHC.Show.Show Haal.EquivalenceOracle.WpMethod.WpMethodConfig
- Haal.Automaton.MealyAutomaton: mealyTransitions :: forall s i o. (Ord s, FiniteOrd i) => MealyAutomaton s i o -> Map (s, i) (s, o)
+ Haal.Automaton.MealyAutomaton: mealyTransitions :: (Ord s, FiniteOrd i) => MealyAutomaton s i o -> Map (s, i) (s, o)
- Haal.BlackBox: class (SUL (aut s) Identity i o) => Automaton aut s i o
+ Haal.BlackBox: class SUL aut s Identity i o => Automaton (aut :: Type -> Type -> Type -> Type) s i o
- Haal.BlackBox: class (Monad m) => SUL sul m i o
+ Haal.BlackBox: class Monad m => SUL (sul :: Type -> Type -> Type) (m :: Type -> Type) i o
- Haal.BlackBox: states :: (Automaton aut s i o, FiniteOrd s) => aut s i o -> Set s
+ Haal.BlackBox: states :: Automaton aut s i o => aut s i o -> Set s
- Haal.BlackBox: transitions :: (Automaton aut s i o, FiniteOrd i, FiniteOrd s) => aut s i o -> Map (s, i) (s, o)
+ Haal.BlackBox: transitions :: Automaton aut s i o => aut s i o -> Map (s, i) (s, o)
- Haal.EquivalenceOracle.WMethod: mkRandomWMethod :: StdGen -> Int -> Int -> RandomWMethod
+ Haal.EquivalenceOracle.WMethod: mkRandomWMethod :: RandomWMethodConfig -> RandomWMethod
- Haal.EquivalenceOracle.WMethod: mkWMethod :: Int -> WMethod
+ Haal.EquivalenceOracle.WMethod: mkWMethod :: WMethodConfig -> WMethod
- Haal.EquivalenceOracle.WpMethod: mkWpMethod :: Int -> WpMethod
+ Haal.EquivalenceOracle.WpMethod: mkWpMethod :: WpMethodConfig -> WpMethod
- Haal.EquivalenceOracle.WpMethod: wpmethodSuiteSize :: a
+ Haal.EquivalenceOracle.WpMethod: wpmethodSuiteSize :: (Automaton aut s i o, FiniteOrd i, FiniteOrd s, Eq o) => WpMethod -> aut s i o -> Int
- Haal.Experiment: Statistics :: Int -> [[i]] -> [aut s i o] -> Statistics aut s i o
+ Haal.Experiment: Statistics :: Int -> [[i]] -> [aut s i o] -> Statistics (aut :: Type -> Type -> Type -> Type) s i o
- Haal.Experiment: [statsCexs] :: Statistics aut s i o -> [[i]]
+ Haal.Experiment: [statsCexs] :: Statistics (aut :: Type -> Type -> Type -> Type) s i o -> [[i]]
- Haal.Experiment: [statsHyps] :: Statistics aut s i o -> [aut s i o]
+ Haal.Experiment: [statsHyps] :: Statistics (aut :: Type -> Type -> Type -> Type) s i o -> [aut s i o]
- Haal.Experiment: [statsRounds] :: Statistics aut s i o -> Int
+ Haal.Experiment: [statsRounds] :: Statistics (aut :: Type -> Type -> Type -> Type) s i o -> Int
- Haal.Experiment: class Learner l aut s | l -> aut s
+ Haal.Experiment: class Learner (l :: Type -> Type -> Type) (aut :: Type -> Type -> Type -> Type) s | l -> aut s
- Haal.Experiment: data Statistics aut s i o
+ Haal.Experiment: data Statistics (aut :: Type -> Type -> Type -> Type) s i o
- Haal.Experiment: experiment :: (SUL sul m i o, Automaton aut s i o, Learner learner aut s, EquivalenceOracle oracle, FiniteOrd i, FiniteOrd s, FiniteEq o) => learner i o -> oracle -> ExperimentT (sul i o) m (aut s i o, Statistics aut s i o)
+ Haal.Experiment: experiment :: forall sul (m :: Type -> Type) i o aut s learner oracle. (SUL sul m i o, Automaton aut s i o, Learner learner aut s, EquivalenceOracle oracle, FiniteOrd i, FiniteOrd s, FiniteEq o) => learner i o -> oracle -> ExperimentT (sul i o) m (aut s i o, Statistics aut s i o)
- Haal.Experiment: findCex :: (SUL sul m i o, Automaton aut s i o, EquivalenceOracle or, FiniteOrd i, FiniteOrd s, Eq o) => or -> aut s i o -> ExperimentT (sul i o) m (or, ([i], [o]))
+ Haal.Experiment: findCex :: forall sul (m :: Type -> Type) i o aut s or. (SUL sul m i o, Automaton aut s i o, EquivalenceOracle or, FiniteOrd i, FiniteOrd s, Eq o) => or -> aut s i o -> ExperimentT (sul i o) m (or, ([i], [o]))
- Haal.Experiment: initialize :: (Learner l aut s, SUL sul m i o, FiniteOrd i, Finite o) => l i o -> ExperimentT (sul i o) m (l i o)
+ Haal.Experiment: initialize :: forall sul (m :: Type -> Type) i o. (Learner l aut s, SUL sul m i o, FiniteOrd i, Finite o) => l i o -> ExperimentT (sul i o) m (l i o)
- Haal.Experiment: learn :: (Learner l aut s, SUL sul m i o, Automaton aut s i o, FiniteOrd i, FiniteOrd s, FiniteEq o) => l i o -> ExperimentT (sul i o) m (l i o, aut s i o)
+ Haal.Experiment: learn :: forall sul (m :: Type -> Type) i o. (Learner l aut s, SUL sul m i o, Automaton aut s i o, FiniteOrd i, FiniteOrd s, FiniteEq o) => l i o -> ExperimentT (sul i o) m (l i o, aut s i o)
- Haal.Experiment: refine :: (Learner l aut s, SUL sul m i o, FiniteOrd i, Finite o) => l i o -> [i] -> ExperimentT (sul i o) m (l i o)
+ Haal.Experiment: refine :: forall sul (m :: Type -> Type) i o. (Learner l aut s, SUL sul m i o, FiniteOrd i, Finite o) => l i o -> [i] -> ExperimentT (sul i o) m (l i o)
- Haal.Experiment: type ExperimentT sul m result = ReaderT sul m result
+ Haal.Experiment: type ExperimentT sul (m :: Type -> Type) result = ReaderT sul m result
- Haal.Learning.LMstar: lmstar :: forall sul i o m. (SUL sul m i o, FiniteOrd i, Eq o, Monad m) => LMstar i o -> ExperimentT (sul i o) m (LMstar i o, MealyAutomaton StateID i o)
+ Haal.Learning.LMstar: lmstar :: forall sul i o (m :: Type -> Type). (SUL sul m i o, FiniteOrd i, Eq o, Monad m) => LMstar i o -> ExperimentT (sul i o) m (LMstar i o, MealyAutomaton StateID i o)
Files
- CHANGELOG.md +23/−2
- examples/demo.hs +1/−1
- examples/div.hs +2/−2
- examples/io.hs +1/−1
- examples/website.hs +2/−2
- haal.cabal +1/−1
- src/Haal/Automaton/MealyAutomaton.hs +3/−3
- src/Haal/Automaton/MooreAutomaton.hs +0/−1
- src/Haal/BlackBox.hs +3/−0
- src/Haal/EquivalenceOracle/CombinedOracle.hs +6/−1
- src/Haal/EquivalenceOracle/RandomWalk.hs +1/−1
- src/Haal/EquivalenceOracle/RandomWords.hs +6/−1
- src/Haal/EquivalenceOracle/WMethod.hs +22/−15
- src/Haal/EquivalenceOracle/WpMethod.hs +58/−10
- src/Haal/Learning/LMstar.hs +37/−27
- test/EquivalenceOracleSpec.hs +3/−3
- test/Utils.hs +35/−39
CHANGELOG.md view
@@ -8,6 +8,29 @@ ## Unreleased +## 0.2.0.0 - 2026-03-05++### Added+- `stepPure`, `walkPure`, `resetPure` exported from `Haal.BlackBox`+- `Config` record types for all equivalence oracles: `WMethodConfig`, `WpMethodConfig`,+ `RandomWalkConfig`, `RandomWordsConfig`, `RandomWMethodConfig`, `RandomWpMethodConfig`+- `mkCombinedOracle` smart constructor for `CombinedOracle`+- `randomWordsConfig` accessor for `RandomWords`+- `mealyDelta`, `mealyLambda` as explicit named exports from `Haal.Automaton.MealyAutomaton`++### Changed+- All oracle constructors now take a `Config` record instead of positional arguments:+ `mkWMethod :: WMethodConfig -> WMethod`, `mkWpMethod :: WpMethodConfig -> WpMethod`, etc.+- `mkRandomWMethod` and `mkRandomWpMethod` now take a `Config` record instead of+ positional arguments (also fixes an argument-order bug in the old interface)++### Removed+- `mealyStep` from `Haal.Automaton.MealyAutomaton`; use `stepPure` from `Haal.BlackBox`+- `mooreStep` from `Haal.Automaton.MooreAutomaton`; use `stepPure` from `Haal.BlackBox`+- Raw constructor exports (`MealyAutomaton (..)`, `WMethod (..)`, `WpMethod (..)`,+ `RandomWalk (..)`, `RandomWords (..)`, `CombinedOracle (..)`, `LMstar (..)`);+ use the corresponding `mk`-prefixed smart constructors instead+ ## 0.1.0.0 - 2025-12-02 - Initial release of `haal`.@@ -17,5 +40,3 @@ - LPlus. - Basic equivalence oracles. - Examples that showcase usage of the library.--
examples/demo.hs view
@@ -18,7 +18,7 @@ sulTransitions S2 B = (S0, Y) -- Set up the experiment.-myexperiment = experiment (mkLMstar Star) (mkWMethod 2)+myexperiment = experiment (mkLMstar Star) (mkWMethod (WMethodConfig 2)) -- Define the Mealy system under learning. Remember that automata can act as suls. mysul = mkMealyAutomaton2 sulTransitions (Set.fromList [S0, S1, S2]) S0
examples/div.hs view
@@ -3,7 +3,7 @@ import Haal.Automaton.MealyAutomaton import Haal.BlackBox (SUL (..), StateID)-import Haal.EquivalenceOracle.WpMethod (WpMethod, mkWpMethod)+import Haal.EquivalenceOracle.WpMethod (WpMethod, WpMethodConfig (..), mkWpMethod) import Haal.Experiment import Haal.Learning.LMstar (LMstar, LMstarConfig (Star), mkLMstar) import Control.Monad.Identity (Identity)@@ -83,7 +83,7 @@ learner = mkLMstar Star oracle :: WpMethod-oracle = mkWpMethod 3+oracle = mkWpMethod (WpMethodConfig 3) exper :: Experiment (Program Binary Bool) (MealyAutomaton StateID Binary Bool, Statistics MealyAutomaton StateID Binary Bool) exper = experiment learner oracle
examples/io.hs view
@@ -77,7 +77,7 @@ learner = mkLMstar Star oracle :: WpMethod-oracle = mkWpMethod 3+oracle = mkWpMethod (WpMethodConfig 3) exper :: ExperimentT
examples/website.hs view
@@ -3,7 +3,7 @@ import qualified Data.List as List import Haal.BlackBox-import Haal.EquivalenceOracle.WMethod (mkWMethod)+import Haal.EquivalenceOracle.WMethod (WMethodConfig (..), mkWMethod) import Haal.Experiment import Haal.Learning.LMstar import System.Process (readProcess)@@ -85,7 +85,7 @@ -------------------------------------------------------------------------------- learner = mkLMstar Star-teacher = mkWMethod 2+teacher = mkWMethod (WMethodConfig 2) exper = experiment learner teacher --------------------------------------------------------------------------------
haal.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: haal-version: 0.1.0.0+version: 0.2.0.0 synopsis: A Haskell library for Active Automata Learning. description: Please see the README on GitHub at <https://github.com/steve-anunknown/haal#readme> category: Model Learning
src/Haal/Automaton/MealyAutomaton.hs view
@@ -4,11 +4,11 @@ -- | This module implements a Mealy automaton. module Haal.Automaton.MealyAutomaton (- MealyAutomaton (..),+ MealyAutomaton, mkMealyAutomaton, mkMealyAutomaton2,- mealyStep,- mealyReset,+ mealyDelta,+ mealyLambda, mealyTransitions, ) where
src/Haal/Automaton/MooreAutomaton.hs view
@@ -6,7 +6,6 @@ module Haal.Automaton.MooreAutomaton ( MooreAutomaton, mkMooreAutomaton,- mooreStep, mooreTransitions, ) where
src/Haal/BlackBox.hs view
@@ -16,6 +16,9 @@ inputs, outputs, walk,+ stepPure,+ walkPure,+ resetPure, initial, distinguish, accessSequences,
src/Haal/EquivalenceOracle/CombinedOracle.hs view
@@ -1,6 +1,7 @@ -- | This module implements a combined equivalence oracle for two oracles. module Haal.EquivalenceOracle.CombinedOracle (- CombinedOracle (..),+ CombinedOracle,+ mkCombinedOracle, ) where import Haal.Experiment@@ -10,6 +11,10 @@ of the first oracle and then using the second oracle. -} data CombinedOracle a b = CombinedOracle a b deriving (Show, Eq)++-- | Constructor for a 'CombinedOracle' value.+mkCombinedOracle :: a -> b -> CombinedOracle a b+mkCombinedOracle = CombinedOracle instance ( EquivalenceOracle a
src/Haal/EquivalenceOracle/RandomWalk.hs view
@@ -1,6 +1,6 @@ -- | This module implements the Random Walk equivalence oracle. module Haal.EquivalenceOracle.RandomWalk (- RandomWalk (..),+ RandomWalk, RandomWalkConfig (..), mkRandomWalk, )
src/Haal/EquivalenceOracle/RandomWords.hs view
@@ -1,8 +1,9 @@ -- | This module implements a simple random words equivalence oracle. module Haal.EquivalenceOracle.RandomWords (- RandomWords (..),+ RandomWords, RandomWordsConfig (..), mkRandomWords,+ randomWordsConfig, ) where @@ -29,6 +30,10 @@ -- | Constructor for a 'RandomWords' data type. mkRandomWords :: RandomWordsConfig -> RandomWords mkRandomWords = RandomWords++-- | Accessor for the 'RandomWordsConfig' of a 'RandomWords' value.+randomWordsConfig :: RandomWords -> RandomWordsConfig+randomWordsConfig (RandomWords config) = config -- | Return the test suite of the 'RandomWords' algorithm. generateRandomWords :: (FiniteOrd a) => RandomWords -> sul a o -> (RandomWords, [[a]])
src/Haal/EquivalenceOracle/WMethod.hs view
@@ -2,9 +2,10 @@ -- | This module implements the W-method equivalence oracle. module Haal.EquivalenceOracle.WMethod (- WMethod (..),+ WMethod,+ WMethodConfig (..), wmethodSuiteSize,- RandomWMethod (..),+ RandomWMethod, RandomWMethodConfig (..), mkWMethod, mkRandomWMethod,@@ -16,18 +17,24 @@ import qualified Data.Set as Set import qualified Data.Vector as Vec import Haal.BlackBox-import Haal.EquivalenceOracle.RandomWords+import Haal.EquivalenceOracle.RandomWords (RandomWordsConfig (..), mkRandomWords, randomWordsConfig) import Haal.Experiment import System.Random (Random (randomRs), RandomGen (split), StdGen) +{- | The 'WMethodConfig' type is used to configure the W-method equivalence oracle.+-}+data WMethodConfig = WMethodConfig+ { wmDepth :: Int+ -- ^ The number of extra states beyond the hypothesis to account for.+ }+ deriving (Show, Eq)+ {- | The 'WMethod' type represents the W-method equivalence oracle.-It is just a wrapper around an integer, which is used for configuring-the exploration depth of the method. -}-newtype WMethod = WMethod Int deriving (Show, Eq)+newtype WMethod = WMethod WMethodConfig deriving (Show, Eq) -- | Constructor for a 'WMethod' value.-mkWMethod :: Int -> WMethod+mkWMethod :: WMethodConfig -> WMethod mkWMethod = WMethod -- | The 'wmethodSuiteSize' function computes the size of the test suite for the W-method.@@ -40,7 +47,7 @@ WMethod -> aut s i o -> Int-wmethodSuiteSize (WMethod d) aut = size+wmethodSuiteSize (WMethod (WMethodConfig d)) aut = size where alphabet = Set.size $ inputs aut accessSeqs = Map.size $ accessSequences aut@@ -58,7 +65,7 @@ WMethod -> aut s i o -> (WMethod, [[i]])-wmethodSuite wm@(WMethod d) aut = (wm, suite)+wmethodSuite wm@(WMethod (WMethodConfig d)) aut = (wm, suite) where alphabet = Set.toList $ inputs aut accessSeqs = accessSequences aut@@ -90,8 +97,8 @@ newtype RandomWMethod = RandomWMethod RandomWMethodConfig deriving (Show, Eq) -- | Constructor for a 'RandomWMethod' value.-mkRandomWMethod :: StdGen -> Int -> Int -> RandomWMethod-mkRandomWMethod g l n = RandomWMethod (RandomWMethodConfig g n l)+mkRandomWMethod :: RandomWMethodConfig -> RandomWMethod+mkRandomWMethod = RandomWMethod -- | The 'randomWMethodSuite' function generates the test suite for the random W-method and a new oracle. randomWMethodSuite ::@@ -105,20 +112,20 @@ aut s i o -> (RandomWMethod, [[i]]) randomWMethodSuite (RandomWMethod (RandomWMethodConfig g wpr wl)) aut =- let rorc = RandomWords (RandomWordsConfig{rwMaxLength = wl, rwMinLength = 1, rwLimit = wpr, rwGen = g})+ let rorc = mkRandomWords (RandomWordsConfig{rwMaxLength = wl, rwMinLength = 1, rwLimit = wpr, rwGen = g}) prefixes = Map.elems $ accessSequences aut vecSuffixes = Vec.fromList $ Set.toList $ globalCharacterizingSet aut - (RandomWords roc', wordBatches) = List.mapAccumL testSuite rorc (replicate (length prefixes) (undefined :: aut s i o))+ (rorc', wordBatches) = List.mapAccumL testSuite rorc (replicate (length prefixes) (undefined :: aut s i o)) flatWords = concat wordBatches - (gen'', gen''') = split (rwGen roc')+ (gen'', gen''') = split (rwGen (randomWordsConfig rorc')) samples = length prefixes * wpr randomSuffixes = take samples $ randomRs (0, Vec.length vecSuffixes - 1) gen'' suffixes = map (vecSuffixes Vec.!) randomSuffixes suite = [prefix ++ rand ++ suffix | prefix <- prefixes, rand <- flatWords, suffix <- suffixes]- in (mkRandomWMethod gen''' wpr wl, suite)+ in (mkRandomWMethod (RandomWMethodConfig gen''' wpr wl), suite) instance EquivalenceOracle RandomWMethod where testSuite = randomWMethodSuite
src/Haal/EquivalenceOracle/WpMethod.hs view
@@ -2,11 +2,11 @@ -- | This module implements the WpMethod. module Haal.EquivalenceOracle.WpMethod (- WpMethod (..),- RandomWpMethod (..),+ WpMethod,+ WpMethodConfig (..),+ RandomWpMethod, RandomWpMethodConfig (..), wpmethodSuiteSize,- randomWpMethodSuite, mkWpMethod, mkRandomWpMethod, ) where@@ -20,17 +20,65 @@ import Haal.Experiment import System.Random (Random (randomR), StdGen) --- | Type for the WpMethod. It simply wraps the depth of the method.-newtype WpMethod = WpMethod Int deriving (Eq, Show)+-- | The 'WpMethodConfig' type is used to configure the Wp-method equivalence oracle.+data WpMethodConfig = WpMethodConfig+ { wpmDepth :: Int+ -- ^ The number of extra states beyond the hypothesis to account for.+ }+ deriving (Show, Eq) +-- | The 'WpMethod' type represents the Wp-method equivalence oracle.+newtype WpMethod = WpMethod WpMethodConfig deriving (Eq, Show)+ -- | Constructor for a 'WpMethod' value.-mkWpMethod :: Int -> WpMethod+mkWpMethod :: WpMethodConfig -> WpMethod mkWpMethod = WpMethod --- | The 'wpmethodSuiteSize' returns the nunmber of test cases in the test suite of WpMethod-wpmethodSuiteSize :: a-wpmethodSuiteSize = error "todo"+-- | The 'wpmethodSuiteSize' returns the number of test cases in the test suite of WpMethod.+wpmethodSuiteSize ::+ ( Automaton aut s i o+ , FiniteOrd i+ , FiniteOrd s+ , Eq o+ ) =>+ WpMethod ->+ aut s i o ->+ Int+wpmethodSuiteSize (WpMethod (WpMethodConfig d)) aut = firstPhaseSize + secondPhaseSize+ where+ alphabetList = Set.toList (inputs aut)+ alphabetSize = length alphabetList+ stateCover = accessSequences aut+ localSufSizes =+ Map.fromAscList+ [ (st, Set.size (localCharacterizingSet aut st))+ | st <- Set.toAscList (states aut)+ ]+ globalSufSize = Set.size (globalCharacterizingSet aut)+ transitionCover =+ Set.fromList+ [ acc ++ [a]+ | acc <- Map.elems stateCover+ , a <- alphabetList+ ]+ difference = Set.fromList (Map.elems stateCover) `Set.difference` transitionCover + -- Closed form: |S| * |W| * (1 + |Σ| + ... + |Σ|^d)+ firstPhaseSize =+ Map.size stateCover+ * globalSufSize+ * sum [alphabetSize ^ k | k <- [0 .. d]]++ -- Walk each acc once, then enumerate middles from that state; no test strings built.+ secondPhaseSize =+ sum+ [ localSufSizes Map.! current (fst (runIdentity (walk afterAcc middle)))+ | acc <- Set.toList difference+ , let afterAcc = fst (runIdentity (walk aut acc))+ , fixed <- [0 .. d]+ , middle <- replicateM fixed alphabetList+ ]+ -- | Returns the test suite for the WpMethod. wpmethodSuite :: forall aut i o s.@@ -42,7 +90,7 @@ WpMethod -> aut s i o -> (WpMethod, [[i]])-wpmethodSuite wpm@(WpMethod d) aut = (wpm, suite)+wpmethodSuite wpm@(WpMethod (WpMethodConfig d)) aut = (wpm, suite) where alphabet = inputs aut stateCover = accessSequences aut
src/Haal/Learning/LMstar.hs view
@@ -6,7 +6,7 @@ -- | This module implements the LM* algorithm for learning Mealy automata. module Haal.Learning.LMstar ( lmstar,- LMstar (..),+ LMstar, LMstarConfig (..), mkLMstar, )@@ -111,7 +111,9 @@ ExperimentT (sul i o) m (LMstar i o, MealyAutomaton StateID i o) lmstar (LMstar ot) = case otIsClosed ot of [] -> case otIsConsistent ot of- ([], []) -> return (LMstar ot, makeHypothesis ot)+ ([], []) -> case makeHypothesis ot of+ Just hyp -> return (LMstar ot, hyp)+ Nothing -> error "LM*: invariant violation — makeHypothesis failed on closed consistent table" inc' -> do ot' <- makeConsistent ot inc' lmstar (LMstar ot')@@ -119,7 +121,9 @@ ot' <- makeClosed ot inc lmstar (LMstar ot') lmstar (LMplus ot) = case otIsClosed ot of- [] -> return (LMplus ot, makeHypothesis ot)+ [] -> case makeHypothesis ot of+ Just hyp -> return (LMplus ot, hyp)+ Nothing -> error "LM+: invariant violation — makeHypothesis failed on closed table" inc -> do ot' <- makeClosed ot inc lmstar (LMplus ot')@@ -176,39 +180,45 @@ {- | The 'makeHypothesis' function constructs a Mealy automaton from the observation table. It uses the default 'StateID' type defined in the 'Experiment' module for representing the automaton states.+Returns 'Nothing' if the observation table is malformed (invariant violated). -}-makeHypothesis :: forall i o. (FiniteOrd i, Eq o) => ObservationTable i o -> MealyAutomaton StateID i o-makeHypothesis ot = mkMealyAutomaton delta' lambda' (Set.fromList [0 .. length repList - 1]) starting+makeHypothesis :: forall i o. (FiniteOrd i, Eq o) => ObservationTable i o -> Maybe (MealyAutomaton StateID i o)+makeHypothesis ot = do+ startId <- getStateId []+ let stateInputPairs = [(sid, i) | sid <- [0 .. numStates - 1], i <- alphaList]+ deltaEntries <- mapM buildDeltaEntry stateInputPairs+ lambdaEntries <- mapM buildLambdaEntry stateInputPairs+ let deltaMap = Map.fromList deltaEntries+ lambdaMap = Map.fromList lambdaEntries+ delta' sid i = deltaMap Map.! (sid, i)+ lambda' sid i = lambdaMap Map.! (sid, i)+ return $ mkMealyAutomaton delta' lambda' (Set.fromList [0 .. numStates - 1]) startId where- -- Equivalence classes: Map from representative prefix to class members- equivMap :: Map.Map [i] [[i]] equivMap = equivalenceClasses ot-- -- Assign an integer ID to each class representative- repList :: [[i]] repList = Map.keys equivMap-- repToId :: Map.Map [i] StateID+ numStates = length repList repToId = Map.fromList (zip repList [0 ..])+ alphaList = [minBound .. maxBound] :: [i] - -- Helper: get the ID for the class a string belongs to- getStateId :: [i] -> StateID- getStateId s =- case List.find (equivalentRows ot s) repList of- Just rep -> repToId Map.! rep- Nothing -> error "No equivalent class found for string!"+ getStateId :: [i] -> Maybe StateID+ getStateId s = List.find (equivalentRows ot s) repList >>= flip Map.lookup repToId - delta' :: StateID -> i -> StateID- delta' sid i =- let rep = repList !! sid- in getStateId (rep ++ [i])+ repAt :: StateID -> Maybe [i]+ repAt sid+ | sid >= 0 && sid < numStates = Just (repList !! sid)+ | otherwise = Nothing - lambda' :: StateID -> i -> o- lambda' sid i =- let rep = repList !! sid- in mappingT ot Map.! (rep, [i])+ buildDeltaEntry :: (StateID, i) -> Maybe ((StateID, i), StateID)+ buildDeltaEntry (sid, i) = do+ rep <- repAt sid+ target <- getStateId (rep ++ [i])+ return ((sid, i), target) - starting = getStateId []+ buildLambdaEntry :: (StateID, i) -> Maybe ((StateID, i), o)+ buildLambdaEntry (sid, i) = do+ rep <- repAt sid+ o <- Map.lookup (rep, [i]) (mappingT ot)+ return ((sid, i), o) -- | The 'makeConsistent' function makes the observation table consistent by adding missing prefixes. makeConsistent ::
test/EquivalenceOracleSpec.hs view
@@ -3,7 +3,7 @@ ) where import Control.Monad.Reader-import Haal.EquivalenceOracle.WMethod (WMethod (..), wmethodSuiteSize)+import Haal.EquivalenceOracle.WMethod (wmethodSuiteSize) import Haal.Experiment import Test.Hspec (Spec, context, describe, it) import Test.QuickCheck (Property, property, (==>))@@ -19,8 +19,8 @@ -- WMethod-specific cardinality law prop_WMethodCardinality :: ArbWMethod -> Mealy State Input Output -> Bool-prop_WMethodCardinality (ArbWMethod (WMethod d)) (Mealy aut) =- length (snd (testSuite (WMethod d) aut)) == wmethodSuiteSize (WMethod d) aut+prop_WMethodCardinality (ArbWMethod wm) (Mealy aut) =+ length (snd (testSuite wm aut)) == wmethodSuiteSize wm aut spec :: Spec spec = do
test/Utils.hs view
@@ -24,39 +24,45 @@ import qualified Data.Maybe import qualified Data.Set as Set import Haal.Automaton.MealyAutomaton (- MealyAutomaton (..),- mealyDelta,- mealyLambda,+ MealyAutomaton,+ mkMealyAutomaton,+ mealyTransitions, ) import Haal.BlackBox import Haal.EquivalenceOracle.RandomWalk (- RandomWalk (RandomWalk),- RandomWalkConfig (RandomWalkConfig),+ RandomWalk,+ RandomWalkConfig (..),+ mkRandomWalk, ) import Haal.EquivalenceOracle.RandomWords (- RandomWords (RandomWords),- RandomWordsConfig (RandomWordsConfig),+ RandomWords,+ RandomWordsConfig (..),+ mkRandomWords, ) import Haal.EquivalenceOracle.WMethod (- RandomWMethod (RandomWMethod),- RandomWMethodConfig (RandomWMethodConfig),- WMethod (WMethod),+ RandomWMethod,+ RandomWMethodConfig (..),+ WMethod,+ WMethodConfig (..), mkWMethod,+ mkRandomWMethod, ) import Haal.EquivalenceOracle.WpMethod (- RandomWpMethod (RandomWpMethod),- RandomWpMethodConfig (RandomWpMethodConfig),- WpMethod (WpMethod),+ RandomWpMethod,+ RandomWpMethodConfig (..),+ WpMethod,+ WpMethodConfig (..), mkWpMethod,+ mkRandomWpMethod, ) import Haal.Experiment (EquivalenceOracle) import System.Random import Test.QuickCheck (Arbitrary (..), Gen, choose, elements, vectorOf) -newtype ArbWMethodConfig = ArbWMethodConfig Int deriving (Show, Eq)+newtype ArbWMethodConfig = ArbWMethodConfig WMethodConfig deriving (Show, Eq) newtype ArbWMethod = ArbWMethod WMethod deriving (Show, Eq) -newtype ArbWpMethodConfig = ArbWpMethodConfig Int deriving (Show, Eq)+newtype ArbWpMethodConfig = ArbWpMethodConfig WpMethodConfig deriving (Show, Eq) newtype ArbWpMethod = ArbWpMethod WpMethod deriving (Show, Eq) newtype ArbRandomWordsConfig = ArbRandomWordsConfig RandomWordsConfig deriving (Show, Eq)@@ -74,7 +80,7 @@ instance Arbitrary ArbWMethodConfig where arbitrary = do d <- choose (1, 5)- return (ArbWMethodConfig d)+ return (ArbWMethodConfig (WMethodConfig d)) instance Arbitrary ArbWMethod where arbitrary = do (ArbWMethodConfig config) <- arbitrary :: Gen ArbWMethodConfig@@ -83,7 +89,7 @@ instance Arbitrary ArbWpMethodConfig where arbitrary = do d <- choose (1, 5)- return (ArbWpMethodConfig d)+ return (ArbWpMethodConfig (WpMethodConfig d)) instance Arbitrary ArbWpMethod where arbitrary = do (ArbWpMethodConfig config) <- arbitrary :: Gen ArbWpMethodConfig@@ -100,7 +106,7 @@ instance Arbitrary ArbRandomWords where arbitrary = do (ArbRandomWordsConfig config) <- arbitrary :: Gen ArbRandomWordsConfig- return (ArbRandomWords (RandomWords config))+ return (ArbRandomWords (mkRandomWords config)) instance Arbitrary ArbRandomWalkConfig where arbitrary = do@@ -112,7 +118,7 @@ instance Arbitrary ArbRandomWalk where arbitrary = do (ArbRandomWalkConfig config) <- arbitrary :: Gen ArbRandomWalkConfig- return (ArbRandomWalk (RandomWalk config))+ return (ArbRandomWalk (mkRandomWalk config)) instance Arbitrary ArbRandomWMethodConfig where arbitrary = do@@ -124,7 +130,7 @@ instance Arbitrary ArbRandomWMethod where arbitrary = do (ArbRandomWMethodConfig config) <- arbitrary :: Gen ArbRandomWMethodConfig- return (ArbRandomWMethod (RandomWMethod config))+ return (ArbRandomWMethod (mkRandomWMethod config)) instance Arbitrary ArbRandomWpMethodConfig where arbitrary = do@@ -138,7 +144,7 @@ instance Arbitrary ArbRandomWpMethod where arbitrary = do (ArbRandomWpMethodConfig config) <- arbitrary :: Gen ArbRandomWpMethodConfig- return (ArbRandomWpMethod (RandomWpMethod config))+ return (ArbRandomWpMethod (mkRandomWpMethod config)) class (EquivalenceOracle oracle) => OracleWrapper w oracle | w -> oracle where unwrap :: w -> oracle@@ -183,13 +189,9 @@ return ( Mealy- ( MealyAutomaton- { mealyDelta = delta- , mealyLambda = lambda- , mealyInitialS = initialState- , mealyCurrentS = currentState- , mealyStates = Set.fromList sts- }+ ( update+ (mkMealyAutomaton delta lambda (Set.fromList sts) initialState)+ currentState ) ) where@@ -246,13 +248,9 @@ return ( NonMinimalMealy- ( MealyAutomaton- { mealyDelta = delta- , mealyLambda = lambda- , mealyInitialS = initialState- , mealyCurrentS = currentState- , mealyStates = Set.fromList sts- }+ ( update+ (mkMealyAutomaton delta lambda (Set.fromList sts) initialState)+ currentState ) ) where@@ -294,8 +292,6 @@ statesAreEquivalent :: MealyAutomaton State Input Output -> State -> State -> Bool statesAreEquivalent _ s1 s2 | s1 == s2 = True statesAreEquivalent automaton s1 s2 =- all (\i -> (delta s1 i, lambda s1 i) == (delta s2 i, lambda s2 i)) alphabet+ all (\i -> trans Map.! (s1, i) == trans Map.! (s2, i)) (inputs automaton) where- delta = mealyDelta automaton- lambda = mealyLambda automaton- alphabet = inputs automaton+ trans = mealyTransitions automaton