{-# LANGUAGE FlexibleContexts #-} ----------------------------------------------------------------------------- -- Copyright 2019, Advise-Me project team. This file is distributed under -- the terms of the Apache License 2.0. For more information, see the files -- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ----------------------------------------------------------------------------- -- | -- Maintainer : bastiaan.heeren@ou.nl -- Stability : provisional -- Portability : portable (depends on ghc) -- ----------------------------------------------------------------------------- module Main.Diagnose where import Main.ParserCSV import Data.List import Data.Time import Ideas.Common.Id import Ideas.Text.HTML import Recognize.Data.MathStoryProblem import Recognize.Data.Approach import Recognize.Data.Entry import Recognize.Data.Solution import Util.W3CSSHTML diagnoseSingle :: MathStoryProblem -> String -> IO Entry diagnoseSingle e _ = timed $ do let entry = diagnose e (defaultSolution [error "diagnoseSingle conversion of Solution"]) print entry writePage ("single."++show e) (makePage (show e) (toHTML entry)) return entry diagnoseMultiple :: MathStoryProblem -> CSV -> IO () diagnoseMultiple e csv = timed $ do let answers = map (defaultSolution . map (uncurry Input . fmap ((:[]).Right))) (restrict csv) -- [[Id,String]] nrs = [1 :: Int ..] entries = zipWith (\_ -> diagnose e) nrs answers -- todo add ann and gs to entry -- writeFileMsg "output/extracted.txt" (outExtract entries) -- always empty writeFileMsg "output/diagnosed.txt" (outDiagnose entries) writeFileMsg "output/categories.txt" (outCategories entries) writeOutput ("output/out."++show e++".txt") entries writePage ("all."++show e) (makePage (show e) (mconcat (map toHTML entries))) --writePages ("html/all."++show e++".html") False entries -- writeErrors "output/errors.txt" entries putStrLn $ "Answers: " ++ show (length entries) putStrLn $ categoryStatistics entries timed :: IO a -> IO a timed m = do t0 <- getCurrentTime a <- m t1 <- getCurrentTime putStrLn $ "time: " ++ show (diffUTCTime t1 t0) return a writeOutput :: FilePath -> [Entry] -> IO () writeOutput file = writeFileMsg file . show {-} writeErrors :: FilePath -> [Entry e] -> IO () writeErrors file = writeFileMsg file . show . filter p . map f where f x = x { rawText = [], formulas = filter (isNothing . getExpr) (formulas x) } p = not . null . formulas -} writeFileMsg :: FilePath -> String -> IO () writeFileMsg file s = do putStr $ "Generating " ++ file ++ "... " writeFile file s putStrLn "ok" -- outExtract :: [Entry e] -> String -- outExtract = unlines . concatMap f -- where -- f entry -- | null (Recognize.Data.Entry.formulas entry) = [nr ++ "EMPTY"] -- | otherwise = map g (Recognize.Data.Entry.formulas entry) -- where -- nr = "#" ++ show (entryNr entry) ++ ": " -- g x = case getExpr x of -- Just xs -> nr ++ show xs -- Nothing -> nr ++ "ERROR: " ++ getString x outDiagnose :: [Entry] -> String outDiagnose = unlines . zipWith f [0 :: Int ..] where f nr entry = nrStr ++ "\n" ++ concatMap (\d -> show d ++ "\n") (diagnoses entry) where nrStr = "#" ++ show nr ++ ": " outCategories :: [Entry] -> String outCategories = unlines . zipWith f [0 :: Int ..] where f nr entry = nrStr ++ intercalate ", " (map (show . approach) $ diagnoses entry) where nrStr = "#" ++ show nr ++ ": " categoryStatistics :: [Entry] -> String categoryStatistics xs = unlines $ map f $ count $ map categoryAsString xs where nrTotal = length xs f (d, n) = d ++ ": " ++ show n ++ percPar n nrTotal count :: Ord a => [a] -> [(a, Int)] count = map f . group . sort where f xs = (head xs, length xs) percPar :: Integral a => a -> a -> String percPar x y = " (" ++ perc x y ++ ")" perc :: Integral a => a -> a -> String perc x y | y == 0 = "0%" | otherwise = show d ++ "." ++ make (show m) ++ "%" where (d, m) = (round ((10000 * fromIntegral x / fromIntegral y) :: Double) :: Integer) `divMod` 100 make s = replicate (2 - length s) '0' ++ s {- instance Show Formula where show x = " " ++ ljustify 25 (rawFormula x) ++ ": " ++ case recognized x of Just xs -> showChecked xs Nothing -> "???" ++ if balanced (rawFormula x) then "" else " (unbalanced)" where showChecked a = show a ++ if checkEquation a then "" else " (not equal)" showList = (++) . unlines . map show -} restrict :: [[String]] -> [[(Id,String)]] restrict xs = map (zip header) content where ys = map (map normalize) xs header = map newId (head ys) content = filter (\y -> p y && not (null y)) (tail ys) p = all (not . isInfixOf "v0") {- = map normalize . filter (not . null) . drop 1 . map f where column x = f [_, x] = unlines $ filter (/= "v0") $ lines x f _ = error "invalid number of rows" -} normalize :: String -> String normalize [] = [] normalize xs | "\\'" `isPrefixOf` xs = "'" ++ normalize (drop 2 xs) | "\\\"" `isPrefixOf` xs = '"' : normalize (drop 2 xs) | "&#x" `isPrefixOf` xs = case break (== ';') (drop 3 xs) of (xs1, ';':xs2) -> case lookup xs1 asciiTable of Just c -> c : normalize xs2 Nothing -> '?' : normalize xs2 _ -> error "normalize" normalize (x:xs) = x : normalize xs asciiTable :: [(String, Char)] asciiTable = [ ("e9", 'e') -- e acute , ("e0", 'a') -- a grave , ("e8", 'e') -- e grave , ("f9", 'u') -- u grave , ("ea", 'e') -- e circumflex , ("e2", 'a') -- a circumflex , ("e7", 'c') -- c cedilla , ("c3", 'A') -- A tilde , ("f7", '%') -- division , ("a0", ' ') -- space , ("a9", '?') -- copyright , ("b0", '?') -- ????? , ("aa", '?') -- ????? ]