1
Fork 0
mirror of https://git.cs.ou.nl/joshua.moerman/mealy-decompose.git synced 2025-04-29 17:57:44 +02:00
mealy-decompose/hs/app/RandomGen.hs
2025-04-29 09:57:09 +02:00

115 lines
4.4 KiB
Haskell

{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
-- | Copyright: (c) 2024-2025 Joshua Moerman, Open Universiteit
-- SPDX-License-Identifier: EUPL-1.2
module RandomGen where
import Data.Partition (Block (..))
import SplittingTree
import Control.Monad.Random.Strict
import Control.Monad.Trans.State (execStateT)
import Data.List (sortOn)
import Data.Map qualified as Map
import Data.Set qualified as Set
import Options.Applicative
import System.Random
data RandomGenOptions = RandomGenOptions
{ numStates :: Int
, numComponents :: Int
}
deriving Show
randomGenOptionsParser :: Parser RandomGenOptions
randomGenOptionsParser =
RandomGenOptions
<$> option auto (long "states" <> short 'n' <> help "Number of states per component (max)" <> metavar "NUM" <> showDefault <> value 10)
<*> option auto (long "components" <> short 'c' <> help "Number of components" <> metavar "COMP" <> showDefault <> value 2)
genTransitions :: _ => Int -> [Char] -> [Char] -> RandT _ _ _
genTransitions size inputs outputs = do
let
states = [1 .. size]
numOutputs = length outputs
randomOutput = (outputs !!) <$> liftRand (uniformR (0, numOutputs - 1))
randomTarget = (states !!) <$> liftRand (uniformR (0, size - 1))
randomTransition s i = (\o t -> (s, i, o, t)) <$> randomOutput <*> randomTarget
t <- sequence $ randomTransition <$> states <*> inputs
return (states, t)
-- numC <= 8
genComposition :: _ => Int -> Int -> [Char] -> RandT _ _ _
genComposition size numC inputs = do
let
components = [1 .. numC]
outputSets = [[], "xy", "zw", "uv", "kl", "mn", "op", "qr", "st"]
allTransitions <- traverse (\c -> genTransitions size inputs (outputSets !! c)) components
let
productState = fmap (Map.fromList . zip components) (mapM fst allTransitions)
allStates = (,) <$> components <*> productState
compMap = Map.fromList $ zip components ((Map.fromList . fmap (\(s, i, o, t) -> ((s, i), (o, t)))) . snd <$> allTransitions)
norm c
| c <= 0 = c + numC
| c > numC = c - numC
| otherwise = c
transition (c, cs) 'L' = (norm (c - 1), cs)
transition (c, cs) 'R' = (norm (c + 1), cs)
transition (c, cs) x = (c, Map.adjust (\s -> snd (compMap Map.! c Map.! (s, x))) c cs)
output _ 'L' = 'L'
output _ 'R' = 'R'
output (c, cs) x = fst (compMap Map.! c Map.! (cs Map.! c, x))
-- initial states, inputs, transition function, outputs
return (head allStates, 'L' : 'R' : inputs, transition, output)
reachability :: _ => s -> [i] -> (s -> i -> s) -> Map.Map s Int
reachability initialState inputs transitions = go 0 Map.empty [initialState]
where
go _ visited [] = visited
go n visited (s : rest) =
let newVis = Map.insert s n visited
newStates = [t | i <- inputs, let t = transitions s i, t `Map.notMember` newVis]
in go (n + 1) newVis (rest ++ newStates)
mainRandomGen :: RandomGenOptions -> IO ()
mainRandomGen RandomGenOptions{..} = do
let
n = numStates
c = numComponents
-- create random composition
(init0, inputs, trans0, outpf0) <- evalRandIO (genComposition n c ['a', 'b'])
-- reachable part only
let
reachableMap = reachability init0 inputs trans0
inverseMap = Map.fromList . fmap (\(a, b) -> (b, a)) . Map.toList $ reachableMap
states = Map.elems reachableMap
init = reachableMap Map.! init0
trans s i = reachableMap Map.! trans0 (inverseMap Map.! s) i
outpf s = outpf0 (inverseMap Map.! s)
-- minimize
let
outputFuns = [(i, fun) | i <- inputs, let fun s = outpf s i]
reverseTransitionMaps i = Map.fromListWith (++) [(t, [s]) | s <- states, let t = trans s i]
reverseFuns = [(i, fun) | i <- inputs, let m = reverseTransitionMaps i, let fun s = Map.findWithDefault [] s m]
PRState{..} <- execStateT (refine (const (pure ())) outputFuns reverseFuns) (initialPRState states)
-- print to stdout
let
toBlock s = getBarePartition partition Map.! s
allTransitions = [(toBlock s, i, o, toBlock t) | s <- states, i <- inputs, let o = outpf s i, let t = trans s i]
uniqueTransitions = sortOn (\(s, _, _, _) -> s /= toBlock init) . Set.toList . Set.fromList $ allTransitions
showLabel i o = "[label=\"" <> [i] <> "/" <> [o] <> "\"]"
showTransition (Block s) i o (Block t) = "s" <> show s <> " -> " <> "s" <> show t <> " " <> showLabel i o
putStrLn "digraph g {"
mapM_ (\(s, i, o, t) -> putStrLn (" " <> showTransition s i o t)) uniqueTransitions
putStrLn "}"