atp-0.1.0.0: src/ATP/Prove.hs
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-|
Module : ATP.Prove
Description : Interface to automated theorem provers.
Copyright : (c) Evgenii Kotelnikov, 2019-2021
License : GPL-3
Maintainer : evgeny.kotelnikov@gmail.com
Stability : experimental
Interface to automated theorem provers.
-}
module ATP.Prove (
ProvingOptions(..),
defaultOptions,
refute,
refuteUsing,
refuteWith,
prove,
proveUsing,
proveWith
) where
import Control.Monad (when)
import Data.Text (Text)
import qualified Data.Text as T (pack)
import Data.TPTP (TPTP)
import Data.TPTP.Parse.Text (parseTSTPOnly)
import Data.TPTP.Pretty (pretty)
import System.Exit (ExitCode(..))
import System.Process (readProcessWithExitCode)
import Text.PrettyPrint.ANSI.Leijen (bold, text)
import ATP.Error
import ATP.FOL (Clauses, Theorem, Solution)
import ATP.Codec.TPTP (encodeClauses, encodeTheorem, decodeSolution)
import ATP.Prover
-- | The options that describe what theorem prover to use for a problem and
-- how to run it.
data ProvingOptions = ProvingOptions {
prover :: Prover,
timeLimit :: TimeLimit,
memoryLimit :: MemoryLimit,
debug :: Bool -- ^ If @True@, print the input, the cli command,
-- the exit code and the output of the prover
} deriving (Eq, Show, Ord)
-- | The default options used by 'refute' and 'prove'.
--
-- >>> defaultOptions
-- ProvingOptions {prover = Prover {vendor = E, executable = "eprover"}, timeLimit = 300, memoryLimit = 2000, debug = False}
defaultOptions :: ProvingOptions
defaultOptions = ProvingOptions {
prover = defaultProver,
timeLimit = 300,
memoryLimit = 2000,
debug = False
}
-- | Attempt to refute a set of clauses using 'defaultProver'.
--
-- > refute = refuteWith defaultOptions
refute :: Clauses -> IO (Partial Solution)
refute = refuteWith defaultOptions
-- | Attempt to refute a set of clauses using a given prover.
refuteUsing :: Prover -> Clauses -> IO (Partial Solution)
refuteUsing p = refuteWith defaultOptions{prover = p}
-- | Attempt to refute a set of clauses with a given set of options.
refuteWith :: ProvingOptions -> Clauses -> IO (Partial Solution)
refuteWith opts = runWith opts . encodeClauses
-- | Attempt to prove a theorem using 'defaultProver'.
--
-- > prove = proveWith defaultOptions
prove :: Theorem -> IO (Partial Solution)
prove = proveWith defaultOptions
-- | Attempt to prove a theorem using a given prover.
proveUsing :: Prover -> Theorem -> IO (Partial Solution)
proveUsing p = proveWith defaultOptions{prover = p}
-- | Attempt to prove a theorem with a given set of options.
proveWith :: ProvingOptions -> Theorem -> IO (Partial Solution)
proveWith opts = runWith opts . encodeTheorem
runWith :: ProvingOptions -> TPTP -> IO (Partial Solution)
runWith opts tptp = do
let ProvingOptions{prover} = opts
let Prover{vendor} = prover
let input = show (pretty tptp)
(exitCode, stdout, stderr) <- runProver opts input
let output = proverOutput vendor exitCode stdout stderr
let solution = output >>= parseSolution
return solution
runProver :: ProvingOptions -> String -> IO (ExitCode, Text, Text)
runProver opts input = do
let ProvingOptions{prover, timeLimit, memoryLimit, debug} = opts
let Prover{vendor, executable} = prover
let arguments = proverArguments vendor timeLimit memoryLimit
let debugPrint header str = when debug $
print (bold (text header)) >>
putStrLn str >> putStr "\n"
debugPrint "Input" input
debugPrint "Command" $ unwords (executable:arguments)
(exitCode, stdout, stderr) <- readProcessWithExitCode executable arguments input
debugPrint "Exit code" (show exitCode)
debugPrint "Standard output" stdout
debugPrint "Standard error" stderr
return (exitCode, T.pack stdout, T.pack stderr)
parseSolution :: Text -> Partial Solution
parseSolution = either parsingError decodeSolution . parseTSTPOnly