packages feed

atp-0.1.0.0: test/Unit/Main.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

{-|
Module       : Unit.Main
Description  : Basic unit tests.
Copyright    : (c) Evgenii Kotelnikov, 2019-2021
License      : GPL-3
Maintainer   : evgeny.kotelnikov@gmail.com
Stability    : experimental
-}

module Unit.Main (tests) where

import Distribution.TestSuite (Test(..), TestInstance(..),
                               Progress(..), Result(..))
import ATP


-- * Helpers

simpleTest :: String -> IO Progress -> Test
simpleTest nm progress = Test $ TestInstance {
  name      = nm,
  tags      = [],
  options   = [],
  setOption = const . const $ Left "not supported",
  run       = progress
}

testCase :: Prover -> String ->
            (Either Error Solution -> Result) ->
            Either Clauses Theorem -> Test
testCase p nm testAnswer input = simpleTest testName progress
  where
    testName = show (vendor p) ++ " " ++ nm
    progress = fmap (Finished . testAnswer . liftPartial) solution
    solution = case input of
                 Left cs -> refuteWith opts cs
                 Right t -> proveWith  opts t
    opts = defaultOptions{prover=p, timeLimit=5}

expectSolution :: (Solution -> Result) -> Either Error Solution -> Result
expectSolution testSolution = \case
  Left  e -> Error ("Failed to find a solution: " ++ show e)
  Right s -> testSolution s

expectSaturation :: Either Error Solution -> Result
expectSaturation = expectSolution $ \case
  Saturation{} -> Pass
  Proof{} -> Error "Unexpected proof"

expectProof :: Either Error Solution -> Result
expectProof = expectSolution $ \case
  Saturation{} -> Error "Unexpected saturation"
  Proof{} -> Pass

expectTimLimitError :: Either Error Solution -> Result
expectTimLimitError = \case
  Left TimeLimitError -> Pass
  Left  e -> Error $ "Unexpected error " ++ show e
  Right _ -> Error "Unexpected solution"


-- * Test data

emptyClause :: Clauses
emptyClause = Clauses [EmptyClause]

negated :: Theorem -> Theorem
negated (Theorem as c) = Theorem as (neg c)

syllogism :: Theorem
syllogism = [humansAreMortal, human "socrates"] |- mortal "socrates"
  where
    humansAreMortal = forall $ \x -> human x ==> mortal x
    human = UnaryPredicate "human"
    mortal = UnaryPredicate "mortal"

groupTheoryAxiom :: Theorem
groupTheoryAxiom = [leftIdentity, leftInverse, associativity, groupOfOrder2] |- commutativity
  where
    inverse = UnaryFunction "inverse"
    (.*.) = BinaryFunction "mult"
    leftIdentity  = forall $ \x -> "e" .*. x === x
    leftInverse   = forall $ \x -> inverse x .*. x === "e"
    associativity = forall $ \x y z -> (x .*. y) .*. z === x .*. (y .*. z)
    groupOfOrder2 = forall $ \x -> x .*. x === "e"
    commutativity = forall $ \x y -> x .*. y === y .*. x


-- * Test suite

tests :: IO [Test]
tests = return [testCase p n t i | (n, t, i) <- cases, p <- provers]
  where
    provers = [eprover, vampire]
    cases = [
        ("refutes an empty clause",       expectProof,      Left emptyClause),
        ("saturates an empty clause set", expectSaturation, Left (Clauses [])),

        ("proves tautology",  expectProof,      Right (Claim Tautology)),
        ("saturates falsity", expectSaturation, Right (Claim Falsity)),

        ("proves syllogism",            expectProof,      Right syllogism),
        ("saturates negated syllogism", expectSaturation, Right (negated syllogism)),

        ("proves group theory axiom", expectProof,         Right groupTheoryAxiom),
        ("reached time limit",        expectTimLimitError, Right (negated groupTheoryAxiom))
      ]