module GramLab.Morfette.Evaluation ( accuracy
                                   , tokenAccuracy
                                   , sentenceAccuracy
                                   , showAccuracy
                                   )
where
import GramLab.Morfette.Token
import Data.Maybe
import GramLab.Utils (lowercase)
import Text.Printf
import GramLab.Binomial


data Accuracy = Acc { lemmaAcc :: AccBL
                    , posAcc   :: AccBL 
                    , jointAcc :: AccBL }

data AccBL = AccBL { test :: [Bool]
                   , baseline :: Maybe [Bool] }

data Experiment = Ex { trials :: Integer
                     , successes :: Integer } deriving (Show)


rer hi lo = ((1-lo)-(1-hi))/(1-lo)

significance :: [Bool] -> [Bool] -> Experiment
significance test baseline = Ex { trials = fromIntegral $ countTrue $ zipWith (/=) test baseline
                                , successes = fromIntegral $ countTrue $ zipWith (>) test baseline  }
countTrue = sum . map fromEnum
pvalue ex = binomialTest (trials ex) (successes ex)



tokenAccuracy :: [Token] -> [Token] -> Maybe [Token] -> Accuracy
tokenAccuracy xs ys bl = accuracy (id,id,id) (map tokToPair xs) 
                                             (map tokToPair ys) 
                                             (fmap (map tokToPair) bl)

sentenceAccuracy :: [[Token]] -> [[Token]] -> Maybe [[Token]] -> Accuracy
sentenceAccuracy xs ys bl = accuracy (map,map,map) (map (map tokToPair) xs) 
                                                   (map (map tokToPair) ys) 
                                                   (fmap (map (map tokToPair)) bl)

tokToPair :: Token -> (String, Maybe String)
tokToPair t = (lowercase $ fromMaybe (tokenForm t) (tokenLemma t), tokenPOS t)


accuracy (g,h,i) gold test mbl = Acc { lemmaAcc = AccBL (correct (g fst) test) (fmap (correct (g fst)) mbl)
                                     , posAcc   = AccBL (correct (h snd) test) (fmap (correct (h snd)) mbl)
                                     , jointAcc = AccBL (correct (i id)  test) (fmap (correct (i id)) mbl) }
    where correct f ys = zipWith (\x y -> f x == f y) gold ys





showAccuracy acc = unlines [ "Lemma acc: " ++ (showAcc . lemmaAcc) acc
                           , "POS   acc: " ++ (showAcc . posAcc  ) acc 
                           , "Joint acc: " ++ (showAcc . jointAcc) acc ]


showAcc (AccBL t mbl) = case mbl of
                            Just bl -> let acc_bl  = (length bl, countTrue bl)
                                           acc_bl_pc = (fromIntegral (snd acc_bl)/(fromIntegral (fst acc_bl)))::Double
                                           ex = significance t bl
                                       in printf "%05.2f%% (%d / %d) %+.2f%%, %.2f%% RER, %d different, %d better, p-value: %g"
                                          (acc_t_pc * 100)
                                          (snd acc_t) 
                                          (fst acc_t) 
                                          (acc_t_pc * 100  - acc_bl_pc * 100)
                                          (rer acc_t_pc acc_bl_pc * 100)
                                          (trials ex)
                                          (successes ex)
                                          (pvalue ex)            
                            Nothing -> printf "%.2f%% (%d / %d)" (100*acc_t_pc) (snd acc_t) (fst acc_t) 
    where acc_t   = (length t, countTrue t)
          acc_t_pc = (fromIntegral (snd acc_t)/(fromIntegral (fst acc_t)))



module GramLab.Morfette.Evaluation ( accuracy
                                   , tokenAccuracy
                                   , sentenceAccuracy
                                   , showAccuracy
                                   )
where
import GramLab.Morfette.Token
import Data.Maybe
import GramLab.Utils (lowercase)
import Text.Printf
import GramLab.Binomial


data Accuracy = Acc { lemmaAcc :: AccBL
                    , posAcc   :: AccBL 
                    , jointAcc :: AccBL }

data AccBL = AccBL { test :: [Bool]
                   , baseline :: Maybe [Bool] }

data Experiment = Ex { trials :: Integer
                     , successes :: Integer } deriving (Show)


rer hi lo = ((1-lo)-(1-hi))/(1-lo)

significance :: [Bool] -> [Bool] -> Experiment
significance test baseline = Ex { trials = fromIntegral $ countTrue $ zipWith (/=) test baseline
                                , successes = fromIntegral $ countTrue $ zipWith (>) test baseline  }
countTrue = sum . map fromEnum
pvalue ex = binomialTest (trials ex) (successes ex)



tokenAccuracy :: [Token] -> [Token] -> Maybe [Token] -> Accuracy
tokenAccuracy xs ys bl = accuracy (id,id,id) (map tokToPair xs) 
                                             (map tokToPair ys) 
                                             (fmap (map tokToPair) bl)

sentenceAccuracy :: [[Token]] -> [[Token]] -> Maybe [[Token]] -> Accuracy
sentenceAccuracy xs ys bl = accuracy (map,map,map) (map (map tokToPair) xs) 
                                                   (map (map tokToPair) ys) 
                                                   (fmap (map (map tokToPair)) bl)

tokToPair :: Token -> (String, Maybe String)
tokToPair t = (lowercase $ fromMaybe (tokenForm t) (tokenLemma t), tokenPOS t)


accuracy (g,h,i) gold test mbl = Acc { lemmaAcc = AccBL (correct (g fst) test) (fmap (correct (g fst)) mbl)
                                     , posAcc   = AccBL (correct (h snd) test) (fmap (correct (h snd)) mbl)
                                     , jointAcc = AccBL (correct (i id)  test) (fmap (correct (i id)) mbl) }
    where correct f ys = zipWith (\x y -> f x == f y) gold ys





showAccuracy acc = unlines [ "Lemma acc: " ++ (showAcc . lemmaAcc) acc
                           , "POS   acc: " ++ (showAcc . posAcc  ) acc 
                           , "Joint acc: " ++ (showAcc . jointAcc) acc ]


showAcc (AccBL t mbl) = case mbl of
                            Just bl -> let acc_bl  = (length bl, countTrue bl)
                                           acc_bl_pc = (fromIntegral (snd acc_bl)/(fromIntegral (fst acc_bl)))::Double
                                           ex = significance t bl
                                       in printf "%05.2f%% (%d / %d) %+.2f%%, %.2f%% RER, %d different, %d better, p-value: %g"
                                          (acc_t_pc * 100)
                                          (snd acc_t) 
                                          (fst acc_t) 
                                          (acc_t_pc * 100  - acc_bl_pc * 100)
                                          (rer acc_t_pc acc_bl_pc * 100)
                                          (trials ex)
                                          (successes ex)
                                          (pvalue ex)            
                            Nothing -> printf "%.2f%% (%d / %d)" (100*acc_t_pc) (snd acc_t) (fst acc_t) 
    where acc_t   = (length t, countTrue t)
          acc_t_pc = (fromIntegral (snd acc_t)/(fromIntegral (fst acc_t)))


