packages feed

haal-0.7.0.0: examples/io.hs

-- we will attempt to reproduce the `div.hs` learning experiment,
-- but this time, instead of using a haskell function as a SUL,
-- we will use an actual program that performs IO.
-- the program reads an integer from stdin and prints whether it is
-- divisible by 3, so its output alphabet is just bool.
-- the input alphabet is binary, as in `div.hs`.
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

import Haal.BlackBox (SUL (..))
import Haal.EquivalenceOracle.WpMethod (WpMethodConfig (..), mkWpMethod)
import Haal.Experiment (measuredExperiment, runExperimentT)
import Haal.Learning.LMstar (LMstarConfig (Star), mkLMstar)
import Haal.Statistics (statistics)
import System.Process (readProcess)

-- Note that this is relative to the project root. Otherwise
-- the executable will not be found. Build it first with
--   ghc examples/divisible3.hs
source :: FilePath
source = "./examples/divisible3"

data Binary = B0 | B1 deriving (Show, Eq, Ord, Enum, Bounded)

-- the bits seen so far are read as a binary number, most significant
-- bit first. the history is stored newest bit first, so the head of the
-- list is the least significant bit.
convert :: [Binary] -> Integer
convert = foldr (\b acc -> toInteger (fromEnum b) + 2 * acc) 0

-- ask the external program about the number the bits represent
askProgram :: [Binary] -> IO Bool
askProgram bits = read <$> readProcess source [] (show (convert bits) ++ "\n")

-- the program itself is stateless, so the SUL keeps the inputs it has
-- received since the last reset and queries the program with all of them
-- on every step.
data Program i o = Program ([i] -> IO o) [i]

instance SUL Program IO where
    step (Program f buf) x = do
        let buf' = x : buf
        o <- f buf'
        return (Program f buf', o)
    reset (Program f _) = return (Program f [])

sul :: Program Binary Bool
sul = Program askProgram []

main :: IO ()
main = do
    oracle <- either fail return (mkWpMethod (WpMethodConfig 3))
    let learner = mkLMstar Star
    (theModel, theStats) <- runExperimentT (measuredExperiment statistics learner oracle) sul
    putStrLn "Learning Experiment"
    putStrLn "==================="
    putStrLn "System Under Learning: ./examples/divisible3"
    putStrLn $ "Learned Model: " ++ show theModel
    putStrLn $ "Experiment Statistics: " ++ show theStats