packages feed

markov-realization 0.1.0 → 0.2.1

raw patch · 8 files changed

+635/−565 lines, 8 filesdep +HTFdep +comonaddep +configuration-toolsdep ~MonadRandomdep ~contravariantdep ~discriminationPVP ok

version bump matches the API change (PVP)

Dependencies added: HTF, comonad, configuration-tools, markov-realization

Dependency ranges changed: MonadRandom, contravariant, discrimination, generic-deriving

API changes (from Hackage documentation)

- Markov: class (Combine m, Grouping m, Semigroup m) => MultiMarkov m
- Markov: multiChain :: MultiMarkov m => [m] -> [[m]]
- Markov: multiStep :: MultiMarkov m => m -> [m]
- Markov: multiTransition :: MultiMarkov m => m -> [m -> [m]]
- Markov.Examples: Extinction :: Int -> Extinction
- Markov.Examples: FromMatrix :: Char -> FromMatrix
- Markov.Examples: Room :: Int -> Room
- Markov.Examples: Simple :: Int -> Simple
- Markov.Examples: Tidal :: Double -> Int -> Tidal
- Markov.Examples: Urn :: (Int, Int) -> Urn
- Markov.Examples: [position] :: Tidal -> Int
- Markov.Examples: [time] :: Tidal -> Double
- Markov.Examples: data FillBin
- Markov.Examples: data Tidal
- Markov.Examples: expectedLoss :: (Fractional a, Markov (Product a) FillBin) => [Product a :* FillBin] -> a
- Markov.Examples: initial :: [Int] -> FillBin
- Markov.Examples: instance Data.Discrimination.Grouping.Grouping Markov.Examples.Extinction
- Markov.Examples: instance Data.Discrimination.Grouping.Grouping Markov.Examples.FillBin
- Markov.Examples: instance Data.Discrimination.Grouping.Grouping Markov.Examples.FromMatrix
- Markov.Examples: instance Data.Discrimination.Grouping.Grouping Markov.Examples.Room
- Markov.Examples: instance Data.Discrimination.Grouping.Grouping Markov.Examples.Simple
- Markov.Examples: instance Data.Discrimination.Grouping.Grouping Markov.Examples.Tidal
- Markov.Examples: instance Data.Discrimination.Grouping.Grouping Markov.Examples.Urn
- Markov.Examples: instance GHC.Base.Semigroup Markov.Examples.Extinction
- Markov.Examples: instance GHC.Base.Semigroup Markov.Examples.Room
- Markov.Examples: instance GHC.Classes.Eq Markov.Examples.Extinction
- Markov.Examples: instance GHC.Classes.Eq Markov.Examples.FillBin
- Markov.Examples: instance GHC.Classes.Eq Markov.Examples.FromMatrix
- Markov.Examples: instance GHC.Classes.Eq Markov.Examples.Room
- Markov.Examples: instance GHC.Classes.Eq Markov.Examples.Simple
- Markov.Examples: instance GHC.Classes.Eq Markov.Examples.Tidal
- Markov.Examples: instance GHC.Classes.Eq Markov.Examples.Urn
- Markov.Examples: instance GHC.Classes.Ord Markov.Examples.FillBin
- Markov.Examples: instance GHC.Classes.Ord Markov.Examples.Simple
- Markov.Examples: instance GHC.Classes.Ord Markov.Examples.Tidal
- Markov.Examples: instance GHC.Classes.Ord Markov.Examples.Urn
- Markov.Examples: instance GHC.Enum.Enum Markov.Examples.Simple
- Markov.Examples: instance GHC.Generics.Generic Markov.Examples.Extinction
- Markov.Examples: instance GHC.Generics.Generic Markov.Examples.FillBin
- Markov.Examples: instance GHC.Generics.Generic Markov.Examples.FromMatrix
- Markov.Examples: instance GHC.Generics.Generic Markov.Examples.Room
- Markov.Examples: instance GHC.Generics.Generic Markov.Examples.Simple
- Markov.Examples: instance GHC.Generics.Generic Markov.Examples.Tidal
- Markov.Examples: instance GHC.Generics.Generic Markov.Examples.Urn
- Markov.Examples: instance GHC.Num.Num Markov.Examples.Extinction
- Markov.Examples: instance GHC.Num.Num Markov.Examples.Room
- Markov.Examples: instance GHC.Num.Num Markov.Examples.Simple
- Markov.Examples: instance GHC.Show.Show Markov.Examples.Extinction
- Markov.Examples: instance GHC.Show.Show Markov.Examples.FillBin
- Markov.Examples: instance GHC.Show.Show Markov.Examples.FromMatrix
- Markov.Examples: instance GHC.Show.Show Markov.Examples.Room
- Markov.Examples: instance GHC.Show.Show Markov.Examples.Simple
- Markov.Examples: instance GHC.Show.Show Markov.Examples.Tidal
- Markov.Examples: instance GHC.Show.Show Markov.Examples.Urn
- Markov.Examples: instance Markov.Combine Markov.Examples.Extinction
- Markov.Examples: instance Markov.Combine Markov.Examples.Room
- Markov.Examples: instance Markov.Markov (Markov.Product GHC.Types.Double) Markov.Examples.FillBin
- Markov.Examples: instance Markov.Markov (Markov.Product GHC.Types.Double) Markov.Examples.FromMatrix
- Markov.Examples: instance Markov.Markov (Markov.Product GHC.Types.Double) Markov.Examples.Simple
- Markov.Examples: instance Markov.Markov (Markov.Product GHC.Types.Double) Markov.Examples.Tidal
- Markov.Examples: instance Markov.Markov (Markov.Product GHC.Types.Double) Markov.Examples.Urn
- Markov.Examples: instance Markov.Markov (Markov.Product GHC.Types.Int) Markov.Examples.Simple
- Markov.Examples: instance Markov.Markov (Markov.Sum GHC.Types.Int) Markov.Examples.Simple
- Markov.Examples: instance Markov.Markov (Markov.Sum GHC.Types.Int, Markov.Product GHC.Real.Rational) Markov.Examples.Extinction
- Markov.Examples: instance Markov.Markov0 Markov.Examples.Simple
- Markov.Examples: instance Markov.MultiMarkov ((Markov.Product GHC.Real.Rational Markov.:* Markov.Merge GHC.Base.String) Markov.:* Markov.Examples.Room)
- Markov.Examples: instance Markov.MultiMarkov ((Markov.Sum GHC.Types.Int Markov.:* Markov.Product GHC.Real.Rational) Markov.:* Markov.Examples.Extinction)
- Markov.Examples: newtype Extinction
- Markov.Examples: newtype FromMatrix
- Markov.Examples: newtype Room
- Markov.Examples: newtype Simple
- Markov.Examples: newtype Urn
- Markov.Instances: instance Data.Discrimination.Grouping.Grouping GHC.Types.Double
- Markov.Instances: instance Data.Discrimination.Grouping.Grouping GHC.Types.Float
+ Markov: sequential :: Markov t m => [m -> [t (m -> m)]]
+ Markov.Example: Extinction :: Int -> Extinction
+ Markov.Example: FromMatrix :: Char -> FromMatrix
+ Markov.Example: Room :: Int -> Room
+ Markov.Example: Simple :: Int -> Simple
+ Markov.Example: Tidal :: Double -> Int -> Tidal
+ Markov.Example: Urn :: (Int, Int) -> Urn
+ Markov.Example: [position] :: Tidal -> Int
+ Markov.Example: [time] :: Tidal -> Double
+ Markov.Example: data FillBin
+ Markov.Example: data Tidal
+ Markov.Example: expectedLoss :: (Fractional a, Markov ((,) (Product a)) FillBin) => [Product a :* FillBin] -> a
+ Markov.Example: initial :: [Int] -> FillBin
+ Markov.Example: instance Data.Discrimination.Grouping.Grouping Markov.Example.Extinction
+ Markov.Example: instance Data.Discrimination.Grouping.Grouping Markov.Example.FillBin
+ Markov.Example: instance Data.Discrimination.Grouping.Grouping Markov.Example.FromMatrix
+ Markov.Example: instance Data.Discrimination.Grouping.Grouping Markov.Example.Room
+ Markov.Example: instance Data.Discrimination.Grouping.Grouping Markov.Example.Simple
+ Markov.Example: instance Data.Discrimination.Grouping.Grouping Markov.Example.Tidal
+ Markov.Example: instance Data.Discrimination.Grouping.Grouping Markov.Example.Urn
+ Markov.Example: instance GHC.Classes.Eq Markov.Example.Extinction
+ Markov.Example: instance GHC.Classes.Eq Markov.Example.FillBin
+ Markov.Example: instance GHC.Classes.Eq Markov.Example.FromMatrix
+ Markov.Example: instance GHC.Classes.Eq Markov.Example.Room
+ Markov.Example: instance GHC.Classes.Eq Markov.Example.Simple
+ Markov.Example: instance GHC.Classes.Eq Markov.Example.Tidal
+ Markov.Example: instance GHC.Classes.Eq Markov.Example.Urn
+ Markov.Example: instance GHC.Classes.Ord Markov.Example.FillBin
+ Markov.Example: instance GHC.Classes.Ord Markov.Example.Simple
+ Markov.Example: instance GHC.Classes.Ord Markov.Example.Tidal
+ Markov.Example: instance GHC.Classes.Ord Markov.Example.Urn
+ Markov.Example: instance GHC.Enum.Enum Markov.Example.Simple
+ Markov.Example: instance GHC.Generics.Generic Markov.Example.Extinction
+ Markov.Example: instance GHC.Generics.Generic Markov.Example.FillBin
+ Markov.Example: instance GHC.Generics.Generic Markov.Example.FromMatrix
+ Markov.Example: instance GHC.Generics.Generic Markov.Example.Room
+ Markov.Example: instance GHC.Generics.Generic Markov.Example.Simple
+ Markov.Example: instance GHC.Generics.Generic Markov.Example.Tidal
+ Markov.Example: instance GHC.Generics.Generic Markov.Example.Urn
+ Markov.Example: instance GHC.Num.Num Markov.Example.Extinction
+ Markov.Example: instance GHC.Num.Num Markov.Example.Room
+ Markov.Example: instance GHC.Num.Num Markov.Example.Simple
+ Markov.Example: instance GHC.Show.Show Markov.Example.Extinction
+ Markov.Example: instance GHC.Show.Show Markov.Example.FillBin
+ Markov.Example: instance GHC.Show.Show Markov.Example.FromMatrix
+ Markov.Example: instance GHC.Show.Show Markov.Example.Room
+ Markov.Example: instance GHC.Show.Show Markov.Example.Simple
+ Markov.Example: instance GHC.Show.Show Markov.Example.Tidal
+ Markov.Example: instance GHC.Show.Show Markov.Example.Urn
+ Markov.Example: instance Markov.Combine Markov.Example.Extinction
+ Markov.Example: instance Markov.Combine Markov.Example.FillBin
+ Markov.Example: instance Markov.Combine Markov.Example.FromMatrix
+ Markov.Example: instance Markov.Combine Markov.Example.Room
+ Markov.Example: instance Markov.Combine Markov.Example.Simple
+ Markov.Example: instance Markov.Combine Markov.Example.Tidal
+ Markov.Example: instance Markov.Combine Markov.Example.Urn
+ Markov.Example: instance Markov.Markov ((,) (Markov.Product GHC.Real.Rational, Markov.Merge GHC.Base.String)) Markov.Example.Room
+ Markov.Example: instance Markov.Markov ((,) (Markov.Product GHC.Types.Double)) Markov.Example.FillBin
+ Markov.Example: instance Markov.Markov ((,) (Markov.Product GHC.Types.Double)) Markov.Example.FromMatrix
+ Markov.Example: instance Markov.Markov ((,) (Markov.Product GHC.Types.Double)) Markov.Example.Simple
+ Markov.Example: instance Markov.Markov ((,) (Markov.Product GHC.Types.Double)) Markov.Example.Tidal
+ Markov.Example: instance Markov.Markov ((,) (Markov.Product GHC.Types.Double)) Markov.Example.Urn
+ Markov.Example: instance Markov.Markov ((,) (Markov.Product GHC.Types.Int)) Markov.Example.Simple
+ Markov.Example: instance Markov.Markov ((,) (Markov.Sum GHC.Types.Int)) Markov.Example.Simple
+ Markov.Example: instance Markov.Markov ((,) (Markov.Sum GHC.Types.Int, Markov.Product GHC.Real.Rational)) Markov.Example.Extinction
+ Markov.Example: instance Markov.Markov0 Markov.Example.Simple
+ Markov.Example: newtype Extinction
+ Markov.Example: newtype FromMatrix
+ Markov.Example: newtype Room
+ Markov.Example: newtype Simple
+ Markov.Example: newtype Urn
+ Markov.Instance: instance Data.Discrimination.Grouping.Grouping GHC.Types.Double
+ Markov.Instance: instance Data.Discrimination.Grouping.Grouping GHC.Types.Float
- Markov: chain :: Markov t m => [(t, m)] -> [[(t, m)]]
+ Markov: chain :: (Combine (t m), Grouping (t m), Markov t m) => [t m] -> [[t m]]
- Markov: class (Combine t, Grouping t, Grouping m, Monoid t) => Markov t m
+ Markov: class (Applicative t, Comonad t) => Markov t m
- Markov: fromLists :: Eq b => [[a]] -> [b] -> b -> [(a, b -> b)]
+ Markov: fromLists :: Eq b => [[a]] -> [b] -> b -> [(a, c -> b)]
- Markov: randomPath :: (Markov a b, Real a, RandomGen g) => (a, b) -> g -> [(a, b)]
+ Markov: randomPath :: (Markov ((,) a) b, Real a, RandomGen g) => (a, b) -> g -> [(a, b)]
- Markov: step :: Markov t m => (t, m) -> [(t, m)]
+ Markov: step :: Markov t m => t m -> [t m]
- Markov: transition :: Markov t m => m -> [(t, m -> m)]
+ Markov: transition :: Markov t m => m -> [t (m -> m)]

