Commit bd186b68 authored by Hans-Peter Deifel's avatar Hans-Peter Deifel 🐢

random-dfa: Replace Int with Word16

This should require 4 times less RAM and allow us to generate larger DFAs.
parent b4cb3bed
......@@ -2,6 +2,7 @@ module CoalgOutput (coalgB) where
import Data.Foldable ( fold )
import Data.List ( intersperse )
import Data.Word
import qualified Data.Text.Lazy.Builder as Build
import qualified Data.Text.Lazy.Builder.Int as Build
......@@ -22,20 +23,23 @@ transitionsB :: DFA -> Build.Builder
transitionsB dfa = foldMap (forStateB dfa) [0 .. dfa ^. states - 1]
forStateB :: DFA -> Int -> Build.Builder
forStateB :: DFA -> Word16 -> Build.Builder
forStateB dfa n =
"s"
<> Build.decimal n
<> ": ("
<> Build.fromString (show (dfa ^?! isFinal . ix n))
<> Build.fromString (show (dfa ^?! isFinal . ix (fromIntegral n)))
<> ", {"
<> fold
(intersperse
", "
(zipWith successorB [0 ..] (dfa ^.. transitions . ix n . each))
(zipWith successorB
[0 ..]
(dfa ^.. transitions . ix (fromIntegral n) . each)
)
)
<> "})\n"
successorB :: Int -> Int -> Build.Builder
successorB :: Word16 -> Word16 -> Build.Builder
successorB label target = Build.decimal label <> ": s" <> Build.decimal target
module DotOutput (dotB) where
import Data.Foldable ( fold )
import Data.Word
import qualified Data.Text.Lazy.Builder as Build
import qualified Data.Text.Lazy.Builder.Int as Build
......@@ -16,21 +17,25 @@ nodesB :: DFA -> Build.Builder
nodesB dfa = foldMap (nodeB dfa) [0 .. dfa ^. states - 1]
nodeB :: DFA -> Int -> Build.Builder
nodeB :: DFA -> Word16 -> Build.Builder
nodeB dfa n = " \"n" <> Build.decimal n <> "\" [shape = " <> shape <> "];\n"
where shape = if dfa ^?! isFinal . ix n then "doublecircle" else "circle"
where
shape =
if dfa ^?! isFinal . ix (fromIntegral n) then "doublecircle" else "circle"
transitionsB :: DFA -> Build.Builder
transitionsB dfa = foldMap (transitionsForB dfa) [0 .. dfa ^. states - 1]
transitionsForB :: DFA -> Int -> Build.Builder
transitionsForB dfa n =
fold (zipWith (transitionB n) [0 ..] (dfa ^.. transitions . ix n . each))
transitionsForB :: DFA -> Word16 -> Build.Builder
transitionsForB dfa n = fold
(zipWith (transitionB n)
[0 ..]
(dfa ^.. transitions . ix (fromIntegral n) . each))
transitionB :: Int -> Int -> Int -> Build.Builder
transitionB :: Word16 -> Word16 -> Word16 -> Build.Builder
transitionB source letter target =
" n"
<> Build.decimal source
......
......@@ -6,6 +6,7 @@ import Control.Applicative
import Control.Monad ( forM_ )
import Data.Maybe ( listToMaybe )
import qualified Data.List.NonEmpty as NE
import Data.Word
import qualified Data.Text.Lazy.IO as TL
import qualified Data.Text.Lazy.Builder as Build
......@@ -24,12 +25,14 @@ import ValmariOutput
-- | Generate a random DFA
randomDFA
:: Int -- ^ Number of states
-> Int -- ^ Size of the alphabet
:: Word16 -- ^ Number of states
-> Word16 -- ^ Size of the alphabet
-> IO DFA
randomDFA s a = do
finals <- VU.replicateM s randomIO
matrix <- V.replicateM s (VU.replicateM a (randomRIO (0, s - 1)))
finals <- VU.replicateM (fromIntegral s) randomIO
matrix <- V.replicateM
(fromIntegral s)
(VU.replicateM (fromIntegral a) (randomRIO (0, s - 1)))
return DFA { dfaStates = s
, dfaLetters = a
, dfaIsFinal = finals
......@@ -46,8 +49,8 @@ instance Show OutputFormat where
data Options = Options
{ _optStates :: Int
, _optLetters :: Int
{ _optStates :: Word16
, _optLetters :: Word16
, _optOutputs :: [(OutputFormat, Maybe (NE.NonEmpty Char))]
} deriving (Show)
makeLensesWith abbreviatedFields ''Options
......@@ -56,14 +59,12 @@ makeLensesWith abbreviatedFields ''Options
options :: OptParse.Parser Options
options =
Options
<$> (OptParse.argument
<$> OptParse.argument
OptParse.auto
(OptParse.metavar "N" <> OptParse.help "Number of states")
)
<*> (OptParse.argument
<*> OptParse.argument
OptParse.auto
(OptParse.metavar "M" <> OptParse.help "Size of the alphabet")
)
<*> some
(OptParse.argument
readOutput
......@@ -86,10 +87,10 @@ readOutput = OptParse.eitherReader $ \s -> case span (/= sep) s of
([] , _ ) -> Left "a"
(_ , []) -> Left "b"
(format, _ : file) -> (, NE.nonEmpty file) <$> case format of
"copar" -> Right Copar
"dot" -> Right Dot
"copar" -> Right Copar
"dot" -> Right Dot
"valmari" -> Right Valmari
_ -> Left "c"
_ -> Left "c"
where sep = ':'
......
......@@ -8,14 +8,22 @@ module Type
, HasIsFinal(..)
) where
import Data.Word
import Data.Vector ( Vector )
import qualified Data.Vector.Unboxed as VU
import Lens.Micro.TH
-- The objective here is to support large DFAs and thus is might seem backwards
-- to restrict the number of states and letters to Word16. In reality, the
-- limiting factor is RAM, e.g 10000x10000 requires already more ram than my
-- 16GB machine has. Word16 requires 4 times less RAM than Int, so it allows for
-- larger graphs in practice.
data DFA = DFA
{ dfaStates :: Int
, dfaLetters :: Int
, dfaTransitions :: Vector (VU.Vector Int)
{ dfaStates :: Word16
, dfaLetters :: Word16
, dfaTransitions :: Vector (VU.Vector Word16)
, dfaIsFinal :: VU.Vector Bool
}
......
module ValmariOutput (valmariB) where
import Data.Monoid
import Data.Word
import qualified Data.Text.Lazy.Builder as Build
import qualified Data.Text.Lazy.Builder.Int as Build
......@@ -38,7 +39,7 @@ transitionsB dfa = foldMap
]
transB :: DFA -> Int -> Int -> Build.Builder
transB :: DFA -> Word16 -> Word16 -> Build.Builder
transB dfa from letter =
Build.decimal (from + 1)
<> " "
......@@ -46,15 +47,16 @@ transB dfa from letter =
<> " "
<> Build.decimal (to + 1)
<> "\n"
where to = dfa ^?! transitions . ix from . ix letter
where
to =
dfa ^?! transitions . ix (fromIntegral from) . ix (fromIntegral letter)
blocksB :: DFA -> Build.Builder
blocksB dfa
| VU.and (dfa ^. isFinal) = statesThatAre final
| otherwise = statesThatAre (not . final)
blocksB dfa | VU.and (dfa ^. isFinal) = statesThatAre final
| otherwise = statesThatAre (not . final)
where
statesThatAre p =
foldMap stateB (filter p [0 .. dfa ^. states - 1]) <> "0 \n"
stateB x = Build.decimal (x+1) <> " "
final x = dfa ^?! isFinal . ix x
stateB x = Build.decimal (x + 1) <> " "
final x = dfa ^?! isFinal . ix (fromIntegral x)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment