stack new GADTtest
- として、環境を作り、cabal, yamlを修正する。言語拡張とかパッケージとかの要求、それのバージョン指定とか、stack buildでメッセージが出るたびに対応していくだけで、最終的にはコンパイルできるようになる
executable GADT-exe
hs-source-dirs: app
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, GADT
, rvar
, random-fu
, plots
, diagrams-lib
, diagrams-rasterific
default-language: Haskell2010
extra-deps:
- erf-native-1.0.0.1
- polynomial-0.7.3
- plots-0.1.0.2
- diagrams-lib-1.4.1.2
- 次のファイルをMain.hsとして、stackで作った領域のapp/ 以下に置き、stack buildする
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
import Data.Random
import qualified Data.Random as Random
import Plots
import Diagrams.Prelude hiding (scale, (<>), Vector)
import Diagrams.Backend.Rasterific.CmdLine
import qualified Data.Random.Distribution.Bernoulli as Bernoulli
import Data.List
type Prob = Double
data Dist a where
Pure :: a -> Dist a
Bind :: Dist b -> (b -> Dist a) -> Dist a
Primitive :: RVar a -> Dist a
Conditional :: (a -> Prob) -> Dist a -> Dist a
condition :: (a -> Prob) -> Dist a -> Dist a
condition = Conditional
instance Functor Dist where
fmap f d = d >>= (pure . f)
instance Applicative Dist where
pure = Pure
f <*> a = a >>= \x -> fmap ($x) f
instance Monad Dist where
(>>=) = Bind
instance Sampleable Dist IO a where
sampleFrom _ (Pure x) = pure x
sampleFrom s (Bind d f) = do
x <- sampleFrom s d
sampleFrom s (f x)
sampleFrom s (Primitive d) = sampleFrom s d
sampleFrom _ (Conditional _ _) = undefined
bernoulli a = Primitive $ Bernoulli.bernoulli a
prior :: Dist a -> Dist (a, Prob)
prior (Conditional c d) = do
(x,s) <- prior d
return (x, s * c x)
prior (Bind d f) = do
(x,s) <- prior d
y <- f x
return (y,s)
prior d = do
x <- d
return (x,1)
mh :: Int
-> Int
-> Dist a
-> Dist [a]
mh dc tc d = fmap (map fst . drop dc) $ proposal >>= iterate (dc + tc)
where
proposal = prior d
iterate 0 _ = pure []
iterate n (x,s) = do
(y,r) <- proposal
accept <- bernoulli $ min 1 (r / s)
let next = if accept then (y,r) else (x,s)
rest <- iterate (n-1) next
return $ next:rest
normalry a b = Primitive $ Random.normal a b
type Point = (Double, Double)
type Param = (Double, Double)
linear :: Dist Param
linear = do
a <- normalry 0 5
b <- normalry 0 5
return (a,b)
point :: Main.Point -> Dist Param -> Dist Param
point (x,y) = condition (\(a,b) -> Data.Random.pdf (Random.Normal (a*x + b) 1) y)
points :: [Main.Point] -> Dist Param -> Dist Param
points ps d = foldl (flip point) d ps
trainingData :: IO [(Double, Double)]
trainingData =
let points = [-5..5]
equation = \x -> 2 * x + 1
addNoise x = Random.sample $ Random.Normal x 1
in sequence . map (\x -> (,) x <$> addNoise (equation x)) $ points
main :: IO ()
main = do
td <- trainingData
putStrLn "Sampling..."
xs <- Random.sample $ mh 100 100000 (points td linear)
putStrLn "Drawing..."
r2AxisMain $ myaxis $ nub xs
where
myaxis :: [(Double, Double)] -> Axis B V2 Double
myaxis mydata1 = r2Axis &~ do
scatterPlot mydata1 $ key "data 1"
stack exec -- GADTtest-exe -o out.png