module Numeric.Probability.Example.TreeGrowth where import qualified Numeric.Probability.Distribution as Dist import qualified Numeric.Probability.Transition as Trans import qualified Numeric.Probability.Random as Rnd import qualified Numeric.Probability.Trace as Trace import Numeric.Probability.Simulation ((~..), (~*.), ) import Numeric.Probability.Percentage (Dist, Trans, RTrans, Expand, RExpand, Space, ) import Numeric.Probability.Visualize ( Vis, Color(Green, Red, Blue), Plot, fig, figP, figure, title, xLabel, yLabel, plotD, color, label, ) import qualified Numeric.Probability.Monad as MonadExt type Height = Int data Tree = Alive Height | Hit Height | Fallen deriving (Ord,Eq,Show) grow :: Trans Tree grow (Alive h) = Dist.normal (map Alive [h+1..h+5]) grow _ = error "TreeGrowth.grow: only alive trees can grow" hit :: Trans Tree hit (Alive h) = Dist.certainly (Hit h) hit _ = error "TreeGrowth.hit: only alive trees can be hit" fall :: Trans Tree fall _ = Dist.certainly Fallen evolve :: Trans Tree evolve t = case t of (Alive _) -> Trans.unfold (Dist.enum [90,4,6] [grow,hit,fall]) t -- (Alive _) -> Trans.unfold (Dist.relative [0.9,0.04,0.06] [grow,hit,fall]) t _ -> Dist.certainly t {- | tree growth simulation: start with seed and run for n generations -} seed :: Tree seed = Alive 0 -- * exact results -- | @tree n@ : tree distribution after n generations tree :: Int -> Tree -> Dist Tree tree n = MonadExt.iterate n evolve -- | @hist n@ : history of tree distributions for n generations hist :: Int -> Expand Tree hist n = Trace.walk n (evolve =<<) . return -- * simulation results {- | Since '(*.)' is overloaded for Trans and RChange, we can run the simulation ~. directly to @n *. live@. -} --simTree k n = k ~. tree n simTree :: Int -> Int -> RTrans Tree simTree k n = (k,n) ~*. evolve simHist :: Int -> Int -> RExpand Tree simHist k n = (k,n) ~.. evolve t2 :: Dist Tree t2 = tree 2 seed h2 :: Space Tree h2 = hist 2 seed sh2, st2 :: IO () st2 = Rnd.print $ simTree 2000 2 seed sh2 = Rnd.print $ simHist 2000 2 seed -- Alternatives: -- -- simTree k n = k ~. n *. random evolve -- simTree k n = (k,n) ~*. evolve -- take a trace height :: Tree -> Int height Fallen = 0 height (Hit h) = h height (Alive h) = h {-- myPlot = plotD ((5 *. evolve) (Alive 0) >>= height) myPlot2 = figP figure{title="Tree Growth",xLabel="Height (m)", yLabel="Probability"} (autoColor [ plotD ((5 *. evolve) (Alive 0) >>= height) ]) --} p1, p2, p3, p4, p5, p6 :: Vis p1 = fig [plotD $ Dist.normal ([1..20]::[Int])] p2 = fig [plotD $ Dist.map height (tree 5 seed)] p3 = figP figure{title="Tree Growth", xLabel="Height (ft)", yLabel="Probability"} [plotD $ Dist.map height (tree 5 seed)] p4 = figP figure{title="Tree Growth", xLabel="Height (ft)", yLabel="Probability"} [heightAtTime 5, heightAtTime 10,heightAtTime 15] heightAtTime :: Int -> Plot heightAtTime y = plotD $ Dist.map height (tree y seed) p5 = figP figure{title="Tree Growth", xLabel="Height (ft)", yLabel="Probability"} (map heightAtTime [3,5,7]) heightCurve :: (Int,Color) -> Plot heightCurve (n,c) = (heightAtTime n){color=c,label=show n++" Years"} p6 = figP figure{title="Tree Growth", xLabel="Height (ft)", yLabel="Probability"} (map heightCurve [(3,Blue),(5,Green),(7,Red)]) done :: Tree -> Bool done (Alive x) = x >= 5 done _ = True ev5 :: Tree -> Dist Tree ev5 = MonadExt.while (not . done) evolve