content: {-# LANGUAGE BangPatterns           #-}
  {-# LANGUAGE FunctionalDependencies #-}
  {-# LANGUAGE MultiParamTypeClasses  #-}
  module QuantLib.Methods.MonteCarlo
          ( module QuantLib.Methods.MonteCarlo
          ) where
  
  import           Control.Monad               ()
  import           Control.Parallel.Strategies
  import           QuantLib.Stochastic.Process
  import           QuantLib.Stochastic.Random
  
  -- | Summary type class aggregates all priced values of paths
  class PathPricer p => Summary m p | m->p where
          -- | Updates summary with given priced pathes
          sSummarize      :: m -> [p] -> m
          -- | Defines a metric, i.e. calculate distance between 2 summaries
          sNorm           :: m -> m -> Double
  
  -- | Path generator is a stochastic path generator
  class PathGenerator m where
          pgMkNew         :: m->IO m
          pgGenerate      :: Integer -> m->Path
  
  -- | Path pricer provides a price for given path
  class PathPricer m where
          ppPrice         :: m -> Path -> m
  
  
  -- | Monte Carlo engine function
  monteCarlo :: (Summary s p, PathGenerator g) => PathMonteCarlo s p g->Int->s
  monteCarlo (PathMonteCarlo s p g) size = sSummarize s priced
    where
          !priced = map pricing [1..size]
          pricing seed = ppPrice p (pgGenerate (fromIntegral seed) g)
  
  -- | Monte Carlo engine function. Parallelized version
  monteCarloParallel :: (Summary s p, PathGenerator g) => PathMonteCarlo s p g->Int->s
  monteCarloParallel (PathMonteCarlo s p g) size = sSummarize s priced
    where
          !priced = map pricing [1..size] `using` rpar
          pricing seed = ppPrice p (pgGenerate (fromIntegral seed) g)
  
  -- | Path-dependant Monte Carlo engine
  data PathMonteCarlo s p g =
          PathMonteCarlo {
                  pmcSummary   :: s,
                  pmcPricer    :: p,
                  pmcGenerator :: g
          }
  
  -- | Stochastic process generator
  data ProcessGenerator sp b d =
          ProcessGenerator {
                  pgStart      :: Dot,
                  pgLength     :: Int,
                  pgProcess    :: sp,
                  pgGenerator  :: b,
                  pgDiscretize :: d
          }
  
  instance (StochasticProcess sp, NormalGenerator b, Discretize d) => PathGenerator (ProcessGenerator sp b d) where
          pgMkNew (ProcessGenerator start len process rnd d)       = do
                  newRnd <- ngMkNew rnd
                  return $! ProcessGenerator start len process newRnd d
          pgGenerate seed (ProcessGenerator start len sp b d) = generatePath newB d sp len start
            where (_, newB) = ngSplitWithSeed seed b
  