Commit dbd78cf8 authored by Hans-Peter Deifel's avatar Hans-Peter Deifel 🐢
Browse files

wta: Change --out-degree to --transitions

It's now used to specify how many transitions you want instead of how many
transitions per state. This is strictly more powerful because you can always
just specify states*out-degree as transition count.
parent cab34a04
Loading
Loading
Loading
Loading
+8 −9
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE LambdaCase #-}

module Generator (genWTA, runGenerator, GeneratorConfig(..), ZeroFrequency(..)) where
module Generator (genWTA, runGenerator, GeneratorConfig(..), EdgeConfig(..)) where

import           Data.Vector                    ( Vector )
import qualified Data.Vector                   as V
@@ -21,18 +21,18 @@ import Probability
import           IndexedTransition
import qualified IndexedTransition

data ZeroFrequency = Percentage Probability | OutDegree Int
data EdgeConfig = ZeroFrequency Probability | NumTransitions Int

data GeneratorConfig m = GeneratorConfig
   { spec :: WTASpec m
   , zeroPolicy :: ZeroFrequency
   , zeroPolicy :: EdgeConfig
   , differentValues :: Maybe Int
   }

type Generator m = ReaderT (GeneratorConfig m) IO

zeroFreq :: GeneratorConfig m -> Probability
zeroFreq (GeneratorConfig { zeroPolicy = Percentage p }) = p
zeroFreq (GeneratorConfig { zeroPolicy = ZeroFrequency p }) = p
zeroFreq _ = error "zeroFreq: unexpected out degree" -- TODO Ugly as hell

runGenerator :: GeneratorConfig m -> Generator m a -> IO a
@@ -107,13 +107,12 @@ uniqueTransitions num (IndexedTransition.Index max) = helper S.empty num


genTransitions' :: Int -> Generator m (Vector (Vector (Transition m)))
genTransitions' outDegree = do
genTransitions' numTransitions = do
  wtaSpec <- asks spec
  let n = numStates wtaSpec
      m = IndexedTransition.maxIndex wtaSpec
      desiredEdges = n * outDegree

  transitions <- lift $ map (IndexedTransition.fromIndex wtaSpec) <$> uniqueTransitions desiredEdges m
  transitions <- lift $ map (IndexedTransition.fromIndex wtaSpec) <$> uniqueTransitions numTransitions m
  weightedTransitions <- (traverse.traverse.traverse) (const genMonoidValue) transitions

  let byState = foldl' (\m (State s, t) -> M.insertWith (++) s [t] m) M.empty weightedTransitions
@@ -126,5 +125,5 @@ genTransitions' outDegree = do

genWTA :: Generator m (WTA m)
genWTA = asks zeroPolicy >>= \case
  OutDegree d -> WTA <$> asks spec <*> genStates <*> (genTransitions' d)
  Percentage _ -> WTA <$> asks spec <*> genStates <*> genTransitions
  NumTransitions d -> WTA <$> asks spec <*> genStates <*> (genTransitions' d)
  ZeroFrequency _ -> WTA <$> asks spec <*> genStates <*> genTransitions
+12 −13
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ data Opts = Opts
  { optMonoid :: SomeMonoid
  , optStates :: Int
  , optSymbols :: SymbolSpec
  , optZeroFrequency :: ZeroFrequency
  , optEdgeConfig :: EdgeConfig
  , optRandomState :: Maybe StdGen
  , optDifferentValues :: Maybe Int
  }
@@ -104,9 +104,9 @@ parseOpts =
            )
          )

parseZeroFreq :: Options.Parser ZeroFrequency
parseZeroFreq :: Options.Parser EdgeConfig
parseZeroFreq =
  (Percentage <$> Options.option
  (ZeroFrequency <$> Options.option
      (Options.eitherReader readProbability)
      (  Options.long "zero-frequency"
      <> Options.showDefault
@@ -116,13 +116,12 @@ parseZeroFreq =
           "Frequency of edges with zero weight as number between 0 and 1."
      )
    )
    <|> (OutDegree <$> Options.option
    <|> (NumTransitions <$> Options.option
          Options.auto
          (  Options.long "out-degree"
          <> Options.metavar "NUM_TRANSITIONS"
          (  Options.long "transitions"
          <> Options.metavar "NUM"
          <> Options.help
               ("Expected number of outgoing transitions per state."
               <> " This calculates the zero frequency from the number of states, symbols and this parameter."
               ("Number of transitions to generate. They will be distributed randomly over states."
               )
          )
        )
@@ -134,9 +133,9 @@ withSpec opts f = case optMonoid opts of
                            , numSymbols = optSymbols opts
                            }

computeProbability :: WTASpec m -> ZeroFrequency -> Probability
computeProbability _ (Percentage p) = p
computeProbability spec (OutDegree d) =
computeProbability :: WTASpec m -> EdgeConfig -> Probability
computeProbability _ (ZeroFrequency p) = p
computeProbability spec (NumTransitions d) =
  let n = numStates spec
      t = V.sum (V.imap (\i syms -> syms * n ^ i) (numSymbols spec))
  in  fromRationalApprox (1 - fromIntegral d / fromIntegral t)
@@ -157,10 +156,10 @@ main = do

  withSpec opts $ \spec -> do
    randGen <- getStdGen
    -- let zeroFreq = computeProbability spec (optZeroFrequency opts)
    -- let zeroFreq = computeProbability spec (optEdgeConfig opts)
    -- hPutStrLn stderr $ "p hacking: " ++ show zeroFreq
    wta <- runGenerator
      (GeneratorConfig spec (optZeroFrequency opts) (optDifferentValues opts))
      (GeneratorConfig spec (optEdgeConfig opts) (optDifferentValues opts))
      genWTA
    putStrLn $ "# Random state for this automaton: '" <> show randGen <> "'"
    T.putStr (Build.toLazyText (buildWTA wta))