    {-# LANGUAGE DeriveDataTypeable, OverloadedStrings, RecordWildCards #-}
    -- |
    -- Module      : Criterion.Analysis.Types
    -- Copyright   : (c) 2011 Bryan O'Sullivan
    --
    -- License     : BSD-style
    -- Maintainer  : bos@serpentine.com
    -- Stability   : experimental
    -- Portability : GHC
    --
    -- Analysis types.

    module Criterion.Analysis.Types
        (
          Outliers (..)
        , OutlierEffect(..)
        , OutlierVariance(..)
        , SampleAnalysis(..)
        ) where

    import Control.DeepSeq (NFData(rnf))
    import Data.Data (Data)
    import Data.Int (Int64)
    import Data.Monoid (Monoid(..))
    import Data.Typeable (Typeable)
    import qualified Statistics.Resampling.Bootstrap as B

    -- | Outliers from sample data, calculated using the boxplot
    -- technique.
    data Outliers = Outliers {
          samplesSeen :: {-# UNPACK #-} !Int64
        , lowSevere   :: {-# UNPACK #-} !Int64
        -- ^ More than 3 times the interquartile range (IQR) below the
        -- first quartile.
        , lowMild     :: {-# UNPACK #-} !Int64
        -- ^ Between 1.5 and 3 times the IQR below the first quartile.
        , highMild    :: {-# UNPACK #-} !Int64
        -- ^ Between 1.5 and 3 times the IQR above the third quartile.
        , highSevere  :: {-# UNPACK #-} !Int64
        -- ^ More than 3 times the IQR above the third quartile.
        } deriving (Eq, Read, Show, Typeable, Data)

    instance NFData Outliers

    -- | A description of the extent to which outliers in the sample data
    -- affect the sample mean and standard deviation.
    data OutlierEffect = Unaffected -- ^ Less than 1% effect.
                       | Slight     -- ^ Between 1% and 10%.
                       | Moderate   -- ^ Between 10% and 50%.
                       | Severe     -- ^ Above 50% (i.e. measurements
                                    -- are useless).
                         deriving (Eq, Ord, Read, Show, Typeable, Data)

    instance NFData OutlierEffect

    instance Monoid Outliers where
        mempty  = Outliers 0 0 0 0 0
        mappend = addOutliers

    addOutliers :: Outliers -> Outliers -> Outliers
    addOutliers (Outliers s a b c d) (Outliers t w x y z) =
        Outliers (s+t) (a+w) (b+x) (c+y) (d+z)
    {-# INLINE addOutliers #-}

    -- | Analysis of the extent to which outliers in a sample affect its
    -- standard deviation (and to some extent, its mean).
    data OutlierVariance = OutlierVariance {
          ovEffect   :: OutlierEffect
        -- ^ Qualitative description of effect.
        , ovDesc     :: String
        -- ^ Brief textual description of effect.
        , ovFraction :: Double
        -- ^ Quantitative description of effect (a fraction between 0 and 1).
        } deriving (Eq, Read, Show, Typeable, Data)

    instance NFData OutlierVariance where
        rnf OutlierVariance{..} = rnf ovEffect `seq` rnf ovDesc `seq` rnf ovFraction

    -- | Result of a bootstrap analysis of a non-parametric sample.
    data SampleAnalysis = SampleAnalysis {
          anMean :: B.Estimate
        , anStdDev :: B.Estimate
        , anOutlierVar :: OutlierVariance
        } deriving (Eq, Show, Typeable, Data)

    instance NFData SampleAnalysis where
        rnf SampleAnalysis{..} =
            rnf anMean `seq` rnf anStdDev `seq` rnf anOutlierVar