sop-satisfier-0.3.4.5: src/SoPSat/SoP.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards #-}
module SoPSat.SoP (
-- * SoP Types
Atom,
Symbol,
Product,
SoP,
SoPE (..),
ToSoP (..),
-- * Operators
(|+|),
(|-|),
(|*|),
(|/|),
(|^|),
-- * Relations
OrdRel (..),
-- * Related
constants,
atoms,
int,
cons,
symbol,
func,
-- * Predicates
isConst,
isFunction,
)
where
import Data.Set (Set, union)
import qualified Data.Set as S
import SoPSat.Internal.SoP
{- | Convertable to a sum of products
with `f` being type to represent functions
and `c` being type to represent constants
-}
class (Ord f, Ord c) => ToSoP f c a where
toSoP :: a -> SoP f c
-- | Predicate for constant @Atom@s
isConst :: Atom f c -> Bool
isConst (C _) = True
isConst _ = False
-- | Predicate for function @Atom@s
isFunction :: Atom f c -> Bool
isFunction (F _ _) = True
isFunction _ = False
instance (Ord f, Ord c) => ToSoP f c (Symbol f c) where
toSoP s = simplifySoP $ S [P [s]]
instance (Ord f, Ord c) => ToSoP f c (Product f c) where
toSoP p = simplifySoP $ S [p]
instance (Ord f, Ord c) => ToSoP f c (SoP f c) where
toSoP = simplifySoP
-- | Order relationship
data OrdRel
= -- | Less than or equal relationship
LeR
| -- | Equality relationship
EqR
| -- | Greater than or equal relationship
GeR
deriving (Eq, Ord)
instance Show OrdRel where
show LeR = "<="
show EqR = "="
show GeR = ">="
-- | Expression
data SoPE f c
= SoPE
{ lhs :: SoP f c
-- ^ Left hand side of the expression
, rhs :: SoP f c
-- ^ Right hand side of the expression
, op :: OrdRel
-- ^ Relationship between sides
}
instance (Eq f, Eq c) => Eq (SoPE f c) where
(SoPE l1 r1 op1) == (SoPE l2 r2 op2)
| op1 == op2
, op1 == EqR =
-- a = b is the same as b = a
(l1 == l2) && (r1 == r2) || (l1 == r2) && (r1 == l2)
| op1 == op2 =
-- (a <= b) is itself
(l1 == l2) && (r1 == r2)
| EqR `notElem` [op1, op2] =
-- (a <= b) is the same as (b >= a)
(l1 == r2) && (r1 == l2)
| otherwise =
False
instance (Show f, Show c) => Show (SoPE f c) where
show SoPE{..} = unwords [show lhs, show op, show rhs]
-- | Creates an integer expression
int :: Integer -> SoP f c
int i = S [P [I i]]
-- | Creates expression from an atom
symbol :: Atom f c -> SoP f c
symbol a = S [P [A a]]
-- | Creates a constant expression
cons :: c -> SoP f c
cons c = S [P [A (C c)]]
-- | Creates a function expression
func :: (Ord f, Ord c) => f -> [SoP f c] -> SoP f c
func f args = S [P [A (F f (map simplifySoP args))]]
infixr 8 |^|
-- | Exponentiation of @SoP@s
(|^|) :: (Ord f, Ord c) => SoP f c -> SoP f c -> SoP f c
-- It's a B2 combinator,
(|^|) = (. simplifySoP) . normaliseExp
infixl 6 |+|
-- | Addition of @SoP@s
(|+|) :: (Ord f, Ord c) => SoP f c -> SoP f c -> SoP f c
(|+|) = mergeSoPAdd
infixl 7 |*|
-- | Multiplication of @SoP@s
(|*|) :: (Ord f, Ord c) => SoP f c -> SoP f c -> SoP f c
(|*|) = mergeSoPMul
infixl 6 |-|
-- | Subtraction of @SoP@s
(|-|) :: (Ord f, Ord c) => SoP f c -> SoP f c -> SoP f c
(|-|) = mergeSoPSub
infixl 7 |/|
{- | Division of @SoP@s
Produces a tuple of a quotient and a remainder
NB. Not implemented
-}
(|/|) :: (Ord f, Ord c) => SoP f c -> SoP f c -> (SoP f c, SoP f c)
(|/|) = mergeSoPDiv
-- | Collects @Atom@s used in a @SoP@
atoms :: (Ord f, Ord c) => SoP f c -> Set (Atom f c)
atoms = S.unions . map atomsProduct . unS
{- | Collects @Atom@s used in a @Product@
Used by @atoms@
-}
atomsProduct :: (Ord f, Ord c) => Product f c -> Set (Atom f c)
atomsProduct = S.unions . map atomsSymbol . unP
{- | Collect @Atom@s used in @Symbol@s
Used by @atomsProduct@
-}
atomsSymbol ::
(Ord f, Ord c) =>
Symbol f c ->
-- | - Empty - if the symbol is an integer
-- - Singleton - if the symbol is an atom
-- - Set of symbols - if the symbol is an exponentiation
Set (Atom f c)
atomsSymbol (I _) = S.empty
atomsSymbol (A a) = S.singleton a
atomsSymbol (E b p) = atoms b `union` atomsProduct p
{- | Collects constants used in @SoP@
Almost equivalent to
@Data.Set.filter isConst . atoms@
, but also collects constants used in functions
-}
constants :: (Ord f, Ord c) => SoP f c -> Set c
constants = S.unions . map constsProduct . unS
{- | Collects constants used in @Product@
Used by @constants@
-}
constsProduct :: (Ord f, Ord c) => Product f c -> Set c
constsProduct = S.unions . map constsSymbol . unP
{- | Collects constants used in @Symbol@
Used by @constsProduct@
-}
constsSymbol :: (Ord f, Ord c) => Symbol f c -> Set c
constsSymbol (I _) = S.empty
constsSymbol (A a) = constsAtom a
constsSymbol (E b p) = constants b `union` constsProduct p
{- | Collects constants used in @Atom@
Used by @constsSymbol@
-}
constsAtom ::
(Ord f, Ord c) =>
Atom f c ->
-- | Singleton - if the atom is a constant
-- Set of constants - if the atom is a function
Set c
constsAtom (C c) = S.singleton c
constsAtom (F _ args) = S.unions $ map constants args