GenZ-0.1.0.0: bench/runtime.hs
module Main where
import Control.Monad (unless, when)
import Criterion.Main
import qualified Criterion.Types
import qualified Data.ByteString.Lazy as BL
import Data.Char (isSpace)
import Data.Csv
import Data.List
import Data.List.Split
import Data.Maybe
import Data.Scientific
import qualified Data.Vector as V
import Numeric
import System.Directory
import System.Environment (getArgs)
import General
import Logic.Propositional.CPL
import Logic.Propositional.IPL
import Logic.Modal.K
import Logic.Modal.K4
import Logic.Modal.GL
import Logic.Modal.S4
import FormM
import FormP
type Case = (String, Int -> Bool, [Int])
-- | Selected formulas. Takes only a few minutes to run.
selection :: [Case]
selection =
makeCases [ ("IPL", intui) ] [("conPei-L", conPeiL), ("conPei-R", conPeiR)] [10,20..100] -- not provable
++ makeCases [ ("K", k) ] [("boxesTop", boxesTop)] [10,20..100] -- provable
++ makeCases [ ("K4", kfour) ] [("lobBoxes", lobBoxes)] [1..10] -- not provable
++ makeCases [ ("GL", gl) ] [("lobBoxes", lobBoxes)] [1..10] -- provable
-- | Large set of formulas. Can take multple hours to run.
allFormulas :: [Case]
allFormulas =
makeCases [("CPL", classical), ("IPL", intui) ] allFormulasP [10,20..100]
++ makeCases [("CPL", classical), ("IPL", intui) ] hardFormulasP [1..10]
++ makeCases [("K", k)] (propFormulasM ++ boxesFormulasM) [10,20..100]
++ makeCases [("K", k)] kFormulasM [1..10]
++ makeCases [("K4", kfour)] (propFormulasM ++ boxesFormulasM) [10,20..100]
++ makeCases [("K4", kfour)] k4FormulasM [1..8]
++ makeCases [("GL", gl)] propFormulasM [10,20..100]
++ makeCases [("S4", sfour)] propFormulasM [10,20..100]
++ makeCases [("S4", sfour)] hards4FormulasM [1..10]
-- | Helper function to run the maximum size of each case.
-- Ueful to adjust the ranges given above.
testAllMaxSizeItems :: IO ()
testAllMaxSizeItems = mapM_ func allItems where
func (n1, f, range) = do
print (n1 ++ show (maximum range))
print $ f (maximum range)
allItems :: [Case]
allItems = nubBy sameC $ selection ++ allFormulas where
sameC (n1, _, _) (n2, _, _) = n1 == n2
makeCases :: (Ord f, Show f) => [(String, Logic f)] -> [(String, Int -> f)] -> [Int] -> [Case]
makeCases logics forms sizes =
[ (fS ++ "-" ++ lS ++ "-" ++ pS , prover logic . formula, sizes)
| (fS, formula) <- forms
, (pS, prover) <- [("GenZ", isProvableZ), ("GenT", isProvableT)]
, (lS, logic) <- logics ]
benchMain :: IO ()
benchMain =
defaultMainWith myConfig (map mybench allItems) where
mybench (name1,f,range) = bgroup name1 $ map (run f) range
run f n = bench (show n) $ whnf f n
myConfig = defaultConfig
{ Criterion.Types.csvFile = Just theCSVname
, Criterion.Types.timeLimit = 10 }
main :: IO ()
main = do
args <- getArgs
unless ("--list" `elem` args) prepareMain
benchMain
unless ("--list" `elem` args) convertMain
-- * CSV to pgfplots
-- | The filename to which the benchmark results will be written in CSV.
theCSVname :: String
theCSVname = "bench/results.csv"
prepareMain :: IO ()
prepareMain = do
oldResults <- doesFileExist theCSVname
when oldResults $ do
putStrLn "Note: moving away old results."
renameFile theCSVname (theCSVname ++ ".OLD")
oldDATfile <- doesFileExist (theCSVname ++ ".dat")
when oldDATfile $ removeFile (theCSVname ++ ".dat")
-- | Convert the .csv file to a .dat file to be used with pgfplots.
convertMain :: IO ()
convertMain = do
putStrLn "Reading results.csv and converting to .dat for pgfplots."
c <- BL.readFile theCSVname
case decode NoHeader c of
Left err -> error $ "could not parse the csv file:" ++ show err
Right csv -> do
let results = map (parseLine . take 2) $ tail $ V.toList (csv :: V.Vector [String])
let columns = nub.sort $ map (fst.fst) results
let widthNeeded = maximum $ map length columns
let longify = longifyTo (widthNeeded + 2)
let firstLine = longifyTo 5 "n" ++ dropWhileEnd isSpace (concatMap longify columns)
let resAt n col = longify $ fromMaybe "nan" $ Data.List.lookup (col,n) results
let resultrow n = concatMap (resAt n) columns
let firstcol = nub.sort $ map (snd.fst) results
let resultrows = map (\n -> longifyTo 5 (show n) ++ dropWhileEnd isSpace (resultrow n)) firstcol
writeFile (theCSVname ++ ".dat") (intercalate "\n" (firstLine:resultrows) ++ "\n")
where
parseLine [namestr,numberstr] = case splitOn "/" namestr of
[name1,nstr] -> ((name1,n),valuestr) where
n = read nstr :: Integer
value = toRealFloat (read numberstr :: Scientific) :: Double
valuestr = Numeric.showFFloat (Just 7) value ""
_ -> error $ "could not parse this case: " ++ namestr
parseLine l = error $ "could not parse this line:\n " ++ show l
longifyTo n s = s ++ replicate (n - length s) ' '