module Math.HiddenMarkovModel.Example.Circle
where
import qualified Math.HiddenMarkovModel as HMM
import qualified Math.HiddenMarkovModel.Distribution as Distr
import qualified Data.Packed.Matrix as Matrix
import qualified Data.Packed.Vector as Vector
import Data.Packed.Vector (Vector)
import qualified System.Random as Rnd
import qualified Control.Monad.Trans.State as MS
import Control.Monad (liftM2, replicateM)
import qualified Data.NonEmpty.Class as NonEmptyC
import qualified Data.NonEmpty as NonEmpty
import Data.Function.HT (nest)
import Data.NonEmpty ((!:))
hmm :: HMM.Gaussian Double
hmm =
HMM.Cons {
HMM.initial = Vector.fromList [1/4, 1/4, 1/4, 1/4],
HMM.transition =
Matrix.fromLists $
[0.9, 0.0, 0.0, 0.1] :
[0.1, 0.9, 0.0, 0.0] :
[0.0, 0.1, 0.9, 0.0] :
[0.0, 0.0, 0.1, 0.9] :
[],
HMM.distribution =
let cov0 = Matrix.fromLists [[0.10, 0.09],[0.09, 0.10]]
cov1 = Matrix.fromLists [[0.10, 0.09],[ 0.09, 0.10]]
in Distr.gaussian $
(Vector.fromList [ 0.5, 0.5], cov0) :
(Vector.fromList [0.5, 0.5], cov1) :
(Vector.fromList [0.5, 0.5], cov0) :
(Vector.fromList [ 0.5, 0.5], cov1) :
[]
}
circleLabeled :: NonEmpty.T [] (HMM.State, Vector Double)
circleLabeled =
NonEmpty.mapTail (take 200) $
fmap
(\x ->
(HMM.state $ mod (floor (x*2/pi)) 4,
Vector.fromList [cos x, sin x])) $
NonEmptyC.iterate (0.1+) 0
circle :: NonEmpty.T [] (Vector Double)
circle = fmap snd circleLabeled
revealed :: NonEmpty.T [] HMM.State
revealed = HMM.reveal hmm circle
reconstructDistribution :: HMM.Gaussian Double
reconstructDistribution =
let s0 = HMM.state 0
gen = Distr.generate (HMM.distribution hmm) s0
in HMM.finishTraining $ HMM.trainSupervised 1 $ fmap ((,) s0) $
flip MS.evalState (Rnd.mkStdGen 23) $
liftM2 (!:) gen $ replicateM 1000 gen
hmmTrainedSupervised :: HMM.Gaussian Double
hmmTrainedSupervised =
HMM.finishTraining $ HMM.trainSupervised 4 circleLabeled
hmmTrainedUnsupervised :: HMM.Gaussian Double
hmmTrainedUnsupervised =
HMM.finishTraining $ HMM.trainUnsupervised hmm circle
hmmIterativelyTrained :: HMM.Gaussian Double
hmmIterativelyTrained =
nest 100
(HMM.finishTraining . flip HMM.trainUnsupervised circle)
hmm