packages feed

atp-0.1.0.0: src/ATP/FirstOrder/Simplification.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}

{-|
Module       : ATP.FirstOrder.Simplification
Description  : Simplification of first-order expressions.
Copyright    : (c) Evgenii Kotelnikov, 2019-2021
License      : GPL-3
Maintainer   : evgeny.kotelnikov@gmail.com
Stability    : experimental
-}
module ATP.FirstOrder.Simplification (
  -- * Simplification
  Simplify(..)
) where

import ATP.FirstOrder.Core
import ATP.FirstOrder.Smart

-- $setup
-- >>> :set -XOverloadedStrings
-- >>> :load Property.Generators


-- * Simplification

-- | A class of first-order expressions that 'simplify' syntactically shrinks
-- while preserving their evaluation.
class Simplify a where
  simplify :: a -> a

-- | Simplify the given formula by replacing each of its constructors with
-- corresponding smart constructors.
instance Simplify LogicalExpression where
  simplify = \case
    Clause  c -> Clause  (simplify c)
    Formula f -> Formula (simplify f)

-- | Simplify the given clause by replacing the 'Literals' constructor with
-- the smart constructor 'clause'. The effects of simplification are
-- the following.
--
-- * @'simplify' c@ does not contain negative constant literals.
-- * @'simplify' c@ does not contain falsum literals.
-- * @'simplify' c@ does not contain redundant tautology literals.
--
-- >>> simplify (UnitClause (Signed Negative (Propositional True)))
-- Literals {getLiterals = []}
--
-- >>> simplify (Literals [FalsityLiteral, Signed Positive (Predicate "p" [])])
-- Literals {getLiterals = [Signed {signof = Positive, unsign = Predicate (PredicateSymbol "p") []}]}
--
-- >>> simplify (Literals [TautologyLiteral, Signed Positive (Predicate "p" [])])
-- Literals {getLiterals = [Signed {signof = Positive, unsign = Propositional True}]}
--
instance Simplify Clause where
  simplify = clause . getLiterals

-- | Simplify the given clause set by replacing the 'Clauses' constructor with
-- the smart constructor 'clauses'. The effects of simplification are
-- the following.
--
-- * @'simplify' c@ does not contain negative constant literals.
-- * @'simplify' c@ does not contain falsum literals.
-- * @'simplify' c@ does not contain tautology literals.
-- * @'simplify' c@ does not contain redundant falsum literals.
--
-- >>> simplify (SingleClause (UnitClause (Signed Negative (Propositional True))))
-- Clauses {getClauses = [Literals {getLiterals = []}]}
--
-- >>> simplify (SingleClause (Literals [FalsityLiteral, Signed Positive (Predicate "p" [])]))
-- Clauses {getClauses = [Literals {getLiterals = [Signed {signof = Positive, unsign = Predicate (PredicateSymbol "p") []}]}]}
--
-- >>> simplify (SingleClause (Literals [TautologyLiteral, Signed Positive (Predicate "p" [])]))
-- Clauses {getClauses = []}
--
instance Simplify Clauses where
  simplify = clauses . getClauses

-- | Simplify the given formula by replacing each of its constructors with
-- corresponding smart constructors. The effects of simplification are
-- the following.
--
-- * @'simplify' f@ does not contain nested negations.
-- * @'simplify' f@ does not contain some of the constant atomic formulas from @f@.
-- * All chained applications of any binary connective inside
--   @'simplify' f@ are right-associative.
--
-- Any formula built only using smart constructors is simplified by construction.
--
-- >>> simplify (Connected Or tautology (Atomic (Predicate "p" [])))
-- Atomic (Propositional True)
--
-- >>> simplify (Negate (Negate (Atomic (Predicate "p" []))))
-- Atomic (Predicate "p" [])
--
-- >>> simplify (Connected And (Connected And (Atomic (Predicate "p" [])) (Atomic (Predicate "q" []))) (Atomic (Predicate "r" [])))
-- Connected And (Atomic (Predicate "p" [])) (Connected And (Atomic (Predicate "q" [])) (Atomic (Predicate "r" [])))
--
instance Simplify Formula where
  simplify = \case
    Atomic l -> Atomic l
    Negate f -> neg (simplify f)
    Connected  c f g -> simplify f # simplify g where (#) = smartConnective c
    Quantified q v f -> quantified q (v, simplify f)

-- | Convert a binary connective to its corresponding smart constructor.
smartConnective :: Connective -> Formula -> Formula -> Formula
smartConnective = \case
  And        -> (/\)
  Or         -> (\/)
  Implies    -> (==>)
  Equivalent -> (<=>)
  Xor        -> (<~>)

-- | Simplify the given theorem by flattening the conjunction of its premises
-- and its conjecture.
instance Simplify Theorem where
  simplify (Theorem as c) = flattenConjunction (fmap simplify as) |- simplify c