Files

README.md view
@@ -1,6 +1,6 @@ # Markov Tutorial -Let X<sub>n</sub> denote the nth state of a Markov chain with state space ℕ.+Let Xₙ denote the nth state of a Markov chain with state space ℕ. For x ≠ 0 define transition probabilities  p(x,0) = q,@@ -14,7 +14,7 @@ p(x,x+1) = s. Let p(x,y) = 0 in all other cases. Suppose we wanted to find-P\[X<sub>n</sub> = j ∩ d = k],+P\[Xₙ = j ∩ d = k], where d denotes the number of transitions from a positive integer to zero. There are three values we need to track — extinctions, probability, and state.@@ -49,17 +49,15 @@  We can now easily see a list of states, deaths, and the probabilities. -<pre>-<b>-> chain [pure 0 :: Sum Int :* Product Rational :* Extinction] !! 3-</b>-((0,8 % 125),0)-((0,111 % 500),1)-((1,51 % 500),0)-((0,9 % 25),2)-((1,9 % 250),1)-((0,27 % 125),3-</pre>+__`> chain [pure 0 :: Sum Int :* Product Rational :* Extinction] !! 3`__+```+[ ((0,8 % 125),0)+, ((0,111 % 500),1)+, ((1,51 % 500),0)+, ((0,9 % 25),2)+, ((1,9 % 250),1)+, ((0,27 % 125),3) ]+```  This means that starting from a state of zero, after three time steps there is a 51/500 chance
markov-realization.cabal view
@@ -1,38 +1,61 @@ cabal-version: 1.12-name: markov-realization-version: 0.1.0-license: BSD3-license-file: LICENSE-copyright: 2019 Alex Loomis-maintainer: atloomis@math.arizona.edu-author: Alex Loomis-homepage: https://github.com/alexloomis/markov-bug-reports: https://github.com/alexloomis/markov/issues-synopsis: Realizations of Markov chains.-description:-    Please see the README on GitHub at <https://github.com/alexloomis/markov#markov-tutorial>-category: Statistics-build-type: Simple++-- This file has been generated from package.yaml by hpack version 0.31.1.+--+-- see: https://github.com/sol/hpack+--+-- hash: b164fe328e9edef0858d48e61b56997280bd4bb2ea6ffe923afb24084a14efe6++name:           markov-realization+version:        0.2.1+description:    Please see the README on GitHub at <https://github.com/alexloomis/markov#markov-tutorial>+homepage:       https://github.com/alexloomis/markov+bug-reports:    https://github.com/alexloomis/markov/issues+author:         Alex Loomis+maintainer:     atloomis@math.arizona.edu+copyright:      2019 Alex Loomis+license:        BSD3+license-file:   LICENSE+build-type:     Simple extra-source-files:     README.md     ChangeLog.md+category:       Statistics+synopsis:       Realizations of Markov chains.  source-repository head-    type: git-    location: git://github.com/alexloomis/markov.git+  type: git+  location: git://github.com/alexloomis/markov.git  library-    exposed-modules:-        Markov-        Markov.Examples-        Markov.Instances-    hs-source-dirs: src-    other-modules:-        Paths_markov_realization-    default-language: Haskell2010-    build-depends:-        base >=4.7 && <5,-        contravariant >=1.5.1 && <1.6,-        discrimination ==0.4.*,-        generic-deriving >=1.12.4 && <1.13,-        MonadRandom >=0.5.1.1 && <0.6+  exposed-modules:+      Markov+      Markov.Example+      Markov.Instance+  other-modules:+      Paths_markov_realization+  hs-source-dirs:+      src+  build-depends:+      base >=4.7 && <5+    , comonad+    , configuration-tools+    , contravariant+    , discrimination+    , generic-deriving+    , MonadRandom+  default-language: Haskell2010++test-suite markov-test+  type: exitcode-stdio-1.0+  main-is: Test.hs+  other-modules:+      Paths_markov_realization+  hs-source-dirs:+      test+  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.7 && <5+    , HTF+    , markov-realization+  default-language: Haskell2010
src/Markov.hs view
@@ -1,6 +1,11 @@-{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving, DeriveGeneric,-DeriveAnyClass, DerivingStrategies, TypeOperators #-}-{-|+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE DeriveAnyClass             #-}+{-# LANGUAGE DerivingStrategies         #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses      #-}+{-# LANGUAGE TypeOperators              #-}+{- | Module      : Markov Description : Realization of Markov processes with known parameters. Maintainer  : atloomis@math.arizona.edu@@ -9,42 +14,45 @@ Three type classes for deterministically analyzing Markov chains with known parameters. 'Markov0' is intended to list possible outcomes,-'Markov' should allow for more sophisticated analysis,-and 'MultiMarkov' is intended to make implementing-hidden Markov models easier.+'Markov' should allow for more sophisticated analysis. See "Examples" for examples. See README for a detailed description. -} module Markov (-              -- *Markov0-                Markov0 (..)-              -- *Markov-              , Markov (..)-              -- *MultiMarkov-              , randomProduct-              , randomPath-              , MultiMarkov (..)-              -- *Combine-              , Combine (..)-              , Merge (..)-              , Sum (..)-              , Product (..)-              -- *Misc-              , (:*)-              , (>*<)-              , fromLists-              -- *Testing-              ) where+     -- *Markov0+       Markov0 (..)+     , chain0 -import Markov.Instances ()-import Control.Applicative ((<**>))-import Generics.Deriving (Generic)+     -- *Markov+     , Markov (..)+     , chain++     -- *Combine+     , Combine (..)+     , Merge (..)+     , Sum (..)+     , Product (..)++     -- *Misc+     , (:*)+     , (>*<)+     , fromLists+     , randomProduct+     , randomPath+     ) where++-- import Configuration.Utils.Operators ((<*<))+import Control.Comonad import Data.Discrimination (Grouping, grouping)+import Generics.Deriving (Generic)++import Markov.Instance ()++import qualified Control.Monad.Random as MR import qualified Data.Discrimination as DD+import qualified Data.Functor.Contravariant as FC import qualified Data.List as DL import qualified Data.List.NonEmpty as NE-import qualified Data.Functor.Contravariant as FC-import qualified Control.Monad.Random as MR  --------------------------------------------------------------- -- Markov0@@ -52,48 +60,43 @@  -- |A basic implementation of Markov chains. class (Eq m) => Markov0 m where-    -- |The transition functions from a state.     transition0 :: m -> [m -> m]     step0       :: m -> [m]     -- |Iterated steps.-    chain0      :: [m] -> [[m]]-    step0 x = fmap ($ x) (transition0 x)-    chain0  = DL.iterate' $ DL.nub . concatMap step0+    transition0 x = const <$> step0 x+    step0 x = ($ x) <$> transition0 x+    {-# MINIMAL transition0 | step0 #-} +chain0 :: Markov0 m => [m] -> [[m]]+chain0 = DL.iterate' $ DL.nub . concatMap step0+ --------------------------------------------------------------------------------------- -- Markov ---------------------------------------------------------------------------------------  -- |An implementation of Markov chains.--- To speed up @chain@, try instead:------ > chain = DL.iterate' $ map summarize' . NE.group . DL.sort . concatMap step--- >     where summarize' xs@((_,b)NE.:|_) = (summarize . fmap fst $ xs, b)-class (Combine t, Grouping t, Grouping m, Monoid t) => Markov t m where-    transition :: m -> [(t, m -> m)]-    step       :: (t,m) -> [(t,m)]-    chain      :: [(t,m)] -> [[(t,m)]]-    step x = fmap (x <**>) (transition $ snd x)-    -- |Iterated steps, with equal states combined using 'summarize' operation.-    chain  = DL.iterate' $ map (summarize' . NE.fromList)-             . DD.group . concatMap step-             where summarize' xs@((_,b)NE.:|_) = (summarize . fmap fst $ xs, b)-             -- WARNING: DD.group does not currently respect equivalence classes.-------------------------------------------------------------------------------------------- Multi-Transition Markov----------------------------------------------------------------------------------------+class (Applicative t, Comonad t) => Markov t m where+    transition :: m -> [t (m -> m)]+    step       :: t m -> [t m]+    sequential :: [m -> [t (m -> m)]]+    transition = fmap (fmap const) . step . pure+    step x = foldr (concatMap . step') [x] sequential+      where step' f y = (<*> y) <$> f (extract y)+    sequential = [transition]+    {-# MINIMAL transition | step | sequential #-}+    -- Could also be defined as follows:+    --+    -- transition = foldr compose stayPut sequential+      -- where stayPut = const [pure id]+            -- compose g f a = composeWith g a =<< f a+            -- composeWith g a x = (<*< x) <$> g (extract $ fmap ($ a) x)+    -- step x = (<*> x) <$> transition (extract x)+    -- sequential = [fmap (fmap const) . step . pure] --- |An implementation of Markov chains that allows multi-transition steps.-class (Combine m, Grouping m, Semigroup m) => MultiMarkov m where-    multiTransition :: m -> [m -> [m]]-    multiStep       :: m -> [m]-    multiChain      :: [m] -> [[m]]-    multiStep x = foldr phi [x] (multiTransition x)-        where phi f = concatMap (delta f)-              delta f y = map (y <>) (f y)-    multiChain  = DL.iterate' $ map (summarize . NE.fromList)-                  . DD.group . concatMap multiStep+-- WARNING: DD.group does not currently respect equivalence classes.+-- |Iterated steps, with equal states combined using 'summarize' operation.+chain :: (Combine (t m), Grouping (t m), Markov t m) => [t m] -> [[t m]]+chain = DL.iterate' $ fmap (summarize . NE.fromList) .  DD.group . concatMap step  --------------------------------------------------------------------------------------- -- Combine@@ -109,7 +112,9 @@ class Combine a where     combine  :: a -> a -> a     summarize :: NE.NonEmpty a -> a+    combine a b = summarize . NE.fromList $ [a,b]     summarize (a NE.:| b) = foldr combine a b+    {-# MINIMAL combine | summarize #-}  instance (Combine a, Combine b) => Combine (a,b) where     combine (w,x) (y,z) = (combine w y, combine x z)@@ -123,10 +128,7 @@  -- |Easier way to write nested 2-tuples. type a :* b = (a,b)--- |Easier way to write nested 2-tuples,--- since @a >*\< b >*\< c >*< d@--- is much easier to read than--- @(((a,b),c),d)@.+-- |Easier way to write nested 2-tuples. -- Left associative, binds weaker than @+@ -- but stronger than @==@. (>*<) :: a -> b -> a :* b@@ -139,35 +141,33 @@  -- Does not group to combine unless equal. -- |Values from a 'Monoid' which have the respective--- binary operation applied each step.+-- binary operation applied each step,+-- where different values mean states should not be combined. -- E.g., strings with concatenation. newtype Merge a = Merge a     deriving (Eq, Generic)     deriving newtype (Semigroup, Monoid, Enum, Num, Fractional, Show)     deriving anyclass Grouping -instance Combine (Merge a) where-    combine = const+instance Combine (Merge a) where combine = const  --------------------------------------------------------------------------------------- -- Sum --------------------------------------------------------------------------------------- --- |Values which are added each step.+-- |Values which are added each step+-- where different values mean states should not be combined. -- E.g., number of times a red ball is picked from an urn. newtype Sum a = Sum a     deriving Generic     deriving newtype (Eq, Enum, Num, Fractional, Show)     deriving anyclass Grouping -instance Combine (Sum a) where-    combine = const+instance Combine (Sum a) where combine = const -instance Num a => Semigroup (Sum a) where-    x <> y = x + y+instance Num a => Semigroup (Sum a) where x <> y = x + y -instance Num a => Monoid (Sum a) where-    mempty = 0+instance Num a => Monoid (Sum a) where mempty = 0  --------------------------------------------------------------------------------------- -- Product@@ -186,17 +186,14 @@     grouping = FC.contramap (const ()) grouping  -- This causes Data.List.group to act more like Data.Discrimination.group-instance Eq (Product a) where-    _ == _ = True+-- |WARNING! Defined @_ == _ = True@!+instance Eq (Product a) where _ == _ = True -instance Num a => Combine (Product a) where-    combine = (+)+instance Num a => Combine (Product a) where combine = (+) -instance Num a => Semigroup (Product a) where-    x <> y = x * y+instance Num a => Semigroup (Product a) where x <> y = x * y -instance Num a => Monoid (Product a) where-    mempty = 1+instance Num a => Monoid (Product a) where mempty = 1  --------------------------------------------------------------------------------------- -- Misc@@ -204,16 +201,17 @@  -- |Randomly choose from a list by probability. randomProduct :: (Real a, MR.MonadRandom m) => [(a, b)] -> m (a, b)-randomProduct xs = MR.fromList . map (\x -> (x, toRational $ fst x)) $ xs+randomProduct = MR.fromList . fmap (\x -> (x, toRational $ fst x))  -- |Returns a single realization of a Markov chain.-randomPath :: (Markov a b, Real a, MR.RandomGen g) => (a,b) -> g -> [(a,b)]-randomPath x g = map (flip MR.evalRand g) . iterate (>>= (randomProduct . step)) $ pure x+randomPath :: (Markov ((,) a) b, Real a, MR.RandomGen g) => (a,b) -> g -> [(a,b)]+randomPath x g = fmap (`MR.evalRand` g) . iterate (>>= (randomProduct . step)) $ pure x  -- |Create a transition function from a transition matrix.--- If [[a]] is an n x n matrix, length [b] should be n.-fromLists :: Eq  b => [[a]] -> [b] -> b -> [(a, b -> b)]+--+-- prop> all (== length matrix) (map length matrix)+-- prop> length matrix == length states+fromLists :: Eq  b => [[a]] -> [b] -> b -> [(a, c -> b)] fromLists matrix states b = case DL.elemIndex b states of     Nothing -> []-    Just n  -> zip (matrix!!n) toState-    where toState = map const states+    Just n  -> zip (matrix!!n) $ fmap const states
+ src/Markov/Example.hs view
@@ -0,0 +1,417 @@+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE DeriveAnyClass             #-}+{-# LANGUAGE DerivingStrategies         #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase                 #-}+{-# LANGUAGE MultiParamTypeClasses      #-}+{-# LANGUAGE TypeOperators              #-}++{-|+Module      : Markov.Example+Description : Examples of Markov chains implemented using "Markov".+Maintainer  : atloomis@math.arizona.edu+Stability   : experimental++Several examples of Markov chains.+It is probably more helpful to read the source code than the Haddock documentation.+-}+module Markov.Example+     ( FromMatrix (..)+     , Simple (..)+     , Urn (..)+     , Extinction (..)+     , Tidal (..)+     , Room (..)+     , FillBin+     , initial+     , expectedLoss+     ) where++import Markov+import Generics.Deriving (Generic)+import Data.Discrimination (Grouping)++---------------------------------------------------------------+-- From a matrix+---------------------------------------------------------------++-- |An example defined from a matrix.+--+-- >>> chain [pure (FromMatrix 't') :: (Product Double, FromMatrix)] !! 100+-- [ (0.5060975609756099,'a')+-- , (0.201219512195122,'t')+-- , (0.29268292682926833,'l') ]+newtype FromMatrix = FromMatrix Char+    deriving Generic+    deriving newtype (Eq, Show)+    deriving anyclass Grouping++instance Combine FromMatrix where combine = const++instance Markov ((,) (Product Double)) FromMatrix where+    transition = let mat = [ [0.4, 0.3, 0.3]+                           , [0.2, 0.1, 0.7]+                           , [0.9, 0.1, 0.0] ]+                     chars = map FromMatrix ['a','t','l']+                 in fromLists mat chars++---------------------------------------------------------------+-- Simple random walk+---------------------------------------------------------------++-- |A simple random walk.+-- Possible outcomes of the first three steps:+--+-- >>> take 3 $ chain0 [Simple 0]+-- [ [0]+-- , [-1,1]+-- , [-2,0,2] ]+--+-- Probability of each outcome:+--+-- >>> take 3 $ chain [pure 0 :: (Product Double, Simple)]+-- [ [(1.0,0)]+-- , [(0.5,-1),(0.5,1)]+-- , [(0.25,-2),(0.5,0),(0.25,2)] ]+--+-- Number of ways to achieve each outcome:+--+-- >>> take 3 $ chain [pure 0 :: (Product Int, Simple)]+-- [ [(1,0)]+-- , [(1,-1),(1,1)]+-- , [(1,-2),(2,0),(1,2)] ]+--+-- Number of times @pred@ was applied,+-- allowing steps in place (@id@)+-- for more interesting output:+--+-- >>> chain [pure 0 :: (Sum Int, Simple)] !! 2+-- [ (2,-2), (1,-1), (1,0), (0,0), (0,1), (0,2) ]++newtype Simple = Simple Int+    deriving Generic+    deriving newtype (Num, Enum, Eq, Ord, Show)+    deriving anyclass Grouping++instance Combine Simple where combine = const++instance Markov0 Simple where+    transition0 _ = [pred, succ]++instance Markov ((,) (Product Double)) Simple where+    transition _ = [ 0.5 >*< pred+                   , 0.5 >*< succ ]++instance Markov ((,) (Product Int)) Simple where+    transition _ = [ 1 >*< pred+                   , 1 >*< succ ]++instance Markov ((,) (Sum Int)) Simple where+    transition _ = [ 1 >*< pred+                   , 0 >*< id+                   , 0 >*< succ ]++---------------------------------------------------------------+-- Urn model+---------------------------------------------------------------++-- |An urn contains balls of two colors.+-- At each step, a ball is chosen uniformly at random from the urn+-- and a ball of the same color is added.+newtype Urn = Urn (Int,Int)+    deriving Generic+    deriving newtype (Eq, Ord, Show)+    deriving anyclass Grouping++instance Combine Urn where combine = const++instance Markov ((,) (Product Double)) Urn where+    transition x = [ probLeft x >*< addLeft+                   , 1 - probLeft x >*< addRight ]++addLeft :: Urn -> Urn+addLeft  (Urn (a,b)) = Urn (a+1,b)++addRight :: Urn -> Urn+addRight (Urn (a,b)) = Urn (a,b+1)++probLeft :: Fractional a => Urn -> a+probLeft (Urn (a,b)) =  fromIntegral a / fromIntegral (a + b)++---------------------------------------------------------------+-- Tutorial+---------------------------------------------------------------++-- |This is the chain from the README.+newtype Extinction = Extinction Int+    deriving Generic+    deriving newtype (Eq, Num, Show)+    deriving anyclass Grouping++instance Combine Extinction where combine = const++instance Markov ((,) (Sum Int, Product Rational)) Extinction where+    transition = \case+        0 -> [ 0 >*< (q+r) >*< id+             , 0 >*< s >*< (+) 1 ]+        _ -> [ 1 >*< q >*< const 0+             , 0 >*< r >*< id+             , 0 >*< s >*< (+) 1 ]+      where q = 0.1; r = 0.3; s = 0.6++---------------------------------------------------------------+-- More complex random walk+---------------------------------------------------------------++-- |A time inhomogenous random walk that vaguely models tides+-- by periodically switching directions+-- and falling back from a shore at the origin.+data Tidal = Tidal { time     :: Double+                   , position :: Int }+                   deriving (Eq, Ord, Show, Generic)+                   deriving anyclass Grouping++instance Combine Tidal where combine = const++instance Markov ((,) (Product Double)) Tidal where+    transition tw = [ probRight tw >*< stepPos (+1)+                    , 1 - probRight tw >*< stepPos (flip (-) 1) ]++stepPos :: (Int -> Int) -> Tidal -> Tidal+stepPos f tw = Tidal (time tw + 1) (f $ position tw)++probRight :: Tidal -> Product Double+probRight tw = Product $ timeBias * positionBias+  where timeBias = (1 + sin (2 * pi * time tw / stepsPerCycle))/2+        positionBias+            | position tw >= 0 = 1 / steepness+            | otherwise       = 1+        stepsPerCycle = 10+        steepness     = 1.3 -- Double from 1 (flat) to +infty++---------------------------------------------------------------+-- Hidden Markov Model+---------------------------------------------------------------++-- |A hidden Markov model.+--+-- >>> :{ filter (\((_,Merge xs),_) -> xs == "aaa") $ chain+--  [1 >*< Merge "" >*< 1 :: Product Rational :* Merge String :* Room] !! 3+-- :}+-- [ ((3243 % 200000,"aaa"),Room 1)+-- , ((9729 % 500000,"aaa"),Room 2)+-- , ((4501 % 250000,"aaa"),Room 3) ]+--+-- Given that all three tokens recieved were @"a"@,+-- there is a probability of approximately @0.34@+-- that the current room is @Room 3@.+newtype Room = Room Int+    deriving (Generic, Show)+    deriving newtype (Eq, Num)+    deriving anyclass Grouping++instance Combine Room where combine = const++-- Note that changeState is applied before giveToken.+-- In spirit, we have @transition = giveToken . changeState@+instance Markov ((,) (Product Rational, Merge String)) Room where+    sequential = [giveToken, changeState]+      where changeState = \case+                1 -> [ 0.3 >*< mempty >*< const 1+                     , 0.6 >*< mempty >*< const 2+                     , 0.1 >*< mempty >*< const 3 ]+                2 -> [ 1.0 >*< mempty >*< const 3 ]+                3 -> [ 0.3 >*< mempty >*< const 1+                     , 0.6 >*< mempty >*< const 2+                     , 0.1 >*< mempty >*< const 3 ]+                _ -> error "State out of bounds in transition"+            giveToken = \case+                1 -> [ 0.5 >*< Merge "a" >*< const 1+                     , 0.5 >*< Merge "b" >*< const 1 ]+                2 -> [ 0.3 >*< Merge "a" >*< const 2+                     , 0.7 >*< Merge "b" >*< const 2 ]+                3 -> [ 0.4 >*< Merge "a" >*< const 3+                     , 0.4 >*< Merge "b" >*< const 3+                     , 0.2 >*< Merge "c" >*< const 3 ]+                _ -> error "State out of bounds in transition"++---------------------------------------------------------------+-- Yet more complex example+---------------------------------------------------------------++-- |Represents bins with free slots and items.+type Bin   = (Open,Full)+type Index = Int+-- |Represents space between bins where they can expand.+type Gap   = Int+type Full  = Int+type Open  = Int+type Trans = FillBin -> FillBin++-- |A collection of bins with gaps between them.+-- At each step an empty space is chosen+-- form a bin or from a gap.+-- If it is in a bin, the space is filled.+-- If it is in a gap, it is assigned to an adjacent bin,+-- which expands to contain it and any intervening spaces,+-- and then the space filled.+data FillBin = End Gap | Ext Gap Bin FillBin deriving (Eq, Ord, Generic, Grouping)++instance Show FillBin where+    show (Ext g b s) = show g ++ " " ++ show b ++ " " ++ show s+    show (End g) = show g++instance Combine FillBin where combine = const++instance Markov ((,) (Product Double)) FillBin where+    transition x = case probId x of+        0 -> filter (\(Product y,_) -> y /= 0) -- Careful, Product _ == Product _ = True+            $  [probAdd i x >*< addItem i | i <- indices]+            ++ [probGrowL i x >*< addItem i . growLeft  j i+                | i <- indices, j <- [1..gapN (i-1) x]]+            ++ [probGrowR i x >*< addItem i . growRight j i+                | i <- indices, j <- [1..gapN i x]]+        1 -> [pure id]+        _ -> error "Pattern not matched in transition"+        where indices = [1..size x]++-- |>>> fBFromLists [1,3,5,10] [(3,5),(9,9),(8,3)]+-- 1 (3,5) 3 (9,9) 5 (8,3) 10+fBFromLists :: [Gap] -> [Bin] -> FillBin+fBFromLists gaps bins = case (gaps,bins) of+    (g:_  , []  ) -> End g+    ([g]  , _   ) -> End g+    (g:gs , b:bs) -> Ext g b $ fBFromLists gs bs+    ([]   , _   ) -> End 0++-- |Create state where all bins start as (0,0).+--+-- >>> initial [5,7,0]+-- 5 (0,0) 7 (0,0) 0+initial :: [Int] -> FillBin+initial gs = fBFromLists gs $ repeat (0,0)++-- |The number of bins.+size :: FillBin -> Int+size = \case+    End _ -> 0+    Ext _ _ s -> 1 + size s++-- |The bins of a state.+getBins :: FillBin -> [Bin]+getBins = \case+    End _ -> []+    Ext _ b s -> b:getBins s++-- |The open values of a state.+getOpen :: FillBin -> [Open]+getOpen x = map fst $ getBins x++-- |The open value of the Nth bin.+openN :: Index -> FillBin -> Open+openN i x = getOpen x !!(i-1)++-- |The full values of a state.+getFull :: FillBin -> [Full]+getFull x = map snd $ getBins x++-- |The full value of the Nth bin.+fullN :: Index -> FillBin -> Full+fullN i x = getFull x !!(i-1)++-- |The gap values of a state.+getGap :: FillBin -> [Gap]+getGap = \case+    End g -> [g]+    Ext g _ s -> g:getGap s++-- |Warning! Indexed from zero!+gapN :: Index -> FillBin -> Gap+gapN i x = getGap x !! i++-- |The command @iApply i f s@ is analagous to+-- @take i s ++ f (drop i s)@.+iApply :: Trans -> Index -> Trans+iApply f idx x = case (idx,x) of+    (1, y) -> f y+    (i, Ext g b s) -> Ext g b $ iApply f (i-1) s+    _ -> error "Pattern not matched in iApply"++-- |Add an item to the ith bin.+addItem :: Index -> Trans+addItem = iApply h+    where h (Ext g (o,f) s) = Ext g (o-1,f+1) s+          h _ = error "pattern not matched in h in addItem"++-- |Expand the ith bin to the left by j.+-- The Markov chain will use @addItem i . growLeft j i@.+growLeft :: Int -> Index -> Trans+growLeft j = iApply h+    where h (Ext g (o,f) s) = Ext (g-j) (o+j,f) s+          h _ = error "pattern not matched in h in growLeft"++growRight :: Int -> Index -> Trans+growRight j = iApply h+    where h (Ext g (o,f) s) = Ext g (o+j,f) (shrink s)+          h _ = error "pattern not matched in h in growRight"+          shrink = \case+              End g -> End (g-j)+              Ext g b t -> Ext (g-j) b t++-- |The sum of all open slots in bins and gaps.+slots :: FillBin -> Int+slots x = sum $ getGap x ++ getOpen x++-- |The probability that a state returns to itself.+probId :: Num a => FillBin -> a+probId x+    | slots x == 0 = 1+    | otherwise    = 0++divInt :: (Integral a, Integral b, Fractional c) => a -> b -> c+divInt x y = fromIntegral x / fromIntegral y++-- |The probability that the ith bin gains an item.+probAdd :: Fractional a => Index -> FillBin -> a+probAdd i x = openN i x `divInt` slots x++-- |The probability that the ith bin expands to the left.+probGrowL :: Fractional a => Index -> FillBin -> a+probGrowL i x+    | test      = 1 `divInt` slots x+    | otherwise = 0+    where test = i == 1 || fullN i x < fullN (i-1) x++-- |The probability that the ith bin expands to the right.+probGrowR :: Fractional a => Index -> FillBin -> a+probGrowR i x+    | test      = 1 `divInt` slots x+    | otherwise = 0+    where test = i == size x || fullN i x <= fullN (i+1) x++---------------------------------------------------------------+-- Several functions to help study the previous process+---------------------------------------------------------------++-- |The \(l^2\) distance between a finished state+-- and a state with perfectly balanced bins.+individualLoss :: Fractional a => FillBin -> a+individualLoss x = sum . map f . getFull $ x+    where f y = (fromIntegral y - ideal)^2+          ideal = sum (getFull x) `divInt` size x++probLoss :: Fractional a => (Product a, FillBin) -> a+probLoss (Product x, y) = x * individualLoss y++-- |Expected loss of a set of states of @['FillBin']@.+-- Loss is the \(l^2\) distance between a finished state+-- and a state with perfectly balanced bins.+--+-- >>> expectedLoss [pure $ initial [1,0,3] :: (Product Double, FillBin)]+-- 2.0+expectedLoss :: (Fractional a, Markov ((,) (Product a)) FillBin) +    => [Product a :* FillBin] -> a+expectedLoss xs = sum . map probLoss $ chain xs !! idx+    where idx = slots . snd . head $ xs
− src/Markov/Examples.hs
@@ -1,422 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, DeriveGeneric, DeriveAnyClass,-DerivingStrategies, GeneralizedNewtypeDeriving, FlexibleInstances, TypeOperators #-}-{-|-Module      : Examples-Description : Examples of Markov chains implemented using "Markov".-Maintainer  : atloomis@math.arizona.edu-Stability   : experimental--Several examples of Markov chains.-It is probably more helpful to read the source code than the Haddock documentation.--}-module Markov.Examples ( FromMatrix (..)-                       , Simple (..)-                       , Urn (..)-                       , Extinction (..)-                       , Tidal (..)-                       , Room (..)-                       , FillBin-                       , initial-                       , expectedLoss-                       ) where--import Markov-import Generics.Deriving (Generic)-import Data.Discrimination (Grouping)-------------------------------------------------------------------- From a matrix-------------------------------------------------------------------- |An example defined from a matrix.------ >>> chain [pure 't' :: Product Double :* Char] !! 100--- [ (0.5060975609756099,'a')--- , (0.201219512195122,'t')--- , (0.29268292682926833,'l') ]-newtype FromMatrix = FromMatrix Char-    deriving Generic-    deriving newtype (Eq, Show)-    deriving anyclass Grouping--instance Markov (Product Double) FromMatrix where-    transition = let mat = [ [0.4, 0.3, 0.3]-                           , [0.2, 0.1, 0.7]-                           , [0.9, 0.1, 0.0] ]-                     chars = map FromMatrix ['a','t','l']-                 in fromLists mat chars-    ------------------------------------------------------------------- Simple random walk-------------------------------------------------------------------- |A simple random walk.--- Possible outcomes of the first three steps:------ >>> take 3 $ chain0 [Simple 0]--- [ [0]--- , [-1,1]--- , [-2,0,2]]------ Probability of each outcome:------ >>> take 3 $ chain [pure 0 :: Product Double :* Simple]--- [ [(1.0,0)]--- , [(0.5,-1),(0.5,1)]--- , [(0.25,-2),(0.5,0),(0.25,2)] ]------ Number of ways to achieve each outcome:------ >>> take 3 $ chain [pure 0 :: Product Int :* Simple]--- [ [(1,0)]--- , [(1,-1),(1,1)]--- , [(1,-2),(2,0),(1,2)] ]------ Number of times @pred@ was applied,--- allowing steps in place (@id@)--- for more interesting output:------ >>> chain [pure 0 :: Sum Int :* Simple] !! 2--- [ (2,-2)--- , (1,-1)--- , (1,0)--- , (0,0)--- , (0,1)--- , (0,2) ]--newtype Simple = Simple Int-    deriving Generic-    deriving newtype (Num, Enum, Eq, Ord, Show)-    deriving anyclass Grouping--instance Markov0 Simple where-    transition0 _ = [pred, succ]--instance Markov (Product Double) Simple where-    transition _ = [ 0.5 >*< pred-                   , 0.5 >*< succ ]--instance Markov (Product Int) Simple where-    transition _ = [ 1 >*< pred-                   , 1 >*< succ ]--instance Markov (Sum Int) Simple where-    transition _ = [ 1 >*< pred-                   , 0 >*< id-                   , 0 >*< succ ]-              -- = [ 1 >*< pred-              --   , pure id-              --   , pure succ ]-------------------------------------------------------------------- Urn model-------------------------------------------------------------------- |An urn contains balls of two colors.--- At each step, a ball is chosen uniformly at random from the urn--- and a ball of the same color is added.-newtype Urn = Urn (Int,Int)-    deriving Generic-    deriving newtype (Eq, Ord, Show)-    deriving anyclass Grouping--instance Markov (Product Double) Urn where-    transition x = [ probLeft x >*< addLeft-                   , 1 - probLeft x >*< addRight ]--addLeft :: Urn -> Urn-addLeft  (Urn (a,b)) = Urn (a+1,b)--addRight :: Urn -> Urn-addRight (Urn (a,b)) = Urn (a,b+1)--probLeft :: Fractional a => Urn -> a-probLeft (Urn (a,b)) = (fromIntegral a)/(fromIntegral $ a + b)-------------------------------------------------------------------- Tutorial-------------------------------------------------------------------- |This is the chain from the README.-newtype Extinction = Extinction Int-    deriving Generic-    deriving newtype (Eq, Num, Show)-    deriving anyclass Grouping--instance Markov (Sum Int, Product Rational) Extinction where-    transition x = case x of-        0 -> [ 0 >*< (q+r) >*< id-             , 0 >*< s >*< (+1) ]-        _ -> [ 1 >*< q >*< const 0-             , 0 >*< r >*< id-             , 0 >*< s >*< (+1) ]-        where q = 0.1; r = 0.3; s = 0.6---- This is equivalent to the definition above.-instance Combine Extinction where-    combine = const--instance Semigroup Extinction where-    (<>) = flip const--instance MultiMarkov (Sum Int :* Product Rational :* Extinction) where-    multiTransition _ = [trans]-        where trans ((_,_),z) = case z of-                  0 -> [ 0 >*< (q+r) >*< 0-                       , 0 >*< s >*< 1 ]-                  x -> [ 1 >*< q >*< 0-                       , 0 >*< r >*< x-                       , 0 >*< s >*< x+1 ]-                  where q = 0.1; r = 0.3; s = 0.6-------------------------------------------------------------------- More complex random walk-------------------------------------------------------------------- |A time inhomogenous random walk that vaguely models tides--- by periodically switching directions--- and falling back from a shore at the origin.-data Tidal = Tidal { time     :: Double-                   , position :: Int }-                   deriving (Eq, Ord, Show, Generic)-                   deriving anyclass Grouping--instance Markov (Product Double) Tidal where-    transition tw = [ probRight tw >*< stepPos (+1)-                    , 1 - (probRight tw) >*< stepPos (flip (-) 1) ]--stepPos :: (Int -> Int) -> Tidal -> Tidal-stepPos f tw = Tidal (time tw + 1) (f $ position tw)--probRight :: Tidal -> Product Double-probRight tw = Product $ timeBias * positionBias-    where timeBias = (1 + sin (2 * pi * (time tw) / stepsPerCycle))/2-          positionBias-              | position tw >= 0 = 1 / steepness-              | otherwise       = 1-          stepsPerCycle = 10-          steepness     = 1.3 -- Double from 1 (flat) to +infty-------------------------------------------------------------------- Hidden Markov Model-------------------------------------------------------------------- |A hidden Markov model.------ >>> filter (\((_,Merge xs),_) -> xs == "aaa") $ multiChain [1 >*< Merge "" >*< 1 :: Product Rational :* Merge String :* Room] !! 3--- [ ((3243 % 200000,"aaa"),Room 1)--- , ((9729 % 500000,"aaa"),Room 2)--- , ((4501 % 250000,"aaa"),Room 3) ]------ Given that all three tokens recieved were @"a"@,--- there is a probability of approximately @0.34@--- that the current room is @Room 3@.-newtype Room = Room Int-    deriving (Generic, Show)-    deriving newtype (Eq, Num)-    deriving anyclass Grouping--instance Semigroup Room where-    (<>) = flip const--instance Combine Room where-    combine = const---- Note that changeState is applied before giveToken.--- In spirit, we have stepj = giveToken . changeState-instance MultiMarkov (Product Rational :* Merge String :* Room) where-    multiTransition _ = [giveToken, changeState]-        where changeState ((_,_),z) = case z of-                  1 -> [ 0.3 >*< mempty >*< 1-                       , 0.6 >*< mempty >*< 2-                       , 0.1 >*< mempty >*< 3 ]-                  2 -> [ 1.0 >*< mempty >*< 3 ]-                  3 -> [ 0.3 >*< mempty >*< 1-                       , 0.6 >*< mempty >*< 2-                       , 0.1 >*< mempty >*< 3 ]-                  _ -> error "State out of bounds in transitionk"-              giveToken ((_,_),z) = case z of-                  1 -> [ 0.5 >*< Merge "a" >*< 1-                       , 0.5 >*< Merge "b" >*< 1 ]-                  2 -> [ 0.3 >*< Merge "a" >*< 2-                       , 0.7 >*< Merge "b" >*< 2 ]-                  3 -> [ 0.4 >*< Merge "a" >*< 3-                       , 0.4 >*< Merge "b" >*< 3-                       , 0.2 >*< Merge "c" >*< 3 ]-                  _ -> error "State out of bounds in transitionk"-------------------------------------------------------------------- Yet more complex example-------------------------------------------------------------------- |Represents bins with free slots and items.-type Bin   = (Open,Full)-type Index = Int--- |Represents space between bins where they can expand.-type Gap   = Int-type Full  = Int-type Open  = Int-type Trans = FillBin -> FillBin---- |A collection of bins with gaps between them.--- At each step an empty space is chosen--- form a bin or from a gap.--- If it is in a bin, the space is filled.--- If it is in a gap, it is assigned to an adjacent bin,--- which expands to contain it and any intervening spaces,--- and then the space filled.-data FillBin = End Gap | Ext Gap Bin FillBin deriving (Eq, Ord, Generic, Grouping)--instance Show FillBin where-    show (Ext g b s) = show g ++ " " ++ show b ++ " " ++ show s-    show (End g) = show g--instance Markov (Product Double) FillBin where-    transition x = case probId x of-        0 -> filter (\(Product y,_) -> y /= 0) -- Careful, Product _ == Product _ = True-            $  [probAdd i x >*< addItem i | i <- indices]-            ++ [probGrowL i x >*< addItem i . growLeft  j i-                | i <- indices, j <- [1..gapN (i-1) x]]-            ++ [probGrowR i x >*< addItem i . growRight j i-                | i <- indices, j <- [1..gapN i x]]-        1 -> [pure id]-        _ -> error "Pattern not matched in transition"-        where indices = [1..size x]---- |>>> fBFromLists [1,3,5,10] [(3,5),(9,9),(8,3)]--- 1 (3,5) 3 (9,9) 5 (8,3) 10-fBFromLists :: [Gap] -> [Bin] -> FillBin-fBFromLists gaps bins = case (gaps,bins) of-    (g:_  , []  ) -> End g-    ([g]  , _   ) -> End g-    (g:gs , b:bs) -> Ext g b $ fBFromLists gs bs-    ([]   , _   ) -> End 0---- |Create state where all bins start as (0,0).------ >>> initial [5,7,0]--- 5 (0,0) 7 (0,0) 0-initial :: [Int] -> FillBin-initial gs = fBFromLists gs $ repeat (0,0)---- |The number of bins.-size :: FillBin -> Int-size x = case x of-    End _ -> 0-    Ext _ _ s -> 1 + size s---- |The bins of a state.-getBins :: FillBin -> [Bin]-getBins x = case x of-    End _ -> []-    Ext _ b s -> b:getBins s---- |The open values of a state.-getOpen :: FillBin -> [Open]-getOpen x = map fst $ getBins x---- |The open value of the Nth bin.-openN :: Index -> FillBin -> Open-openN i x = (getOpen x)!!(i-1)---- |The full values of a state.-getFull :: FillBin -> [Full]-getFull x = map snd $ getBins x---- |The full value of the Nth bin.-fullN :: Index -> FillBin -> Full-fullN i x = (getFull x)!!(i-1)---- |The gap values of a state.-getGap :: FillBin -> [Gap]-getGap x = case x of-    End g -> [g]-    Ext g _ s -> g:getGap s---- |Warning! Indexed from zero!-gapN :: Index -> FillBin -> Gap-gapN i x = (getGap x)!!i---- |The command @iApply i f s@ is analagous to--- @take i s ++ f (drop i s)@.-iApply :: Trans -> Index -> Trans-iApply f idx x = case (idx,x) of-    (1, y) -> f y-    (i, Ext g b s) -> Ext g b $ iApply f (i-1) s-    _ -> error "Pattern not matched in iApply"---- |Add an item to the ith bin.-addItem :: Index -> Trans-addItem = iApply h-    where h (Ext g (o,f) s) = Ext g (o-1,f+1) s-          h _ = error "pattern not matched in h in addItem"---- |Expand the ith bin to the left by j.--- The Markov chain will use @addItem i . growLeft j i@.-growLeft :: Int -> Index -> Trans-growLeft j = iApply h-    where h (Ext g (o,f) s) = Ext (g-j) (o+j,f) s-          h _ = error "pattern not matched in h in growLeft"--growRight :: Int -> Index -> Trans-growRight j = iApply h-    where h (Ext g (o,f) s) = Ext g (o+j,f) (shrink s)-          h _ = error "pattern not matched in h in growRight"-          shrink s = case s of-              End g -> End (g-j)-              Ext g b t -> Ext (g-j) b t---- |The sum of all open slots in bins and gaps.-slots :: FillBin -> Int-slots x = sum $ getGap x ++ getOpen x---- |The probability that a state returns to itself.-probId :: Num a => FillBin -> a-probId x = case slots x == 0 of-    True  -> 1-    False -> 0--divInt :: (Integral a, Integral b, Fractional c) => a -> b -> c-divInt x y = (fromIntegral x)/(fromIntegral y)---- |The probability that the ith bin gains an item.-probAdd :: Fractional a => Index -> FillBin -> a-probAdd i x = openN i x `divInt` slots x---- |The probability that the ith bin expands to the left.-probGrowL :: Fractional a => Index -> FillBin -> a-probGrowL i x = case test of-    True  -> 1 `divInt` slots x-    False -> 0-    where test = i == 1 || fullN i x < fullN (i-1) x---- |The probability that the ith bin expands to the right.-probGrowR :: Fractional a => Index -> FillBin -> a-probGrowR i x = case test of-    True  -> 1 `divInt` slots x-    False -> 0-    where test = i == size x || fullN i x <= fullN (i+1) x-------------------------------------------------------------------- Several functions to help study the previous process-------------------------------------------------------------------- |The \(l^2\) distance between a finished state--- and a state with perfectly balanced bins.-individualLoss :: Fractional a => FillBin -> a-individualLoss x = sum . map f . getFull $ x-    where f y = (fromIntegral y - ideal)^2-          ideal = sum (getFull x) `divInt` size x--probLoss :: Fractional a => (Product a, FillBin) -> a-probLoss (Product x, y) = x * individualLoss y---- |Expected loss of a set of pstates of @['FillBin']@.--- Loss is the \(l^2\) distance between a finished state--- and a state with perfectly balanced bins.------ >>> expectedLoss [pure $ initial [1,0,3] :: Product Double :* FillBin]--- 2.0-expectedLoss :: (Fractional a, Markov (Product a) FillBin) => [Product a :* FillBin] -> a-expectedLoss xs = sum . map probLoss $ (chain xs) !! idx-    where idx = slots . snd . head $ xs
+ src/Markov/Instance.hs view
@@ -0,0 +1,8 @@+module Markov.Instance where++import Data.Discrimination (Grouping, grouping)+import Data.Functor.Contravariant (contramap)+import GHC.Float (castFloatToWord32, castDoubleToWord64)++instance Grouping Float where grouping = contramap castFloatToWord32 grouping+instance Grouping Double where grouping = contramap castDoubleToWord64 grouping
− src/Markov/Instances.hs
@@ -1,9 +0,0 @@-module Markov.Instances where--import Data.Discrimination (Grouping, grouping)-import Data.Functor.Contravariant (contramap)-import Data.Functor.Contravariant.Divisible (conquer)-import GHC.Float (castFloatToWord32, castDoubleToWord64)--instance Grouping Float where grouping = contramap castFloatToWord32 grouping-instance Grouping Double where grouping = contramap castDoubleToWord64 grouping
+ test/Test.hs view
@@ -0,0 +1,57 @@+{-# OPTIONS_GHC -F -pgmF htfpp #-}+{-# LANGUAGE TypeOperators     #-}++import Data.Ratio+import Test.Framework++import Markov+import Markov.Example++main = htfMain htf_thisModulesTests++-- Examples in the documentation.+test_fromMatrix =+    assertEqual+    (chain [pure (FromMatrix 't') :: (Product Double, FromMatrix)] !! 100)+    [ (0.5060975609756099, FromMatrix 'a')+    , (0.201219512195122, FromMatrix 't')+    , (0.29268292682926833, FromMatrix 'l') ]++test_m0Simple =+    assertEqual+    (take 3 $ chain0 [Simple 0])+    [ [0]+    , [-1,1]+    , [-2,0,2] ]++test_pdSimple =+    assertEqual+    (take 3 $ chain [pure 0 :: (Product Double, Simple)])+    [ [(1.0,0)]+    , [(0.5,-1),(0.5,1)]+    , [(0.25,-2),(0.5,0),(0.25,2)] ]++test_piSimple =+    assertEqual+    (take 3 $ chain [pure 0 :: (Product Int, Simple)])+    [ [(1,0)]+    , [(1,-1),(1,1)]+    , [(1,-2),(2,0),(1,2)] ]++test_siSimple =+    assertEqual+    (chain [pure 0 :: (Sum Int, Simple)] !! 2)+    [ (2,-2), (1,-1), (1,0), (0,0), (0,1), (0,2) ]++test_HMM =+    assertEqual+    (filter (\((_,Merge xs),_) -> xs == "aaa") $ chain+    [1 >*< Merge "" >*< 1 :: Product Rational :* Merge String :* Room] !! 3)+    [ ((Product $ 3243 % 200000, Merge "aaa"),Room 1)+    , ((Product $ 9729 % 500000, Merge "aaa"),Room 2)+    , ((Product $ 4501 % 250000, Merge "aaa"),Room 3) ]++test_expLoss =+    assertEqual+    (expectedLoss [pure $ initial [1,0,3] :: (Product Double, FillBin)])+    2