HLearn-classification-0.0.1: src/HLearn/Models/DistributionContainer.hs
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module HLearn.Models.DistributionContainer
where
import Debug.Trace
import GHC.Float (double2Float, float2Double)
import Numeric.SpecFunctions (logFactorial)
import Test.QuickCheck hiding (classify)
import qualified Data.Foldable as F
import qualified Data.Map as Map
import Prelude hiding (log)
import HLearn.Algebra
import HLearn.DataContainers
import HLearn.Models.Classification
import HLearn.Models.Distributions
-------------------------------------------------------------------------------
data MaybeDistributionParams baseparams = MaybeDistributionParams baseparams
instance (Model baseparams basedist) => Model (MaybeDistributionParams baseparams) (MaybeDistribution basedist) where
getparams (MaybeDistribution basedist) = MaybeDistributionParams $ getparams basedist
instance (DefaultModel baseparams basedist) => DefaultModel (MaybeDistributionParams baseparams) (MaybeDistribution basedist) where
defparams = MaybeDistributionParams $ defparams
newtype MaybeDistribution basedist = MaybeDistribution basedist
deriving (Eq,Show,Read,Semigroup)
instance (Monoid basedist) => Monoid (MaybeDistribution basedist)
where
mempty = MaybeDistribution mempty
mappend (MaybeDistribution d1) (MaybeDistribution d2) = MaybeDistribution $ d1 `mappend` d2
instance
( DefaultHomTrainer baseparams datatype basedist
, Monoid basedist
) => HomTrainer (MaybeDistributionParams baseparams) (Maybe datatype) (MaybeDistribution basedist)
where
train1dp' (MaybeDistributionParams baseparams) Nothing = MaybeDistribution mempty
train1dp' (MaybeDistributionParams baseparams) (Just x) = MaybeDistribution $ train1dp x
-- instance (DistributionEstimator basedist datatype) => DistributionEstimator (MaybeDistribution basedist) (Maybe datatype) where
-- add1sample (MaybeDistribution basedist) dp = case dp of
-- Nothing -> MaybeDistribution $ basedist
-- Just x -> MaybeDistribution $ add1sample basedist x
instance
( Distribution basedist sampletype Double
) => Distribution (MaybeDistribution basedist) (Maybe sampletype) Double
where
pdf (MaybeDistribution basedist) dp = case dp of
Nothing -> 1
Just x -> pdf basedist x
cdf (MaybeDistribution basedist) dp = case dp of
Nothing -> 0
Just x -> cdf basedist x
cdfInverse (MaybeDistribution basedist) prob = Just $ cdfInverse basedist prob
-- drawSample (MaybeDistribution basedist) = do
-- sample <- drawSample basedist
-- return $ Just sample
---------------------------------------
newtype ContinuousDistribution basedist = ContinuousDistribution (MaybeDistribution basedist)
deriving (Eq,Show,Read,Semigroup)
data ContinuousDistributionParams baseparams = ContinuousDistributionParams
instance Model (ContinuousDistributionParams baseparams) (ContinuousDistribution basedist) where
getparams _ = ContinuousDistributionParams
instance DefaultModel (ContinuousDistributionParams baseparams) (ContinuousDistribution basedist) where
defparams = ContinuousDistributionParams
instance
( DefaultHomTrainer (MaybeDistributionParams baseparams) (Maybe Double) (MaybeDistribution basedist)
, Monoid basedist
, Semigroup basedist
) =>
HomTrainer (ContinuousDistributionParams baseparams) DataItem (ContinuousDistribution basedist)
where
train1dp' ContinuousDistributionParams dp = case dp of
Missing -> ContinuousDistribution $ train1dp (Nothing :: Maybe Double)
Continuous x -> ContinuousDistribution $ train1dp $ Just x
Discrete x -> error "ContinuousDistribution.add1sample: cannot add discrete"
instance
( Distribution (MaybeDistribution basedist) (Maybe Double) Double
, Monoid basedist
) =>
Distribution (ContinuousDistribution basedist) DataItem Double
where
pdf (ContinuousDistribution basedist) dp = case dp of
Missing -> pdf basedist (Nothing :: Maybe Double)
Continuous x -> pdf basedist $ Just x
Discrete x -> error "ContinuousDistribution.pdf: cannot sample discrete"
cdf = error "ContinuousDistribution.cdf: not implemented"
-- cdfInverse = error "ContinuousDistribution.cdfInverse: not implemented"
cdfInverse (ContinuousDistribution maybedist) prob = case cdfInverse maybedist prob of
Nothing -> Missing
Just x -> Continuous x
-- cdfInverse (ContinuousDistribution maybedist) (Discrete x) = error "ContinuousDistribution.cdfInverse: cannot discrete"
-- cdfInverse (ContinuousDistribution maybedist) (Continuous x) = cdfInverse maybedist $ Just x
-- drawSample (ContinuousDistribution basedist) = do
-- sample <- drawSample basedist
-- return $ case sample of
-- Nothing -> Missing
-- Just x -> Continuous x
instance (NFData basedist) => NFData (ContinuousDistribution basedist) where
rnf (ContinuousDistribution (MaybeDistribution basedist)) = rnf basedist
instance (RegularSemigroup basedist) => RegularSemigroup (ContinuousDistribution basedist) where
inverse (ContinuousDistribution (MaybeDistribution basedist)) = ContinuousDistribution $ MaybeDistribution $ inverse basedist
instance (Monoid basedist) => Monoid (ContinuousDistribution basedist) where
mempty = ContinuousDistribution $ MaybeDistribution mempty
mappend (ContinuousDistribution (MaybeDistribution basedist1)) (ContinuousDistribution (MaybeDistribution basedist2)) =
ContinuousDistribution $ MaybeDistribution $ mappend basedist1 basedist2
-------------------------------------------------------------------------------
-- DistContainer
data DistContainer = UnknownDist
| DistContainer (ContinuousDistribution (Gaussian Double))
| DistDiscrete (Categorical DataItem Double)
-- | DistContainer Poisson
deriving (Show{-,Read,Eq-})
data DistContainerParams = DistContainerParams
instance Semigroup DistContainer where
(<>) = mappend
instance Monoid DistContainer where
mempty = UnknownDist
mappend UnknownDist b = b
mappend a UnknownDist = a
mappend (DistContainer a) (DistContainer b) = DistContainer $ mappend a b
mappend (DistDiscrete a) (DistDiscrete b) = DistDiscrete $ mappend a b -- error "DistContiner.mappend (DistDiscrete) not yet implemented"
instance RegularSemigroup DistContainer where
inverse UnknownDist = UnknownDist
inverse (DistContainer x) = DistContainer $ inverse x
inverse (DistDiscrete x) = DistDiscrete $ inverse x
instance Model DistContainerParams DistContainer where
getparams _ = DistContainerParams
instance DefaultModel DistContainerParams DistContainer where
defparams = DistContainerParams
instance HomTrainer DistContainerParams DataItem DistContainer where
-- train1dp' DistContainerParams (Gaussian x) =
train1dp' DistContainerParams Missing = trace "Distribution.add1sample: Warning, cannot determine which type of distribution to select." UnknownDist
train1dp' DistContainerParams di@(Discrete x) = DistDiscrete $ train1dp di
train1dp' DistContainerParams di@(Continuous x) = DistContainer $ train1dp di
-- instance DistributionEstimator DistContainer DataItem where
-- {-# INLINE add1sample #-}
-- add1sample UnknownDist di =
-- case di of
-- Missing -> trace "Distribution.add1sample: Warning, cannot determine which type of distribution to select." UnknownDist
-- Discrete x -> DistDiscrete $ add1sample (mempty::Categorical DataItem) di
-- Continuous x -> DistContainer $ add1sample (mempty{-:: ContinuousDistribution (Gaussian Double)-}) di
-- add1sample (DistContainer dist) di = DistContainer $ add1sample dist di
-- add1sample (DistDiscrete dist) di = DistDiscrete $ add1sample dist di
instance Distribution DistContainer DataItem Double where
{-# INLINE pdf #-}
pdf UnknownDist _ = trace "Distribution.pdf: Warning sampling from an UnkownDist" 0.3
pdf (DistContainer dist) di = pdf dist di
pdf (DistDiscrete dist) di = pdf dist di
cdf (DistContainer dist) = cdf dist
cdf (DistDiscrete dist) = cdf dist
cdfInverse (DistContainer dist) = cdfInverse dist
cdfInverse (DistDiscrete dist) = cdfInverse dist
{- drawSample (DistContainer dist) = drawSample dist
drawSample (DistDiscrete dist) = drawSample dist
drawSample (UnknownDist) = return Missing-}
-- serializationIndex dist = 0
{-instance Binary DistContainer where
put (UnknownDist) = put (0::Word8)
put (DistContainer dist) = put (serializationIndex dist) >> put dist
get = do
tag <- getWord8
case tag of
0 -> return UnknownDist
1 -> liftM DistContainer get
2 -> liftM DistContainer get-}
instance NFData DistContainer where
rnf (UnknownDist) = ()
rnf (DistContainer dist) = rnf dist
rnf (DistDiscrete dist) = rnf dist
-------------------------------------------------------------------------------
-- DiscretePDF
-- data DiscretePDF = DiscretePDF
-- { pdf :: Map.Map (Maybe String) Int
-- }
-- deriving (Show,Read,Eq)
--
-- instance Distribution DiscretePDF DataItem where
--
-- -- serializationIndex d = 0
--
-- {-# INLINE add1sample #-}
-- add1sample d Missing = DiscretePDF $ Map.insertWith (+) (Nothing) 1 (pdf d)
-- add1sample d (Discrete x) = DiscretePDF $ Map.insertWith (+) (Just x) 1 (pdf d) -- error "add1sample: cannot add discrete DataItem to (Gaussian Double)"
-- add1sample d (Continuous x) = error "add1sample: cannot add continuous DataItem to DiscretePDF"
--
-- {-# INLINE pdf #-}
-- pdf d Missing = getProb Nothing $ pdf d
-- pdf d (Discrete x) = getProb (Just x) $ pdf d--error "pdf: cannot sample a discrete DataItem from a (Gaussian Double)"
-- pdf d (Continuous x) = error "pdf: cannot sample a continuous DataItem from a DiscretePDF"
--
-- getProb :: (Maybe String) -> Map.Map (Maybe String) Int -> Probability
-- getProb key pdf = logFloat $ 0.0001+((fi val)/(fi tot)::Double)
-- where
-- val = case Map.lookup key pdf of
-- Nothing -> 0
-- Just x -> x
-- tot = F.foldl' (+) 0 pdf
--
-- instance Semigroup DiscretePDF where
-- (<>) d1 d2 = DiscretePDF $ Map.unionWith (+) (pdf d1) (pdf d2)
--
-- instance Monoid DiscretePDF where
-- mempty = DiscretePDF mempty
-- mappend = (<>)
--
-- instance NFData DiscretePDF where
-- rnf d = rnf $ pdf d