packages feed

haskseg-0.1.0.0: src/Text/HaskSeg/Probability.hs

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Text.HaskSeg.Probability (Prob, LogProb, showDist, Probability(..), sampleCategorical, Categorical) where

import Data.List (unfoldr, nub, mapAccumL, intercalate, sort)
import Data.Vector (Vector)
import qualified Data.Vector as Vector
import Control.Monad.Random
import Text.Printf (printf, PrintfArg(..), fmtPrecision, fmtChar, errorBadFormat, formatString, vFmt, IsChar)

newtype Prob = Prob Double deriving (Show, Read, Eq, Ord, Num)
type Dist = Vector Prob
newtype LogProb = LogProb Double deriving (Show, Read, Eq, Ord)
type LogDist = Vector LogProb

showDist :: (Probability p, Show p) => Vector p -> String
showDist ps = intercalate ", " $ (map (\v -> printf "%.8f" v :: String) . map (/ total)) ps'
  where
    ps' = map toDouble (Vector.toList ps)
    total = sum ps'

instance Num LogProb where
  (LogProb a) + (LogProb b) = LogProb (l + (logBase 2 v))
    where
      (l, s) = if a > b then (a, b) else (b, a)
      d = s - l
      v = 1 + (2 ** d)
  (LogProb a) * (LogProb b) = LogProb (a + b)
  negate = undefined
  abs = undefined
  signum = undefined
  fromInteger i = fromDouble (fromIntegral i)

instance Fractional Prob where
  recip (Prob a) = Prob (1.0 / a)
  fromRational a = undefined
  
instance Fractional LogProb where  
  recip (LogProb a) = LogProb (-a)
  fromRational a = undefined
  
class (Ord p, Num p, Fractional p) => Probability p where
  fromDouble :: Double -> p
  toDouble :: p -> Double
  unwrap :: p -> Double
  
class (Probability p) => Categorical p where
  sampleCategorical :: (MonadRandom m) => Vector p -> m Int
  sampleCategorical xps = do
    let sums = Vector.scanl (+) (fromDouble 0.0 :: p) xps
        maxP = toDouble $ Vector.last sums
    v <- getRandomR (0.0, maxP)
    let v' = fromDouble v :: p
    return (Vector.length (Vector.takeWhile (\x -> x < v') sums) - 1)

instance Probability LogProb where
  fromDouble p = LogProb (logBase 2 p)
  toDouble (LogProb lp) = 2 ** lp
  unwrap (LogProb lp) = lp
  
instance Probability Prob where
  fromDouble p = Prob p
  toDouble (Prob p) = p
  unwrap (Prob p) = p

instance Categorical LogProb
instance Categorical Prob