packages feed

twee-lib 2.1 → 2.1.1

raw patch · 86 files changed

+5787/−8278 lines, 86 files

Files

+ Data/ChurchList.hs view
@@ -0,0 +1,99 @@+-- Church-encoded lists. Used in Twee.CP to make sure that fusion happens.+{-# LANGUAGE Rank2Types, BangPatterns #-}+module Data.ChurchList where++import Prelude(Functor(..), Applicative(..), Monad(..), Bool(..), Maybe(..), (.), ($), id)+import qualified Prelude+import GHC.Magic(oneShot)+import GHC.Exts(build)+import Control.Monad(MonadPlus(..), liftM2)+import Control.Applicative(Alternative(..))++newtype ChurchList a =+  ChurchList (forall b. (a -> b -> b) -> b -> b)++{-# INLINE foldr #-}+foldr :: (a -> b -> b) -> b -> ChurchList a -> b+foldr op e (ChurchList f) = eta (f op (eta e))+  -- Using eta here seems to help with eta-expanding foldl'++{-# INLINE[0] eta #-}+eta :: a -> a+eta x = x+{-# RULES "eta" forall f. eta f = \x -> f x #-}++{-# INLINE nil #-}+nil :: ChurchList a+nil = ChurchList (\_ n -> n)++{-# INLINE unit #-}+unit :: a -> ChurchList a+unit x = ChurchList (\c n -> c x n)++{-# INLINE cons #-}+cons :: a -> ChurchList a -> ChurchList a+cons x xs = ChurchList (\c n -> c x (foldr c n xs))++{-# INLINE append #-}+append :: ChurchList a -> ChurchList a -> ChurchList a+append xs ys = ChurchList (\c n -> foldr c (foldr c n ys) xs)++{-# INLINE join #-}+join :: ChurchList (ChurchList a) -> ChurchList a+join xss = ChurchList (\c n -> foldr (\xs ys -> foldr c ys xs) n xss)++instance Functor ChurchList where+  {-# INLINE fmap #-}+  fmap f xs = ChurchList (\c n -> foldr (c . f) n xs)++instance Applicative ChurchList where+  {-# INLINE pure #-}+  pure = return+  {-# INLINE (<*>) #-}+  (<*>) = liftM2 ($)++instance Monad ChurchList where+  {-# INLINE return #-}+  return = unit+  {-# INLINE (>>=) #-}+  xs >>= f = join (fmap f xs)++instance Alternative ChurchList where+  {-# INLINE empty #-}+  empty = nil+  {-# INLINE (<|>) #-}+  (<|>) = append++instance MonadPlus ChurchList where+  {-# INLINE mzero #-}+  mzero = empty+  {-# INLINE mplus #-}+  mplus = (<|>)++{-# INLINE fromList #-}+fromList :: [a] -> ChurchList a+fromList xs = ChurchList (\c n -> Prelude.foldr c n xs)++{-# INLINE toList #-}+toList :: ChurchList a -> [a]+toList (ChurchList f) = build f++{-# INLINE foldl' #-}+foldl' :: (b -> a -> b) -> b -> ChurchList a -> b+foldl' op e xs =+  foldr (\x f -> oneShot (\ (!acc) -> f (op acc x))) id xs e++{-# INLINE filter #-}+filter :: (a -> Bool) -> ChurchList a -> ChurchList a+filter p xs =+  ChurchList $ \c n ->+    let            +      {-# INLINE op #-}+      op x xs = if p x then c x xs else xs+    in+      foldr op n xs++{-# INLINE fromMaybe #-}+fromMaybe :: Maybe a -> ChurchList a+fromMaybe Nothing = nil+fromMaybe (Just x) = unit x
+ Data/DynamicArray.hs view
@@ -0,0 +1,67 @@+-- | Zero-indexed dynamic arrays, optimised for lookup.+-- Modification is slow. Uninitialised indices have a default value.+{-# LANGUAGE CPP #-}+module Data.DynamicArray where++#ifdef BOUNDS_CHECKS+import qualified Data.Primitive.SmallArray.Checked as P+#else+import qualified Data.Primitive.SmallArray as P+#endif+import Control.Monad.ST+import Data.List++-- | A type which has a default value.+class Default a where+  -- | The default value.+  def :: a++-- | An array.+data Array a =+  Array {+    -- | The size of the array.+    arraySize     :: {-# UNPACK #-} !Int,+    -- | The contents of the array.+    arrayContents :: {-# UNPACK #-} !(P.SmallArray a) }++-- | Convert an array to a list of (index, value) pairs.+{-# INLINE toList #-}+toList :: Array a -> [(Int, a)]+toList arr =+  [ (i, x)+  | i <- [0..arraySize arr-1],+    let x = P.indexSmallArray (arrayContents arr) i ]++instance Show a => Show (Array a) where+  show arr =+    "{" +++    intercalate ", "+      [ show i ++ "->" ++ show x+      | (i, x) <- toList arr ] +++    "}"++-- | Create an empty array.+newArray :: Default a => Array a+newArray = runST $ do+  marr <- P.newSmallArray 0 def+  arr  <- P.unsafeFreezeSmallArray marr+  return (Array 0 arr)++-- | Index into an array. O(1) time.+{-# INLINE (!) #-}+(!) :: Default a => Array a -> Int -> a+arr ! n+  | 0 <= n && n < arraySize arr =+    P.indexSmallArray (arrayContents arr) n+  | otherwise = def++-- | Update the array. O(n) time.+{-# INLINEABLE update #-}+update :: Default a => Int -> a -> Array a -> Array a+update n x arr = runST $ do+  let size = arraySize arr `max` (n+1)+  marr <- P.newSmallArray size def+  P.copySmallArray marr 0 (arrayContents arr) 0 (arraySize arr)+  P.writeSmallArray marr n $! x+  arr' <- P.unsafeFreezeSmallArray marr+  return (Array size arr')
+ Data/Heap.hs view
@@ -0,0 +1,154 @@+-- | Skew heaps.++{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}+module Data.Heap(+  Heap, empty, singleton, insert, removeMin, union, mapMaybe, size) where++-- | A heap.++-- Representation: the size of the heap, and the heap itself.+data Heap a = Heap {-# UNPACK #-} !Int !(Heap1 a) deriving Show+-- N.B.: arguments are not strict so code has to take care+-- to force stuff appropriately.+data Heap1 a = Nil | Node a (Heap1 a) (Heap1 a) deriving Show++-- | Take the union of two heaps.+{-# INLINEABLE union #-}+union :: Ord a => Heap a -> Heap a -> Heap a+union (Heap n1 h1) (Heap n2 h2) = Heap (n1+n2) (union1 h1 h2)++{-# INLINEABLE union1 #-}+union1 :: forall a. Ord a => Heap1 a -> Heap1 a -> Heap1 a+union1 = u1+  where+    -- The generated code is better when we do everything+    -- through this u1 function instead of union1...+    -- This is because u1 has no Ord constraint in its type.+    u1 :: Heap1 a -> Heap1 a -> Heap1 a+    u1 Nil h = h+    u1 h Nil = h+    u1 h1@(Node x1 l1 r1) h2@(Node x2 l2 r2)+      | x1 <= x2 = (Node x1 $! u1 r1 h2) l1+      | otherwise = (Node x2 $! u1 r2 h1) l2++-- | A singleton heap.+{-# INLINE singleton #-}+singleton :: a -> Heap a+singleton !x = Heap 1 (Node x Nil Nil)++-- | The empty heap.+{-# INLINE empty #-}+empty :: Heap a+empty = Heap 0 Nil++-- | Insert an element.+{-# INLINEABLE insert #-}+insert :: Ord a => a -> Heap a -> Heap a+insert x h = union (singleton x) h++-- | Find and remove the minimum element.+{-# INLINEABLE removeMin #-}+removeMin :: Ord a => Heap a -> Maybe (a, Heap a)+removeMin (Heap _ Nil) = Nothing+removeMin (Heap n (Node x l r)) = Just (x, Heap (n-1) (union1 l r))++-- | Map a function over a heap, removing all values which+-- map to 'Nothing'. May be more efficient when the function+-- being mapped is mostly monotonic.+{-# INLINEABLE mapMaybe #-}+mapMaybe :: Ord b => (a -> Maybe b) -> Heap a -> Heap b+mapMaybe f (Heap _ h) = Heap (sz 0 h') h'+  where+    -- Compute the size fairly efficiently.+    sz !n Nil = n+    sz !n (Node _ l r) = sz (sz (n+1) l) r++    h' = mm h++    mm Nil = Nil+    mm (Node x l r) =+      case f x of+        -- If the value maps to Nothing, get rid of it.+        Nothing -> union1 l' r'+        -- Otherwise, check if the heap invariant still holds+        -- and sift downwards to restore it.+        Just !y -> down y l' r'+      where+        !l' = mm l+        !r' = mm r++    down x l@(Node y ll lr) r@(Node z rl rr)+      -- Put the smallest of x, y and z at the root.+      | y < x && y <= z =+        (Node y $! down x ll lr) r+      | z < x && z <= y =+        Node z l $! down x rl rr+    down x Nil (Node y l r)+      -- Put the smallest of x and y at the root.+      | y < x =+        Node y Nil $! down x l r+    down x (Node y l r) Nil+      -- Put the smallest of x and y at the root.+      | y < x =+        (Node y $! down x l r) Nil+    down x l r = Node x l r++-- | Return the number of elements in the heap.+{-# INLINE size #-}+size :: Heap a -> Int+size (Heap n _) = n++-- Testing code:+-- import Test.QuickCheck+-- import qualified Data.List as List+-- import qualified Data.Maybe as Maybe++-- instance (Arbitrary a, Ord a) => Arbitrary (Heap a) where+--   arbitrary = sized arb+--     where+--       arb 0 = return empty+--       arb n =+--         frequency+--           [(1, singleton <$> arbitrary),+--            (n-1, union <$> arb' <*> arb')]+--         where+--           arb' = arb (n `div` 2)++-- toList :: Ord a => Heap a -> [a]+-- toList = List.unfoldr removeMin++-- invariant :: Ord a => Heap a -> Bool+-- invariant h@(Heap n h1) =+--   n == length (toList h) && ord h1+--   where+--     ord Nil = True+--     ord (Node x l r) = ord1 x l && ord1 x r++--     ord1 _ Nil = True+--     ord1 x h@(Node y _ _) = x <= y && ord h++-- prop_1 h = withMaxSuccess 10000 $ invariant h+-- prop_2 x h = withMaxSuccess 10000 $ invariant (insert x h)+-- prop_3 h =+--   withMaxSuccess 1000 $+--   case removeMin h of+--     Nothing -> discard+--     Just (_, h) -> invariant h+-- prop_4 h = withMaxSuccess 10000 $ List.sort (toList h) == toList h+-- prop_5 x h = withMaxSuccess 10000 $ toList (insert x h) == List.insert x (toList h)+-- prop_6 x h =+--   withMaxSuccess 1000 $+--   case removeMin h of+--     Nothing -> discard+--     Just (x, h') -> toList h == List.insert x (toList h')+-- prop_7 h1 h2 = withMaxSuccess 10000 $+--   invariant (union h1 h2)+-- prop_8 h1 h2 = withMaxSuccess 10000 $+--   toList (union h1 h2) == List.sort (toList h1 ++ toList h2)+-- prop_9 (Blind f) h = withMaxSuccess 10000 $+--   invariant (mapMaybe f h)+-- prop_10 (Blind f) h = withMaxSuccess 1000000 $+--   toList (mapMaybe f h) == List.sort (Maybe.mapMaybe f (toList h))++-- return []+-- main = $quickCheckAll
+ Data/Primitive/ByteArray/Checked.hs view
@@ -0,0 +1,74 @@+-- | A bounds-checked version of 'Data.Primitive.ByteArray'.+-- See that module for documentation.++{-# LANGUAGE ScopedTypeVariables #-}+module Data.Primitive.ByteArray.Checked(+  module Data.Primitive.ByteArray,+  module Data.Primitive.ByteArray.Checked) where++import Control.Monad.Primitive+import qualified Data.Primitive.ByteArray as P+import Data.Primitive(Prim)+import Data.Primitive.ByteArray(+  ByteArray(..), MutableByteArray(..),+  newByteArray, newPinnedByteArray, newAlignedPinnedByteArray,+  byteArrayContents, mutableByteArrayContents,+  sameMutableByteArray,+  unsafeFreezeByteArray, unsafeThawByteArray,+  sizeofByteArray, sizeofMutableByteArray)+import Data.Primitive.Checked+import Data.Word++instance Sized ByteArray where+  size = sizeofByteArray+instance Sized (MutableByteArray m) where+  size = sizeofMutableByteArray++{-# INLINE readByteArray #-}+readByteArray :: forall m a. (PrimMonad m, Prim a) => MutableByteArray (PrimState m) -> Int -> m a+readByteArray arr n =+  checkPrim (undefined :: a) arr n $+  P.readByteArray arr n++{-# INLINE writeByteArray #-}+writeByteArray :: (PrimMonad m, Prim a) => MutableByteArray (PrimState m) -> Int -> a -> m ()+writeByteArray arr n x =+  checkPrim x arr n $+  P.writeByteArray arr n x++{-# INLINE indexByteArray #-}+indexByteArray :: forall a. Prim a => ByteArray -> Int -> a+indexByteArray arr n =+  checkPrim (undefined :: a) arr n $+  P.indexByteArray arr n++{-# INLINE copyByteArray #-}+copyByteArray :: PrimMonad m => MutableByteArray (PrimState m) -> Int -> ByteArray -> Int -> Int -> m ()+copyByteArray arr1 n1 arr2 n2 len =+  range arr1 n1 len $+  range arr2 n2 len $+  P.copyByteArray arr1 n1 arr2 n2 len++{-# INLINE moveByteArray #-}+moveByteArray :: PrimMonad m => MutableByteArray (PrimState m) -> Int -> MutableByteArray (PrimState m) -> Int -> Int -> m ()+moveByteArray arr1 n1 arr2 n2 len =+  range arr1 n1 len $+  range arr2 n2 len $+  P.moveByteArray arr1 n1 arr2 n2 len++{-# INLINE copyMutableByteArray #-}+copyMutableByteArray :: PrimMonad m => MutableByteArray (PrimState m) -> Int -> MutableByteArray (PrimState m) -> Int -> Int -> m ()+copyMutableByteArray arr1 n1 arr2 n2 len =+  range arr1 n1 len $+  range arr2 n2 len $+  P.copyMutableByteArray arr1 n1 arr2 n2 len++{-# INLINE setByteArray #-}+setByteArray :: (Prim a, PrimMonad m) => MutableByteArray (PrimState m) -> Int -> Int -> a -> m ()+setByteArray arr n len x =+  rangePrim x arr n len $+  P.setByteArray arr n len x++{-# INLINE fillByteArray #-}+fillByteArray :: PrimMonad m => MutableByteArray (PrimState m) -> Int -> Int -> Word8 -> m ()+fillByteArray = setByteArray
+ Data/Primitive/Checked.hs view
@@ -0,0 +1,46 @@+-- | A helper module for array bounds checking.++module Data.Primitive.Checked where++import Data.Primitive(Prim, sizeOf)++-- | A type class of things which have a size (e.g., arrays).+class Sized a where+  -- | Read the size of the thing.+  size :: a -> Int++-- | Check that a single access is in bounds.+{-# INLINE check #-}+check :: Sized a => a -> Int -> b -> b+check arr n x+  | n >= 0 && n < size arr = x+  | otherwise = error "out-of-bounds array access"++-- | Check that a range of accesses is in bounds.+-- The range is inclusive.+{-# INLINE range #-}+range :: Sized a => a -> Int -> Int -> b -> b+range arr n len x+  | len < 0 = error "array slice has negative length"+  | len == 0 = x+  | otherwise =+    check arr n $+    check arr (n+len-1) $ x++-- | Check that a single access is in bounds.+-- The index accessed is computed by multiplying by the size+-- of the first argument.+{-# INLINE checkPrim #-}+checkPrim :: (Sized a, Prim b) => b -> a -> Int -> c -> c+checkPrim x arr n res =+  range arr (n*sizeOf x) (sizeOf x) res+  +-- | Check that a range of accesses is in bounds.+-- The range is inclusive.+-- The index accessed is computed by multiplying by the size+-- of the first argument.+{-# INLINE rangePrim #-}+rangePrim :: (Sized a, Prim b) => b -> a -> Int -> Int -> c -> c+rangePrim x arr n len res =+  range arr (n*sizeOf x) (len*sizeOf x) res+  
+ Data/Primitive/SmallArray/Checked.hs view
@@ -0,0 +1,80 @@+-- | A bounds-checked version of 'Data.Primitive.SmallArray'.+-- See that module for documentation.++module Data.Primitive.SmallArray.Checked(+  module Data.Primitive.SmallArray,+  module Data.Primitive.SmallArray.Checked) where++import Control.Monad.Primitive+import qualified Data.Primitive.SmallArray as P+import Data.Primitive.SmallArray(+  SmallArray(..), SmallMutableArray(..), newSmallArray, unsafeFreezeSmallArray,+  unsafeThawSmallArray, sizeofSmallArray, sizeofSmallMutableArray)+import Data.Primitive.Checked++instance Sized (SmallArray a) where+  size = sizeofSmallArray+instance Sized (SmallMutableArray m a) where+  size = sizeofSmallMutableArray++{-# INLINE readSmallArray #-}+readSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> m a+readSmallArray arr n =+  check arr n $+  P.readSmallArray arr n++{-# INLINE writeSmallArray #-}+writeSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> a -> m ()+writeSmallArray arr n x =+  check arr n $+  P.writeSmallArray arr n x++{-# INLINE indexSmallArrayM #-}+indexSmallArrayM :: Monad m => SmallArray a -> Int -> m a+indexSmallArrayM arr n =+  check arr n $+  P.indexSmallArrayM arr n++{-# INLINE indexSmallArray #-}+indexSmallArray :: SmallArray a -> Int -> a+indexSmallArray arr n =+  check arr n $+  P.indexSmallArray arr n++{-# INLINE cloneSmallArray #-}+cloneSmallArray :: SmallArray a -> Int -> Int -> SmallArray a+cloneSmallArray arr n len =+  range arr n len $+  P.cloneSmallArray arr n len++{-# INLINE cloneSmallMutableArray #-}+cloneSmallMutableArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> Int -> m (SmallMutableArray (PrimState m) a)+cloneSmallMutableArray arr n len =+  range arr n len $+  P.cloneSmallMutableArray arr n len++{-# INLINE freezeSmallArray #-}+freezeSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> Int -> m (SmallArray a)+freezeSmallArray arr n len =+  range arr n len $+  P.freezeSmallArray arr n len++{-# INLINE thawSmallArray #-}+thawSmallArray :: PrimMonad m => SmallArray a -> Int -> Int -> m (SmallMutableArray (PrimState m) a)+thawSmallArray arr n len =+  range arr n len $+  P.thawSmallArray arr n len++{-# INLINE copySmallArray #-}+copySmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> SmallArray a -> Int -> Int -> m ()+copySmallArray arr1 n1 arr2 n2 len =+  range arr1 n1 len $+  range arr2 n2 len $+  P.copySmallArray arr1 n1 arr2 n2 len++{-# INLINE copySmallMutableArray #-}+copySmallMutableArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> SmallMutableArray (PrimState m) a -> Int -> Int -> m ()+copySmallMutableArray arr1 n1 arr2 n2 len =+  range arr1 n1 len $+  range arr2 n2 len $+  P.copySmallMutableArray arr1 n1 arr2 n2 len
− README.md
@@ -1,25 +0,0 @@-This is twee, an equational theorem prover.--The version in this git repository is likely to be unstable!-To install the latest stable version, run:--    cabal install twee--If you have LLVM installed, you can get a slightly faster version by-running:--    cabal install twee -fllvm--If you really want the latest unstable version, run `cabal install` in-this repository, and then in the `executable` subdirectory.-You will most likely need the latest git version of Jukebox, from-https://github.com/nick8325/jukebox, too - and things may break from-time to time.--Afterwards, run `twee nameofproblem.p`. The problem should be in TPTP-format (http://www.tptp.org). You can find a few examples in the-`tests` directory. All axioms and conjectures must be equations, but-you can freely use quantifiers. If it succeeds in proving your-problem, twee will print a human-readable proof.--For the official manual, see http://nick8325.github.io/twee.
+ Twee.hs view
@@ -0,0 +1,616 @@+-- | The main prover loop.+{-# LANGUAGE RecordWildCards, MultiParamTypeClasses, GADTs, BangPatterns, OverloadedStrings, ScopedTypeVariables, GeneralizedNewtypeDeriving, PatternGuards, TypeFamilies #-}+module Twee where++import Twee.Base+import Twee.Rule hiding (normalForms)+import qualified Twee.Rule as Rule+import Twee.Equation+import qualified Twee.Proof as Proof+import Twee.Proof(Proof, Axiom(..), Lemma(..), ProvedGoal(..), provedGoal, certify, derivation, symm)+import Twee.CP hiding (Config)+import qualified Twee.CP as CP+import Twee.Join hiding (Config, defaultConfig)+import qualified Twee.Join as Join+import qualified Twee.Rule.Index as RuleIndex+import Twee.Rule.Index(RuleIndex(..))+import qualified Twee.Index as Index+import Twee.Index(Index)+import Twee.Constraints+import Twee.Utils+import Twee.Task+import qualified Twee.PassiveQueue as Queue+import Twee.PassiveQueue(Queue, Passive(..))+import qualified Data.IntMap.Strict as IntMap+import Data.IntMap(IntMap)+import Data.Maybe+import Data.List+import Data.Function+import qualified Data.Set as Set+import Data.Set(Set)+import Data.Int+import Data.Ord+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Class+import qualified Control.Monad.Trans.State.Strict as StateM++----------------------------------------------------------------------+-- * Configuration and prover state.+----------------------------------------------------------------------++-- | The prover configuration.+data Config =+  Config {+    cfg_max_term_size          :: Int,+    cfg_max_critical_pairs     :: Int64,+    cfg_max_cp_depth           :: Int,+    cfg_simplify               :: Bool,+    cfg_renormalise_percent    :: Int,+    cfg_critical_pairs         :: CP.Config,+    cfg_join                   :: Join.Config,+    cfg_proof_presentation     :: Proof.Config }++-- | The prover state.+data State f =+  State {+    st_rules          :: !(RuleIndex f (ActiveRule f)),+    st_active_ids     :: !(IntMap (Active f)),+    st_rule_ids       :: !(IntMap (ActiveRule f)),+    st_joinable       :: !(Index f (Equation f)),+    st_goals          :: ![Goal f],+    st_queue          :: !(Queue Params),+    st_next_active    :: {-# UNPACK #-} !Id,+    st_next_rule      :: {-# UNPACK #-} !RuleId,+    st_considered     :: {-# UNPACK #-} !Int64,+    st_messages_rev   :: ![Message f] }++-- | The default prover configuration.+defaultConfig :: Config+defaultConfig =+  Config {+    cfg_max_term_size = maxBound,+    cfg_max_critical_pairs = maxBound,+    cfg_max_cp_depth = maxBound,+    cfg_simplify = True,+    cfg_renormalise_percent = 5,+    cfg_critical_pairs = CP.defaultConfig,+    cfg_join = Join.defaultConfig,+    cfg_proof_presentation = Proof.defaultConfig }++-- | Does this configuration run the prover in a complete mode?+configIsComplete :: Config -> Bool+configIsComplete Config{..} =+  cfg_max_term_size == maxBound &&+  cfg_max_critical_pairs == maxBound &&+  cfg_max_cp_depth == maxBound++-- | The initial state.+initialState :: State f+initialState =+  State {+    st_rules = RuleIndex.empty,+    st_active_ids = IntMap.empty,+    st_rule_ids = IntMap.empty,+    st_joinable = Index.empty,+    st_goals = [],+    st_queue = Queue.empty,+    st_next_active = 1,+    st_next_rule = 0,+    st_considered = 0,+    st_messages_rev = [] }++----------------------------------------------------------------------+-- * Messages.+----------------------------------------------------------------------++-- | A message which is produced by the prover when something interesting happens.+data Message f =+    -- | A new rule.+    NewActive !(Active f)+    -- | A new joinable equation.+  | NewEquation !(Equation f)+    -- | A rule was deleted.+  | DeleteActive !(Active f)+    -- | The CP queue was simplified.+  | SimplifyQueue+    -- | The rules were reduced wrt each other.+  | Interreduce++instance Function f => Pretty (Message f) where+  pPrint (NewActive rule) = pPrint rule+  pPrint (NewEquation eqn) =+    text "  (hard)" <+> pPrint eqn+  pPrint (DeleteActive rule) =+    text "  (delete rule " <> pPrint (active_id rule) <> text ")"+  pPrint SimplifyQueue =+    text "  (simplifying queued critical pairs...)"+  pPrint Interreduce =+    text "  (simplifying rules with respect to one another...)"++-- | Emit a message.+message :: PrettyTerm f => Message f -> State f -> State f+message !msg state@State{..} =+  state { st_messages_rev = msg:st_messages_rev }++-- | Forget about all emitted messages.+clearMessages :: State f -> State f+clearMessages state@State{..} =+  state { st_messages_rev = [] }++-- | Get all emitted messages.+messages :: State f -> [Message f]+messages state = reverse (st_messages_rev state)++----------------------------------------------------------------------+-- * The CP queue.+----------------------------------------------------------------------++data Params+instance Queue.Params Params where+  type Score Params = Int+  type Id Params = RuleId+  type PackedId Params = Int32+  type PackedScore Params = Int32+  packScore _ = fromIntegral+  unpackScore _ = fromIntegral+  packId _ = fromIntegral+  unpackId _ = fromIntegral++-- | Compute all critical pairs from a rule.+{-# INLINEABLE makePassives #-}+makePassives :: Function f => Config -> State f -> ActiveRule f -> [Passive Params]+makePassives Config{..} State{..} rule =+  {-# SCC makePassive #-}+  [ Passive (fromIntegral (score cfg_critical_pairs o)) (rule_rid rule1) (rule_rid rule2) (fromIntegral (overlap_pos o))+  | (rule1, rule2, o) <- overlaps (Depth cfg_max_cp_depth) (index_oriented st_rules) rules rule ]+  where+    rules = IntMap.elems st_rule_ids++-- | Turn a Passive back into an overlap.+-- Doesn't try to simplify it.+{-# INLINEABLE findPassive #-}+findPassive :: forall f. Function f => Config -> State f -> Passive Params -> Maybe (ActiveRule f, ActiveRule f, Overlap f)+findPassive Config{..} State{..} Passive{..} = {-# SCC findPassive #-} do+  rule1 <- IntMap.lookup (fromIntegral passive_rule1) st_rule_ids+  rule2 <- IntMap.lookup (fromIntegral passive_rule2) st_rule_ids+  let !depth = 1 + max (the rule1) (the rule2)+  overlap <-+    overlapAt (fromIntegral passive_pos) depth+      (renameAvoiding (the rule2 :: Rule f) (the rule1)) (the rule2)+  return (rule1, rule2, overlap)++-- | Renormalise a queued Passive.+{-# INLINEABLE simplifyPassive #-}+simplifyPassive :: Function f => Config -> State f -> Passive Params -> Maybe (Passive Params)+simplifyPassive config@Config{..} state@State{..} passive = {-# SCC simplifyPassive #-} do+  (_, _, overlap) <- findPassive config state passive+  overlap <- simplifyOverlap (index_oriented st_rules) overlap+  return passive {+    passive_score = fromIntegral $+      fromIntegral (passive_score passive) `intMin`+      score cfg_critical_pairs overlap }++-- | Renormalise the entire queue.+{-# INLINEABLE simplifyQueue #-}+simplifyQueue :: Function f => Config -> State f -> State f+simplifyQueue config state =+  {-# SCC simplifyQueue #-}+  state { st_queue = simp (st_queue state) }+  where+    simp =+      Queue.mapMaybe (simplifyPassive config state)++-- | Enqueue a set of critical pairs.+{-# INLINEABLE enqueue #-}+enqueue :: Function f => State f -> RuleId -> [Passive Params] -> State f+enqueue state rule passives =+  {-# SCC enqueue #-}+  state { st_queue = Queue.insert rule passives (st_queue state) }++-- | Dequeue a critical pair.+--+-- Also takes care of:+--+--   * removing any orphans from the head of the queue+--   * ignoring CPs that are too big+{-# INLINEABLE dequeue #-}+dequeue :: Function f => Config -> State f -> (Maybe (CriticalPair f, ActiveRule f, ActiveRule f), State f)+dequeue config@Config{..} state@State{..} =+  {-# SCC dequeue #-}+  case deq 0 st_queue of+    -- Explicitly make the queue empty, in case it e.g. contained a+    -- lot of orphans+    Nothing -> (Nothing, state { st_queue = Queue.empty })+    Just (overlap, n, queue) ->+      (Just overlap,+       state { st_queue = queue, st_considered = st_considered + n })+  where+    deq !n queue = do+      (passive, queue) <- Queue.removeMin queue+      case findPassive config state passive of+        Just (rule1, rule2, overlap)+          | passive_score passive >= 0,+            Just Overlap{overlap_eqn = t :=: u} <-+              simplifyOverlap (index_oriented st_rules) overlap,+            size t <= cfg_max_term_size,+            size u <= cfg_max_term_size,+            Just cp <- makeCriticalPair rule1 rule2 overlap ->+              return ((cp, rule1, rule2), n+1, queue)+        _ -> deq (n+1) queue++----------------------------------------------------------------------+-- * Active rewrite rules.+----------------------------------------------------------------------++data Active f =+  Active {+    active_id    :: {-# UNPACK #-} !Id,+    active_depth :: {-# UNPACK #-} !Depth,+    active_rule  :: {-# UNPACK #-} !(Rule f),+    active_top   :: !(Maybe (Term f)),+    active_proof :: {-# UNPACK #-} !(Proof f),+    -- A model in which the rule is false (used when reorienting)+    active_model :: !(Model f),+    active_rules :: ![ActiveRule f] }++active_cp :: Active f -> CriticalPair f+active_cp Active{..} =+  CriticalPair {+    cp_eqn = unorient active_rule,+    cp_depth = active_depth,+    cp_top = active_top,+    cp_proof = derivation active_proof }++-- An active oriented in a particular direction.+data ActiveRule f =+  ActiveRule {+    rule_active    :: {-# UNPACK #-} !Id,+    rule_rid       :: {-# UNPACK #-} !RuleId,+    rule_depth     :: {-# UNPACK #-} !Depth,+    rule_rule      :: {-# UNPACK #-} !(Rule f),+    rule_proof     :: {-# UNPACK #-} !(Proof f),+    rule_positions :: !(Positions f) }++instance PrettyTerm f => Symbolic (ActiveRule f) where+  type ConstantOf (ActiveRule f) = f+  termsDL ActiveRule{..} =+    termsDL rule_rule `mplus`+    termsDL (derivation rule_proof)+  subst_ sub r@ActiveRule{..} =+    r {+      rule_rule = rule',+      rule_proof = certify (subst_ sub (derivation rule_proof)),+      rule_positions = positions (lhs rule') }+    where+      rule' = subst_ sub rule_rule++instance Eq (Active f) where+  (==) = (==) `on` active_id++instance Eq (ActiveRule f) where+  (==) = (==) `on` rule_rid++instance Function f => Pretty (Active f) where+  pPrint Active{..} =+    pPrint active_id <> text "." <+> pPrint (canonicalise active_rule)++instance Has (ActiveRule f) Id where the = rule_active+instance Has (ActiveRule f) RuleId where the = rule_rid+instance Has (ActiveRule f) Depth where the = rule_depth+instance f ~ g => Has (ActiveRule f) (Rule g) where the = rule_rule+instance f ~ g => Has (ActiveRule f) (Proof g) where the = rule_proof+instance f ~ g => Has (ActiveRule f) (Lemma g) where the x = Lemma (the x) (the x)+instance f ~ g => Has (ActiveRule f) (Positions g) where the = rule_positions++newtype RuleId = RuleId Id deriving (Eq, Ord, Show, Num, Real, Integral, Enum)++-- Add a new active.+{-# INLINEABLE addActive #-}+addActive :: Function f => Config -> State f -> (Id -> RuleId -> RuleId -> Active f) -> State f+addActive config state@State{..} active0 =+  {-# SCC addActive #-}+  let+    active@Active{..} = active0 st_next_active st_next_rule (succ st_next_rule)+    state' =+      message (NewActive active) $+      addActiveOnly state{st_next_active = st_next_active+1, st_next_rule = st_next_rule+2} active+  in if subsumed st_joinable st_rules (unorient active_rule) then+    state+  else+    normaliseGoals $+    foldl' (uncurry . enqueue) state'+      [ (the rule, makePassives config state' rule)+      | rule <- active_rules ]++-- Add an active without generating critical pairs. Used in interreduction.+{-# INLINEABLE addActiveOnly #-}+addActiveOnly :: Function f => State f -> Active f -> State f+addActiveOnly state@State{..} active@Active{..} =+  state {+    st_rules = foldl' insertRule st_rules active_rules,+    st_active_ids = IntMap.insert (fromIntegral active_id) active st_active_ids,+    st_rule_ids = foldl' insertRuleId st_rule_ids active_rules }+  where+    insertRule rules rule@ActiveRule{..} =+      RuleIndex.insert (lhs rule_rule) rule rules+    insertRuleId rules rule@ActiveRule{..} =+      IntMap.insert (fromIntegral rule_rid) rule rules++-- Delete an active. Used in interreduction, not suitable for general use.+{-# INLINE deleteActive #-}+deleteActive :: Function f => State f -> Active f -> State f+deleteActive state@State{..} Active{..} =+  state {+    st_rules = foldl' deleteRule st_rules active_rules,+    st_active_ids = IntMap.delete (fromIntegral active_id) st_active_ids,+    st_rule_ids = foldl' deleteRuleId st_rule_ids active_rules }+  where+    deleteRule rules rule =+      RuleIndex.delete (lhs (rule_rule rule)) rule rules+    deleteRuleId rules ActiveRule{..} =+      IntMap.delete (fromIntegral rule_rid) rules++-- Try to join a critical pair.+{-# INLINEABLE consider #-}+consider :: Function f => Config -> State f -> CriticalPair f -> State f+consider config state cp =+  considerUsing (st_rules state) config state cp++-- Try to join a critical pair, but using a different set of critical+-- pairs for normalisation.+{-# INLINEABLE considerUsing #-}+considerUsing ::+  Function f =>+  RuleIndex f (ActiveRule f) -> Config -> State f -> CriticalPair f -> State f+considerUsing rules config@Config{..} state@State{..} cp0 =+  {-# SCC consider #-}+  -- Important to canonicalise the rule so that we don't get+  -- bigger and bigger variable indices over time+  let cp = canonicalise cp0 in+  case joinCriticalPair cfg_join st_joinable rules Nothing cp of+    Right (mcp, cps) ->+      let+        state' = foldl' (considerUsing rules config) state cps+      in case mcp of+        Just cp -> addJoinable state' (cp_eqn cp)+        Nothing -> state'++    Left (cp, model) ->+      foldl' (addCP config model) state (split cp)++{-# INLINEABLE addCP #-}+addCP :: Function f => Config -> Model f -> State f -> CriticalPair f -> State f+addCP config model state@State{..} CriticalPair{..} =+  addActive config state $ \n k1 k2 ->+  let+    pf = certify cp_proof+    rule = orient cp_eqn++    makeRule k r p =+      ActiveRule {+        rule_active = n,+        rule_rid = k,+        rule_depth = cp_depth,+        rule_rule = r rule,+        rule_proof = p pf,+        rule_positions = positions (lhs (r rule)) }+  in+  Active {+    active_id = n,+    active_depth = cp_depth,+    active_rule = rule,+    active_model = model,+    active_top = cp_top,+    active_proof = pf,+    active_rules =+      usortBy (comparing (canonicalise . rule_rule)) $+        makeRule k1 id id:+        [ makeRule k2 backwards (certify . symm . derivation)+        | not (oriented (orientation rule)) ] }++-- Add a new equation.+{-# INLINEABLE addAxiom #-}+addAxiom :: Function f => Config -> State f -> Axiom f -> State f+addAxiom config state axiom =+  consider config state $+    CriticalPair {+      cp_eqn = axiom_eqn axiom,+      cp_depth = 0,+      cp_top = Nothing,+      cp_proof = Proof.axiom axiom }++-- Record an equation as being joinable.+{-# INLINEABLE addJoinable #-}+addJoinable :: Function f => State f -> Equation f -> State f+addJoinable state eqn@(t :=: u) =+  message (NewEquation eqn) $+  state {+    st_joinable =+      Index.insert t (t :=: u) $+      Index.insert u (u :=: t) (st_joinable state) }++-- For goal terms we store the set of all their normal forms.+-- Name and number are for information only.+data Goal f =+  Goal {+    goal_name   :: String,+    goal_number :: Int,+    goal_eqn    :: Equation f,+    goal_lhs    :: Set (Resulting f),+    goal_rhs    :: Set (Resulting f) }++-- Add a new goal.+{-# INLINEABLE addGoal #-}+addGoal :: Function f => Config -> State f -> Goal f -> State f+addGoal _config state@State{..} goal =+  normaliseGoals state { st_goals = goal:st_goals }++-- Normalise all goals.+{-# INLINEABLE normaliseGoals #-}+normaliseGoals :: Function f => State f -> State f+normaliseGoals state@State{..} =+  {-# SCC normaliseGoals #-}+  state {+    st_goals =+      map (goalMap (successors (rewrite reduces (index_all st_rules)) . Set.toList)) st_goals }+  where+    goalMap f goal@Goal{..} =+      goal { goal_lhs = f goal_lhs, goal_rhs = f goal_rhs }++-- Create a goal.+{-# INLINE goal #-}+goal :: Int -> String -> Equation f -> Goal f+goal n name (t :=: u) =+  Goal {+    goal_name = name,+    goal_number = n,+    goal_eqn = t :=: u,+    goal_lhs = Set.singleton (reduce (Refl t)),+    goal_rhs = Set.singleton (reduce (Refl u)) }++----------------------------------------------------------------------+-- Interreduction.+----------------------------------------------------------------------++-- Simplify all rules.+{-# INLINEABLE interreduce #-}+interreduce :: Function f => Config -> State f -> State f+interreduce config@Config{..} state =+  {-# SCC interreduce #-}+  let+    state' =+      foldl' (interreduce1 config)+        -- Clear out st_joinable, since we don't know which+        -- equations have made use of each active.+        state { st_joinable = Index.empty }+        (IntMap.elems (st_active_ids state))+    in state' { st_joinable = st_joinable state }++{-# INLINEABLE interreduce1 #-}+interreduce1 :: Function f => Config -> State f -> Active f -> State f+interreduce1 config@Config{..} state active =+  -- Exclude the active from the rewrite rules when testing+  -- joinability, otherwise it will be trivially joinable.+  case+    joinCriticalPair cfg_join+      (st_joinable state)+      (st_rules (deleteActive state active))+      (Just (active_model active)) (active_cp active)+  of+    Right (_, cps) ->+      flip (foldl' (consider config)) cps $+      message (DeleteActive active) $+      deleteActive state active+    Left (cp, model)+      | not (cp_eqn cp `isInstanceOf` cp_eqn (active_cp active)) ->+        flip (foldl' (addCP config model)) (split cp) $+        message (DeleteActive active) $+        deleteActive state active+      | model /= active_model active ->+        flip addActiveOnly active { active_model = model } $+        deleteActive state active+      | otherwise ->+        state+  where+    (t :=: u) `isInstanceOf` (t' :=: u') = isJust $ do+      sub <- match t' t+      matchIn sub u' u+++----------------------------------------------------------------------+-- The main loop.+----------------------------------------------------------------------++data Output m f =+  Output {+    output_message :: Message f -> m () }++{-# INLINE complete #-}+complete :: (Function f, MonadIO m) => Output m f -> Config -> State f -> m (State f)+complete Output{..} config@Config{..} state =+  flip StateM.execStateT state $ do+    tasks <- sequence+      [newTask 1 (fromIntegral cfg_renormalise_percent / 100) $ do+         lift $ output_message SimplifyQueue+         state <- StateM.get+         StateM.put $! simplifyQueue config state,+       newTask 0.25 0.05 $ do+         when cfg_simplify $ do+           lift $ output_message Interreduce+           state <- StateM.get+           StateM.put $! interreduce config state]++    let+      loop = do+        progress <- StateM.state (complete1 config)+        state <- StateM.get+        lift $ mapM_ output_message (messages state)+        StateM.put (clearMessages state)+        mapM_ checkTask tasks+        when progress loop++    loop++{-# INLINEABLE complete1 #-}+complete1 :: Function f => Config -> State f -> (Bool, State f)+complete1 config@Config{..} state+  | st_considered state >= cfg_max_critical_pairs =+    (False, state)+  | solved state = (False, state)+  | otherwise =+    case dequeue config state of+      (Nothing, state) -> (False, state)+      (Just (overlap, _, _), state) ->+        (True, consider config state overlap)++{-# INLINEABLE solved #-}+solved :: Function f => State f -> Bool+solved = not . null . solutions++-- Return whatever goals we have proved and their proofs.+{-# INLINEABLE solutions #-}+solutions :: Function f => State f -> [ProvedGoal f]+solutions State{..} = {-# SCC solutions #-} do+  Goal{goal_lhs = ts, goal_rhs = us, ..} <- st_goals+  guard (not (null (Set.intersection ts us)))+  let t:_ = filter (`Set.member` us) (Set.toList ts)+      u:_ = filter (== t) (Set.toList us)+      -- Strict so that we check the proof before returning a solution+      !p =+        Proof.certify $+          reductionProof (reduction t) `Proof.trans`+          Proof.symm (reductionProof (reduction u))+  return (provedGoal goal_number goal_name p)++-- Return all current rewrite rules.+{-# INLINEABLE rules #-}+rules :: Function f => State f -> [Rule f]+rules = map active_rule . IntMap.elems . st_active_ids++----------------------------------------------------------------------+-- For code which uses twee as a library.+----------------------------------------------------------------------++{-# INLINEABLE completePure #-}+completePure :: Function f => Config -> State f -> State f+completePure cfg state+  | progress = completePure cfg (clearMessages state')+  | otherwise = state'+  where+    (progress, state') = complete1 cfg state++{-# INLINEABLE normaliseTerm #-}+normaliseTerm :: Function f => State f -> Term f -> Resulting f+normaliseTerm State{..} t =+  normaliseWith (const True) (rewrite reduces (index_all st_rules)) t++{-# INLINEABLE normalForms #-}+normalForms :: Function f => State f -> Term f -> Set (Resulting f)+normalForms State{..} t =+  Rule.normalForms (rewrite reduces (index_all st_rules)) [reduce (Refl t)]++{-# INLINEABLE simplifyTerm #-}+simplifyTerm :: Function f => State f -> Term f -> Term f+simplifyTerm State{..} t =+  simplify (index_oriented st_rules) t
+ Twee/Base.hs view
@@ -0,0 +1,285 @@+-- | Useful operations on terms and similar. Also re-exports some generally+-- useful modules such as 'Twee.Term' and 'Twee.Pretty'.++{-# LANGUAGE TypeFamilies, FlexibleInstances, UndecidableInstances, DeriveFunctor, DefaultSignatures, FlexibleContexts, TypeOperators, MultiParamTypeClasses, GeneralizedNewtypeDeriving, ConstraintKinds, RecordWildCards #-}+module Twee.Base(+  -- * Re-exported functionality+  module Twee.Term, module Twee.Pretty,+  -- * The 'Symbolic' typeclass+  Symbolic(..), subst, terms,+  TermOf, TermListOf, SubstOf, TriangleSubstOf, BuilderOf, FunOf,+  vars, isGround, funs, occ, occVar, canonicalise, renameAvoiding,+  -- * General-purpose functionality+  Id(..), Has(..),+  -- * Typeclasses+  Minimal(..), minimalTerm, isMinimal, erase,+  Skolem(..), Arity(..), Sized(..), Ordered(..), lessThan, orientTerms, EqualsBonus(..), Strictness(..), Function, Extended(..)) where++import Prelude hiding (lookup)+import Control.Monad+import qualified Data.DList as DList+import Twee.Term hiding (subst, canonicalise)+import qualified Twee.Term as Term+import Twee.Pretty+import Twee.Constraints hiding (funs)+import Data.DList(DList)+import Data.Typeable+import Data.Int+import Data.Maybe+import qualified Data.IntMap.Strict as IntMap++-- | Represents a unique identifier (e.g., for a rule).+newtype Id = Id { unId :: Int32 }+  deriving (Eq, Ord, Show, Enum, Bounded, Num, Real, Integral)++instance Pretty Id where+  pPrint = text . show . unId++-- | Generalisation of term functionality to things that contain terms (e.g.,+-- rewrite rules and equations).+class Symbolic a where+  type ConstantOf a++  -- | Compute a 'DList' of all terms which appear in the argument+  -- (used for e.g. computing free variables).+  -- See also 'terms'.+  termsDL :: a -> DList (TermListOf a)++  -- | Apply a substitution.+  -- When using the 'Symbolic' type class, you can use 'subst' instead.+  subst_ :: (Var -> BuilderOf a) -> a -> a++-- | Apply a substitution.+subst :: (Symbolic a, Substitution s, SubstFun s ~ ConstantOf a) => s -> a -> a+subst sub x = subst_ (evalSubst sub) x++-- | Find all terms occuring in the argument.+terms :: Symbolic a => a -> [TermListOf a]+terms = DList.toList . termsDL++-- | A term compatible with a given 'Symbolic'.+type TermOf a = Term (ConstantOf a)+-- | A termlist compatible with a given 'Symbolic'.+type TermListOf a = TermList (ConstantOf a)+-- | A substitution compatible with a given 'Symbolic'.+type SubstOf a = Subst (ConstantOf a)+-- | A triangle substitution compatible with a given 'Symbolic'.+type TriangleSubstOf a = TriangleSubst (ConstantOf a)+-- | A builder compatible with a given 'Symbolic'.+type BuilderOf a = Builder (ConstantOf a)+-- | The underlying type of function symbols of a given 'Symbolic'.+type FunOf a = Fun (ConstantOf a)++instance Symbolic (Term f) where+  type ConstantOf (Term f) = f+  termsDL = return . singleton+  subst_ sub = build . Term.subst sub++instance Symbolic (TermList f) where+  type ConstantOf (TermList f) = f+  termsDL = return+  subst_ sub = buildList . Term.substList sub++instance Symbolic (Subst f) where+  type ConstantOf (Subst f) = f+  termsDL (Subst sub) = termsDL (IntMap.elems sub)+  subst_ sub (Subst s) = Subst (fmap (subst_ sub) s)++instance (ConstantOf a ~ ConstantOf b, Symbolic a, Symbolic b) => Symbolic (a, b) where+  type ConstantOf (a, b) = ConstantOf a+  termsDL (x, y) = termsDL x `mplus` termsDL y+  subst_ sub (x, y) = (subst_ sub x, subst_ sub y)++instance (ConstantOf a ~ ConstantOf b,+          ConstantOf a ~ ConstantOf c,+          Symbolic a, Symbolic b, Symbolic c) => Symbolic (a, b, c) where+  type ConstantOf (a, b, c) = ConstantOf a+  termsDL (x, y, z) = termsDL x `mplus` termsDL y `mplus` termsDL z+  subst_ sub (x, y, z) = (subst_ sub x, subst_ sub y, subst_ sub z)++instance Symbolic a => Symbolic [a] where+  type ConstantOf [a] = ConstantOf a+  termsDL xs = msum (map termsDL xs)+  subst_ sub xs = map (subst_ sub) xs++instance Symbolic a => Symbolic (Maybe a) where+  type ConstantOf (Maybe a) = ConstantOf a+  termsDL Nothing = mzero+  termsDL (Just x) = termsDL x+  subst_ sub x = fmap (subst_ sub) x++-- | An instance @'Has' a b@ indicates that a value of type @a@ contains a value+-- of type @b@ which is somehow part of the meaning of the @a@.+--+-- A number of functions use 'Has' constraints to work in a more general setting.+-- For example, the functions in 'Twee.CP' operate on rewrite rules, but actually+-- accept any @a@ satisfying @'Has' a ('Twee.Rule.Rule' f)@.+--+-- Use taste when definining 'Has' instances; don't do it willy-nilly.+class Has a b where+  -- | Get at the thing.+  the :: a -> b++instance Has a a where+  the = id++-- | Find the variables occurring in the argument.+{-# INLINE vars #-}+vars :: Symbolic a => a -> [Var]+vars x = [ v | t <- DList.toList (termsDL x), Var v <- subtermsList t ]++-- | Test if the argument is ground.+{-# INLINE isGround #-}+isGround :: Symbolic a => a -> Bool+isGround = null . vars++-- | Find the function symbols occurring in the argument.+{-# INLINE funs #-}+funs :: Symbolic a => a -> [FunOf a]+funs x = [ f | t <- DList.toList (termsDL x), App f _ <- subtermsList t ]++-- | Count how many times a function symbol occurs in the argument.+{-# INLINE occ #-}+occ :: Symbolic a => FunOf a -> a -> Int+occ x t = length (filter (== x) (funs t))++-- | Count how many times a variable occurs in the argument.+{-# INLINE occVar #-}+occVar :: Symbolic a => Var -> a -> Int+occVar x t = length (filter (== x) (vars t))++-- | Rename the argument so that variables are introduced in a canonical order+-- (starting with V0, then V1 and so on).+{-# INLINEABLE canonicalise #-}+canonicalise :: Symbolic a => a -> a+canonicalise t = subst sub t+  where+    sub = Term.canonicalise (DList.toList (termsDL t))++-- | Rename the second argument so that it does not mention any variable which+-- occurs in the first.+{-# INLINEABLE renameAvoiding #-}+renameAvoiding :: (Symbolic a, Symbolic b) => a -> b -> b+renameAvoiding x y+  | x2 < y1 || y2 < x1 =+    -- No overlap. Important in the case when x is ground,+    -- in which case x2 == minBound and the calculation below doesn't work.+    y+  | otherwise =+    -- Map y1 to x2+1+    subst (\(V x) -> var (V (x-y1+x2+1))) y+  where+    (V x1, V x2) = boundLists (terms x)+    (V y1, V y2) = boundLists (terms y)++-- | Check if a term is the minimal constant.+isMinimal :: Minimal f => Term f -> Bool+isMinimal (App f Empty) | f == minimal = True+isMinimal _ = False++-- | Build the minimal constant as a term.+minimalTerm :: Minimal f => Term f+minimalTerm = build (con minimal)++-- | Erase a given set of variables from the argument, replacing them with the+-- minimal constant.+erase :: (Symbolic a, ConstantOf a ~ f, Minimal f) => [Var] -> a -> a+erase [] t = t+erase xs t = subst sub t+  where+    sub = fromMaybe undefined $ listToSubst [(x, minimalTerm) | x <- xs]++-- | Construction of Skolem constants.+class Skolem f where+  -- | Turn a variable into a Skolem constant.+  skolem  :: Var -> Fun f++-- | For types which have a notion of arity.+class Arity f where+  -- | Measure the arity.+  arity :: f -> Int++instance Arity f => Arity (Fun f) where+  arity = arity . fun_value++-- | For types which have a notion of size.+class Sized a where+  -- | Compute the size.+  size  :: a -> Int++instance Sized f => Sized (Fun f) where+  size = size . fun_value++instance Sized f => Sized (TermList f) where+  size = aux 0+    where+      aux n Empty = n+      aux n (ConsSym (App f _) t) = aux (n+size f) t+      aux n (Cons (Var _) t) = aux (n+1) t++instance Sized f => Sized (Term f) where+  size = size . singleton++-- | The collection of constraints which the type of function symbols must+-- satisfy in order to be used by twee.+type Function f = (Ordered f, Arity f, Sized f, Minimal f, Skolem f, PrettyTerm f, EqualsBonus f)++-- | A hack for encoding Horn clauses. See 'Twee.CP.Score'.+-- The default implementation of 'hasEqualsBonus' should work OK.+class EqualsBonus f where+  hasEqualsBonus :: f -> Bool+  hasEqualsBonus _ = False+  isEquals, isTrue, isFalse :: f -> Bool+  isEquals _ = False+  isTrue _ = False+  isFalse _ = False++instance EqualsBonus f => EqualsBonus (Fun f) where+  hasEqualsBonus = hasEqualsBonus . fun_value+  isEquals = isEquals . fun_value+  isTrue = isTrue . fun_value+  isFalse = isFalse . fun_value++-- | A function symbol extended with a minimal constant and Skolem functions.+-- Comes equipped with 'Minimal' and 'Skolem' instances.+data Extended f =+    -- | The minimal constant.+    Minimal+    -- | A Skolem function.+  | Skolem Var+    -- | An ordinary function symbol.+  | Function f+  deriving (Eq, Ord, Show, Functor)++instance Pretty f => Pretty (Extended f) where+  pPrintPrec _ _ Minimal = text "?"+  pPrintPrec _ _ (Skolem (V n)) = text "sk" <> pPrint n+  pPrintPrec l p (Function f) = pPrintPrec l p f++instance PrettyTerm f => PrettyTerm (Extended f) where+  termStyle (Function f) = termStyle f+  termStyle _ = uncurried++instance Sized f => Sized (Extended f) where+  size (Function f) = size f+  size _ = 1++instance Arity f => Arity (Extended f) where+  arity (Function f) = arity f+  arity _ = 0++instance (Typeable f, Ord f) => Minimal (Extended f) where+  minimal = fun Minimal++instance (Typeable f, Ord f) => Skolem (Extended f) where+  skolem x = fun (Skolem x)++instance EqualsBonus f => EqualsBonus (Extended f) where+  hasEqualsBonus (Function f) = hasEqualsBonus f+  hasEqualsBonus _ = False+  isEquals (Function f) = isEquals f+  isEquals _ = False+  isTrue (Function f) = isTrue f+  isTrue _ = False+  isFalse (Function f) = isFalse f+  isFalse _ = False
+ Twee/CP.hs view
@@ -0,0 +1,330 @@+-- | Critical pair generation.+{-# LANGUAGE BangPatterns, FlexibleContexts, ScopedTypeVariables, MultiParamTypeClasses, RecordWildCards, OverloadedStrings, TypeFamilies, GeneralizedNewtypeDeriving #-}+module Twee.CP where++import qualified Twee.Term as Term+import Twee.Base+import Twee.Rule+import Twee.Index(Index)+import qualified Data.Set as Set+import Control.Monad+import Data.Maybe+import Data.List+import qualified Data.ChurchList as ChurchList+import Data.ChurchList (ChurchList(..))+import Twee.Utils+import Twee.Equation+import qualified Twee.Proof as Proof+import Twee.Proof(Derivation, Lemma, congPath)++-- | The set of positions at which a term can have critical overlaps.+data Positions f = NilP | ConsP {-# UNPACK #-} !Int !(Positions f)+type PositionsOf a = Positions (ConstantOf a)++instance Show (Positions f) where+  show = show . ChurchList.toList . positionsChurch++-- | Calculate the set of positions for a term.+positions :: Term f -> Positions f+positions t = aux 0 Set.empty (singleton t)+  where+    -- Consider only general superpositions.+    aux !_ !_ Empty = NilP+    aux n m (Cons (Var _) t) = aux (n+1) m t+    aux n m (ConsSym t@App{} u)+      | t `Set.member` m = aux (n+1) m u+      | otherwise = ConsP n (aux (n+1) (Set.insert t m) u)++{-# INLINE positionsChurch #-}+positionsChurch :: Positions f -> ChurchList Int+positionsChurch posns =+  ChurchList $ \c n ->+    let+      pos NilP = n+      pos (ConsP x posns) = c x (pos posns)+    in+      pos posns++-- | A critical overlap of one rule with another.+data Overlap f =+  Overlap {+    -- | The depth (1 for CPs of axioms, 2 for CPs whose rules have depth 1, etc.)+    overlap_depth :: {-# UNPACK #-} !Depth,+    -- | The critical term.+    overlap_top   :: {-# UNPACK #-} !(Term f),+    -- | The part of the critical term which the inner rule rewrites.+    overlap_inner :: {-# UNPACK #-} !(Term f),+    -- | The position in the critical term which is rewritten.+    overlap_pos   :: {-# UNPACK #-} !Int,+    -- | The critical pair itself.+    overlap_eqn   :: {-# UNPACK #-} !(Equation f) }+  deriving Show+type OverlapOf a = Overlap (ConstantOf a)++-- | Represents the depth of a critical pair.+newtype Depth = Depth Int deriving (Eq, Ord, Num, Real, Enum, Integral, Show)++-- | Compute all overlaps of a rule with a set of rules.+{-# INLINEABLE overlaps #-}+overlaps ::+  (Function f, Has a (Rule f), Has a (Positions f), Has a Depth) =>+  Depth -> Index f a -> [a] -> a -> [(a, a, Overlap f)]+overlaps max_depth idx rules r =+  ChurchList.toList (overlapsChurch max_depth idx rules r)++{-# INLINE overlapsChurch #-}+overlapsChurch :: forall f a.+  (Function f, Has a (Rule f), Has a (Positions f), Has a Depth) =>+  Depth -> Index f a -> [a] -> a -> ChurchList (a, a, Overlap f)+overlapsChurch max_depth idx rules r1 = do+  guard (the r1 < max_depth)+  r2 <- ChurchList.fromList rules+  guard (the r2 < max_depth)+  let !depth = 1 + max (the r1) (the r2)+  do { o <- asymmetricOverlaps idx depth (the r1) r1' (the r2); return (r1, r2, o) } `mplus`+    do { o <- asymmetricOverlaps idx depth (the r2) (the r2) r1'; return (r2, r1, o) }+  where+    !r1' = renameAvoiding (map the rules :: [Rule f]) (the r1)++{-# INLINE asymmetricOverlaps #-}+asymmetricOverlaps ::+  (Function f, Has a (Rule f), Has a Depth) =>+  Index f a -> Depth -> Positions f -> Rule f -> Rule f -> ChurchList (Overlap f)+asymmetricOverlaps idx depth posns r1 r2 = do+  n <- positionsChurch posns+  ChurchList.fromMaybe $+    overlapAt n depth r1 r2 >>=+    simplifyOverlap idx++-- | Create an overlap at a particular position in a term.+-- Doesn't simplify the overlap.+{-# INLINE overlapAt #-}+overlapAt :: Int -> Depth -> Rule f -> Rule f -> Maybe (Overlap f)+overlapAt !n !depth (Rule _ !outer !outer') (Rule _ !inner !inner') = do+  let t = at n (singleton outer)+  sub <- unifyTri inner t+  let+    top = {-# SCC overlap_top #-} termSubst sub outer+    innerTerm = {-# SCC overlap_inner #-} termSubst sub inner+    -- Make sure to keep in sync with overlapProof+    lhs = {-# SCC overlap_eqn_1 #-} termSubst sub outer'+    rhs = {-# SCC overlap_eqn_2 #-}+      buildReplacePositionSub sub n (singleton inner') (singleton outer)++  guard (lhs /= rhs)+  return Overlap {+    overlap_depth = depth,+    overlap_top = top,+    overlap_inner = innerTerm,+    overlap_pos = n,+    overlap_eqn = lhs :=: rhs }++-- | Simplify an overlap and remove it if it's trivial.+{-# INLINE simplifyOverlap #-}+simplifyOverlap :: (Function f, Has a (Rule f)) => Index f a -> Overlap f -> Maybe (Overlap f)+simplifyOverlap idx overlap@Overlap{overlap_eqn = lhs :=: rhs, ..}+  | lhs == rhs'  = Nothing+  | lhs' == rhs' = Nothing+  | otherwise = Just overlap{overlap_eqn = lhs' :=: rhs'}+  where+    lhs' = simplify idx lhs+    rhs' = simplify idx rhs++-- Put these in separate functions to avoid code blowup+buildReplacePositionSub :: TriangleSubst f -> Int -> TermList f -> TermList f -> Term f+buildReplacePositionSub !sub !n !inner' !outer =+  build (replacePositionSub sub n inner' outer)++termSubst :: TriangleSubst f -> Term f -> Term f+termSubst sub t = build (Term.subst sub t)++-- | The configuration for the critical pair weighting heuristic.+data Config =+  Config {+    cfg_lhsweight :: !Int,+    cfg_rhsweight :: !Int,+    cfg_funweight :: !Int,+    cfg_varweight :: !Int,+    cfg_depthweight :: !Int,+    cfg_dupcost :: !Int,+    cfg_dupfactor :: !Int }++-- | The default heuristic configuration.+defaultConfig :: Config+defaultConfig =+  Config {+    cfg_lhsweight = 3,+    cfg_rhsweight = 1,+    cfg_funweight = 7,+    cfg_varweight = 6,+    cfg_depthweight = 16,+    cfg_dupcost = 7,+    cfg_dupfactor = 0 }++-- | Compute a score for a critical pair.++-- We compute:+--   cfg_lhsweight * size l + cfg_rhsweight * size r+-- where l is the biggest term and r is the smallest,+-- and variables have weight 1 and functions have weight cfg_funweight.+{-# INLINEABLE score #-}+score :: Function f => Config -> Overlap f -> Int+score Config{..} Overlap{..} =+  fromIntegral overlap_depth * cfg_depthweight ++  (m + n) * cfg_rhsweight ++  intMax m n * (cfg_lhsweight - cfg_rhsweight)+  where+    l :=: r = overlap_eqn+    m = size' 0 (singleton l)+    n = size' 0 (singleton r)++    size' !n Empty = n+    size' n (Cons t ts)+      | len t > 1, t `isSubtermOfList` ts =+        size' (n+cfg_dupcost+cfg_dupfactor*size t) ts+    size' n ts+      | Cons (App f ws@(Cons a (Cons b us))) vs <- ts,+        hasEqualsBonus (fun_value f),+        Just sub <- unify a b =+        size' (n+cfg_funweight*size f) ws `min`+        size' (size' (n+1) (subst sub us)) (subst sub vs)+    size' n (Cons (Var _) ts) =+      size' (n+cfg_varweight) ts+    size' n (ConsSym (App f _) ts) =+      size' (n+cfg_funweight*size f) ts++----------------------------------------------------------------------+-- * Higher-level handling of critical pairs.+----------------------------------------------------------------------++-- | A critical pair together with information about how it was derived+data CriticalPair f =+  CriticalPair {+    -- | The critical pair itself.+    cp_eqn   :: {-# UNPACK #-} !(Equation f),+    -- | The depth of the critical pair.+    cp_depth :: {-# UNPACK #-} !Depth,+    -- | The critical term, if there is one.+    -- (Axioms do not have a critical term.)+    cp_top   :: !(Maybe (Term f)),+    -- | A derivation of the critical pair from the axioms.+    cp_proof :: !(Derivation f) }++instance Symbolic (CriticalPair f) where+  type ConstantOf (CriticalPair f) = f+  termsDL CriticalPair{..} =+    termsDL cp_eqn `mplus` termsDL cp_top `mplus` termsDL cp_proof+  subst_ sub CriticalPair{..} =+    CriticalPair {+      cp_eqn = subst_ sub cp_eqn,+      cp_depth = cp_depth,+      cp_top = subst_ sub cp_top,+      cp_proof = subst_ sub cp_proof }++instance PrettyTerm f => Pretty (CriticalPair f) where+  pPrint CriticalPair{..} =+    vcat [+      pPrint cp_eqn,+      nest 2 (text "top:" <+> pPrint cp_top) ]++-- | Split a critical pair so that it can be turned into rules.+--+-- The resulting critical pairs have the property that no variable appears on+-- the right that is not on the left.++-- See the comment below.+split :: Function f => CriticalPair f -> [CriticalPair f]+split CriticalPair{cp_eqn = l :=: r, ..}+  | l == r = []+  | otherwise =+    -- If we have something which is almost a rule, except that some+    -- variables appear only on the right-hand side, e.g.:+    --   f x y -> g x z+    -- then we replace it with the following two rules:+    --   f x y -> g x ?+    --   g x z -> g x ?+    -- where the second rule is weakly oriented and ? is the minimal+    -- constant.+    --+    -- If we have an unoriented equation with a similar problem, e.g.:+    --   f x y = g x z+    -- then we replace it with potentially three rules:+    --   f x ? = g x ?+    --   f x y -> f x ?+    --   g x z -> g x ?++    -- The main rule l -> r' or r -> l' or l' = r'+    [ CriticalPair {+        cp_eqn   = l :=: r',+        cp_depth = cp_depth,+        cp_top   = eraseExcept (vars l) cp_top,+        cp_proof = eraseExcept (vars l) cp_proof }+    | ord == Just GT ] +++    [ CriticalPair {+        cp_eqn   = r :=: l',+        cp_depth = cp_depth,+        cp_top   = eraseExcept (vars r) cp_top,+        cp_proof = Proof.symm (eraseExcept (vars r) cp_proof) }+    | ord == Just LT ] +++    [ CriticalPair {+        cp_eqn   = l' :=: r',+        cp_depth = cp_depth,+        cp_top   = eraseExcept (vars l) $ eraseExcept (vars r) cp_top,+        cp_proof = eraseExcept (vars l) $ eraseExcept (vars r) cp_proof }+    | ord == Nothing ] ++++    -- Weak rules l -> l' or r -> r'+    [ CriticalPair {+        cp_eqn   = l :=: l',+        cp_depth = cp_depth + 1,+        cp_top   = Nothing,+        cp_proof = cp_proof `Proof.trans` Proof.symm (erase ls cp_proof) }+    | not (null ls), ord /= Just GT ] +++    [ CriticalPair {+        cp_eqn   = r :=: r',+        cp_depth = cp_depth + 1,+        cp_top   = Nothing,+        cp_proof = Proof.symm cp_proof `Proof.trans` erase rs cp_proof }+    | not (null rs), ord /= Just LT ]+    where+      ord = orientTerms l' r'+      l' = erase ls l+      r' = erase rs r+      ls = usort (vars l) \\ usort (vars r)+      rs = usort (vars r) \\ usort (vars l)++      eraseExcept vs t =+        erase (usort (vars t) \\ usort vs) t++-- | Make a critical pair from two rules and an overlap.+{-# INLINEABLE makeCriticalPair #-}+makeCriticalPair ::+  (Has a (Rule f), Has a (Lemma f), Has a Id, Function f) =>+  a -> a -> Overlap f -> Maybe (CriticalPair f)+makeCriticalPair r1 r2 overlap@Overlap{..}+  | lessEq overlap_top t = Nothing+  | lessEq overlap_top u = Nothing+  | otherwise =+    Just $+      CriticalPair overlap_eqn+        overlap_depth+        (Just overlap_top)+        (overlapProof r1 r2 overlap)+  where+    t :=: u = overlap_eqn++-- | Return a proof for a critical pair.+{-# INLINEABLE overlapProof #-}+overlapProof ::+  forall a f.+  (Has a (Rule f), Has a (Lemma f), Has a Id) =>+  a -> a -> Overlap f -> Derivation f+overlapProof left right Overlap{..} =+  Proof.symm (reductionProof (step left leftSub))+  `Proof.trans`+  congPath path overlap_top (reductionProof (step right rightSub))+  where+    Just leftSub = match (lhs (the left)) overlap_top+    Just rightSub = match (lhs (the right)) overlap_inner++    path = positionToPath (lhs (the left) :: Term f) overlap_pos
+ Twee/Constraints.hs view
@@ -0,0 +1,312 @@+{-# LANGUAGE FlexibleContexts, UndecidableInstances, RecordWildCards #-}+-- | Solving constraints on variable ordering.+module Twee.Constraints where++--import Twee.Base hiding (equals, Term, pattern Fun, pattern Var, lookup, funs)+import qualified Twee.Term as Flat+import qualified Data.Map.Strict as Map+import Twee.Pretty hiding (equals)+import Twee.Utils+import Data.Maybe+import Data.List+import Data.Function+import Data.Graph+import Data.Map.Strict(Map)+import Data.Ord+import Twee.Term hiding (lookup)++data Atom f = Constant (Fun f) | Variable Var deriving (Show, Eq, Ord)++{-# INLINE atoms #-}+atoms :: Term f -> [Atom f]+atoms t = aux (singleton t)+  where+    aux Empty = []+    aux (Cons (App f Empty) t) = Constant f:aux t+    aux (Cons (Var x) t) = Variable x:aux t+    aux (ConsSym _ t) = aux t++toTerm :: Atom f -> Term f+toTerm (Constant f) = build (con f)+toTerm (Variable x) = build (var x)++fromTerm :: Flat.Term f -> Maybe (Atom f)+fromTerm (App f Empty) = Just (Constant f)+fromTerm (Var x) = Just (Variable x)+fromTerm _ = Nothing++instance PrettyTerm f => Pretty (Atom f) where+  pPrint = pPrint . toTerm++data Formula f =+    Less   (Atom f) (Atom f)+  | LessEq (Atom f) (Atom f)+  | And [Formula f]+  | Or  [Formula f]+  deriving (Eq, Ord, Show)++instance PrettyTerm f => Pretty (Formula f) where+  pPrintPrec _ _ (Less t u) = hang (pPrint t <+> text "<") 2 (pPrint u)+  pPrintPrec _ _ (LessEq t u) = hang (pPrint t <+> text "<=") 2 (pPrint u)+  pPrintPrec _ _ (And []) = text "true"+  pPrintPrec _ _ (Or []) = text "false"+  pPrintPrec l p (And xs) =+    maybeParens (p > 10)+      (fsep (punctuate (text " &") (nest_ (map (pPrintPrec l 11) xs))))+    where+      nest_ (x:xs) = x:map (nest 2) xs+      nest_ [] = undefined+  pPrintPrec l p (Or xs) =+    maybeParens (p > 10)+      (fsep (punctuate (text " |") (nest_ (map (pPrintPrec l 11) xs))))+    where+      nest_ (x:xs) = x:map (nest 2) xs+      nest_ [] = undefined++negateFormula :: Formula f -> Formula f+negateFormula (Less t u) = LessEq u t+negateFormula (LessEq t u) = Less u t+negateFormula (And ts) = Or (map negateFormula ts)+negateFormula (Or ts) = And (map negateFormula ts)++conj forms+  | false `elem` forms' = false+  | otherwise =+    case forms' of+      [x] -> x+      xs  -> And xs+  where+    flatten (And xs) = xs+    flatten x = [x]+    forms' = filter (/= true) (usort (concatMap flatten forms))+disj forms+  | true `elem` forms' = true+  | otherwise =+    case forms' of+      [x] -> x+      xs  -> Or xs+  where+    flatten (Or xs) = xs+    flatten x = [x]+    forms' = filter (/= false) (usort (concatMap flatten forms))++x &&& y = conj [x, y]+x ||| y = disj [x, y]+true  = And []+false = Or []++data Branch f =+  -- Branches are kept normalised wrt equals+  Branch {+    funs        :: [Fun f],+    less        :: [(Atom f, Atom f)],  -- sorted+    equals      :: [(Atom f, Atom f)] } -- sorted, greatest atom first in each pair+  deriving (Eq, Ord)++instance PrettyTerm f => Pretty (Branch f) where+  pPrint Branch{..} =+    braces $ fsep $ punctuate (text ",") $+      [pPrint x <+> text "<" <+> pPrint y | (x, y) <- less ] +++      [pPrint x <+> text "=" <+> pPrint y | (x, y) <- equals ]++trueBranch :: Branch f+trueBranch = Branch [] [] []++norm :: Eq f => Branch f -> Atom f -> Atom f+norm Branch{..} x = fromMaybe x (lookup x equals)++contradictory :: (Minimal f, Ord f) => Branch f -> Bool+contradictory Branch{..} =+  or [f == minimal | (_, Constant f) <- less] ||+  or [f /= g | (Constant f, Constant g) <- equals] ||+  any cyclic (stronglyConnComp+    [(x, x, [y | (x', y) <- less, x == x']) | x <- usort (map fst less)])+  where+    cyclic (AcyclicSCC _) = False+    cyclic (CyclicSCC _) = True++formAnd :: (Minimal f, Ordered f) => Formula f -> [Branch f] -> [Branch f]+formAnd f bs = usort (bs >>= add f)+  where+    add (Less t u) b = addLess t u b+    add (LessEq t u) b = addLess t u b ++ addEquals t u b+    add (And []) b = [b]+    add (And (f:fs)) b = add f b >>= add (And fs)+    add (Or fs) b = usort (concat [ add f b | f <- fs ])++branches :: (Minimal f, Ordered f) => Formula f -> [Branch f]+branches x = aux [x]+  where+    aux [] = [Branch [] [] []]+    aux (And xs:ys) = aux (xs ++ ys)+    aux (Or xs:ys) = usort $ concat [aux (x:ys) | x <- xs]+    aux (Less t u:xs) = usort $ concatMap (addLess t u) (aux xs)+    aux (LessEq t u:xs) =+      usort $+      concatMap (addLess t u) (aux xs) +++      concatMap (addEquals u t) (aux xs)++addLess :: (Minimal f, Ordered f) => Atom f -> Atom f -> Branch f -> [Branch f]+addLess _ (Constant min) _ | min == minimal = []+addLess (Constant min) _ b | min == minimal = [b]+addLess t0 u0 b@Branch{..} =+  filter (not . contradictory)+    [addTerm t (addTerm u b{less = usort ((t, u):less)})]+  where+    t = norm b t0+    u = norm b u0++addEquals :: (Minimal f, Ordered f) => Atom f -> Atom f -> Branch f -> [Branch f]+addEquals t0 u0 b@Branch{..}+  | t == u || (t, u) `elem` equals = [b]+  | otherwise =+    filter (not . contradictory)+      [addTerm t (addTerm u b {+         equals      = usort $ (t, u):[(x', y') | (x, y) <- equals, let (y', x') = sort2 (sub x, sub y), x' /= y'],+         less        = usort $ [(sub x, sub y) | (x, y) <- less] })]+  where+    sort2 (x, y) = (min x y, max x y)+    (u, t) = sort2 (norm b t0, norm b u0)++    sub x+      | x == t = u+      | otherwise = x++addTerm :: (Minimal f, Ordered f) => Atom f -> Branch f -> Branch f+addTerm (Constant f) b+  | f `notElem` funs b =+    b {+      funs = f:funs b,+      less =+        usort $+          [ (Constant f, Constant g) | g <- funs b, f << g ] +++          [ (Constant g, Constant f) | g <- funs b, g << f ] ++ less b }+addTerm _ b = b++newtype Model f = Model (Map (Atom f) (Int, Int))+  deriving (Eq, Show)+-- Representation: map from atom to (major, minor)+-- x <  y if major x < major y+-- x <= y if major x = major y and minor x < minor y++instance PrettyTerm f => Pretty (Model f) where+  pPrint (Model m)+    | Map.size m <= 1 = text "empty"+    | otherwise = fsep (go (sortBy (comparing snd) (Map.toList m)))+      where+        go [(x, _)] = [pPrint x]+        go ((x, (i, _)):xs@((_, (j, _)):_)) =+          (pPrint x <+> text rel):go xs+          where+            rel = if i == j then "<=" else "<"++modelToLiterals :: Model f -> [Formula f]+modelToLiterals (Model m) = go (sortBy (comparing snd) (Map.toList m))+  where+    go []  = []+    go [_] = []+    go ((x, (i, _)):xs@((y, (j, _)):_)) =+      rel x y:go xs+      where+        rel = if i == j then LessEq else Less++modelFromOrder :: (Minimal f, Ord f) => [Atom f] -> Model f+modelFromOrder xs =+  Model (Map.fromList [(x, (i, i)) | (x, i) <- zip xs [0..]])++weakenModel :: Model f -> [Model f]+weakenModel (Model m) =+  [ Model (Map.delete x m) | x <- Map.keys m ] +++  [ Model (Map.fromList xs)+  | xs <- glue (sortBy (comparing snd) (Map.toList m)),+    all ok (groupBy ((==) `on` (fst . snd)) xs) ]+  where+    glue [] = []+    glue [_] = []+    glue (a@(_x, (i1, j1)):b@(y, (i2, _)):xs) =+      [ (a:(y, (i1, j1+1)):xs) | i1 < i2 ] +++      map (a:) (glue (b:xs))++    -- We must never make two constants equal+    ok xs = length [x | (Constant x, _) <- xs] <= 1++varInModel :: (Minimal f, Ord f) => Model f -> Var -> Bool+varInModel (Model m) x = Variable x `Map.member` m++varGroups :: (Minimal f, Ord f) => Model f -> [(Fun f, [Var], Maybe (Fun f))]+varGroups (Model m) = filter nonempty (go minimal (map fst (sortBy (comparing snd) (Map.toList m))))+  where+    go f xs =+      case span isVariable xs of+        (_, []) -> [(f, map unVariable xs, Nothing)]+        (ys, Constant g:zs) ->+          (f, map unVariable ys, Just g):go g zs+    isVariable (Constant _) = False+    isVariable (Variable _) = True+    unVariable (Variable x) = x+    nonempty (_, [], _) = False+    nonempty _ = True++class Minimal f where+  minimal :: Fun f++{-# INLINE lessEqInModel #-}+lessEqInModel :: (Minimal f, Ordered f) => Model f -> Atom f -> Atom f -> Maybe Strictness+lessEqInModel (Model m) x y+  | Just (a, _) <- Map.lookup x m,+    Just (b, _) <- Map.lookup y m,+    a < b = Just Strict+  | Just a <- Map.lookup x m,+    Just b <- Map.lookup y m,+    a < b = Just Nonstrict+  | x == y = Just Nonstrict+  | Constant a <- x, Constant b <- y, a << b = Just Strict+  | Constant a <- x, a == minimal = Just Nonstrict+  | otherwise = Nothing++solve :: (Minimal f, Ordered f, PrettyTerm f) => [Atom f] -> Branch f -> Either (Model f) (Subst f)+solve xs branch@Branch{..}+  | null equals && not (all true less) =+    error $ "Model " ++ prettyShow model ++ " is not a model of " ++ prettyShow branch ++ " (edges = " ++ prettyShow edges ++ ", vs = " ++ prettyShow vs ++ ")"+  | null equals = Left model+  | otherwise = Right sub+    where+      sub = fromMaybe undefined . listToSubst $+        [(x, toTerm y) | (Variable x, y) <- equals] +++        [(y, toTerm x) | (x@Constant{}, Variable y) <- equals]+      vs = Constant minimal:reverse (flattenSCCs (stronglyConnComp edges))+      edges = [(x, x, [y | (x', y) <- less', x == x']) | x <- as, x /= Constant minimal]+      less' = less ++ [(Constant x, Constant y) | Constant x <- as, Constant y <- as, x << y]+      as = usort $ xs ++ map fst less ++ map snd less+      model = modelFromOrder vs+      true (t, u) = lessEqInModel model t u == Just Strict++class Ord f => Ordered f where+  -- | Return 'True' if the first term is less than or equal to the second,+  -- in the term ordering.+  lessEq :: Term f -> Term f -> Bool+  -- | Check if the first term is less than or equal to the second in the given model,+  -- and decide whether the inequality is strict or nonstrict.+  lessIn :: Model f -> Term f -> Term f -> Maybe Strictness++-- | Describes whether an inequality is strict or nonstrict.+data Strictness =+    -- | The first term is strictly less than the second.+    Strict+    -- | The first term is less than or equal to the second.+  | Nonstrict deriving (Eq, Show)++-- | Return 'True' if the first argument is strictly less than the second,+-- in the term ordering.+lessThan :: Ordered f => Term f -> Term f -> Bool+lessThan t u = lessEq t u && isNothing (unify t u)++-- | Return the direction in which the terms are oriented according to the term+-- ordering, or 'Nothing' if they cannot be oriented. A result of @'Just' 'LT'@+-- means that the first term is less than /or equal to/ the second.+orientTerms :: Ordered f => Term f -> Term f -> Maybe Ordering+orientTerms t u+  | t == u = Just EQ+  | lessEq t u = Just LT+  | lessEq u t = Just GT+  | otherwise = Nothing
+ Twee/Equation.hs view
@@ -0,0 +1,58 @@+-- | Equations.+{-# LANGUAGE TypeFamilies #-}+module Twee.Equation where++import Twee.Base+import Data.Maybe+import Control.Monad++--------------------------------------------------------------------------------+-- * Equations.+--------------------------------------------------------------------------------++data Equation f =+  (:=:) {+    eqn_lhs :: {-# UNPACK #-} !(Term f),+    eqn_rhs :: {-# UNPACK #-} !(Term f) }+  deriving (Eq, Ord, Show)+type EquationOf a = Equation (ConstantOf a)++instance Symbolic (Equation f) where+  type ConstantOf (Equation f) = f+  termsDL (t :=: u) = termsDL t `mplus` termsDL u+  subst_ sub (t :=: u) = subst_ sub t :=: subst_ sub u++instance PrettyTerm f => Pretty (Equation f) where+  pPrint (x :=: y) = pPrint x <+> text "=" <+> pPrint y++instance Sized f => Sized (Equation f) where+  size (x :=: y) = size x + size y++-- | Order an equation roughly left-to-right.+-- However, there is no guarantee that the result is oriented.+order :: Function f => Equation f -> Equation f+order (l :=: r)+  | l == r = l :=: r+  | otherwise =+    case compare (size l) (size r) of+      LT -> r :=: l+      GT -> l :=: r+      EQ -> if lessEq l r then r :=: l else l :=: r++-- | Apply a function to both sides of an equation.+bothSides :: (Term f -> Term f') -> Equation f -> Equation f'+bothSides f (t :=: u) = f t :=: f u++-- | Is an equation of the form t = t?+trivial :: Eq f => Equation f -> Bool+trivial (t :=: u) = t == u++simplerThan :: Function f => Equation f -> Equation f -> Bool+eq1 `simplerThan` eq2 =+  t1 `lessEq` t2 &&+  (isNothing (unify t1 t2) || (u1 `lessEq` u2))+  where+    t1 :=: u1 = skolemise eq1+    t2 :=: u2 = skolemise eq2++    skolemise = subst (con . skolem)
+ Twee/Index.hs view
@@ -0,0 +1,310 @@+-- | A term index to accelerate matching.+-- An index is a multimap from terms to arbitrary values.+--+-- The type of query supported is: given a search term, find all keys such that+-- the search term is an instance of the key, and return the corresponding+-- values.++{-# LANGUAGE BangPatterns, RecordWildCards, OverloadedStrings, FlexibleContexts #-}+-- We get some bogus warnings because of pattern synonyms.+{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}+module Twee.Index(+  Index,+  empty,+  null,+  singleton,+  insert,+  delete,+  lookup,+  matches,+  approxMatches,+  elems) where++import qualified Prelude+import Prelude hiding (null, lookup)+import Data.Maybe+import Twee.Base hiding (var, fun, empty, size, singleton, prefix, funs, lookupList, lookup)+import qualified Twee.Term as Term+import Twee.Term.Core(TermList(..))+import Data.DynamicArray+import qualified Data.List as List++-- The term index in this module is an _imperfect discrimination tree_.+-- This is a trie whose keys are terms, represented as flat lists of symbols,+-- but where all variables have been replaced by a single don't-care variable '_'.+-- That is, the edges of the trie can be either function symbols or '_'.+-- To insert a key-value pair into the discrimination tree, we first replace all+-- variables in the key with '_', and then do ordinary trie insertion.+--+-- Lookup maintains a term list, which is initially the search term.+-- It proceeds down the trie, consuming bits of the term list as it goes.+--+-- If the current trie node has an edge for a function symbol f, and the term at+-- the head of the term list is f(t1..tn), we can follow the f edge. We then+-- delete f from the term list, but keep t1..tn at the front of the term list.+-- (In other words we delete only the symbol f and not its arguments.)+--+-- If the current trie node has an edge for '_', we can always follow that edge.+-- We then remove the head term from the term list, as the '_' represents a+-- variable that should match that whole term.+--+-- If the term list ever becomes empty, we have a possible match. We then+-- do matching on the values stored at the current node to see if they are+-- genuine matches.+--+-- Often there are two edges we can follow (function symbol and '_'), and in+-- that case the algorithm uses backtracking.++-- | A term index: a multimap from @'Term' f@ to @a@.+data Index f a =+  -- A non-empty index.+  Index {+    -- Size of smallest term in index.+    size   :: {-# UNPACK #-} !Int,+    -- When all keys in the index start with the same sequence of symbols, we+    -- compress them into this prefix; the "fun" and "var" fields below refer to+    -- the first symbol _after_ the prefix, and the "here" field contains values+    -- whose remaining key is exactly this prefix.+    prefix :: {-# UNPACK #-} !(TermList f),+    -- The values that are found at this node.+    here   :: [a],+    -- Function symbol edges.+    -- The array is indexed by function number.+    fun    :: {-# UNPACK #-} !(Array (Index f a)),+    -- Variable edge.+    var    :: !(Index f a) } |+  -- An empty index.+  Nil+  deriving Show++instance Default (Index f a) where def = Nil++-- To get predictable performance, the lookup function uses an explicit stack+-- instead of recursion to control backtracking.+data Stack f a =+  -- A normal stack frame: records the current index node and term.+  Frame {+    frame_term  :: {-# UNPACK #-} !(TermList f),+    frame_index :: !(Index f a),+    frame_rest  :: !(Stack f a) }+  -- A stack frame which is used when we have found a match.+  | Yield {+    yield_found :: [a],+    yield_rest  :: !(Stack f a) }+  -- End of stack.+  | Stop++-- Turn a stack into a list of results.+run :: Stack f a -> [a]+run Stop = []+run Frame{..} = run ({-# SCC run_inner #-} step frame_term frame_index frame_rest)+run Yield{..} = {-# SCC run_found #-} yield_found ++ run yield_rest++-- Execute a single stack frame.+{-# INLINE step #-}+step :: TermList f -> Index f a -> Stack f a -> Stack f a+step !_ _ _ | False = undefined+step t idx rest =+  case idx of+    Nil -> rest+    Index{..}+      | lenList t < size ->+        rest -- the search term is smaller than any in this index+      | otherwise ->+        pref t prefix here fun var rest++-- The main work of 'step' goes on here.+-- It is carefully tweaked to generate nice code,+-- including using UnsafeCons and only casing on each+-- term list exactly once.+pref :: TermList f -> TermList f -> [a] -> Array (Index f a) -> Index f a -> Stack f a -> Stack f a+pref !_ !_ _ !_ !_ _ | False = undefined+pref search prefix here fun var rest =+  case search of+    Empty ->+      case prefix of+        Empty ->+          -- The search term matches this node.+          case here of+            [] -> rest+            _ -> Yield here rest+        _ ->+          -- We've run out of search term - it doesn't match this node.+          rest+    UnsafeCons t ts ->+      case prefix of+        Cons u us ->+          -- Check the search term against the prefix.+          case (t, u) of+            (_, Var _) ->+              -- Prefix contains a variable - if there is a match, the+              -- variable will be bound to t.+              pref ts us here fun var rest+            (App f _, App g _) | f == g ->+              -- Term and prefix start with same symbol, chop them off.+               let+                 UnsafeConsSym _ ts' = search+                 UnsafeConsSym _ us' = prefix+               in pref ts' us' here fun var rest+            _ ->+              -- Term and prefix don't match.+              rest+        _ ->+          -- We've exhausted the prefix, so let's descend into the tree.+          -- Seems to work better to explore the function node first.+          let+            tryVar =+              case var of+                Nil -> rest+                Index{} -> Frame ts var rest+              where+                UnsafeCons _ ts = search++            tryFun =+              case t of+                App f _ ->+                  case fun ! fun_id f of+                    Nil -> tryVar+                    idx -> Frame ts idx $! tryVar+                _ ->+                  tryVar+              where+                UnsafeConsSym t ts = search+          in+            tryFun++-- | An empty index.+empty :: Index f a+empty = Nil++-- | Is the index empty?+null :: Index f a -> Bool+null Nil = True+null _ = False++-- | An index with one entry.+singleton :: Term f -> a -> Index f a+singleton !t x = singletonList (Term.singleton t) x++-- An index with one entry, giving a termlist instead of a term.+{-# INLINE singletonList #-}+singletonList :: TermList f -> a -> Index f a+singletonList t x = Index 0 t [x] newArray Nil++-- | Insert an entry into the index.+insert :: Term f -> a -> Index f a -> Index f a+insert !t x !idx = {-# SCC insert #-} aux (Term.singleton t) idx+  where+    aux t Nil = singletonList t x+    aux (Cons t ts) idx@Index{prefix = Cons u us} | t == u =+      withPrefix (Term.singleton t) (aux ts idx{prefix = us})+    aux t idx@Index{prefix = Cons{}} = aux t (expand idx)++    aux Empty idx =+      idx { size = 0, here = x:here idx }+    aux t@(ConsSym (App f _) u) idx =+      idx {+        size = lenList t `min` size idx,+        fun  = update (fun_id f) idx' (fun idx) }+      where+        idx' = aux u (fun idx ! fun_id f)+    aux t@(ConsSym (Var _) u) idx =+      idx {+        size = lenList t `min` size idx,+        var  = aux u (var idx) }++-- Add a prefix to an index.+-- Does not update the size field.+{-# INLINE withPrefix #-}+withPrefix :: TermList f -> Index f a -> Index f a+withPrefix Empty idx = idx+withPrefix _ Nil = Nil+withPrefix t idx@Index{..} =+  idx{prefix = buildList (builder t `mappend` builder prefix)}++-- Take an index with a prefix and pull out the first symbol of the prefix,+-- giving an index which doesn't start with a prefix.+{-# INLINE expand #-}+expand :: Index f a -> Index f a+expand idx@Index{size = size, prefix = ConsSym t ts} =+  case t of+    Var _ ->+      Index {+        size = size,+        prefix = Term.empty,+        here = [],+        fun = newArray,+        var = idx { prefix = ts, size = size - 1 } }+    App f _ ->+      Index {+        size = size,+        prefix = Term.empty,+        here = [],+        fun = update (fun_id f) idx { prefix = ts, size = size - 1 } newArray,+        var = Nil }++-- | Delete an entry from the index.+{-# INLINEABLE delete #-}+delete :: Eq a => Term f -> a -> Index f a -> Index f a+delete !t x !idx = {-# SCC delete #-} aux (Term.singleton t) idx+  where+    aux _ Nil = Nil+    aux (Cons t ts) idx@Index{prefix = Cons u us} | t == u =+      withPrefix (Term.singleton t) (aux ts idx{prefix = us})+    aux _ idx@Index{prefix = Cons{}} = idx++    aux Empty idx+      | x `List.elem` here idx =+        idx { here = List.delete x (here idx) }+      | otherwise =+        error "deleted term not found in index"+    aux (ConsSym (App f _) t) idx =+      idx { fun = update (fun_id f) (aux t (fun idx ! fun_id f)) (fun idx) }+    aux (ConsSym (Var _) t) idx =+      idx { var = aux t (var idx) }++-- | Look up a term in the index. Finds all key-value such that the search term+-- is an instance of the key, and returns an instance of the the value which+-- makes the search term exactly equal to the key.+{-# INLINE lookup #-}+lookup :: (Has a b, Symbolic b, Has b (TermOf b)) => TermOf b -> Index (ConstantOf b) a -> [b]+lookup t idx = lookupList (Term.singleton t) idx++{-# INLINEABLE lookupList #-}+lookupList :: (Has a b, Symbolic b, Has b (TermOf b)) => TermListOf b -> Index (ConstantOf b) a -> [b]+lookupList t idx =+  [ subst sub x+  | x <- List.map the (approxMatchesList t idx),+    sub <- maybeToList (matchList (Term.singleton (the x)) t)]++-- | Look up a term in the index. Like 'lookup', but returns the exact value+-- that was inserted into the index, not an instance. Also returns a substitution+-- which when applied to the value gives you the matching instance.+{-# INLINE matches #-}+matches :: Has a (Term f) => Term f -> Index f a -> [(Subst f, a)]+matches t idx = matchesList (Term.singleton t) idx++{-# INLINEABLE matchesList #-}+matchesList :: Has a (Term f) => TermList f -> Index f a -> [(Subst f, a)]+matchesList t idx =+  [ (sub, x)+  | x <- approxMatchesList t idx,+    sub <- maybeToList (matchList (Term.singleton (the x)) t)]++-- | Look up a term in the index, possibly returning spurious extra results.+{-# INLINE approxMatches #-}+approxMatches :: Term f -> Index f a -> [a]+approxMatches t idx = approxMatchesList (Term.singleton t) idx++approxMatchesList :: TermList f -> Index f a -> [a]+approxMatchesList t idx =+  {-# SCC approxMatchesList #-}+  run (Frame t idx Stop)++-- | Return all elements of the index.+elems :: Index f a -> [a]+elems Nil = []+elems idx =+  here idx +++  concatMap elems (Prelude.map snd (toList (fun idx))) +++  elems (var idx)
+ Twee/Join.hs view
@@ -0,0 +1,212 @@+-- | Tactics for joining critical pairs.+{-# LANGUAGE FlexibleContexts, BangPatterns, RecordWildCards, TypeFamilies #-}+module Twee.Join where++import Twee.Base+import Twee.Rule+import Twee.Equation+import Twee.Proof(Lemma)+import qualified Twee.Proof as Proof+import Twee.CP hiding (Config)+import Twee.Constraints+import qualified Twee.Index as Index+import Twee.Index(Index)+import Twee.Rule.Index(RuleIndex(..))+import Twee.Utils+import Data.Maybe+import Data.Either+import Data.Ord+import qualified Data.Set as Set++data Config =+  Config {+    cfg_ground_join :: !Bool,+    cfg_use_connectedness :: !Bool,+    cfg_set_join :: !Bool }++defaultConfig :: Config+defaultConfig =+  Config {+    cfg_ground_join = True,+    cfg_use_connectedness = True,+    cfg_set_join = False }++{-# INLINEABLE joinCriticalPair #-}+joinCriticalPair ::+  (Function f, Has a (Rule f), Has a (Lemma f)) =>+  Config ->+  Index f (Equation f) -> RuleIndex f a ->+  Maybe (Model f) -> -- A model to try before checking ground joinability+  CriticalPair f ->+  Either+    -- Failed to join critical pair.+    -- Returns simplified critical pair and model in which it failed to hold.+    (CriticalPair f, Model f)+    -- Split critical pair into several instances.+    -- Returns list of instances which must be joined,+    -- and an optional equation which can be added to the joinable set+    -- after successfully joining all instances.+    (Maybe (CriticalPair f), [CriticalPair f])+joinCriticalPair config eqns idx mmodel cp@CriticalPair{cp_eqn = t :=: u} =+  {-# SCC joinCriticalPair #-}+  case allSteps config eqns idx cp of+    Nothing ->+      Right (Nothing, [])+    _ | cfg_set_join config &&+        not (null $ Set.intersection+          (normalForms (rewrite reduces (index_all idx)) [reduce (Refl t)])+          (normalForms (rewrite reduces (index_all idx)) [reduce (Refl u)])) ->+      Right (Just cp, [])+    Just cp ->+      case groundJoinFromMaybe config eqns idx mmodel (branches (And [])) cp of+        Left model -> Left (cp, model)+        Right cps -> Right (Just cp, cps)++{-# INLINEABLE step1 #-}+{-# INLINEABLE step2 #-}+{-# INLINEABLE step3 #-}+{-# INLINEABLE allSteps #-}+step1, step2, step3, allSteps ::+  (Function f, Has a (Rule f), Has a (Lemma f)) =>+  Config -> Index f (Equation f) -> RuleIndex f a -> CriticalPair f -> Maybe (CriticalPair f)+allSteps config eqns idx cp =+  step1 config eqns idx cp >>=+  step2 config eqns idx >>=+  step3 config eqns idx+step1 _ eqns idx = joinWith eqns idx (\t _ -> normaliseWith (const True) (rewrite reducesOriented (index_oriented idx)) t)+step2 _ eqns idx = joinWith eqns idx (\t _ -> normaliseWith (const True) (rewrite reduces (index_all idx)) t)+step3 Config{..} eqns idx cp+  | not cfg_use_connectedness = Just cp+  | otherwise =+    case cp_top cp of+      Just top ->+        case (join (cp, top), join (flipCP (cp, top))) of+          (Just _, Just _) -> Just cp+          _ -> Nothing+      _ -> Just cp+  where+    join (cp, top) =+      joinWith eqns idx (\t u -> normaliseWith (`lessThan` top) (rewrite (ok t u) (index_all idx)) t) cp++    ok t u rule sub =+      unorient rule `simplerThan` (t :=: u) &&+      reducesSkolem rule sub++    flipCP :: Symbolic a => a -> a+    flipCP t = subst sub t+      where+        n = maximum (0:map fromEnum (vars t))+        sub (V x) = var (V (n - x))+++{-# INLINEABLE joinWith #-}+joinWith ::+  (Has a (Rule f), Has a (Lemma f)) =>+  Index f (Equation f) -> RuleIndex f a -> (Term f -> Term f -> Resulting f) -> CriticalPair f -> Maybe (CriticalPair f)+joinWith eqns idx reduce cp@CriticalPair{cp_eqn = lhs :=: rhs, ..}+  | subsumed eqns idx eqn = Nothing+  | otherwise =+    Just cp {+      cp_eqn = eqn,+      cp_proof =+        Proof.symm (reductionProof (reduction lred)) `Proof.trans`+        cp_proof `Proof.trans`+        reductionProof (reduction rred) }+  where+    lred = reduce lhs rhs+    rred = reduce rhs lhs+    eqn = result lred :=: result rred++{-# INLINEABLE subsumed #-}+subsumed ::+  (Has a (Rule f), Has a (Lemma f)) =>+  Index f (Equation f) -> RuleIndex f a -> Equation f -> Bool+subsumed eqns idx (t :=: u)+  | t == u = True+  | or [ rhs rule == u | rule <- Index.lookup t (index_all idx) ] = True+  | or [ rhs rule == t | rule <- Index.lookup u (index_all idx) ] = True+    -- No need to do this symmetrically because addJoinable adds+    -- both orientations of each equation+  | or [ u == subst sub u'+       | t' :=: u' <- Index.approxMatches t eqns,+         sub <- maybeToList (match t' t) ] = True+subsumed eqns idx (App f ts :=: App g us)+  | f == g =+    let+      sub Empty Empty = True+      sub (Cons t ts) (Cons u us) =+        subsumed eqns idx (t :=: u) && sub ts us+      sub _ _ = error "Function used with multiple arities"+    in+      sub ts us+subsumed _ _ _ = False++{-# INLINEABLE groundJoin #-}+groundJoin ::+  (Function f, Has a (Rule f), Has a (Lemma f)) =>+  Config -> Index f (Equation f) -> RuleIndex f a -> [Branch f] -> CriticalPair f -> Either (Model f) [CriticalPair f]+groundJoin config eqns idx ctx cp@CriticalPair{cp_eqn = t :=: u, ..} =+  case partitionEithers (map (solve (usort (atoms t ++ atoms u))) ctx) of+    ([], instances) ->+      let cps = [ subst sub cp | sub <- instances ] in+      Right (usortBy (comparing (canonicalise . order . cp_eqn)) cps)+    (model:_, _) ->+      groundJoinFrom config eqns idx model ctx cp++{-# INLINEABLE groundJoinFrom #-}+groundJoinFrom ::+  (Function f, Has a (Rule f), Has a (Lemma f)) =>+  Config -> Index f (Equation f) -> RuleIndex f a -> Model f -> [Branch f] -> CriticalPair f -> Either (Model f) [CriticalPair f]+groundJoinFrom config@Config{..} eqns idx model ctx cp@CriticalPair{cp_eqn = t :=: u, ..}+  | not cfg_ground_join ||+    (modelOK model && isJust (allSteps config eqns idx cp { cp_eqn = t' :=: u' })) = Left model+  | otherwise =+      let model1 = optimise model weakenModel (\m -> not (modelOK m) || (valid m (reduction nt) && valid m (reduction nu)))+          model2 = optimise model1 weakenModel (\m -> not (modelOK m) || isNothing (allSteps config eqns idx cp { cp_eqn = result (normaliseIn m t u) :=: result (normaliseIn m u t) }))++          diag [] = Or []+          diag (r:rs) = negateFormula r ||| (weaken r &&& diag rs)+          weaken (LessEq t u) = Less t u+          weaken x = x+          ctx' = formAnd (diag (modelToLiterals model2)) ctx in++      groundJoin config eqns idx ctx' cp+  where+    normaliseIn m t u = normaliseWith (const True) (rewrite (ok t u m) (index_all idx)) t+    ok t u m rule sub =+      reducesInModel m rule sub &&+      unorient rule `simplerThan` (t :=: u)++    nt = normaliseIn model t u+    nu = normaliseIn model u t+    t' = result nt+    u' = result nu++    -- XXX not safe to exploit the top term if we then add the equation to+    -- the joinable set. (It might then be used to join a CP with an entirely+    -- different top term.)+    modelOK _ = True+{-    modelOK m =+      case cp_top of+        Nothing -> True+        Just top ->+          isNothing (lessIn m top t) && isNothing (lessIn m top u)-}++{-# INLINEABLE groundJoinFromMaybe #-}+groundJoinFromMaybe ::+  (Function f, Has a (Rule f), Has a (Lemma f)) =>+  Config -> Index f (Equation f) -> RuleIndex f a -> Maybe (Model f) -> [Branch f] -> CriticalPair f -> Either (Model f) [CriticalPair f]+groundJoinFromMaybe config eqns idx Nothing = groundJoin config eqns idx+groundJoinFromMaybe config eqns idx (Just model) = groundJoinFrom config eqns idx model++{-# INLINEABLE valid #-}+valid :: Function f => Model f -> Reduction f -> Bool+valid model red =+  and [ reducesInModel model rule sub+      | Step _ rule sub <- steps red ]++optimise :: a -> (a -> [a]) -> (a -> Bool) -> a+optimise x f p =+  case filter p (f x) of+    y:_ -> optimise y f p+    _   -> x
+ Twee/KBO.hs view
@@ -0,0 +1,121 @@+-- | An implementation of Knuth-Bendix ordering.++{-# LANGUAGE PatternGuards #-}+module Twee.KBO(lessEq, lessIn) where++import Twee.Base hiding (lessEq, lessIn)+import Data.List+import Twee.Constraints hiding (lessEq, lessIn)+import qualified Data.Map.Strict as Map+import Data.Map.Strict(Map)+import Data.Maybe+import Control.Monad++-- | Check if one term is less than another in KBO.+lessEq :: Function f => Term f -> Term f -> Bool+lessEq (App f Empty) _ | f == minimal = True+lessEq (Var x) (Var y) | x == y = True+lessEq _ (Var _) = False+lessEq (Var x) t = x `elem` vars t+lessEq t@(App f ts) u@(App g us) =+  (st < su ||+   (st == su && f << g) ||+   (st == su && f == g && lexLess ts us)) &&+  xs `isSubsequenceOf` ys+  where+    lexLess Empty Empty = True+    lexLess (Cons t ts) (Cons u us)+      | t == u = lexLess ts us+      | otherwise =+        lessEq t u &&+        case unify t u of+          Nothing -> True+          Just sub+            | not (allSubst (\_ (Cons t Empty) -> isMinimal t) sub) -> error "weird term inequality"+            | otherwise -> lexLess (subst sub ts) (subst sub us)+    lexLess _ _ = error "incorrect function arity"+    xs = sort (vars t)+    ys = sort (vars u)+    st = size t+    su = size u++-- | Check if one term is less than another in a given model.++-- See "notes/kbo under assumptions" for how this works.++lessIn :: Function f => Model f -> Term f -> Term f -> Maybe Strictness+lessIn model t u =+  case sizeLessIn model t u of+    Nothing -> Nothing+    Just Strict -> Just Strict+    Just Nonstrict -> lexLessIn model t u++sizeLessIn :: Function f => Model f -> Term f -> Term f -> Maybe Strictness+sizeLessIn model t u =+  case minimumIn model m of+    Just l+      | l >  -k -> Just Strict+      | l == -k -> Just Nonstrict+    _ -> Nothing+  where+    (k, m) =+      foldr (addSize id)+        (foldr (addSize negate) (0, Map.empty) (subterms t))+        (subterms u)+    addSize op (App f _) (k, m) = (k + op (size f), m)+    addSize op (Var x) (k, m) = (k, Map.insertWith (+) x (op 1) m)++minimumIn :: Function f => Model f -> Map Var Int -> Maybe Int+minimumIn model t =+  liftM2 (+)+    (fmap sum (mapM minGroup (varGroups model)))+    (fmap sum (mapM minOrphan (Map.toList t)))+  where+    minGroup (lo, xs, mhi)+      | all (>= 0) sums = Just (sum coeffs * size lo)+      | otherwise =+        case mhi of+          Nothing -> Nothing+          Just hi ->+            let coeff = negate (minimum coeffs) in+            Just $+              sum coeffs * size lo ++              coeff * (size lo - size hi)+      where+        coeffs = map (\x -> Map.findWithDefault 0 x t) xs+        sums = scanr1 (+) coeffs++    minOrphan (x, k)+      | varInModel model x = Just 0+      | k < 0 = Nothing+      | otherwise = Just k++lexLessIn :: Function f => Model f -> Term f -> Term f -> Maybe Strictness+lexLessIn _ t u | t == u = Just Nonstrict+lexLessIn cond t u+  | Just a <- fromTerm t,+    Just b <- fromTerm u,+    Just x <- lessEqInModel cond a b = Just x+  | Just a <- fromTerm t,+    any isJust+      [ lessEqInModel cond a b+      | v <- properSubterms u, Just b <- [fromTerm v]] =+        Just Strict+lexLessIn cond (App f ts) (App g us)+  | f == g = loop ts us+  | f << g = Just Strict+  | otherwise = Nothing+  where+    loop Empty Empty = Just Nonstrict+    loop (Cons t ts) (Cons u us)+      | t == u = loop ts us+      | otherwise =+        case lessIn cond t u of+          Nothing -> Nothing+          Just Strict -> Just Strict+          Just Nonstrict ->+            let Just sub = unify t u in+            loop (subst sub ts) (subst sub us)+    loop _ _ = error "incorrect function arity"+lexLessIn _ t _ | isMinimal t = Just Nonstrict+lexLessIn _ _ _ = Nothing
+ Twee/Label.hs view
@@ -0,0 +1,125 @@+-- | Assignment of unique IDs to values.+-- Inspired by the 'intern' package.++{-# LANGUAGE RecordWildCards, ScopedTypeVariables, BangPatterns #-}+module Twee.Label(Label, unsafeMkLabel, labelNum, label, find) where++import Data.IORef+import System.IO.Unsafe+import qualified Data.Map.Strict as Map+import Data.Map.Strict(Map)+import qualified Data.IntMap.Strict as IntMap+import Data.IntMap.Strict(IntMap)+import Data.Typeable+import GHC.Exts+import Unsafe.Coerce+import Data.Int++-- | A value of type @a@ which has been given a unique ID.+newtype Label a =+  Label {+    -- | The unique ID of a label.+    labelNum :: Int32 }+  deriving (Eq, Ord, Show)++-- | Construct a @'Label' a@ from its unique ID, which must be the 'labelNum' of+-- an already existing 'Label'. Extremely unsafe!+unsafeMkLabel :: Int32 -> Label a+unsafeMkLabel = Label++-- The global cache of labels.+{-# NOINLINE cachesRef #-}+cachesRef :: IORef Caches+cachesRef = unsafePerformIO (newIORef (Caches 0 Map.empty IntMap.empty))++data Caches =+  Caches {+    -- The next id number to assign.+    caches_nextId :: {-# UNPACK #-} !Int32,+    -- A map from values to labels.+    caches_from   :: !(Map TypeRep (Cache Any)),+    -- The reverse map from labels to values.+    caches_to     :: !(IntMap Any) }++type Cache a = Map a Int32++atomicModifyCaches :: (Caches -> (Caches, a)) -> IO a+atomicModifyCaches f = do+  -- N.B. atomicModifyIORef' ref f evaluates f ref *after* doing the+  -- compare-and-swap. This causes bad things to happen when 'label'+  -- is used reentrantly (i.e. the Ord instance itself calls label).+  -- This function only lets the swap happen if caches_nextId didn't+  -- change (i.e., no new values were inserted).+  !caches <- readIORef cachesRef+  -- First compute the update.+  let !(!caches', !x) = f caches+  -- Now see if anyone else updated the cache in between+  -- (can happen if f called 'label', or in a concurrent setting).+  ok <- atomicModifyIORef' cachesRef $ \cachesNow ->+    if caches_nextId caches == caches_nextId cachesNow+    then (caches', True)+    else (cachesNow, False)+  if ok then return x else atomicModifyCaches f++-- Versions of unsafeCoerce with slightly more type checking+toAnyCache :: Cache a -> Cache Any+toAnyCache = unsafeCoerce++fromAnyCache :: Cache Any -> Cache a+fromAnyCache = unsafeCoerce++toAny :: a -> Any+toAny = unsafeCoerce++fromAny :: Any -> a+fromAny = unsafeCoerce++-- | Assign a label to a value.+{-# NOINLINE label #-}+label :: forall a. (Typeable a, Ord a) => a -> Label a+label x =+  unsafeDupablePerformIO $ do+    -- Common case: label is already there.+    caches <- readIORef cachesRef+    case tryFind caches of+      Just l -> return l+      Nothing -> do+        -- Rare case: label was not there.+        x <- atomicModifyCaches $ \caches ->+          case tryFind caches of+            Just l -> (caches, l)+            Nothing ->+              insert caches+        return x++  where+    ty = typeOf x++    tryFind :: Caches -> Maybe (Label a)+    tryFind Caches{..} =+      Label <$> (Map.lookup ty caches_from >>= Map.lookup x . fromAnyCache)++    insert :: Caches -> (Caches, Label a)+    insert caches@Caches{..} =+      if n < 0 then error "label overflow" else+      (caches {+         caches_nextId = n+1,+         caches_from = Map.insert ty (toAnyCache (Map.insert x n cache)) caches_from,+         caches_to = IntMap.insert (fromIntegral n) (toAny x) caches_to },+       Label n)+      where+        n = caches_nextId+        cache =+          fromAnyCache $+          Map.findWithDefault Map.empty ty caches_from++-- | Recover the underlying value from a label.+find :: Label a -> a+-- N.B. must force n before calling readIORef, otherwise a call of+-- the form+--   find (label x)+-- doesn't work.+find (Label !n) = unsafeDupablePerformIO $ do+  Caches{..} <- readIORef cachesRef+  x <- return $! fromAny (IntMap.findWithDefault undefined (fromIntegral n) caches_to)+  return x
+ Twee/PassiveQueue.hs view
@@ -0,0 +1,183 @@+-- | A queue of passive critical pairs, using a memory-efficient representation.+{-# LANGUAGE TypeFamilies, RecordWildCards, FlexibleContexts, ScopedTypeVariables, StandaloneDeriving #-}+module Twee.PassiveQueue(+  Params(..),+  Queue,+  Passive(..),+  empty, insert, removeMin, mapMaybe) where++import qualified Data.Heap as Heap+import qualified Data.Vector.Unboxed as Vector+import Data.Int+import Data.List hiding (insert)+import qualified Data.Maybe+import Data.Ord+import Data.Proxy+import Twee.Utils++-- | A datatype representing all the type parameters of the queue.+class (Eq (Id params), Integral (Id params), Ord (Score params), Vector.Unbox (PackedScore params), Vector.Unbox (PackedId params)) => Params params where+  -- | The score assigned to critical pairs. Smaller scores are better.+  type Score params+  -- | The type of ID numbers used to name rules.+  type Id params++  -- | A 'Score' packed for storage into a 'Vector.Vector'. Must be an instance of 'Vector.Unbox'.+  type PackedScore params+  -- | An 'Id' packed for storage into a 'Vector.Vector'. Must be an instance of 'Vector.Unbox'.+  type PackedId params++  -- | Pack a 'Score'.+  packScore :: proxy params -> Score params -> PackedScore params+  -- | Unpack a 'PackedScore'.+  unpackScore :: proxy params -> PackedScore params -> Score params+  -- | Pack an 'Id'.+  packId :: proxy params -> Id params -> PackedId params+  -- | Unpack a 'PackedId'.+  unpackId :: proxy params -> PackedId params -> Id params++-- | A critical pair queue.+newtype Queue params =+  Queue (Heap.Heap (PassiveSet params))++-- All passive CPs generated from one given rule.+data PassiveSet params =+  PassiveSet {+    passiveset_best  :: {-# UNPACK #-} !(Passive params),+    passiveset_rule  :: !(Id params),+    -- CPs where the rule is the left-hand rule+    passiveset_left  :: {-# UNPACK #-} !(Vector.Vector (PackedScore params, PackedId params, Int32)),+    -- CPs where the rule is the right-hand rule+    passiveset_right :: {-# UNPACK #-} !(Vector.Vector (PackedScore params, PackedId params, Int32)) }+instance Params params => Eq (PassiveSet params) where+  x == y = compare x y == EQ+instance Params params => Ord (PassiveSet params) where+  compare = comparing passiveset_best++-- A smart-ish constructor.+{-# INLINEABLE mkPassiveSet #-}+mkPassiveSet ::+  Params params =>+  Proxy params ->+  Id params ->+  Vector.Vector (PackedScore params, PackedId params, Int32) ->+  Vector.Vector (PackedScore params, PackedId params, Int32) ->+  Maybe (PassiveSet params)+mkPassiveSet proxy rule left right+  | Vector.null left && Vector.null right = Nothing+  | not (Vector.null left) &&+    (Vector.null right || l <= r) =+    Just PassiveSet {+      passiveset_best  = l,+      passiveset_rule  = rule,+      passiveset_left  = Vector.tail left,+      passiveset_right = right }+    -- In this case we must have not (Vector.null right).+  | otherwise =+    Just PassiveSet {+      passiveset_best  = r,+      passiveset_rule  = rule,+      passiveset_left  = left,+      passiveset_right = Vector.tail right }+  where+    l = unpack proxy rule True (Vector.head left)+    r = unpack proxy rule False (Vector.head right)++-- Unpack a triple into a Passive.+{-# INLINEABLE unpack #-}+unpack :: Params params => Proxy params -> Id params -> Bool -> (PackedScore params, PackedId params, Int32) -> Passive params+unpack proxy rule isLeft (score, id, pos) =+  Passive {+    passive_score = unpackScore proxy score,+    passive_rule1 = if isLeft then rule else rule',+    passive_rule2 = if isLeft then rule' else rule,+    passive_pos = fromIntegral pos }+  where+    rule' = unpackId proxy id++-- Make a PassiveSet from a list of Passives.+{-# INLINEABLE makePassiveSet #-}+makePassiveSet :: forall params. Params params => Id params -> [Passive params] -> Maybe (PassiveSet params)+makePassiveSet _ [] = Nothing+makePassiveSet rule ps+  | and [passive_rule2 p == rule | p <- right] =+    mkPassiveSet proxy rule+      (Vector.fromList (map (pack True) (sort left)))+      (Vector.fromList (map (pack False) (sort right)))+  | otherwise = error "rule id does not occur in passive"+  where+    proxy :: Proxy params+    proxy = Proxy+    +    (left, right) = partition (\p -> passive_rule1 p == rule) ps+    pack isLeft Passive{..} =+      (packScore proxy passive_score,+       packId proxy (if isLeft then passive_rule2 else passive_rule1),+       fromIntegral passive_pos)++-- Find and remove the best element from a PassiveSet.+{-# INLINEABLE unconsPassiveSet #-}+unconsPassiveSet :: forall params. Params params => PassiveSet params -> (Passive params, Maybe (PassiveSet params))+unconsPassiveSet PassiveSet{..} =+  (passiveset_best, mkPassiveSet (Proxy :: Proxy params) passiveset_rule passiveset_left passiveset_right)++-- | A queued critical pair.+data Passive params =+  Passive {+    -- | The score of this critical pair.+    passive_score :: !(Score params),+    -- | The rule which does the outermost rewrite in this critical pair.+    passive_rule1 :: !(Id params),+    -- | The rule which does the innermost rewrite in this critical pair.+    passive_rule2 :: !(Id params),+    -- | The position of the overlap. See 'Twee.CP.overlap_pos'.+    passive_pos   :: {-# UNPACK #-} !Int }++instance Params params => Eq (Passive params) where+  x == y = compare x y == EQ++instance Params params => Ord (Passive params) where+  compare = comparing f+    where+      f Passive{..} =+        (passive_score,+         intMax (fromIntegral passive_rule1) (fromIntegral passive_rule2),+         intMin (fromIntegral passive_rule1) (fromIntegral passive_rule2),+         passive_pos)++-- | The empty queue.+empty :: Queue params+empty = Queue Heap.empty++-- | Add a set of 'Passive's to the queue.+{-# INLINEABLE insert #-}+insert :: Params params => Id params -> [Passive params] -> Queue params -> Queue params+insert rule passives (Queue q) =+  Queue $+  case makePassiveSet rule passives of+    Nothing -> q+    Just p -> Heap.insert p q++-- | Remove the minimum 'Passive' from the queue.+{-# INLINEABLE removeMin #-}+removeMin :: Params params => Queue params -> Maybe (Passive params, Queue params)+removeMin (Queue q) = do+  (passiveset, q) <- Heap.removeMin q+  case unconsPassiveSet passiveset of+    (passive, Just passiveset') ->+      Just (passive, Queue (Heap.insert passiveset' q))+    (passive, Nothing) ->+      Just (passive, Queue q)++-- | Map a function over all 'Passive's.+{-# INLINEABLE mapMaybe #-}+mapMaybe :: Params params => (Passive params -> Maybe (Passive params)) -> Queue params -> Queue params+mapMaybe f (Queue q) = Queue (Heap.mapMaybe g q)+  where+    g PassiveSet{..} =+      makePassiveSet passiveset_rule $ Data.Maybe.mapMaybe f $+        passiveset_best:+        map (unpack proxy passiveset_rule True) (Vector.toList passiveset_left) +++        map (unpack proxy passiveset_rule False) (Vector.toList passiveset_right)+    proxy :: Proxy params+    proxy = Proxy
+ Twee/Pretty.hs view
@@ -0,0 +1,182 @@+-- | Pretty-printing of terms and assorted other values.++{-# LANGUAGE Rank2Types #-}+module Twee.Pretty(module Twee.Pretty, module Text.PrettyPrint.HughesPJClass, Pretty(..)) where++import Text.PrettyPrint.HughesPJClass hiding (empty)+import qualified Text.PrettyPrint.HughesPJClass as PP+import qualified Data.Map as Map+import Data.Map(Map)+import qualified Data.Set as Set+import Data.Set(Set)+import Data.Ratio+import Twee.Term++-- * Miscellaneous 'Pretty' instances and utilities.++-- | Print a value to the console.+prettyPrint :: Pretty a => a -> IO ()+prettyPrint x = putStrLn (prettyShow x)++-- | The empty document. Used to avoid name clashes with 'Twee.Term.empty'.+pPrintEmpty :: Doc+pPrintEmpty = PP.empty++instance Pretty Doc where pPrint = id++-- | Print a tuple of values.+pPrintTuple :: [Doc] -> Doc+pPrintTuple = parens . fsep . punctuate comma++instance Pretty a => Pretty (Set a) where+  pPrint = pPrintSet . map pPrint . Set.toList++-- | Print a set of vlaues.+pPrintSet :: [Doc] -> Doc+pPrintSet = braces . fsep . punctuate comma++instance Pretty Var where+  pPrint (V n) =+    text $+      vars !! (n `mod` length vars):+      case n `div` length vars of+        0 -> ""+        m -> show (m+1)+    where+      vars = "XYZWVUTS"++instance (Pretty k, Pretty v) => Pretty (Map k v) where+  pPrint = pPrintSet . map binding . Map.toList+    where+      binding (x, v) = hang (pPrint x <+> text "=>") 2 (pPrint v)++instance (Eq a, Integral a, Pretty a) => Pretty (Ratio a) where+  pPrint a+    | denominator a == 1 = pPrint (numerator a)+    | otherwise = text "(" <+> pPrint (numerator a) <> text "/" <> pPrint (denominator a) <+> text ")"++-- | Generate a list of candidate names for pretty-printing.+supply :: [String] -> [String]+supply names =+  names +++  [ name ++ show i | i <- [2..], name <- names ]++-- * Pretty-printing of terms.++instance Pretty f => Pretty (Fun f) where+  pPrintPrec l p = pPrintPrec l p . fun_value++instance PrettyTerm f => PrettyTerm (Fun f) where+  termStyle f = termStyle (fun_value f)++instance PrettyTerm f => Pretty (Term f) where+  pPrintPrec l p (Var x) = pPrintPrec l p x+  pPrintPrec l p (App f xs) =+    pPrintTerm (termStyle f) l p (pPrint f) (unpack xs)++instance PrettyTerm f => Pretty (TermList f) where+  pPrintPrec _ _ = pPrint . unpack++instance PrettyTerm f => Pretty (Subst f) where+  pPrint sub = text "{" <> fsep (punctuate (text ",") docs) <> text "}"+    where+      docs =+        [ hang (pPrint x <+> text "->") 2 (pPrint t)+        | (x, t) <- substToList sub ]++-- | A class for customising the printing of function symbols.+class Pretty f => PrettyTerm f where+  -- | The style of the function symbol. Defaults to 'curried'.+  termStyle :: f -> TermStyle+  termStyle _ = curried++-- | Defines how to print out a function symbol.+newtype TermStyle =+  TermStyle {+    -- | Renders a function application.+    -- Takes the following arguments in this order:+    -- Pretty-printing level, current precedence,+    -- pretty-printed function symbol and list of arguments to the function.+    pPrintTerm :: forall a. Pretty a => PrettyLevel -> Rational -> Doc -> [a] -> Doc }++invisible, curried, uncurried, prefix, postfix :: TermStyle++-- | For operators like @$@ that should be printed as a blank space.+invisible =+  TermStyle $ \l p d ->+    let+      f [] = d+      f [t] = pPrintPrec l p t+      f (t:ts) =+        maybeParens (p > 10) $+          pPrint t <+>+            (hsep (map (pPrintPrec l 11) ts))+    in f++-- | For functions that should be printed curried.+curried =+  TermStyle $ \l p d ->+    let+      f [] = d+      f xs =+        maybeParens (p > 10) $+          d <+>+            (hsep (map (pPrintPrec l 11) xs))+    in f++-- | For functions that should be printed uncurried.+uncurried =+  TermStyle $ \l _ d ->+    let+      f [] = d+      f xs =+        d <> parens (hsep (punctuate comma (map (pPrintPrec l 0) xs)))+    in f++-- | A helper function that deals with under- and oversaturated applications.+fixedArity :: Int -> TermStyle -> TermStyle+fixedArity arity style =+  TermStyle $ \l p d ->+    let+      f xs+        | length xs < arity = pPrintTerm curried l p (parens d) xs+        | length xs > arity =+            maybeParens (p > 10) $+              hsep (pPrintTerm style l 11 d ys:+                    map (pPrintPrec l 11) zs)+        | otherwise = pPrintTerm style l p d xs+        where+          (ys, zs) = splitAt arity xs+    in f++-- | A helper function that drops a certain number of arguments.+implicitArguments :: Int -> TermStyle -> TermStyle+implicitArguments n (TermStyle pp) =+  TermStyle $ \l p d xs -> pp l p d (drop n xs)++-- | For prefix operators.+prefix =+  fixedArity 1 $+  TermStyle $ \l _ d [x] ->+    d <> pPrintPrec l 11 x++-- | For postfix operators.+postfix =+  fixedArity 1 $+  TermStyle $ \l _ d [x] ->+    pPrintPrec l 11 x <> d++-- | For infix operators.+infixStyle :: Int -> TermStyle+infixStyle pOp =+  fixedArity 2 $+  TermStyle $ \l p d [x, y] ->+    maybeParens (p > fromIntegral pOp) $+      pPrintPrec l (fromIntegral pOp+1) x <+> d <+>+      pPrintPrec l (fromIntegral pOp+1) y++-- | For tuples.+tupleStyle :: TermStyle+tupleStyle =+  TermStyle $ \l _ _ xs ->+    parens (hsep (punctuate comma (map (pPrintPrec l 0) xs)))
+ Twee/Proof.hs view
@@ -0,0 +1,723 @@+-- | Equational proofs which are checked for correctedness.+{-# LANGUAGE TypeFamilies, PatternGuards, RecordWildCards, ScopedTypeVariables #-}+module Twee.Proof(+  -- * Constructing proofs+  Proof, Derivation(..), Lemma(..), Axiom(..),+  certify, equation, derivation,+  -- ** Smart constructors for derivations+  lemma, axiom, symm, trans, cong, congPath,++  -- * Analysing proofs+  simplify, usedLemmas, usedAxioms, usedLemmasAndSubsts, usedAxiomsAndSubsts,++  -- * Pretty-printing proofs+  Config(..), defaultConfig, Presentation(..),+  ProvedGoal(..), provedGoal, checkProvedGoal,+  pPrintPresentation, present, describeEquation) where++import Twee.Base hiding (invisible)+import Twee.Equation+import Twee.Utils+import Control.Monad+import Data.Maybe+import Data.List+import Data.Ord+import qualified Data.Set as Set+import qualified Data.Map.Strict as Map++----------------------------------------------------------------------+-- Equational proofs. Only valid proofs can be constructed.+----------------------------------------------------------------------++-- | A checked proof. If you have a value of type @Proof f@,+-- it should jolly well represent a valid proof!+--+-- The only way to construct a @Proof f@ is by using 'certify'.+data Proof f =+  Proof {+    equation   :: !(Equation f),+    derivation :: !(Derivation f) }+  deriving (Eq, Show)++-- | A derivation is an unchecked proof. It might be wrong!+-- The way to check it is to call 'certify' to turn it into a 'Proof'.+data Derivation f =+    -- | Apply an existing rule (with proof!) to the root of a term+    UseLemma {-# UNPACK #-} !(Lemma f) !(Subst f)+    -- | Apply an axiom to the root of a term+  | UseAxiom {-# UNPACK #-} !(Axiom f) !(Subst f)+    -- | Reflexivity. @'Refl' t@ proves @t = t@.+  | Refl !(Term f)+    -- | Symmetry+  | Symm !(Derivation f)+    -- | Transivitity+  | Trans !(Derivation f) !(Derivation f)+    -- | Congruence.+    -- Parallel, i.e., takes a function symbol and one derivation for each+    -- argument of that function.+  | Cong {-# UNPACK #-} !(Fun f) ![Derivation f]+  deriving (Eq, Show)++-- | A lemma, which includes a proof.+data Lemma f =+  Lemma {+    -- | The id number of the lemma.+    -- Has no semantic meaning; for convenience only.+    lemma_id :: {-# UNPACK #-} !Id,+    -- | A proof of the lemma.+    lemma_proof :: !(Proof f) }+  deriving Show++--  | An axiom, which comes without proof.+data Axiom f =+  Axiom {+    -- | The number of the axiom.+    -- Has no semantic meaning; for convenience only.+    axiom_number :: {-# UNPACK #-} !Int,+    -- | A description of the axiom.+    -- Has no semantic meaning; for convenience only.+    axiom_name :: !String,+    -- | The equation which the axiom asserts.+    axiom_eqn :: !(Equation f) }+  deriving (Eq, Ord, Show)++-- | Checks a 'Derivation' and, if it is correct, returns a+-- certified 'Proof'.+--+-- If the 'Derivation' is incorrect, throws an exception.++-- This is the trusted core of the module.+{-# INLINEABLE certify #-}+certify :: PrettyTerm f => Derivation f -> Proof f+certify p =+  {-# SCC certify #-}+  case check p of+    Nothing -> error ("Invalid proof created!\n" ++ prettyShow p)+    Just eqn -> Proof eqn p+  where+    check (UseLemma Lemma{..} sub) =+      return (subst sub (equation lemma_proof))+    check (UseAxiom Axiom{..} sub) =+      return (subst sub axiom_eqn)+    check (Refl t) =+      return (t :=: t)+    check (Symm p) = do+      t :=: u <- check p+      return (u :=: t)+    check (Trans p q) = do+      t :=: u1 <- check p+      u2 :=: v <- check q+      guard (u1 == u2)+      return (t :=: v)+    check (Cong f ps) = do+      eqns <- mapM check ps+      return+        (build (app f (map eqn_lhs eqns)) :=:+         build (app f (map eqn_rhs eqns)))++----------------------------------------------------------------------+-- Everything below this point need not be trusted, since all proof+-- construction goes through the "proof" function.+----------------------------------------------------------------------++-- Typeclass instances.+instance Eq (Lemma f) where+  x == y = compare x y == EQ+instance Ord (Lemma f) where+  compare =+    comparing (\x ->+      -- Don't look into lemma proofs when comparing derivations,+      -- to avoid exponential blowup+      (lemma_id x, equation (lemma_proof x)))++instance Symbolic (Derivation f) where+  type ConstantOf (Derivation f) = f+  termsDL (UseLemma _ sub) = termsDL sub+  termsDL (UseAxiom _ sub) = termsDL sub+  termsDL (Refl t) = termsDL t+  termsDL (Symm p) = termsDL p+  termsDL (Trans p q) = termsDL p `mplus` termsDL q+  termsDL (Cong _ ps) = termsDL ps++  subst_ sub (UseLemma lemma s) = UseLemma lemma (subst_ sub s)+  subst_ sub (UseAxiom axiom s) = UseAxiom axiom (subst_ sub s)+  subst_ sub (Refl t) = Refl (subst_ sub t)+  subst_ sub (Symm p) = symm (subst_ sub p)+  subst_ sub (Trans p q) = trans (subst_ sub p) (subst_ sub q)+  subst_ sub (Cong f ps) = cong f (subst_ sub ps)++instance Function f => Pretty (Proof f) where+  pPrint = pPrintLemma defaultConfig prettyShow+instance PrettyTerm f => Pretty (Derivation f) where+  pPrint (UseLemma lemma sub) =+    text "subst" <> pPrintTuple [pPrint lemma, pPrint sub]+  pPrint (UseAxiom axiom sub) =+    text "subst" <> pPrintTuple [pPrint axiom, pPrint sub]+  pPrint (Refl t) =+    text "refl" <> pPrintTuple [pPrint t]+  pPrint (Symm p) =+    text "symm" <> pPrintTuple [pPrint p]+  pPrint (Trans p q) =+    text "trans" <> pPrintTuple [pPrint p, pPrint q]+  pPrint (Cong f ps) =+    text "cong" <> pPrintTuple (pPrint f:map pPrint ps)++instance PrettyTerm f => Pretty (Axiom f) where+  pPrint Axiom{..} =+    text "axiom" <>+    pPrintTuple [pPrint axiom_number, text axiom_name, pPrint axiom_eqn]++instance PrettyTerm f => Pretty (Lemma f) where+  pPrint Lemma{..} =+    text "lemma" <>+    pPrintTuple [pPrint lemma_id, pPrint (equation lemma_proof)]++-- | Simplify a derivation.+--+-- After simplification, a derivation has the following properties:+--+--   * 'Symm' is pushed down next to 'Lemma' and 'Axiom'+--   * 'Refl' only occurs inside 'Cong' or at the top level+--   * 'Trans' is right-associated and is pushed inside 'Cong' if possible+simplify :: Minimal f => (Lemma f -> Maybe (Derivation f)) -> Derivation f -> Derivation f+simplify lem p = simp p+  where+    simp p@(UseLemma lemma sub) =+      case lem lemma of+        Nothing -> p+        Just q ->+          let+            -- Get rid of any variables that are not bound by sub+            -- (e.g., ones which only occur internally in q)+            dead = usort (vars q) \\ substDomain sub+          in simp (subst sub (erase dead q))+    simp (Symm p) = symm (simp p)+    simp (Trans p q) = trans (simp p) (simp q)+    simp (Cong f ps) = cong f (map simp ps)+    simp p = p++lemma :: Lemma f -> Subst f -> Derivation f+lemma lem@Lemma{..} sub = UseLemma lem sub++axiom :: Axiom f -> Derivation f+axiom ax@Axiom{..} =+  UseAxiom ax $+    fromJust $+    listToSubst [(x, build (var x)) | x <- vars axiom_eqn]++symm :: Derivation f -> Derivation f+symm (Refl t) = Refl t+symm (Symm p) = p+symm (Trans p q) = trans (symm q) (symm p)+symm (Cong f ps) = cong f (map symm ps)+symm p = Symm p++trans :: Derivation f -> Derivation f -> Derivation f+trans Refl{} p = p+trans p Refl{} = p+trans (Trans p q) r =+  -- Right-associate uses of transitivity.+  -- p cannot be a Trans (if it was created with the smart+  -- constructors) but q could be.+  Trans p (trans q r)+-- Collect adjacent uses of congruence.+trans (Cong f ps) (Cong g qs) | f == g =+  transCong f ps qs+trans (Cong f ps) (Trans (Cong g qs) r) | f == g =+  trans (transCong f ps qs) r+trans p q = Trans p q++transCong :: Fun f -> [Derivation f] -> [Derivation f] -> Derivation f+transCong f ps qs =+  cong f (zipWith trans ps qs)++cong :: Fun f -> [Derivation f] -> Derivation f+cong f ps =+  case sequence (map unRefl ps) of+    Nothing -> Cong f ps+    Just ts -> Refl (build (app f ts))+  where+    unRefl (Refl t) = Just t+    unRefl _ = Nothing++-- | Find all lemmas which are used in a derivation.+usedLemmas :: Derivation f -> [Lemma f]+usedLemmas p = map fst (usedLemmasAndSubsts p)++-- | Find all lemmas which are used in a derivation,+-- together with the substitutions used.+usedLemmasAndSubsts :: Derivation f -> [(Lemma f, Subst f)]+usedLemmasAndSubsts p = lem p []+  where+    lem (UseLemma lemma sub) = ((lemma, sub):)+    lem (Symm p) = lem p+    lem (Trans p q) = lem p . lem q+    lem (Cong _ ps) = foldr (.) id (map lem ps)+    lem _ = id++-- | Find all axioms which are used in a derivation.+usedAxioms :: Derivation f -> [Axiom f]+usedAxioms p = map fst (usedAxiomsAndSubsts p)++-- | Find all axioms which are used in a derivation,+-- together with the substitutions used.+usedAxiomsAndSubsts :: Derivation f -> [(Axiom f, Subst f)]+usedAxiomsAndSubsts p = ax p []+  where+    ax (UseAxiom axiom sub) = ((axiom, sub):)+    ax (Symm p) = ax p+    ax (Trans p q) = ax p . ax q+    ax (Cong _ ps) = foldr (.) id (map ax ps)+    ax _ = id++-- | Applies a derivation at a particular path in a term.+congPath :: [Int] -> Term f -> Derivation f -> Derivation f+congPath [] _ p = p+congPath (n:ns) (App f t) p | n <= length ts =+  cong f $+    map Refl (take n ts) +++    [congPath ns (ts !! n) p] +++    map Refl (drop (n+1) ts)+  where+    ts = unpack t+congPath _ _ _ = error "bad path"++----------------------------------------------------------------------+-- Pretty-printing of proofs.+----------------------------------------------------------------------++-- | Options for proof presentation.+data Config =+  Config {+    -- | Never inline lemmas.+    cfg_all_lemmas :: !Bool,+    -- | Inline all lemmas.+    cfg_no_lemmas :: !Bool,+    -- | Print out explicit substitutions.+    cfg_show_instances :: !Bool }++-- | The default configuration.+defaultConfig :: Config+defaultConfig =+  Config {+    cfg_all_lemmas = False,+    cfg_no_lemmas = False,+    cfg_show_instances = False }++-- | A proof, with all axioms and lemmas explicitly listed.+data Presentation f =+  Presentation {+    -- | The used axioms.+    pres_axioms :: [Axiom f],+    -- | The used lemmas.+    pres_lemmas :: [Lemma f],+    -- | The goals proved.+    pres_goals  :: [ProvedGoal f] }+  deriving Show++-- Note: only the pg_proof field should be trusted!+-- The remaining fields are for information only.+data ProvedGoal f =+  ProvedGoal {+    pg_number  :: Int,+    pg_name    :: String,+    pg_proof   :: Proof f,++    -- Extra fields for existentially-quantified goals, giving the original goal+    -- and the existential witness. These fields are not verified. If you want+    -- to check them, use checkProvedGoal.+    --+    -- In general, subst pg_witness_hint pg_goal_hint == equation pg_proof.+    -- For non-existential goals, pg_goal_hint == equation pg_proof+    -- and pg_witness_hint is the empty substitution.+    pg_goal_hint    :: Equation f,+    pg_witness_hint :: Subst f }+  deriving Show++-- | Construct a @ProvedGoal@.+provedGoal :: Int -> String -> Proof f -> ProvedGoal f+provedGoal number name proof =+  ProvedGoal {+    pg_number = number,+    pg_name = name,+    pg_proof = proof,+    pg_goal_hint = equation proof,+    pg_witness_hint = emptySubst }++-- | Check that pg_goal/pg_witness match up with pg_proof.+checkProvedGoal :: Function f => ProvedGoal f -> ProvedGoal f+checkProvedGoal pg@ProvedGoal{..}+  | subst pg_witness_hint pg_goal_hint == equation pg_proof =+    pg+  | otherwise =+    error $ show $+      text "Invalid ProvedGoal!" $$+      text "Claims to prove" <+> pPrint pg_goal_hint $$+      text "with witness" <+> pPrint pg_witness_hint <> text "," $$+      text "but actually proves" <+> pPrint (equation pg_proof)++instance Function f => Pretty (Presentation f) where+  pPrint = pPrintPresentation defaultConfig++-- | Simplify and present a proof.+present :: Function f => Config -> [ProvedGoal f] -> Presentation f+present config goals =+  -- First find all the used lemmas, then hand off to presentWithGoals+  presentWithGoals config goals+    (used Set.empty (concatMap (usedLemmas . derivation . pg_proof) goals))+  where+    used lems [] = Set.elems lems+    used lems (x:xs)+      | x `Set.member` lems = used lems xs+      | otherwise =+        used (Set.insert x lems)+          (usedLemmas (derivation (lemma_proof x)) ++ xs)++presentWithGoals ::+  Function f =>+  Config -> [ProvedGoal f] -> [Lemma f] -> Presentation f+presentWithGoals config@Config{..} goals lemmas+  -- We inline a lemma if one of the following holds:+  --   * It only has one step+  --   * It is subsumed by an earlier lemma+  --   * It is only used once+  --   * It has to do with $equals (for printing of the goal proof)+  --   * The option cfg_no_lemmas is true+  -- First we compute all inlinings, then apply simplify to remove them,+  -- then repeat if any lemma was inlined+  | Map.null inlinings =+    let+      axioms = usort $+        concatMap (usedAxioms . derivation . pg_proof) goals +++        concatMap (usedAxioms . derivation . lemma_proof) lemmas+    in+      Presentation axioms+        [ lemma { lemma_proof = flattenProof lemma_proof }+        | lemma@Lemma{..} <- lemmas ]+        [ decodeGoal (goal { pg_proof = flattenProof pg_proof })+        | goal@ProvedGoal{..} <- goals ]++  | otherwise =+    let+      inline lemma = Map.lookup lemma inlinings++      goals' =+        [ decodeGoal (goal { pg_proof = certify $ simplify inline (derivation pg_proof) })+        | goal@ProvedGoal{..} <- goals ]+      lemmas' =+        [ Lemma n (certify $ simplify inline (derivation p))+        | lemma@(Lemma n p) <- lemmas, not (lemma `Map.member` inlinings) ]+    in+      presentWithGoals config goals' lemmas'++  where+    inlinings =+      Map.fromList+        [ (lemma, p)+        | lemma <- lemmas, Just p <- [tryInline lemma]]++    tryInline (Lemma n p)+      | shouldInline n p = Just (derivation p)+    tryInline (Lemma n p)+      -- Check for subsumption by an earlier lemma+      | Just (Lemma m q) <- Map.lookup (canonicalise (t :=: u)) equations, m < n =+        Just (subsume p (derivation q))+      | Just (Lemma m q) <- Map.lookup (canonicalise (u :=: t)) equations, m < n =+        Just (subsume p (Symm (derivation q)))+      where+        t :=: u = equation p+    tryInline _ = Nothing++    shouldInline n p =+      cfg_no_lemmas ||+      oneStep (derivation p) ||+      (not cfg_all_lemmas &&+       (isJust (decodeEquality (eqn_lhs (equation p))) ||+        isJust (decodeEquality (eqn_rhs (equation p))) ||+        Map.lookup n uses == Just 1))+  +    subsume p q =+      -- Rename q so its variables match p's+      subst sub q+      where+        t  :=: u  = equation p+        t' :=: u' = equation (certify q)+        Just sub  = matchList (buildList [t', u']) (buildList [t, u])++    -- Record which lemma proves each equation+    equations =+      Map.fromList+        [ (canonicalise (equation lemma_proof), lemma)+        | lemma@Lemma{..} <- lemmas]++    -- Count how many times each lemma is used+    uses =+      Map.fromListWith (+)+        [ (lemma_id, 1)+        | Lemma{..} <-+            concatMap usedLemmas+              (map (derivation . pg_proof) goals +++               map (derivation . lemma_proof) lemmas) ]++    -- Check if a proof only has one step.+    -- Trans only occurs at the top level by this point.+    oneStep Trans{} = False+    oneStep _ = True++invisible :: Function f => Equation f -> Bool+invisible (t :=: u) = show (pPrint t) == show (pPrint u)++-- Pretty-print the proof of a single lemma.+pPrintLemma :: Function f => Config -> (Id -> String) -> Proof f -> Doc+pPrintLemma Config{..} lemmaName p =+  ppTerm (eqn_lhs (equation q)) $$ pp (derivation q)+  where+    q = flattenProof p++    pp (Trans p q) = pp p $$ pp q+    pp p | invisible (equation (certify p)) = pPrintEmpty+    pp p =+      (text "= { by" <+>+       ppStep+         (nub (map (show . ppLemma) (usedLemmasAndSubsts p)) +++          nub (map (show . ppAxiom) (usedAxiomsAndSubsts p))) <+>+       text "}" $$+       ppTerm (eqn_rhs (equation (certify p))))++    ppTerm t = text "  " <> pPrint t++    ppStep [] = text "reflexivity" -- ??+    ppStep [x] = text x+    ppStep xs =+      hcat (punctuate (text ", ") (map text (init xs))) <+>+      text "and" <+>+      text (last xs)++    ppLemma (Lemma{..}, sub) =+      text "lemma" <+> text (lemmaName lemma_id) <> showSubst sub+    ppAxiom (Axiom{..}, sub) =+      text "axiom" <+> pPrint axiom_number <+> parens (text axiom_name) <> showSubst sub++    showSubst sub+      | cfg_show_instances && not (null (substToList sub)) =+        text " with " <>+        fsep (punctuate comma+          [ pPrint x <+> text "->" <+> pPrint t+          | (x, t) <- substToList sub ])+      | otherwise = pPrintEmpty++-- Transform a proof so that each step uses exactly one axiom+-- or lemma. The proof will have the following form afterwards:+--   * Trans only occurs at the outermost level and is right-associated+--   * Each Cong has exactly one non-Refl argument (no parallel rewriting)+--   * Symm only occurs innermost, i.e., next to UseLemma or UseAxiom+--   * Refl only occurs as an argument to Cong, or outermost if the+--     whole proof is a single reflexivity step+flattenProof :: Function f => Proof f -> Proof f+flattenProof =+  certify . flat . simplify (const Nothing) . derivation+  where+    flat (Trans p q) = trans (flat p) (flat q)+    flat p@(Cong f ps) =+      foldr trans (reflAfter p)+        [ Cong f $+            map reflAfter (take i ps) +++            [p] +++            map reflBefore (drop (i+1) ps)+        | (i, q) <- zip [0..] qs,+          p <- steps q ]+      where+        qs = map flat ps+    flat p = p++    reflBefore p = Refl (eqn_lhs (equation (certify p)))+    reflAfter p  = Refl (eqn_rhs (equation (certify p)))++    steps Refl{} = []+    steps (Trans p q) = steps p ++ steps q+    steps p = [p]++    trans (Trans p q) r = trans p (trans q r)+    trans Refl{} p = p+    trans p Refl{} = p+    trans p q =+      case strip q of+        Nothing -> Trans p q+        Just q' -> trans p q'++    strip p+      | t == u = Just (Refl t)+      | otherwise = strip' t p+      where+        t :=: u = equation (certify p)+    strip' t (Trans _ q)+      | eqn_lhs (equation (certify q)) == t = Just q+      | otherwise = strip' t q+    strip' _ _ = Nothing++-- Transform a derivation into a list of single steps.+-- Each step has the following form:+--   * Trans does not occur+--   * Symm only occurs innermost, i.e., next to UseLemma or UseAxiom+--   * Each Cong has exactly one non-Refl argument (no parallel rewriting)+--   * Refl only occurs as an argument to Cong+derivSteps :: Function f => Derivation f -> [Derivation f]+derivSteps = steps . derivation . flattenProof . certify+  where+    steps Refl{} = []+    steps (Trans p q) = steps p ++ steps q+    steps p = [p]++-- | Print a presented proof.+pPrintPresentation :: forall f. Function f => Config -> Presentation f -> Doc+pPrintPresentation config (Presentation axioms lemmas goals) =+  vcat $ intersperse (text "") $+    vcat [ describeEquation "Axiom" (show n) (Just name) eqn+         | Axiom n name eqn <- axioms,+           not (invisible eqn) ]:+    [ pp "Lemma" (num n) Nothing (equation p) emptySubst p+    | Lemma n p <- lemmas,+      not (invisible (equation p)) ] +++    [ pp "Goal" (show num) (Just pg_name) pg_goal_hint pg_witness_hint pg_proof+    | (num, ProvedGoal{..}) <- zip [1..] goals ]+  where+    pp kind n mname eqn witness p =+      describeEquation kind n mname eqn $$+      ppWitness witness $$+      text "Proof:" $$+      pPrintLemma config num p++    num x = show (fromJust (Map.lookup x nums))+    nums = Map.fromList (zip (map lemma_id lemmas) [n+1 ..])+    n = maximum $ 0:map axiom_number axioms++    ppWitness sub+      | sub == emptySubst = pPrintEmpty+      | otherwise =+          vcat [+            text "The goal is true when:",+            nest 2 $ vcat+              [ pPrint x <+> text "=" <+> pPrint t+              | (x, t) <- substToList sub ],+            if minimal `elem` funs sub then+              text "where" <+> doubleQuotes (pPrint (minimal :: Fun f)) <+>+              text "stands for an arbitrary term of your choice."+            else pPrintEmpty,+            text ""]++-- | Format an equation nicely.+--+-- Used both here and in the main file.+describeEquation ::+  PrettyTerm f =>+  String -> String -> Maybe String -> Equation f -> Doc+describeEquation kind num mname eqn =+  text kind <+> text num <>+  (case mname of+     Nothing -> text ""+     Just name -> text (" (" ++ name ++ ")")) <>+  text ":" <+> pPrint eqn <> text "."++----------------------------------------------------------------------+-- Making proofs of existential goals more readable.+----------------------------------------------------------------------++-- The idea: the only axioms which mention $equals, $true and $false+-- are:+--   * $equals(x,x) = $true  (reflexivity)+--   * $equals(t,u) = $false (conjecture)+-- This implies that a proof $true = $false must have the following+-- structure, if we expand out all lemmas:+--   $true = $equals(s,s) = ... = $equals(t,u) = $false.+--+-- The substitution in the last step $equals(t,u) = $false is in fact the+-- witness to the existential.+--+-- Furthermore, we can make it so that the inner "..." doesn't use the $equals+-- axioms. If it does, one of the "..." steps results in either $true or $false,+-- and we can chop off everything before the $true or after the $false.+--+-- Once we have done that, every proof step in the "..." must be a congruence+-- step of the shape+--   $equals(t, u) = $equals(v, w).+-- This is because there are no other axioms which mention $equals. Hence we can+-- split the proof of $equals(s,s) = $equals(t,u) into separate proofs of s=t+-- and s=u.+--+-- What we have got out is:+--   * the witness to the existential+--   * a proof that both sides of the conjecture are equal+-- and we can present that to the user.++-- Decode $equals(t,u) into an equation t=u.+decodeEquality :: Function f => Term f -> Maybe (Equation f)+decodeEquality (App equals (Cons t (Cons u Empty)))+  | isEquals equals = Just (t :=: u)+decodeEquality _ = Nothing++-- Tries to transform a proof of $true = $false into a proof of+-- the original existentially-quantified formula.+decodeGoal :: Function f => ProvedGoal f -> ProvedGoal f+decodeGoal pg =+  case maybeDecodeGoal pg of+    Nothing -> pg+    Just (name, witness, goal, deriv) ->+      checkProvedGoal $+      pg {+        pg_name = name,+        pg_proof = certify deriv,+        pg_goal_hint = goal,+        pg_witness_hint = witness }++maybeDecodeGoal :: forall f. Function f =>+  ProvedGoal f -> Maybe (String, Subst f, Equation f, Derivation f)+maybeDecodeGoal ProvedGoal{..}+  --  N.B. presentWithGoals takes care of expanding any lemma which mentions+  --  $equals, and flattening the proof.+  | isFalseTerm u = extract (derivSteps deriv)+    -- Orient the equation so that $false is the RHS.+  | isFalseTerm t = extract (derivSteps (symm deriv))+  | otherwise = Nothing+  where+    isFalseTerm, isTrueTerm :: Term f -> Bool+    isFalseTerm (App false _) = isFalse false+    isFalseTerm _ = False+    isTrueTerm (App true _) = isTrue true+    isTrueTerm _ = False++    t :=: u = equation pg_proof+    deriv = derivation pg_proof++    -- Detect $true = $equals(t, t).+    decodeReflexivity :: Derivation f -> Maybe (Term f)+    decodeReflexivity (Symm (UseAxiom Axiom{..} sub)) = do+      guard (isTrueTerm (eqn_rhs axiom_eqn))+      (t :=: u) <- decodeEquality (eqn_lhs axiom_eqn)+      guard (t == u)+      return (subst sub t)+    decodeReflexivity _ = Nothing++    -- Detect $equals(t, u) = $false.+    decodeConjecture :: Derivation f -> Maybe (String, Equation f, Subst f)+    decodeConjecture (UseAxiom Axiom{..} sub) = do+      guard (isFalseTerm (eqn_rhs axiom_eqn))+      eqn <- decodeEquality (eqn_lhs axiom_eqn)+      return (axiom_name, eqn, sub)+    decodeConjecture _ = Nothing++    extract (p:ps) = do+      -- Start by finding $true = $equals(t,u).+      t <- decodeReflexivity p+      cont (Refl t) (Refl t) ps+    extract [] = Nothing++    cont p1 p2 (p:ps)+      | Just t <- decodeReflexivity p =+        cont (Refl t) (Refl t) ps+      | Just (name, eqn, sub) <- decodeConjecture p =+        -- If p1: s=t and p2: s=u+        -- then symm p1 `trans` p2: t=u.+        return (name, sub, eqn, symm p1 `trans` p2)+      | Cong eq [p1', p2'] <- p, isEquals eq =+        cont (p1 `trans` p1') (p2 `trans` p2') ps+    cont _ _ _ = Nothing
+ Twee/Rule.hs view
@@ -0,0 +1,488 @@+-- | Term rewriting.+{-# LANGUAGE TypeFamilies, FlexibleContexts, RecordWildCards, BangPatterns, OverloadedStrings, MultiParamTypeClasses, ScopedTypeVariables, GeneralizedNewtypeDeriving #-}+module Twee.Rule where++import Twee.Base+import Twee.Constraints+import qualified Twee.Index as Index+import Twee.Index(Index)+import Control.Monad+import Control.Monad.Trans.Class+import Control.Monad.Trans.State.Strict+import Data.Maybe+import Data.List+import Twee.Utils+import qualified Data.Set as Set+import Data.Set(Set)+import qualified Twee.Term as Term+import Data.Ord+import Twee.Equation+import qualified Twee.Proof as Proof+import Twee.Proof(Derivation, Lemma(..))+import Data.Tuple++--------------------------------------------------------------------------------+-- * Rewrite rules.+--------------------------------------------------------------------------------++-- | A rewrite rule.+data Rule f =+  Rule {+    -- | Information about whether and how the rule is oriented.+    orientation :: !(Orientation f),+    -- Invariant:+    -- For oriented rules: vars rhs `isSubsetOf` vars lhs+    -- For unoriented rules: vars lhs == vars rhs++    -- | The left-hand side of the rule.+    lhs :: {-# UNPACK #-} !(Term f),+    -- | The right-hand side of the rule.+    rhs :: {-# UNPACK #-} !(Term f) }+  deriving (Eq, Ord, Show)+type RuleOf a = Rule (ConstantOf a)++-- | A rule's orientation.+--+-- 'Oriented' and 'WeaklyOriented' rules are used only left-to-right.+-- 'Permutative' and 'Unoriented' rules are used bidirectionally.+data Orientation f =+    -- | An oriented rule.+    Oriented+    -- | A weakly oriented rule.+    -- The first argument is the minimal constant, the second argument is a list+    -- of terms which are weakly oriented in the rule.+    -- +    -- A rule with orientation @'WeaklyOriented' k ts@ can be used unless+    -- all terms in @ts@ are equal to @k@.+  | WeaklyOriented {-# UNPACK #-} !(Fun f) [Term f]+    -- | A permutative rule.+    --+    -- A rule with orientation @'Permutative' ts@ can be used if+    -- @map fst ts@ is lexicographically greater than @map snd ts@.+  | Permutative [(Term f, Term f)]+    -- | An unoriented rule.+  | Unoriented+  deriving Show++instance Eq (Orientation f) where _ == _ = True+instance Ord (Orientation f) where compare _ _ = EQ++-- | Is a rule oriented or weakly oriented?+oriented :: Orientation f -> Bool+oriented Oriented{} = True+oriented WeaklyOriented{} = True+oriented _ = False++-- | Is a rule weakly oriented?+weaklyOriented :: Orientation f -> Bool+weaklyOriented WeaklyOriented{} = True+weaklyOriented _ = False++instance Symbolic (Rule f) where+  type ConstantOf (Rule f) = f+  termsDL (Rule or t u) = termsDL or `mplus` termsDL t `mplus` termsDL u+  subst_ sub (Rule or t u) = Rule (subst_ sub or) (subst_ sub t) (subst_ sub u)++instance f ~ g => Has (Rule f) (Term g) where+  the = lhs++instance Symbolic (Orientation f) where+  type ConstantOf (Orientation f) = f++  termsDL Oriented = mzero+  termsDL (WeaklyOriented _ ts) = termsDL ts+  termsDL (Permutative ts) = termsDL ts+  termsDL Unoriented = mzero++  subst_ _   Oriented = Oriented+  subst_ sub (WeaklyOriented min ts) = WeaklyOriented min (subst_ sub ts)+  subst_ sub (Permutative ts) = Permutative (subst_ sub ts)+  subst_ _   Unoriented = Unoriented++instance PrettyTerm f => Pretty (Rule f) where+  pPrint (Rule or l r) =+    pPrint l <+> text (showOrientation or) <+> pPrint r+    where+      showOrientation Oriented = "->"+      showOrientation WeaklyOriented{} = "~>"+      showOrientation Permutative{} = "<->"+      showOrientation Unoriented = "="++-- | Turn a rule into an equation.+unorient :: Rule f -> Equation f+unorient (Rule _ l r) = l :=: r++-- | Turn an equation t :=: u into a rule t -> u by computing the+-- orientation info (e.g. oriented, permutative or unoriented).+--+-- Crashes if t -> u is not a valid rule, for example if there is+-- a variable in @u@ which is not in @t@. To prevent this happening,+-- combine with 'Twee.CP.split'.+orient :: Function f => Equation f -> Rule f+orient (t :=: u) = Rule o t u+  where+    o | lessEq u t =+        case unify t u of+          Nothing -> Oriented+          Just sub+            | allSubst (\_ (Cons t Empty) -> isMinimal t) sub ->+              WeaklyOriented minimal (map (build . var . fst) (substToList sub))+            | otherwise -> Unoriented+      | lessEq t u = error "wrongly-oriented rule"+      | not (null (usort (vars u) \\ usort (vars t))) =+        error "unbound variables in rule"+      | Just ts <- evalStateT (makePermutative t u) [],+        permutativeOK t u ts =+        Permutative ts+      | otherwise = Unoriented++    permutativeOK _ _ [] = True+    permutativeOK t u ((Var x, Var y):xs) =+      lessIn model u t == Just Strict &&+      permutativeOK t' u' xs+      where+        model = modelFromOrder [Variable y, Variable x]+        sub x' = if x == x' then var y else var x'+        t' = subst sub t+        u' = subst sub u++    makePermutative t u = do+      msub <- gets listToSubst+      sub  <- lift msub+      aux (subst sub t) (subst sub u)+        where+          aux (Var x) (Var y)+            | x == y = return []+            | otherwise = do+              modify ((x, build $ var y):)+              return [(build $ var x, build $ var y)]++          aux (App f ts) (App g us)+            | f == g =+              fmap concat (zipWithM makePermutative (unpack ts) (unpack us))++          aux _ _ = mzero++-- | Flip an unoriented rule so that it goes right-to-left.+backwards :: Rule f -> Rule f+backwards (Rule or t u) = Rule (back or) u t+  where+    back (Permutative xs) = Permutative (map swap xs)+    back Unoriented = Unoriented+    back _ = error "Can't turn oriented rule backwards"++--------------------------------------------------------------------------------+-- * Extra-fast rewriting, without proof output or unorientable rules.+--------------------------------------------------------------------------------++-- | Compute the normal form of a term wrt only oriented rules.+{-# INLINEABLE simplify #-}+simplify :: (Function f, Has a (Rule f)) => Index f a -> Term f -> Term f+simplify !idx !t = {-# SCC simplify #-} simplify1 idx t++{-# INLINEABLE simplify1 #-}+simplify1 :: (Function f, Has a (Rule f)) => Index f a -> Term f -> Term f+simplify1 idx t+  | t == u = t+  | otherwise = simplify idx u+  where+    u = build (simp (singleton t))++    simp Empty = mempty+    simp (Cons (Var x) t) = var x `mappend` simp t+    simp (Cons t u)+      | Just (rule, sub) <- simpleRewrite idx t =+        Term.subst sub (rhs rule) `mappend` simp u+    simp (Cons (App f ts) us) =+      app f (simp ts) `mappend` simp us++-- | Check if a term can be simplified.+{-# INLINEABLE canSimplify #-}+canSimplify :: (Function f, Has a (Rule f)) => Index f a -> Term f -> Bool+canSimplify idx t = canSimplifyList idx (singleton t)++{-# INLINEABLE canSimplifyList #-}+canSimplifyList :: (Function f, Has a (Rule f)) => Index f a -> TermList f -> Bool+canSimplifyList idx t =+  {-# SCC canSimplifyList #-}+  any (isJust . simpleRewrite idx) (filter isApp (subtermsList t))++-- | Find a simplification step that applies to a term.+{-# INLINEABLE simpleRewrite #-}+simpleRewrite :: (Function f, Has a (Rule f)) => Index f a -> Term f -> Maybe (Rule f, Subst f)+simpleRewrite idx t =+  -- Use instead of maybeToList to make fusion work+  foldr (\x _ -> Just x) Nothing $ do+    rule <- the <$> Index.approxMatches t idx+    guard (oriented (orientation rule))+    sub <- maybeToList (match (lhs rule) t)+    guard (reducesOriented rule sub)+    return (rule, sub)++--------------------------------------------------------------------------------+-- * Rewriting, with proof output.+--------------------------------------------------------------------------------++-- | A strategy gives a set of possible reductions for a term.+type Strategy f = Term f -> [Reduction f]++-- | A multi-step rewrite proof @t ->* u@+data Reduction f =+    -- | Apply a single rewrite rule to the root of a term+    Step {-# UNPACK #-} !(Lemma f) !(Rule f) !(Subst f)+    -- | Reflexivity+  | Refl {-# UNPACK #-} !(Term f)+    -- | Transivitity+  | Trans !(Reduction f) !(Reduction f)+    -- | Congruence+  | Cong {-# UNPACK #-} !(Fun f) ![Reduction f]+  deriving Show++instance Symbolic (Reduction f) where+  type ConstantOf (Reduction f) = f+  termsDL (Step _ _ sub) = termsDL sub+  termsDL (Refl t) = termsDL t+  termsDL (Trans p q) = termsDL p `mplus` termsDL q+  termsDL (Cong _ ps) = termsDL ps++  subst_ sub (Step lemma rule s) = Step lemma rule (subst_ sub s)+  subst_ sub (Refl t) = Refl (subst_ sub t)+  subst_ sub (Trans p q) = Trans (subst_ sub p) (subst_ sub q)+  subst_ sub (Cong f ps) = Cong f (subst_ sub ps)++instance Function f => Pretty (Reduction f) where+  pPrint = pPrint . reductionProof++-- | A smart constructor for Trans which simplifies Refl.+trans :: Reduction f -> Reduction f -> Reduction f+trans Refl{} p = p+trans p Refl{} = p+-- Make right-associative to improve performance of 'result'+trans p (Trans q r) = Trans (Trans p q) r+trans p q = Trans p q++-- | A smart constructor for Cong which simplifies Refl.+cong :: Fun f -> [Reduction f] -> Reduction f+cong f ps+  | all isRefl ps = Refl (result (reduce (Cong f ps)))+  | otherwise = Cong f ps+  where+    isRefl Refl{} = True+    isRefl _ = False++-- | The list of all rewrite rules used in a rewrite proof.+steps :: Reduction f -> [Reduction f]+steps r = aux r []+  where+    aux step@Step{} = (step:)+    aux (Refl _) = id+    aux (Trans p q) = aux p . aux q+    aux (Cong _ ps) = foldr (.) id (map aux ps)++-- | Turn a reduction into a proof.+reductionProof :: Reduction f -> Derivation f+reductionProof (Step lemma _ sub) =+  Proof.lemma lemma sub+reductionProof (Refl t) = Proof.Refl t+reductionProof (Trans p q) =+  Proof.trans (reductionProof p) (reductionProof q)+reductionProof (Cong f ps) = Proof.cong f (map reductionProof ps)++-- | Construct a basic rewrite step.+{-# INLINE step #-}+step :: (Has a (Rule f), Has a (Lemma f)) => a -> Subst f -> Reduction f+step x sub = Step (the x) (the x) sub++----------------------------------------------------------------------+-- | A rewrite proof with the final term attached.+-- Has an @Ord@ instance which compares the final term.+----------------------------------------------------------------------++data Resulting f =+  Resulting {+    result :: {-# UNPACK #-} !(Term f),+    reduction :: !(Reduction f) }+  deriving Show++instance Eq (Resulting f) where x == y = compare x y == EQ+instance Ord (Resulting f) where compare = comparing result++instance Symbolic (Resulting f) where+  type ConstantOf (Resulting f) = f+  termsDL (Resulting t red) =+    termsDL t `mplus` termsDL red+  subst_ sub (Resulting t red) =+    Resulting (subst_ sub t) (subst_ sub red)++instance Function f => Pretty (Resulting f) where+  pPrint = pPrint . reduction++-- | Construct a 'Resulting' from a 'Reduction'.+reduce :: Reduction f -> Resulting f+reduce p =+  Resulting (res p) p+  where+    res (Trans _ q) = res q+    res (Refl t) = t+    res p = {-# SCC res_emitRes #-} build (emitResult p)++    emitResult (Step _ r sub) = Term.subst sub (rhs r)+    emitResult (Refl t) = builder t+    emitResult (Trans _ q) = emitResult q+    emitResult (Cong f ps) = app f (map emitResult ps)++--------------------------------------------------------------------------------+-- * Strategy combinators.+--------------------------------------------------------------------------------++-- | Normalise a term wrt a particular strategy.+{-# INLINE normaliseWith #-}+normaliseWith :: Function f => (Term f -> Bool) -> Strategy f -> Term f -> Resulting f+normaliseWith ok strat t = {-# SCC normaliseWith #-} res+  where+    res = aux 0 (Refl t) t+    aux 1000 p _ =+      error $+        "Possibly nonterminating rewrite:\n" ++ prettyShow p+    aux n p t =+      case parallel strat t of+        (q:_) | u <- result (reduce q), ok u ->+          aux (n+1) (p `trans` q) u+        _ -> Resulting t p++-- | Compute all normal forms of a set of terms wrt a particular strategy.+normalForms :: Function f => Strategy f -> [Resulting f] -> Set (Resulting f)+normalForms strat ps = snd (successorsAndNormalForms strat ps)++-- | Compute all successors of a set of terms (a successor of a term @t@+-- is a term @u@ such that @t ->* u@).+successors :: Function f => Strategy f -> [Resulting f] -> Set (Resulting f)+successors strat ps = Set.union qs rs+  where+    (qs, rs) = successorsAndNormalForms strat ps++{-# INLINEABLE successorsAndNormalForms #-}+successorsAndNormalForms :: Function f => Strategy f -> [Resulting f] ->+  (Set (Resulting f), Set (Resulting f))+successorsAndNormalForms strat ps =+  {-# SCC successorsAndNormalForms #-} go Set.empty Set.empty ps+  where+    go dead norm [] = (dead, norm)+    go dead norm (p:ps)+      | p `Set.member` dead = go dead norm ps+      | p `Set.member` norm = go dead norm ps+      | null qs = go dead (Set.insert p norm) ps+      | otherwise =+        go (Set.insert p dead) norm (qs ++ ps)+      where+        qs =+          [ reduce (reduction p `Trans` q)+          | q <- anywhere strat (result p) ]++-- | Apply a strategy anywhere in a term.+anywhere :: Strategy f -> Strategy f+anywhere strat t = strat t ++ nested (anywhere strat) t++-- | Apply a strategy to some child of the root function.+nested :: Strategy f -> Strategy f+nested _ Var{} = []+nested strat (App f ts) =+  cong f <$> inner [] ts+  where+    inner _ Empty = []+    inner before (Cons t u) =+      [ reverse before ++ [p] ++ map Refl (unpack u)+      | p <- strat t ] +++      inner (Refl t:before) u++-- | Apply a strategy in parallel in as many places as possible.+-- Takes only the first rewrite of each strategy.+{-# INLINE parallel #-}+parallel :: PrettyTerm f => Strategy f -> Strategy f+parallel strat t =+  case par t of+    Refl{} -> []+    p -> [p]+  where+    par t | p:_ <- strat t = p+    par (App f ts) = cong f (inner [] ts)+    par t = Refl t++    inner before Empty = reverse before+    inner before (Cons t u) = inner (par t:before) u++--------------------------------------------------------------------------------+-- * Basic strategies. These only apply at the root of the term.+--------------------------------------------------------------------------------++-- | A strategy which rewrites using an index.+{-# INLINE rewrite #-}+rewrite :: (Function f, Has a (Rule f), Has a (Lemma f)) => (Rule f -> Subst f -> Bool) -> Index f a -> Strategy f+rewrite p rules t = do+  rule <- Index.approxMatches t rules+  tryRule p rule t++-- | A strategy which applies one rule only.+{-# INLINEABLE tryRule #-}+tryRule :: (Function f, Has a (Rule f), Has a (Lemma f)) => (Rule f -> Subst f -> Bool) -> a -> Strategy f+tryRule p rule t = do+  sub <- maybeToList (match (lhs (the rule)) t)+  guard (p (the rule) sub)+  return (step rule sub)++-- | Check if a rule can be applied, given an ordering <= on terms.+{-# INLINEABLE reducesWith #-}+reducesWith :: Function f => (Term f -> Term f -> Bool) -> Rule f -> Subst f -> Bool+reducesWith _ (Rule Oriented _ _) _ = True+reducesWith _ (Rule (WeaklyOriented min ts) _ _) sub =+  -- Be a bit careful here not to build new terms+  -- (reducesWith is used in simplify).+  -- This is the same as:+  --   any (not . isMinimal) (subst sub ts)+  any (not . isMinimal . expand) ts+  where+    expand t@(Var x) = fromMaybe t (Term.lookup x sub)+    expand t = t++    isMinimal (App f Empty) = f == min+    isMinimal _ = False+reducesWith p (Rule (Permutative ts) _ _) sub =+  aux ts+  where+    aux [] = False+    aux ((t, u):ts)+      | t' == u' = aux ts+      | otherwise = p u' t'+      where+        t' = subst sub t+        u' = subst sub u+reducesWith p (Rule Unoriented t u) sub =+  p u' t' && u' /= t'+  where+    t' = subst sub t+    u' = subst sub u++-- | Check if a rule can be applied normally.+{-# INLINEABLE reduces #-}+reduces :: Function f => Rule f -> Subst f -> Bool+reduces rule sub = reducesWith lessEq rule sub++-- | Check if a rule can be applied and is oriented.+{-# INLINEABLE reducesOriented #-}+reducesOriented :: Function f => Rule f -> Subst f -> Bool+reducesOriented rule sub =+  oriented (orientation rule) && reducesWith undefined rule sub++-- | Check if a rule can be applied in a particular model.+{-# INLINEABLE reducesInModel #-}+reducesInModel :: Function f => Model f -> Rule f -> Subst f -> Bool+reducesInModel cond rule sub =+  reducesWith (\t u -> isJust (lessIn cond t u)) rule sub++-- | Check if a rule can be applied to the Skolemised version of a term.+{-# INLINEABLE reducesSkolem #-}+reducesSkolem :: Function f => Rule f -> Subst f -> Bool+reducesSkolem rule sub =+  reducesWith (\t u -> lessEq (subst skolemise t) (subst skolemise u)) rule sub+  where+    skolemise = con . skolem
+ Twee/Rule/Index.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE RecordWildCards, ScopedTypeVariables, FlexibleContexts #-}+module Twee.Rule.Index(+  RuleIndex(..),+  empty, insert, delete,+  approxMatches, matches, lookup) where++import Prelude hiding (lookup)+import Twee.Base hiding (lookup, empty)+import Twee.Rule+import Twee.Index hiding (insert, delete, empty)+import qualified Twee.Index as Index++data RuleIndex f a =+  RuleIndex {+    index_oriented :: !(Index f a),+    index_weak     :: !(Index f a),+    index_all      :: !(Index f a) }+  deriving Show++empty :: RuleIndex f a+empty = RuleIndex Index.empty Index.empty Index.empty++insert :: forall f a. Has a (Rule f) => Term f -> a -> RuleIndex f a -> RuleIndex f a+insert t x RuleIndex{..} =+  RuleIndex {+    index_oriented = insertWhen (oriented or) index_oriented,+    index_weak = insertWhen (weaklyOriented or) index_weak,+    index_all = insertWhen True index_all }+  where+    Rule or _ _ = the x :: Rule f++    insertWhen False idx = idx+    insertWhen True idx = Index.insert t x idx++delete :: forall f a. (Eq a, Has a (Rule f)) => Term f -> a -> RuleIndex f a -> RuleIndex f a+delete t x RuleIndex{..} =+  RuleIndex {+    index_oriented = deleteWhen (oriented or) index_oriented,+    index_weak = deleteWhen (weaklyOriented or) index_weak,+    index_all = deleteWhen True index_all }+  where+    Rule or _ _ = the x :: Rule f++    deleteWhen False idx = idx+    deleteWhen True idx = Index.delete t x idx
+ Twee/Task.hs view
@@ -0,0 +1,56 @@+-- | A module which can run housekeeping tasks every so often.+{-# LANGUAGE RecordWildCards #-}+module Twee.Task(Task, newTask, checkTask) where++import System.CPUTime+import Data.IORef+import Control.Monad.IO.Class++data TaskData m a =+  TaskData {+    -- When was the task created?+    task_start :: !Integer,+    -- When was the task last run?+    task_last :: !Integer,+    -- How long have we spent on this task so far?+    task_spent :: !Integer,+    -- How often should we run this task at most, in seconds?+    task_frequency :: !Double,+    -- What proportion of our time should we spend on the task?+    task_budget :: !Double,+    -- The task itself+    task_what :: m a }++-- | A task which runs in the monad @m@ and produces a value of type @a@.+newtype Task m a = Task (IORef (TaskData m a))++-- | Create a new task that should be run a certain proportion+-- of the time. The first argument is how often in seconds the+-- task should run, at most. The second argument is the maximum+-- percentage of time that should be spent on the task.+newTask :: MonadIO m => Double -> Double -> m a -> m (Task m a)+newTask freq budget what = liftIO $ do+  now <- getCPUTime+  Task <$> newIORef (TaskData now now 0 freq budget what)++-- | Run a task if it's time to run it.+checkTask :: MonadIO m => Task m a -> m (Maybe a)+checkTask (Task ref) = do+  task@TaskData{..} <- liftIO $ readIORef ref+  now <- liftIO getCPUTime+  if not (taskDue now task) then return Nothing else do+    res <- task_what+    after <- liftIO getCPUTime+    liftIO $ writeIORef ref task {+      task_last = after,+      task_spent = task_spent + (after-now) }+    return (Just res)++-- Check if a task should be run now.+taskDue :: Integer -> TaskData m a -> Bool+taskDue now TaskData{..} =+  -- Don't run more than the frequency says.+  fromInteger (now - task_last) >= task_frequency * 10^12 &&+  -- Run if we spent less than task_budget proportion of the total time so far.+  -- Use > rather than >= so that tasks with zero budget never get run.+  fromInteger (now - task_start) * task_budget > fromInteger task_spent
+ Twee/Term.hs view
@@ -0,0 +1,647 @@+-- | Terms and substitutions.+--+-- Terms in twee are represented as arrays rather than as an algebraic data+-- type. This module defines pattern synonyms ('App', 'Var', 'Cons', 'Empty')+-- which means that pattern matching on terms works just as normal.+-- The pattern synonyms can not be used to create new terms; for that you+-- have to use a builder interface ('Build').+--+-- This module also provides:+--+--   * pattern synonyms for iterating through a term one symbol at a time+--     ('ConsSym');+--   * substitutions ('Substitution', 'Subst', 'subst');+--   * unification ('unify') and matching ('match');+--   * miscellaneous useful functions on terms.+{-# LANGUAGE BangPatterns, PatternSynonyms, ViewPatterns, TypeFamilies, OverloadedStrings, ScopedTypeVariables #-}+module Twee.Term(+  -- * Terms+  Term, pattern Var, pattern App, isApp, isVar, singleton, len,+  -- * Termlists+  TermList, pattern Empty, pattern Cons, pattern ConsSym,+  pattern UnsafeCons, pattern UnsafeConsSym,+  empty, unpack, lenList,+  -- * Function symbols and variables+  Fun, fun, fun_id, fun_value, pattern F, Var(..), +  -- * Building terms+  Build(..),+  Builder,+  build, buildList,+  con, app, var,+  -- * Access to subterms+  children, properSubterms, subtermsList, subterms, occurs, isSubtermOf, isSubtermOfList, at,+  -- * Substitutions+  Substitution(..),+  subst,+  Subst(..),+  -- ** Constructing and querying substitutions+  emptySubst, listToSubst, substToList,+  lookup, lookupList,+  extend, extendList, unsafeExtendList,+  retract,+  -- ** Other operations on substitutions+  foldSubst, allSubst, substDomain,+  substSize,+  substCompose, substCompatible, substUnion, idempotent, idempotentOn,+  canonicalise,+  -- * Matching+  match, matchIn, matchList, matchListIn, isInstanceOf, isVariantOf,+  -- * Unification+  unify, unifyList,+  unifyTri, unifyListTri,+  TriangleSubst(..),+  close,+  -- * Positions in terms+  positionToPath, pathToPosition,+  replacePosition,+  replacePositionSub,+  -- * Miscellaneous functions+  bound, boundList, boundLists, mapFun, mapFunList, (<<)) where++import Prelude hiding (lookup)+import Twee.Term.Core hiding (F)+import Data.List hiding (lookup, find)+import Data.Maybe+import Data.Monoid+import Data.IntMap.Strict(IntMap)+import qualified Data.IntMap.Strict as IntMap++--------------------------------------------------------------------------------+-- * A type class for builders+--------------------------------------------------------------------------------++-- | Instances of 'Build' can be turned into terms using 'build' or 'buildList',+-- and turned into term builders using 'builder'. Has instances for terms,+-- termlists, builders, and Haskell lists.+class Build a where+  -- | The underlying type of function symbols.+  type BuildFun a+  -- | Convert a value into a 'Builder'.+  builder :: a -> Builder (BuildFun a)++instance Build (Builder f) where+  type BuildFun (Builder f) = f+  builder = id++instance Build (Term f) where+  type BuildFun (Term f) = f+  builder = emitTermList . singleton++instance Build (TermList f) where+  type BuildFun (TermList f) = f+  builder = emitTermList++instance Build a => Build [a] where+  type BuildFun [a] = BuildFun a+  {-# INLINE builder #-}+  builder = mconcat . map builder++-- | Build a term. The given builder must produce exactly one term.+{-# INLINE build #-}+build :: Build a => a -> Term (BuildFun a)+build x =+  case buildList x of+    Cons t Empty -> t++-- | Build a termlist.+{-# INLINE buildList #-}+buildList :: Build a => a -> TermList (BuildFun a)+buildList x = {-# SCC buildList #-} buildTermList (builder x)++-- | Build a constant (a function with no arguments).+{-# INLINE con #-}+con :: Fun f -> Builder f+con x = emitApp x mempty++-- | Build a function application.+{-# INLINE app #-}+app :: Build a => Fun (BuildFun a) -> a -> Builder (BuildFun a)+app f ts = emitApp f (builder ts)++-- | Build a variable.+var :: Var -> Builder f+var = emitVar++--------------------------------------------------------------------------------+-- Functions for substitutions.+--------------------------------------------------------------------------------++{-# INLINE substToList' #-}+substToList' :: Subst f -> [(Var, TermList f)]+substToList' (Subst sub) = [(V x, t) | (x, t) <- IntMap.toList sub]++-- | Convert a substitution to a list of bindings.+{-# INLINE substToList #-}+substToList :: Subst f -> [(Var, Term f)]+substToList sub =+  [(x, t) | (x, Cons t Empty) <- substToList' sub]++-- | Fold a function over a substitution.+{-# INLINE foldSubst #-}+foldSubst :: (Var -> TermList f -> b -> b) -> b -> Subst f -> b+foldSubst op e !sub = foldr (uncurry op) e (substToList' sub)++-- | Check if all bindings of a substitution satisfy a given property.+{-# INLINE allSubst #-}+allSubst :: (Var -> TermList f -> Bool) -> Subst f -> Bool+allSubst p = foldSubst (\x t y -> p x t && y) True++-- | Compute the set of variables bound by a substitution.+{-# INLINE substDomain #-}+substDomain :: Subst f -> [Var]+substDomain (Subst sub) = map V (IntMap.keys sub)++--------------------------------------------------------------------------------+-- Substitution.+--------------------------------------------------------------------------------++-- | A class for values which act as substitutions.+--+-- Instances include 'Subst' as well as functions from variables to terms.+class Substitution s where+  -- | The underlying type of function symbols.+  type SubstFun s++  -- | Apply the substitution to a variable.+  evalSubst :: s -> Var -> Builder (SubstFun s)++  -- | Apply the substitution to a termlist.+  {-# INLINE substList #-}+  substList :: s -> TermList (SubstFun s) -> Builder (SubstFun s)+  substList sub ts = aux ts+    where+      aux Empty = mempty+      aux (Cons (Var x) ts) = evalSubst sub x <> aux ts+      aux (Cons (App f ts) us) = app f (aux ts) <> aux us++instance (Build a, v ~ Var) => Substitution (v -> a) where+  type SubstFun (v -> a) = BuildFun a++  {-# INLINE evalSubst #-}+  evalSubst sub x = builder (sub x)++instance Substitution (Subst f) where+  type SubstFun (Subst f) = f++  {-# INLINE evalSubst #-}+  evalSubst sub x =+    case lookupList x sub of+      Nothing -> var x+      Just ts -> builder ts++-- | Apply a substitution to a term.+{-# INLINE subst #-}+subst :: Substitution s => s -> Term (SubstFun s) -> Builder (SubstFun s)+subst sub t = substList sub (singleton t)++-- | A substitution which maps variables to terms of type @'Term' f@.+newtype Subst f =+  Subst {+    unSubst :: IntMap (TermList f) }+  deriving Eq++-- | Return the highest-number variable in a substitution plus 1.+{-# INLINE substSize #-}+substSize :: Subst f -> Int+substSize (Subst sub)+  | IntMap.null sub = 0+  | otherwise = fst (IntMap.findMax sub) + 1++-- | Look up a variable in a substitution, returning a termlist.+{-# INLINE lookupList #-}+lookupList :: Var -> Subst f -> Maybe (TermList f)+lookupList x (Subst sub) = IntMap.lookup (var_id x) sub++-- | Add a new binding to a substitution, giving a termlist.+{-# INLINE extendList #-}+extendList :: Var -> TermList f -> Subst f -> Maybe (Subst f)+extendList x !t (Subst sub) =+  case IntMap.lookup (var_id x) sub of+    Nothing -> Just $! Subst (IntMap.insert (var_id x) t sub)+    Just u+      | t == u    -> Just (Subst sub)+      | otherwise -> Nothing++-- | Remove a binding from a substitution.+{-# INLINE retract #-}+retract :: Var -> Subst f -> Subst f+retract x (Subst sub) = Subst (IntMap.delete (var_id x) sub)++-- | Add a new binding to a substitution.+-- Overwrites any existing binding.+{-# INLINE unsafeExtendList #-}+unsafeExtendList :: Var -> TermList f -> Subst f -> Subst f+unsafeExtendList x !t (Subst sub) = Subst (IntMap.insert (var_id x) t sub)++-- | Compose two substitutions.+substCompose :: Substitution s => Subst (SubstFun s) -> s -> Subst (SubstFun s)+substCompose (Subst !sub1) !sub2 =+  Subst (IntMap.map (buildList . substList sub2) sub1)++-- | Check if two substitutions are compatible (they do not send the same+-- variable to different terms).+substCompatible :: Subst f -> Subst f -> Bool+substCompatible (Subst !sub1) (Subst !sub2) =+  IntMap.null (IntMap.mergeWithKey f g h sub1 sub2)+  where+    f _ t u+      | t == u = Nothing+      | otherwise = Just t+    g _ = IntMap.empty+    h _ = IntMap.empty++-- | Take the union of two substitutions.+-- The substitutions must be compatible, which is not checked.+substUnion :: Subst f -> Subst f -> Subst f+substUnion (Subst !sub1) (Subst !sub2) =+  Subst (IntMap.union sub1 sub2)++-- | Check if a substitution is idempotent (applying it twice has the same+-- effect as applying it once).+{-# INLINE idempotent #-}+idempotent :: Subst f -> Bool+idempotent !sub = allSubst (\_ t -> sub `idempotentOn` t) sub++-- | Check if a substitution has no effect on a given term.+{-# INLINE idempotentOn #-}+idempotentOn :: Subst f -> TermList f -> Bool+idempotentOn !sub = aux+  where+    aux Empty = True+    aux (ConsSym App{} t) = aux t+    aux (Cons (Var x) t) = isNothing (lookupList x sub) && aux t++-- | Iterate a triangle substitution to make it idempotent.+close :: TriangleSubst f -> Subst f+close (Triangle sub)+  | idempotent sub = sub+  | otherwise      = close (Triangle (substCompose sub sub))++-- | Return a substitution which renames the variables of a list of terms to put+-- them in a canonical order.+canonicalise :: [TermList f] -> Subst f+canonicalise [] = emptySubst+canonicalise (t:ts) = loop emptySubst vars t ts+  where+    (V m, V n) = boundLists (t:ts)+    vars =+      buildTermList $+        -- Produces two variables when the term is ground+        -- (n = minBound, m = maxBound), which is OK.+        mconcat [emitVar (V x) | x <- [0..n-m+1]]++    loop !_ !_ !_ !_ | False = undefined+    loop sub _ Empty [] = sub+    loop sub Empty _ _ = sub+    loop sub vs Empty (t:ts) = loop sub vs t ts+    loop sub vs (ConsSym App{} t) ts = loop sub vs t ts+    loop sub vs0@(Cons v vs) (Cons (Var x) t) ts =+      case extend x v sub of+        Just sub -> loop sub vs  t ts+        Nothing  -> loop sub vs0 t ts++-- | The empty substitution.+{-# NOINLINE emptySubst #-}+emptySubst = Subst IntMap.empty++-- | Construct a substitution from a list.+-- Returns @Nothing@ if a variable is bound to several different terms.+listToSubst :: [(Var, Term f)] -> Maybe (Subst f)+listToSubst sub = matchList pat t+  where+    pat = buildList (map (var . fst) sub)+    t   = buildList (map snd sub)++--------------------------------------------------------------------------------+-- Matching.+--------------------------------------------------------------------------------++-- | @'match' pat t@ matches the term @t@ against the pattern @pat@.+{-# INLINE match #-}+match :: Term f -> Term f -> Maybe (Subst f)+match pat t = matchList (singleton pat) (singleton t)++-- | A variant of 'match' which extends an existing substitution.+{-# INLINE matchIn #-}+matchIn :: Subst f -> Term f -> Term f -> Maybe (Subst f)+matchIn sub pat t = matchListIn sub (singleton pat) (singleton t)++-- | A variant of 'match' which works on termlists.+{-# INLINE matchList #-}+matchList :: TermList f -> TermList f -> Maybe (Subst f)+matchList pat t = matchListIn emptySubst pat t++-- | A variant of 'match' which works on termlists+-- and extends an existing substitution.+matchListIn :: Subst f -> TermList f -> TermList f -> Maybe (Subst f)+matchListIn !sub !pat !t+  | lenList t < lenList pat = Nothing+  | otherwise =+    let loop !_ !_ !_ | False = undefined+        loop sub Empty Empty = Just sub+        loop sub (ConsSym (App f _) pat) (ConsSym (App g _) t)+          | f == g = loop sub pat t+        loop sub (Cons (Var x) pat) (Cons t u) = do+          sub <- extend x t sub+          loop sub pat u+        loop _ _ _ = Nothing+    in {-# SCC match #-} loop sub pat t++--------------------------------------------------------------------------------+-- Unification.+--------------------------------------------------------------------------------++-- | A triangle substitution is one in which variables can be defined in terms+-- of each other, though not in a circular way.+--+-- The main use of triangle substitutions is in unification; 'unifyTri' returns+-- one. A triangle substitution can be converted to an ordinary substitution+-- with 'close', or used directly using its 'Substitution' instance.+newtype TriangleSubst f = Triangle { unTriangle :: Subst f }+  deriving Show++instance Substitution (TriangleSubst f) where+  type SubstFun (TriangleSubst f) = f++  {-# INLINE evalSubst #-}+  evalSubst (Triangle sub) x =+    case lookupList x sub of+      Nothing  -> var x+      Just ts  -> substList (Triangle sub) ts++  -- Redefine substList to get better inlining behaviour+  {-# INLINE substList #-}+  substList (Triangle sub) ts = aux ts+    where+      aux Empty = mempty+      aux (Cons (Var x) ts) = auxVar x <> aux ts+      aux (Cons (App f ts) us) = app f (aux ts) <> aux us++      auxVar x =+        case lookupList x sub of+          Nothing -> var x+          Just ts -> aux ts++-- | Unify two terms.+unify :: Term f -> Term f -> Maybe (Subst f)+unify t u = unifyList (singleton t) (singleton u)++-- | Unify two termlists.+unifyList :: TermList f -> TermList f -> Maybe (Subst f)+unifyList t u = do+  sub <- unifyListTri t u+  -- Not strict so that isJust (unify t u) doesn't force the substitution+  return (close sub)++-- | Unify two terms, returning a triangle substitution.+-- This is slightly faster than 'unify'.+unifyTri :: Term f -> Term f -> Maybe (TriangleSubst f)+unifyTri t u = unifyListTri (singleton t) (singleton u)++-- | Unify two termlists, returning a triangle substitution.+-- This is slightly faster than 'unify'.+unifyListTri :: TermList f -> TermList f -> Maybe (TriangleSubst f)+unifyListTri !t !u = fmap Triangle ({-# SCC unify #-} loop emptySubst t u)+  where+    loop !_ !_ !_ | False = undefined+    loop sub Empty Empty = Just sub+    loop sub (ConsSym (App f _) t) (ConsSym (App g _) u)+      | f == g = loop sub t u+    loop sub (Cons (Var x) t) (Cons u v) = do+      sub <- var sub x u+      loop sub t v+    loop sub (Cons t u) (Cons (Var x) v) = do+      sub <- var sub x t+      loop sub u v+    loop _ _ _ = Nothing++    var sub x t =+      case lookupList x sub of+        Just u -> loop sub u (singleton t)+        Nothing -> var1 sub x t++    var1 sub x t@(Var y)+      | x == y = return sub+      | otherwise =+        case lookup y sub of+          Just t  -> var1 sub x t+          Nothing -> extend x t sub++    var1 sub x t = do+      occurs sub x (singleton t)+      extend x t sub++    occurs !_ !_ Empty = Just ()+    occurs sub x (ConsSym App{} t) = occurs sub x t+    occurs sub x (ConsSym (Var y) t)+      | x == y = Nothing+      | otherwise = do+          occurs sub x t+          case lookupList y sub of+            Nothing -> Just ()+            Just u  -> occurs sub x u++--------------------------------------------------------------------------------+-- Miscellaneous stuff.+--------------------------------------------------------------------------------++-- | The empty termlist.+{-# NOINLINE empty #-}+empty :: forall f. TermList f+empty = buildList (mempty :: Builder f)++-- | Get the children (direct subterms) of a term.+children :: Term f -> TermList f+children t =+  case singleton t of+    UnsafeConsSym _ ts -> ts++-- | Convert a termlist into an ordinary list of terms.+unpack :: TermList f -> [Term f]+unpack t = unfoldr op t+  where+    op Empty = Nothing+    op (Cons t ts) = Just (t, ts)++instance Show (Term f) where+  show (Var x) = show x+  show (App f Empty) = show f+  show (App f ts) = show f ++ "(" ++ intercalate "," (map show (unpack ts)) ++ ")"++instance Show (TermList f) where+  show = show . unpack++instance Show (Subst f) where+  show subst =+    show+      [ (i, t)+      | i <- [0..substSize subst-1],+        Just t <- [lookup (V i) subst] ]++-- | Look up a variable in a substitution.+{-# INLINE lookup #-}+lookup :: Var -> Subst f -> Maybe (Term f)+lookup x s = do+  Cons t Empty <- lookupList x s+  return t++-- | Add a new binding to a substitution.+{-# INLINE extend #-}+extend :: Var -> Term f -> Subst f -> Maybe (Subst f)+extend x t sub = extendList x (singleton t) sub++-- | Find the length of a term.+{-# INLINE len #-}+len :: Term f -> Int+len = lenList . singleton++-- | Return the lowest- and highest-numbered variables in a term.+{-# INLINE bound #-}+bound :: Term f -> (Var, Var)+bound t = boundList (singleton t)++-- | Return the lowest- and highest-numbered variables in a termlist.+{-# INLINE boundList #-}+boundList :: TermList f -> (Var, Var)+boundList t = boundListFrom (V maxBound) (V minBound) t++boundListFrom :: Var -> Var -> TermList f -> (Var, Var)+boundListFrom !m !n Empty = (m, n)+boundListFrom m n (ConsSym App{} t) = boundListFrom m n t+boundListFrom m n (ConsSym (Var x) t) =+  boundListFrom (m `min` x) (n `max` x) t++-- | Return the lowest- and highest-numbered variables in a list of termlists.+boundLists :: [TermList f] -> (Var, Var)+boundLists t = boundListsFrom (V maxBound) (V minBound) t++boundListsFrom :: Var -> Var -> [TermList f] -> (Var, Var)+boundListsFrom !m !n [] = (m, n)+boundListsFrom m n (t:ts) =+  let+    (m', n') = boundListFrom m n t+  in+    boundListsFrom m' n' ts++-- | Check if a variable occurs in a term.+{-# INLINE occurs #-}+occurs :: Var -> Term f -> Bool+occurs x t = occursList x (singleton t)++-- | Find all subterms of a termlist.+{-# INLINE subtermsList #-}+subtermsList :: TermList f -> [Term f]+subtermsList t = unfoldr op t+  where+    op Empty = Nothing+    op (ConsSym t u) = Just (t, u)++-- | Find all subterms of a term.+{-# INLINE subterms #-}+subterms :: Term f -> [Term f]+subterms = subtermsList . singleton++-- | Find all proper subterms of a term.+{-# INLINE properSubterms #-}+properSubterms :: Term f -> [Term f]+properSubterms = subtermsList . children++-- | Check if a term is a function application.+isApp :: Term f -> Bool+isApp App{} = True+isApp _     = False++-- | Check if a term is a variable+isVar :: Term f -> Bool+isVar Var{} = True+isVar _     = False++-- | @t \`'isInstanceOf'\` pat@ checks if @t@ is an instance of @pat@.+isInstanceOf :: Term f -> Term f -> Bool+t `isInstanceOf` pat = isJust (match pat t)++-- | Check if two terms are renamings of one another.+isVariantOf :: Term f -> Term f -> Bool+t `isVariantOf` u = t `isInstanceOf` u && u `isInstanceOf` t++-- | Is a term a subterm of another one?+isSubtermOf :: Term f -> Term f -> Bool+t `isSubtermOf` u = t `isSubtermOfList` singleton u++-- | Map a function over the function symbols in a term.+mapFun :: (Fun f -> Fun g) -> Term f -> Builder g+mapFun f = mapFunList f . singleton++-- | Map a function over the function symbols in a termlist.+mapFunList :: (Fun f -> Fun g) -> TermList f -> Builder g+mapFunList f ts = aux ts+  where+    aux Empty = mempty+    aux (Cons (Var x) ts) = var x `mappend` aux ts+    aux (Cons (App ff ts) us) = app (f ff) (aux ts) `mappend` aux us++-- | Replace the term at a given position in a term with a different term.+{-# INLINE replacePosition #-}+replacePosition :: (Build a, BuildFun a ~ f) => Int -> a -> TermList f -> Builder f+replacePosition n !x = aux n+  where+    aux !_ !_ | False = undefined+    aux _ Empty = mempty+    aux 0 (Cons _ t) = builder x `mappend` builder t+    aux n (Cons (Var x) t) = var x `mappend` aux (n-1) t+    aux n (Cons t@(App f ts) u)+      | n < len t =+        app f (aux (n-1) ts) `mappend` builder u+      | otherwise =+        builder t `mappend` aux (n-len t) u++-- | Replace the term at a given position in a term with a different term, while+-- simultaneously applying a substitution. Useful for building critical pairs.+{-# INLINE replacePositionSub #-}+replacePositionSub :: (Substitution sub, SubstFun sub ~ f) => sub -> Int -> TermList f -> TermList f -> Builder f+replacePositionSub sub n !x = aux n+  where+    aux !_ !_ | False = undefined+    aux _ Empty = mempty+    aux n (Cons t u)+      | n < len t = inside n t `mappend` outside u+      | otherwise = outside (singleton t) `mappend` aux (n-len t) u++    inside 0 _ = outside x+    inside n (App f ts) = app f (aux (n-1) ts)+    inside _ _ = undefined -- implies n >= len t++    outside t = substList sub t++-- | Convert a position in a term, expressed as a single number, into a path.+positionToPath :: Term f -> Int -> [Int]+positionToPath t n = term t n+  where+    term _ 0 = []+    term t n = list 0 (children t) (n-1)++    list _ Empty _ = error "bad position"+    list k (Cons t u) n+      | n < len t = k:term t n+      | otherwise = list (k+1) u (n-len t)++-- | Convert a path in a term into a position.+pathToPosition :: Term f -> [Int] -> Int+pathToPosition t ns = term 0 t ns+  where+    term k _ [] = k+    term k t (n:ns) = list (k+1) (children t) n ns++    list _ Empty _ _ = error "bad path"+    list k (Cons t _) 0 ns = term k t ns+    list k (Cons t u) n ns =+      list (k+len t) u (n-1) ns++-- | A pattern which extracts the 'fun_value' from a 'Fun'.+pattern F :: f -> Fun f+pattern F x <- (fun_value -> x)+{-# COMPLETE F #-}++-- | Compare the 'fun_value's of two 'Fun's.+(<<) :: Ord f => Fun f -> Fun f -> Bool+f << g = fun_value f < fun_value g
+ Twee/Term/Core.hs view
@@ -0,0 +1,427 @@+-- Terms and substitutions, implemented using flatterms.+-- This module contains all the low-level icky bits+-- and provides primitives for building higher-level stuff.+{-# LANGUAGE CPP, PatternSynonyms, ViewPatterns,+    MagicHash, UnboxedTuples, BangPatterns,+    RankNTypes, RecordWildCards, GeneralizedNewtypeDeriving #-}+module Twee.Term.Core where++import Data.Primitive(sizeOf)+#ifdef BOUNDS_CHECKS+import Data.Primitive.ByteArray.Checked+#else+import Data.Primitive.ByteArray+#endif+import Control.Monad.ST.Strict+import Data.Bits+import Data.Int+import GHC.Int(Int(..))+import GHC.Prim+import GHC.ST hiding (liftST)+import Data.Ord+import Twee.Label+import Data.Typeable++--------------------------------------------------------------------------------+-- Symbols. A symbol is a single function or variable in a flatterm.+--------------------------------------------------------------------------------++data Symbol =+  Symbol {+    -- Is it a function?+    isFun :: Bool,+    -- What is its number?+    index :: Int,+    -- What is the size of the term rooted at this symbol?+    size  :: Int }++instance Show Symbol where+  show Symbol{..}+    | isFun = show (F index) ++ "=" ++ show size+    | otherwise = show (V index)++-- Convert symbols to/from Int64 for storage in flatterms.+-- The encoding:+--   * bits 0-30: size+--   * bit  31: 0 (variable) or 1 (function)+--   * bits 32-63: index+{-# INLINE toSymbol #-}+toSymbol :: Int64 -> Symbol+toSymbol n =+  Symbol (testBit n 31)+    (fromIntegral (n `unsafeShiftR` 32))+    (fromIntegral (n .&. 0x7fffffff))++{-# INLINE fromSymbol #-}+fromSymbol :: Symbol -> Int64+fromSymbol Symbol{..} =+  fromIntegral size ++  fromIntegral index `unsafeShiftL` 32 ++  fromIntegral (fromEnum isFun) `unsafeShiftL` 31++--------------------------------------------------------------------------------+-- Flatterms, or rather lists of terms.+--------------------------------------------------------------------------------++-- | @'TermList' f@ is a list of terms whose function symbols have type @f@.+-- It is either a 'Cons' or an 'Empty'. You can turn it into a @['Term' f]@+-- with 'Twee.Term.unpack'.++-- A TermList is a slice of an unboxed array of symbols.+data TermList f =+  TermList {+    low   :: {-# UNPACK #-} !Int,+    high  :: {-# UNPACK #-} !Int,+    array :: {-# UNPACK #-} !ByteArray }++-- | Index into a termlist.+at :: Int -> TermList f -> Term f+at n (TermList lo hi arr)+  | n < 0 || lo+n >= hi = error "term index out of bounds"+  | otherwise =+    case TermList (lo+n) hi arr of+      UnsafeCons t _ -> t++{-# INLINE lenList #-}+-- | The length of (number of symbols in) a termlist.+lenList :: TermList f -> Int+lenList (TermList low high _) = high - low++-- | @'Term' f@ is a term whose function symbols have type @f@.+-- It is either a 'Var' or an 'App'.++-- A term is a special case of a termlist.+-- We store it as the termlist together with the root symbol.+data Term f =+  Term {+    root     :: {-# UNPACK #-} !Int64,+    termlist :: {-# UNPACK #-} !(TermList f) }++instance Eq (Term f) where+  x == y = termlist x == termlist y++instance Ord (Term f) where+  compare = comparing termlist++-- Pattern synonyms for termlists:+-- * Empty :: TermList f+--   Empty is the empty termlist.+-- * Cons t ts :: Term f -> TermList f -> TermList f+--   Cons t ts is the termlist t:ts.+-- * ConsSym t ts :: Term f -> TermList f -> TermList f+--   ConsSym t ts is like Cons t ts but ts also includes t's children+--   (operationally, ts seeks one term to the right in the termlist).+-- * UnsafeCons/UnsafeConsSym: like Cons and ConsSym but don't check+--   that the termlist is non-empty.++-- | Matches the empty termlist.+pattern Empty :: TermList f+pattern Empty <- (patHead -> Nothing)++-- | Matches a non-empty termlist, unpacking it into head and tail.+pattern Cons :: Term f -> TermList f -> TermList f+pattern Cons t ts <- (patHead -> Just (t, _, ts))++{-# COMPLETE Empty, Cons #-}+{-# COMPLETE Empty, ConsSym #-}++-- | Like 'Cons', but does not check that the termlist is non-empty. Use only if+-- you are sure the termlist is non-empty.+pattern UnsafeCons :: Term f -> TermList f -> TermList f+pattern UnsafeCons t ts <- (unsafePatHead -> Just (t, _, ts))++-- | Matches a non-empty termlist, unpacking it into head and+-- /everything except the root symbol of the head/.+-- Useful for iterating through terms one symbol at a time.+--+-- For example, if @ts@ is the termlist @[f(x,y), g(z)]@,+-- then @let ConsSym u us = ts@ results in the following bindings:+--+-- > u  = f(x,y)+-- > us = [x, y, g(z)]+pattern ConsSym :: Term f -> TermList f -> TermList f+pattern ConsSym t ts <- (patHead -> Just (t, ts, _))++-- | Like 'ConsSym', but does not check that the termlist is non-empty. Use only+-- if you are sure the termlist is non-empty.+pattern UnsafeConsSym :: Term f -> TermList f -> TermList f+pattern UnsafeConsSym t ts <- (unsafePatHead -> Just (t, ts, _))++-- A helper for UnsafeCons/UnsafeConsSym.+{-# INLINE unsafePatHead #-}+unsafePatHead :: TermList f -> Maybe (Term f, TermList f, TermList f)+unsafePatHead TermList{..} =+  Just (Term x (TermList low (low+size) array),+        TermList (low+1) high array,+        TermList (low+size) high array)+  where+    !x = indexByteArray array low+    Symbol{..} = toSymbol x++-- A helper for Cons/ConsSym.+{-# INLINE patHead #-}+patHead :: TermList f -> Maybe (Term f, TermList f, TermList f)+patHead t@TermList{..}+  | low == high = Nothing+  | otherwise = unsafePatHead t++-- Pattern synonyms for single terms.+-- * Var :: Var -> Term f+-- * App :: Fun f -> TermList f -> Term f++-- | A function symbol. @f@ is the underlying type of function symbols defined+-- by the user; @'Fun' f@ is an @f@ together with an automatically-generated unique number.+newtype Fun f =+  F {+    -- | The unique number of a 'Fun'.+    fun_id :: Int }+instance Eq (Fun f) where+  f == g = fun_id f == fun_id g+instance Ord (Fun f) where+  compare = comparing fun_id++-- | Construct a 'Fun' from a function symbol.+fun :: (Ord f, Typeable f) => f -> Fun f+fun f = F (fromIntegral (labelNum (label f)))++-- | The underlying function symbol of a 'Fun'.+fun_value :: Fun f -> f+fun_value f = find (unsafeMkLabel (fromIntegral (fun_id f)))++-- | A variable.+newtype Var =+  V {+    -- | The variable's number.+    -- Don't use huge variable numbers:+    -- they will be truncated to 32 bits when stored in a term.+    var_id :: Int } deriving (Eq, Ord, Enum)+instance Show (Fun f) where show f = "f" ++ show (fun_id f)+instance Show Var     where show x = "x" ++ show (var_id x)++-- | Matches a variable.+pattern Var :: Var -> Term f+pattern Var x <- (patTerm -> Left x)++-- | Matches a function application.+pattern App :: Fun f -> TermList f -> Term f+pattern App f ts <- (patTerm -> Right (f, ts))++{-# COMPLETE Var, App #-}++-- A helper function for Var and App.+{-# INLINE patTerm #-}+patTerm :: Term f -> Either Var (Fun f, TermList f)+patTerm t@Term{..}+  | isFun     = Right (F index, ts)+  | otherwise = Left (V index)+  where+    Symbol{..} = toSymbol root+    !(UnsafeConsSym _ ts) = singleton t++-- | Convert a term to a termlist.+{-# INLINE singleton #-}+singleton :: Term f -> TermList f+singleton Term{..} = termlist++-- We can implement equality almost without access to the+-- internal representation of the termlists, but we cheat by+-- comparing Int64s instead of Symbols.+instance Eq (TermList f) where+  -- Manual worker-wrapper to prevent too much from being inlined.+  t == u = eqTermList t u++{-# INLINE eqTermList #-}+eqTermList :: TermList f -> TermList f -> Bool+eqTermList+  (TermList (I# low1) (I# high1) (ByteArray array1))+  (TermList (I# low2) (I# high2) (ByteArray array2)) =+    weqTermList low1 high1 array1 low2 high2 array2++-- Manually worker-wrapper transform the thing, ugh...+{-# NOINLINE weqTermList #-}+weqTermList ::+  Int# -> Int# -> ByteArray# ->+  Int# -> Int# -> ByteArray# ->+  Bool+weqTermList low1 high1 array1 low2 high2 array2 =+  lenList t == lenList u && eqSameLength t u+  where+    t = TermList (I# low1) (I# high1) (ByteArray array1)+    u = TermList (I# low2) (I# high2) (ByteArray array2)+    eqSameLength Empty !_ = True+    eqSameLength (ConsSym s1 t) (UnsafeConsSym s2 u) =+      root s1 == root s2 && eqSameLength t u++instance Ord (TermList f) where+  {-# INLINE compare #-}+  compare t u =+    case compare (lenList t) (lenList u) of+      EQ -> compareContents t u+      x  -> x++compareContents :: TermList f -> TermList f -> Ordering+compareContents Empty !_ = EQ+compareContents (ConsSym s1 t) (UnsafeConsSym s2 u) =+  case compare (root s1) (root s2) of+    EQ -> compareContents t u+    x  -> x++--------------------------------------------------------------------------------+-- Building terms.+--------------------------------------------------------------------------------++-- | A monoid for building terms.+-- 'mempty' represents the empty termlist, while 'mappend' appends two termlists.+newtype Builder f =+  Builder {+    unBuilder ::+      -- Takes: the term array and size, and current position in the term.+      -- Returns the final position, which may be out of bounds.+      forall s. Builder1 s f }++type Builder1 s f = State# s -> MutableByteArray# s -> Int# -> Int# -> (# State# s, Int# #)++instance Monoid (Builder f) where+  {-# INLINE mempty #-}+  mempty = Builder built+  {-# INLINE mappend #-}+  Builder m1 `mappend` Builder m2 = Builder (m1 `then_` m2)++-- Build a termlist from a Builder.+-- Works by guessing an appropriate size, and retrying if that was too small.+{-# INLINE buildTermList #-}+buildTermList :: Builder f -> TermList f+buildTermList builder = runST $ do+  let+    Builder m = builder+    loop n@(I# n#) = do+      MutableByteArray mbytearray# <-+        newByteArray (n * sizeOf (fromSymbol undefined))+      n' <-+        ST $ \s ->+          case m s mbytearray# n# 0# of+            (# s, n# #) -> (# s, I# n# #)+      if n' <= n then do+        !bytearray <- unsafeFreezeByteArray (MutableByteArray mbytearray#)+        return (TermList 0 n' bytearray)+       else loop (n'*2)+  loop 32++-- Get at the term array.+{-# INLINE getByteArray #-}+getByteArray :: (MutableByteArray s -> Builder1 s f) -> Builder1 s f+getByteArray k = \s bytearray n i -> k (MutableByteArray bytearray) s bytearray n i++-- Get at the array size.+{-# INLINE getSize #-}+getSize :: (Int -> Builder1 s f) -> Builder1 s f+getSize k = \s bytearray n i -> k (I# n) s bytearray n i++-- Get at the current array index.+{-# INLINE getIndex #-}+getIndex :: (Int -> Builder1 s f) -> Builder1 s f+getIndex k = \s bytearray n i -> k (I# i) s bytearray n i++-- Change the current array index.+{-# INLINE putIndex #-}+putIndex :: Int -> Builder1 s f+putIndex (I# i) = \s _ _ _ -> (# s, i #)++-- Lift an ST computation into a builder.+{-# INLINE liftST #-}+liftST :: ST s () -> Builder1 s f+liftST (ST m) =+  \s _ _ i ->+  case m s of+    (# s, () #) -> (# s, i #)++-- Finish building.+{-# INLINE built #-}+built :: Builder1 s f+built = \s _ _ i -> (# s, i #)++-- Sequence two builder operations.+{-# INLINE then_ #-}+then_ :: Builder1 s f -> Builder1 s f -> Builder1 s f+then_ m1 m2 =+  \s bytearray n i ->+    case m1 s bytearray n i of+      (# s, i #) -> m2 s bytearray n i++-- checked j m executes m only if the array has room for j more symbols.+{-# INLINE checked #-}+checked :: Int -> Builder1 s f -> Builder1 s f+checked j m =+  getSize $ \n ->+  getIndex $ \i ->+  if i + j <= n then m else putIndex (i + j)++-- Emit an arbitrary symbol, with given arguments.+{-# INLINE emitSymbolBuilder #-}+emitSymbolBuilder :: Symbol -> Builder f -> Builder f+emitSymbolBuilder x inner =+  Builder $ checked 1 $+    getByteArray $ \bytearray ->+    -- Skip the symbol itself, then fill it in at the end, when we know the size+    -- of the symbol's arguments.+    getIndex $ \n ->+    putIndex (n+1) `then_`+    unBuilder inner `then_`+    -- Fill in the symbol.+    getIndex (\m ->+      liftST $ writeByteArray bytearray n (fromSymbol x { size = m - n }))++-- Emit a function application.+{-# INLINE emitApp #-}+emitApp :: Fun f -> Builder f -> Builder f+emitApp (F n) inner = emitSymbolBuilder (Symbol True n 0) inner++-- Emit a variable.+{-# INLINE emitVar #-}+emitVar :: Var -> Builder f+emitVar x = emitSymbolBuilder (Symbol False (var_id x) 1) mempty++-- Emit a whole termlist.+{-# INLINE emitTermList #-}+emitTermList :: TermList f -> Builder f+emitTermList (TermList lo hi array) =+  Builder $ checked (hi-lo) $+    getByteArray $ \mbytearray ->+    getIndex $ \n ->+    let k = sizeOf (fromSymbol undefined) in+    liftST (copyByteArray mbytearray (n*k) array (lo*k) ((hi-lo)*k)) `then_`+    putIndex (n + hi-lo)++----------------------------------------------------------------------+-- Efficient subterm testing.+----------------------------------------------------------------------++-- | Is a term contained as a subterm in a given termlist?+{-# INLINE isSubtermOfList #-}+isSubtermOfList :: Term f -> TermList f -> Bool+isSubtermOfList t u =+  isSubArrayOf (singleton t) u++-- N.B. this one should not be exported from Twee.Term+-- because subarray is not the same as subterm if t is not+-- a singleton+isSubArrayOf :: TermList f -> TermList f -> Bool+isSubArrayOf t u =+  lenList t <= lenList u && (here t u || next t u)+  where+    here Empty _ = True+    here (ConsSym s1 t) (UnsafeConsSym s2 u) =+      root s1 == root s2 && here t u++    -- This is safe because lenList t <= lenList u+    -- so if u = Empty, then t = Empty and here t u = True.+    next t (UnsafeConsSym _ u) = isSubArrayOf t u++-- | Check if a variable occurs in a termlist.+{-# INLINE occursList #-}+occursList :: Var -> TermList f -> Bool+occursList (V x) t = symbolOccursList (fromSymbol (Symbol False x 1)) t++symbolOccursList :: Int64 -> TermList f -> Bool+symbolOccursList !_ Empty = False+symbolOccursList n (ConsSym t ts) = root t == n || symbolOccursList n ts
+ Twee/Utils.hs view
@@ -0,0 +1,145 @@+-- | Miscellaneous utility functions.++{-# LANGUAGE CPP, MagicHash #-}+module Twee.Utils where++import Control.Arrow((&&&))+import Control.Exception+import Data.List(groupBy, sortBy)+import Data.Ord(comparing)+import System.IO+import GHC.Prim+import GHC.Types+import Data.Bits+--import Test.QuickCheck hiding ((.&.))++repeatM :: Monad m => m a -> m [a]+repeatM = sequence . repeat++partitionBy :: Ord b => (a -> b) -> [a] -> [[a]]+partitionBy value =+  map (map fst) .+  groupBy (\x y -> snd x == snd y) .+  sortBy (comparing snd) .+  map (id &&& value)++collate :: Ord a => ([b] -> c) -> [(a, b)] -> [(a, c)]+collate f = map g . partitionBy fst+  where+    g xs = (fst (head xs), f (map snd xs))++isSorted :: Ord a => [a] -> Bool+isSorted xs = and (zipWith (<=) xs (tail xs))++isSortedBy :: Ord b => (a -> b) -> [a] -> Bool+isSortedBy f xs = isSorted (map f xs)++usort :: Ord a => [a] -> [a]+usort = usortBy compare++usortBy :: (a -> a -> Ordering) -> [a] -> [a]+usortBy f = map head . groupBy (\x y -> f x y == EQ) . sortBy f++sortBy' :: Ord b => (a -> b) -> [a] -> [a]+sortBy' f = map snd . sortBy (comparing fst) . map (\x -> (f x, x))++usortBy' :: Ord b => (a -> b) -> [a] -> [a]+usortBy' f = map snd . usortBy (comparing fst) . map (\x -> (f x, x))++orElse :: Ordering -> Ordering -> Ordering+EQ `orElse` x = x+x  `orElse` _ = x++unbuffered :: IO a -> IO a+unbuffered x = do+  buf <- hGetBuffering stdout+  bracket_+    (hSetBuffering stdout NoBuffering)+    (hSetBuffering stdout buf)+    x++newtype Max a = Max { getMax :: Maybe a }++getMaxWith :: Ord a => a -> Max a -> a+getMaxWith x (Max (Just y)) = x `max` y+getMaxWith x (Max Nothing)  = x++instance Ord a => Monoid (Max a) where+  mempty = Max Nothing+  Max (Just x) `mappend` y = Max (Just (getMaxWith x y))+  Max Nothing  `mappend` y = y++newtype Min a = Min { getMin :: Maybe a }++getMinWith :: Ord a => a -> Min a -> a+getMinWith x (Min (Just y)) = x `min` y+getMinWith x (Min Nothing)  = x++instance Ord a => Monoid (Min a) where+  mempty = Min Nothing+  Min (Just x) `mappend` y = Min (Just (getMinWith x y))+  Min Nothing  `mappend` y = y++labelM :: Monad m => (a -> m b) -> [a] -> m [(a, b)]+labelM f = mapM (\x -> do { y <- f x; return (x, y) })++#if __GLASGOW_HASKELL__ < 710+isSubsequenceOf :: Ord a => [a] -> [a] -> Bool+[] `isSubsequenceOf` ys = True+(x:xs) `isSubsequenceOf` [] = False+(x:xs) `isSubsequenceOf` (y:ys)+  | x == y = xs `isSubsequenceOf` ys+  | otherwise = (x:xs) `isSubsequenceOf` ys+#endif++{-# INLINE fixpoint #-}+fixpoint :: Eq a => (a -> a) -> a -> a+fixpoint f x = fxp x+  where+    fxp x+      | x == y = x+      | otherwise = fxp y+      where+        y = f x++-- From "Bit twiddling hacks": branchless min and max+{-# INLINE intMin #-}+intMin :: Int -> Int -> Int+intMin x y =+  y `xor` ((x `xor` y) .&. negate (x .<. y))+  where+    I# x .<. I# y = I# (x <# y)++{-# INLINE intMax #-}+intMax :: Int -> Int -> Int+intMax x y =+  x `xor` ((x `xor` y) .&. negate (x .<. y))+  where+    I# x .<. I# y = I# (x <# y)++-- Split an interval (inclusive bounds) into a particular number of blocks+splitInterval :: Integral a => a -> (a, a) -> [(a, a)]+splitInterval k (lo, hi) =+  [ (lo+i*blockSize, (lo+(i+1)*blockSize-1) `min` hi)+  | i <- [0..k-1] ]+  where+    size = (hi-lo+1)+    blockSize = (size + k - 1) `div` k -- division rounding up+{-+prop_split_1 (Positive k) (lo, hi) =+  -- Check that all elements occur exactly once+  concat [[x..y] | (x, y) <- splitInterval k (lo, hi)] === [lo..hi]++-- Check that we have the correct number and distribution of blocks+prop_split_2 (Positive k) (lo, hi) =+  counterexample (show splits) $ conjoin+    [counterexample "Reason: too many splits" $+       length splits <= k,+     counterexample "Reason: too few splits" $+       length [lo..hi] >= k ==> length splits == k,+     counterexample "Reason: uneven distribution" $+      not (null splits) ==>+       minimum (map length splits) + 1 >= maximum (map length splits)]+  where+    splits = splitInterval k (lo, hi)+-}
− misc/analyse_trace.pl
@@ -1,32 +0,0 @@-:- use_module(boo067_good, []).-:- use_module(boo067_bad, []).--ground(Pred, X) :--	call(Pred, Y),-	numbervars(Y, 1, _),-	X=Y.--default(Pred, X) :--    call(Pred, boo067_good, boo067_bad, X).--missing(X) :- default(missing, X).-missing(Good, Bad, X) :--	ground(Good:lemma, X),-	\+ found(Bad, add(rule(_, X))).--variant(rule(N, X=Y), rule(N, X=Y)).-variant(rule(N, X=Y), rule(N, Y=X)).--found(Mod, Rule) :--	variant(Rule, Rule1),-	Mod:step(add(Rule1)).--gone(Mod, rule(N, X)) :--	ground(Mod:lemma, X),-	found(Mod, rule(N, X)),-	Mod:step(delete(N)).--reappeared(Mod, rule(N, X), M) :--	ground(found(Mod), rule(N, X)),-	found(Mod, rule(M, X)),-	M > N.
− misc/bench.hs
@@ -1,74 +0,0 @@-{-# LANGUAGE PatternGuards, FlexibleInstances #-}-import Criterion.Main-import Twee.Term hiding (isFun)-import qualified Twee.Term-import Test.QuickCheck-import Data.Int-import Data.Maybe-import Twee.Term.Core hiding (subst)--instance Num (Fun Int) where fromInteger n = F (fromInteger n) (fromInteger n)-instance Num Var where fromInteger = V . fromInteger--t0, t1, u0, u1, t2, t, u :: Term Int-t0 = build $ fun 0 [var 0, fun 0 [var 0, fun 0 [fun 0 [var 0, var 1], var 2]]]-u0 = build $ fun 0 [fun 0 [fun 2 [fun 2 [var 2, var 2], var 1], fun 0 [fun 2 [var 2, var 2], var 3]], fun 0 [fun 0 [fun 2 [fun 2 [var 2, var 2], var 1], fun 0 [fun 2 [var 2, var 2], var 3]], fun 0 [fun 0 [fun 0 [fun 2 [fun 2 [var 2, var 2], var 1], fun 0 [fun 2 [var 2, var 2], var 3]], fun 2 [fun 2 [var 2, var 2], var 1]], fun 2 [var 2, var 2]]]]--t1 = build $ fun 0 [fun 1 [var 0], fun 1 [var 1]]-u1 = build $ fun 0 [fun 1 [fun 0 [fun 2 emptyTermList, fun 3 emptyTermList]], fun 1 [fun 0 [fun 4 emptyTermList, fun 5 emptyTermList]]]--t2 = build $ fun 0 [var 0, fun 1 [var 1, fun 1 [var 1, var 1]]]-u2 = build $ fun 0 [fun 0 [var 2, var 2], var 2]--t = t0-u = u0--Just sub = match t u--mgu1 t u = let Just sub = unifyTri t u in build (subst sub t)-mgu2 t u = let Just sub = unify t u in build (subst sub t)--Just sub' = unifyTri t2 u2-Just csub' = unify t2 u2--main = do-  print t-  print u-  print (match t u)-  print (build (subst sub t))-  print (unifyTri t2 u2)-  print (close sub')-  print (build (subst sub' t2))-  print (build (subst sub' u2))-  print (mgu1 t2 u2)-  print (mgu2 t2 u2)-  print (t == t)-  print (build (subst sub t) == u)-  print (build (subst sub' t2) == build (subst sub' u2))-  print (build (subst csub' t1) == build (subst sub' t1))-  print (mgu1 t2 u2 == mgu2 t2 u2)-  print (build (subst csub' t2) == build (subst sub' t2))-  defaultMain [-    bench "eq-t" (whnf (uncurry (==)) (t, t)),-    bench "eq-u" (whnf (uncurry (==)) (u, u)),-    bench "match" (whnf (fromJust . uncurry match) (t, u)),-    bench "subst" (whnf (build . uncurry subst) (sub, t)),-    bench "unifyTri" (whnf (fromJust . uncurry unifyTri) (t2, u2)),-    bench "unify-close" (whnf (uncurry unify) (t2, u2)),-    bench "unify-subst-iter1" (whnf (build . uncurry subst) (sub', t2)),-    bench "unify-subst-iter2" (whnf (build . uncurry subst) (sub', u2)),-    bench "unify-subst-closed1" (whnf (build . uncurry subst) (csub', t2)),-    bench "unify-subst-closed2" (whnf (build . uncurry subst) (csub', u2)),-    bench "mgu-tri" (whnf (uncurry mgu1) (t2, u2)),-    bench "mgu-close" (whnf (uncurry mgu2) (t2, u2)),-    bench "make-constant" (whnf (build . uncurry fun) (F 0 0, emptyTermList)),-    bench "baseline" (whnf (uncurry (+)) (0 :: Int, 0))]--prop :: Bool -> NonNegative (Small Int) -> NonNegative (Small Int) -> Property-prop fun_ (NonNegative (Small index_)) (NonNegative (Small size_)) =-  (isFun x, index x, size x) === (fun_, index_, size_)-  where-    x = toSymbol (fromSymbol (Symbol fun_ index_ size_))--prop2 :: Int64 -> Property-prop2 x = fromSymbol (toSymbol x) === x
− misc/ring_conn.pl
@@ -1,801 +0,0 @@-:- module(ring_conn, [step/1, lemma/1]).-:- discontiguous(step/1).-:- discontiguous(lemma/1).-:- style_check(-singleton).-step(add(rule(1, (X1 + X2) = (X2 + X1)))).-step(add(rule(2, ((X1 + X2) + X3) = (X1 + (X2 + X3))))).-step(add(rule(3, (0 + X1) = X1))).-step(add(rule(4, (X1 + -X1) = 0))).-step(add(rule(5, ((X1 * X2) * X3) = (X1 * (X2 * X3))))).-step(add(rule(6, ((X1 * X2) + (X1 * X3)) = (X1 * (X2 + X3))))).-step(add(rule(7, ((X1 * X3) + (X2 * X3)) = ((X1 + X2) * X3)))).-step(add(rule(8, (X1 * (X1 * X1)) = X1))).-step(add(rule(9, -0 = 0))).-step(add(rule(10, (X1 + 0) = X1))).-step(add(rule(11, (X1 + (-X1 + X2)) = X2))).-step(add(rule(12, -(-X1) = X1))).-step(add(rule(13, (X1 + (X2 + X3)) = (X3 + (X1 + X2))))).-step(add(rule(14, (X1 + (X2 + X3)) = (X2 + (X1 + X3))))).-step(add(rule(15, ((X1 + X1) * X2) = (X1 * (X2 + X2))))).-step(add(rule(16, (X2 + (X1 + -X2)) = X1))).-step(add(rule(17, (0 * (X1 + X1)) = (0 * X1)))).-step(add(rule(18, (X1 * (X1 * (X1 * X2))) = (X1 * X2)))).-step(hard((X1 + (X2 + X3)) = (X3 + (X2 + X1)))).-step(hard((X1 + (X2 + X3)) = (X1 + (X3 + X2)))).-step(add(rule(19, (X1 + (X2 + -(X1 + X2))) = 0))).-step(add(rule(20, (X1 + -(-X2 + X1)) = X2))).-step(add(rule(21, (X1 * ((X1 * X1) + X2)) = (X1 + (X1 * X2))))).-step(add(rule(22, (X1 + (X1 * 0)) = X1))).-step(add(rule(23, (X1 * 0) = 0))).-step(add(rule(24, (X1 * (X2 + (X1 * X1))) = (X1 + (X1 * X2))))).-step(add(rule(25, (X2 + -(X1 + X2)) = -X1))).-step(add(rule(26, ((X1 + X1) * (X1 * X1)) = (X1 + X1)))).-step(hard(0 = (X1 + (X2 + -(X2 + X1))))).-step(add(rule(27, (X2 + -(X2 + -X1)) = X1))).-step(add(rule(28, -(-X1 + -X2) = (X2 + X1)))).-step(add(rule(29, (X1 * (0 * X2)) = (0 * X2)))).-step(add(rule(30, (X1 + (X2 * (X1 * X1))) = ((X1 + X2) * (X1 * X1))))).-step(add(rule(31, (X2 + -(X2 + X1)) = -X1))).-step(hard((-X1 + (X2 + (X3 + X1))) = (X3 + X2))).-step(add(rule(32, (X3 + (X2 + (-X3 + X1))) = (X1 + X2)))).-step(add(rule(33, (X3 + (X1 + (X2 + -X3))) = (X1 + X2)))).-step(add(rule(34, -(X1 + -X2) = (X2 + -X1)))).-step(add(rule(35, (-X1 + -X2) = -(X2 + X1)))).-step(add(rule(36, (X1 + (X1 * -(X1 * X1))) = 0))).-step(add(rule(37, (-X1 * -(-X1 * -X1)) = X1))).-step(add(rule(38, (-X1 * (-X1 * X1)) = X1))).-step(add(rule(39, (X1 * -(X1 * X1)) = -X1))).-step(hard((X1 + (X2 + (X3 + X4))) = (X2 + (X3 + (X4 + X1))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X3 + (X2 + (X4 + X1))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X3 + (X4 + (X1 + X2))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X4 + (X3 + (X1 + X2))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X3 + (X1 + (X2 + X4))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X4 + (X2 + (X3 + X1))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X2 + (X4 + (X1 + X3))))).-step(add(rule(40, ((X1 + X1) * (X2 * X3)) = (X1 * ((X2 + X2) * X3))))).-step(add(rule(41, (X1 * (X1 * (X1 + X1))) = (X1 + X1)))).-step(add(rule(42, (X1 * (X2 * (X3 + X3))) = (X1 * ((X2 + X2) * X3))))).-step(add(rule(43, (X1 + (X1 * (X1 * X2))) = (X1 * (X1 * (X1 + X2)))))).-step(add(rule(44, (X1 + (X1 * (X2 * X1))) = (X1 * ((X1 + X2) * X1))))).-step(add(rule(45, (X1 + (0 * X1)) = X1))).-step(add(rule(46, (0 * X1) = 0))).-step(add(rule(47, (X2 + (X3 + (-(X2 + X3) + X1))) = X1))).-step(hard((X1 + (X2 + (-(X2 + X1) + X3))) = X3)).-step(add(rule(48, (X1 * (X1 * -X1)) = -X1))).-step(add(rule(49, -(-X1 + X2) = (X1 + -X2)))).-step(add(rule(50, ((X1 * X2) + ((X1 * X3) + X4)) = ((X1 * (X2 + X3)) + X4)))).-step(add(rule(51, ((X1 * X2) + ((X3 * X2) + X4)) = (((X1 + X3) * X2) + X4)))).-step(add(rule(52, ((X1 * (X2 * X4)) + (X3 * X4)) = (((X1 * X2) + X3) * X4)))).-step(add(rule(53, (((X1 * X1) + X2) * X1) = (X1 + (X2 * X1))))).-step(add(rule(54, (X1 + (-(X1 * X1) * X1)) = 0))).-step(add(rule(55, (-(X1 * X1) * X1) = -X1))).-step(add(rule(56, ((X1 + (X1 * X2)) * X3) = (X1 * (X3 + (X2 * X3)))))).-step(add(rule(57, ((X2 + (X1 * X1)) * X1) = (X1 + (X2 * X1))))).-step(add(rule(58, ((X1 * X4) + (X2 * (X3 * X4))) = ((X1 + (X2 * X3)) * X4)))).-step(add(rule(59, (X1 * (X2 * (X1 * (X2 * (X1 * X2))))) = (X1 * X2)))).-step(add(rule(60, (X1 * ((X1 * (X1 * X2)) + X3)) = (X1 * (X2 + X3))))).-step(add(rule(61, (X1 * (X2 + (X1 * (X1 * X3)))) = (X1 * (X2 + X3))))).-step(add(rule(62, (X1 * (X2 + X2)) = (X1 * (X1 * ((X1 + X1) * X2)))))).-step(add(rule(63, (X1 * (X1 * (X1 + (X1 * X2)))) = (X1 + (X1 * X2))))).-step(add(rule(64, (X1 + (X1 * (-(X1 * X1) + X2))) = (X1 * X2)))).-step(add(rule(65, ((X1 + X1) * (X2 * X3)) = (X1 * (X2 * (X3 + X3)))))).-step(add(rule(66, (-(X1 * X3) + (X1 * (X2 + X3))) = (X1 * X2)))).-step(add(rule(67, -(X1 * -X2) = (X1 * X2)))).-step(add(rule(68, -(X1 * X2) = (X1 * -X2)))).-step(add(rule(69, (X1 * (X2 * (-X2 * -X2))) = (X1 * X2)))).-step(add(rule(70, (-X1 * (X1 * -X1)) = X1))).-step(add(rule(71, (X1 * (-X1 * -X1)) = X1))).-step(add(rule(72, (-X1 * (X1 * X1)) = -X1))).-step(add(rule(73, (X1 * (-X1 * X1)) = -X1))).-step(add(rule(74, ((X2 * -X3) + ((X1 + X2) * X3)) = (X1 * X3)))).-step(add(rule(75, (-X1 * -X2) = (X1 * X2)))).-step(add(rule(76, (-X1 * X2) = (X1 * -X2)))).-step(add(rule(77, (X2 + (X3 + (X1 + -(X2 + X3)))) = X1))).-step(hard(X1 = (X2 + (X3 + (-(X3 + X2) + X1))))).-step(add(rule(78, ((X1 + (X1 * X1)) * (X1 * X1)) = (X1 + (X1 * X1))))).-step(add(rule(79, (X1 + (X1 * ((X1 + X1) * -X1))) = -X1))).-step(add(rule(80, ((X1 * X2) + (X3 + (X1 * X4))) = (X3 + (X1 * (X4 + X2)))))).-step(add(rule(81, ((X1 * X2) + (X3 + (X4 * X2))) = (X3 + ((X4 + X1) * X2))))).-step(add(rule(82, ((X1 + X2) * (X3 + X3)) = ((X1 + (X2 + (X1 + X2))) * X3)))).-step(add(rule(83, ((X1 + (X1 + X2)) * X3) = ((X1 * (X3 + X3)) + (X2 * X3))))).-step(add(rule(84, ((X1 + (X1 + X1)) * X2) = (X1 * (X2 + (X2 + X2)))))).-step(add(rule(85, ((X1 + (X2 + X2)) * X3) = ((X1 * X3) + (X2 * (X3 + X3)))))).-step(hard(((X1 + X2) * (X3 + X3)) = ((X2 + (X1 + (X2 + X1))) * X3))).-step(add(rule(86, ((X1 + X1) * (X2 + X3)) = (X1 * (X2 + (X3 + (X2 + X3))))))).-step(add(rule(87, (X1 * (X2 + (X2 + X3))) = (((X1 + X1) * X2) + (X1 * X3))))).-step(add(rule(88, (X1 * (X2 + (X3 + X3))) = ((X1 * X2) + ((X1 + X1) * X3))))).-step(add(rule(89, (X1 + (X1 * (X2 + X2))) = (X1 + ((X1 + X1) * X2))))).-step(add(rule(90, (X1 * -(X2 + X2)) = ((X1 + X1) * -X2)))).-step(hard(((X1 + X1) * (X2 + X3)) = (X1 * (X3 + (X2 + (X3 + X2)))))).-step(add(rule(91, (X1 * (((X1 * X1) + X2) * X3)) = ((X1 + (X1 * X2)) * X3)))).-step(add(rule(92, (X1 * (X3 + ((X1 * X1) + X2))) = (X1 + (X1 * (X2 + X3)))))).-step(add(rule(93, (X1 * (X2 + (X3 + (X1 * X1)))) = (X1 + (X1 * (X2 + X3)))))).-step(add(rule(94, (X1 * ((X2 + (X1 * X1)) * X3)) = ((X1 + (X1 * X2)) * X3)))).-step(add(rule(95, (X1 + (-(X2 + X1) + X3)) = (-X2 + X3)))).-step(add(rule(96, (X3 + -(X1 + (X2 + X3))) = -(X1 + X2)))).-step(add(rule(97, (X1 + (X2 + -(X3 + X1))) = (X2 + -X3)))).-step(add(rule(98, (((X1 * X1) + X2) * (X1 * X3)) = ((X1 + (X2 * X1)) * X3)))).-step(add(rule(99, ((X1 + (X2 * X3)) * (X3 * X3)) = (((X1 * X3) + X2) * X3)))).-step(add(rule(100, ((X1 + (X2 * X2)) * (X2 * X3)) = ((X2 + (X1 * X2)) * X3)))).-step(add(rule(101, (X1 * (X1 * -(X1 + X1))) = -(X1 + X1)))).-step(add(rule(102, (X1 * (X1 * ((X1 + X1) * X2))) = ((X1 + X1) * X2)))).-step(add(rule(103, ((X1 + (X1 + X1)) * (X1 * X1)) = (X1 + (X1 + X1))))).-step(add(rule(104, ((X1 + (X1 * (X2 * X2))) * X2) = (X1 * (X2 + X2))))).-step(add(rule(105, (((X1 * (X2 * X2)) + X3) * X2) = ((X1 + X3) * X2)))).-step(add(rule(106, (X1 + (X1 * (X2 + (X1 * -X1)))) = (X1 * X2)))).-step(add(rule(107, (X1 + (((X1 * -X1) + X2) * X1)) = (X2 * X1)))).-step(add(rule(108, (X1 + ((X2 + (X1 * -X1)) * X1)) = (X2 * X1)))).-step(add(rule(109, (X1 + ((-X2 + (X1 * X1)) * -X1)) = (X2 * X1)))).-step(add(rule(110, ((X3 * -X2) + ((X3 + X1) * X2)) = (X1 * X2)))).-step(hard(X1 = (X2 + (X3 + (X1 + -(X3 + X2)))))).-step(add(rule(111, ((X3 * X2) + ((X1 + X3) * -X2)) = (X1 * -X2)))).-step(add(rule(112, ((X1 + (X1 + (X1 + X1))) * X2) = (X1 * (X2 + (X2 + (X2 + X2))))))).-step(add(rule(113, ((X1 * X3) + (X2 * (X1 * (X1 * X3)))) = ((X1 + X2) * (X1 * (X1 * X3)))))).-step(add(rule(114, (X1 * ((X1 + X1) * ((X1 + X1) * (X2 + X2)))) = ((X1 + X1) * X2)))).-step(add(rule(115, (((X1 + X2) * (X1 * X1)) + X3) = (X1 + ((X2 * (X1 * X1)) + X3))))).-step(interreduce).-step(delete(rule(11, (X1 + (-X1 + X2)) = X2))).-step(delete(rule(13, (X1 + (X2 + X3)) = (X3 + (X1 + X2))))).-step(delete(rule(17, (0 * (X1 + X1)) = (0 * X1)))).-step(delete(rule(19, (X1 + (X2 + -(X1 + X2))) = 0))).-step(delete(rule(20, (X1 + -(-X2 + X1)) = X2))).-step(delete(rule(21, (X1 * ((X1 * X1) + X2)) = (X1 + (X1 * X2))))).-step(delete(rule(22, (X1 + (X1 * 0)) = X1))).-step(delete(rule(25, (X2 + -(X1 + X2)) = -X1))).-step(delete(rule(26, ((X1 + X1) * (X1 * X1)) = (X1 + X1)))).-step(delete(rule(27, (X2 + -(X2 + -X1)) = X1))).-step(delete(rule(28, -(-X1 + -X2) = (X2 + X1)))).-step(delete(rule(29, (X1 * (0 * X2)) = (0 * X2)))).-step(delete(rule(36, (X1 + (X1 * -(X1 * X1))) = 0))).-step(delete(rule(37, (-X1 * -(-X1 * -X1)) = X1))).-step(delete(rule(38, (-X1 * (-X1 * X1)) = X1))).-step(delete(rule(39, (X1 * -(X1 * X1)) = -X1))).-step(delete(rule(45, (X1 + (0 * X1)) = X1))).-step(delete(rule(47, (X2 + (X3 + (-(X2 + X3) + X1))) = X1))).-step(delete(rule(50, ((X1 * X2) + ((X1 * X3) + X4)) = ((X1 * (X2 + X3)) + X4)))).-step(delete(rule(51, ((X1 * X2) + ((X3 * X2) + X4)) = (((X1 + X3) * X2) + X4)))).-step(delete(rule(53, (((X1 * X1) + X2) * X1) = (X1 + (X2 * X1))))).-step(delete(rule(54, (X1 + (-(X1 * X1) * X1)) = 0))).-step(delete(rule(55, (-(X1 * X1) * X1) = -X1))).-step(delete(rule(60, (X1 * ((X1 * (X1 * X2)) + X3)) = (X1 * (X2 + X3))))).-step(delete(rule(62, (X1 * (X2 + X2)) = (X1 * (X1 * ((X1 + X1) * X2)))))).-step(delete(rule(64, (X1 + (X1 * (-(X1 * X1) + X2))) = (X1 * X2)))).-step(delete(rule(66, (-(X1 * X3) + (X1 * (X2 + X3))) = (X1 * X2)))).-step(delete(rule(67, -(X1 * -X2) = (X1 * X2)))).-step(delete(rule(69, (X1 * (X2 * (-X2 * -X2))) = (X1 * X2)))).-step(delete(rule(70, (-X1 * (X1 * -X1)) = X1))).-step(delete(rule(71, (X1 * (-X1 * -X1)) = X1))).-step(delete(rule(72, (-X1 * (X1 * X1)) = -X1))).-step(delete(rule(73, (X1 * (-X1 * X1)) = -X1))).-step(delete(rule(74, ((X2 * -X3) + ((X1 + X2) * X3)) = (X1 * X3)))).-step(delete(rule(75, (-X1 * -X2) = (X1 * X2)))).-step(delete(rule(77, (X2 + (X3 + (X1 + -(X2 + X3)))) = X1))).-step(delete(rule(78, ((X1 + (X1 * X1)) * (X1 * X1)) = (X1 + (X1 * X1))))).-step(delete(rule(79, (X1 + (X1 * ((X1 + X1) * -X1))) = -X1))).-step(delete(rule(91, (X1 * (((X1 * X1) + X2) * X3)) = ((X1 + (X1 * X2)) * X3)))).-step(delete(rule(95, (X1 + (-(X2 + X1) + X3)) = (-X2 + X3)))).-step(delete(rule(98, (((X1 * X1) + X2) * (X1 * X3)) = ((X1 + (X2 * X1)) * X3)))).-step(delete(rule(107, (X1 + (((X1 * -X1) + X2) * X1)) = (X2 * X1)))).-step(add(rule(116, (X1 + (X2 * (X3 * (X1 * X1)))) = ((X1 + (X2 * X3)) * (X1 * X1))))).-step(add(rule(117, (X1 + (X2 + (X3 * (X1 * X1)))) = (X2 + ((X1 + X3) * (X1 * X1)))))).-step(add(rule(118, (X1 * (X1 * (X1 + (X1 + X1)))) = (X1 + (X1 + X1))))).-step(add(rule(119, ((X1 + (X2 + X2)) * (X1 * X1)) = (X1 + (X2 * (X1 * (X1 + X1))))))).-step(add(rule(120, (X1 + (X1 * (X2 * (X3 * X1)))) = (X1 * (((X2 * X3) + X1) * X1))))).-step(add(rule(121, ((X2 * -X3) + (X1 * X3)) = ((X1 + -X2) * X3)))).-step(add(rule(122, (X1 + (-(X1 + X2) + X3)) = (-X2 + X3)))).-step(add(rule(123, (X1 + (X2 + -(X1 + X3))) = (X2 + -X3)))).-step(add(rule(124, (X3 + -(X1 + (X3 + X2))) = -(X1 + X2)))).-step(add(rule(125, (X1 * (X1 * (X2 + (X1 * X3)))) = (X1 * ((X1 * X2) + X3))))).-step(add(rule(126, ((X3 + (X3 + (X2 + X2))) * X4) = ((X3 + X2) * (X4 + X4))))).-step(hard(((X1 + X2) * (X3 + X3)) = ((X1 + (X2 + (X2 + X1))) * X3))).-step(hard(((X1 + X2) * (X3 + X3)) = ((X2 + (X1 + (X1 + X2))) * X3))).-step(hard(((X1 * (X2 + X2)) + (X3 * X2)) = ((X1 + (X3 + X1)) * X2))).-step(add(rule(127, ((X1 + (X1 + X2)) * X3) = ((X2 * X3) + (X1 * (X3 + X3)))))).-step(hard(((X1 + (X1 + X2)) * X3) = ((X2 + (X1 + X1)) * X3))).-step(hard(((X1 * X2) + (X3 * (X2 + X2))) = ((X3 + (X1 + X3)) * X2))).-step(hard(((X1 + (X2 + X2)) * X3) = ((X2 * (X3 + X3)) + (X1 * X3)))).-step(add(rule(128, (X1 * (X4 + (X4 + (X3 + X3)))) = ((X1 + X1) * (X4 + X3))))).-step(hard(((X1 + X1) * (X2 + X3)) = (X1 * (X2 + (X3 + (X3 + X2)))))).-step(hard(((X1 + X1) * (X2 + X3)) = (X1 * (X3 + (X2 + (X2 + X3)))))).-step(hard((((X1 + X1) * X2) + (X1 * X3)) = (X1 * (X2 + (X3 + X2))))).-step(add(rule(129, (X1 * (X2 + (X2 + X3))) = ((X1 * X3) + ((X1 + X1) * X2))))).-step(hard((X1 * (X2 + (X2 + X3))) = (X1 * (X3 + (X2 + X2))))).-step(hard(((X1 * X2) + ((X1 + X1) * X3)) = (X1 * (X3 + (X2 + X3))))).-step(hard((X1 * (X2 + (X3 + X3))) = (((X1 + X1) * X3) + (X1 * X2)))).-step(add(rule(130, (X1 * ((X1 * (X1 * X2)) + (X3 + X3))) = ((X1 * X2) + ((X1 + X1) * X3))))).-step(add(rule(131, (((X3 * X2) + X1) * (X2 * X2)) = (((X1 * X2) + X3) * X2)))).-step(add(rule(132, (X2 + (-X2 + (X1 * -X2))) = (X1 * -X2)))).-step(add(rule(133, (X1 * ((X1 + X1) * (X1 + (X1 + (X1 + X1))))) = (X1 + X1)))).-step(add(rule(134, (X4 + (X2 + (X3 + (-X4 + X1)))) = (X1 + (X2 + X3))))).-step(add(rule(135, -(X1 + (-X2 + X3)) = (X2 + -(X3 + X1))))).-step(add(rule(136, (X4 + (X1 + (X2 + (X3 + -X4)))) = (X1 + (X2 + X3))))).-step(add(rule(137, -(X1 + (X2 + -X3)) = (X3 + -(X1 + X2))))).-step(add(rule(138, (-X1 + (-X2 + X3)) = (-(X2 + X1) + X3)))).-step(add(rule(139, (-X1 + (X2 + -X3)) = (X2 + -(X3 + X1))))).-step(add(rule(140, -(X3 + (X1 * -X2)) = ((X1 * X2) + -X3)))).-step(add(rule(141, ((X2 * -X3) + -X1) = -(X1 + (X2 * X3))))).-step(add(rule(142, (-X3 + (X1 * -X2)) = -((X1 * X2) + X3)))).-step(add(rule(143, ((X1 + -X2) * -X3) = ((X2 + -X1) * X3)))).-step(add(rule(144, ((X2 + (X1 * (X3 * X3))) * X3) = ((X1 + X2) * X3)))).-step(add(rule(145, ((X1 + X1) * (X1 + (X1 + (X1 + X1)))) = (X1 * (X1 + X1))))).-step(add(rule(146, (X1 + (X1 * ((X1 * -X1) + X2))) = (X1 * X2)))).-step(add(rule(147, (X2 + (-X2 + (X1 * X2))) = (X1 * X2)))).-step(add(rule(148, ((X1 * (X2 + X2)) + ((X1 + X1) * X3)) = ((X1 + X1) * (X2 + X3))))).-step(add(rule(149, (((X1 + X1) * X2) + (X1 * (X3 + X3))) = ((X1 + X1) * (X2 + X3))))).-step(add(rule(150, (X1 + (X1 + ((X1 + X1) * X2))) = ((X1 + X1) * (X2 + (X1 * X1)))))).-step(add(rule(151, (((X1 + X1) * X3) + (X2 * (X3 + X3))) = ((X1 + X2) * (X3 + X3))))).-step(add(rule(152, ((X1 * (X3 + X3)) + ((X2 + X2) * X3)) = ((X1 + X2) * (X3 + X3))))).-step(add(rule(153, (((X1 + X1) * -X2) + X3) = ((X1 * -(X2 + X2)) + X3)))).-step(add(rule(154, ((X1 * (X2 + X2)) + X3) = (((X1 + X1) * X2) + X3)))).-step(add(rule(155, (X1 + ((X2 + X2) * X3)) = (X1 + (X2 * (X3 + X3)))))).-step(add(rule(156, (X1 + ((X1 + (X1 * X1)) * -X1)) = (X1 * -X1)))).-step(add(rule(157, (X2 + ((X1 + (X2 * X2)) * -X2)) = (X1 * -X2)))).-step(add(rule(158, ((((X2 * -X2) + X1) * -X2) + X3) = (X2 + (X3 + (X1 * -X2)))))).-step(add(rule(159, ((X3 * X2) + ((X3 + X1) * -X2)) = (X1 * -X2)))).-step(add(rule(160, (((? * X2) + ((? * X2) + ((X3 + ?) * -(X2 + X2)))) * X4) = (X3 * (X2 * -(X4 + X4)))))).-step(add(rule(161, (((X1 * X2) + ((X1 * X2) + ((X3 + X1) * -(X2 + X2)))) * X4) = (((? * X2) + ((? * X2) + ((X3 + ?) * -(X2 + X2)))) * X4)))).-step(interreduce).-step(delete(rule(63, (X1 * (X1 * (X1 + (X1 * X2)))) = (X1 + (X1 * X2))))).-step(delete(rule(82, ((X1 + X2) * (X3 + X3)) = ((X1 + (X2 + (X1 + X2))) * X3)))).-step(delete(rule(85, ((X1 + (X2 + X2)) * X3) = ((X1 * X3) + (X2 * (X3 + X3)))))).-step(delete(rule(86, ((X1 + X1) * (X2 + X3)) = (X1 * (X2 + (X3 + (X2 + X3))))))).-step(delete(rule(88, (X1 * (X2 + (X3 + X3))) = ((X1 * X2) + ((X1 + X1) * X3))))).-step(delete(rule(89, (X1 + (X1 * (X2 + X2))) = (X1 + ((X1 + X1) * X2))))).-step(delete(rule(96, (X3 + -(X1 + (X2 + X3))) = -(X1 + X2)))).-step(delete(rule(104, ((X1 + (X1 * (X2 * X2))) * X2) = (X1 * (X2 + X2))))).-step(delete(rule(105, (((X1 * (X2 * X2)) + X3) * X2) = ((X1 + X3) * X2)))).-step(delete(rule(109, (X1 + ((-X2 + (X1 * X1)) * -X1)) = (X2 * X1)))).-step(delete(rule(110, ((X3 * -X2) + ((X3 + X1) * X2)) = (X1 * X2)))).-step(delete(rule(111, ((X3 * X2) + ((X1 + X3) * -X2)) = (X1 * -X2)))).-step(delete(rule(122, (X1 + (-(X1 + X2) + X3)) = (-X2 + X3)))).-step(delete(rule(132, (X2 + (-X2 + (X1 * -X2))) = (X1 * -X2)))).-step(delete(rule(133, (X1 * ((X1 + X1) * (X1 + (X1 + (X1 + X1))))) = (X1 + X1)))).-step(delete(rule(134, (X4 + (X2 + (X3 + (-X4 + X1)))) = (X1 + (X2 + X3))))).-step(delete(rule(135, -(X1 + (-X2 + X3)) = (X2 + -(X3 + X1))))).-step(delete(rule(138, (-X1 + (-X2 + X3)) = (-(X2 + X1) + X3)))).-step(delete(rule(156, (X1 + ((X1 + (X1 * X1)) * -X1)) = (X1 * -X1)))).-step(delete(rule(160, (((? * X2) + ((? * X2) + ((X3 + ?) * -(X2 + X2)))) * X4) = (X3 * (X2 * -(X4 + X4)))))).-step(add(rule(162, (((? * X2) + ((? * X2) + ((? + X3) * -(X2 + X2)))) * X4) = (X3 * (X2 * -(X4 + X4)))))).-step(delete(rule(161, (((X1 * X2) + ((X1 * X2) + ((X3 + X1) * -(X2 + X2)))) * X4) = (((? * X2) + ((? * X2) + ((X3 + ?) * -(X2 + X2)))) * X4)))).-step(add(rule(163, (((X1 * X2) + ((X1 * X2) + ((X3 + X1) * -(X2 + X2)))) * X4) = (((? * X2) + ((? * X2) + ((? + X3) * -(X2 + X2)))) * X4)))).-step(add(rule(164, (X1 * (X2 * ((X3 + X3) * X4))) = ((X1 + X1) * (X2 * (X3 * X4)))))).-step(add(rule(165, (X1 * (X2 * ((X3 + X3) * X4))) = (X1 * ((X2 + X2) * (X3 * X4)))))).-step(add(rule(166, ((X1 + X1) * (X2 * ((X2 + X2) * (X2 + X2)))) = (X1 * (X2 + X2))))).-step(add(rule(167, (X1 * (X2 * (X3 * (X4 + X4)))) = (X1 * (X2 * ((X3 + X3) * X4)))))).-step(add(rule(168, (X1 * (((X2 + X2) * X3) + X4)) = (X1 * ((X2 * (X3 + X3)) + X4))))).-step(add(rule(169, (X1 * (X2 + ((X3 + X3) * X4))) = (X1 * (X2 + (X3 * (X4 + X4))))))).-step(add(rule(170, ((X1 * (X1 * (X1 + X2))) + X3) = (X1 + ((X1 * (X1 * X2)) + X3))))).-step(add(rule(171, (X1 + (X2 + (X1 * (X1 * X3)))) = (X2 + (X1 * (X1 * (X1 + X3))))))).-step(add(rule(172, (X1 * (X1 * (X1 + (X2 + X2)))) = (X1 + (X1 * ((X1 + X1) * X2)))))).-step(add(rule(173, ((X1 * ((X1 + X2) * X1)) + X3) = (X1 + ((X1 * (X2 * X1)) + X3))))).-step(add(rule(174, (X1 + (X2 + (X1 * (X3 * X1)))) = (X2 + (X1 * ((X1 + X3) * X1)))))).-step(add(rule(175, (X1 * ((X1 + (X2 + X2)) * X1)) = (X1 + (X1 * (X2 * (X1 + X1))))))).-step(add(rule(176, ((((X1 + X1) * X2) + X3) * X4) = (((X1 * (X2 + X2)) + X3) * X4)))).-step(add(rule(177, ((X1 + (X1 * X2)) * (X3 * X4)) = (X1 * ((X3 + (X2 * X3)) * X4))))).-step(add(rule(178, (X1 * (X2 * (X3 + (X4 * X3)))) = (X1 * ((X2 + (X2 * X4)) * X3))))).-step(add(rule(179, (X1 * (X2 + ((X3 + X3) * X2))) = ((X1 + ((X1 + X1) * X3)) * X2)))).-step(add(rule(180, (X1 * (X2 + (X1 * (X3 * X2)))) = (X1 * (X1 * ((X1 + X3) * X2)))))).-step(add(rule(181, (X1 * (X2 + (X3 * (X1 * X2)))) = (X1 * ((X1 + X3) * (X1 * X2)))))).-step(add(rule(182, ((X1 + (X1 * (X2 * X3))) * X4) = (X1 * (X4 + (X2 * (X3 * X4))))))).-step(add(rule(183, ((X1 + (X1 * (X2 + X2))) * X3) = (X1 * (X3 + (X2 * (X3 + X3))))))).-step(add(rule(184, ((X1 + ((X2 + X2) * X3)) * X4) = ((X1 + (X2 * (X3 + X3))) * X4)))).-step(add(rule(185, (X1 * -(X2 + (X1 * X1))) = -(X1 + (X1 * X2))))).-step(add(rule(186, ((X1 + (X2 * X2)) * -X2) = -(X2 + (X1 * X2))))).-step(add(rule(187, ((X2 * X1) + -(X1 + (X2 * X1))) = -X1))).-step(add(rule(188, ((X1 * X3) + (X2 * -X3)) = ((X1 + -X2) * X3)))).-step(add(rule(189, ((X1 * X2) + (X3 * (X2 + X4))) = ((X3 * X4) + ((X1 + X3) * X2))))).-step(hard(((X1 + (X3 + X1)) * X2) = ((X3 + (X1 + X1)) * X2))).-step(hard(((X1 + (X3 + X1)) * X2) = ((X1 + (X1 + X3)) * X2))).-step(add(rule(190, (X1 + (X1 * ((X1 * X2) + X3))) = (X1 * (X3 + (X1 * (X1 + X2))))))).-step(add(rule(191, (X1 + (X1 * ((X2 * X1) + X3))) = (X1 * (X3 + ((X1 + X2) * X1)))))).-step(hard(((X1 + (X1 + X2)) * (X2 * X2)) = (X2 + (X1 * (X2 * (X2 + X2)))))).-step(hard((X1 + (X1 * (X2 * (X1 + X1)))) = (X1 * ((X2 + (X2 + X1)) * X1)))).-step(hard((X1 + (X1 * ((X1 + X1) * X2))) = (X1 * (X1 * (X2 + (X2 + X1)))))).-step(add(rule(192, (X1 * ((X2 * X3) + ((X2 * X3) + X4))) = (X1 * (((X2 + X2) * X3) + X4))))).-step(add(rule(193, (X1 * (X2 + (X2 + (X3 * X2)))) = ((X1 + (X1 + (X1 * X3))) * X2)))).-step(add(rule(194, (X1 + (X1 + (X1 * (X2 + X2)))) = ((X1 + X1) * ((X1 * X1) + X2))))).-step(add(rule(195, (X1 + (X1 * (X2 + (X1 * X3)))) = (X1 * (X2 + (X1 * (X3 + X1))))))).-step(add(rule(196, (X1 + (X1 * (X2 + (X3 * X1)))) = (X1 * (X2 + ((X3 + X1) * X1)))))).-step(add(rule(197, ((X1 + (X2 + (X1 * X1))) * (X1 * X1)) = (X1 + ((X1 + (X2 * X1)) * X1))))).-step(add(rule(198, ((X1 + (X2 * -X2)) * -X2) = (X2 + (X1 * -X2))))).-step(add(rule(199, (((X2 + X1) * (X1 * X1)) + X3) = (X1 + ((X2 * (X1 * X1)) + X3))))).-step(add(rule(200, (X1 + (((X2 * X1) + X3) * X1)) = ((((X1 + X2) * X1) + X3) * X1)))).-step(add(rule(201, (X1 + ((X2 + X3) * (X2 * X2))) = (X2 + ((X3 * (X2 * X2)) + X1))))).-step(add(rule(202, ((X1 + ((X1 * X1) + X2)) * (X1 * X1)) = ((X1 + ((X2 + X1) * X1)) * X1)))).-step(add(rule(203, (X1 + (X2 + (X3 * (X1 * X1)))) = (X2 + ((X3 + X1) * (X1 * X1)))))).-step(add(rule(204, (X1 + ((X2 + (X3 * X1)) * X1)) = ((X2 + ((X1 + X3) * X1)) * X1)))).-step(hard((X1 + (X2 * (X1 * (X1 + X1)))) = ((X2 + (X1 + X2)) * (X1 * X1)))).-step(add(rule(205, ((X1 + X1) * (X2 + (X2 + X2))) = ((X1 + (X1 + X1)) * (X2 + X2))))).-step(add(rule(206, (X1 * (X2 + (X2 + (X1 * (X1 + X1))))) = ((X1 + X1) * (X2 + (X1 * X1)))))).-step(simplify_queue).-step(interreduce).-step(delete(rule(106, (X1 + (X1 * (X2 + (X1 * -X1)))) = (X1 * X2)))).-step(delete(rule(117, (X1 + (X2 + (X3 * (X1 * X1)))) = (X2 + ((X1 + X3) * (X1 * X1)))))).-step(delete(rule(121, ((X2 * -X3) + (X1 * X3)) = ((X1 + -X2) * X3)))).-step(delete(rule(146, (X1 + (X1 * ((X1 * -X1) + X2))) = (X1 * X2)))).-step(delete(rule(157, (X2 + ((X1 + (X2 * X2)) * -X2)) = (X1 * -X2)))).-step(delete(rule(158, ((((X2 * -X2) + X1) * -X2) + X3) = (X2 + (X3 + (X1 * -X2)))))).-step(delete(rule(159, ((X3 * X2) + ((X3 + X1) * -X2)) = (X1 * -X2)))).-step(delete(rule(190, (X1 + (X1 * ((X1 * X2) + X3))) = (X1 * (X3 + (X1 * (X1 + X2))))))).-step(delete(rule(191, (X1 + (X1 * ((X2 * X1) + X3))) = (X1 * (X3 + ((X1 + X2) * X1)))))).-step(delete(rule(197, ((X1 + (X2 + (X1 * X1))) * (X1 * X1)) = (X1 + ((X1 + (X2 * X1)) * X1))))).-step(add(rule(207, ((X1 + (X2 + (X1 * X1))) * (X1 * X1)) = ((X1 + ((X1 + X2) * X1)) * X1)))).-step(delete(rule(200, (X1 + (((X2 * X1) + X3) * X1)) = ((((X1 + X2) * X1) + X3) * X1)))).-step(delete(rule(202, ((X1 + ((X1 * X1) + X2)) * (X1 * X1)) = ((X1 + ((X2 + X1) * X1)) * X1)))).-step(hard(((X1 + X3) * (X2 + X2)) = ((X3 + X1) * (X2 + X2)))).-step(hard(((X1 + X1) * (X2 + X3)) = ((X1 + X1) * (X3 + X2)))).-step(add(rule(208, (X2 + (X2 + (X1 * (X2 * (X2 + X2))))) = ((X1 + X2) * (X2 * (X2 + X2)))))).-step(add(rule(209, (X1 * ((X1 + X1) * (X1 + X1))) = (X1 + (X1 + (X1 + X1)))))).-step(add(rule(210, (X3 + (X4 + (X2 + (-(X3 + X4) + X1)))) = (X1 + X2)))).-step(add(rule(211, (X3 + (X4 + (X1 + (X2 + -(X3 + X4))))) = (X1 + X2)))).-step(add(rule(212, (X1 * ((X1 * (X1 + X1)) + X2)) = (X1 + (X1 + (X1 * X2)))))).-step(add(rule(213, (X1 * (X2 + (X1 * (X1 + X1)))) = (X1 + (X1 + (X1 * X2)))))).-step(add(rule(214, ((X2 + (X3 + (X1 * X1))) * X1) = (X1 + ((X2 + X3) * X1))))).-step(add(rule(215, (X2 + (X2 + (X1 * (X2 + X2)))) = ((X1 + (X2 * X2)) * (X2 + X2))))).-step(add(rule(216, ((X1 + X1) * (X2 + X2)) = (X1 * ((X1 + X1) * ((X1 + X1) * X2)))))).-step(add(rule(217, ((X1 + X1) * ((X1 + X1) * (X2 + X2))) = (X1 * ((X1 + X1) * X2))))).-step(add(rule(218, (X1 * (X1 * ((X1 * X3) + X2))) = (X1 * ((X1 * X2) + X3))))).-step(hard(((X1 + X2) * (X3 + X3)) = ((X1 + (X2 + (X1 + X2))) * X3))).-step(hard(((X1 + (X1 + (X2 + X2))) * X3) = ((X2 + X1) * (X3 + X3)))).-step(hard(((X1 + X1) * (X2 + X3)) = (X1 * (X2 + (X3 + (X2 + X3)))))).-step(hard((X1 * (X2 + (X2 + (X3 + X3)))) = ((X1 + X1) * (X3 + X2)))).-step(add(rule(219, ((X1 + (X2 * (X2 + X2))) * X2) = (X2 + (X2 + (X1 * X2)))))).-step(add(rule(220, -(X2 + (-X1 + X3)) = (X1 + -(X2 + X3))))).-step(add(rule(221, -((X1 * -X2) + X3) = ((X1 * X2) + -X3)))).-step(add(rule(222, ((? + (-? + X2)) * (X3 + X3)) = ((X2 + X2) * X3)))).-step(add(rule(223, ((X1 + (-X1 + X2)) * (X3 + X3)) = ((? + (-? + X2)) * (X3 + X3))))).-step(add(rule(224, ((X1 + X1) * (? + (-? + X3))) = (X1 * (X3 + X3))))).-step(add(rule(225, ((X1 + X1) * (X2 + (-X2 + X3))) = ((X1 + X1) * (? + (-? + X3)))))).-step(add(rule(226, ((-X1 + X2) * -X3) = ((X1 + -X2) * X3)))).-step(add(rule(227, ((X1 * X2) + -(X3 + (X1 * X2))) = -X3))).-step(add(rule(228, (((X1 + X1) * X2) + X3) = (X3 + (X1 * (X2 + X2)))))).-step(add(rule(229, ((X1 * (X2 + X2)) + X3) = (X3 + ((X1 + X1) * X2))))).-step(add(rule(230, (X1 * (X2 * (X1 * (X2 * (X1 * (X2 * X3)))))) = (X1 * (X2 * X3))))).-step(add(rule(231, ((X1 * (X2 * X3)) + ((X4 * X3) + X5)) = ((((X1 * X2) + X4) * X3) + X5)))).-step(add(rule(232, ((X1 * (X2 * (X3 * X5))) + (X4 * X5)) = (((X1 * (X2 * X3)) + X4) * X5)))).-step(add(rule(233, ((X1 * (X2 * X5)) + (X3 * (X4 * X5))) = (((X1 * X2) + (X3 * X4)) * X5)))).-step(add(rule(234, ((X1 * (X2 * X3)) + (X4 + (X5 * X3))) = (X4 + (((X1 * X2) + X5) * X3))))).-step(add(rule(235, ((((X1 + X1) * X2) + X3) * X4) = ((X1 * (X2 * (X4 + X4))) + (X3 * X4))))).-step(add(rule(236, ((X1 + ((X1 + X1) * X2)) * X3) = (X1 * (X3 + (X2 * (X3 + X3))))))).-step(add(rule(237, (((X1 * (X2 + X2)) + X3) * X4) = ((X1 * (X2 * (X4 + X4))) + (X3 * X4))))).-step(add(rule(238, (((X1 * X2) + (X3 + X3)) * X4) = ((X1 * (X2 * X4)) + (X3 * (X4 + X4)))))).-step(add(rule(239, (((X1 * X1) + (X2 + X2)) * X1) = (X1 + (X2 * (X1 + X1)))))).-step(add(rule(240, ((X1 + X1) * ((X2 + (X1 * X1)) * X3)) = ((X1 + X1) * (X3 + (X2 * X3)))))).-step(add(rule(241, ((X2 + ((X1 * X1) + X2)) * X1) = (X1 + (X2 * (X1 + X1)))))).-step(add(rule(242, (((X1 * X2) + X3) * (X2 * (X2 * X4))) = ((X1 + (X3 * X2)) * (X2 * X4))))).-step(add(rule(243, ((X1 + (X1 * (X2 * -X2))) * (X2 * X3)) = 0))).-step(add(rule(244, (X1 * (X2 + (X2 * (X1 * -X1)))) = 0))).-step(add(rule(245, ((X1 + (X1 * (X2 * -X2))) * (X2 + X2)) = 0))).-step(add(rule(246, (X1 * ((X2 + (X2 * (X1 * -X1))) * X3)) = 0))).-step(add(rule(247, ((X1 + (X1 * (X2 * -X2))) * -X2) = 0))).-step(add(rule(248, (X1 * -(X2 + (X2 * (X1 * -X1)))) = 0))).-step(add(rule(249, (X1 * (-X2 + (X2 * (X1 * X1)))) = 0))).-step(add(rule(250, ((X1 * X2) + ((X3 * (X4 * X2)) + X5)) = (((X1 + (X3 * X4)) * X2) + X5)))).-step(add(rule(251, ((X1 * X5) + (X2 * (X3 * (X4 * X5)))) = ((X1 + (X2 * (X3 * X4))) * X5)))).-step(add(rule(252, ((X1 * X2) + (X3 + (X4 * (X5 * X2)))) = (X3 + ((X1 + (X4 * X5)) * X2))))).-step(add(rule(253, (X1 + ((X2 + (X1 * X3)) * X1)) = ((X2 + (X1 * (X1 + X3))) * X1)))).-step(add(rule(254, ((X1 + (X1 + (X2 * X3))) * X4) = ((X1 * (X4 + X4)) + (X2 * (X3 * X4)))))).-step(add(rule(255, ((X1 + ((X2 + X2) * X3)) * X4) = ((X1 * X4) + (X2 * (X3 * (X4 + X4))))))).-step(add(rule(256, ((X1 + (X2 * (X3 + X3))) * X4) = ((X1 * X4) + (X2 * (X3 * (X4 + X4))))))).-step(add(rule(257, ((X1 + (X2 * X3)) * (X3 * (X3 * X4))) = (((X1 * X3) + X2) * (X3 * X4))))).-step(add(rule(258, (X1 * ((X2 * (X1 * (X2 * (X1 * X2)))) + X3)) = (X1 * (X2 + X3))))).-step(add(rule(259, (X1 * (X2 + (X3 * (X1 * (X3 * (X1 * X3)))))) = (X1 * (X2 + X3))))).-step(add(rule(260, (X2 + ((X1 + X2) * (X2 * -X2))) = (X1 * (X2 * -X2))))).-step(add(rule(261, (X1 * (X2 * -(X3 + X3))) = (X1 * ((X2 + X2) * -X3))))).-step(add(rule(262, (X1 * (X2 + (X3 * X2))) = (X1 * (X1 * ((X1 + (X1 * X3)) * X2)))))).-step(add(rule(263, (X1 * (X2 + (X3 + (X1 * (X1 * X4))))) = (X1 * (X2 + (X3 + X4)))))).-step(add(rule(264, (X1 * ((X2 + (X1 * (X1 * X3))) * X4)) = (X1 * ((X2 + X3) * X4))))).-step(add(rule(265, (X1 * (X2 + (X3 + X3))) = (X1 * (X2 + (X1 * ((X1 + X1) * X3))))))).-step(add(rule(266, (X1 * (X2 + (X1 * (X1 + (X1 * X3))))) = (X1 + (X1 * (X2 + X3)))))).-step(add(rule(267, (X1 * (X2 * -(X3 + X3))) = ((X1 + X1) * (X2 * -X3))))).-step(add(rule(268, ((X1 + (X1 * X2)) * -X3) = (X1 * -(X3 + (X2 * X3)))))).-step(add(rule(269, (X1 + (X2 * (X1 * -X1))) = ((X1 + -X2) * (X1 * X1))))).-step(add(rule(270, ((X1 + X1) * (X1 + X1)) = (X1 * -(X1 + X1))))).-step(add(rule(271, ((X1 + X1) * -(X1 + X1)) = (X1 * (X1 + X1))))).-step(add(rule(272, (X1 + (X1 + (X1 + X1))) = -(X1 + X1)))).-step(add(rule(273, -(X1 + (X1 + X1)) = (X1 + (X1 + X1))))).-step(add(rule(274, (-X1 + (X2 * (X1 * X1))) = ((-X1 + X2) * (X1 * X1))))).-step(add(rule(275, -(X1 + (X1 * (X2 * -X1))) = (X1 * ((X2 + -X1) * X1))))).-step(add(rule(276, (X1 + (X1 * (X2 * -X1))) = (X1 * ((X1 + -X2) * X1))))).-step(add(rule(277, ((X1 + (X1 * -X2)) * X3) = (X1 * (X3 + (X2 * -X3)))))).-step(add(rule(278, (X1 * (X2 + (X2 + X2))) = ((X1 + (X1 + X1)) * -X2)))).-step(add(rule(279, ((X1 + X1) * (X2 + (X2 + X2))) = 0))).-step(interreduce).-step(delete(rule(108, (X1 + ((X2 + (X1 * -X1)) * X1)) = (X2 * X1)))).-step(delete(rule(112, ((X1 + (X1 + (X1 + X1))) * X2) = (X1 * (X2 + (X2 + (X2 + X2))))))).-step(delete(rule(113, ((X1 * X3) + (X2 * (X1 * (X1 * X3)))) = ((X1 + X2) * (X1 * (X1 * X3)))))).-step(delete(rule(114, (X1 * ((X1 + X1) * ((X1 + X1) * (X2 + X2)))) = ((X1 + X1) * X2)))).-step(delete(rule(145, ((X1 + X1) * (X1 + (X1 + (X1 + X1)))) = (X1 * (X1 + X1))))).-step(delete(rule(154, ((X1 * (X2 + X2)) + X3) = (((X1 + X1) * X2) + X3)))).-step(delete(rule(166, ((X1 + X1) * (X2 * ((X2 + X2) * (X2 + X2)))) = (X1 * (X2 + X2))))).-step(add(rule(280, ((X1 + X1) * -(X2 + X2)) = (X1 * (X2 + X2))))).-step(delete(rule(187, ((X2 * X1) + -(X1 + (X2 * X1))) = -X1))).-step(delete(rule(205, ((X1 + X1) * (X2 + (X2 + X2))) = ((X1 + (X1 + X1)) * (X2 + X2))))).-step(add(rule(281, ((X1 + (X1 + X1)) * (X2 + X2)) = 0))).-step(delete(rule(209, (X1 * ((X1 + X1) * (X1 + X1))) = (X1 + (X1 + (X1 + X1)))))).-step(delete(rule(210, (X3 + (X4 + (X2 + (-(X3 + X4) + X1)))) = (X1 + X2)))).-step(delete(rule(212, (X1 * ((X1 * (X1 + X1)) + X2)) = (X1 + (X1 + (X1 * X2)))))).-step(delete(rule(231, ((X1 * (X2 * X3)) + ((X4 * X3) + X5)) = ((((X1 * X2) + X4) * X3) + X5)))).-step(delete(rule(242, (((X1 * X2) + X3) * (X2 * (X2 * X4))) = ((X1 + (X3 * X2)) * (X2 * X4))))).-step(delete(rule(247, ((X1 + (X1 * (X2 * -X2))) * -X2) = 0))).-step(delete(rule(250, ((X1 * X2) + ((X3 * (X4 * X2)) + X5)) = (((X1 + (X3 * X4)) * X2) + X5)))).-step(delete(rule(258, (X1 * ((X2 * (X1 * (X2 * (X1 * X2)))) + X3)) = (X1 * (X2 + X3))))).-step(delete(rule(260, (X2 + ((X1 + X2) * (X2 * -X2))) = (X1 * (X2 * -X2))))).-step(delete(rule(271, ((X1 + X1) * -(X1 + X1)) = (X1 * (X1 + X1))))).-step(delete(rule(275, -(X1 + (X1 * (X2 * -X1))) = (X1 * ((X2 + -X1) * X1))))).-step(add(rule(282, ((X1 + (X1 + X1)) * -(X2 + X2)) = 0))).-step(add(rule(283, ((X1 + X1) * (X2 + X2)) = (X1 * -(X2 + X2))))).-step(add(rule(284, ((X1 + (X1 + X1)) * ((X2 + X2) * X3)) = 0))).-step(add(rule(285, ((X1 + (X1 + X1)) * (X2 * (X3 + X3))) = 0))).-step(add(rule(286, ((X1 + X1) * ((X2 + (X2 + X2)) * X3)) = 0))).-step(add(rule(287, (((X1 + X1) * X2) + (((X1 + X1) * X2) + (((X1 + X1) * X2) + X3))) = X3))).-step(add(rule(288, (((X1 + (X1 + X1)) * X2) + (((X1 + (X1 + X1)) * X2) + X3)) = X3))).-step(add(rule(289, ((X1 + X1) * (X2 + (X2 * (X1 * (X1 + X1))))) = 0))).-step(add(rule(290, ((X1 + (X1 * (X2 * (X2 + X2)))) * (X2 + X2)) = 0))).-step(add(rule(291, ((X1 + X1) * (X2 * (X3 + (X3 + X3)))) = 0))).-step(add(rule(292, (X1 * (X2 + (X2 + X3))) = (X1 * ((X1 * ((X1 + X1) * X2)) + X3))))).-step(add(rule(293, ((X1 + (X1 + X1)) * (X1 * ((X1 + X1) * X2))) = 0))).-step(add(rule(294, ((X1 + (X1 + X1)) * (X1 * -(X1 + X1))) = 0))).-step(add(rule(295, (X1 * (-X2 + (-X2 + X3))) = (X1 * (-(X2 + X2) + X3))))).-step(add(rule(296, (X1 * (X1 * ((X1 + (X1 * X2)) * X3))) = ((X1 + (X1 * X2)) * X3)))).-step(add(rule(297, (((X1 * (X2 * (X3 * X3))) + X4) * X3) = (((X1 * X2) + X4) * X3)))).-step(add(rule(298, (((X1 * (X2 * (X2 + X2))) + X3) * X2) = ((X1 + (X1 + X3)) * X2)))).-step(add(rule(299, (X1 * (-(X2 + X2) + X3)) = (X1 * (X3 + -(X2 + X2)))))).-step(add(rule(300, ((X1 * -(X2 + X2)) + X3) = (X3 + ((X1 + X1) * -X2))))).-step(add(rule(301, (X1 + ((X2 + X2) * -X3)) = (X1 + (X2 * -(X3 + X3)))))).-step(add(rule(302, -(X3 + ((X1 + X1) * X2)) = -(X3 + (X1 * (X2 + X2)))))).-step(add(rule(303, (((X1 + X1) * -X2) + X3) = (X3 + (X1 * -(X2 + X2)))))).-step(add(rule(304, (((X1 * (X2 * X2)) + X3) * (X2 * X4)) = ((X1 + X3) * (X2 * X4))))).-step(add(rule(305, ((X1 + (X2 * (X3 * X3))) * (X3 * X4)) = ((X1 + X2) * (X3 * X4))))).-step(add(rule(306, (X1 * ((X1 * -X1) + X2)) = (-X1 + (X1 * X2))))).-step(add(rule(307, (X1 + (-X1 + (X1 * X2))) = (X1 * X2)))).-step(add(rule(308, (X1 * (X2 + (X1 * -X1))) = (-X1 + (X1 * X2))))).-step(add(rule(309, (X1 * (X2 * (X3 * (X4 + X4)))) = ((X1 + X1) * (X2 * (X3 * X4)))))).-step(add(rule(310, (X1 * (X2 * (X3 * (X4 + X4)))) = (X1 * ((X2 + X2) * (X3 * X4)))))).-step(add(rule(311, ((X1 + X1) * (X2 * (X3 + X3))) = (X1 * (X2 * -(X3 + X3)))))).-step(add(rule(312, ((X1 + X1) * ((X2 + X2) * X3)) = (X1 * (X2 * -(X3 + X3)))))).-step(add(rule(313, ((X1 * (X2 + X2)) + ((X3 + -X1) * X2)) = ((X1 + X3) * X2)))).-step(add(rule(314, ((X1 * (X2 + X2)) + ((-X1 + X3) * X2)) = ((X3 + X1) * X2)))).-step(add(rule(315, ((X1 + (X1 + X1)) * (X2 * X3)) = (X1 * ((X2 + (X2 + X2)) * X3))))).-step(add(rule(316, (X1 * (X2 * (X3 + (X3 + X3)))) = (X1 * ((X2 + (X2 + X2)) * X3))))).-step(add(rule(317, (((X1 + X1) * X2) + (X1 * (X3 + -X2))) = (X1 * (X2 + X3))))).-step(add(rule(318, (((X1 + X1) * X2) + (X1 * (-X2 + X3))) = (X1 * (X3 + X2))))).-step(add(rule(319, (X1 * (X2 + (X2 * (X1 * X1)))) = ((X1 + X1) * X2)))).-step(add(rule(320, (X1 + (X1 * (X2 + ((X1 * -X1) + X3)))) = (X1 * (X3 + X2))))).-step(hard(((X1 + (X1 + (X2 + X2))) * X3) = ((X1 + (X2 + (X1 + X2))) * X3))).-step(hard((X1 * (X2 + (X2 + (X3 + X3)))) = (X1 * (X2 + (X3 + (X2 + X3)))))).-step(add(rule(321, (X1 * (((X2 + X2) * X3) + X4)) = (X1 * (X4 + ((X2 + X2) * X3)))))).-step(add(rule(322, (X1 * (((X2 + X2) * X3) + X4)) = (X1 * (X4 + (X2 * (X3 + X3))))))).-step(add(rule(323, (X1 * ((X2 * (X3 + X3)) + X4)) = (X1 * (X4 + ((X2 + X2) * X3)))))).-step(add(rule(324, (X1 + (X1 * (X2 * (X3 + X3)))) = (X1 + (X1 * ((X2 + X2) * X3)))))).-step(hard((X1 * (X2 * (X3 + (X4 + X4)))) = (X1 * (X2 * (X4 + (X4 + X3)))))).-step(hard((X1 * ((X2 + (X4 + X4)) * X3)) = (X1 * ((X4 + (X4 + X2)) * X3)))).-step(add(rule(325, ((X1 * (X1 * (X2 + X1))) + X3) = (X1 + ((X1 * (X1 * X2)) + X3))))).-step(add(rule(326, (X1 + (X2 * (X2 * (X2 + X3)))) = (X2 + ((X2 * (X2 * X3)) + X1))))).-step(add(rule(327, (X1 + (X2 + (X1 * (X1 * X3)))) = (X2 + (X1 * (X1 * (X3 + X1))))))).-step(hard((X1 + (X1 * ((X1 + X1) * X2))) = (X1 * (X1 * (X2 + (X1 + X2)))))).-step(add(rule(328, ((X1 * ((X2 + X1) * X1)) + X3) = (X1 + ((X1 * (X2 * X1)) + X3))))).-step(add(rule(329, (X1 + (X2 * ((X2 + X3) * X2))) = (X2 + ((X2 * (X3 * X2)) + X1))))).-step(add(rule(330, (X1 + (X2 + (X1 * (X3 * X1)))) = (X2 + (X1 * ((X3 + X1) * X1)))))).-step(hard((X1 + (X1 * (X2 * (X1 + X1)))) = (X1 * ((X2 + (X1 + X2)) * X1)))).-step(add(rule(331, (((X1 * (X2 + X2)) + X3) * X4) = ((X3 + ((X1 + X1) * X2)) * X4)))).-step(add(rule(332, ((((X1 + X1) * X2) + X3) * X4) = ((X3 + (X1 * (X2 + X2))) * X4)))).-step(add(rule(333, ((X1 + (X1 * X2)) * (X2 * X3)) = (X1 * (X2 * (X3 + (X2 * X3))))))).-step(add(rule(334, ((X1 + X1) * (X2 + (X1 * ((X1 + X1) * X2)))) = 0))).-step(add(rule(335, (X1 * (X1 * ((X1 + X2) * X2))) = (X1 * ((X2 + X1) * (X2 * X2)))))).-step(add(rule(336, (X1 * (X2 + (X1 * (X3 * X2)))) = (X1 * (X1 * ((X3 + X1) * X2)))))).-step(add(rule(337, (X1 * ((X1 + X2) * (X1 * X2))) = (X1 * (X2 * ((X2 + X1) * X2)))))).-step(add(rule(338, (X1 * (X2 + (X3 * (X1 * X2)))) = (X1 * ((X3 + X1) * (X1 * X2)))))).-step(add(rule(339, (X1 * -(X2 + (X1 * (X1 * -X2)))) = 0))).-step(add(rule(340, ((X1 + (X1 * (X2 * X3))) * X3) = (X1 * ((X3 + X2) * (X3 * X3)))))).-step(add(rule(341, ((X1 + (X1 * (X2 * -X2))) * X2) = 0))).-step(add(rule(342, ((X1 + (X1 * (X2 * -X2))) * -X2) = 0))).-step(add(rule(343, ((X1 + (X1 * (X2 * X3))) * X2) = (X1 * (X2 * ((X2 + X3) * X2)))))).-step(add(rule(344, (X1 * -((X1 * X1) + X2)) = -(X1 + (X1 * X2))))).-step(add(rule(345, (((X1 * X1) + X2) * -X1) = -(X1 + (X2 * X1))))).-step(add(rule(346, ((X1 * X2) + ((X3 + X1) * X4)) = ((X1 * (X4 + X2)) + (X3 * X4))))).-step(hard((X1 * (X2 + (X3 + X2))) = (X1 * (X3 + (X2 + X2))))).-step(hard((X1 * (X2 + (X3 + X2))) = (X1 * (X2 + (X2 + X3))))).-step(add(rule(347, ((X1 * -X2) + ((X3 + X1) * X2)) = (X3 * X2)))).-step(add(rule(348, ((X1 * X2) + ((X3 + X1) * X4)) = ((X3 * X4) + (X1 * (X2 + X4)))))).-step(add(rule(349, (X1 * (X2 + -(X3 + X2))) = (X1 * -X3)))).-step(add(rule(350, ((X1 + -(X3 + X1)) * X2) = (X3 * -X2)))).-step(add(rule(351, (((X1 * X2) + (X4 + X1)) * X3) = ((X4 + (X1 + (X1 * X2))) * X3)))).-step(interreduce).-step(delete(rule(103, ((X1 + (X1 + X1)) * (X1 * X1)) = (X1 + (X1 + X1))))).-step(delete(rule(153, (((X1 + X1) * -X2) + X3) = ((X1 * -(X2 + X2)) + X3)))).-step(delete(rule(168, (X1 * (((X2 + X2) * X3) + X4)) = (X1 * ((X2 * (X3 + X3)) + X4))))).-step(delete(rule(171, (X1 + (X2 + (X1 * (X1 * X3)))) = (X2 + (X1 * (X1 * (X1 + X3))))))).-step(delete(rule(174, (X1 + (X2 + (X1 * (X3 * X1)))) = (X2 + (X1 * ((X1 + X3) * X1)))))).-step(delete(rule(180, (X1 * (X2 + (X1 * (X3 * X2)))) = (X1 * (X1 * ((X1 + X3) * X2)))))).-step(delete(rule(181, (X1 * (X2 + (X3 * (X1 * X2)))) = (X1 * ((X1 + X3) * (X1 * X2)))))).-step(delete(rule(189, ((X1 * X2) + (X3 * (X2 + X4))) = ((X3 * X4) + ((X1 + X3) * X2))))).-step(delete(rule(216, ((X1 + X1) * (X2 + X2)) = (X1 * ((X1 + X1) * ((X1 + X1) * X2)))))).-step(add(rule(352, (X1 * -(X2 + X2)) = (X1 * ((X1 + X1) * ((X1 + X1) * X2)))))).-step(delete(rule(217, ((X1 + X1) * ((X1 + X1) * (X2 + X2))) = (X1 * ((X1 + X1) * X2))))).-step(delete(rule(262, (X1 * (X2 + (X3 * X2))) = (X1 * (X1 * ((X1 + (X1 * X3)) * X2)))))).-step(delete(rule(270, ((X1 + X1) * (X1 + X1)) = (X1 * -(X1 + X1))))).-step(delete(rule(288, (((X1 + (X1 + X1)) * X2) + (((X1 + (X1 + X1)) * X2) + X3)) = X3))).-step(delete(rule(293, ((X1 + (X1 + X1)) * (X1 * ((X1 + X1) * X2))) = 0))).-step(delete(rule(294, ((X1 + (X1 + X1)) * (X1 * -(X1 + X1))) = 0))).-step(delete(rule(304, (((X1 * (X2 * X2)) + X3) * (X2 * X4)) = ((X1 + X3) * (X2 * X4))))).-step(delete(rule(306, (X1 * ((X1 * -X1) + X2)) = (-X1 + (X1 * X2))))).-step(delete(rule(341, ((X1 + (X1 * (X2 * -X2))) * X2) = 0))).-step(add(rule(353, (X1 * ((X1 + X1) * ((X1 + X1) * X2))) = ((X1 + X1) * -X2)))).-step(add(rule(354, (X1 + (X1 + (X1 * (X2 + X2)))) = ((X1 + X1) * (X2 + (X1 * X1)))))).-step(add(rule(355, (X1 + (X1 * ((X1 * X3) + X2))) = (X1 * (X2 + (X1 * (X3 + X1))))))).-step(add(rule(356, (X1 * (X2 + (X1 * (X2 + X1)))) = (X1 + ((X1 + (X1 * X1)) * X2))))).-step(add(rule(357, (X1 + (X1 * ((X3 * X1) + X2))) = (X1 * (X2 + ((X3 + X1) * X1)))))).-step(add(rule(358, (((X1 * -X1) + X2) * -X1) = (X1 + (X2 * -X1))))).-step(add(rule(359, ((X1 + (X2 * -X2)) * X2) = (-X2 + (X1 * X2))))).-step(hard((X1 + ((X2 * (X1 * X1)) + X3)) = (X3 + ((X2 + X1) * (X1 * X1))))).-step(add(rule(360, (X1 + ((X2 + X3) * (X2 * X2))) = (X2 + (X1 + (X3 * (X2 * X2))))))).-step(hard((X1 + ((X2 + X3) * (X3 * X3))) = (X1 + ((X3 + X2) * (X3 * X3))))).-step(add(rule(361, (X2 + (((X3 * X2) + X1) * X2)) = ((X1 + ((X2 + X3) * X2)) * X2)))).-step(add(rule(362, ((X1 + ((X2 + X1) * X2)) * X2) = (X2 + (X1 * (X2 + (X2 * X2))))))).-step(add(rule(363, ((X1 + ((X1 * X1) + X2)) * (X1 * X1)) = ((X1 + ((X1 + X2) * X1)) * X1)))).-step(add(rule(364, ((X2 + (X1 + (X1 * X1))) * (X1 * X1)) = ((X1 + ((X1 + X2) * X1)) * X1)))).-step(add(rule(365, ((X1 + (X1 * X3)) * (X2 + X2)) = ((X1 + X1) * (X2 + (X3 * X2)))))).-step(add(rule(366, (X2 + (((X2 * X3) + X1) * X2)) = ((X1 + (X2 * (X2 + X3))) * X2)))).-step(add(rule(367, ((X1 + (X1 + (X1 + X2))) * (X3 + X3)) = (X2 * (X3 + X3))))).-step(add(rule(368, ((X1 + ((X2 * X2) + X3)) * (X2 * X2)) = ((X2 + ((X1 + X3) * X2)) * X2)))).-step(add(rule(369, (X1 * ((X2 * (X3 + X3)) + X4)) = (X1 * (((X2 + X2) * X3) + X4))))).-step(hard((X1 + X2) = (X3 + (X4 + (X1 + (X2 + -(X4 + X3))))))).-step(add(rule(370, ((X3 + ((X1 * X1) + X2)) * X1) = (X1 + ((X2 + X3) * X1))))).-step(add(rule(371, (((X1 * (X1 + X1)) + X2) * X1) = (X1 + (X1 + (X2 * X1)))))).-step(add(rule(372, (X1 * (X2 + (X3 + (X3 * (X1 * -X1))))) = (X1 * X2)))).-step(add(rule(373, ((X1 + X1) * ((X2 + X2) * -X3)) = (X1 * ((X2 + X2) * X3))))).-step(add(rule(374, ((X1 + X1) * (-(X2 + X2) + X3)) = ((X1 + X1) * (X2 + X3))))).-step(add(rule(375, ((X1 + X1) * (X2 + -(X3 + X3))) = ((X1 + X1) * (X2 + X3))))).-step(add(rule(376, ((X1 + X1) * (X2 * -(X3 + X3))) = (X1 * (X2 * (X3 + X3)))))).-step(add(rule(377, ((X1 + (X1 * (X2 * (X2 + X2)))) * ((X2 + X2) * X3)) = 0))).-step(add(rule(378, ((X1 + (X1 + X1)) * (X2 + (X3 + (X2 + X3)))) = 0))).-step(add(rule(379, ((X1 + (X1 + X1)) * (X2 + (X2 + (X3 + X3)))) = 0))).-step(add(rule(380, (X1 * (-X2 + (X1 * ((X1 + X1) * X2)))) = (X1 * X2)))).-step(add(rule(381, ((X1 + (X1 + X1)) * -X2) = ((X1 + (X1 + X1)) * X2)))).-step(add(rule(382, ((-X1 + (X1 * (X2 * (X2 + X2)))) * X2) = (X1 * X2)))).-step(add(rule(383, (X1 * ((X1 * (X1 + X1)) + X2)) = (X1 + (X1 + (X1 * X2)))))).-step(hard((((X1 * X1) + (X2 + X1)) * X1) = (X1 + ((X2 + X1) * X1)))).-step(hard(((X1 + (-X1 + (X3 + X1))) * X2) = ((X3 + X1) * X2))).-step(add(rule(384, (X2 + (-(X2 + (X3 * X2)) + ((X1 + (X3 + (X1 * X3))) * X2))) = (X1 * (X2 + (X3 * X2)))))).-step(add(rule(385, (X2 + (X2 + (X2 + (X2 + (X2 + (X2 + ((X1 + (X1 + X1)) * X2))))))) = (X1 * (X2 + (X2 + X2)))))).-step(add(rule(386, ((X2 * -X3) + ((X2 + (X2 + (X1 * X2))) * X3)) = ((X2 + (X1 * X2)) * X3)))).-step(add(rule(387, (((X1 + X1) * X2) + X3) = (? + (? + (X3 + (-(? + ?) + (X1 * (X2 + X2))))))))).-step(add(rule(388, (X4 + (X5 + (X3 + (-(X4 + X5) + (X1 * (X2 + X2)))))) = (? + (? + (X3 + (-(? + ?) + (X1 * (X2 + X2))))))))).-step(add(rule(389, (((X1 + X1) * X2) + X3) = ((X1 * (X2 + X2)) + X3)))).-step(add(rule(390, ((X1 * (X2 + X2)) + X3) = (? + (? + (X3 + (-(? + ?) + ((X1 + X1) * X2)))))))).-step(add(rule(391, (X4 + (X5 + (X3 + (-(X4 + X5) + ((X1 + X1) * X2))))) = (? + (? + (X3 + (-(? + ?) + ((X1 + X1) * X2)))))))).-step(add(rule(392, (X1 * (X2 * (X3 + (X3 * (X1 * -X1))))) = 0))).-step(add(rule(393, (X1 * (X2 * (X3 + (X1 * (X1 * -X3))))) = 0))).-step(add(rule(394, ((X1 + (X1 + X1)) * (X2 * -(X3 + X3))) = 0))).-step(add(rule(395, ((X1 + (X1 * (X2 * (X2 + X2)))) * -(X2 + X2)) = 0))).-step(add(rule(396, ((X3 * -X2) + ((X3 + X1) * X2)) = (X1 * X2)))).-step(add(rule(397, ((X1 + X1) * ((X1 + X1) * X2)) = (X1 * ((X1 + X1) * -X2))))).-step(add(rule(398, ((X1 + X1) * (X2 + (X2 * (X1 * -X1)))) = 0))).-step(add(rule(399, (X1 * (X2 * (X3 + (X1 * (X2 * (X1 * X2)))))) = (X1 * (X2 + (X2 * X3)))))).-step(add(rule(400, (X1 + (X2 + (X3 * ((X1 + X2) * (X1 + X2))))) = ((X1 + (X2 + X3)) * ((X1 + X2) * (X1 + X2)))))).-step(add(rule(401, ((X1 + (X2 + (X1 + X2))) * ((X1 + X2) * (X1 + X2))) = (X1 + (X2 + (X1 + X2)))))).-step(add(rule(402, ((X1 * X2) + (X3 * (X1 * (X2 * (X1 * X2))))) = (((X1 * X2) + X3) * (X1 * (X2 * (X1 * X2))))))).-step(add(rule(403, (X1 * ((X1 + (X2 * X1)) * (X2 * (X1 * X2)))) = (X1 * (X2 + (X1 * (X2 * (X1 * X2)))))))).-step(add(rule(404, ((X1 + (X1 * (X2 * -X2))) * (X3 * X2)) = 0))).-step(add(rule(405, (X1 * (X3 * (X3 * (X2 * X3)))) = (X1 * (X2 * X3))))).-step(add(rule(406, ((X3 * X4) + (X1 * (X2 * (X3 * (X3 * X4))))) = (((X1 * X2) + X3) * (X3 * (X3 * X4)))))).-step(add(rule(407, ((X2 + -X1) * (X3 + X3)) = ((X2 + (-(X1 + X1) + X2)) * X3)))).-step(add(rule(408, ((X1 + X1) * (X3 + -X2)) = (X1 * (X3 + (-(X2 + X2) + X3)))))).-step(add(rule(409, ((X1 + (((X2 * -X2) + X1) * (X2 * -X2))) * (X2 * -X2)) = (X2 * -X2)))).-step(add(rule(410, (X1 * (X2 + (X1 * ((X1 + X1) * -X2)))) = (X1 * -X2)))).-step(add(rule(411, ((X1 + (X1 + X2)) * -(X3 + X3)) = ((X1 + -X2) * (X3 + X3))))).-step(add(rule(412, ((X1 + X1) * ((X2 + X2) * X3)) = (X1 * ((X2 + X2) * -X3))))).-step(add(rule(413, ((X1 + X1) * (X2 + (X2 + X3))) = ((X1 + X1) * (X3 + -X2))))).-step(add(rule(414, ((X1 + X1) * (X2 + (X1 * ((X1 + X1) * X3)))) = ((X1 + X1) * (X2 + -X3))))).-step(add(rule(415, ((X2 + (X2 * (X3 * -X3))) * X3) = 0))).-step(add(rule(416, ((X2 + (X2 + X1)) * (X3 + X3)) = ((X1 + -X2) * (X3 + X3))))).-step(add(rule(417, ((X1 + X1) * (X2 + (X3 + X3))) = ((X1 + X1) * (X2 + -X3))))).-step(add(rule(418, ((X1 + (X2 * -(X2 + X2))) * X2) = ((X1 * X2) + -(X2 + X2))))).-step(add(rule(419, ((X1 + (X2 * (X2 * -X1))) * -X2) = 0))).-step(add(rule(420, (X1 * (X1 * (X2 * X1))) = (X2 * X1)))).-step(add(rule(421, (X2 * (X2 * (X1 * -X2))) = (X1 * -X2)))).-step(add(rule(422, ((X1 + (X2 * (X2 * -X1))) * X2) = 0))).-step(add(rule(423, ((X1 + X2) * ((X3 + X3) * X4)) = ((X1 + (X2 + (X1 + X2))) * (X3 * X4))))).-step(add(rule(424, ((X1 + (X2 + (X1 + X2))) * (X3 + (X3 + X3))) = 0))).-step(add(rule(425, ((X1 + X2) * ((X3 + X3) * X4)) = ((X1 + (X1 + (X2 + X2))) * (X3 * X4))))).-step(hard(((X1 + X2) * ((X3 + X3) * X4)) = ((X2 + X1) * (X3 * (X4 + X4))))).-step(add(rule(426, ((X1 + -(X2 + X2)) * (X3 + X3)) = ((X1 + X2) * (X3 + X3))))).-step(add(rule(427, (X1 * ((X2 + X2) * (X3 + (X2 * X2)))) = ((X1 + X1) * (X2 + (X2 * X3)))))).-step(add(rule(428, ((X1 + X1) * ((X2 + X3) * X4)) = (X1 * ((X2 + (X3 + (X2 + X3))) * X4))))).-step(add(rule(429, (X1 * (((X2 + X2) * X3) + X4)) = (((X1 + X1) * (X2 * X3)) + (X1 * X4))))).-step(add(rule(430, (X1 + ((X1 + X1) * (X2 * X3))) = (X1 + (X1 * ((X2 + X2) * X3)))))).-step(add(rule(431, (X1 * (X2 + ((X3 + X3) * X4))) = ((X1 * X2) + ((X1 + X1) * (X3 * X4)))))).-step(add(rule(432, (X1 * (X2 + (X1 * -(X1 + X1)))) = ((X1 * X2) + -(X1 + X1))))).-step(add(rule(433, ((X1 + X1) * ((X2 + X3) * X4)) = (X1 * ((X2 + (X2 + (X3 + X3))) * X4))))).-step(hard(((X1 + X1) * ((X2 + X3) * X4)) = (X1 * ((X3 + X2) * (X4 + X4))))).-step(add(rule(434, (X1 * ((X2 + X2) * (X3 + X4))) = (X1 * (X2 * (X3 + (X4 + (X3 + X4)))))))).-step(add(rule(435, (X1 * ((X2 + X2) * (X3 + X4))) = (X1 * (X2 * (X3 + (X3 + (X4 + X4)))))))).-step(hard((X1 * ((X2 + X2) * (X3 + X4))) = (X1 * ((X2 + X2) * (X4 + X3))))).-step(add(rule(436, (X1 * ((X2 + X3) * (X4 + X4))) = (X1 * ((X2 + (X3 + (X2 + X3))) * X4))))).-step(add(rule(437, (X1 * ((X2 + X3) * (X4 + X4))) = (X1 * ((X2 + (X2 + (X3 + X3))) * X4))))).-step(interreduce).-step(delete(rule(194, (X1 + (X1 + (X1 * (X2 + X2)))) = ((X1 + X1) * ((X1 * X1) + X2))))).-step(delete(rule(207, ((X1 + (X2 + (X1 * X1))) * (X1 * X1)) = ((X1 + ((X1 + X2) * X1)) * X1)))).-step(delete(rule(240, ((X1 + X1) * ((X2 + (X1 * X1)) * X3)) = ((X1 + X1) * (X3 + (X2 * X3)))))).-step(delete(rule(241, ((X2 + ((X1 * X1) + X2)) * X1) = (X1 + (X2 * (X1 + X1)))))).-step(delete(rule(245, ((X1 + (X1 * (X2 * -X2))) * (X2 + X2)) = 0))).-step(delete(rule(278, (X1 * (X2 + (X2 + X2))) = ((X1 + (X1 + X1)) * -X2)))).-step(delete(rule(279, ((X1 + X1) * (X2 + (X2 + X2))) = 0))).-step(delete(rule(281, ((X1 + (X1 + X1)) * (X2 + X2)) = 0))).-step(delete(rule(282, ((X1 + (X1 + X1)) * -(X2 + X2)) = 0))).-step(delete(rule(290, ((X1 + (X1 * (X2 * (X2 + X2)))) * (X2 + X2)) = 0))).-step(delete(rule(312, ((X1 + X1) * ((X2 + X2) * X3)) = (X1 * (X2 * -(X3 + X3)))))).-step(delete(rule(334, ((X1 + X1) * (X2 + (X1 * ((X1 + X1) * X2)))) = 0))).-step(delete(rule(352, (X1 * -(X2 + X2)) = (X1 * ((X1 + X1) * ((X1 + X1) * X2)))))).-step(delete(rule(353, (X1 * ((X1 + X1) * ((X1 + X1) * X2))) = ((X1 + X1) * -X2)))).-step(delete(rule(363, ((X1 + ((X1 * X1) + X2)) * (X1 * X1)) = ((X1 + ((X1 + X2) * X1)) * X1)))).-step(delete(rule(367, ((X1 + (X1 + (X1 + X2))) * (X3 + X3)) = (X2 * (X3 + X3))))).-step(delete(rule(373, ((X1 + X1) * ((X2 + X2) * -X3)) = (X1 * ((X2 + X2) * X3))))).-step(delete(rule(374, ((X1 + X1) * (-(X2 + X2) + X3)) = ((X1 + X1) * (X2 + X3))))).-step(delete(rule(378, ((X1 + (X1 + X1)) * (X2 + (X3 + (X2 + X3)))) = 0))).-step(delete(rule(386, ((X2 * -X3) + ((X2 + (X2 + (X1 * X2))) * X3)) = ((X2 + (X1 * X2)) * X3)))).-step(delete(rule(397, ((X1 + X1) * ((X1 + X1) * X2)) = (X1 * ((X1 + X1) * -X2))))).-step(delete(rule(401, ((X1 + (X2 + (X1 + X2))) * ((X1 + X2) * (X1 + X2))) = (X1 + (X2 + (X1 + X2)))))).-step(add(rule(438, ((X1 + X2) * ((X1 + X2) * (X1 + (X1 + (X2 + X2))))) = (X1 + (X2 + (X1 + X2)))))).-step(delete(rule(404, ((X1 + (X1 * (X2 * -X2))) * (X3 * X2)) = 0))).-step(delete(rule(405, (X1 * (X3 * (X3 * (X2 * X3)))) = (X1 * (X2 * X3))))).-step(delete(rule(413, ((X1 + X1) * (X2 + (X2 + X3))) = ((X1 + X1) * (X3 + -X2))))).-step(delete(rule(423, ((X1 + X2) * ((X3 + X3) * X4)) = ((X1 + (X2 + (X1 + X2))) * (X3 * X4))))).-step(delete(rule(428, ((X1 + X1) * ((X2 + X3) * X4)) = (X1 * ((X2 + (X3 + (X2 + X3))) * X4))))).-step(delete(rule(434, (X1 * ((X2 + X2) * (X3 + X4))) = (X1 * (X2 * (X3 + (X4 + (X3 + X4)))))))).-step(delete(rule(436, (X1 * ((X2 + X3) * (X4 + X4))) = (X1 * ((X2 + (X3 + (X2 + X3))) * X4))))).-step(hard((X1 * ((X2 + X3) * (X4 + X4))) = (X1 * ((X3 + X2) * (X4 + X4))))).-step(add(rule(439, ((X1 * X2) + (X3 * -(X2 + X2))) = ((X1 + -(X3 + X3)) * X2)))).-step(add(rule(440, ((X1 + (X2 + X2)) * X3) = ((X1 * X3) + (X2 * (X3 + X3)))))).-step(hard((((X1 + X1) * X2) + (X1 * -(X2 + X2))) = 0)).-step(add(rule(441, ((X1 + X2) * (X3 + (X4 * X3))) = ((X1 + (X2 + ((X1 + X2) * X4))) * X3)))).-step(add(rule(442, ((X1 + ((X1 * X2) + X3)) * X4) = ((X1 * (X4 + (X2 * X4))) + (X3 * X4))))).-step(add(rule(443, ((X1 + (X2 + (X2 * X3))) * X4) = ((X1 * X4) + (X2 * (X4 + (X3 * X4))))))).-step(add(rule(444, ((X1 + X1) * (X2 + (X3 * X2))) = ((X1 + (X1 + (X1 * (X3 + X3)))) * X2)))).-step(add(rule(445, (X1 * (X2 + ((X3 + (X1 * X1)) * X2))) = ((X1 + (X1 + (X1 * X3))) * X2)))).-step(add(rule(446, ((X1 + (X1 * X2)) * (X3 + X4)) = (X1 * (X3 + (X4 + (X2 * (X3 + X4)))))))).-step(add(rule(447, (X1 * (X2 + ((X3 * X2) + X4))) = (((X1 + (X1 * X3)) * X2) + (X1 * X4))))).-step(add(rule(448, (X1 * (-X2 + (X3 * X2))) = ((-X1 + (X1 * X3)) * X2)))).-step(add(rule(449, (X1 + (X1 * (X2 + (X3 * X2)))) = (X1 + ((X1 + (X1 * X3)) * X2))))).-step(add(rule(450, (X1 * ((X2 * X3) + ((X2 * -X3) + X4))) = (X1 * X4)))).-step(add(rule(451, (X1 * (X2 * (X3 * (X1 * X1)))) = (X1 * (X2 * X3))))).-step(add(rule(452, (X1 * (X2 * (X1 * X1))) = (X1 * X2)))).-step(add(rule(453, (X1 * (X2 * (X1 * -X1))) = (X1 * -X2)))).-step(add(rule(454, (X1 * (X2 + (X3 * (X1 * X1)))) = (X1 * (X2 + X3))))).-step(add(rule(455, (X1 * (X2 * (X1 * (X1 + X1)))) = ((X1 + X1) * X2)))).-step(add(rule(456, (X1 * ((X1 + (X2 * X1)) * X1)) = (X1 + (X1 * X2))))).-step(add(rule(457, (X1 * (X2 * (X1 * X2))) = (X1 * (X2 * (X2 * X1)))))).-step(add(rule(458, ((X1 + (X2 * X1)) * X1) = (X1 * (X1 + (X1 * X2)))))).-step(add(rule(459, (X1 * (X2 + (X3 + (X4 * X3)))) = ((X1 * X2) + ((X1 + (X1 * X4)) * X3))))).-step(add(rule(460, (X1 * (X2 + (X3 + X3))) = ((X1 * X2) + ((X1 + X1) * X3))))).-step(add(rule(461, (X1 * ((X1 * X1) + (X2 + X2))) = (X1 + ((X1 + X1) * X2))))).-step(add(rule(462, ((X1 + (X2 + X1)) * (X3 + X3)) = ((X2 + -X1) * (X3 + X3))))).-step(add(rule(463, ((X2 + (X1 + X1)) * (X3 + X3)) = ((X2 + -X1) * (X3 + X3))))).-step(add(rule(464, ((X1 + X1) * (X3 + (X2 * X3))) = (X1 * (X3 + (X3 + ((X2 + X2) * X3))))))).-step(add(rule(465, (X1 * -(X2 + (X1 * (X1 * X3)))) = (X1 * -(X2 + X3))))).-step(add(rule(466, ((X3 * X5) + (X1 + (X2 + (X3 * X4)))) = (X1 + (X2 + (X3 * (X4 + X5))))))).-step(add(rule(467, (X1 + (X2 * (X3 + (X4 + X4)))) = (((X2 + X2) * X4) + (X1 + (X2 * X3)))))).-step(add(rule(468, (X1 + (X2 * (X3 + (X3 + X3)))) = (X1 + ((X2 + (X2 + X2)) * X3))))).-step(add(rule(469, (X1 + (X2 * (X3 + (X3 + X4)))) = ((X2 * X4) + (X1 + ((X2 + X2) * X3)))))).-step(add(rule(470, (X1 + (X2 + (X2 * (X3 + X3)))) = (X2 + (X1 + ((X2 + X2) * X3)))))).-step(hard((X1 * (X2 + (X3 + (X3 + X4)))) = (X1 * (X4 + (X3 + (X3 + X2)))))).-step(add(rule(471, ((X2 * X3) + ((X1 + X2) * (X1 * X1))) = (X1 + (X2 * ((X1 * X1) + X3)))))).-step(add(rule(472, ((X4 * X5) + (X1 + (X2 + (X3 * X5)))) = (X1 + (X2 + ((X3 + X4) * X5)))))).-step(add(rule(473, (X1 + ((X2 + (X3 + X3)) * X4)) = ((X3 * (X4 + X4)) + (X1 + (X2 * X4)))))).-step(add(rule(474, ((X1 + X1) * (X2 + (X3 + X2))) = ((X1 + X1) * (X3 + -X2))))).-step(add(rule(475, (X1 + ((X2 + (X2 + X3)) * X4)) = ((X3 * X4) + (X1 + (X2 * (X4 + X4))))))).-step(hard(((X1 + (X3 + (X3 + X4))) * X2) = ((X4 + (X3 + (X3 + X1))) * X2))).-step(add(rule(476, ((X1 + (X1 + X2)) * (X3 * X4)) = (((X1 * (X3 + X3)) + (X2 * X3)) * X4)))).-step(add(rule(477, (X1 * ((X2 * (X3 + X3)) + (X4 * X3))) = (X1 * ((X2 + (X2 + X4)) * X3))))).-step(add(rule(478, ((X1 * (X2 + X2)) + ((X3 + X4) * X2)) = ((X1 + (X3 + (X1 + X4))) * X2)))).-step(hard(((X1 + (X2 + (X1 + X3))) * X4) = ((X1 + (X1 + (X2 + X3))) * X4))).-step(add(rule(479, ((X1 * (X2 + X2)) + ((X3 * X2) + X4)) = (((X1 + (X1 + X3)) * X2) + X4)))).-step(hard(((X1 + (X1 + (X2 + X4))) * X3) = ((X2 + (X4 + (X1 + X1))) * X3))).-step(add(rule(480, (((X1 * X2) + ((X1 * X2) + X3)) * X4) = ((X1 * (X2 * (X4 + X4))) + (X3 * X4))))).-step(add(rule(481, (((X1 * X2) + ((X1 * X2) + X3)) * X4) = (((X1 * (X2 + X2)) + X3) * X4)))).-step(add(rule(482, ((X1 * (X2 + X2)) + (X3 + (X4 * X2))) = (X3 + ((X1 + (X1 + X4)) * X2))))).-step(hard((X1 + ((X2 + (X2 + X3)) * X4)) = (X1 + ((X3 + (X2 + X2)) * X4)))).-step(hard(((X1 + (X3 + (X3 + X4))) * X2) = ((X3 + (X3 + (X1 + X4))) * X2))).-step(add(rule(483, ((X1 * (X2 + X2)) + ((X3 + X4) * X2)) = ((X4 + (X1 + (X1 + X3))) * X2)))).-step(add(rule(484, ((-? + (X2 + (X2 + ?))) * X3) = (X2 * (X3 + X3))))).-step(add(rule(485, ((-X1 + (X2 + (X2 + X1))) * X3) = ((-? + (X2 + (X2 + ?))) * X3)))).-step(hard(((X1 + (X2 + (X2 + X3))) * X4) = ((X2 + (X2 + (X3 + X1))) * X4))).-step(hard(((X1 + (X2 + (X2 + X3))) * X4) = ((X2 + (X3 + (X2 + X1))) * X4))).-step(add(rule(486, (X1 * (((X2 + X2) * X3) + (X2 * X4))) = (X1 * (X2 * (X3 + (X3 + X4))))))).-step(add(rule(487, (X1 * ((X2 + (X2 + X3)) * X4)) = ((((X1 + X1) * X2) + (X1 * X3)) * X4)))).-step(add(rule(488, ((X1 + (X1 + X1)) * (X2 * X3)) = (X1 * (X2 * (X3 + (X3 + X3))))))).-step(add(rule(489, (((X1 + X1) * X2) + (X1 * (X3 + X4))) = (X1 * (X2 + (X3 + (X2 + X4))))))).-step(hard((X1 * (X2 + (X3 + (X2 + X4)))) = (X1 * (X2 + (X2 + (X3 + X4)))))).-step(add(rule(490, (((X1 + X1) * X2) + ((X1 * X3) + X4)) = ((X1 * (X2 + (X2 + X3))) + X4)))).-step(hard((X1 * (X2 + (X2 + (X3 + X4)))) = (X1 * (X3 + (X4 + (X2 + X2)))))).-step(add(rule(491, ((X1 * (X2 + X2)) + ((X1 * -(X2 + X2)) + X3)) = X3))).-step(add(rule(492, (((X1 + X1) * X2) + (X3 + (X1 * X4))) = (X3 + (X1 * (X2 + (X2 + X4))))))).-step(hard((X1 + (X2 * (X3 + (X3 + X4)))) = (X1 + (X2 * (X4 + (X3 + X3)))))).-step(hard((X1 * (X2 + (X3 + (X3 + X4)))) = (X1 * (X3 + (X3 + (X2 + X4)))))).-step(add(rule(493, (X1 * (X2 + (X2 + ((X3 + X3) * X4)))) = ((X1 + X1) * (X2 + (X3 * X4)))))).-step(add(rule(494, (X1 * (X2 + X2)) = ((X1 + X1) * (X2 + (? + (? + ?))))))).-step(add(rule(495, ((X1 + X1) * (X2 + (X3 + (X3 + X3)))) = ((X1 + X1) * (X2 + (? + (? + ?))))))).-step(add(rule(496, ((X1 + X1) * (X2 + -X3)) = (X1 * (X2 + (X2 + -(X3 + X3))))))).-step(add(rule(497, (X1 * (X1 * (X2 + (X2 + (X1 * X3))))) = (X1 * (((X1 + X1) * X2) + X3))))).-step(add(rule(498, (((X1 + X1) * X2) + (X1 * (X3 + X4))) = (X1 * (X4 + (X2 + (X2 + X3))))))).-step(add(rule(499, (X1 * (-? + (X3 + (X3 + ?)))) = ((X1 + X1) * X3)))).-step(add(rule(500, (X1 * (-X2 + (X3 + (X3 + X2)))) = (X1 * (-? + (X3 + (X3 + ?))))))).-step(hard((X1 * (X2 + (X3 + (X3 + X4)))) = (X1 * (X3 + (X3 + (X4 + X2)))))).-step(hard((X1 * (X2 + (X3 + (X3 + X4)))) = (X1 * (X3 + (X4 + (X3 + X2)))))).-step(add(rule(501, (X1 * (X3 + (X4 + ((X1 * X1) + X2)))) = (X1 + (X1 * (X2 + (X3 + X4))))))).-step(add(rule(502, (X1 * ((X2 + ((X1 * X1) + X3)) * X4)) = ((X1 + (X1 * (X3 + X2))) * X4)))).-step(add(rule(503, (X1 * (X2 + (X3 + (X4 + (X1 * X1))))) = (X1 + (X1 * (X2 + (X3 + X4))))))).-step(add(rule(504, (X1 * ((X2 + (X3 + (X1 * X1))) * X4)) = ((X1 + (X1 * (X2 + X3))) * X4)))).-step(hard(((X1 + (X1 * (X2 + X3))) * X4) = ((X1 + (X1 * (X3 + X2))) * X4))).-step(add(rule(505, ((X1 + (X1 * X2)) * ((X2 + (X1 * X1)) * (X2 + (X1 * X1)))) = (X1 + (X1 * X2))))).-step(interreduce).-step(delete(rule(162, (((? * X2) + ((? * X2) + ((? + X3) * -(X2 + X2)))) * X4) = (X3 * (X2 * -(X4 + X4)))))).-step(delete(rule(163, (((X1 * X2) + ((X1 * X2) + ((X3 + X1) * -(X2 + X2)))) * X4) = (((? * X2) + ((? * X2) + ((? + X3) * -(X2 + X2)))) * X4)))).-step(delete(rule(249, (X1 * (-X2 + (X2 * (X1 * X1)))) = 0))).-step(delete(rule(287, (((X1 + X1) * X2) + (((X1 + X1) * X2) + (((X1 + X1) * X2) + X3))) = X3))).-step(delete(rule(319, (X1 * (X2 + (X2 * (X1 * X1)))) = ((X1 + X1) * X2)))).-step(delete(rule(339, (X1 * -(X2 + (X1 * (X1 * -X2)))) = 0))).-step(delete(rule(364, ((X2 + (X1 + (X1 * X1))) * (X1 * X1)) = ((X1 + ((X1 + X2) * X1)) * X1)))).-step(add(rule(506, ((X2 + (X1 + (X1 * X1))) * (X1 * X1)) = (X1 * (X1 + (X1 * (X1 + X2))))))).-step(delete(rule(368, ((X1 + ((X2 * X2) + X3)) * (X2 * X2)) = ((X2 + ((X1 + X3) * X2)) * X2)))).-step(add(rule(507, ((X1 + ((X2 * X2) + X3)) * (X2 * X2)) = (X2 * (X2 + (X2 * (X1 + X3))))))).-step(delete(rule(408, ((X1 + X1) * (X3 + -X2)) = (X1 * (X3 + (-(X2 + X2) + X3)))))).-step(delete(rule(416, ((X2 + (X2 + X1)) * (X3 + X3)) = ((X1 + -X2) * (X3 + X3))))).-step(delete(rule(456, (X1 * ((X1 + (X2 * X1)) * X1)) = (X1 + (X1 * X2))))).-step(delete(rule(464, ((X1 + X1) * (X3 + (X2 * X3))) = (X1 * (X3 + (X3 + ((X2 + X2) * X3))))))).-step(delete(rule(467, (X1 + (X2 * (X3 + (X4 + X4)))) = (((X2 + X2) * X4) + (X1 + (X2 * X3)))))).-step(delete(rule(473, (X1 + ((X2 + (X3 + X3)) * X4)) = ((X3 * (X4 + X4)) + (X1 + (X2 * X4)))))).-step(delete(rule(480, (((X1 * X2) + ((X1 * X2) + X3)) * X4) = ((X1 * (X2 * (X4 + X4))) + (X3 * X4))))).-step(delete(rule(484, ((-? + (X2 + (X2 + ?))) * X3) = (X2 * (X3 + X3))))).-step(add(rule(508, ((? + (-? + (X2 + X2))) * X3) = (X2 * (X3 + X3))))).-step(delete(rule(485, ((-X1 + (X2 + (X2 + X1))) * X3) = ((-? + (X2 + (X2 + ?))) * X3)))).-step(add(rule(509, ((-X1 + (X2 + (X2 + X1))) * X3) = ((? + (-? + (X2 + X2))) * X3)))).-step(delete(rule(494, (X1 * (X2 + X2)) = ((X1 + X1) * (X2 + (? + (? + ?))))))).-step(add(rule(510, (X1 * (X2 + X2)) = ((X1 + X1) * (? + (? + (? + X2))))))).-step(delete(rule(495, ((X1 + X1) * (X2 + (X3 + (X3 + X3)))) = ((X1 + X1) * (X2 + (? + (? + ?))))))).-step(add(rule(511, ((X1 + X1) * (X2 + (X3 + (X3 + X3)))) = ((X1 + X1) * (? + (? + (? + X2))))))).-step(delete(rule(499, (X1 * (-? + (X3 + (X3 + ?)))) = ((X1 + X1) * X3)))).-step(add(rule(512, (X1 * (? + (-? + (X3 + X3)))) = ((X1 + X1) * X3)))).-step(delete(rule(500, (X1 * (-X2 + (X3 + (X3 + X2)))) = (X1 * (-? + (X3 + (X3 + ?))))))).-step(add(rule(513, (X1 * (-X2 + (X3 + (X3 + X2)))) = (X1 * (? + (-? + (X3 + X3))))))).-step(delete(rule(501, (X1 * (X3 + (X4 + ((X1 * X1) + X2)))) = (X1 + (X1 * (X2 + (X3 + X4))))))).-step(add(rule(514, ((X1 + (X3 * -X1)) * X1) = (X1 * (X1 + (X1 * -X3)))))).-step(add(rule(515, (X1 * (X1 * -X2)) = (X2 * (X1 * -X1))))).-step(add(rule(516, (X1 * (X2 * X2)) = (X2 * (X2 * X1))))).-step(add(rule(517, (X1 * (X1 * X2)) = (X1 * (X2 * X1))))).-step(add(rule(518, (X1 * X2) = (X2 * X1)))).--lemma((X1 + 0) = X1).-lemma((X1 + (-X1 + X2)) = X2).-lemma(-(-X1) = X1).-lemma((X1 + (X2 + X3)) = (X2 + (X1 + X3))).-lemma((X2 + (X1 + -X2)) = X1).-lemma((X1 * (X1 * (X1 * X2))) = (X1 * X2)).-lemma((X1 + (X2 + -(X1 + X2))) = 0).-lemma((X1 * ((X1 * X1) + X2)) = (X1 + (X1 * X2))).-lemma((X1 * 0) = 0).-lemma((X1 * (X2 + (X1 * X1))) = (X1 + (X1 * X2))).-lemma((X2 + -(X1 + X2)) = -X1).-lemma((X1 + (X2 * (X1 * X1))) = ((X1 + X2) * (X1 * X1))).-lemma((X2 + -(X2 + X1)) = -X1).-lemma(-(X1 + -X2) = (X2 + -X1)).-lemma((X1 + (X1 * (X2 * X1))) = (X1 * ((X1 + X2) * X1))).-lemma((0 * X1) = 0).-lemma(((X1 * (X2 * X4)) + (X3 * X4)) = (((X1 * X2) + X3) * X4)).-lemma((X1 * (X3 + (X2 * X3))) = ((X1 + (X1 * X2)) * X3)).-lemma(((X1 + (X1 * X2)) * X3) = (X1 * (X3 + (X2 * X3)))).-lemma(((X1 * X4) + (X2 * (X3 * X4))) = ((X1 + (X2 * X3)) * X4)).-lemma(-(X1 * X2) = (X1 * -X2)).-lemma((-X1 * X2) = (X1 * -X2)).-lemma((X1 * ((X2 + (X1 * X1)) * X3)) = ((X1 + (X1 * X2)) * X3)).-lemma(((X1 + (X2 * X3)) * (X3 * X3)) = (((X1 * X3) + X2) * X3)).-lemma((((X3 * X2) + X1) * (X2 * X2)) = (((X1 * X2) + X3) * X2)).-lemma(((X1 + -X2) * -X3) = ((X2 + -X1) * X3)).-lemma(((X1 + (X1 * X2)) * (X3 * X4)) = (X1 * ((X3 + (X2 * X3)) * X4))).-lemma(((X1 * X2) + (X3 * (X2 + X4))) = ((X3 * X4) + ((X1 + X3) * X2))).-lemma(((X1 + (X1 * (X2 * -X2))) * (X2 * X3)) = 0).-lemma((X1 * ((X2 + (X1 * (X1 * X3))) * X4)) = (X1 * ((X2 + X3) * X4))).-lemma(((X1 + (X2 * (X3 * X3))) * (X3 * X4)) = ((X1 + X2) * (X3 * X4))).-lemma((X1 * (X1 * (X2 * X1))) = (X2 * X1)).-lemma((X1 * (X2 * (X3 * (X1 * X1)))) = (X1 * (X2 * X3))).
− misc/ring_noconn.pl
@@ -1,977 +0,0 @@-:- module(ring_noconn, [step/1, lemma/1]).-:- discontiguous(step/1).-:- discontiguous(lemma/1).-:- style_check(-singleton).-step(add(rule(1, (X1 + X2) = (X2 + X1)))).-step(add(rule(2, ((X1 + X2) + X3) = (X1 + (X2 + X3))))).-step(add(rule(3, (0 + X1) = X1))).-step(add(rule(4, (X1 + -X1) = 0))).-step(add(rule(5, ((X1 * X2) * X3) = (X1 * (X2 * X3))))).-step(add(rule(6, ((X1 * X2) + (X1 * X3)) = (X1 * (X2 + X3))))).-step(add(rule(7, ((X1 * X3) + (X2 * X3)) = ((X1 + X2) * X3)))).-step(add(rule(8, (X1 * (X1 * X1)) = X1))).-step(add(rule(9, -0 = 0))).-step(add(rule(10, (X1 + 0) = X1))).-step(add(rule(11, (X1 + (-X1 + X2)) = X2))).-step(add(rule(12, -(-X1) = X1))).-step(add(rule(13, (X1 + (X2 + X3)) = (X3 + (X1 + X2))))).-step(add(rule(14, (X1 + (X2 + X3)) = (X2 + (X1 + X3))))).-step(hard((X1 * (X2 + X3)) = (X1 * (X3 + X2)))).-step(hard(((X1 + X2) * X3) = ((X2 + X1) * X3))).-step(add(rule(15, ((X1 + X1) * X2) = (X1 * (X2 + X2))))).-step(add(rule(16, (X2 + (X1 + -X2)) = X1))).-step(add(rule(17, (0 * (X1 + X1)) = (0 * X1)))).-step(add(rule(18, (X1 * (X1 * (X1 * X2))) = (X1 * X2)))).-step(hard((X1 + (X2 + X3)) = (X3 + (X2 + X1)))).-step(hard((X1 + (X2 + X3)) = (X1 + (X3 + X2)))).-step(add(rule(19, (X1 + (X2 + -(X1 + X2))) = 0))).-step(add(rule(20, (X1 + -(-X2 + X1)) = X2))).-step(add(rule(21, (X1 * ((X1 * X1) + X2)) = (X1 + (X1 * X2))))).-step(add(rule(22, (X1 + (X1 * 0)) = X1))).-step(add(rule(23, (X1 * 0) = 0))).-step(add(rule(24, (X1 * (X2 + (X1 * X1))) = (X1 + (X1 * X2))))).-step(add(rule(25, (X2 + -(X1 + X2)) = -X1))).-step(add(rule(26, ((X1 + X1) * (X1 * X1)) = (X1 + X1)))).-step(hard(0 = (X1 + (X2 + -(X2 + X1))))).-step(add(rule(27, (X2 + -(X2 + -X1)) = X1))).-step(add(rule(28, -(-X1 + -X2) = (X2 + X1)))).-step(add(rule(29, (X1 * (0 * X2)) = (0 * X2)))).-step(add(rule(30, (X1 + (X2 * (X1 * X1))) = ((X1 + X2) * (X1 * X1))))).-step(add(rule(31, (X2 + -(X2 + X1)) = -X1))).-step(hard((-X1 + (X2 + (X3 + X1))) = (X3 + X2))).-step(add(rule(32, (X3 + (X2 + (-X3 + X1))) = (X1 + X2)))).-step(add(rule(33, (X3 + (X1 + (X2 + -X3))) = (X1 + X2)))).-step(add(rule(34, -(X1 + -X2) = (X2 + -X1)))).-step(add(rule(35, (-X1 + -X2) = -(X2 + X1)))).-step(add(rule(36, -(-X2 + X1) = (-X1 + X2)))).-step(hard(-(X1 + X2) = -(X2 + X1))).-step(add(rule(37, (X1 + (X1 * -(X1 * X1))) = 0))).-step(add(rule(38, (-X1 * -(-X1 * -X1)) = X1))).-step(add(rule(39, (-X1 * (-X1 * X1)) = X1))).-step(add(rule(40, (X1 * -(X1 * X1)) = -X1))).-step(hard((X1 + (X2 + (X3 + X4))) = (X2 + (X3 + (X4 + X1))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X3 + (X1 + (X2 + X4))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X3 + (X2 + (X4 + X1))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X3 + (X4 + (X1 + X2))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X4 + (X3 + (X1 + X2))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X4 + (X2 + (X3 + X1))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X2 + (X4 + (X1 + X3))))).-step(add(rule(41, ((X1 + X1) * (X2 * X3)) = (X1 * ((X2 + X2) * X3))))).-step(add(rule(42, (X1 * (X1 * (X1 + X1))) = (X1 + X1)))).-step(add(rule(43, (X1 * (X2 * (X3 + X3))) = (X1 * ((X2 + X2) * X3))))).-step(add(rule(44, (X1 * (X2 * (X3 + X3))) = ((X1 + X1) * (X2 * X3))))).-step(add(rule(45, (X1 + (X1 * (X1 * X2))) = (X1 * (X1 * (X1 + X2)))))).-step(add(rule(46, (X1 + (X1 * (X2 * X1))) = (X1 * ((X1 + X2) * X1))))).-step(add(rule(47, (X1 + (0 * X1)) = X1))).-step(add(rule(48, (0 * X1) = 0))).-step(hard((X1 * (X1 * (X1 + X2))) = (X1 * (X1 * (X2 + X1))))).-step(hard((X1 * ((X1 + X2) * X1)) = (X1 * ((X2 + X1) * X1)))).-step(add(rule(49, (X2 + (X3 + (-(X2 + X3) + X1))) = X1))).-step(hard((X1 + (X2 + (-(X2 + X1) + X3))) = X3)).-step(add(rule(50, (X1 * (X1 * -X1)) = -X1))).-step(hard((X1 + X2) = (-X3 + (X2 + (X3 + X1))))).-step(hard((X1 + X2) = (-X3 + (X1 + (X2 + X3))))).-step(hard((X1 + X2) = (-X3 + (X2 + (X1 + X3))))).-step(add(rule(51, ((X1 * X2) + ((X1 * X3) + X4)) = ((X1 * (X2 + X3)) + X4)))).-step(hard(((X1 * (X2 + X3)) + X4) = ((X1 * (X3 + X2)) + X4))).-step(add(rule(52, ((X1 * X2) + ((X3 * X2) + X4)) = (((X1 + X3) * X2) + X4)))).-step(hard((((X1 + X2) * X3) + X4) = (((X2 + X1) * X3) + X4))).-step(add(rule(53, (((X1 + X1) * X2) + X3) = ((X1 * (X2 + X2)) + X3)))).-step(add(rule(54, ((X1 * (X2 * X4)) + (X3 * X4)) = (((X1 * X2) + X3) * X4)))).-step(add(rule(55, (((X1 * X1) + X2) * X1) = (X1 + (X2 * X1))))).-step(add(rule(56, (X1 + (-(X1 * X1) * X1)) = 0))).-step(add(rule(57, (-(X1 * X1) * X1) = -X1))).-step(add(rule(58, ((X1 + (X1 * X2)) * X3) = (X1 * (X3 + (X2 * X3)))))).-step(add(rule(59, ((X2 + (X1 * X1)) * X1) = (X1 + (X2 * X1))))).-step(add(rule(60, ((X1 * X4) + (X2 * (X3 * X4))) = ((X1 + (X2 * X3)) * X4)))).-step(add(rule(61, (X1 * (X2 * (X1 * (X2 * (X1 * X2))))) = (X1 * X2)))).-step(add(rule(62, (X3 + (X2 + -(X3 + X1))) = (-X1 + X2)))).-step(add(rule(63, (X3 + (-(X3 + X2) + X1)) = (X1 + -X2)))).-step(add(rule(64, (X1 * ((X1 * (X1 * X2)) + X3)) = (X1 * (X2 + X3))))).-step(add(rule(65, (X1 * (X2 + (X1 * (X1 * X3)))) = (X1 * (X2 + X3))))).-step(add(rule(66, (X1 * (X2 + X2)) = (X1 * (X1 * ((X1 + X1) * X2)))))).-step(add(rule(67, (X1 * (X1 * (X1 + (X1 * X2)))) = (X1 + (X1 * X2))))).-step(add(rule(68, -((X1 + X1) * X2) = -(X1 * (X2 + X2))))).-step(hard((X1 + -(X3 + X2)) = (-(X2 + X3) + X1))).-step(hard(-(X3 + (X1 + X2)) = -(X1 + (X3 + X2)))).-step(add(rule(69, (X1 + (X1 * (-(X1 * X1) + X2))) = (X1 * X2)))).-step(hard((X1 + (X2 + (X3 + X4))) = (X2 + (X4 + (X3 + X1))))).-step(add(rule(70, (-(X1 * X3) + (X1 * (X2 + X3))) = (X1 * X2)))).-step(add(rule(71, -(X1 * -X2) = (X1 * X2)))).-step(add(rule(72, -(X1 * X2) = (X1 * -X2)))).-step(add(rule(73, (X1 * (X2 * (-X2 * -X2))) = (X1 * X2)))).-step(add(rule(74, (-X1 * (X1 * -X1)) = X1))).-step(add(rule(75, (X1 * (-X1 * -X1)) = X1))).-step(add(rule(76, (-X1 * (X1 * X1)) = -X1))).-step(add(rule(77, (X1 * (-X1 * X1)) = -X1))).-step(add(rule(78, ((X2 * -X3) + ((X1 + X2) * X3)) = (X1 * X3)))).-step(add(rule(79, (-X1 * -X2) = (X1 * X2)))).-step(add(rule(80, (-X1 * X2) = (X1 * -X2)))).-step(add(rule(81, ((X1 * (X2 + X2)) + X3) = (X3 + ((X1 + X1) * X2))))).-step(add(rule(82, (X1 * -(X2 + X2)) = ((X1 + X1) * -X2)))).-step(add(rule(83, (X1 + ((X2 + X2) * X3)) = (X1 + (X2 * (X3 + X3)))))).-step(add(rule(84, (((X1 + X1) * X2) + X3) = (X3 + (X1 * (X2 + X2)))))).-step(add(rule(85, (X2 + (X3 + (X1 + -(X2 + X3)))) = X1))).-step(add(rule(86, ((X1 + (X1 * X1)) * (X1 * X1)) = (X1 + (X1 * X1))))).-step(add(rule(87, ((X1 * X2) + (X3 + (X1 * X4))) = (X3 + (X1 * (X4 + X2)))))).-step(hard((X1 + (X2 * (X3 + X4))) = ((X2 * (X4 + X3)) + X1))).-step(hard((X1 * (X2 + (X3 + X4))) = (X1 * (X4 + (X2 + X3))))).-step(hard((X1 + (X2 * (X3 + X4))) = (X1 + (X2 * (X4 + X3))))).-step(add(rule(88, ((X1 * X2) + (X3 + (X4 * X2))) = (X3 + ((X4 + X1) * X2))))).-step(hard((X1 + ((X2 + X3) * X4)) = (((X3 + X2) * X4) + X1))).-step(hard(((X1 + (X3 + X4)) * X2) = ((X4 + (X1 + X3)) * X2))).-step(hard((X1 + ((X2 + X3) * X4)) = (X1 + ((X3 + X2) * X4)))).-step(add(rule(89, ((X1 + X2) * (X3 + X3)) = ((X1 + (X2 + (X1 + X2))) * X3)))).-step(add(rule(90, ((X1 + (X1 + X2)) * X3) = ((X1 * (X3 + X3)) + (X2 * X3))))).-step(add(rule(91, ((X1 + (X1 + X1)) * X2) = (X1 * (X2 + (X2 + X2)))))).-step(add(rule(92, ((X1 + (X2 + X2)) * X3) = ((X1 * X3) + (X2 * (X3 + X3)))))).-step(add(rule(93, ((X1 + X2) * (X3 + X3)) = ((X2 + (X1 + (X2 + X1))) * X3)))).-step(add(rule(94, ((X1 + X2) * (X3 + X3)) = ((X1 + (X1 + (X2 + X2))) * X3)))).-step(add(rule(95, ((X1 + X1) * (X2 + X3)) = (X1 * (X2 + (X3 + (X2 + X3))))))).-step(add(rule(96, (X1 * (X2 + (X2 + X3))) = (((X1 + X1) * X2) + (X1 * X3))))).-step(add(rule(97, (X1 * (X2 + (X3 + X3))) = ((X1 * X2) + ((X1 + X1) * X3))))).-step(add(rule(98, ((X1 + X1) * (X2 + X3)) = (X1 * (X3 + (X2 + (X3 + X2))))))).-step(add(rule(99, ((X1 + X1) * (X2 + X3)) = (X1 * (X2 + (X2 + (X3 + X3))))))).-step(add(rule(100, (X1 * (((X1 * X1) + X2) * X3)) = ((X1 + (X1 * X2)) * X3)))).-step(add(rule(101, (X1 * (X3 + ((X1 * X1) + X2))) = (X1 + (X1 * (X2 + X3)))))).-step(add(rule(102, (X1 * (X2 + (X3 + (X1 * X1)))) = (X1 + (X1 * (X2 + X3)))))).-step(add(rule(103, (X1 * ((X2 + (X1 * X1)) * X3)) = ((X1 + (X1 * X2)) * X3)))).-step(add(rule(104, (X1 + (-(X2 + X1) + X3)) = (-X2 + X3)))).-step(add(rule(105, (X3 + -(X1 + (X2 + X3))) = -(X1 + X2)))).-step(add(rule(106, (X1 + (X2 + -(X3 + X1))) = (X2 + -X3)))).-step(add(rule(107, (((X1 * X1) + X2) * (X1 * X3)) = ((X1 + (X2 * X1)) * X3)))).-step(add(rule(108, ((X1 + (X2 * X3)) * (X3 * X3)) = (((X1 * X3) + X2) * X3)))).-step(add(rule(109, ((X1 + (X2 * X2)) * (X2 * X3)) = ((X2 + (X1 * X2)) * X3)))).-step(add(rule(110, (X1 * (X1 * -(X1 + X1))) = -(X1 + X1)))).-step(add(rule(111, (X1 * (X1 * ((X1 + X1) * X2))) = ((X1 + X1) * X2)))).-step(add(rule(112, ((X1 + (X1 + X1)) * (X1 * X1)) = (X1 + (X1 + X1))))).-step(add(rule(113, (-X1 + (X2 + -X3)) = (X2 + -(X1 + X3))))).-step(hard((X1 * -(X2 + X3)) = (X1 * -(X3 + X2)))).-step(add(rule(114, ((X1 + (X1 * (X2 * X2))) * X2) = (X1 * (X2 + X2))))).-step(hard(-(X2 + (X3 + X1)) = -(X1 + (X2 + X3)))).-step(hard(-(X3 + (X1 + X2)) = -(X3 + (X2 + X1)))).-step(add(rule(115, (((X1 * (X2 * X2)) + X3) * X2) = ((X1 + X3) * X2)))).-step(hard((X1 + -(X2 + X3)) = (X1 + -(X3 + X2)))).-step(add(rule(116, (X1 + (X1 * (X2 + (X1 * -X1)))) = (X1 * X2)))).-step(add(rule(117, ((X1 * -X3) + ((X1 + X2) * X3)) = (X2 * X3)))).-step(add(rule(118, (X1 + (((X1 * -X1) + X2) * X1)) = (X2 * X1)))).-step(add(rule(119, (X1 + ((X2 + (X1 * -X1)) * X1)) = (X2 * X1)))).-step(add(rule(120, (X1 + ((-X2 + (X1 * X1)) * -X1)) = (X2 * X1)))).-step(interreduce).-step(delete(rule(13, (X1 + (X2 + X3)) = (X3 + (X1 + X2))))).-step(delete(rule(17, (0 * (X1 + X1)) = (0 * X1)))).-step(delete(rule(19, (X1 + (X2 + -(X1 + X2))) = 0))).-step(delete(rule(20, (X1 + -(-X2 + X1)) = X2))).-step(delete(rule(22, (X1 + (X1 * 0)) = X1))).-step(delete(rule(26, ((X1 + X1) * (X1 * X1)) = (X1 + X1)))).-step(delete(rule(27, (X2 + -(X2 + -X1)) = X1))).-step(delete(rule(28, -(-X1 + -X2) = (X2 + X1)))).-step(delete(rule(29, (X1 * (0 * X2)) = (0 * X2)))).-step(delete(rule(37, (X1 + (X1 * -(X1 * X1))) = 0))).-step(delete(rule(38, (-X1 * -(-X1 * -X1)) = X1))).-step(delete(rule(39, (-X1 * (-X1 * X1)) = X1))).-step(delete(rule(40, (X1 * -(X1 * X1)) = -X1))).-step(delete(rule(47, (X1 + (0 * X1)) = X1))).-step(delete(rule(49, (X2 + (X3 + (-(X2 + X3) + X1))) = X1))).-step(delete(rule(56, (X1 + (-(X1 * X1) * X1)) = 0))).-step(delete(rule(57, (-(X1 * X1) * X1) = -X1))).-step(delete(rule(66, (X1 * (X2 + X2)) = (X1 * (X1 * ((X1 + X1) * X2)))))).-step(delete(rule(68, -((X1 + X1) * X2) = -(X1 * (X2 + X2))))).-step(delete(rule(69, (X1 + (X1 * (-(X1 * X1) + X2))) = (X1 * X2)))).-step(add(rule(121, (X1 + (X1 * ((X1 * -X1) + X2))) = (X1 * X2)))).-step(delete(rule(70, (-(X1 * X3) + (X1 * (X2 + X3))) = (X1 * X2)))).-step(delete(rule(71, -(X1 * -X2) = (X1 * X2)))).-step(delete(rule(73, (X1 * (X2 * (-X2 * -X2))) = (X1 * X2)))).-step(delete(rule(74, (-X1 * (X1 * -X1)) = X1))).-step(delete(rule(75, (X1 * (-X1 * -X1)) = X1))).-step(delete(rule(76, (-X1 * (X1 * X1)) = -X1))).-step(delete(rule(77, (X1 * (-X1 * X1)) = -X1))).-step(delete(rule(79, (-X1 * -X2) = (X1 * X2)))).-step(delete(rule(85, (X2 + (X3 + (X1 + -(X2 + X3)))) = X1))).-step(delete(rule(86, ((X1 + (X1 * X1)) * (X1 * X1)) = (X1 + (X1 * X1))))).-step(delete(rule(89, ((X1 + X2) * (X3 + X3)) = ((X1 + (X2 + (X1 + X2))) * X3)))).-step(delete(rule(93, ((X1 + X2) * (X3 + X3)) = ((X2 + (X1 + (X2 + X1))) * X3)))).-step(delete(rule(95, ((X1 + X1) * (X2 + X3)) = (X1 * (X2 + (X3 + (X2 + X3))))))).-step(delete(rule(98, ((X1 + X1) * (X2 + X3)) = (X1 * (X3 + (X2 + (X3 + X2))))))).-step(add(rule(122, ((X1 + (X1 * (X2 * -X2))) * X2) = 0))).-step(add(rule(123, ((X3 * X2) + ((X1 + X3) * -X2)) = (X1 * -X2)))).-step(add(rule(124, ((X1 + (X1 + (X1 + X1))) * X2) = (X1 * (X2 + (X2 + (X2 + X2))))))).-step(add(rule(125, ((X1 * X3) + (X2 * (X1 * (X1 * X3)))) = ((X1 + X2) * (X1 * (X1 * X3)))))).-step(add(rule(126, (X1 * ((X1 + X1) * ((X1 + X1) * (X2 + X2)))) = ((X1 + X1) * X2)))).-step(add(rule(127, (((X1 + X2) * (X1 * X1)) + X3) = (X1 + ((X2 * (X1 * X1)) + X3))))).-step(add(rule(128, (X1 + (X2 * (X3 * (X1 * X1)))) = ((X1 + (X2 * X3)) * (X1 * X1))))).-step(add(rule(129, (X1 + (X2 + (X3 * (X1 * X1)))) = (X2 + ((X1 + X3) * (X1 * X1)))))).-step(add(rule(130, (X1 * (X1 * (X1 + (X1 + X1)))) = (X1 + (X1 + X1))))).-step(add(rule(131, ((X1 + (X2 + X2)) * (X1 * X1)) = (X1 + (X2 * (X1 * (X1 + X1))))))).-step(add(rule(132, ((X1 * (X2 + X3)) + (X4 * X3)) = ((X1 * X2) + ((X1 + X4) * X3))))).-step(add(rule(133, ((X1 * X2) + ((X1 + X3) * -X2)) = (X3 * -X2)))).-step(add(rule(134, (X1 + (X1 * ((X1 * X2) + X3))) = (X1 * ((X1 * (X1 + X2)) + X3))))).-step(add(rule(135, (((X1 + X2) * X3) + (X2 * X4)) = ((X1 * X3) + (X2 * (X3 + X4)))))).-step(add(rule(136, (((X1 + X2) * (X2 * X2)) + X3) = (X2 + ((X1 * (X2 * X2)) + X3))))).-step(add(rule(137, (X1 + (X1 * ((X2 * X1) + X3))) = (X1 * (((X1 + X2) * X1) + X3))))).-step(add(rule(138, (((X1 * X2) + X3) * (X2 * X2)) = ((X1 + (X3 * X2)) * X2)))).-step(add(rule(139, ((X1 + (X2 * (X3 * X3))) * X3) = ((X1 + X2) * X3)))).-step(add(rule(140, (X1 + (X1 * (X2 * (X3 * X1)))) = (X1 * (((X2 * X3) + X1) * X1))))).-step(add(rule(141, ((X1 * -X3) + (X2 * X3)) = ((-X1 + X2) * X3)))).-step(hard(((-X1 + (X2 + X1)) * X3) = (X2 * X3))).-step(hard((X1 * X2) = ((-X3 + (X1 + X3)) * X2))).-step(add(rule(142, (((X1 * -X1) + X2) * -X1) = (X1 + (X2 * -X1))))).-step(add(rule(143, ((X1 + (X2 * -X2)) * -X2) = (X2 + (X1 * -X2))))).-step(add(rule(144, (((X1 * -X1) + X2) * X1) = (-X1 + (X2 * X1))))).-step(add(rule(145, (-X1 + (-X1 + X2)) = (-(X1 + X1) + X2)))).-step(add(rule(146, (X1 * -((X1 * -X1) + X2)) = (X1 + (X1 * -X2))))).-step(add(rule(147, (X1 * ((X1 * -X1) + X2)) = (-X1 + (X1 * X2))))).-step(add(rule(148, (X3 + -(X1 + (X3 + X2))) = -(X1 + X2)))).-step(hard(X1 = (-X3 + (X1 + X3)))).-step(add(rule(149, ((X2 + ((X1 * X1) + X3)) * X1) = (X1 + ((X2 + X3) * X1))))).-step(add(rule(150, (X1 * (X1 * ((X1 * X2) + X3))) = (X1 * (X2 + (X1 * X3)))))).-step(add(rule(151, (X1 * (X1 * (X2 + (X1 * X3)))) = (X1 * ((X1 * X2) + X3))))).-step(hard(((X1 * (X2 + X2)) + (X3 * X2)) = ((X1 + (X3 + X1)) * X2))).-step(add(rule(152, ((X1 + (X1 + X2)) * X3) = ((X2 * X3) + (X1 * (X3 + X3)))))).-step(hard(((X1 * X2) + (X3 * (X2 + X2))) = ((X3 + (X1 + X3)) * X2))).-step(hard(((X1 + (X2 + X2)) * X3) = ((X2 * (X3 + X3)) + (X1 * X3)))).-step(hard(((X1 + (X1 + (X2 + X2))) * X3) = ((X2 + X1) * (X3 + X3)))).-step(hard(((X1 + X2) * (X3 + X3)) = ((X1 + (X2 + (X2 + X1))) * X3))).-step(hard(((X1 + X2) * (X3 + X3)) = ((X1 + (X2 + (X1 + X2))) * X3))).-step(hard((((X1 + X1) * X2) + (X1 * X3)) = (X1 * (X2 + (X3 + X2))))).-step(add(rule(153, (X1 * (X2 + (X2 + X3))) = ((X1 * X3) + ((X1 + X1) * X2))))).-step(hard(((X1 * X2) + ((X1 + X1) * X3)) = (X1 * (X3 + (X2 + X3))))).-step(hard((X1 * (X2 + (X3 + X3))) = (((X1 + X1) * X3) + (X1 * X2)))).-step(hard((X1 * (X2 + (X2 + (X3 + X3)))) = ((X1 + X1) * (X3 + X2)))).-step(hard(((X1 + X1) * (X2 + X3)) = (X1 * (X2 + (X3 + (X3 + X2)))))).-step(hard(((X1 + X1) * (X2 + X3)) = (X1 * (X2 + (X3 + (X2 + X3)))))).-step(add(rule(154, (X1 * ((X1 + X1) * (X1 + (X1 + (X1 + X1))))) = (X1 + X1)))).-step(add(rule(155, (X1 * ((X1 * (X1 + X1)) + X2)) = (X1 + (X1 + (X1 * X2)))))).-step(add(rule(156, (X4 + (X2 + (X3 + (-X4 + X1)))) = (X1 + (X2 + X3))))).-step(hard((X1 + (X2 + X3)) = (X2 + (X3 + X1)))).-step(hard((X1 + (-X2 + (X3 + X2))) = (X1 + X3))).-step(hard((-X1 + (X2 + (X1 + X3))) = (X2 + X3))).-step(hard((-(X1 + X2) + (X3 + X1)) = (X3 + -X2))).-step(hard((X4 + (X5 + (X2 + X3))) = (X4 + (X2 + (X3 + X5))))).-step(hard((-(X1 + X2) + (X3 + X2)) = (-X1 + X3))).-step(add(rule(157, -(X1 + (-X2 + X3)) = (X2 + -(X3 + X1))))).-step(hard(-X1 = (-X2 + (-X1 + X2)))).-step(add(rule(158, (X4 + (X1 + (X2 + (X3 + -X4)))) = (X1 + (X2 + X3))))).-step(add(rule(159, -(X1 + (X2 + -X3)) = (X3 + -(X1 + X2))))).-step(add(rule(160, (-X1 + (-X2 + X3)) = (-(X2 + X1) + X3)))).-step(add(rule(161, -(X3 + (X1 * -X2)) = ((X1 * X2) + -X3)))).-step(add(rule(162, ((X2 * -X3) + -X1) = -(X1 + (X2 * X3))))).-step(add(rule(163, (-X3 + (X1 * -X2)) = -((X1 * X2) + X3)))).-step(add(rule(164, -((X2 * -X3) + X1) = (-X1 + (X2 * X3))))).-step(add(rule(165, ((X1 + -X2) * -X3) = ((X2 + -X1) * X3)))).-step(add(rule(166, ((-X1 + X2) * -X3) = ((-X2 + X1) * X3)))).-step(hard((X1 + (X1 * (-X2 + (X3 + X2)))) = (X1 + (X1 * X3)))).-step(interreduce).-step(delete(rule(67, (X1 * (X1 * (X1 + (X1 * X2)))) = (X1 + (X1 * X2))))).-step(delete(rule(78, ((X2 * -X3) + ((X1 + X2) * X3)) = (X1 * X3)))).-step(delete(rule(114, ((X1 + (X1 * (X2 * X2))) * X2) = (X1 * (X2 + X2))))).-step(delete(rule(117, ((X1 * -X3) + ((X1 + X2) * X3)) = (X2 * X3)))).-step(delete(rule(118, (X1 + (((X1 * -X1) + X2) * X1)) = (X2 * X1)))).-step(delete(rule(120, (X1 + ((-X2 + (X1 * X1)) * -X1)) = (X2 * X1)))).-step(delete(rule(121, (X1 + (X1 * ((X1 * -X1) + X2))) = (X1 * X2)))).-step(delete(rule(145, (-X1 + (-X1 + X2)) = (-(X1 + X1) + X2)))).-step(delete(rule(146, (X1 * -((X1 * -X1) + X2)) = (X1 + (X1 * -X2))))).-step(add(rule(167, ((X1 + X1) * (X1 + (X1 + (X1 + X1)))) = (X1 * (X1 + X1))))).-step(hard((-(X1 + X2) + X3) = (-(X2 + X1) + X3))).-step(add(rule(168, ((X1 * (X2 + X2)) + ((X1 + X1) * -X2)) = 0))).-step(add(rule(169, (((X1 + X1) * X2) + (X1 * -(X2 + X2))) = 0))).-step(add(rule(170, ((X1 * X3) + (X2 * -X3)) = ((-X2 + X1) * X3)))).-step(add(rule(171, ((X1 + (X1 * (X2 * -X2))) * -X2) = 0))).-step(add(rule(172, ((X1 + (X1 * (X2 * -X2))) * (X2 * -X2)) = 0))).-step(hard((X1 + (-X3 + (X2 + X3))) = (X2 + X1))).-step(hard((X1 * X2) = ((-X4 + (X1 + X4)) * X2))).-step(add(rule(173, ((X1 * (X2 + X2)) + ((X1 + X1) * X3)) = ((X1 + X1) * (X2 + X3))))).-step(add(rule(174, (((X1 + X1) * X2) + (X1 * (X3 + X3))) = ((X1 + X1) * (X2 + X3))))).-step(add(rule(175, (X1 + (X1 + ((X1 + X1) * X2))) = ((X1 + X1) * (X2 + (X1 * X1)))))).-step(add(rule(176, (X1 * ((X1 + X1) * (X1 + X1))) = (X1 + (X1 + (X1 + X1)))))).-step(add(rule(177, (((X1 + X1) * X3) + (X2 * (X3 + X3))) = ((X1 + X2) * (X3 + X3))))).-step(add(rule(178, ((X1 * (X3 + X3)) + ((X2 + X2) * X3)) = ((X1 + X2) * (X3 + X3))))).-step(add(rule(179, (X1 + (X1 * -(X2 + (X1 * X1)))) = (X1 * -X2)))).-step(add(rule(180, (X1 + ((X2 + (X1 * X1)) * -X1)) = (X2 * -X1)))).-step(add(rule(181, (X2 + (X3 + (-X1 + X4))) = (X2 + (X4 + (-X1 + X3)))))).-step(hard((X1 + (X2 + (X3 + X4))) = (X1 + (X4 + (X3 + X2))))).-step(add(rule(182, (((X1 + X1) * -X2) + X3) = ((X1 * -(X2 + X2)) + X3)))).-step(add(rule(183, (X1 + ((X2 + X2) * -X3)) = (X1 + (X2 * -(X3 + X3)))))).-step(add(rule(184, (X1 + ((X2 + X2) * -X3)) = ((X2 * -(X3 + X3)) + X1)))).-step(add(rule(185, (X3 * ((X2 + X2) * -X4)) = (X3 * (X2 * -(X4 + X4)))))).-step(add(rule(186, (X1 * (X4 * -(X3 + X3))) = ((X1 + X1) * (X4 * -X3))))).-step(add(rule(187, (X2 + (((X2 * X2) + X1) * -X2)) = (X1 * -X2)))).-step(add(rule(188, ((X1 + (X1 + X1)) * -X2) = (X1 * -(X2 + (X2 + X2)))))).-step(hard((-(X1 + X2) + (X3 + X4)) = (X3 + (X4 + -(X2 + X1))))).-step(add(rule(189, (X1 + (X2 * -(X3 + X3))) = (((X2 + X2) * -X3) + X1)))).-step(add(rule(190, (X1 * (X2 * ((X3 + X3) * X4))) = ((X1 + X1) * (X2 * (X3 * X4)))))).-step(add(rule(191, (X1 * (X2 * ((X3 + X3) * X4))) = (X1 * ((X2 + X2) * (X3 * X4)))))).-step(add(rule(192, ((X1 + X1) * (X2 + (X2 + (X2 + X2)))) = (X1 * (X2 + X2))))).-step(add(rule(193, (X1 * (X2 * ((X3 + X3) * X4))) = (X1 * (X2 * (X3 * (X4 + X4))))))).-step(add(rule(194, (X1 * ((X2 * (X3 + X3)) + X4)) = (X1 * (((X2 + X2) * X3) + X4))))).-step(add(rule(195, (X1 * ((X2 + X2) * (X3 * X4))) = (X1 * (X2 * (X3 * (X4 + X4))))))).-step(add(rule(196, (X1 * (X2 + (X3 * (X4 + X4)))) = (X1 * (X2 + ((X3 + X3) * X4)))))).-step(add(rule(197, ((X1 + X1) * (X2 * (X3 * X4))) = (X1 * (X2 * (X3 * (X4 + X4))))))).-step(interreduce).-step(delete(rule(123, ((X3 * X2) + ((X1 + X3) * -X2)) = (X1 * -X2)))).-step(delete(rule(133, ((X1 * X2) + ((X1 + X3) * -X2)) = (X3 * -X2)))).-step(delete(rule(154, (X1 * ((X1 + X1) * (X1 + (X1 + (X1 + X1))))) = (X1 + X1)))).-step(delete(rule(167, ((X1 + X1) * (X1 + (X1 + (X1 + X1)))) = (X1 * (X1 + X1))))).-step(delete(rule(168, ((X1 * (X2 + X2)) + ((X1 + X1) * -X2)) = 0))).-step(add(rule(198, ((X1 * (X1 * (X1 + X2))) + X3) = (X1 + ((X1 * (X1 * X2)) + X3))))).-step(add(rule(199, (X1 + (X2 + (X1 * (X1 * X3)))) = (X2 + (X1 * (X1 * (X1 + X3))))))).-step(add(rule(200, (X1 * (X1 * (X1 + (X2 + X2)))) = (X1 + (X1 * ((X1 + X1) * X2)))))).-step(add(rule(201, ((X1 * ((X1 + X2) * X1)) + X3) = (X1 + ((X1 * (X2 * X1)) + X3))))).-step(add(rule(202, (X1 + (X2 + (X1 * (X3 * X1)))) = (X2 + (X1 * ((X1 + X3) * X1)))))).-step(add(rule(203, (X1 * ((X1 + (X2 + X2)) * X1)) = (X1 + (X1 * (X2 * (X1 + X1))))))).-step(add(rule(204, ((X2 * -X3) + (((X1 + X2) * X3) + X4)) = ((X1 * X3) + X4)))).-step(hard(((X1 + X3) * X2) = ((-X4 + (X1 + (X4 + X3))) * X2))).-step(hard(((X1 * X2) + X3) = (((-X4 + (X1 + X4)) * X2) + X3))).-step(hard(((-X3 + X1) * X2) = ((-(X3 + X4) + (X1 + X4)) * X2))).-step(add(rule(205, ((X1 * (X2 * (X3 + X3))) + X4) = ((X1 * ((X2 + X2) * X3)) + X4)))).-step(add(rule(206, ((X1 * (X2 * (X3 + X3))) + X4) = (((X1 + X1) * (X2 * X3)) + X4)))).-step(add(rule(207, ((X1 * (X2 + X2)) + (X3 + X4)) = (X3 + (((X1 + X1) * X2) + X4))))).-step(add(rule(208, (((X1 + X1) * X2) + (X3 + X4)) = (X3 + ((X1 * (X2 + X2)) + X4))))).-step(add(rule(209, (X1 + (X1 * ((X2 + X2) * X3))) = (X1 + (X1 * (X2 * (X3 + X3))))))).-step(add(rule(210, (((X1 + X1) * (X2 * X3)) + X4) = ((X1 * ((X2 + X2) * X3)) + X4)))).-step(add(rule(211, ((((X1 + X1) * X2) + X3) * X4) = (((X1 * (X2 + X2)) + X3) * X4)))).-step(add(rule(212, (X1 + ((X1 + (X2 * X1)) * X1)) = ((X1 + ((X1 + X2) * X1)) * X1)))).-step(simplify_queue).-step(interreduce).-step(hard((X1 + X2) = (X2 + (-X4 + (X1 + X4))))).-step(hard((X1 + ((X1 * (X3 + X2)) + X4)) = (X1 + ((X1 * (X2 + X3)) + X4)))).-step(hard((X4 + (X1 * (-X3 + (X2 + X3)))) = ((X1 * X2) + X4))).-step(add(rule(213, (X1 + (X1 * (X1 + (X1 * X2)))) = (X1 * (X1 + (X1 * (X2 + X1))))))).-step(hard((X1 * (X1 + (X1 * (X1 + X2)))) = (X1 * (X1 + (X1 * (X2 + X1)))))).-step(add(rule(214, ((X1 + (X1 * X2)) * (X1 * X1)) = (X1 * ((X1 + (X2 * X1)) * X1))))).-step(add(rule(215, (X1 + (X1 * (X1 + (X2 * X1)))) = (X1 * (X1 + ((X1 + X2) * X1)))))).-step(add(rule(216, (X1 + (((X1 * X2) + X3) * X1)) = (((X1 * (X1 + X2)) + X3) * X1)))).-step(add(rule(217, (X1 + (((X2 * X1) + X3) * X1)) = ((((X1 + X2) * X1) + X3) * X1)))).-step(hard(((-X2 + (X1 + X2)) * (X1 * X1)) = X1)).-step(add(rule(218, ((X1 + (X1 * X2)) * (X3 * X4)) = (X1 * ((X3 + (X2 * X3)) * X4))))).-step(add(rule(219, (X1 * (X2 * (X3 + (X4 * X3)))) = (X1 * ((X2 + (X2 * X4)) * X3))))).-step(add(rule(220, (X1 * (X2 * (X3 + (X2 * X3)))) = ((X1 + (X1 * X2)) * (X2 * X3))))).-step(add(rule(221, (X1 * (X2 + ((X3 + X3) * X2))) = ((X1 + ((X1 + X1) * X3)) * X2)))).-step(add(rule(222, (X1 * (X2 + (X1 * (X3 * X2)))) = (X1 * (X1 * ((X1 + X3) * X2)))))).-step(add(rule(223, (X1 * (X2 + (X3 * (X1 * X2)))) = (X1 * ((X1 + X3) * (X1 * X2)))))).-step(add(rule(224, ((X1 + (X1 * (X2 * X3))) * X4) = (X1 * (X4 + (X2 * (X3 * X4))))))).-step(add(rule(225, ((X1 + (X1 * (X2 + X2))) * X3) = (X1 * (X3 + (X2 * (X3 + X3))))))).-step(add(rule(226, ((X1 + ((X2 + X2) * X3)) * X4) = ((X1 + (X2 * (X3 + X3))) * X4)))).-step(add(rule(227, (X1 * (X3 + (X2 * (X1 * X3)))) = (X1 * ((X2 + X1) * (X1 * X3)))))).-step(add(rule(228, (X1 * -(X2 + (X1 * (X1 * -X2)))) = 0))).-step(add(rule(229, (X1 * -((X1 * X1) + X2)) = -(X1 + (X1 * X2))))).-step(add(rule(230, (X1 * -(X2 + (X1 * X1))) = -(X1 + (X1 * X2))))).-step(add(rule(231, (((X1 * X1) + X2) * -X1) = -(X1 + (X2 * X1))))).-step(interreduce).-step(delete(rule(179, (X1 + (X1 * -(X2 + (X1 * X1)))) = (X1 * -X2)))).-step(delete(rule(187, (X2 + (((X2 * X2) + X1) * -X2)) = (X1 * -X2)))).-step(delete(rule(214, ((X1 + (X1 * X2)) * (X1 * X1)) = (X1 * ((X1 + (X2 * X1)) * X1))))).-step(add(rule(232, ((X1 + (X2 * X2)) * -X2) = -(X2 + (X1 * X2))))).-step(add(rule(233, ((X1 * X2) + (X3 * (X2 + X4))) = ((X3 * X4) + ((X1 + X3) * X2))))).-step(hard((X1 + (X2 + (X2 * (X4 + X3)))) = (X2 + (X1 + (X2 * (X3 + X4)))))).-step(add(rule(234, (X1 + (X1 * (X2 + (X1 * X3)))) = (X1 * (X2 + (X1 * (X3 + X1))))))).-step(hard((X4 + (X1 * (X5 + (X2 + X3)))) = (X4 + (X1 * (X5 + (X3 + X2)))))).-step(add(rule(235, ((X1 * X2) + (X3 * (X4 + X2))) = (((X3 + X1) * X2) + (X3 * X4))))).-step(hard((X1 * (-X2 + (X3 + X2))) = (X1 * X3))).-step(add(rule(236, (X1 + ((X2 + (X1 * X3)) * X1)) = ((X2 + (X1 * (X3 + X1))) * X1)))).-step(add(rule(237, ((X1 * X2) + ((X1 + X3) * X4)) = ((X3 * X4) + (X1 * (X2 + X4)))))).-step(add(rule(238, (X1 + ((X2 + X3) * (X3 * X3))) = (X3 + (X1 + (X2 * (X3 * X3))))))).-step(add(rule(239, (X1 + ((X2 + X3) * (X2 * X2))) = ((X3 * (X2 * X2)) + (X1 + X2))))).-step(add(rule(240, (X1 + (X1 * (X2 + (X3 * X1)))) = (X1 * (X2 + ((X3 + X1) * X1)))))).-step(add(rule(241, ((X1 * X2) + ((X3 + X1) * X4)) = ((X1 * (X4 + X2)) + (X3 * X4))))).-step(hard((X4 + ((X5 + (X1 + X2)) * X3)) = (X4 + ((X5 + (X2 + X1)) * X3)))).-step(add(rule(242, (X1 + ((X2 + (X3 * X1)) * X1)) = ((X2 + ((X3 + X1) * X1)) * X1)))).-step(hard(((X1 + (X1 + X2)) * (X2 * X2)) = (X2 + (X1 * (X2 * (X2 + X2)))))).-step(hard((X1 + (X1 * (X2 * (X1 + X1)))) = (X1 * ((X2 + (X2 + X1)) * X1)))).-step(hard(((X1 + (X1 + (X2 + X2))) * X3) = ((X1 + (X2 + (X1 + X2))) * X3))).-step(add(rule(243, (((X1 * (X1 + X1)) + (X2 + X2)) * X1) = (((X1 * X1) + X2) * (X1 + X1))))).-step(hard((X1 + (X1 * ((X1 + X1) * X2))) = (X1 * (X1 * (X2 + (X2 + X1)))))).-step(add(rule(244, (X1 * (X3 + (X2 * (X3 + X3)))) = ((X1 + ((X1 + X1) * X2)) * X3)))).-step(add(rule(245, (X1 * (X2 + (X2 + (X3 * X2)))) = ((X1 + (X1 + (X1 * X3))) * X2)))).-step(hard((X1 * (X1 * (X2 + (X1 + X1)))) = (X1 * (X1 * (X1 + (X1 + X2)))))).-step(hard((X1 * (X2 + (X2 + (X3 + X3)))) = (X1 * (X2 + (X3 + (X2 + X3)))))).-step(add(rule(246, ((X1 + X1) * ((X1 * X1) + X2)) = (X1 + (X1 + (X1 * (X2 + X2))))))).-step(hard((X1 * (X1 + ((X1 + X2) * X1))) = (X1 * (X1 + ((X2 + X1) * X1))))).-step(add(rule(247, (X1 * (((X1 * (X1 + X1)) + X2) * X3)) = (X1 * (X3 + (X3 + (X2 * X3))))))).-step(interreduce).-step(delete(rule(116, (X1 + (X1 * (X2 + (X1 * -X1)))) = (X1 * X2)))).-step(delete(rule(119, (X1 + ((X2 + (X1 * -X1)) * X1)) = (X2 * X1)))).-step(delete(rule(180, (X1 + ((X2 + (X1 * X1)) * -X1)) = (X2 * -X1)))).-step(delete(rule(212, (X1 + ((X1 + (X2 * X1)) * X1)) = ((X1 + ((X1 + X2) * X1)) * X1)))).-step(delete(rule(213, (X1 + (X1 * (X1 + (X1 * X2)))) = (X1 * (X1 + (X1 * (X2 + X1))))))).-step(delete(rule(215, (X1 + (X1 * (X1 + (X2 * X1)))) = (X1 * (X1 + ((X1 + X2) * X1)))))).-step(add(rule(248, (X1 * (X2 + (X2 + (X1 * (X1 + X1))))) = ((X1 + X1) * ((X1 * X1) + X2))))).-step(add(rule(249, (X1 + (X1 + (X1 * (X2 + X2)))) = ((X1 + X1) * (X2 + (X1 * X1)))))).-step(hard((X1 * (X1 * ((X1 + X2) * X3))) = (X1 * (X1 * ((X2 + X1) * X3))))).-step(hard((X1 * ((X1 + X2) * (X1 * X3))) = (X1 * ((X2 + X1) * (X1 * X3))))).-step(add(rule(250, ((X1 + ((X1 * X1) + X2)) * (X1 * X1)) = ((X1 + ((X2 + X1) * X1)) * X1)))).-step(add(rule(251, ((X1 + (X1 * (X2 * X3))) * X3) = (X1 * ((X2 + X3) * (X3 * X3)))))).-step(hard((X1 * ((X2 + X1) * X2)) = (X1 * ((X1 + X2) * X2)))).-step(add(rule(252, ((X1 + (X2 + (X1 * X1))) * (X1 * X1)) = ((X1 + ((X2 + X1) * X1)) * X1)))).-step(add(rule(253, (X1 * ((X1 + (X2 * (X1 * X2))) * (X1 * X2))) = ((X1 + X1) * X2)))).-step(hard((X1 + ((X2 * (X1 * X1)) + X3)) = (X3 + ((X1 + X2) * (X1 * X1))))).-step(hard(((X1 + ((X2 + X1) * X1)) * X1) = ((X1 + ((X1 + X2) * X1)) * X1))).-step(hard(((X1 + (X2 + X3)) * (X1 * X1)) = ((X2 + (X1 + X3)) * (X1 * X1)))).-step(hard(((X2 + ((X3 + X1) * X1)) * X1) = ((X2 + ((X1 + X3) * X1)) * X1))).-step(hard((X1 + (X2 * (X1 * (X1 + X1)))) = ((X2 + (X1 + X2)) * (X1 * X1)))).-step(add(rule(254, ((X1 * X2) + ((X1 + X3) * X4)) = ((X1 * (X4 + X2)) + (X3 * X4))))).-step(add(rule(255, ((X1 * (X2 + X3)) + (X4 * X3)) = (((X1 + X4) * X3) + (X1 * X2))))).-step(add(rule(256, ((X1 * (X2 + X3)) + (X4 * X3)) = ((X1 * X2) + ((X4 + X1) * X3))))).-step(hard((X1 * ((X1 * (X1 + X2)) + X3)) = (X1 * (X3 + (X1 * (X2 + X1)))))).-step(add(rule(257, ((X1 * X2) + (X3 * (X2 + X4))) = (((X3 + X1) * X2) + (X3 * X4))))).-step(hard((((X1 + X2) * X3) + (X2 * X4)) = ((X2 * (X3 + X4)) + (X1 * X3)))).-step(add(rule(258, (((X1 + X2) * X3) + (X2 * X4)) = ((X1 * X3) + (X2 * (X4 + X3)))))).-step(hard((X1 + ((X2 * (X1 * X1)) + X3)) = (X3 + ((X2 + X1) * (X1 * X1))))).-step(hard(((((X1 + X2) * X1) + X3) * X1) = ((((X2 + X1) * X1) + X3) * X1))).-step(hard((X1 * (((X1 + X2) * X1) + X3)) = (X1 * (X3 + ((X2 + X1) * X1))))).-step(add(rule(259, ((X1 + (X1 * (X2 * X3))) * X3) = (X1 * ((X3 + X2) * (X3 * X3)))))).-step(add(rule(260, ((X2 + (X1 * -X1)) * X1) = (-X1 + (X2 * X1))))).-step(add(rule(261, (X1 * (X2 + (X1 * -X1))) = (-X1 + (X1 * X2))))).-step(add(rule(262, ((X1 + X1) * (X2 + (X2 + X2))) = ((X1 + (X1 + X1)) * (X2 + X2))))).-step(interreduce).-step(delete(rule(241, ((X1 * X2) + ((X3 + X1) * X4)) = ((X1 * (X4 + X2)) + (X3 * X4))))).-step(delete(rule(255, ((X1 * (X2 + X3)) + (X4 * X3)) = (((X1 + X4) * X3) + (X1 * X2))))).-step(add(rule(263, (X1 + (X1 + (X2 * (X1 + X1)))) = (((X1 * X1) + X2) * (X1 + X1))))).-step(add(rule(264, (X2 + (X2 + (X1 * (X2 * (X2 + X2))))) = ((X1 + X2) * (X2 * (X2 + X2)))))).-step(add(rule(265, (X3 + (X4 + (X2 + (-(X3 + X4) + X1)))) = (X1 + X2)))).-step(hard((X1 + -X2) = (-(X2 + X3) + (X1 + X3)))).-step(hard((X1 + (X2 + (X3 + X4))) = (X1 + (X2 + (X4 + X3))))).-step(hard((X3 + (X4 + (X5 + X2))) = (X3 + (X5 + (X4 + X2))))).-step(hard((X1 + X2) = (X2 + (-(X4 + X5) + (X1 + (X4 + X5)))))).-step(add(rule(266, (X3 + (X4 + (X1 + (X2 + -(X3 + X4))))) = (X1 + X2)))).-step(add(rule(267, (X1 * (X2 + (X1 * (X1 + X1)))) = (X1 + (X1 + (X1 * X2)))))).-step(add(rule(268, ((X2 + (X3 + (X1 * X1))) * X1) = (X1 + ((X2 + X3) * X1))))).-step(add(rule(269, (X1 * (X2 + ((X1 * (X1 * -X2)) + X3))) = (X1 * X3)))).-step(hard((X1 * X2) = (X1 * (-X3 + (X2 + X3))))).-step(add(rule(270, (X1 * (X2 + (X3 + (X1 * (X1 * -X2))))) = (X1 * X3)))).-step(hard((X1 + -X2) = (-X3 + (X1 + (X3 + -X2))))).-step(add(rule(271, ((X1 + X1) * (X2 + X2)) = (X1 * ((X1 + X1) * ((X1 + X1) * X2)))))).-step(add(rule(272, ((X1 + X1) * ((X1 + X1) * (X2 + X2))) = (X1 * ((X1 + X1) * X2))))).-step(hard((-X2 + X1) = (-(X2 + X3) + (X1 + X3)))).-step(add(rule(273, (((X1 * (X1 + X1)) + X2) * X1) = (X1 + (X1 + (X2 * X1)))))).-step(hard(((X1 + (X3 + (X3 + X1))) * X2) = ((X3 + X1) * (X2 + X2)))).-step(add(rule(274, ((X1 + (X2 * (X2 + X2))) * X2) = (X2 + (X2 + (X1 * X2)))))).-step(hard((X1 * (X2 + (X3 + (X3 + X2)))) = ((X1 + X1) * (X3 + X2)))).-step(hard((X1 + (X2 + X3)) = (-X4 + (X2 + (X3 + (X4 + X1)))))).-step(hard((X1 + (-X2 + (X3 + (X4 + X2)))) = (X1 + (X4 + X3)))).-step(hard((X1 + (X2 + X3)) = (-X4 + (X1 + (X2 + (X3 + X4)))))).-step(hard((X1 + (X2 + (-X3 + (X4 + X3)))) = (X1 + (X2 + X4)))).-step(hard(((X1 * X2) + X3) = (((-X5 + (X1 + X5)) * X2) + X3))).-step(hard((X1 + ((-X2 + (X4 + X2)) * X3)) = (X1 + (X4 * X3)))).-step(hard((X1 + (X3 + (-X2 + (X4 + X2)))) = (X3 + (X4 + X1)))).-step(hard((X1 * (X2 * X3)) = (X1 * (X2 * (-X4 + (X3 + X4)))))).-step(hard((X1 * (X2 * X3)) = (X1 * ((-X4 + (X2 + X4)) * X3)))).-step(add(rule(275, (X1 * (X2 + (X1 * (X1 + (X1 * -X2))))) = X1))).-step(hard(((X1 * -(X2 + X2)) + ((X1 + X1) * X2)) = 0)).-step(add(rule(276, (X1 * (X2 * (X1 * (X2 * (X1 * (X2 * X3)))))) = (X1 * (X2 * X3))))).-step(interreduce).-step(delete(rule(126, (X1 * ((X1 + X1) * ((X1 + X1) * (X2 + X2)))) = ((X1 + X1) * X2)))).-step(delete(rule(243, (((X1 * (X1 + X1)) + (X2 + X2)) * X1) = (((X1 * X1) + X2) * (X1 + X1))))).-step(add(rule(277, (X1 + (X1 + ((X2 + X2) * X1))) = (((X1 * X1) + X2) * (X1 + X1))))).-step(add(rule(278, ((X1 * X2) + (X3 + ((X1 * X4) + X5))) = (X3 + ((X1 * (X2 + X4)) + X5))))).-step(hard((X1 + (X2 * (X3 + (X4 + X5)))) = (X1 + (X2 * (X4 + (X5 + X3)))))).-step(hard(((X1 * (X2 + (X3 + X4))) + X5) = ((X1 * (X3 + (X2 + X4))) + X5))).-step(add(rule(279, ((X1 * (X2 + (X2 + X3))) + X4) = (((X1 + X1) * X2) + ((X1 * X3) + X4))))).-step(add(rule(280, (X4 + ((X1 * (X2 + X2)) + X5)) = (((X1 + X1) * X2) + (X5 + X4))))).-step(add(rule(281, ((X1 * (X2 + (X2 + X2))) + X3) = (((X1 + (X1 + X1)) * X2) + X3)))).-step(add(rule(282, (-? + ((X2 * (X3 + X3)) + ?)) = ((X2 + X2) * X3)))).-step(add(rule(283, (-X1 + ((X2 * (X3 + X3)) + X1)) = (-? + ((X2 * (X3 + X3)) + ?))))).-step(add(rule(284, ((X1 * (X2 + (X3 + X3))) + X4) = ((X1 * X2) + (((X1 + X1) * X3) + X4))))).-step(add(rule(285, (X1 + (((X1 + X1) * X2) + X3)) = (X1 + ((X1 * (X2 + X2)) + X3))))).-step(add(rule(286, ((X1 * (X2 * X4)) + ((X3 * X4) + X5)) = ((((X1 * X2) + X3) * X4) + X5)))).-step(add(rule(287, ((-X3 + ((X1 * X2) + X3)) * X4) = (X1 * (X2 * X4))))).-step(add(rule(288, ((X1 * X3) + ((X2 * (X1 * X3)) + X4)) = (((X1 + (X2 * X1)) * X3) + X4)))).-step(add(rule(289, (((X1 + (X1 * X2)) * X3) + X4) = ((X1 * (X3 + (X2 * X3))) + X4)))).-step(add(rule(290, ((X1 + (X1 * X2)) * -X3) = (X1 * -(X3 + (X2 * X3)))))).-step(hard(((X1 + X1) * X2) = ((-X3 + (X1 + (X1 + X3))) * X2))).-step(add(rule(291, ((X1 * X4) + ((X2 * (X3 * X4)) + X5)) = (((X1 + (X2 * X3)) * X4) + X5)))).-step(add(rule(292, ((X1 * X2) + (X3 + ((X4 * X2) + X5))) = (X3 + (((X1 + X4) * X2) + X5))))).-step(hard((X1 + ((-X3 + (X2 + X3)) * X4)) = ((X2 * X4) + X1))).-step(hard((X1 + ((X2 + (X3 + X5)) * X4)) = (X1 + ((X3 + (X5 + X2)) * X4)))).-step(hard((((X1 + (X3 + X4)) * X2) + X5) = (((X3 + (X1 + X4)) * X2) + X5))).-step(add(rule(293, (X1 + (((X2 + X2) * X3) + X4)) = (X1 + ((X2 * (X3 + X3)) + X4))))).-step(add(rule(294, (((X1 + (X1 + X2)) * X3) + X4) = ((X1 * (X3 + X3)) + ((X2 * X3) + X4))))).-step(hard(((-X2 + (X1 + (X1 + X2))) * X3) = (X1 * (X3 + X3)))).-step(add(rule(295, (((X1 + (X2 + X2)) * X3) + X4) = ((X1 * X3) + ((X2 * (X3 + X3)) + X4))))).-step(add(rule(296, ((X1 * (X2 * (X3 * X5))) + (X4 * X5)) = (((X1 * (X2 * X3)) + X4) * X5)))).-step(add(rule(297, ((X1 * (X2 * X5)) + (X3 * (X4 * X5))) = (((X1 * X2) + (X3 * X4)) * X5)))).-step(add(rule(298, ((X1 * X4) + (X2 * (X3 * (X1 * X4)))) = ((X1 + (X2 * (X3 * X1))) * X4)))).-step(add(rule(299, ((X1 * (X2 * X3)) + (X4 + (X5 * X3))) = (X4 + (((X1 * X2) + X5) * X3))))).-step(add(rule(300, ((X1 + ((X3 * X4) + X5)) * X2) = (((X3 * X4) + (X1 + X5)) * X2)))).-step(hard(((X1 + (X2 + X3)) * X4) = ((X2 + (X1 + X3)) * X4))).-step(add(rule(301, ((X2 * X4) + (X1 + (X3 * (X2 * X4)))) = (X1 + ((X2 + (X3 * X2)) * X4))))).-step(hard(((((X1 + X4) * X2) + X5) * X3) = ((((X4 + X1) * X2) + X5) * X3))).-step(add(rule(302, (X1 + ((X2 + (X2 * X3)) * X4)) = (X1 + (X2 * (X4 + (X3 * X4))))))).-step(add(rule(303, ((((X1 + X1) * X2) + X3) * X4) = ((X1 * (X2 * (X4 + X4))) + (X3 * X4))))).-step(add(rule(304, ((X1 + X1) * ((X2 + (X1 * X1)) * X3)) = (X1 * (((X3 * X3) + X2) * (X3 + X3)))))).-step(add(rule(305, ((X1 + X1) * (-X2 + (X1 * (X1 * X2)))) = 0))).-step(add(rule(306, (((X1 * (X2 + X2)) + X3) * X4) = ((X1 * (X2 * (X4 + X4))) + (X3 * X4))))).-step(add(rule(307, (((X1 * X2) + (X3 + X3)) * X4) = ((X1 * (X2 * X4)) + (X3 * (X4 + X4)))))).-step(interreduce).-step(delete(rule(125, ((X1 * X3) + (X2 * (X1 * (X1 * X3)))) = ((X1 + X2) * (X1 * (X1 * X3)))))).-step(delete(rule(282, (-? + ((X2 * (X3 + X3)) + ?)) = ((X2 + X2) * X3)))).-step(delete(rule(283, (-X1 + ((X2 * (X3 + X3)) + X1)) = (-? + ((X2 * (X3 + X3)) + ?))))).-step(add(rule(308, (-X1 + ((X2 * (X3 + X3)) + X1)) = (X2 * (X3 + X3))))).-step(delete(rule(285, (X1 + (((X1 + X1) * X2) + X3)) = (X1 + ((X1 * (X2 + X2)) + X3))))).-step(delete(rule(288, ((X1 * X3) + ((X2 * (X1 * X3)) + X4)) = (((X1 + (X2 * X1)) * X3) + X4)))).-step(hard((X1 + X1) = (-X2 + (X1 + (X1 + X2))))).-step(hard((X1 + X2) = (-X3 + (X1 + (X3 + X2))))).-step(add(rule(309, ((X1 + X1) * ((X2 + (X1 * X1)) * X3)) = ((X1 + X1) * (X3 + (X2 * X3)))))).-step(add(rule(310, (((X1 * X2) + X3) * (X2 * (X2 * X4))) = ((X1 + (X3 * X2)) * (X2 * X4))))).-step(add(rule(311, ((X1 + (X1 * (X2 * -X2))) * (X2 * X3)) = 0))).-step(add(rule(312, (X1 * (X2 + (X2 * (X1 * -X1)))) = 0))).-step(hard((X1 * ((-X2 + (X1 + X2)) * X1)) = X1)).-step(add(rule(313, ((X1 + (X1 * (X2 * -X2))) * (X2 + X2)) = 0))).-step(add(rule(314, (X1 * ((X2 + (X1 * (X1 * -X2))) * X3)) = 0))).-step(add(rule(315, ((X1 + (X2 * (X2 * -X1))) * X2) = 0))).-step(add(rule(316, (X1 * ((X2 + (X2 * (X1 * -X1))) * X3)) = 0))).-step(add(rule(317, (X1 * -(X2 + (X2 * (X1 * -X1)))) = 0))).-step(add(rule(318, ((-X1 + (X2 * (X2 * X1))) * X2) = 0))).-step(add(rule(319, ((X1 * X5) + (X2 * (X3 * (X4 * X5)))) = ((X1 + (X2 * (X3 * X4))) * X5)))).-step(add(rule(320, ((X1 * X2) + (X3 + (X4 * (X5 * X2)))) = (X3 + ((X1 + (X4 * X5)) * X2))))).-step(hard(((X4 + ((X5 + X1) * X2)) * X3) = ((X4 + ((X1 + X5) * X2)) * X3))).-step(hard(((X2 + (X1 * (X3 + X1))) * X1) = ((X2 + (X1 * (X1 + X3))) * X1))).-step(add(rule(321, ((X1 + (X1 + (X2 * X3))) * X4) = ((X1 * (X4 + X4)) + (X2 * (X3 * X4)))))).-step(add(rule(322, ((X1 + ((X2 + X2) * X3)) * X4) = ((X1 * X4) + (X2 * (X3 * (X4 + X4))))))).-step(add(rule(323, (X1 + (X2 * (X3 * (X1 + X1)))) = (X1 + ((X2 + X2) * (X3 * X1)))))).-step(add(rule(324, ((X1 + (X2 * (X3 + X3))) * X4) = ((X1 * X4) + (X2 * (X3 * (X4 + X4))))))).-step(add(rule(325, (X1 + (X2 * (X3 * (X1 + X1)))) = (X1 + (X2 * ((X3 + X3) * X1)))))).-step(add(rule(326, ((X1 + (X2 * X3)) * (X3 * (X3 * X4))) = (((X1 * X3) + X2) * (X3 * X4))))).-step(add(rule(327, (X1 * ((X2 * (X1 * (X2 * (X1 * X2)))) + X3)) = (X1 * (X2 + X3))))).-step(add(rule(328, (X1 * (X2 + (X3 * (X1 * (X3 * (X1 * X3)))))) = (X1 * (X2 + X3))))).-step(add(rule(329, (X1 + (X2 + (-(X1 + X3) + X4))) = (-X3 + (X2 + X4))))).-step(hard(-(X3 + (X2 + X1)) = -(X1 + (X2 + X3)))).-step(add(rule(330, (X4 + (X2 + (X3 + -(X4 + X1)))) = (-X1 + (X2 + X3))))).-step(hard((-(X1 + X2) + (X3 + X1)) = (-X2 + X3))).-step(add(rule(331, (X4 + (X3 + -(X1 + (X4 + X2)))) = (-(X1 + X2) + X3)))).-step(hard((X1 + X2) = (-X4 + (X1 + (X4 + X2))))).-step(add(rule(332, (X4 + (-(X2 + (X4 + X3)) + X1)) = (X1 + -(X2 + X3))))).-step(hard((X1 + X2) = (-X4 + (X2 + (X4 + X1))))).-step(add(rule(333, (X2 + ((X2 + X1) * (X2 * -X2))) = (X1 * (X2 * -X2))))).-step(add(rule(334, (X2 + (X1 * (X2 * -X2))) = ((-X1 + X2) * (X2 * X2))))).-step(add(rule(335, (X1 + (X1 * (X2 * -X1))) = (X1 * ((-X2 + X1) * X1))))).-step(add(rule(336, (((X1 * (X2 * (X1 * X2))) + X3) * (X1 * X2)) = ((X1 + (X3 * X1)) * X2)))).-step(add(rule(337, (X1 * (X2 + (X3 * X2))) = (X1 * (X1 * ((X1 + (X1 * X3)) * X2)))))).-step(add(rule(338, (X1 * (((X1 * (X1 * X2)) + X3) * X4)) = (X1 * ((X2 + X3) * X4))))).-step(add(rule(339, (X1 * (X2 + ((X1 * (X1 * X3)) + X4))) = (X1 * (X2 + (X3 + X4)))))).-step(hard((X1 * (X2 + (X3 + X4))) = (X1 * (X3 + (X2 + X4))))).-step(add(rule(340, (X1 * (X2 + (X2 + X3))) = (X1 * ((X1 * ((X1 + X1) * X2)) + X3))))).-step(interreduce).-step(delete(rule(172, ((X1 + (X1 * (X2 * -X2))) * (X2 * -X2)) = 0))).-step(delete(rule(269, (X1 * (X2 + ((X1 * (X1 * -X2)) + X3))) = (X1 * X3)))).-step(delete(rule(298, ((X1 * X4) + (X2 * (X3 * (X1 * X4)))) = ((X1 + (X2 * (X3 * X1))) * X4)))).-step(delete(rule(301, ((X2 * X4) + (X1 + (X3 * (X2 * X4)))) = (X1 + ((X2 + (X3 * X2)) * X4))))).-step(delete(rule(333, (X2 + ((X2 + X1) * (X2 * -X2))) = (X1 * (X2 * -X2))))).-step(add(rule(341, (X1 * ((X1 * (X1 + (X1 * X2))) + X3)) = (X1 + (X1 * (X2 + X3)))))).-step(add(rule(342, (X1 * (X2 + (X3 + (X1 * (X1 * X4))))) = (X1 * (X2 + (X3 + X4)))))).-step(hard((X1 * (X2 + (X3 + X4))) = (X1 * (X2 + (X4 + X3))))).-step(add(rule(343, (X1 * ((X2 + (X1 * (X1 * X3))) * X4)) = (X1 * ((X2 + X3) * X4))))).-step(hard((X1 * ((X2 + X3) * X4)) = (X1 * ((X3 + X2) * X4)))).-step(add(rule(344, (X1 * (X2 + (X3 + X3))) = (X1 * (X2 + (X1 * ((X1 + X1) * X3))))))).-step(add(rule(345, (X1 * (X2 + (X1 * (X1 + (X1 * X3))))) = (X1 + (X1 * (X3 + X2)))))).-step(add(rule(346, (-X1 + (X2 * (X1 * X1))) = ((-X1 + X2) * (X1 * X1))))).-step(add(rule(347, (X1 * (X1 * (-X1 + X2))) = (X1 * (X1 * (X2 + -X1)))))).-step(hard(((X1 * -(X2 + X3)) + X4) = ((X1 * -(X3 + X2)) + X4))).-step(add(rule(348, ((X1 + (X1 * -X2)) * X3) = (X1 * (X3 + (X2 * -X3)))))).-step(hard((X1 + (X2 * -(X3 + X4))) = (X1 + (X2 * -(X4 + X3))))).-step(add(rule(349, (X1 * (X1 * ((X1 + (X1 * X2)) * X3))) = ((X1 + (X1 * X2)) * X3)))).-step(add(rule(350, -(((X1 + X1) * X2) + X3) = -((X1 * (X2 + X2)) + X3)))).-step(add(rule(351, -(X1 + ((X2 + X2) * X3)) = -(X1 + (X2 * (X3 + X3)))))).-step(add(rule(352, -((X1 * (X2 + X2)) + X3) = -(X3 + ((X1 + X1) * X2))))).-step(add(rule(353, -(((X1 + X1) * X2) + X3) = -(X3 + (X1 * (X2 + X2)))))).-step(add(rule(354, (((X1 * (X2 * (X3 * X3))) + X4) * X3) = (((X1 * X2) + X4) * X3)))).-step(add(rule(355, (((X1 * (X2 * (X2 + X2))) + X3) * X2) = ((X1 + (X1 + X3)) * X2)))).-step(hard((X1 + (X3 + -(X4 + X2))) = (X3 + (X1 + -(X2 + X4))))).-step(add(rule(356, ((X1 + (X2 * (X3 * X1))) * (X1 * X1)) = (X1 + (X2 * (X3 * X1)))))).-step(add(rule(357, ((X1 + (X2 * (X3 * (X4 * X4)))) * X4) = ((X1 + (X2 * X3)) * X4)))).-step(add(rule(358, ((X1 + (X2 * (X3 * (X3 + X3)))) * X3) = ((X1 + (X2 + X2)) * X3)))).-step(hard(((-(X1 + X2) + X4) * X3) = ((-(X2 + X1) + X4) * X3))).-step(add(rule(359, ((-X1 + X2) * (X1 * -X1)) = ((-X2 + X1) * (X1 * X1))))).-step(add(rule(360, (-X1 + (X1 * (X2 * X1))) = (X1 * ((-X1 + X2) * X1))))).-step(add(rule(361, (-X1 + (X2 * (X1 * -X1))) = ((X1 + X2) * (X1 * -X1))))).-step(add(rule(362, (-X1 + (X1 * (X1 * X2))) = (X1 * (X1 * (-X1 + X2)))))).-step(add(rule(363, (-X1 + (X1 * (X2 * -X1))) = (X1 * ((X1 + X2) * -X1))))).-step(add(rule(364, ((X1 + X1) * ((X1 * (X1 * X2)) + X3)) = ((X1 + X1) * (X2 + X3))))).-step(add(rule(365, ((X1 + X1) * (X2 + (X1 * (X1 * -X2)))) = 0))).-step(add(rule(366, ((X1 + X1) * (X2 + (X1 * (X1 * X3)))) = ((X1 + X1) * (X2 + X3))))).-step(add(rule(367, (X1 * ((X1 + X1) * -(X1 + X1))) = -(X1 + (X1 + (X1 + X1)))))).-step(add(rule(368, ((X1 + X1) * (X1 + (X1 + X1))) = 0))).-step(interreduce).-step(delete(rule(270, (X1 * (X2 + (X3 + (X1 * (X1 * -X2))))) = (X1 * X3)))).-step(delete(rule(275, (X1 * (X2 + (X1 * (X1 + (X1 * -X2))))) = X1))).-step(delete(rule(305, ((X1 + X1) * (-X2 + (X1 * (X1 * X2)))) = 0))).-step(delete(rule(314, (X1 * ((X2 + (X1 * (X1 * -X2))) * X3)) = 0))).-step(delete(rule(337, (X1 * (X2 + (X3 * X2))) = (X1 * (X1 * ((X1 + (X1 * X3)) * X2)))))).-step(delete(rule(365, ((X1 + X1) * (X2 + (X1 * (X1 * -X2)))) = 0))).-step(add(rule(369, ((X1 + (X1 + X1)) * -(X1 + X1)) = 0))).-step(add(rule(370, ((X1 + X1) * -(X1 + (X1 + X1))) = 0))).-step(add(rule(371, ((X1 + (X1 + X1)) * ((X1 + X1) * -X2)) = 0))).-step(add(rule(372, ((X1 + (X1 + X1)) * -(X1 + (X1 + (X1 + X1)))) = 0))).-step(add(rule(373, ((X1 + X1) * ((X1 + (X1 + X1)) * -X2)) = 0))).-step(add(rule(374, ((X1 + X1) * ((X1 + (X1 + X1)) * X2)) = 0))).-step(add(rule(375, ((X1 + (X1 + (X1 + X1))) * (X1 + (X1 + X1))) = 0))).-step(add(rule(376, ((X1 + (X1 + X1)) * ((X1 + X1) * X2)) = 0))).-step(add(rule(377, ((X1 + (X1 + X1)) * (X1 + (X1 + (X1 + X1)))) = 0))).-step(add(rule(378, ((X1 + X1) * (X2 * (X1 + (X1 + X1)))) = 0))).-step(add(rule(379, ((X1 + (X1 + X1)) * (X2 * (X1 + X1))) = 0))).-step(hard((X1 + (X2 + (-X3 + X4))) = (X4 + (-X3 + (X2 + X1))))).-step(add(rule(380, (X1 + (-X2 + (X3 + X4))) = (X3 + (-X2 + (X1 + X4)))))).-step(hard((X2 + -X1) = (-(X1 + X4) + (X2 + X4)))).-step(hard((X1 + (X2 + (X3 + X4))) = (X3 + (X2 + (X1 + X4))))).-step(hard((X1 + (-(X3 + X2) + X4)) = (X1 + (X4 + -(X2 + X3))))).-step(hard((X2 + (-(X3 + X1) + X4)) = (X2 + (-(X1 + X3) + X4)))).-step(hard((X1 + (X3 + -(X4 + X2))) = (X1 + (X3 + -(X2 + X4))))).-step(hard((X1 + -(X4 + (X3 + X2))) = (X1 + -(X4 + (X2 + X3))))).-step(add(rule(381, (-X1 + (X2 + (X1 * -X1))) = (X2 + -(X1 + (X1 * X1)))))).-step(hard(-(((X1 + X2) * X3) + X4) = -(X4 + ((X2 + X1) * X3)))).-step(add(rule(382, ((X1 + (X1 * X2)) * (X2 * -X2)) = (X1 * -(X2 + (X2 * X2)))))).-step(add(rule(383, (((X1 * (X2 * X2)) + X3) * (X2 * X4)) = ((X1 + X3) * (X2 * X4))))).-step(add(rule(384, ((X1 + (X2 * (X3 * X3))) * (X3 * X4)) = ((X1 + X2) * (X3 * X4))))).-step(hard((-(X2 + (X3 + X1)) + X4) = (X4 + -(X2 + (X1 + X3))))).-step(hard((-(X2 + (X3 + X1)) + X4) = (-(X3 + (X1 + X2)) + X4))).-step(hard((-(X2 + (X3 + X1)) + X4) = (X4 + -(X3 + (X2 + X1))))).-step(hard((X2 + -(X1 + (X3 + X4))) = (X2 + -(X4 + (X3 + X1))))).-step(hard((X1 + (X3 + -(X4 + X2))) = (X3 + (-(X2 + X4) + X1)))).-step(hard(-(X3 + (X4 + (X1 + X2))) = -(X4 + (X1 + (X3 + X2))))).-step(hard(-(X3 + (X4 + (X1 + X2))) = -(X1 + (X4 + (X2 + X3))))).-step(hard((X2 + -(X1 + (X3 + X4))) = (X2 + -(X3 + (X1 + X4))))).-step(hard(-(X3 + (X4 + (X1 + X2))) = -(X3 + (X1 + (X4 + X2))))).-step(hard(-(X3 + (X4 + (X1 + X2))) = -(X1 + (X3 + (X2 + X4))))).-step(hard((X2 + -(X1 + (X3 + X4))) = (-(X3 + (X4 + X1)) + X2))).-step(hard((X1 + (-(X3 + X5) + X4)) = (X4 + (-(X5 + X3) + X1)))).-step(add(rule(385, (X1 * (X1 * (-X1 + ((X1 + X1) * X2)))) = (-X1 + (X1 * (X2 + X2)))))).-step(add(rule(386, (X1 + (X1 * (X2 + ((X1 * -X1) + X3)))) = (X1 * (X3 + X2))))).-step(add(rule(387, -(X1 + (X1 + (X1 + X1))) = (X1 + X1)))).-step(add(rule(388, -(X1 + (X1 + X1)) = (X1 + (X1 + X1))))).-step(add(rule(389, (X1 + (X1 + (X1 + X1))) = -(X1 + X1)))).-step(add(rule(390, ((X1 + X1) * -(X2 + X2)) = (X1 * (X2 + X2))))).-step(add(rule(391, ((X1 + X1) * (X2 + (X2 + X2))) = 0))).-step(add(rule(392, ((X1 + (X1 + X1)) * (X2 + X2)) = 0))).-step(add(rule(393, ((X1 + X1) * (X2 + X2)) = (X1 * -(X2 + X2))))).-step(hard((X1 * (X2 + (-X3 + (X4 + X3)))) = (X1 * (X2 + X4)))).-step(add(rule(394, (X1 + (X1 * (X2 + (X3 + (X1 * -X1))))) = (X1 * (X2 + X3))))).-step(add(rule(395, (((X1 + X2) * X3) + (X4 + (X2 * -X3))) = ((X1 * X3) + X4)))).-step(hard(((X1 * X2) + X3) = (X3 + ((-X4 + (X1 + X4)) * X2)))).-step(hard(-(X1 + ((X2 + X3) * X4)) = -(X1 + ((X3 + X2) * X4)))).-step(add(rule(396, ((X1 * -X3) + (((X1 + X2) * X3) + X4)) = (X4 + (X2 * X3))))).-step(add(rule(397, (((X1 + X2) * X3) + (X4 + (X1 * -X3))) = ((X2 * X3) + X4)))).-step(hard(((-X1 + (X3 + (X4 + X1))) * X2) = ((X3 + X4) * X2))).-step(hard(((X1 + X3) * X2) = ((-X4 + (X1 + (X3 + X4))) * X2))).-step(add(rule(398, ((X1 * (X2 + X2)) + (((X1 + X1) * -X2) + X3)) = X3))).-step(hard(X1 = (-(X2 + X2) + (X1 + (X2 + X2))))).-step(hard(((X1 * X2) + X3) = ((X1 * (-X4 + (X2 + X4))) + X3))).-step(add(rule(399, ((X1 * (X2 + X2)) + (X3 + ((X1 + X1) * -X2))) = X3))).-step(add(rule(400, (((X1 + X1) * X2) + ((X1 * -(X2 + X2)) + X3)) = X3))).-step(hard(X1 = (-X2 + (X1 + X2)))).-step(add(rule(401, (((X1 + X1) * X2) + (X3 + (X1 * -(X2 + X2)))) = X3))).-step(add(rule(402, (X1 + ((X2 + ((X1 * -X1) + X3)) * X1)) = ((X3 + X2) * X1)))).-step(hard(((X1 + (-X2 + (X3 + X2))) * X4) = ((X1 + X3) * X4))).-step(add(rule(403, (X1 + ((X2 + (X3 + (X1 * -X1))) * X1)) = ((X2 + X3) * X1)))).-step(interreduce).-step(delete(rule(124, ((X1 + (X1 + (X1 + X1))) * X2) = (X1 * (X2 + (X2 + (X2 + X2))))))).-step(delete(rule(176, (X1 * ((X1 + X1) * (X1 + X1))) = (X1 + (X1 + (X1 + X1)))))).-step(delete(rule(188, ((X1 + (X1 + X1)) * -X2) = (X1 * -(X2 + (X2 + X2)))))).-step(add(rule(404, ((X1 + (X1 + X1)) * -X2) = (X1 * (X2 + (X2 + X2)))))).-step(delete(rule(192, ((X1 + X1) * (X2 + (X2 + (X2 + X2)))) = (X1 * (X2 + X2))))).-step(delete(rule(262, ((X1 + X1) * (X2 + (X2 + X2))) = ((X1 + (X1 + X1)) * (X2 + X2))))).-step(delete(rule(271, ((X1 + X1) * (X2 + X2)) = (X1 * ((X1 + X1) * ((X1 + X1) * X2)))))).-step(add(rule(405, (X1 * -(X2 + X2)) = (X1 * ((X1 + X1) * ((X1 + X1) * X2)))))).-step(delete(rule(272, ((X1 + X1) * ((X1 + X1) * (X2 + X2))) = (X1 * ((X1 + X1) * X2))))).-step(delete(rule(367, (X1 * ((X1 + X1) * -(X1 + X1))) = -(X1 + (X1 + (X1 + X1)))))).-step(delete(rule(368, ((X1 + X1) * (X1 + (X1 + X1))) = 0))).-step(delete(rule(370, ((X1 + X1) * -(X1 + (X1 + X1))) = 0))).-step(delete(rule(371, ((X1 + (X1 + X1)) * ((X1 + X1) * -X2)) = 0))).-step(delete(rule(372, ((X1 + (X1 + X1)) * -(X1 + (X1 + (X1 + X1)))) = 0))).-step(delete(rule(373, ((X1 + X1) * ((X1 + (X1 + X1)) * -X2)) = 0))).-step(delete(rule(375, ((X1 + (X1 + (X1 + X1))) * (X1 + (X1 + X1))) = 0))).-step(delete(rule(377, ((X1 + (X1 + X1)) * (X1 + (X1 + (X1 + X1)))) = 0))).-step(delete(rule(387, -(X1 + (X1 + (X1 + X1))) = (X1 + X1)))).-step(add(rule(406, ((X1 + (X1 + X1)) * -(X2 + X2)) = 0))).-step(add(rule(407, ((X1 + (X1 + X1)) * (X1 * -(X1 + X1))) = 0))).-step(add(rule(408, ((X1 + X1) * (X2 * (X3 + (X3 + X3)))) = 0))).-step(add(rule(409, ((X1 + X1) * ((X2 + (X2 + X2)) * X3)) = 0))).-step(add(rule(410, ((X1 + (X1 + X1)) * -X2) = ((X1 + (X1 + X1)) * X2)))).-step(add(rule(411, ((X1 + (X1 + X1)) * (X2 * -(X3 + X3))) = 0))).-step(add(rule(412, ((X1 + X1) * ((X1 + X1) * X2)) = (X1 * (X1 * -(X2 + X2)))))).-step(add(rule(413, (X1 * ((X1 + X1) * ((X1 + X1) * X2))) = ((X1 + X1) * -X2)))).-step(add(rule(414, (X1 + ((X2 + X2) * (X3 * X1))) = (X1 + (X2 * ((X3 + X3) * X1)))))).-step(add(rule(415, (X1 + (X2 * ((X3 + X3) * X4))) = ((X2 * (X3 * (X4 + X4))) + X1)))).-step(add(rule(416, (X1 + ((X2 + X2) * (X3 * X4))) = ((X2 * (X3 * (X4 + X4))) + X1)))).-step(add(rule(417, (X1 + ((X2 + X2) * (X3 * X4))) = ((X2 * ((X3 + X3) * X4)) + X1)))).-step(add(rule(418, (X1 + (X2 + ((X3 + X3) * X4))) = (X1 + ((X3 * (X4 + X4)) + X2))))).-step(add(rule(419, ((X1 + (X1 + X1)) * ((X2 + X2) * X3)) = 0))).-step(add(rule(420, ((X1 + (X1 + X1)) * (X2 * (X3 + X3))) = 0))).-step(add(rule(421, ((X1 * (X2 + X2)) + (X3 + X4)) = (X3 + (X4 + ((X1 + X1) * X2)))))).-step(add(rule(422, (X1 * (X2 * -(X3 + X3))) = ((X1 + X1) * ((X2 + X2) * X3))))).-step(add(rule(423, (X1 + (X1 + (X2 + (X1 + X1)))) = (X2 + -(X1 + X1))))).-step(add(rule(424, ((X1 + X1) * (X2 * (X3 + X3))) = (X1 * (X2 * -(X3 + X3)))))).-step(add(rule(425, (X1 + (X1 + (X1 + (X1 + X2)))) = (-(X1 + X1) + X2)))).-step(add(rule(426, (X1 * ((X2 * (X3 + X3)) + X4)) = (X1 * (X4 + ((X2 + X2) * X3)))))).-step(add(rule(427, (X1 + (X2 + ((X3 + X3) * X4))) = (X2 + ((X3 * (X4 + X4)) + X1))))).-step(add(rule(428, (X1 + (X2 + (X3 * (X4 + X4)))) = (X1 + (X2 + ((X3 + X3) * X4)))))).-step(add(rule(429, (X1 + (X2 * (X3 * (X4 + X4)))) = (X1 + (X2 * ((X3 + X3) * X4)))))).-step(add(rule(430, (X1 + (X2 * (X3 * (X4 + X4)))) = (X1 + ((X2 + X2) * (X3 * X4)))))).-step(hard((X1 + (X2 + ((X3 + X3) * X4))) = (X2 + (X1 + (X3 * (X4 + X4)))))).-step(add(rule(431, (X1 + ((X2 + X2) * (X3 * X4))) = (X1 + (X2 * ((X3 + X3) * X4)))))).-step(add(rule(432, (X1 + (X2 * (X3 * (X4 + X4)))) = ((X2 * ((X3 + X3) * X4)) + X1)))).-step(add(rule(433, (X1 + (X2 * (X3 * (X4 + X4)))) = (((X2 + X2) * (X3 * X4)) + X1)))).-step(add(rule(434, (X1 + (X2 + (X3 * (X4 + X4)))) = (X1 + (((X3 + X3) * X4) + X2))))).-step(add(rule(435, (((X1 + X1) * X2) + (X3 + X4)) = (X3 + (X4 + (X1 * (X2 + X2))))))).-step(add(rule(436, (X1 * (((X2 + X2) * X3) + X4)) = (X1 * (X4 + (X2 * (X3 + X3))))))).-step(add(rule(437, (((X1 + X1) * (X2 * X3)) + X4) = (X4 + (X1 * ((X2 + X2) * X3)))))).-step(add(rule(438, (X1 + (X2 + (X3 * (X4 + X4)))) = (X2 + (((X3 + X3) * X4) + X1))))).-step(add(rule(439, ((X1 * (X2 + X2)) + ((-X1 + X3) * X2)) = ((X1 + X3) * X2)))).-step(hard(((X1 + (X4 + X2)) * X3) = ((X1 + (X2 + X4)) * X3))).-step(hard(((X1 + X2) * X3) = ((-X1 + (X2 + (X1 + X1))) * X3))).-step(add(rule(440, ((X1 * (X2 + X2)) + ((X3 + -X1) * X2)) = ((X1 + X3) * X2)))).-step(add(rule(441, ((X1 + (X1 + X1)) * (X2 * X3)) = (X1 * ((X2 + (X2 + X2)) * X3))))).-step(add(rule(442, ((X1 + (X1 * (X2 * (X2 + X2)))) * (X2 + X2)) = 0))).-step(add(rule(443, (X1 * (X2 * (X3 + (X3 + X3)))) = (X1 * ((X2 + (X2 + X2)) * X3))))).-step(add(rule(444, (X1 * (X2 * (X3 + (X3 + X3)))) = ((X1 + (X1 + X1)) * (X2 * X3))))).-step(add(rule(445, ((X1 + X1) * (X2 + (X1 * ((X1 + X1) * X2)))) = 0))).-step(add(rule(446, (((X1 + X1) * X2) + (X1 * (-X2 + X3))) = (X1 * (X2 + X3))))).-step(hard((X1 * (X2 * (X4 + X3))) = (X1 * (X2 * (X3 + X4))))).-step(hard((X1 * (X2 + X3)) = (X1 * (-X2 + (X3 + (X2 + X2)))))).-step(add(rule(447, (X1 * (X2 + (X2 * (X1 * X1)))) = ((X1 + X1) * X2)))).-step(hard((X1 * (X1 * -(X1 + X2))) = (X1 * (X1 * -(X2 + X1))))).-step(add(rule(448, (((X1 + X1) * X2) + (X1 * (X3 + -X2))) = (X1 * (X2 + X3))))).-step(add(rule(449, ((X1 + ((X2 + X2) * X3)) * X4) = (((X2 * (X3 + X3)) + X1) * X4)))).-step(add(rule(450, ((X1 + (X2 * (X3 + X3))) * X4) = ((((X2 + X2) * X3) + X1) * X4)))).-step(hard((X1 * (X3 + (X1 * (-X2 + (X1 + X2))))) = (X1 + (X1 * X3)))).-step(add(rule(451, ((X1 + (((X1 * -X2) + X3) * X2)) * X2) = (X3 * (X2 * X2))))).-step(hard((X1 * X2) = ((-X2 + (X1 + X2)) * X2))).-step(add(rule(452, (X1 * (X1 * (X2 * X1))) = (X2 * X1)))).-step(add(rule(453, ((X1 + ((X2 + (X1 * -X3)) * X3)) * X3) = (X2 * (X3 * X3))))).-step(add(rule(454, (X1 * (X1 * (X1 + (X2 * X1)))) = (X1 + (X2 * X1))))).-step(hard((((X1 * (X1 + X2)) + X3) * X1) = (((X1 * (X2 + X1)) + X3) * X1))).-step(hard((X1 + (X2 * ((X3 + X4) * X1))) = (X1 + (X2 * ((X4 + X3) * X1))))).-step(add(rule(455, (X1 * (X3 + (X1 * (X2 * X3)))) = (X1 * (X1 * ((X2 + X1) * X3)))))).-step(hard((X1 + (X2 + (X3 + (X4 + X5)))) = (X3 + (X5 + (X4 + (X1 + X2)))))).-step(interreduce).-step(delete(rule(112, ((X1 + (X1 + X1)) * (X1 * X1)) = (X1 + (X1 + X1))))).-step(delete(rule(209, (X1 + (X1 * ((X2 + X2) * X3))) = (X1 + (X1 * (X2 * (X3 + X3))))))).-step(delete(rule(323, (X1 + (X2 * (X3 * (X1 + X1)))) = (X1 + ((X2 + X2) * (X3 * X1)))))).-step(delete(rule(325, (X1 + (X2 * (X3 * (X1 + X1)))) = (X1 + (X2 * ((X3 + X3) * X1)))))).-step(delete(rule(369, ((X1 + (X1 + X1)) * -(X1 + X1)) = 0))).-step(delete(rule(374, ((X1 + X1) * ((X1 + (X1 + X1)) * X2)) = 0))).-step(delete(rule(376, ((X1 + (X1 + X1)) * ((X1 + X1) * X2)) = 0))).-step(delete(rule(378, ((X1 + X1) * (X2 * (X1 + (X1 + X1)))) = 0))).-step(delete(rule(379, ((X1 + (X1 + X1)) * (X2 * (X1 + X1))) = 0))).-step(delete(rule(404, ((X1 + (X1 + X1)) * -X2) = (X1 * (X2 + (X2 + X2)))))).-step(delete(rule(405, (X1 * -(X2 + X2)) = (X1 * ((X1 + X1) * ((X1 + X1) * X2)))))).-step(delete(rule(406, ((X1 + (X1 + X1)) * -(X2 + X2)) = 0))).-step(delete(rule(407, ((X1 + (X1 + X1)) * (X1 * -(X1 + X1))) = 0))).-step(delete(rule(412, ((X1 + X1) * ((X1 + X1) * X2)) = (X1 * (X1 * -(X2 + X2)))))).-step(delete(rule(414, (X1 + ((X2 + X2) * (X3 * X1))) = (X1 + (X2 * ((X3 + X3) * X1)))))).-step(delete(rule(423, (X1 + (X1 + (X2 + (X1 + X1)))) = (X2 + -(X1 + X1))))).-step(hard((X1 + (X2 + (X3 + (X4 + X5)))) = (X2 + (X4 + (X5 + (X3 + X1)))))).-step(hard((X1 + (X2 + (X3 + (X4 + X5)))) = (X3 + (X4 + (X5 + (X1 + X2)))))).-step(add(rule(456, ((X1 + X1) * ((X1 * (X1 + X1)) + X2)) = (-(X1 + X1) + ((X1 + X1) * X2))))).-step(hard((X1 * ((X2 + (X4 + X4)) * X3)) = (X1 * ((X4 + (X4 + X2)) * X3)))).-step(hard((X1 * (X2 * (X3 + (X4 + X4)))) = (X1 * (X2 * (X4 + (X4 + X3)))))).-step(hard((X1 + ((X1 * (X1 * X2)) + X3)) = (X3 + (X1 * (X1 * (X1 + X2)))))).-step(add(rule(457, ((X1 * (X1 * (X2 + X1))) + X3) = (X1 + ((X1 * (X1 * X2)) + X3))))).-step(add(rule(458, (X1 + (X2 + (X1 * (X1 * X3)))) = (X2 + (X1 * (X1 * (X3 + X1))))))).-step(hard((X1 + -(X2 + X2)) = (X2 + (X1 + (X2 + (X2 + X2)))))).-step(hard((X1 + (X1 + (X2 + (X1 + X1)))) = (X2 + -(X1 + X1)))).-step(hard((X1 * (X2 + (X1 * (X3 + X1)))) = (X1 * (X2 + (X1 * (X1 + X3)))))).-step(hard((X1 + (X1 * ((X1 + X1) * X2))) = (X1 * (X1 * (X2 + (X1 + X2)))))).-step(hard((X1 + ((X1 * (X2 * X1)) + X3)) = (X3 + (X1 * ((X1 + X2) * X1))))).-step(add(rule(459, ((X1 * ((X2 + X1) * X1)) + X3) = (X1 + ((X1 * (X2 * X1)) + X3))))).-step(add(rule(460, (X1 + (X2 + (X1 * (X3 * X1)))) = (X2 + (X1 * ((X3 + X1) * X1)))))).-step(hard((X1 * (X2 + ((X3 + X1) * X1))) = (X1 * (X2 + ((X1 + X3) * X1))))).-step(hard((X1 + (X1 * (X2 * (X1 + X1)))) = (X1 * ((X2 + (X1 + X2)) * X1)))).-step(add(rule(461, ((X4 * -X2) + (X3 + ((X1 + X4) * X2))) = ((X1 * X2) + X3)))).-step(hard(((X1 + X3) * X2) = ((-X4 + (X3 + (X1 + X4))) * X2))).-step(hard(((X1 * X2) + X3) = (-X2 + (X3 + (X2 + (X1 * X2)))))).-step(hard(((X1 * X2) + X3) = (X3 + ((-X5 + (X1 + X5)) * X2)))).-step(hard(((-X3 + X1) * X2) = ((-(X4 + X3) + (X1 + X4)) * X2))).-step(add(rule(462, (X1 + (((X2 + X2) * X3) + X4)) = ((X2 * (X3 + X3)) + (X4 + X1))))).-step(hard(((X1 * (X2 + X2)) + (X3 + X4)) = (((X1 + X1) * X2) + (X4 + X3)))).-step(hard((((X1 * (X1 + X2)) + X3) * X1) = ((X3 + (X1 * (X2 + X1))) * X1))).-step(hard(((((X1 + X2) * X1) + X3) * X1) = ((X3 + ((X2 + X1) * X1)) * X1))).-step(add(rule(463, (X1 * (X1 * ((X1 + X2) * X2))) = (X1 * ((X2 + X1) * (X2 * X2)))))).-step(add(rule(464, (X1 * ((X1 + X2) * (X1 * X2))) = (X1 * (X2 * ((X2 + X1) * X2)))))).-step(add(rule(465, ((X1 + (X1 * (X2 * X3))) * X2) = (X1 * (X2 * ((X2 + X3) * X2)))))).-step(add(rule(466, (X1 * (X2 + (X3 * (X2 + X2)))) = (X1 * ((X3 + (X1 * (X1 + (X1 * X3)))) * X2))))).-step(add(rule(467, (X1 * ((X2 + X1) * (X1 * X2))) = (X1 * (X2 * ((X2 + X1) * X2)))))).-step(hard(((X1 * X2) + ((X3 + X1) * X4)) = ((X1 * (X4 + X2)) + (X3 * X4)))).-step(add(rule(468, ((X1 * X2) + ((X3 + X1) * X4)) = ((X3 * X4) + (X1 * (X2 + X4)))))).-step(interreduce).-step(delete(rule(235, ((X1 * X2) + (X3 * (X4 + X2))) = (((X3 + X1) * X2) + (X3 * X4))))).-step(delete(rule(256, ((X1 * (X2 + X3)) + (X4 * X3)) = ((X1 * X2) + ((X4 + X1) * X3))))).-step(delete(rule(258, (((X1 + X2) * X3) + (X2 * X4)) = ((X1 * X3) + (X2 * (X4 + X3)))))).-step(hard((X1 * ((X2 + (X4 + X4)) * X3)) = (X1 * ((X4 + (X2 + X4)) * X3)))).-step(add(rule(469, ((X1 * X2) + (X3 * (X2 + X4))) = ((X3 * X4) + ((X3 + X1) * X2))))).-step(hard((X1 * (X1 * (X2 + (X3 + X1)))) = (X1 * (X1 * (X1 + (X2 + X3)))))).-step(add(rule(470, (X1 * (X2 + (X1 * (X2 + X1)))) = (X1 + ((X1 + (X1 * X1)) * X2))))).-step(hard((X1 * ((X2 + (X3 + X1)) * X1)) = (X1 * ((X1 + (X2 + X3)) * X1)))).-step(add(rule(471, ((X1 + (X2 + (X2 * X2))) * (X2 * X2)) = ((X2 + ((X1 + X2) * X2)) * X2)))).-step(hard(((X1 * X2) + (X3 * (X4 + X2))) = (((X3 + X1) * X2) + (X3 * X4)))).-step(hard((X1 * (X2 * (X3 + (X4 + X4)))) = (X1 * (X2 * (X4 + (X3 + X4)))))).-step(hard(((X1 * (X2 * X2)) + (X3 + X2)) = (X3 + ((X1 + X2) * (X2 * X2))))).-step(hard(((X1 * (X2 * X1)) + (X3 + X1)) = (X3 + (X1 * ((X1 + X2) * X1))))).-step(add(rule(472, ((X1 + ((X1 + X2) * X2)) * X2) = (X2 + (X1 * (X2 + (X2 * X2))))))).-step(add(rule(473, (X1 * (X1 * (X1 + (X1 + (X1 * (X2 + X2)))))) = ((X1 + X1) * (X2 + (X1 * X1)))))).-step(add(rule(474, (X1 * ((X1 + X2) * (X2 * X2))) = (X1 * (X1 * ((X1 + X2) * X2)))))).-step(hard(((X1 * (X2 + X3)) + (X4 * X2)) = (((X1 + X4) * X2) + (X1 * X3)))).-step(add(rule(475, ((X1 + (X1 * X1)) * (X1 + X1)) = ((X1 + X1) * (X1 + (X1 * X1)))))).-step(hard((X1 + (X2 + (X3 + (X4 + X5)))) = (X2 + (X3 + (X5 + (X4 + X1)))))).-step(hard((X3 + (X4 + (X5 + (X6 + X2)))) = (X3 + (X5 + (X6 + (X4 + X2)))))).-step(hard((X3 + (X4 + (X5 + (X6 + X2)))) = (X3 + (X4 + (X6 + (X5 + X2)))))).-step(add(rule(476, (X1 + (X1 + ((X2 + X2) * X1))) = ((X2 + (X1 * X1)) * (X1 + X1))))).-step(hard(((X1 * (X2 + (X2 + X3))) + X4) = ((X1 * (X3 + (X2 + X2))) + X4))).-step(hard((((X1 + X1) * X2) + (X3 + X4)) = (X4 + (X3 + (X1 * (X2 + X2)))))).-step(add(rule(477, (X1 + ((X2 * (X3 + X3)) + X4)) = (X4 + (((X2 + X2) * X3) + X1))))).-step(add(rule(478, (((X1 + (X1 + X1)) * X2) + X3) = (X3 + (X1 * (X2 + (X2 + X2))))))).-step(add(rule(479, (X1 + (X2 * (X3 + (X3 + X3)))) = (X1 + ((X2 + (X2 + X2)) * X3))))).-step(add(rule(480, ((X1 * (X2 + (X2 + X2))) + X3) = (X3 + ((X1 + (X1 + X1)) * X2))))).-step(hard(((X1 * (X2 + (X3 + X3))) + X4) = (X4 + (X1 * (X3 + (X3 + X2)))))).-step(add(rule(481, ((X1 * (X2 + (X3 * X2))) + X4) = (X4 + ((X1 + (X1 * X3)) * X2))))).-step(add(rule(482, (((X1 + (X1 * X2)) * X3) + X4) = (X4 + (X1 * (X3 + (X2 * X3))))))).-step(hard((((X1 + (X1 + X2)) * X3) + X4) = (((X2 + (X1 + X1)) * X3) + X4))).-step(hard((((X1 + (X2 + X2)) * X3) + X4) = (X4 + ((X2 + (X2 + X1)) * X3)))).-step(hard(((X3 + (X1 * (X4 + X2))) * X5) = ((X3 + (X1 * (X2 + X4))) * X5))).-step(hard(((X1 + (X1 + (X2 + X3))) * X4) = ((X2 + (X1 + (X1 + X3))) * X4))).-step(hard((((X1 * (X2 + X3)) + X4) * X5) = (((X1 * (X3 + X2)) + X4) * X5))).-step(add(rule(483, ((X1 + (X1 * X2)) * (X1 + X1)) = ((X1 + X1) * (X1 + (X2 * X1)))))).-step(add(rule(484, ((X1 + (X1 * X3)) * (X2 + X2)) = ((X1 + X1) * (X2 + (X3 * X2)))))).-step(add(rule(485, ((X1 + (X2 + (X3 * X3))) * (X3 * X3)) = ((X3 + ((X1 + X2) * X3)) * X3)))).-step(hard((X1 + (X1 * (X3 + (X4 + X2)))) = (X1 + (X1 * (X4 + (X3 + X2)))))).-step(hard((X1 * (X1 * (X3 + (X1 + X2)))) = (X1 * (X1 * (X1 + (X3 + X2)))))).-step(hard((X1 * ((X3 + (X1 + X2)) * X1)) = (X1 * ((X1 + (X3 + X2)) * X1)))).-step(hard((X1 * (((X2 + X1) * X1) + X3)) = (X1 * (((X1 + X2) * X1) + X3)))).-step(hard((X1 + (X4 + ((X5 + X2) * X3))) = (X4 + (((X2 + X5) * X3) + X1)))).-step(add(rule(486, ((X1 + X1) * (X2 + (X1 * (X1 + (X1 + X1))))) = ((X1 + X1) * X2)))).-step(interreduce).-step(delete(rule(252, ((X1 + (X2 + (X1 * X1))) * (X1 * X1)) = ((X1 + ((X2 + X1) * X1)) * X1)))).-step(delete(rule(313, ((X1 + (X1 * (X2 * -X2))) * (X2 + X2)) = 0))).-step(delete(rule(442, ((X1 + (X1 * (X2 * (X2 + X2)))) * (X2 + X2)) = 0))).-step(delete(rule(471, ((X1 + (X2 + (X2 * X2))) * (X2 * X2)) = ((X2 + ((X1 + X2) * X2)) * X2)))).-step(delete(rule(475, ((X1 + (X1 * X1)) * (X1 + X1)) = ((X1 + X1) * (X1 + (X1 * X1)))))).-step(delete(rule(483, ((X1 + (X1 * X2)) * (X1 + X1)) = ((X1 + X1) * (X1 + (X2 * X1)))))).-step(add(rule(487, ((X1 + X1) * (X2 * (X3 * (X1 + (X1 + X1))))) = 0))).-step(add(rule(488, (((X1 * (X1 + (X1 + X1))) + X2) * (X1 + X1)) = (X2 * (X1 + X1))))).-step(add(rule(489, ((X2 + (X1 * (X1 + (X1 + X1)))) * (X1 + X1)) = (X2 * (X1 + X1))))).-step(add(rule(490, (X1 * (X2 + X2)) = ((X1 + X1) * (? + (? + (? + X2))))))).-step(add(rule(491, ((X1 + X1) * (X3 + (X3 + (X3 + X2)))) = ((X1 + X1) * (? + (? + (? + X2))))))).-step(add(rule(492, (X1 * (X2 + X2)) = ((X1 + X1) * (X2 + (? + (? + ?))))))).-step(add(rule(493, ((X1 + X1) * (X2 + (X3 + (X3 + X3)))) = ((X1 + X1) * (X2 + (? + (? + ?))))))).-step(hard((X2 + ((X1 + (X3 + X4)) * X2)) = (X2 + ((X4 + (X3 + X1)) * X2)))).-step(hard(((X2 + X3) * ((X1 + X1) * X4)) = ((X3 + X2) * (X1 * (X4 + X4))))).-step(hard((X1 * ((X3 + X4) * (X2 + X2))) = ((X1 + X1) * ((X4 + X3) * X2)))).-step(hard((X3 + ((X4 + (X5 + X2)) * X3)) = (X3 + ((X5 + (X4 + X2)) * X3)))).-step(add(rule(494, ((X1 + ((X1 * (X2 * -X2)) + X3)) * X2) = (X3 * X2)))).-step(add(rule(495, ((X1 + (-X2 + X3)) * X4) = ((X3 + (-X2 + X1)) * X4)))).-step(hard(((X1 + (X2 + X3)) * X4) = ((X3 + (X2 + X1)) * X4))).-step(add(rule(496, ((X1 + (X2 + (X1 * (X3 * -X3)))) * X3) = (X2 * X3)))).-step(hard((X1 + X2) = (-X4 + (X2 + (X1 + X4))))).-step(hard((X1 + X2) = (-X5 + (X2 + (X1 + X5))))).-step(add(rule(497, ((X1 + (X2 + (X2 * (X3 * -X3)))) * X3) = (X1 * X3)))).-step(add(rule(498, (X1 * (X2 + (X2 * (X1 * (X2 * (X1 * -X2)))))) = 0))).-step(add(rule(499, (X1 * (X2 + ((X2 * (X1 * -X1)) + X3))) = (X1 * X3)))).-step(add(rule(500, (X1 * (X2 * (X1 * X1))) = (X1 * X2)))).-step(add(rule(501, (X1 * (X2 * (X1 * -X1))) = (X1 * -X2)))).-step(add(rule(502, (X1 * ((X2 * (X1 * X1)) + X3)) = (X1 * (X2 + X3))))).-step(add(rule(503, (X1 * (X2 + (X3 * (X1 * X1)))) = (X1 * (X3 + X2))))).-step(add(rule(504, (X1 * (X2 * (X1 * (X1 + X1)))) = (X1 * (X2 + X2))))).-step(add(rule(505, (X1 * (X2 * (X1 * X2))) = (X1 * (X2 * (X2 * X1)))))).-step(add(rule(506, (X1 * (X2 + (-X3 + X4))) = (X1 * (X4 + (-X3 + X2)))))).-step(hard((X1 * (X2 + (X3 + X4))) = (X1 * (X4 + (X3 + X2))))).-step(add(rule(507, (X1 * (X2 + (X3 + (X3 * (X1 * -X1))))) = (X1 * X2)))).-step(add(rule(508, (X1 * (-X2 + (X1 * ((X1 + X1) * X2)))) = (X1 * X2)))).-step(add(rule(509, ((-X1 + (X1 * (X2 * (X2 + X2)))) * X2) = (X1 * X2)))).-step(add(rule(510, ((X5 * -X4) + (X2 + (X1 + (X5 * X4)))) = (X1 + X2)))).-step(hard((X1 + X2) = (-(X3 + X3) + (X2 + (X1 + (X3 + X3)))))).-step(add(rule(511, (X1 * (X1 * (X2 * -X1))) = (X2 * -X1)))).-step(add(rule(512, (X3 * (X2 * X2)) = (X2 * (X2 * X3))))).-step(hard(((X1 + X1) * (X2 + X1)) = (X1 * (X1 + (X2 + (X1 + X2)))))).-step(hard((-X1 + (X2 + (X1 + (X3 + X4)))) = (X3 + (X4 + X2)))).-step(hard((X1 + (X2 * X3)) = (X1 + ((-X4 + (X2 + X4)) * X3)))).-step(hard((-X1 + (X2 + (X3 + (X1 + X4)))) = (X3 + (X2 + X4)))).-step(hard((-X1 + (X2 + (X3 + (X4 + X1)))) = (X4 + (X2 + X3)))).-step(hard((X1 + (X2 + X3)) = (-X4 + (X2 + (X1 + (X4 + X3)))))).-step(hard((-X1 + (X4 + (X1 + (X3 + X5)))) = (X4 + (X5 + X3)))).-step(hard((X1 + (X2 + X3)) = (-X4 + (X2 + (X3 + (X1 + X4)))))).-step(hard((X1 + (X2 + (-X5 + (X4 + X5)))) = (X4 + (X1 + X2)))).-step(hard(((X1 * X2) + X3) = (X3 + ((-X6 + (X1 + X6)) * X2)))).-step(hard(((X1 + X3) * X2) = ((-X4 + (X3 + (X4 + X1))) * X2))).-step(add(rule(513, (-? + (((X2 + X2) * X3) + ?)) = (X2 * (X3 + X3))))).-step(add(rule(514, (-X1 + (((X2 + X2) * X3) + X1)) = (-? + (((X2 + X2) * X3) + ?))))).-step(add(rule(515, ((X1 + (X2 * (X2 * X1))) * X2) = (X1 * (X2 + X2))))).-step(hard((X1 * (X2 * X2)) = (X2 * (X2 * (-X2 + (X1 + X2)))))).-step(add(rule(516, ((X2 + (X1 * (X1 + (X1 * -X2)))) * X1) = X1))).-step(interreduce).-step(delete(rule(30, (X1 + (X2 * (X1 * X1))) = ((X1 + X2) * (X1 * X1))))).-step(add(rule(517, (X1 + (X2 * (X1 * X1))) = (X1 * (X1 * (X1 + X2)))))).-step(delete(rule(108, ((X1 + (X2 * X3)) * (X3 * X3)) = (((X1 * X3) + X2) * X3)))).-step(add(rule(518, (X3 * (X3 * (X1 + (X2 * X3)))) = (((X1 * X3) + X2) * X3)))).-step(delete(rule(127, (((X1 + X2) * (X1 * X1)) + X3) = (X1 + ((X2 * (X1 * X1)) + X3))))).-step(delete(rule(128, (X1 + (X2 * (X3 * (X1 * X1)))) = ((X1 + (X2 * X3)) * (X1 * X1))))).-step(add(rule(519, (X1 + (X2 * (X3 * (X1 * X1)))) = (X1 * (X1 * (X1 + (X2 * X3))))))).-step(delete(rule(129, (X1 + (X2 + (X3 * (X1 * X1)))) = (X2 + ((X1 + X3) * (X1 * X1)))))).-step(delete(rule(131, ((X1 + (X2 + X2)) * (X1 * X1)) = (X1 + (X2 * (X1 * (X1 + X1))))))).-step(add(rule(520, (X1 * (X1 * (X1 + (X2 + X2)))) = (X1 + (X2 * (X1 * (X1 + X1))))))).-step(delete(rule(136, (((X1 + X2) * (X2 * X2)) + X3) = (X2 + ((X1 * (X2 * X2)) + X3))))).-step(delete(rule(138, (((X1 * X2) + X3) * (X2 * X2)) = ((X1 + (X3 * X2)) * X2)))).-step(add(rule(521, (X2 * (X2 * ((X1 * X2) + X3))) = ((X1 + (X3 * X2)) * X2)))).-step(delete(rule(238, (X1 + ((X2 + X3) * (X3 * X3))) = (X3 + (X1 + (X2 * (X3 * X3))))))).-step(add(rule(522, (X1 + (X3 * (X3 * (X2 + X3)))) = (X3 + (X1 + (X2 * (X3 * X3))))))).-step(delete(rule(239, (X1 + ((X2 + X3) * (X2 * X2))) = ((X3 * (X2 * X2)) + (X1 + X2))))).-step(add(rule(523, (X1 + (X2 * (X2 * (X2 + X3)))) = ((X3 * (X2 * X2)) + (X1 + X2))))).-step(delete(rule(250, ((X1 + ((X1 * X1) + X2)) * (X1 * X1)) = ((X1 + ((X2 + X1) * X1)) * X1)))).-step(add(rule(524, ((X1 + ((X2 + X1) * X1)) * X1) = (X1 * (X1 + (X1 * (X2 + X1))))))).-step(delete(rule(251, ((X1 + (X1 * (X2 * X3))) * X3) = (X1 * ((X2 + X3) * (X3 * X3)))))).-step(add(rule(525, ((X1 + (X1 * (X2 * X3))) * X3) = (X1 * (X3 * (X3 * (X2 + X3))))))).-step(delete(rule(259, ((X1 + (X1 * (X2 * X3))) * X3) = (X1 * ((X3 + X2) * (X3 * X3)))))).-step(add(rule(526, ((X1 + (X1 * (X2 * X3))) * X3) = (X1 * (X3 * (X3 * (X3 + X2))))))).-step(delete(rule(334, (X2 + (X1 * (X2 * -X2))) = ((-X1 + X2) * (X2 * X2))))).-step(add(rule(527, (X2 + (X1 * (X2 * -X2))) = (X2 * (X2 * (-X1 + X2)))))).-step(delete(rule(346, (-X1 + (X2 * (X1 * X1))) = ((-X1 + X2) * (X1 * X1))))).-step(add(rule(528, (-X1 + (X2 * (X1 * X1))) = (X1 * (X1 * (-X1 + X2)))))).-step(delete(rule(356, ((X1 + (X2 * (X3 * X1))) * (X1 * X1)) = (X1 + (X2 * (X3 * X1)))))).-step(add(rule(529, (X1 * (X1 * (X1 + (X2 * (X3 * X1))))) = (X1 + (X2 * (X3 * X1)))))).-step(delete(rule(359, ((-X1 + X2) * (X1 * -X1)) = ((-X2 + X1) * (X1 * X1))))).-step(add(rule(530, ((-X1 + X2) * (X1 * -X1)) = (X1 * (X1 * (-X2 + X1)))))).-step(delete(rule(447, (X1 * (X2 + (X2 * (X1 * X1)))) = ((X1 + X1) * X2)))).-step(delete(rule(454, (X1 * (X1 * (X1 + (X2 * X1)))) = (X1 + (X2 * X1))))).-step(delete(rule(458, (X1 + (X2 + (X1 * (X1 * X3)))) = (X2 + (X1 * (X1 * (X3 + X1))))))).-step(delete(rule(463, (X1 * (X1 * ((X1 + X2) * X2))) = (X1 * ((X2 + X1) * (X2 * X2)))))).-step(add(rule(531, (X1 * (X1 * ((X1 + X2) * X2))) = (X1 * (X2 * (X2 * (X2 + X1))))))).-step(delete(rule(474, (X1 * ((X1 + X2) * (X2 * X2))) = (X1 * (X1 * ((X1 + X2) * X2)))))).-step(add(rule(532, (X1 * (X2 * (X2 * (X1 + X2)))) = (X1 * (X1 * ((X1 + X2) * X2)))))).-step(delete(rule(485, ((X1 + (X2 + (X3 * X3))) * (X3 * X3)) = ((X3 + ((X1 + X2) * X3)) * X3)))).-step(add(rule(533, ((X3 + ((X1 + X2) * X3)) * X3) = (X3 * (X3 + (X3 * (X1 + X2))))))).-step(delete(rule(492, (X1 * (X2 + X2)) = ((X1 + X1) * (X2 + (? + (? + ?))))))).-step(delete(rule(493, ((X1 + X1) * (X2 + (X3 + (X3 + X3)))) = ((X1 + X1) * (X2 + (? + (? + ?))))))).-step(add(rule(534, ((X1 + X1) * (X2 + (X3 + (X3 + X3)))) = ((X1 + X1) * (? + (? + (? + X2))))))).-step(delete(rule(513, (-? + (((X2 + X2) * X3) + ?)) = (X2 * (X3 + X3))))).-step(delete(rule(514, (-X1 + (((X2 + X2) * X3) + X1)) = (-? + (((X2 + X2) * X3) + ?))))).-step(add(rule(535, (-X1 + (((X2 + X2) * X3) + X1)) = ((X2 + X2) * X3)))).-step(simplify_queue).-step(add(rule(536, (X1 * ((X1 + (X2 * X1)) * X1)) = (X1 + (X1 * X2))))).-step(add(rule(537, ((X2 + (X1 * X2)) * X2) = (X2 * (X2 + (X2 * X1)))))).-step(add(rule(538, (X1 * (X2 * (X3 * X3))) = (X3 * (X3 * (X1 * X2)))))).-step(add(rule(539, (X1 * (X2 * (X2 + X2))) = (X2 * (X2 * (X1 + X1)))))).-step(hard((X1 * X2) = (X1 * (-X1 + (X2 + X1))))).-step(add(rule(540, (X1 * (X2 * -X2)) = (X2 * (X2 * -X1))))).-step(add(rule(541, ((X1 + X1) * X2) = (X2 * (X2 * (X1 * (X2 + X2))))))).-step(add(rule(542, (X1 * (X1 * (X2 * X3))) = (X2 * (X1 * (X1 * X3)))))).-step(add(rule(543, (X2 * X1) = (X1 * X2)))).--lemma((X1 + 0) = X1).-lemma((X1 + (-X1 + X2)) = X2).-lemma(-(-X1) = X1).-lemma((X2 + (X1 + -X2)) = X1).-lemma((X1 * (X1 * (X1 * X2))) = (X1 * X2)).-lemma((X1 + (X2 + -(X1 + X2))) = 0).-lemma((X1 * ((X1 * X1) + X2)) = (X1 + (X1 * X2))).-lemma((X1 * 0) = 0).-lemma((-X1 * -(-X1 * -X1)) = X1).-lemma((X1 + (X1 * (X1 * X2))) = (X1 * (X1 * (X1 + X2)))).-lemma((0 * X1) = 0).-lemma(((X1 * (X2 * X4)) + (X3 * X4)) = (((X1 * X2) + X3) * X4)).-lemma(((X1 * X4) + (X2 * (X3 * X4))) = ((X1 + (X2 * X3)) * X4)).-lemma((X1 * (X2 * (X1 * (X2 * (X1 * X2))))) = (X1 * X2)).-lemma(-(X1 * X2) = (X1 * -X2)).-lemma((-X1 * X2) = (X1 * -X2)).-lemma(((X1 + (X1 * (X2 * -X2))) * (X2 * X3)) = 0).-lemma(((X1 + (((X1 * -X2) + X3) * X2)) * X2) = (X3 * (X2 * X2))).-lemma((X1 * (X1 * (X2 * X1))) = (X2 * X1)).-lemma((X1 * (X2 * (X1 * X1))) = (X1 * X2)).-lemma((X1 * (X2 * (X3 * X3))) = (X3 * (X3 * (X1 * X2)))).
− misc/static-libstdc++
@@ -1,24 +0,0 @@-#!/bin/zsh-typeset -a args--process() {-    for arg in $*; do-        case $arg in-            \"*\")-                process $(echo $arg | cut -c2- | rev | cut -c2- | rev)-                ;;-            @*)-                process $(cat $(echo $arg | cut -c2-))-                ;;-            -lstdc++ | -fuse-ld=gold)-                ;;-            *)-                args+=$arg-                ;;-        esac-    done-}--process $*--exec g++ -static-libgcc -static-libstdc++ $args
− misc/test.hs
@@ -1,161 +0,0 @@-{-# LANGUAGE TemplateHaskell, FlexibleInstances, FlexibleContexts, UndecidableInstances, StandaloneDeriving, ScopedTypeVariables, TupleSections, DeriveGeneric #-}-import Twee.Constraints-import Twee.Term hiding (subst, canonicalise, F)-import Twee.Term.Core hiding (F)-import Test.QuickCheck hiding (Function, Fun)-import Test.QuickCheck.All-import Twee.Pretty-import Twee.CP-import Twee.Proof-import qualified Twee.KBO as Ord-import Text.PrettyPrint-import Twee.Base hiding (F)-import Twee.Rule-import Twee.Equation-import Control.Monad-import qualified Data.Map as Map-import Data.Maybe-import Data.Ord-import Data.List-import Data.Typeable-import qualified Twee.Index as Index-import Data.Int-import GHC.Generics--newtype Func = F Int deriving (Eq, Ord, Show)--instance Pretty Func where pPrint (F f) = text "f" <> int f-instance PrettyTerm Func-instance Arbitrary (Subst Func) where-  arbitrary = fmap fromJust (fmap listToSubst (liftM2 zip (fmap nub arbitrary) (infiniteListOf arbitrary)))-instance Arbitrary Func where-  arbitrary = F <$> choose (1, 1)-instance Minimal Func where-  minimal = fun (F 0)-instance Sized Func where size _ = 1-instance Arity Func where-  arity (F 0) = 0-  arity (F 1) = 2-instance Skolem Func-instance EqualsBonus Func--instance Arbitrary Var where arbitrary = fmap V (choose (0, 3))-instance (Ord f, Typeable f, Arbitrary f) => Arbitrary (Fun f) where-  arbitrary = fmap fun arbitrary--instance (Ord f, Typeable f, Arbitrary f, Sized f, Arity f) => Arbitrary (Term f) where-  arbitrary =-    sized $ \n ->-      oneof $-        [ build <$> var <$> arbitrary ] ++-        [ do { f <- arbitrary; build <$> app f <$> vectorOf (arity f) (resize ((n-1) `div` arity f) arbitrary :: Gen (Term f)) } | n > 0 ]-  shrink (App f ts0) =-    ts ++ (build <$> app f <$> shrinkOne ts)-    where-      ts = unpack ts0-      shrinkOne [] = []-      shrinkOne (x:xs) =-        [ y:xs | y <- shrink x ] ++-        [ x:ys | ys <- shrinkOne xs ]-  shrink _ = []--data Pair f = Pair (Term f) (Term f) deriving Show--instance (Ord f, Typeable f, Arbitrary f, Arity f, Sized f) => Arbitrary (Pair f) where-  arbitrary = liftM2 Pair arbitrary arbitrary-  shrink (Pair x y) =-    [ Pair x' y  | x' <- shrink x ] ++-    [ Pair x y'  | y' <- shrink y ] ++-    [ Pair x' y' | x' <- shrink x, y' <- shrink y ]--instance Ordered Func where-  lessIn = Ord.lessIn-  lessEq = Ord.lessEq--instance Function f => Arbitrary (Model f) where-  arbitrary = fmap (modelFromOrder . map Variable . nub) arbitrary-  shrink = weakenModel--prop_1 :: Model Func -> Pair Func -> Subst Func -> Property-prop_1 model (Pair t u) sub =-  counterexample ("Model: " ++ prettyShow model) $-  counterexample ("Subst: " ++ prettyShow sub) $-  conjoin $ do-    let cp = CriticalPair (t :=: u) 0 Nothing (axiom (Axiom 0 "dummy" (t :=: u)))-    r@(Rule _ t' u') <- map orient (map cp_eqn (split cp))-    return $-      counterexample ("LHS:   " ++ prettyShow t') $-      counterexample ("RHS:   " ++ prettyShow u') $-      counterexample ("Rule:  " ++ prettyShow r) $-      counterexample ("Inst:  " ++ prettyShow (Rule Oriented (subst sub t') (subst sub u'))) $-      counterexample ("Res:   " ++ show (lessIn model (subst sub u') (subst sub t'))) $-      not (reducesInModel model r sub) || isJust (lessIn model (subst sub u') (subst sub t'))--prop_2 :: Model Func -> Pair Func -> Bool-prop_2 model (Pair t u) =-  not (lessIn model t u == Just Strict && isJust (lessIn model u t))--prop_3 :: Pair Func -> Bool-prop_3 (Pair t u) =-  not (lessThan t u && lessEq u t)--prop_4 :: Pair Func -> Property-prop_4 (Pair t u) =-  t /= u ==> -  not (lessEq t u && lessEq u t)--prop_5 :: Term Func -> Property-prop_5 t =-  lessEq t t .&&. not (lessThan t t)--prop_paths :: Term Func -> Property-prop_paths t =-  forAllShrink (choose (0, len t-1)) shrink $ \n ->-    counterexample (show (positionToPath t n)) $-    pathToPosition t (positionToPath t n) === n--deriving instance Ord f => Ord (Subst f)--prop_index :: [Term Func] -> Term Func -> Property-prop_index ts u =-  counterexample (show ts) $-  counterexample (show idx) $-  sort (catMaybes [fmap (,t) (match t u) | t <- ts]) ===-  sort (Index.matches u idx)-  where-    idx = foldr (\t -> Index.insert t t) Index.empty ts--deriving instance Eq Symbol-deriving instance Generic Symbol--instance Arbitrary Symbol where-  arbitrary =-    Symbol <$>-      arbitrary <*>-      fmap getLarge arbitrary <*>-      (fmap (fromIntegral . getLarge) (arbitrary :: Gen (Large Int32)) `suchThat` (> 0) `suchThat` (< 2^31))-  shrink s =-    filter ok (genericShrink s)-    where-      ok s = Twee.Term.Core.size s > 0--prop_symbol_1 :: Symbol -> Property-prop_symbol_1 s =-  withMaxSuccess 100000 $-  counterexample ("fun/index/size = " ++ show (isFun s, index s, Twee.Term.Core.size s)) $-  counterexample ("n = " ++ show (fromSymbol s)) $-  toSymbol (fromSymbol s) === twiddle s-  where-    twiddle s =-      s { index = fromIntegral (fromIntegral (index s) :: Int32) }--prop_symbol_2 :: Int64 -> Property-prop_symbol_2 n =-  withMaxSuccess 100000 $-  fromSymbol (toSymbol n) === n--return []-main = $forAllProperties (quickCheckWithResult stdArgs { maxSuccess = 1000000 })--t :: Term Func-t = build (app (fun (F 0)) [app (fun (F 1)) [var (V 0), var (V 1)], var (V 2)])
− src/Data/ChurchList.hs
@@ -1,99 +0,0 @@--- Church-encoded lists. Used in Twee.CP to make sure that fusion happens.-{-# LANGUAGE Rank2Types, BangPatterns #-}-module Data.ChurchList where--import Prelude(Functor(..), Applicative(..), Monad(..), Bool(..), Maybe(..), (.), ($), id)-import qualified Prelude-import GHC.Magic(oneShot)-import GHC.Exts(build)-import Control.Monad(MonadPlus(..), liftM2)-import Control.Applicative(Alternative(..))--newtype ChurchList a =-  ChurchList (forall b. (a -> b -> b) -> b -> b)--{-# INLINE foldr #-}-foldr :: (a -> b -> b) -> b -> ChurchList a -> b-foldr op e (ChurchList f) = eta (f op (eta e))-  -- Using eta here seems to help with eta-expanding foldl'--{-# INLINE[0] eta #-}-eta :: a -> a-eta x = x-{-# RULES "eta" forall f. eta f = \x -> f x #-}--{-# INLINE nil #-}-nil :: ChurchList a-nil = ChurchList (\_ n -> n)--{-# INLINE unit #-}-unit :: a -> ChurchList a-unit x = ChurchList (\c n -> c x n)--{-# INLINE cons #-}-cons :: a -> ChurchList a -> ChurchList a-cons x xs = ChurchList (\c n -> c x (foldr c n xs))--{-# INLINE append #-}-append :: ChurchList a -> ChurchList a -> ChurchList a-append xs ys = ChurchList (\c n -> foldr c (foldr c n ys) xs)--{-# INLINE join #-}-join :: ChurchList (ChurchList a) -> ChurchList a-join xss = ChurchList (\c n -> foldr (\xs ys -> foldr c ys xs) n xss)--instance Functor ChurchList where-  {-# INLINE fmap #-}-  fmap f xs = ChurchList (\c n -> foldr (c . f) n xs)--instance Applicative ChurchList where-  {-# INLINE pure #-}-  pure = return-  {-# INLINE (<*>) #-}-  (<*>) = liftM2 ($)--instance Monad ChurchList where-  {-# INLINE return #-}-  return = unit-  {-# INLINE (>>=) #-}-  xs >>= f = join (fmap f xs)--instance Alternative ChurchList where-  {-# INLINE empty #-}-  empty = nil-  {-# INLINE (<|>) #-}-  (<|>) = append--instance MonadPlus ChurchList where-  {-# INLINE mzero #-}-  mzero = empty-  {-# INLINE mplus #-}-  mplus = (<|>)--{-# INLINE fromList #-}-fromList :: [a] -> ChurchList a-fromList xs = ChurchList (\c n -> Prelude.foldr c n xs)--{-# INLINE toList #-}-toList :: ChurchList a -> [a]-toList (ChurchList f) = build f--{-# INLINE foldl' #-}-foldl' :: (b -> a -> b) -> b -> ChurchList a -> b-foldl' op e xs =-  foldr (\x f -> oneShot (\ (!acc) -> f (op acc x))) id xs e--{-# INLINE filter #-}-filter :: (a -> Bool) -> ChurchList a -> ChurchList a-filter p xs =-  ChurchList $ \c n ->-    let            -      {-# INLINE op #-}-      op x xs = if p x then c x xs else xs-    in-      foldr op n xs--{-# INLINE fromMaybe #-}-fromMaybe :: Maybe a -> ChurchList a-fromMaybe Nothing = nil-fromMaybe (Just x) = unit x
− src/Data/DynamicArray.hs
@@ -1,67 +0,0 @@--- | Zero-indexed dynamic arrays, optimised for lookup.--- Modification is slow. Uninitialised indices have a default value.-{-# LANGUAGE CPP #-}-module Data.DynamicArray where--#ifdef BOUNDS_CHECKS-import qualified Data.Primitive.SmallArray.Checked as P-#else-import qualified Data.Primitive.SmallArray as P-#endif-import Control.Monad.ST-import Data.List---- | A type which has a default value.-class Default a where-  -- | The default value.-  def :: a---- | An array.-data Array a =-  Array {-    -- | The size of the array.-    arraySize     :: {-# UNPACK #-} !Int,-    -- | The contents of the array.-    arrayContents :: {-# UNPACK #-} !(P.SmallArray a) }---- | Convert an array to a list of (index, value) pairs.-{-# INLINE toList #-}-toList :: Array a -> [(Int, a)]-toList arr =-  [ (i, x)-  | i <- [0..arraySize arr-1],-    let x = P.indexSmallArray (arrayContents arr) i ]--instance Show a => Show (Array a) where-  show arr =-    "{" ++-    intercalate ", "-      [ show i ++ "->" ++ show x-      | (i, x) <- toList arr ] ++-    "}"---- | Create an empty array.-newArray :: Default a => Array a-newArray = runST $ do-  marr <- P.newSmallArray 0 def-  arr  <- P.unsafeFreezeSmallArray marr-  return (Array 0 arr)---- | Index into an array. O(1) time.-{-# INLINE (!) #-}-(!) :: Default a => Array a -> Int -> a-arr ! n-  | 0 <= n && n < arraySize arr =-    P.indexSmallArray (arrayContents arr) n-  | otherwise = def---- | Update the array. O(n) time.-{-# INLINEABLE update #-}-update :: Default a => Int -> a -> Array a -> Array a-update n x arr = runST $ do-  let size = arraySize arr `max` (n+1)-  marr <- P.newSmallArray size def-  P.copySmallArray marr 0 (arrayContents arr) 0 (arraySize arr)-  P.writeSmallArray marr n $! x-  arr' <- P.unsafeFreezeSmallArray marr-  return (Array size arr')
− src/Data/Heap.hs
@@ -1,154 +0,0 @@--- | Skew heaps.--{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}-module Data.Heap(-  Heap, empty, singleton, insert, removeMin, union, mapMaybe, size) where---- | A heap.---- Representation: the size of the heap, and the heap itself.-data Heap a = Heap {-# UNPACK #-} !Int !(Heap1 a) deriving Show--- N.B.: arguments are not strict so code has to take care--- to force stuff appropriately.-data Heap1 a = Nil | Node a (Heap1 a) (Heap1 a) deriving Show---- | Take the union of two heaps.-{-# INLINEABLE union #-}-union :: Ord a => Heap a -> Heap a -> Heap a-union (Heap n1 h1) (Heap n2 h2) = Heap (n1+n2) (union1 h1 h2)--{-# INLINEABLE union1 #-}-union1 :: forall a. Ord a => Heap1 a -> Heap1 a -> Heap1 a-union1 = u1-  where-    -- The generated code is better when we do everything-    -- through this u1 function instead of union1...-    -- This is because u1 has no Ord constraint in its type.-    u1 :: Heap1 a -> Heap1 a -> Heap1 a-    u1 Nil h = h-    u1 h Nil = h-    u1 h1@(Node x1 l1 r1) h2@(Node x2 l2 r2)-      | x1 <= x2 = (Node x1 $! u1 r1 h2) l1-      | otherwise = (Node x2 $! u1 r2 h1) l2---- | A singleton heap.-{-# INLINE singleton #-}-singleton :: a -> Heap a-singleton !x = Heap 1 (Node x Nil Nil)---- | The empty heap.-{-# INLINE empty #-}-empty :: Heap a-empty = Heap 0 Nil---- | Insert an element.-{-# INLINEABLE insert #-}-insert :: Ord a => a -> Heap a -> Heap a-insert x h = union (singleton x) h---- | Find and remove the minimum element.-{-# INLINEABLE removeMin #-}-removeMin :: Ord a => Heap a -> Maybe (a, Heap a)-removeMin (Heap _ Nil) = Nothing-removeMin (Heap n (Node x l r)) = Just (x, Heap (n-1) (union1 l r))---- | Map a function over a heap, removing all values which--- map to 'Nothing'. May be more efficient when the function--- being mapped is mostly monotonic.-{-# INLINEABLE mapMaybe #-}-mapMaybe :: Ord b => (a -> Maybe b) -> Heap a -> Heap b-mapMaybe f (Heap _ h) = Heap (sz 0 h') h'-  where-    -- Compute the size fairly efficiently.-    sz !n Nil = n-    sz !n (Node _ l r) = sz (sz (n+1) l) r--    h' = mm h--    mm Nil = Nil-    mm (Node x l r) =-      case f x of-        -- If the value maps to Nothing, get rid of it.-        Nothing -> union1 l' r'-        -- Otherwise, check if the heap invariant still holds-        -- and sift downwards to restore it.-        Just !y -> down y l' r'-      where-        !l' = mm l-        !r' = mm r--    down x l@(Node y ll lr) r@(Node z rl rr)-      -- Put the smallest of x, y and z at the root.-      | y < x && y <= z =-        (Node y $! down x ll lr) r-      | z < x && z <= y =-        Node z l $! down x rl rr-    down x Nil (Node y l r)-      -- Put the smallest of x and y at the root.-      | y < x =-        Node y Nil $! down x l r-    down x (Node y l r) Nil-      -- Put the smallest of x and y at the root.-      | y < x =-        (Node y $! down x l r) Nil-    down x l r = Node x l r---- | Return the number of elements in the heap.-{-# INLINE size #-}-size :: Heap a -> Int-size (Heap n _) = n---- Testing code:--- import Test.QuickCheck--- import qualified Data.List as List--- import qualified Data.Maybe as Maybe---- instance (Arbitrary a, Ord a) => Arbitrary (Heap a) where---   arbitrary = sized arb---     where---       arb 0 = return empty---       arb n =---         frequency---           [(1, singleton <$> arbitrary),---            (n-1, union <$> arb' <*> arb')]---         where---           arb' = arb (n `div` 2)---- toList :: Ord a => Heap a -> [a]--- toList = List.unfoldr removeMin---- invariant :: Ord a => Heap a -> Bool--- invariant h@(Heap n h1) =---   n == length (toList h) && ord h1---   where---     ord Nil = True---     ord (Node x l r) = ord1 x l && ord1 x r----     ord1 _ Nil = True---     ord1 x h@(Node y _ _) = x <= y && ord h---- prop_1 h = withMaxSuccess 10000 $ invariant h--- prop_2 x h = withMaxSuccess 10000 $ invariant (insert x h)--- prop_3 h =---   withMaxSuccess 1000 $---   case removeMin h of---     Nothing -> discard---     Just (_, h) -> invariant h--- prop_4 h = withMaxSuccess 10000 $ List.sort (toList h) == toList h--- prop_5 x h = withMaxSuccess 10000 $ toList (insert x h) == List.insert x (toList h)--- prop_6 x h =---   withMaxSuccess 1000 $---   case removeMin h of---     Nothing -> discard---     Just (x, h') -> toList h == List.insert x (toList h')--- prop_7 h1 h2 = withMaxSuccess 10000 $---   invariant (union h1 h2)--- prop_8 h1 h2 = withMaxSuccess 10000 $---   toList (union h1 h2) == List.sort (toList h1 ++ toList h2)--- prop_9 (Blind f) h = withMaxSuccess 10000 $---   invariant (mapMaybe f h)--- prop_10 (Blind f) h = withMaxSuccess 1000000 $---   toList (mapMaybe f h) == List.sort (Maybe.mapMaybe f (toList h))---- return []--- main = $quickCheckAll
− src/Data/Primitive/ByteArray/Checked.hs
@@ -1,74 +0,0 @@--- | A bounds-checked version of 'Data.Primitive.ByteArray'.--- See that module for documentation.--{-# LANGUAGE ScopedTypeVariables #-}-module Data.Primitive.ByteArray.Checked(-  module Data.Primitive.ByteArray,-  module Data.Primitive.ByteArray.Checked) where--import Control.Monad.Primitive-import qualified Data.Primitive.ByteArray as P-import Data.Primitive(Prim)-import Data.Primitive.ByteArray(-  ByteArray(..), MutableByteArray(..),-  newByteArray, newPinnedByteArray, newAlignedPinnedByteArray,-  byteArrayContents, mutableByteArrayContents,-  sameMutableByteArray,-  unsafeFreezeByteArray, unsafeThawByteArray,-  sizeofByteArray, sizeofMutableByteArray)-import Data.Primitive.Checked-import Data.Word--instance Sized ByteArray where-  size = sizeofByteArray-instance Sized (MutableByteArray m) where-  size = sizeofMutableByteArray--{-# INLINE readByteArray #-}-readByteArray :: forall m a. (PrimMonad m, Prim a) => MutableByteArray (PrimState m) -> Int -> m a-readByteArray arr n =-  checkPrim (undefined :: a) arr n $-  P.readByteArray arr n--{-# INLINE writeByteArray #-}-writeByteArray :: (PrimMonad m, Prim a) => MutableByteArray (PrimState m) -> Int -> a -> m ()-writeByteArray arr n x =-  checkPrim x arr n $-  P.writeByteArray arr n x--{-# INLINE indexByteArray #-}-indexByteArray :: forall a. Prim a => ByteArray -> Int -> a-indexByteArray arr n =-  checkPrim (undefined :: a) arr n $-  P.indexByteArray arr n--{-# INLINE copyByteArray #-}-copyByteArray :: PrimMonad m => MutableByteArray (PrimState m) -> Int -> ByteArray -> Int -> Int -> m ()-copyByteArray arr1 n1 arr2 n2 len =-  range arr1 n1 len $-  range arr2 n2 len $-  P.copyByteArray arr1 n1 arr2 n2 len--{-# INLINE moveByteArray #-}-moveByteArray :: PrimMonad m => MutableByteArray (PrimState m) -> Int -> MutableByteArray (PrimState m) -> Int -> Int -> m ()-moveByteArray arr1 n1 arr2 n2 len =-  range arr1 n1 len $-  range arr2 n2 len $-  P.moveByteArray arr1 n1 arr2 n2 len--{-# INLINE copyMutableByteArray #-}-copyMutableByteArray :: PrimMonad m => MutableByteArray (PrimState m) -> Int -> MutableByteArray (PrimState m) -> Int -> Int -> m ()-copyMutableByteArray arr1 n1 arr2 n2 len =-  range arr1 n1 len $-  range arr2 n2 len $-  P.copyMutableByteArray arr1 n1 arr2 n2 len--{-# INLINE setByteArray #-}-setByteArray :: (Prim a, PrimMonad m) => MutableByteArray (PrimState m) -> Int -> Int -> a -> m ()-setByteArray arr n len x =-  rangePrim x arr n len $-  P.setByteArray arr n len x--{-# INLINE fillByteArray #-}-fillByteArray :: PrimMonad m => MutableByteArray (PrimState m) -> Int -> Int -> Word8 -> m ()-fillByteArray = setByteArray
− src/Data/Primitive/Checked.hs
@@ -1,46 +0,0 @@--- | A helper module for array bounds checking.--module Data.Primitive.Checked where--import Data.Primitive(Prim, sizeOf)---- | A type class of things which have a size (e.g., arrays).-class Sized a where-  -- | Read the size of the thing.-  size :: a -> Int---- | Check that a single access is in bounds.-{-# INLINE check #-}-check :: Sized a => a -> Int -> b -> b-check arr n x-  | n >= 0 && n < size arr = x-  | otherwise = error "out-of-bounds array access"---- | Check that a range of accesses is in bounds.--- The range is inclusive.-{-# INLINE range #-}-range :: Sized a => a -> Int -> Int -> b -> b-range arr n len x-  | len < 0 = error "array slice has negative length"-  | len == 0 = x-  | otherwise =-    check arr n $-    check arr (n+len-1) $ x---- | Check that a single access is in bounds.--- The index accessed is computed by multiplying by the size--- of the first argument.-{-# INLINE checkPrim #-}-checkPrim :: (Sized a, Prim b) => b -> a -> Int -> c -> c-checkPrim x arr n res =-  range arr (n*sizeOf x) (sizeOf x) res-  --- | Check that a range of accesses is in bounds.--- The range is inclusive.--- The index accessed is computed by multiplying by the size--- of the first argument.-{-# INLINE rangePrim #-}-rangePrim :: (Sized a, Prim b) => b -> a -> Int -> Int -> c -> c-rangePrim x arr n len res =-  range arr (n*sizeOf x) (len*sizeOf x) res-  
− src/Data/Primitive/SmallArray/Checked.hs
@@ -1,80 +0,0 @@--- | A bounds-checked version of 'Data.Primitive.SmallArray'.--- See that module for documentation.--module Data.Primitive.SmallArray.Checked(-  module Data.Primitive.SmallArray,-  module Data.Primitive.SmallArray.Checked) where--import Control.Monad.Primitive-import qualified Data.Primitive.SmallArray as P-import Data.Primitive.SmallArray(-  SmallArray(..), SmallMutableArray(..), newSmallArray, unsafeFreezeSmallArray,-  unsafeThawSmallArray, sizeofSmallArray, sizeofSmallMutableArray)-import Data.Primitive.Checked--instance Sized (SmallArray a) where-  size = sizeofSmallArray-instance Sized (SmallMutableArray m a) where-  size = sizeofSmallMutableArray--{-# INLINE readSmallArray #-}-readSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> m a-readSmallArray arr n =-  check arr n $-  P.readSmallArray arr n--{-# INLINE writeSmallArray #-}-writeSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> a -> m ()-writeSmallArray arr n x =-  check arr n $-  P.writeSmallArray arr n x--{-# INLINE indexSmallArrayM #-}-indexSmallArrayM :: Monad m => SmallArray a -> Int -> m a-indexSmallArrayM arr n =-  check arr n $-  P.indexSmallArrayM arr n--{-# INLINE indexSmallArray #-}-indexSmallArray :: SmallArray a -> Int -> a-indexSmallArray arr n =-  check arr n $-  P.indexSmallArray arr n--{-# INLINE cloneSmallArray #-}-cloneSmallArray :: SmallArray a -> Int -> Int -> SmallArray a-cloneSmallArray arr n len =-  range arr n len $-  P.cloneSmallArray arr n len--{-# INLINE cloneSmallMutableArray #-}-cloneSmallMutableArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> Int -> m (SmallMutableArray (PrimState m) a)-cloneSmallMutableArray arr n len =-  range arr n len $-  P.cloneSmallMutableArray arr n len--{-# INLINE freezeSmallArray #-}-freezeSmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> Int -> m (SmallArray a)-freezeSmallArray arr n len =-  range arr n len $-  P.freezeSmallArray arr n len--{-# INLINE thawSmallArray #-}-thawSmallArray :: PrimMonad m => SmallArray a -> Int -> Int -> m (SmallMutableArray (PrimState m) a)-thawSmallArray arr n len =-  range arr n len $-  P.thawSmallArray arr n len--{-# INLINE copySmallArray #-}-copySmallArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> SmallArray a -> Int -> Int -> m ()-copySmallArray arr1 n1 arr2 n2 len =-  range arr1 n1 len $-  range arr2 n2 len $-  P.copySmallArray arr1 n1 arr2 n2 len--{-# INLINE copySmallMutableArray #-}-copySmallMutableArray :: PrimMonad m => SmallMutableArray (PrimState m) a -> Int -> SmallMutableArray (PrimState m) a -> Int -> Int -> m ()-copySmallMutableArray arr1 n1 arr2 n2 len =-  range arr1 n1 len $-  range arr2 n2 len $-  P.copySmallMutableArray arr1 n1 arr2 n2 len
− src/Twee.hs
@@ -1,610 +0,0 @@--- | The main prover loop.-{-# LANGUAGE RecordWildCards, MultiParamTypeClasses, GADTs, BangPatterns, OverloadedStrings, ScopedTypeVariables, GeneralizedNewtypeDeriving, PatternGuards, TypeFamilies #-}-module Twee where--import Twee.Base-import Twee.Rule-import Twee.Equation-import qualified Twee.Proof as Proof-import Twee.Proof(Proof, Axiom(..), Lemma(..), ProvedGoal(..), provedGoal, certify, derivation, symm)-import Twee.CP hiding (Config)-import qualified Twee.CP as CP-import Twee.Join hiding (Config, defaultConfig)-import qualified Twee.Join as Join-import qualified Twee.Rule.Index as RuleIndex-import Twee.Rule.Index(RuleIndex(..))-import qualified Twee.Index as Index-import Twee.Index(Index)-import Twee.Constraints-import Twee.Utils-import Twee.Task-import qualified Twee.PassiveQueue as Queue-import Twee.PassiveQueue(Queue, Passive(..))-import qualified Data.IntMap.Strict as IntMap-import Data.IntMap(IntMap)-import Data.Maybe-import Data.List-import Data.Function-import qualified Data.Set as Set-import Data.Set(Set)-import Data.Int-import Data.Ord-import Control.Monad-import Control.Monad.IO.Class-import Control.Monad.Trans.Class-import qualified Control.Monad.Trans.State.Strict as StateM--------------------------------------------------------------------------- * Configuration and prover state.--------------------------------------------------------------------------- | The prover configuration.-data Config =-  Config {-    cfg_max_term_size          :: Int,-    cfg_max_critical_pairs     :: Int64,-    cfg_max_cp_depth           :: Int,-    cfg_simplify               :: Bool,-    cfg_renormalise_percent    :: Int,-    cfg_critical_pairs         :: CP.Config,-    cfg_join                   :: Join.Config,-    cfg_proof_presentation     :: Proof.Config }---- | The prover state.-data State f =-  State {-    st_rules          :: !(RuleIndex f (ActiveRule f)),-    st_active_ids     :: !(IntMap (Active f)),-    st_rule_ids       :: !(IntMap (ActiveRule f)),-    st_joinable       :: !(Index f (Equation f)),-    st_goals          :: ![Goal f],-    st_queue          :: !(Queue Params),-    st_next_active    :: {-# UNPACK #-} !Id,-    st_next_rule      :: {-# UNPACK #-} !RuleId,-    st_considered     :: {-# UNPACK #-} !Int64,-    st_messages_rev   :: ![Message f] }---- | The default prover configuration.-defaultConfig :: Config-defaultConfig =-  Config {-    cfg_max_term_size = maxBound,-    cfg_max_critical_pairs = maxBound,-    cfg_max_cp_depth = maxBound,-    cfg_simplify = True,-    cfg_renormalise_percent = 5,-    cfg_critical_pairs = CP.defaultConfig,-    cfg_join = Join.defaultConfig,-    cfg_proof_presentation = Proof.defaultConfig }---- | Does this configuration run the prover in a complete mode?-configIsComplete :: Config -> Bool-configIsComplete Config{..} =-  cfg_max_term_size == maxBound &&-  cfg_max_critical_pairs == maxBound &&-  cfg_max_cp_depth == maxBound---- | The initial state.-initialState :: State f-initialState =-  State {-    st_rules = RuleIndex.empty,-    st_active_ids = IntMap.empty,-    st_rule_ids = IntMap.empty,-    st_joinable = Index.empty,-    st_goals = [],-    st_queue = Queue.empty,-    st_next_active = 1,-    st_next_rule = 0,-    st_considered = 0,-    st_messages_rev = [] }--------------------------------------------------------------------------- * Messages.--------------------------------------------------------------------------- | A message which is produced by the prover when something interesting happens.-data Message f =-    -- | A new rule.-    NewActive !(Active f)-    -- | A new joinable equation.-  | NewEquation !(Equation f)-    -- | A rule was deleted.-  | DeleteActive !(Active f)-    -- | The CP queue was simplified.-  | SimplifyQueue-    -- | The rules were reduced wrt each other.-  | Interreduce--instance Function f => Pretty (Message f) where-  pPrint (NewActive rule) = pPrint rule-  pPrint (NewEquation eqn) =-    text "  (hard)" <+> pPrint eqn-  pPrint (DeleteActive rule) =-    text "  (delete rule " <> pPrint (active_id rule) <> text ")"-  pPrint SimplifyQueue =-    text "  (simplifying queued critical pairs...)"-  pPrint Interreduce =-    text "  (simplifying rules with respect to one another...)"---- | Emit a message.-message :: PrettyTerm f => Message f -> State f -> State f-message !msg state@State{..} =-  state { st_messages_rev = msg:st_messages_rev }---- | Forget about all emitted messages.-clearMessages :: State f -> State f-clearMessages state@State{..} =-  state { st_messages_rev = [] }---- | Get all emitted messages.-messages :: State f -> [Message f]-messages state = reverse (st_messages_rev state)--------------------------------------------------------------------------- * The CP queue.-------------------------------------------------------------------------data Params-instance Queue.Params Params where-  type Score Params = Int-  type Id Params = RuleId-  type PackedId Params = Int32-  type PackedScore Params = Int32-  packScore _ = fromIntegral-  unpackScore _ = fromIntegral-  packId _ = fromIntegral-  unpackId _ = fromIntegral---- | Compute all critical pairs from a rule.-{-# INLINEABLE makePassives #-}-makePassives :: Function f => Config -> State f -> ActiveRule f -> [Passive Params]-makePassives Config{..} State{..} rule =-  {-# SCC makePassive #-}-  [ Passive (fromIntegral (score cfg_critical_pairs o)) (rule_rid rule1) (rule_rid rule2) (fromIntegral (overlap_pos o))-  | (rule1, rule2, o) <- overlaps (Depth cfg_max_cp_depth) (index_oriented st_rules) rules rule ]-  where-    rules = IntMap.elems st_rule_ids---- | Turn a Passive back into an overlap.--- Doesn't try to simplify it.-{-# INLINEABLE findPassive #-}-findPassive :: forall f. Function f => Config -> State f -> Passive Params -> Maybe (ActiveRule f, ActiveRule f, Overlap f)-findPassive Config{..} State{..} Passive{..} = {-# SCC findPassive #-} do-  rule1 <- IntMap.lookup (fromIntegral passive_rule1) st_rule_ids-  rule2 <- IntMap.lookup (fromIntegral passive_rule2) st_rule_ids-  let !depth = 1 + max (the rule1) (the rule2)-  overlap <--    overlapAt (fromIntegral passive_pos) depth-      (renameAvoiding (the rule2 :: Rule f) (the rule1)) (the rule2)-  return (rule1, rule2, overlap)---- | Renormalise a queued Passive.-{-# INLINEABLE simplifyPassive #-}-simplifyPassive :: Function f => Config -> State f -> Passive Params -> Maybe (Passive Params)-simplifyPassive config@Config{..} state@State{..} passive = {-# SCC simplifyPassive #-} do-  (_, _, overlap) <- findPassive config state passive-  overlap <- simplifyOverlap (index_oriented st_rules) overlap-  return passive {-    passive_score = fromIntegral $-      fromIntegral (passive_score passive) `intMin`-      score cfg_critical_pairs overlap }---- | Renormalise the entire queue.-{-# INLINEABLE simplifyQueue #-}-simplifyQueue :: Function f => Config -> State f -> State f-simplifyQueue config state =-  {-# SCC simplifyQueue #-}-  state { st_queue = simp (st_queue state) }-  where-    simp =-      Queue.mapMaybe (simplifyPassive config state)---- | Enqueue a set of critical pairs.-{-# INLINEABLE enqueue #-}-enqueue :: Function f => State f -> RuleId -> [Passive Params] -> State f-enqueue state rule passives =-  {-# SCC enqueue #-}-  state { st_queue = Queue.insert rule passives (st_queue state) }---- | Dequeue a critical pair.------ Also takes care of:------   * removing any orphans from the head of the queue---   * ignoring CPs that are too big-{-# INLINEABLE dequeue #-}-dequeue :: Function f => Config -> State f -> (Maybe (CriticalPair f, ActiveRule f, ActiveRule f), State f)-dequeue config@Config{..} state@State{..} =-  {-# SCC dequeue #-}-  case deq 0 st_queue of-    -- Explicitly make the queue empty, in case it e.g. contained a-    -- lot of orphans-    Nothing -> (Nothing, state { st_queue = Queue.empty })-    Just (overlap, n, queue) ->-      (Just overlap,-       state { st_queue = queue, st_considered = st_considered + n })-  where-    deq !n queue = do-      (passive, queue) <- Queue.removeMin queue-      case findPassive config state passive of-        Just (rule1, rule2, overlap)-          | passive_score passive >= 0,-            Just Overlap{overlap_eqn = t :=: u} <--              simplifyOverlap (index_oriented st_rules) overlap,-            size t <= cfg_max_term_size,-            size u <= cfg_max_term_size,-            Just cp <- makeCriticalPair rule1 rule2 overlap ->-              return ((cp, rule1, rule2), n+1, queue)-        _ -> deq (n+1) queue--------------------------------------------------------------------------- * Active rewrite rules.-------------------------------------------------------------------------data Active f =-  Active {-    active_id    :: {-# UNPACK #-} !Id,-    active_depth :: {-# UNPACK #-} !Depth,-    active_rule  :: {-# UNPACK #-} !(Rule f),-    active_top   :: !(Maybe (Term f)),-    active_proof :: {-# UNPACK #-} !(Proof f),-    -- A model in which the rule is false (used when reorienting)-    active_model :: !(Model f),-    active_rules :: ![ActiveRule f] }--active_cp :: Active f -> CriticalPair f-active_cp Active{..} =-  CriticalPair {-    cp_eqn = unorient active_rule,-    cp_depth = active_depth,-    cp_top = active_top,-    cp_proof = derivation active_proof }---- An active oriented in a particular direction.-data ActiveRule f =-  ActiveRule {-    rule_active    :: {-# UNPACK #-} !Id,-    rule_rid       :: {-# UNPACK #-} !RuleId,-    rule_depth     :: {-# UNPACK #-} !Depth,-    rule_rule      :: {-# UNPACK #-} !(Rule f),-    rule_proof     :: {-# UNPACK #-} !(Proof f),-    rule_positions :: !(Positions f) }--instance PrettyTerm f => Symbolic (ActiveRule f) where-  type ConstantOf (ActiveRule f) = f-  termsDL ActiveRule{..} =-    termsDL rule_rule `mplus`-    termsDL (derivation rule_proof)-  subst_ sub r@ActiveRule{..} =-    r {-      rule_rule = rule',-      rule_proof = certify (subst_ sub (derivation rule_proof)),-      rule_positions = positions (lhs rule') }-    where-      rule' = subst_ sub rule_rule--instance Eq (Active f) where-  (==) = (==) `on` active_id--instance Eq (ActiveRule f) where-  (==) = (==) `on` rule_rid--instance Function f => Pretty (Active f) where-  pPrint Active{..} =-    pPrint active_id <> text "." <+> pPrint (canonicalise active_rule)--instance Has (ActiveRule f) Id where the = rule_active-instance Has (ActiveRule f) RuleId where the = rule_rid-instance Has (ActiveRule f) Depth where the = rule_depth-instance f ~ g => Has (ActiveRule f) (Rule g) where the = rule_rule-instance f ~ g => Has (ActiveRule f) (Proof g) where the = rule_proof-instance f ~ g => Has (ActiveRule f) (Lemma g) where the x = Lemma (the x) (the x)-instance f ~ g => Has (ActiveRule f) (Positions g) where the = rule_positions--newtype RuleId = RuleId Id deriving (Eq, Ord, Show, Num, Real, Integral, Enum)---- Add a new active.-{-# INLINEABLE addActive #-}-addActive :: Function f => Config -> State f -> (Id -> RuleId -> RuleId -> Active f) -> State f-addActive config state@State{..} active0 =-  {-# SCC addActive #-}-  let-    active@Active{..} = active0 st_next_active st_next_rule (succ st_next_rule)-    state' =-      message (NewActive active) $-      addActiveOnly state{st_next_active = st_next_active+1, st_next_rule = st_next_rule+2} active-  in if subsumed st_joinable st_rules (unorient active_rule) then-    state-  else-    normaliseGoals $-    foldl' (uncurry . enqueue) state'-      [ (the rule, makePassives config state' rule)-      | rule <- active_rules ]---- Add an active without generating critical pairs. Used in interreduction.-{-# INLINEABLE addActiveOnly #-}-addActiveOnly :: Function f => State f -> Active f -> State f-addActiveOnly state@State{..} active@Active{..} =-  state {-    st_rules = foldl' insertRule st_rules active_rules,-    st_active_ids = IntMap.insert (fromIntegral active_id) active st_active_ids,-    st_rule_ids = foldl' insertRuleId st_rule_ids active_rules }-  where-    insertRule rules rule@ActiveRule{..} =-      RuleIndex.insert (lhs rule_rule) rule rules-    insertRuleId rules rule@ActiveRule{..} =-      IntMap.insert (fromIntegral rule_rid) rule rules---- Delete an active. Used in interreduction, not suitable for general use.-{-# INLINE deleteActive #-}-deleteActive :: Function f => State f -> Active f -> State f-deleteActive state@State{..} Active{..} =-  state {-    st_rules = foldl' deleteRule st_rules active_rules,-    st_active_ids = IntMap.delete (fromIntegral active_id) st_active_ids,-    st_rule_ids = foldl' deleteRuleId st_rule_ids active_rules }-  where-    deleteRule rules rule =-      RuleIndex.delete (lhs (rule_rule rule)) rule rules-    deleteRuleId rules ActiveRule{..} =-      IntMap.delete (fromIntegral rule_rid) rules---- Try to join a critical pair.-{-# INLINEABLE consider #-}-consider :: Function f => Config -> State f -> CriticalPair f -> State f-consider config state cp =-  considerUsing (st_rules state) config state cp---- Try to join a critical pair, but using a different set of critical--- pairs for normalisation.-{-# INLINEABLE considerUsing #-}-considerUsing ::-  Function f =>-  RuleIndex f (ActiveRule f) -> Config -> State f -> CriticalPair f -> State f-considerUsing rules config@Config{..} state@State{..} cp0 =-  {-# SCC consider #-}-  -- Important to canonicalise the rule so that we don't get-  -- bigger and bigger variable indices over time-  let cp = canonicalise cp0 in-  case joinCriticalPair cfg_join st_joinable rules Nothing cp of-    Right (mcp, cps) ->-      let-        state' = foldl' (considerUsing rules config) state cps-      in case mcp of-        Just cp -> addJoinable state' (cp_eqn cp)-        Nothing -> state'--    Left (cp, model) ->-      foldl' (addCP config model) state (split cp)--{-# INLINEABLE addCP #-}-addCP :: Function f => Config -> Model f -> State f -> CriticalPair f -> State f-addCP config model state@State{..} CriticalPair{..} =-  addActive config state $ \n k1 k2 ->-  let-    pf = certify cp_proof-    rule = orient cp_eqn--    makeRule k r p =-      ActiveRule {-        rule_active = n,-        rule_rid = k,-        rule_depth = cp_depth,-        rule_rule = r rule,-        rule_proof = p pf,-        rule_positions = positions (lhs (r rule)) }-  in-  Active {-    active_id = n,-    active_depth = cp_depth,-    active_rule = rule,-    active_model = model,-    active_top = cp_top,-    active_proof = pf,-    active_rules =-      usortBy (comparing (canonicalise . rule_rule)) $-        makeRule k1 id id:-        [ makeRule k2 backwards (certify . symm . derivation)-        | not (oriented (orientation rule)) ] }---- Add a new equation.-{-# INLINEABLE addAxiom #-}-addAxiom :: Function f => Config -> State f -> Axiom f -> State f-addAxiom config state axiom =-  consider config state $-    CriticalPair {-      cp_eqn = axiom_eqn axiom,-      cp_depth = 0,-      cp_top = Nothing,-      cp_proof = Proof.axiom axiom }---- Record an equation as being joinable.-{-# INLINEABLE addJoinable #-}-addJoinable :: Function f => State f -> Equation f -> State f-addJoinable state eqn@(t :=: u) =-  message (NewEquation eqn) $-  state {-    st_joinable =-      Index.insert t (t :=: u) $-      Index.insert u (u :=: t) (st_joinable state) }---- For goal terms we store the set of all their normal forms.--- Name and number are for information only.-data Goal f =-  Goal {-    goal_name   :: String,-    goal_number :: Int,-    goal_eqn    :: Equation f,-    goal_lhs    :: Set (Resulting f),-    goal_rhs    :: Set (Resulting f) }---- Add a new goal.-{-# INLINEABLE addGoal #-}-addGoal :: Function f => Config -> State f -> Goal f -> State f-addGoal _config state@State{..} goal =-  normaliseGoals state { st_goals = goal:st_goals }---- Normalise all goals.-{-# INLINEABLE normaliseGoals #-}-normaliseGoals :: Function f => State f -> State f-normaliseGoals state@State{..} =-  {-# SCC normaliseGoals #-}-  state {-    st_goals =-      map (goalMap (successors (rewrite reduces (index_all st_rules)) . Set.toList)) st_goals }-  where-    goalMap f goal@Goal{..} =-      goal { goal_lhs = f goal_lhs, goal_rhs = f goal_rhs }---- Create a goal.-{-# INLINE goal #-}-goal :: Int -> String -> Equation f -> Goal f-goal n name (t :=: u) =-  Goal {-    goal_name = name,-    goal_number = n,-    goal_eqn = t :=: u,-    goal_lhs = Set.singleton (reduce (Refl t)),-    goal_rhs = Set.singleton (reduce (Refl u)) }--------------------------------------------------------------------------- Interreduction.--------------------------------------------------------------------------- Simplify all rules.-{-# INLINEABLE interreduce #-}-interreduce :: Function f => Config -> State f -> State f-interreduce config@Config{..} state =-  {-# SCC interreduce #-}-  let-    state' =-      foldl' (interreduce1 config)-        -- Clear out st_joinable, since we don't know which-        -- equations have made use of each active.-        state { st_joinable = Index.empty }-        (IntMap.elems (st_active_ids state))-    in state' { st_joinable = st_joinable state }--{-# INLINEABLE interreduce1 #-}-interreduce1 :: Function f => Config -> State f -> Active f -> State f-interreduce1 config@Config{..} state active =-  -- Exclude the active from the rewrite rules when testing-  -- joinability, otherwise it will be trivially joinable.-  case-    joinCriticalPair cfg_join-      (st_joinable state)-      (st_rules (deleteActive state active))-      (Just (active_model active)) (active_cp active)-  of-    Right (_, cps) ->-      flip (foldl' (consider config)) cps $-      message (DeleteActive active) $-      deleteActive state active-    Left (cp, model)-      | not (cp_eqn cp `isInstanceOf` cp_eqn (active_cp active)) ->-        flip (foldl' (addCP config model)) (split cp) $-        message (DeleteActive active) $-        deleteActive state active-      | model /= active_model active ->-        flip addActiveOnly active { active_model = model } $-        deleteActive state active-      | otherwise ->-        state-  where-    (t :=: u) `isInstanceOf` (t' :=: u') = isJust $ do-      sub <- match t' t-      matchIn sub u' u---------------------------------------------------------------------------- The main loop.-------------------------------------------------------------------------data Output m f =-  Output {-    output_message :: Message f -> m () }--{-# INLINE complete #-}-complete :: (Function f, MonadIO m) => Output m f -> Config -> State f -> m (State f)-complete Output{..} config@Config{..} state =-  flip StateM.execStateT state $ do-    tasks <- sequence-      [newTask 1 (fromIntegral cfg_renormalise_percent / 100) $ do-         lift $ output_message SimplifyQueue-         state <- StateM.get-         StateM.put $! simplifyQueue config state,-       newTask 0.25 0.05 $ do-         when cfg_simplify $ do-           lift $ output_message Interreduce-           state <- StateM.get-           StateM.put $! interreduce config state]--    let-      loop = do-        progress <- StateM.state (complete1 config)-        state <- StateM.get-        lift $ mapM_ output_message (messages state)-        StateM.put (clearMessages state)-        mapM_ checkTask tasks-        when progress loop--    loop--{-# INLINEABLE complete1 #-}-complete1 :: Function f => Config -> State f -> (Bool, State f)-complete1 config@Config{..} state-  | st_considered state >= cfg_max_critical_pairs =-    (False, state)-  | solved state = (False, state)-  | otherwise =-    case dequeue config state of-      (Nothing, state) -> (False, state)-      (Just (overlap, _, _), state) ->-        (True, consider config state overlap)--{-# INLINEABLE solved #-}-solved :: Function f => State f -> Bool-solved = not . null . solutions---- Return whatever goals we have proved and their proofs.-{-# INLINEABLE solutions #-}-solutions :: Function f => State f -> [ProvedGoal f]-solutions State{..} = {-# SCC solutions #-} do-  Goal{goal_lhs = ts, goal_rhs = us, ..} <- st_goals-  guard (not (null (Set.intersection ts us)))-  let t:_ = filter (`Set.member` us) (Set.toList ts)-      u:_ = filter (== t) (Set.toList us)-      -- Strict so that we check the proof before returning a solution-      !p =-        Proof.certify $-          reductionProof (reduction t) `Proof.trans`-          Proof.symm (reductionProof (reduction u))-  return (provedGoal goal_number goal_name p)---- Return all current rewrite rules.-{-# INLINEABLE rules #-}-rules :: Function f => State f -> [Rule f]-rules = map active_rule . IntMap.elems . st_active_ids--------------------------------------------------------------------------- For code which uses twee as a library.-------------------------------------------------------------------------{-# INLINEABLE completePure #-}-completePure :: Function f => Config -> State f -> State f-completePure cfg state-  | progress = completePure cfg (clearMessages state')-  | otherwise = state'-  where-    (progress, state') = complete1 cfg state--{-# INLINEABLE normaliseTerm #-}-normaliseTerm :: Function f => State f -> Term f -> Resulting f-normaliseTerm State{..} t =-  normaliseWith (const True) (rewrite reduces (index_all st_rules)) t--{-# INLINEABLE simplifyTerm #-}-simplifyTerm :: Function f => State f -> Term f -> Term f-simplifyTerm State{..} t =-  simplify (index_oriented st_rules) t
− src/Twee/Base.hs
@@ -1,285 +0,0 @@--- | Useful operations on terms and similar. Also re-exports some generally--- useful modules such as 'Twee.Term' and 'Twee.Pretty'.--{-# LANGUAGE TypeFamilies, FlexibleInstances, UndecidableInstances, DeriveFunctor, DefaultSignatures, FlexibleContexts, TypeOperators, MultiParamTypeClasses, GeneralizedNewtypeDeriving, ConstraintKinds, RecordWildCards #-}-module Twee.Base(-  -- * Re-exported functionality-  module Twee.Term, module Twee.Pretty,-  -- * The 'Symbolic' typeclass-  Symbolic(..), subst, terms,-  TermOf, TermListOf, SubstOf, TriangleSubstOf, BuilderOf, FunOf,-  vars, isGround, funs, occ, occVar, canonicalise, renameAvoiding,-  -- * General-purpose functionality-  Id(..), Has(..),-  -- * Typeclasses-  Minimal(..), minimalTerm, isMinimal, erase,-  Skolem(..), Arity(..), Sized(..), Ordered(..), lessThan, orientTerms, EqualsBonus(..), Strictness(..), Function, Extended(..)) where--import Prelude hiding (lookup)-import Control.Monad-import qualified Data.DList as DList-import Twee.Term hiding (subst, canonicalise)-import qualified Twee.Term as Term-import Twee.Pretty-import Twee.Constraints hiding (funs)-import Data.DList(DList)-import Data.Typeable-import Data.Int-import Data.Maybe-import qualified Data.IntMap.Strict as IntMap---- | Represents a unique identifier (e.g., for a rule).-newtype Id = Id { unId :: Int32 }-  deriving (Eq, Ord, Show, Enum, Bounded, Num, Real, Integral)--instance Pretty Id where-  pPrint = text . show . unId---- | Generalisation of term functionality to things that contain terms (e.g.,--- rewrite rules and equations).-class Symbolic a where-  type ConstantOf a--  -- | Compute a 'DList' of all terms which appear in the argument-  -- (used for e.g. computing free variables).-  -- See also 'terms'.-  termsDL :: a -> DList (TermListOf a)--  -- | Apply a substitution.-  -- When using the 'Symbolic' type class, you can use 'subst' instead.-  subst_ :: (Var -> BuilderOf a) -> a -> a---- | Apply a substitution.-subst :: (Symbolic a, Substitution s, SubstFun s ~ ConstantOf a) => s -> a -> a-subst sub x = subst_ (evalSubst sub) x---- | Find all terms occuring in the argument.-terms :: Symbolic a => a -> [TermListOf a]-terms = DList.toList . termsDL---- | A term compatible with a given 'Symbolic'.-type TermOf a = Term (ConstantOf a)--- | A termlist compatible with a given 'Symbolic'.-type TermListOf a = TermList (ConstantOf a)--- | A substitution compatible with a given 'Symbolic'.-type SubstOf a = Subst (ConstantOf a)--- | A triangle substitution compatible with a given 'Symbolic'.-type TriangleSubstOf a = TriangleSubst (ConstantOf a)--- | A builder compatible with a given 'Symbolic'.-type BuilderOf a = Builder (ConstantOf a)--- | The underlying type of function symbols of a given 'Symbolic'.-type FunOf a = Fun (ConstantOf a)--instance Symbolic (Term f) where-  type ConstantOf (Term f) = f-  termsDL = return . singleton-  subst_ sub = build . Term.subst sub--instance Symbolic (TermList f) where-  type ConstantOf (TermList f) = f-  termsDL = return-  subst_ sub = buildList . Term.substList sub--instance Symbolic (Subst f) where-  type ConstantOf (Subst f) = f-  termsDL (Subst sub) = termsDL (IntMap.elems sub)-  subst_ sub (Subst s) = Subst (fmap (subst_ sub) s)--instance (ConstantOf a ~ ConstantOf b, Symbolic a, Symbolic b) => Symbolic (a, b) where-  type ConstantOf (a, b) = ConstantOf a-  termsDL (x, y) = termsDL x `mplus` termsDL y-  subst_ sub (x, y) = (subst_ sub x, subst_ sub y)--instance (ConstantOf a ~ ConstantOf b,-          ConstantOf a ~ ConstantOf c,-          Symbolic a, Symbolic b, Symbolic c) => Symbolic (a, b, c) where-  type ConstantOf (a, b, c) = ConstantOf a-  termsDL (x, y, z) = termsDL x `mplus` termsDL y `mplus` termsDL z-  subst_ sub (x, y, z) = (subst_ sub x, subst_ sub y, subst_ sub z)--instance Symbolic a => Symbolic [a] where-  type ConstantOf [a] = ConstantOf a-  termsDL xs = msum (map termsDL xs)-  subst_ sub xs = map (subst_ sub) xs--instance Symbolic a => Symbolic (Maybe a) where-  type ConstantOf (Maybe a) = ConstantOf a-  termsDL Nothing = mzero-  termsDL (Just x) = termsDL x-  subst_ sub x = fmap (subst_ sub) x---- | An instance @'Has' a b@ indicates that a value of type @a@ contains a value--- of type @b@ which is somehow part of the meaning of the @a@.------ A number of functions use 'Has' constraints to work in a more general setting.--- For example, the functions in 'Twee.CP' operate on rewrite rules, but actually--- accept any @a@ satisfying @'Has' a ('Twee.Rule.Rule' f)@.------ Use taste when definining 'Has' instances; don't do it willy-nilly.-class Has a b where-  -- | Get at the thing.-  the :: a -> b--instance Has a a where-  the = id---- | Find the variables occurring in the argument.-{-# INLINE vars #-}-vars :: Symbolic a => a -> [Var]-vars x = [ v | t <- DList.toList (termsDL x), Var v <- subtermsList t ]---- | Test if the argument is ground.-{-# INLINE isGround #-}-isGround :: Symbolic a => a -> Bool-isGround = null . vars---- | Find the function symbols occurring in the argument.-{-# INLINE funs #-}-funs :: Symbolic a => a -> [FunOf a]-funs x = [ f | t <- DList.toList (termsDL x), App f _ <- subtermsList t ]---- | Count how many times a function symbol occurs in the argument.-{-# INLINE occ #-}-occ :: Symbolic a => FunOf a -> a -> Int-occ x t = length (filter (== x) (funs t))---- | Count how many times a variable occurs in the argument.-{-# INLINE occVar #-}-occVar :: Symbolic a => Var -> a -> Int-occVar x t = length (filter (== x) (vars t))---- | Rename the argument so that variables are introduced in a canonical order--- (starting with V0, then V1 and so on).-{-# INLINEABLE canonicalise #-}-canonicalise :: Symbolic a => a -> a-canonicalise t = subst sub t-  where-    sub = Term.canonicalise (DList.toList (termsDL t))---- | Rename the second argument so that it does not mention any variable which--- occurs in the first.-{-# INLINEABLE renameAvoiding #-}-renameAvoiding :: (Symbolic a, Symbolic b) => a -> b -> b-renameAvoiding x y-  | x2 < y1 || y2 < x1 =-    -- No overlap. Important in the case when x is ground,-    -- in which case x2 == minBound and the calculation below doesn't work.-    y-  | otherwise =-    -- Map y1 to x2+1-    subst (\(V x) -> var (V (x-y1+x2+1))) y-  where-    (V x1, V x2) = boundLists (terms x)-    (V y1, V y2) = boundLists (terms y)---- | Check if a term is the minimal constant.-isMinimal :: Minimal f => Term f -> Bool-isMinimal (App f Empty) | f == minimal = True-isMinimal _ = False---- | Build the minimal constant as a term.-minimalTerm :: Minimal f => Term f-minimalTerm = build (con minimal)---- | Erase a given set of variables from the argument, replacing them with the--- minimal constant.-erase :: (Symbolic a, ConstantOf a ~ f, Minimal f) => [Var] -> a -> a-erase [] t = t-erase xs t = subst sub t-  where-    sub = fromMaybe undefined $ listToSubst [(x, minimalTerm) | x <- xs]---- | Construction of Skolem constants.-class Skolem f where-  -- | Turn a variable into a Skolem constant.-  skolem  :: Var -> Fun f---- | For types which have a notion of arity.-class Arity f where-  -- | Measure the arity.-  arity :: f -> Int--instance Arity f => Arity (Fun f) where-  arity = arity . fun_value---- | For types which have a notion of size.-class Sized a where-  -- | Compute the size.-  size  :: a -> Int--instance Sized f => Sized (Fun f) where-  size = size . fun_value--instance Sized f => Sized (TermList f) where-  size = aux 0-    where-      aux n Empty = n-      aux n (ConsSym (App f _) t) = aux (n+size f) t-      aux n (Cons (Var _) t) = aux (n+1) t--instance Sized f => Sized (Term f) where-  size = size . singleton---- | The collection of constraints which the type of function symbols must--- satisfy in order to be used by twee.-type Function f = (Ordered f, Arity f, Sized f, Minimal f, Skolem f, PrettyTerm f, EqualsBonus f)---- | A hack for encoding Horn clauses. See 'Twee.CP.Score'.--- The default implementation of 'hasEqualsBonus' should work OK.-class EqualsBonus f where-  hasEqualsBonus :: f -> Bool-  hasEqualsBonus _ = False-  isEquals, isTrue, isFalse :: f -> Bool-  isEquals _ = False-  isTrue _ = False-  isFalse _ = False--instance EqualsBonus f => EqualsBonus (Fun f) where-  hasEqualsBonus = hasEqualsBonus . fun_value-  isEquals = isEquals . fun_value-  isTrue = isTrue . fun_value-  isFalse = isFalse . fun_value---- | A function symbol extended with a minimal constant and Skolem functions.--- Comes equipped with 'Minimal' and 'Skolem' instances.-data Extended f =-    -- | The minimal constant.-    Minimal-    -- | A Skolem function.-  | Skolem Var-    -- | An ordinary function symbol.-  | Function f-  deriving (Eq, Ord, Show, Functor)--instance Pretty f => Pretty (Extended f) where-  pPrintPrec _ _ Minimal = text "?"-  pPrintPrec _ _ (Skolem (V n)) = text "sk" <> pPrint n-  pPrintPrec l p (Function f) = pPrintPrec l p f--instance PrettyTerm f => PrettyTerm (Extended f) where-  termStyle (Function f) = termStyle f-  termStyle _ = uncurried--instance Sized f => Sized (Extended f) where-  size (Function f) = size f-  size _ = 1--instance Arity f => Arity (Extended f) where-  arity (Function f) = arity f-  arity _ = 0--instance (Typeable f, Ord f) => Minimal (Extended f) where-  minimal = fun Minimal--instance (Typeable f, Ord f) => Skolem (Extended f) where-  skolem x = fun (Skolem x)--instance EqualsBonus f => EqualsBonus (Extended f) where-  hasEqualsBonus (Function f) = hasEqualsBonus f-  hasEqualsBonus _ = False-  isEquals (Function f) = isEquals f-  isEquals _ = False-  isTrue (Function f) = isTrue f-  isTrue _ = False-  isFalse (Function f) = isFalse f-  isFalse _ = False
− src/Twee/CP.hs
@@ -1,328 +0,0 @@--- | Critical pair generation.-{-# LANGUAGE BangPatterns, FlexibleContexts, ScopedTypeVariables, MultiParamTypeClasses, RecordWildCards, OverloadedStrings, TypeFamilies, GeneralizedNewtypeDeriving #-}-module Twee.CP where--import qualified Twee.Term as Term-import Twee.Base-import Twee.Rule-import Twee.Index(Index)-import qualified Data.Set as Set-import Control.Monad-import Data.Maybe-import Data.List-import qualified Data.ChurchList as ChurchList-import Data.ChurchList (ChurchList(..))-import Twee.Utils-import Twee.Equation-import qualified Twee.Proof as Proof-import Twee.Proof(Derivation, Lemma, congPath)---- | The set of positions at which a term can have critical overlaps.-data Positions f = NilP | ConsP {-# UNPACK #-} !Int !(Positions f)-type PositionsOf a = Positions (ConstantOf a)--instance Show (Positions f) where-  show = show . ChurchList.toList . positionsChurch---- | Calculate the set of positions for a term.-positions :: Term f -> Positions f-positions t = aux 0 Set.empty (singleton t)-  where-    -- Consider only general superpositions.-    aux !_ !_ Empty = NilP-    aux n m (Cons (Var _) t) = aux (n+1) m t-    aux n m (ConsSym t@App{} u)-      | t `Set.member` m = aux (n+1) m u-      | otherwise = ConsP n (aux (n+1) (Set.insert t m) u)--{-# INLINE positionsChurch #-}-positionsChurch :: Positions f -> ChurchList Int-positionsChurch posns =-  ChurchList $ \c n ->-    let-      pos NilP = n-      pos (ConsP x posns) = c x (pos posns)-    in-      pos posns---- | A critical overlap of one rule with another.-data Overlap f =-  Overlap {-    -- | The depth (1 for CPs of axioms, 2 for CPs whose rules have depth 1, etc.)-    overlap_depth :: {-# UNPACK #-} !Depth,-    -- | The critical term.-    overlap_top   :: {-# UNPACK #-} !(Term f),-    -- | The part of the critical term which the inner rule rewrites.-    overlap_inner :: {-# UNPACK #-} !(Term f),-    -- | The position in the critical term which is rewritten.-    overlap_pos   :: {-# UNPACK #-} !Int,-    -- | The critical pair itself.-    overlap_eqn   :: {-# UNPACK #-} !(Equation f) }-  deriving Show-type OverlapOf a = Overlap (ConstantOf a)---- | Represents the depth of a critical pair.-newtype Depth = Depth Int deriving (Eq, Ord, Num, Real, Enum, Integral, Show)---- | Compute all overlaps of a rule with a set of rules.-{-# INLINEABLE overlaps #-}-overlaps ::-  (Function f, Has a (Rule f), Has a (Positions f), Has a Depth) =>-  Depth -> Index f a -> [a] -> a -> [(a, a, Overlap f)]-overlaps max_depth idx rules r =-  ChurchList.toList (overlapsChurch max_depth idx rules r)--{-# INLINE overlapsChurch #-}-overlapsChurch :: forall f a.-  (Function f, Has a (Rule f), Has a (Positions f), Has a Depth) =>-  Depth -> Index f a -> [a] -> a -> ChurchList (a, a, Overlap f)-overlapsChurch max_depth idx rules r1 = do-  guard (the r1 < max_depth)-  r2 <- ChurchList.fromList rules-  guard (the r2 < max_depth)-  let !depth = 1 + max (the r1) (the r2)-  do { o <- asymmetricOverlaps idx depth (the r1) r1' (the r2); return (r1, r2, o) } `mplus`-    do { o <- asymmetricOverlaps idx depth (the r2) (the r2) r1'; return (r2, r1, o) }-  where-    !r1' = renameAvoiding (map the rules :: [Rule f]) (the r1)--{-# INLINE asymmetricOverlaps #-}-asymmetricOverlaps ::-  (Function f, Has a (Rule f), Has a Depth) =>-  Index f a -> Depth -> Positions f -> Rule f -> Rule f -> ChurchList (Overlap f)-asymmetricOverlaps idx depth posns r1 r2 = do-  n <- positionsChurch posns-  ChurchList.fromMaybe $-    overlapAt n depth r1 r2 >>=-    simplifyOverlap idx---- | Create an overlap at a particular position in a term.--- Doesn't simplify the overlap.-{-# INLINE overlapAt #-}-overlapAt :: Int -> Depth -> Rule f -> Rule f -> Maybe (Overlap f)-overlapAt !n !depth (Rule _ !outer !outer') (Rule _ !inner !inner') = do-  let t = at n (singleton outer)-  sub <- unifyTri inner t-  let-    top = {-# SCC overlap_top #-} termSubst sub outer-    innerTerm = {-# SCC overlap_inner #-} termSubst sub inner-    -- Make sure to keep in sync with overlapProof-    lhs = {-# SCC overlap_eqn_1 #-} termSubst sub outer'-    rhs = {-# SCC overlap_eqn_2 #-}-      buildReplacePositionSub sub n (singleton inner') (singleton outer)--  guard (lhs /= rhs)-  return Overlap {-    overlap_depth = depth,-    overlap_top = top,-    overlap_inner = innerTerm,-    overlap_pos = n,-    overlap_eqn = lhs :=: rhs }---- | Simplify an overlap and remove it if it's trivial.-{-# INLINE simplifyOverlap #-}-simplifyOverlap :: (Function f, Has a (Rule f)) => Index f a -> Overlap f -> Maybe (Overlap f)-simplifyOverlap idx overlap@Overlap{overlap_eqn = lhs :=: rhs, ..}-  | lhs == rhs'  = Nothing-  | lhs' == rhs' = Nothing-  | otherwise = Just overlap{overlap_eqn = lhs' :=: rhs'}-  where-    lhs' = simplify idx lhs-    rhs' = simplify idx rhs---- Put these in separate functions to avoid code blowup-buildReplacePositionSub :: TriangleSubst f -> Int -> TermList f -> TermList f -> Term f-buildReplacePositionSub !sub !n !inner' !outer =-  build (replacePositionSub sub n inner' outer)--termSubst :: TriangleSubst f -> Term f -> Term f-termSubst sub t = build (Term.subst sub t)---- | The configuration for the critical pair weighting heuristic.-data Config =-  Config {-    cfg_lhsweight :: !Int,-    cfg_rhsweight :: !Int,-    cfg_funweight :: !Int,-    cfg_varweight :: !Int,-    cfg_depthweight :: !Int,-    cfg_dupcost :: !Int,-    cfg_dupfactor :: !Int }---- | The default heuristic configuration.-defaultConfig :: Config-defaultConfig =-  Config {-    cfg_lhsweight = 3,-    cfg_rhsweight = 1,-    cfg_funweight = 7,-    cfg_varweight = 6,-    cfg_depthweight = 16,-    cfg_dupcost = 7,-    cfg_dupfactor = 0 }---- | Compute a score for a critical pair.---- We compute:---   cfg_lhsweight * size l + cfg_rhsweight * size r--- where l is the biggest term and r is the smallest,--- and variables have weight 1 and functions have weight cfg_funweight.-{-# INLINEABLE score #-}-score :: Function f => Config -> Overlap f -> Int-score Config{..} Overlap{..} =-  fromIntegral overlap_depth * cfg_depthweight +-  (m + n) * cfg_rhsweight +-  intMax m n * (cfg_lhsweight - cfg_rhsweight)-  where-    l :=: r = overlap_eqn-    m = size' 0 (singleton l)-    n = size' 0 (singleton r)--    size' !n Empty = n-    size' n (Cons t ts)-      | len t > 1, t `isSubtermOfList` ts =-        size' (n+cfg_dupcost+cfg_dupfactor*size t) ts-    size' n ts-      | Cons (App f (Cons a (Cons b us))) vs <- ts,-        hasEqualsBonus (fun_value f), isJust (unify a b) =-        size' (size' (n+1) us) vs-    size' n (Cons (Var _) ts) =-      size' (n+cfg_varweight) ts-    size' n (ConsSym (App f _) ts) =-      size' (n+cfg_funweight*size f) ts--------------------------------------------------------------------------- * Higher-level handling of critical pairs.--------------------------------------------------------------------------- | A critical pair together with information about how it was derived-data CriticalPair f =-  CriticalPair {-    -- | The critical pair itself.-    cp_eqn   :: {-# UNPACK #-} !(Equation f),-    -- | The depth of the critical pair.-    cp_depth :: {-# UNPACK #-} !Depth,-    -- | The critical term, if there is one.-    -- (Axioms do not have a critical term.)-    cp_top   :: !(Maybe (Term f)),-    -- | A derivation of the critical pair from the axioms.-    cp_proof :: !(Derivation f) }--instance Symbolic (CriticalPair f) where-  type ConstantOf (CriticalPair f) = f-  termsDL CriticalPair{..} =-    termsDL cp_eqn `mplus` termsDL cp_top `mplus` termsDL cp_proof-  subst_ sub CriticalPair{..} =-    CriticalPair {-      cp_eqn = subst_ sub cp_eqn,-      cp_depth = cp_depth,-      cp_top = subst_ sub cp_top,-      cp_proof = subst_ sub cp_proof }--instance PrettyTerm f => Pretty (CriticalPair f) where-  pPrint CriticalPair{..} =-    vcat [-      pPrint cp_eqn,-      nest 2 (text "top:" <+> pPrint cp_top) ]---- | Split a critical pair so that it can be turned into rules.------ The resulting critical pairs have the property that no variable appears on--- the right that is not on the left.---- See the comment below.-split :: Function f => CriticalPair f -> [CriticalPair f]-split CriticalPair{cp_eqn = l :=: r, ..}-  | l == r = []-  | otherwise =-    -- If we have something which is almost a rule, except that some-    -- variables appear only on the right-hand side, e.g.:-    --   f x y -> g x z-    -- then we replace it with the following two rules:-    --   f x y -> g x ?-    --   g x z -> g x ?-    -- where the second rule is weakly oriented and ? is the minimal-    -- constant.-    ---    -- If we have an unoriented equation with a similar problem, e.g.:-    --   f x y = g x z-    -- then we replace it with potentially three rules:-    --   f x ? = g x ?-    --   f x y -> f x ?-    --   g x z -> g x ?--    -- The main rule l -> r' or r -> l' or l' = r'-    [ CriticalPair {-        cp_eqn   = l :=: r',-        cp_depth = cp_depth,-        cp_top   = eraseExcept (vars l) cp_top,-        cp_proof = eraseExcept (vars l) cp_proof }-    | ord == Just GT ] ++-    [ CriticalPair {-        cp_eqn   = r :=: l',-        cp_depth = cp_depth,-        cp_top   = eraseExcept (vars r) cp_top,-        cp_proof = Proof.symm (eraseExcept (vars r) cp_proof) }-    | ord == Just LT ] ++-    [ CriticalPair {-        cp_eqn   = l' :=: r',-        cp_depth = cp_depth,-        cp_top   = eraseExcept (vars l) $ eraseExcept (vars r) cp_top,-        cp_proof = eraseExcept (vars l) $ eraseExcept (vars r) cp_proof }-    | ord == Nothing ] ++--    -- Weak rules l -> l' or r -> r'-    [ CriticalPair {-        cp_eqn   = l :=: l',-        cp_depth = cp_depth + 1,-        cp_top   = Nothing,-        cp_proof = cp_proof `Proof.trans` Proof.symm (erase ls cp_proof) }-    | not (null ls), ord /= Just GT ] ++-    [ CriticalPair {-        cp_eqn   = r :=: r',-        cp_depth = cp_depth + 1,-        cp_top   = Nothing,-        cp_proof = Proof.symm cp_proof `Proof.trans` erase rs cp_proof }-    | not (null rs), ord /= Just LT ]-    where-      ord = orientTerms l' r'-      l' = erase ls l-      r' = erase rs r-      ls = usort (vars l) \\ usort (vars r)-      rs = usort (vars r) \\ usort (vars l)--      eraseExcept vs t =-        erase (usort (vars t) \\ usort vs) t---- | Make a critical pair from two rules and an overlap.-{-# INLINEABLE makeCriticalPair #-}-makeCriticalPair ::-  (Has a (Rule f), Has a (Lemma f), Has a Id, Function f) =>-  a -> a -> Overlap f -> Maybe (CriticalPair f)-makeCriticalPair r1 r2 overlap@Overlap{..}-  | lessEq overlap_top t = Nothing-  | lessEq overlap_top u = Nothing-  | otherwise =-    Just $-      CriticalPair overlap_eqn-        overlap_depth-        (Just overlap_top)-        (overlapProof r1 r2 overlap)-  where-    t :=: u = overlap_eqn---- | Return a proof for a critical pair.-{-# INLINEABLE overlapProof #-}-overlapProof ::-  forall a f.-  (Has a (Rule f), Has a (Lemma f), Has a Id) =>-  a -> a -> Overlap f -> Derivation f-overlapProof left right Overlap{..} =-  Proof.symm (reductionProof (step left leftSub))-  `Proof.trans`-  congPath path overlap_top (reductionProof (step right rightSub))-  where-    Just leftSub = match (lhs (the left)) overlap_top-    Just rightSub = match (lhs (the right)) overlap_inner--    path = positionToPath (lhs (the left) :: Term f) overlap_pos
− src/Twee/Constraints.hs
@@ -1,312 +0,0 @@-{-# LANGUAGE FlexibleContexts, UndecidableInstances, RecordWildCards #-}--- | Solving constraints on variable ordering.-module Twee.Constraints where----import Twee.Base hiding (equals, Term, pattern Fun, pattern Var, lookup, funs)-import qualified Twee.Term as Flat-import qualified Data.Map.Strict as Map-import Twee.Pretty hiding (equals)-import Twee.Utils-import Data.Maybe-import Data.List-import Data.Function-import Data.Graph-import Data.Map.Strict(Map)-import Data.Ord-import Twee.Term hiding (lookup)--data Atom f = Constant (Fun f) | Variable Var deriving (Show, Eq, Ord)--{-# INLINE atoms #-}-atoms :: Term f -> [Atom f]-atoms t = aux (singleton t)-  where-    aux Empty = []-    aux (Cons (App f Empty) t) = Constant f:aux t-    aux (Cons (Var x) t) = Variable x:aux t-    aux (ConsSym _ t) = aux t--toTerm :: Atom f -> Term f-toTerm (Constant f) = build (con f)-toTerm (Variable x) = build (var x)--fromTerm :: Flat.Term f -> Maybe (Atom f)-fromTerm (App f Empty) = Just (Constant f)-fromTerm (Var x) = Just (Variable x)-fromTerm _ = Nothing--instance PrettyTerm f => Pretty (Atom f) where-  pPrint = pPrint . toTerm--data Formula f =-    Less   (Atom f) (Atom f)-  | LessEq (Atom f) (Atom f)-  | And [Formula f]-  | Or  [Formula f]-  deriving (Eq, Ord, Show)--instance PrettyTerm f => Pretty (Formula f) where-  pPrintPrec _ _ (Less t u) = hang (pPrint t <+> text "<") 2 (pPrint u)-  pPrintPrec _ _ (LessEq t u) = hang (pPrint t <+> text "<=") 2 (pPrint u)-  pPrintPrec _ _ (And []) = text "true"-  pPrintPrec _ _ (Or []) = text "false"-  pPrintPrec l p (And xs) =-    maybeParens (p > 10)-      (fsep (punctuate (text " &") (nest_ (map (pPrintPrec l 11) xs))))-    where-      nest_ (x:xs) = x:map (nest 2) xs-      nest_ [] = undefined-  pPrintPrec l p (Or xs) =-    maybeParens (p > 10)-      (fsep (punctuate (text " |") (nest_ (map (pPrintPrec l 11) xs))))-    where-      nest_ (x:xs) = x:map (nest 2) xs-      nest_ [] = undefined--negateFormula :: Formula f -> Formula f-negateFormula (Less t u) = LessEq u t-negateFormula (LessEq t u) = Less u t-negateFormula (And ts) = Or (map negateFormula ts)-negateFormula (Or ts) = And (map negateFormula ts)--conj forms-  | false `elem` forms' = false-  | otherwise =-    case forms' of-      [x] -> x-      xs  -> And xs-  where-    flatten (And xs) = xs-    flatten x = [x]-    forms' = filter (/= true) (usort (concatMap flatten forms))-disj forms-  | true `elem` forms' = true-  | otherwise =-    case forms' of-      [x] -> x-      xs  -> Or xs-  where-    flatten (Or xs) = xs-    flatten x = [x]-    forms' = filter (/= false) (usort (concatMap flatten forms))--x &&& y = conj [x, y]-x ||| y = disj [x, y]-true  = And []-false = Or []--data Branch f =-  -- Branches are kept normalised wrt equals-  Branch {-    funs        :: [Fun f],-    less        :: [(Atom f, Atom f)],  -- sorted-    equals      :: [(Atom f, Atom f)] } -- sorted, greatest atom first in each pair-  deriving (Eq, Ord)--instance PrettyTerm f => Pretty (Branch f) where-  pPrint Branch{..} =-    braces $ fsep $ punctuate (text ",") $-      [pPrint x <+> text "<" <+> pPrint y | (x, y) <- less ] ++-      [pPrint x <+> text "=" <+> pPrint y | (x, y) <- equals ]--trueBranch :: Branch f-trueBranch = Branch [] [] []--norm :: Eq f => Branch f -> Atom f -> Atom f-norm Branch{..} x = fromMaybe x (lookup x equals)--contradictory :: (Minimal f, Ord f) => Branch f -> Bool-contradictory Branch{..} =-  or [f == minimal | (_, Constant f) <- less] ||-  or [f /= g | (Constant f, Constant g) <- equals] ||-  any cyclic (stronglyConnComp-    [(x, x, [y | (x', y) <- less, x == x']) | x <- usort (map fst less)])-  where-    cyclic (AcyclicSCC _) = False-    cyclic (CyclicSCC _) = True--formAnd :: (Minimal f, Ordered f) => Formula f -> [Branch f] -> [Branch f]-formAnd f bs = usort (bs >>= add f)-  where-    add (Less t u) b = addLess t u b-    add (LessEq t u) b = addLess t u b ++ addEquals t u b-    add (And []) b = [b]-    add (And (f:fs)) b = add f b >>= add (And fs)-    add (Or fs) b = usort (concat [ add f b | f <- fs ])--branches :: (Minimal f, Ordered f) => Formula f -> [Branch f]-branches x = aux [x]-  where-    aux [] = [Branch [] [] []]-    aux (And xs:ys) = aux (xs ++ ys)-    aux (Or xs:ys) = usort $ concat [aux (x:ys) | x <- xs]-    aux (Less t u:xs) = usort $ concatMap (addLess t u) (aux xs)-    aux (LessEq t u:xs) =-      usort $-      concatMap (addLess t u) (aux xs) ++-      concatMap (addEquals u t) (aux xs)--addLess :: (Minimal f, Ordered f) => Atom f -> Atom f -> Branch f -> [Branch f]-addLess _ (Constant min) _ | min == minimal = []-addLess (Constant min) _ b | min == minimal = [b]-addLess t0 u0 b@Branch{..} =-  filter (not . contradictory)-    [addTerm t (addTerm u b{less = usort ((t, u):less)})]-  where-    t = norm b t0-    u = norm b u0--addEquals :: (Minimal f, Ordered f) => Atom f -> Atom f -> Branch f -> [Branch f]-addEquals t0 u0 b@Branch{..}-  | t == u || (t, u) `elem` equals = [b]-  | otherwise =-    filter (not . contradictory)-      [addTerm t (addTerm u b {-         equals      = usort $ (t, u):[(x', y') | (x, y) <- equals, let (y', x') = sort2 (sub x, sub y), x' /= y'],-         less        = usort $ [(sub x, sub y) | (x, y) <- less] })]-  where-    sort2 (x, y) = (min x y, max x y)-    (u, t) = sort2 (norm b t0, norm b u0)--    sub x-      | x == t = u-      | otherwise = x--addTerm :: (Minimal f, Ordered f) => Atom f -> Branch f -> Branch f-addTerm (Constant f) b-  | f `notElem` funs b =-    b {-      funs = f:funs b,-      less =-        usort $-          [ (Constant f, Constant g) | g <- funs b, f << g ] ++-          [ (Constant g, Constant f) | g <- funs b, g << f ] ++ less b }-addTerm _ b = b--newtype Model f = Model (Map (Atom f) (Int, Int))-  deriving (Eq, Show)--- Representation: map from atom to (major, minor)--- x <  y if major x < major y--- x <= y if major x = major y and minor x < minor y--instance PrettyTerm f => Pretty (Model f) where-  pPrint (Model m)-    | Map.size m <= 1 = text "empty"-    | otherwise = fsep (go (sortBy (comparing snd) (Map.toList m)))-      where-        go [(x, _)] = [pPrint x]-        go ((x, (i, _)):xs@((_, (j, _)):_)) =-          (pPrint x <+> text rel):go xs-          where-            rel = if i == j then "<=" else "<"--modelToLiterals :: Model f -> [Formula f]-modelToLiterals (Model m) = go (sortBy (comparing snd) (Map.toList m))-  where-    go []  = []-    go [_] = []-    go ((x, (i, _)):xs@((y, (j, _)):_)) =-      rel x y:go xs-      where-        rel = if i == j then LessEq else Less--modelFromOrder :: (Minimal f, Ord f) => [Atom f] -> Model f-modelFromOrder xs =-  Model (Map.fromList [(x, (i, i)) | (x, i) <- zip xs [0..]])--weakenModel :: Model f -> [Model f]-weakenModel (Model m) =-  [ Model (Map.delete x m) | x <- Map.keys m ] ++-  [ Model (Map.fromList xs)-  | xs <- glue (sortBy (comparing snd) (Map.toList m)),-    all ok (groupBy ((==) `on` (fst . snd)) xs) ]-  where-    glue [] = []-    glue [_] = []-    glue (a@(_x, (i1, j1)):b@(y, (i2, _)):xs) =-      [ (a:(y, (i1, j1+1)):xs) | i1 < i2 ] ++-      map (a:) (glue (b:xs))--    -- We must never make two constants equal-    ok xs = length [x | (Constant x, _) <- xs] <= 1--varInModel :: (Minimal f, Ord f) => Model f -> Var -> Bool-varInModel (Model m) x = Variable x `Map.member` m--varGroups :: (Minimal f, Ord f) => Model f -> [(Fun f, [Var], Maybe (Fun f))]-varGroups (Model m) = filter nonempty (go minimal (map fst (sortBy (comparing snd) (Map.toList m))))-  where-    go f xs =-      case span isVariable xs of-        (_, []) -> [(f, map unVariable xs, Nothing)]-        (ys, Constant g:zs) ->-          (f, map unVariable ys, Just g):go g zs-    isVariable (Constant _) = False-    isVariable (Variable _) = True-    unVariable (Variable x) = x-    nonempty (_, [], _) = False-    nonempty _ = True--class Minimal f where-  minimal :: Fun f--{-# INLINE lessEqInModel #-}-lessEqInModel :: (Minimal f, Ordered f) => Model f -> Atom f -> Atom f -> Maybe Strictness-lessEqInModel (Model m) x y-  | Just (a, _) <- Map.lookup x m,-    Just (b, _) <- Map.lookup y m,-    a < b = Just Strict-  | Just a <- Map.lookup x m,-    Just b <- Map.lookup y m,-    a < b = Just Nonstrict-  | x == y = Just Nonstrict-  | Constant a <- x, Constant b <- y, a << b = Just Strict-  | Constant a <- x, a == minimal = Just Nonstrict-  | otherwise = Nothing--solve :: (Minimal f, Ordered f, PrettyTerm f) => [Atom f] -> Branch f -> Either (Model f) (Subst f)-solve xs branch@Branch{..}-  | null equals && not (all true less) =-    error $ "Model " ++ prettyShow model ++ " is not a model of " ++ prettyShow branch ++ " (edges = " ++ prettyShow edges ++ ", vs = " ++ prettyShow vs ++ ")"-  | null equals = Left model-  | otherwise = Right sub-    where-      sub = fromMaybe undefined . listToSubst $-        [(x, toTerm y) | (Variable x, y) <- equals] ++-        [(y, toTerm x) | (x@Constant{}, Variable y) <- equals]-      vs = Constant minimal:reverse (flattenSCCs (stronglyConnComp edges))-      edges = [(x, x, [y | (x', y) <- less', x == x']) | x <- as, x /= Constant minimal]-      less' = less ++ [(Constant x, Constant y) | Constant x <- as, Constant y <- as, x << y]-      as = usort $ xs ++ map fst less ++ map snd less-      model = modelFromOrder vs-      true (t, u) = lessEqInModel model t u == Just Strict--class Ord f => Ordered f where-  -- | Return 'True' if the first term is less than or equal to the second,-  -- in the term ordering.-  lessEq :: Term f -> Term f -> Bool-  -- | Check if the first term is less than or equal to the second in the given model,-  -- and decide whether the inequality is strict or nonstrict.-  lessIn :: Model f -> Term f -> Term f -> Maybe Strictness---- | Describes whether an inequality is strict or nonstrict.-data Strictness =-    -- | The first term is strictly less than the second.-    Strict-    -- | The first term is less than or equal to the second.-  | Nonstrict deriving (Eq, Show)---- | Return 'True' if the first argument is strictly less than the second,--- in the term ordering.-lessThan :: Ordered f => Term f -> Term f -> Bool-lessThan t u = lessEq t u && isNothing (unify t u)---- | Return the direction in which the terms are oriented according to the term--- ordering, or 'Nothing' if they cannot be oriented. A result of @'Just' 'LT'@--- means that the first term is less than /or equal to/ the second.-orientTerms :: Ordered f => Term f -> Term f -> Maybe Ordering-orientTerms t u-  | t == u = Just EQ-  | lessEq t u = Just LT-  | lessEq u t = Just GT-  | otherwise = Nothing
− src/Twee/Equation.hs
@@ -1,58 +0,0 @@--- | Equations.-{-# LANGUAGE TypeFamilies #-}-module Twee.Equation where--import Twee.Base-import Data.Maybe-import Control.Monad------------------------------------------------------------------------------------- * Equations.-----------------------------------------------------------------------------------data Equation f =-  (:=:) {-    eqn_lhs :: {-# UNPACK #-} !(Term f),-    eqn_rhs :: {-# UNPACK #-} !(Term f) }-  deriving (Eq, Ord, Show)-type EquationOf a = Equation (ConstantOf a)--instance Symbolic (Equation f) where-  type ConstantOf (Equation f) = f-  termsDL (t :=: u) = termsDL t `mplus` termsDL u-  subst_ sub (t :=: u) = subst_ sub t :=: subst_ sub u--instance PrettyTerm f => Pretty (Equation f) where-  pPrint (x :=: y) = pPrint x <+> text "=" <+> pPrint y--instance Sized f => Sized (Equation f) where-  size (x :=: y) = size x + size y---- | Order an equation roughly left-to-right.--- However, there is no guarantee that the result is oriented.-order :: Function f => Equation f -> Equation f-order (l :=: r)-  | l == r = l :=: r-  | otherwise =-    case compare (size l) (size r) of-      LT -> r :=: l-      GT -> l :=: r-      EQ -> if lessEq l r then r :=: l else l :=: r---- | Apply a function to both sides of an equation.-bothSides :: (Term f -> Term f') -> Equation f -> Equation f'-bothSides f (t :=: u) = f t :=: f u---- | Is an equation of the form t = t?-trivial :: Eq f => Equation f -> Bool-trivial (t :=: u) = t == u--simplerThan :: Function f => Equation f -> Equation f -> Bool-eq1 `simplerThan` eq2 =-  t1 `lessEq` t2 &&-  (isNothing (unify t1 t2) || (u1 `lessEq` u2))-  where-    t1 :=: u1 = skolemise eq1-    t2 :=: u2 = skolemise eq2--    skolemise = subst (con . skolem)
− src/Twee/Index.hs
@@ -1,310 +0,0 @@--- | A term index to accelerate matching.--- An index is a multimap from terms to arbitrary values.------ The type of query supported is: given a search term, find all keys such that--- the search term is an instance of the key, and return the corresponding--- values.--{-# LANGUAGE BangPatterns, RecordWildCards, OverloadedStrings, FlexibleContexts #-}--- We get some bogus warnings because of pattern synonyms.-{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}-module Twee.Index(-  Index,-  empty,-  null,-  singleton,-  insert,-  delete,-  lookup,-  matches,-  approxMatches,-  elems) where--import qualified Prelude-import Prelude hiding (null, lookup)-import Data.Maybe-import Twee.Base hiding (var, fun, empty, size, singleton, prefix, funs, lookupList, lookup)-import qualified Twee.Term as Term-import Twee.Term.Core(TermList(..))-import Data.DynamicArray-import qualified Data.List as List---- The term index in this module is an _imperfect discrimination tree_.--- This is a trie whose keys are terms, represented as flat lists of symbols,--- but where all variables have been replaced by a single don't-care variable '_'.--- That is, the edges of the trie can be either function symbols or '_'.--- To insert a key-value pair into the discrimination tree, we first replace all--- variables in the key with '_', and then do ordinary trie insertion.------ Lookup maintains a term list, which is initially the search term.--- It proceeds down the trie, consuming bits of the term list as it goes.------ If the current trie node has an edge for a function symbol f, and the term at--- the head of the term list is f(t1..tn), we can follow the f edge. We then--- delete f from the term list, but keep t1..tn at the front of the term list.--- (In other words we delete only the symbol f and not its arguments.)------ If the current trie node has an edge for '_', we can always follow that edge.--- We then remove the head term from the term list, as the '_' represents a--- variable that should match that whole term.------ If the term list ever becomes empty, we have a possible match. We then--- do matching on the values stored at the current node to see if they are--- genuine matches.------ Often there are two edges we can follow (function symbol and '_'), and in--- that case the algorithm uses backtracking.---- | A term index: a multimap from @'Term' f@ to @a@.-data Index f a =-  -- A non-empty index.-  Index {-    -- Size of smallest term in index.-    size   :: {-# UNPACK #-} !Int,-    -- When all keys in the index start with the same sequence of symbols, we-    -- compress them into this prefix; the "fun" and "var" fields below refer to-    -- the first symbol _after_ the prefix, and the "here" field contains values-    -- whose remaining key is exactly this prefix.-    prefix :: {-# UNPACK #-} !(TermList f),-    -- The values that are found at this node.-    here   :: [a],-    -- Function symbol edges.-    -- The array is indexed by function number.-    fun    :: {-# UNPACK #-} !(Array (Index f a)),-    -- Variable edge.-    var    :: !(Index f a) } |-  -- An empty index.-  Nil-  deriving Show--instance Default (Index f a) where def = Nil---- To get predictable performance, the lookup function uses an explicit stack--- instead of recursion to control backtracking.-data Stack f a =-  -- A normal stack frame: records the current index node and term.-  Frame {-    frame_term  :: {-# UNPACK #-} !(TermList f),-    frame_index :: !(Index f a),-    frame_rest  :: !(Stack f a) }-  -- A stack frame which is used when we have found a match.-  | Yield {-    yield_found :: [a],-    yield_rest  :: !(Stack f a) }-  -- End of stack.-  | Stop---- Turn a stack into a list of results.-run :: Stack f a -> [a]-run Stop = []-run Frame{..} = run ({-# SCC run_inner #-} step frame_term frame_index frame_rest)-run Yield{..} = {-# SCC run_found #-} yield_found ++ run yield_rest---- Execute a single stack frame.-{-# INLINE step #-}-step :: TermList f -> Index f a -> Stack f a -> Stack f a-step !_ _ _ | False = undefined-step t idx rest =-  case idx of-    Nil -> rest-    Index{..}-      | lenList t < size ->-        rest -- the search term is smaller than any in this index-      | otherwise ->-        pref t prefix here fun var rest---- The main work of 'step' goes on here.--- It is carefully tweaked to generate nice code,--- including using UnsafeCons and only casing on each--- term list exactly once.-pref :: TermList f -> TermList f -> [a] -> Array (Index f a) -> Index f a -> Stack f a -> Stack f a-pref !_ !_ _ !_ !_ _ | False = undefined-pref search prefix here fun var rest =-  case search of-    Empty ->-      case prefix of-        Empty ->-          -- The search term matches this node.-          case here of-            [] -> rest-            _ -> Yield here rest-        _ ->-          -- We've run out of search term - it doesn't match this node.-          rest-    UnsafeCons t ts ->-      case prefix of-        Cons u us ->-          -- Check the search term against the prefix.-          case (t, u) of-            (_, Var _) ->-              -- Prefix contains a variable - if there is a match, the-              -- variable will be bound to t.-              pref ts us here fun var rest-            (App f _, App g _) | f == g ->-              -- Term and prefix start with same symbol, chop them off.-               let-                 UnsafeConsSym _ ts' = search-                 UnsafeConsSym _ us' = prefix-               in pref ts' us' here fun var rest-            _ ->-              -- Term and prefix don't match.-              rest-        _ ->-          -- We've exhausted the prefix, so let's descend into the tree.-          -- Seems to work better to explore the function node first.-          let-            tryVar =-              case var of-                Nil -> rest-                Index{} -> Frame ts var rest-              where-                UnsafeCons _ ts = search--            tryFun =-              case t of-                App f _ ->-                  case fun ! fun_id f of-                    Nil -> tryVar-                    idx -> Frame ts idx $! tryVar-                _ ->-                  tryVar-              where-                UnsafeConsSym t ts = search-          in-            tryFun---- | An empty index.-empty :: Index f a-empty = Nil---- | Is the index empty?-null :: Index f a -> Bool-null Nil = True-null _ = False---- | An index with one entry.-singleton :: Term f -> a -> Index f a-singleton !t x = singletonList (Term.singleton t) x---- An index with one entry, giving a termlist instead of a term.-{-# INLINE singletonList #-}-singletonList :: TermList f -> a -> Index f a-singletonList t x = Index 0 t [x] newArray Nil---- | Insert an entry into the index.-insert :: Term f -> a -> Index f a -> Index f a-insert !t x !idx = {-# SCC insert #-} aux (Term.singleton t) idx-  where-    aux t Nil = singletonList t x-    aux (Cons t ts) idx@Index{prefix = Cons u us} | t == u =-      withPrefix (Term.singleton t) (aux ts idx{prefix = us})-    aux t idx@Index{prefix = Cons{}} = aux t (expand idx)--    aux Empty idx =-      idx { size = 0, here = x:here idx }-    aux t@(ConsSym (App f _) u) idx =-      idx {-        size = lenList t `min` size idx,-        fun  = update (fun_id f) idx' (fun idx) }-      where-        idx' = aux u (fun idx ! fun_id f)-    aux t@(ConsSym (Var _) u) idx =-      idx {-        size = lenList t `min` size idx,-        var  = aux u (var idx) }---- Add a prefix to an index.--- Does not update the size field.-{-# INLINE withPrefix #-}-withPrefix :: TermList f -> Index f a -> Index f a-withPrefix Empty idx = idx-withPrefix _ Nil = Nil-withPrefix t idx@Index{..} =-  idx{prefix = buildList (builder t `mappend` builder prefix)}---- Take an index with a prefix and pull out the first symbol of the prefix,--- giving an index which doesn't start with a prefix.-{-# INLINE expand #-}-expand :: Index f a -> Index f a-expand idx@Index{size = size, prefix = ConsSym t ts} =-  case t of-    Var _ ->-      Index {-        size = size,-        prefix = Term.empty,-        here = [],-        fun = newArray,-        var = idx { prefix = ts, size = size - 1 } }-    App f _ ->-      Index {-        size = size,-        prefix = Term.empty,-        here = [],-        fun = update (fun_id f) idx { prefix = ts, size = size - 1 } newArray,-        var = Nil }---- | Delete an entry from the index.-{-# INLINEABLE delete #-}-delete :: Eq a => Term f -> a -> Index f a -> Index f a-delete !t x !idx = {-# SCC delete #-} aux (Term.singleton t) idx-  where-    aux _ Nil = Nil-    aux (Cons t ts) idx@Index{prefix = Cons u us} | t == u =-      withPrefix (Term.singleton t) (aux ts idx{prefix = us})-    aux _ idx@Index{prefix = Cons{}} = idx--    aux Empty idx-      | x `List.elem` here idx =-        idx { here = List.delete x (here idx) }-      | otherwise =-        error "deleted term not found in index"-    aux (ConsSym (App f _) t) idx =-      idx { fun = update (fun_id f) (aux t (fun idx ! fun_id f)) (fun idx) }-    aux (ConsSym (Var _) t) idx =-      idx { var = aux t (var idx) }---- | Look up a term in the index. Finds all key-value such that the search term--- is an instance of the key, and returns an instance of the the value which--- makes the search term exactly equal to the key.-{-# INLINE lookup #-}-lookup :: (Has a b, Symbolic b, Has b (TermOf b)) => TermOf b -> Index (ConstantOf b) a -> [b]-lookup t idx = lookupList (Term.singleton t) idx--{-# INLINEABLE lookupList #-}-lookupList :: (Has a b, Symbolic b, Has b (TermOf b)) => TermListOf b -> Index (ConstantOf b) a -> [b]-lookupList t idx =-  [ subst sub x-  | x <- List.map the (approxMatchesList t idx),-    sub <- maybeToList (matchList (Term.singleton (the x)) t)]---- | Look up a term in the index. Like 'lookup', but returns the exact value--- that was inserted into the index, not an instance. Also returns a substitution--- which when applied to the value gives you the matching instance.-{-# INLINE matches #-}-matches :: Has a (Term f) => Term f -> Index f a -> [(Subst f, a)]-matches t idx = matchesList (Term.singleton t) idx--{-# INLINEABLE matchesList #-}-matchesList :: Has a (Term f) => TermList f -> Index f a -> [(Subst f, a)]-matchesList t idx =-  [ (sub, x)-  | x <- approxMatchesList t idx,-    sub <- maybeToList (matchList (Term.singleton (the x)) t)]---- | Look up a term in the index, possibly returning spurious extra results.-{-# INLINE approxMatches #-}-approxMatches :: Term f -> Index f a -> [a]-approxMatches t idx = approxMatchesList (Term.singleton t) idx--approxMatchesList :: TermList f -> Index f a -> [a]-approxMatchesList t idx =-  {-# SCC approxMatchesList #-}-  run (Frame t idx Stop)---- | Return all elements of the index.-elems :: Index f a -> [a]-elems Nil = []-elems idx =-  here idx ++-  concatMap elems (Prelude.map snd (toList (fun idx))) ++-  elems (var idx)
− src/Twee/Join.hs
@@ -1,212 +0,0 @@--- | Tactics for joining critical pairs.-{-# LANGUAGE FlexibleContexts, BangPatterns, RecordWildCards, TypeFamilies #-}-module Twee.Join where--import Twee.Base-import Twee.Rule-import Twee.Equation-import Twee.Proof(Lemma)-import qualified Twee.Proof as Proof-import Twee.CP hiding (Config)-import Twee.Constraints-import qualified Twee.Index as Index-import Twee.Index(Index)-import Twee.Rule.Index(RuleIndex(..))-import Twee.Utils-import Data.Maybe-import Data.Either-import Data.Ord-import qualified Data.Set as Set--data Config =-  Config {-    cfg_ground_join :: !Bool,-    cfg_use_connectedness :: !Bool,-    cfg_set_join :: !Bool }--defaultConfig :: Config-defaultConfig =-  Config {-    cfg_ground_join = True,-    cfg_use_connectedness = True,-    cfg_set_join = False }--{-# INLINEABLE joinCriticalPair #-}-joinCriticalPair ::-  (Function f, Has a (Rule f), Has a (Lemma f)) =>-  Config ->-  Index f (Equation f) -> RuleIndex f a ->-  Maybe (Model f) -> -- A model to try before checking ground joinability-  CriticalPair f ->-  Either-    -- Failed to join critical pair.-    -- Returns simplified critical pair and model in which it failed to hold.-    (CriticalPair f, Model f)-    -- Split critical pair into several instances.-    -- Returns list of instances which must be joined,-    -- and an optional equation which can be added to the joinable set-    -- after successfully joining all instances.-    (Maybe (CriticalPair f), [CriticalPair f])-joinCriticalPair config eqns idx mmodel cp@CriticalPair{cp_eqn = t :=: u} =-  {-# SCC joinCriticalPair #-}-  case allSteps config eqns idx cp of-    Nothing ->-      Right (Nothing, [])-    _ | cfg_set_join config &&-        not (null $ Set.intersection-          (normalForms (rewrite reduces (index_all idx)) [reduce (Refl t)])-          (normalForms (rewrite reduces (index_all idx)) [reduce (Refl u)])) ->-      Right (Just cp, [])-    Just cp ->-      case groundJoinFromMaybe config eqns idx mmodel (branches (And [])) cp of-        Left model -> Left (cp, model)-        Right cps -> Right (Just cp, cps)--{-# INLINEABLE step1 #-}-{-# INLINEABLE step2 #-}-{-# INLINEABLE step3 #-}-{-# INLINEABLE allSteps #-}-step1, step2, step3, allSteps ::-  (Function f, Has a (Rule f), Has a (Lemma f)) =>-  Config -> Index f (Equation f) -> RuleIndex f a -> CriticalPair f -> Maybe (CriticalPair f)-allSteps config eqns idx cp =-  step1 config eqns idx cp >>=-  step2 config eqns idx >>=-  step3 config eqns idx-step1 _ eqns idx = joinWith eqns idx (\t _ -> normaliseWith (const True) (rewrite reducesOriented (index_oriented idx)) t)-step2 _ eqns idx = joinWith eqns idx (\t _ -> normaliseWith (const True) (rewrite reduces (index_all idx)) t)-step3 Config{..} eqns idx cp-  | not cfg_use_connectedness = Just cp-  | otherwise =-    case cp_top cp of-      Just top ->-        case (join (cp, top), join (flipCP (cp, top))) of-          (Just _, Just _) -> Just cp-          _ -> Nothing-      _ -> Just cp-  where-    join (cp, top) =-      joinWith eqns idx (\t u -> normaliseWith (`lessThan` top) (rewrite (ok t u) (index_all idx)) t) cp--    ok t u rule sub =-      unorient rule `simplerThan` (t :=: u) &&-      reducesSkolem rule sub--    flipCP :: Symbolic a => a -> a-    flipCP t = subst sub t-      where-        n = maximum (0:map fromEnum (vars t))-        sub (V x) = var (V (n - x))---{-# INLINEABLE joinWith #-}-joinWith ::-  (Has a (Rule f), Has a (Lemma f)) =>-  Index f (Equation f) -> RuleIndex f a -> (Term f -> Term f -> Resulting f) -> CriticalPair f -> Maybe (CriticalPair f)-joinWith eqns idx reduce cp@CriticalPair{cp_eqn = lhs :=: rhs, ..}-  | subsumed eqns idx eqn = Nothing-  | otherwise =-    Just cp {-      cp_eqn = eqn,-      cp_proof =-        Proof.symm (reductionProof (reduction lred)) `Proof.trans`-        cp_proof `Proof.trans`-        reductionProof (reduction rred) }-  where-    lred = reduce lhs rhs-    rred = reduce rhs lhs-    eqn = result lred :=: result rred--{-# INLINEABLE subsumed #-}-subsumed ::-  (Has a (Rule f), Has a (Lemma f)) =>-  Index f (Equation f) -> RuleIndex f a -> Equation f -> Bool-subsumed eqns idx (t :=: u)-  | t == u = True-  | or [ rhs rule == u | rule <- Index.lookup t (index_all idx) ] = True-  | or [ rhs rule == t | rule <- Index.lookup u (index_all idx) ] = True-    -- No need to do this symmetrically because addJoinable adds-    -- both orientations of each equation-  | or [ u == subst sub u'-       | t' :=: u' <- Index.approxMatches t eqns,-         sub <- maybeToList (match t' t) ] = True-subsumed eqns idx (App f ts :=: App g us)-  | f == g =-    let-      sub Empty Empty = True-      sub (Cons t ts) (Cons u us) =-        subsumed eqns idx (t :=: u) && sub ts us-      sub _ _ = error "Function used with multiple arities"-    in-      sub ts us-subsumed _ _ _ = False--{-# INLINEABLE groundJoin #-}-groundJoin ::-  (Function f, Has a (Rule f), Has a (Lemma f)) =>-  Config -> Index f (Equation f) -> RuleIndex f a -> [Branch f] -> CriticalPair f -> Either (Model f) [CriticalPair f]-groundJoin config eqns idx ctx cp@CriticalPair{cp_eqn = t :=: u, ..} =-  case partitionEithers (map (solve (usort (atoms t ++ atoms u))) ctx) of-    ([], instances) ->-      let cps = [ subst sub cp | sub <- instances ] in-      Right (usortBy (comparing (canonicalise . order . cp_eqn)) cps)-    (model:_, _) ->-      groundJoinFrom config eqns idx model ctx cp--{-# INLINEABLE groundJoinFrom #-}-groundJoinFrom ::-  (Function f, Has a (Rule f), Has a (Lemma f)) =>-  Config -> Index f (Equation f) -> RuleIndex f a -> Model f -> [Branch f] -> CriticalPair f -> Either (Model f) [CriticalPair f]-groundJoinFrom config@Config{..} eqns idx model ctx cp@CriticalPair{cp_eqn = t :=: u, ..}-  | not cfg_ground_join ||-    (modelOK model && isJust (allSteps config eqns idx cp { cp_eqn = t' :=: u' })) = Left model-  | otherwise =-      let model1 = optimise model weakenModel (\m -> not (modelOK m) || (valid m (reduction nt) && valid m (reduction nu)))-          model2 = optimise model1 weakenModel (\m -> not (modelOK m) || isNothing (allSteps config eqns idx cp { cp_eqn = result (normaliseIn m t u) :=: result (normaliseIn m u t) }))--          diag [] = Or []-          diag (r:rs) = negateFormula r ||| (weaken r &&& diag rs)-          weaken (LessEq t u) = Less t u-          weaken x = x-          ctx' = formAnd (diag (modelToLiterals model2)) ctx in--      groundJoin config eqns idx ctx' cp-  where-    normaliseIn m t u = normaliseWith (const True) (rewrite (ok t u m) (index_all idx)) t-    ok t u m rule sub =-      reducesInModel m rule sub &&-      unorient rule `simplerThan` (t :=: u)--    nt = normaliseIn model t u-    nu = normaliseIn model u t-    t' = result nt-    u' = result nu--    -- XXX not safe to exploit the top term if we then add the equation to-    -- the joinable set. (It might then be used to join a CP with an entirely-    -- different top term.)-    modelOK _ = True-{-    modelOK m =-      case cp_top of-        Nothing -> True-        Just top ->-          isNothing (lessIn m top t) && isNothing (lessIn m top u)-}--{-# INLINEABLE groundJoinFromMaybe #-}-groundJoinFromMaybe ::-  (Function f, Has a (Rule f), Has a (Lemma f)) =>-  Config -> Index f (Equation f) -> RuleIndex f a -> Maybe (Model f) -> [Branch f] -> CriticalPair f -> Either (Model f) [CriticalPair f]-groundJoinFromMaybe config eqns idx Nothing = groundJoin config eqns idx-groundJoinFromMaybe config eqns idx (Just model) = groundJoinFrom config eqns idx model--{-# INLINEABLE valid #-}-valid :: Function f => Model f -> Reduction f -> Bool-valid model red =-  and [ reducesInModel model rule sub-      | Step _ rule sub <- steps red ]--optimise :: a -> (a -> [a]) -> (a -> Bool) -> a-optimise x f p =-  case filter p (f x) of-    y:_ -> optimise y f p-    _   -> x
− src/Twee/KBO.hs
@@ -1,121 +0,0 @@--- | An implementation of Knuth-Bendix ordering.--{-# LANGUAGE PatternGuards #-}-module Twee.KBO(lessEq, lessIn) where--import Twee.Base hiding (lessEq, lessIn)-import Data.List-import Twee.Constraints hiding (lessEq, lessIn)-import qualified Data.Map.Strict as Map-import Data.Map.Strict(Map)-import Data.Maybe-import Control.Monad---- | Check if one term is less than another in KBO.-lessEq :: Function f => Term f -> Term f -> Bool-lessEq (App f Empty) _ | f == minimal = True-lessEq (Var x) (Var y) | x == y = True-lessEq _ (Var _) = False-lessEq (Var x) t = x `elem` vars t-lessEq t@(App f ts) u@(App g us) =-  (st < su ||-   (st == su && f << g) ||-   (st == su && f == g && lexLess ts us)) &&-  xs `isSubsequenceOf` ys-  where-    lexLess Empty Empty = True-    lexLess (Cons t ts) (Cons u us)-      | t == u = lexLess ts us-      | otherwise =-        lessEq t u &&-        case unify t u of-          Nothing -> True-          Just sub-            | not (allSubst (\_ (Cons t Empty) -> isMinimal t) sub) -> error "weird term inequality"-            | otherwise -> lexLess (subst sub ts) (subst sub us)-    lexLess _ _ = error "incorrect function arity"-    xs = sort (vars t)-    ys = sort (vars u)-    st = size t-    su = size u---- | Check if one term is less than another in a given model.---- See "notes/kbo under assumptions" for how this works.--lessIn :: Function f => Model f -> Term f -> Term f -> Maybe Strictness-lessIn model t u =-  case sizeLessIn model t u of-    Nothing -> Nothing-    Just Strict -> Just Strict-    Just Nonstrict -> lexLessIn model t u--sizeLessIn :: Function f => Model f -> Term f -> Term f -> Maybe Strictness-sizeLessIn model t u =-  case minimumIn model m of-    Just l-      | l >  -k -> Just Strict-      | l == -k -> Just Nonstrict-    _ -> Nothing-  where-    (k, m) =-      foldr (addSize id)-        (foldr (addSize negate) (0, Map.empty) (subterms t))-        (subterms u)-    addSize op (App f _) (k, m) = (k + op (size f), m)-    addSize op (Var x) (k, m) = (k, Map.insertWith (+) x (op 1) m)--minimumIn :: Function f => Model f -> Map Var Int -> Maybe Int-minimumIn model t =-  liftM2 (+)-    (fmap sum (mapM minGroup (varGroups model)))-    (fmap sum (mapM minOrphan (Map.toList t)))-  where-    minGroup (lo, xs, mhi)-      | all (>= 0) sums = Just (sum coeffs * size lo)-      | otherwise =-        case mhi of-          Nothing -> Nothing-          Just hi ->-            let coeff = negate (minimum coeffs) in-            Just $-              sum coeffs * size lo +-              coeff * (size lo - size hi)-      where-        coeffs = map (\x -> Map.findWithDefault 0 x t) xs-        sums = scanr1 (+) coeffs--    minOrphan (x, k)-      | varInModel model x = Just 0-      | k < 0 = Nothing-      | otherwise = Just k--lexLessIn :: Function f => Model f -> Term f -> Term f -> Maybe Strictness-lexLessIn _ t u | t == u = Just Nonstrict-lexLessIn cond t u-  | Just a <- fromTerm t,-    Just b <- fromTerm u,-    Just x <- lessEqInModel cond a b = Just x-  | Just a <- fromTerm t,-    any isJust-      [ lessEqInModel cond a b-      | v <- properSubterms u, Just b <- [fromTerm v]] =-        Just Strict-lexLessIn cond (App f ts) (App g us)-  | f == g = loop ts us-  | f << g = Just Strict-  | otherwise = Nothing-  where-    loop Empty Empty = Just Nonstrict-    loop (Cons t ts) (Cons u us)-      | t == u = loop ts us-      | otherwise =-        case lessIn cond t u of-          Nothing -> Nothing-          Just Strict -> Just Strict-          Just Nonstrict ->-            let Just sub = unify t u in-            loop (subst sub ts) (subst sub us)-    loop _ _ = error "incorrect function arity"-lexLessIn _ t _ | isMinimal t = Just Nonstrict-lexLessIn _ _ _ = Nothing
− src/Twee/Label.hs
@@ -1,125 +0,0 @@--- | Assignment of unique IDs to values.--- Inspired by the 'intern' package.--{-# LANGUAGE RecordWildCards, ScopedTypeVariables, BangPatterns #-}-module Twee.Label(Label, unsafeMkLabel, labelNum, label, find) where--import Data.IORef-import System.IO.Unsafe-import qualified Data.Map.Strict as Map-import Data.Map.Strict(Map)-import qualified Data.IntMap.Strict as IntMap-import Data.IntMap.Strict(IntMap)-import Data.Typeable-import GHC.Exts-import Unsafe.Coerce-import Data.Int---- | A value of type @a@ which has been given a unique ID.-newtype Label a =-  Label {-    -- | The unique ID of a label.-    labelNum :: Int32 }-  deriving (Eq, Ord, Show)---- | Construct a @'Label' a@ from its unique ID, which must be the 'labelNum' of--- an already existing 'Label'. Extremely unsafe!-unsafeMkLabel :: Int32 -> Label a-unsafeMkLabel = Label---- The global cache of labels.-{-# NOINLINE cachesRef #-}-cachesRef :: IORef Caches-cachesRef = unsafePerformIO (newIORef (Caches 0 Map.empty IntMap.empty))--data Caches =-  Caches {-    -- The next id number to assign.-    caches_nextId :: {-# UNPACK #-} !Int32,-    -- A map from values to labels.-    caches_from   :: !(Map TypeRep (Cache Any)),-    -- The reverse map from labels to values.-    caches_to     :: !(IntMap Any) }--type Cache a = Map a Int32--atomicModifyCaches :: (Caches -> (Caches, a)) -> IO a-atomicModifyCaches f = do-  -- N.B. atomicModifyIORef' ref f evaluates f ref *after* doing the-  -- compare-and-swap. This causes bad things to happen when 'label'-  -- is used reentrantly (i.e. the Ord instance itself calls label).-  -- This function only lets the swap happen if caches_nextId didn't-  -- change (i.e., no new values were inserted).-  !caches <- readIORef cachesRef-  -- First compute the update.-  let !(!caches', !x) = f caches-  -- Now see if anyone else updated the cache in between-  -- (can happen if f called 'label', or in a concurrent setting).-  ok <- atomicModifyIORef' cachesRef $ \cachesNow ->-    if caches_nextId caches == caches_nextId cachesNow-    then (caches', True)-    else (cachesNow, False)-  if ok then return x else atomicModifyCaches f---- Versions of unsafeCoerce with slightly more type checking-toAnyCache :: Cache a -> Cache Any-toAnyCache = unsafeCoerce--fromAnyCache :: Cache Any -> Cache a-fromAnyCache = unsafeCoerce--toAny :: a -> Any-toAny = unsafeCoerce--fromAny :: Any -> a-fromAny = unsafeCoerce---- | Assign a label to a value.-{-# NOINLINE label #-}-label :: forall a. (Typeable a, Ord a) => a -> Label a-label x =-  unsafeDupablePerformIO $ do-    -- Common case: label is already there.-    caches <- readIORef cachesRef-    case tryFind caches of-      Just l -> return l-      Nothing -> do-        -- Rare case: label was not there.-        x <- atomicModifyCaches $ \caches ->-          case tryFind caches of-            Just l -> (caches, l)-            Nothing ->-              insert caches-        return x--  where-    ty = typeOf x--    tryFind :: Caches -> Maybe (Label a)-    tryFind Caches{..} =-      Label <$> (Map.lookup ty caches_from >>= Map.lookup x . fromAnyCache)--    insert :: Caches -> (Caches, Label a)-    insert caches@Caches{..} =-      if n < 0 then error "label overflow" else-      (caches {-         caches_nextId = n+1,-         caches_from = Map.insert ty (toAnyCache (Map.insert x n cache)) caches_from,-         caches_to = IntMap.insert (fromIntegral n) (toAny x) caches_to },-       Label n)-      where-        n = caches_nextId-        cache =-          fromAnyCache $-          Map.findWithDefault Map.empty ty caches_from---- | Recover the underlying value from a label.-find :: Label a -> a--- N.B. must force n before calling readIORef, otherwise a call of--- the form---   find (label x)--- doesn't work.-find (Label !n) = unsafeDupablePerformIO $ do-  Caches{..} <- readIORef cachesRef-  x <- return $! fromAny (IntMap.findWithDefault undefined (fromIntegral n) caches_to)-  return x
− src/Twee/PassiveQueue.hs
@@ -1,183 +0,0 @@--- | A queue of passive critical pairs, using a memory-efficient representation.-{-# LANGUAGE TypeFamilies, RecordWildCards, FlexibleContexts, ScopedTypeVariables, StandaloneDeriving #-}-module Twee.PassiveQueue(-  Params(..),-  Queue,-  Passive(..),-  empty, insert, removeMin, mapMaybe) where--import qualified Data.Heap as Heap-import qualified Data.Vector.Unboxed as Vector-import Data.Int-import Data.List hiding (insert)-import qualified Data.Maybe-import Data.Ord-import Data.Proxy-import Twee.Utils---- | A datatype representing all the type parameters of the queue.-class (Eq (Id params), Integral (Id params), Ord (Score params), Vector.Unbox (PackedScore params), Vector.Unbox (PackedId params)) => Params params where-  -- | The score assigned to critical pairs. Smaller scores are better.-  type Score params-  -- | The type of ID numbers used to name rules.-  type Id params--  -- | A 'Score' packed for storage into a 'Vector.Vector'. Must be an instance of 'Vector.Unbox'.-  type PackedScore params-  -- | An 'Id' packed for storage into a 'Vector.Vector'. Must be an instance of 'Vector.Unbox'.-  type PackedId params--  -- | Pack a 'Score'.-  packScore :: proxy params -> Score params -> PackedScore params-  -- | Unpack a 'PackedScore'.-  unpackScore :: proxy params -> PackedScore params -> Score params-  -- | Pack an 'Id'.-  packId :: proxy params -> Id params -> PackedId params-  -- | Unpack a 'PackedId'.-  unpackId :: proxy params -> PackedId params -> Id params---- | A critical pair queue.-newtype Queue params =-  Queue (Heap.Heap (PassiveSet params))---- All passive CPs generated from one given rule.-data PassiveSet params =-  PassiveSet {-    passiveset_best  :: {-# UNPACK #-} !(Passive params),-    passiveset_rule  :: !(Id params),-    -- CPs where the rule is the left-hand rule-    passiveset_left  :: {-# UNPACK #-} !(Vector.Vector (PackedScore params, PackedId params, Int32)),-    -- CPs where the rule is the right-hand rule-    passiveset_right :: {-# UNPACK #-} !(Vector.Vector (PackedScore params, PackedId params, Int32)) }-instance Params params => Eq (PassiveSet params) where-  x == y = compare x y == EQ-instance Params params => Ord (PassiveSet params) where-  compare = comparing passiveset_best---- A smart-ish constructor.-{-# INLINEABLE mkPassiveSet #-}-mkPassiveSet ::-  Params params =>-  Proxy params ->-  Id params ->-  Vector.Vector (PackedScore params, PackedId params, Int32) ->-  Vector.Vector (PackedScore params, PackedId params, Int32) ->-  Maybe (PassiveSet params)-mkPassiveSet proxy rule left right-  | Vector.null left && Vector.null right = Nothing-  | not (Vector.null left) &&-    (Vector.null right || l <= r) =-    Just PassiveSet {-      passiveset_best  = l,-      passiveset_rule  = rule,-      passiveset_left  = Vector.tail left,-      passiveset_right = right }-    -- In this case we must have not (Vector.null right).-  | otherwise =-    Just PassiveSet {-      passiveset_best  = r,-      passiveset_rule  = rule,-      passiveset_left  = left,-      passiveset_right = Vector.tail right }-  where-    l = unpack proxy rule True (Vector.head left)-    r = unpack proxy rule False (Vector.head right)---- Unpack a triple into a Passive.-{-# INLINEABLE unpack #-}-unpack :: Params params => Proxy params -> Id params -> Bool -> (PackedScore params, PackedId params, Int32) -> Passive params-unpack proxy rule isLeft (score, id, pos) =-  Passive {-    passive_score = unpackScore proxy score,-    passive_rule1 = if isLeft then rule else rule',-    passive_rule2 = if isLeft then rule' else rule,-    passive_pos = fromIntegral pos }-  where-    rule' = unpackId proxy id---- Make a PassiveSet from a list of Passives.-{-# INLINEABLE makePassiveSet #-}-makePassiveSet :: forall params. Params params => Id params -> [Passive params] -> Maybe (PassiveSet params)-makePassiveSet _ [] = Nothing-makePassiveSet rule ps-  | and [passive_rule2 p == rule | p <- right] =-    mkPassiveSet proxy rule-      (Vector.fromList (map (pack True) (sort left)))-      (Vector.fromList (map (pack False) (sort right)))-  | otherwise = error "rule id does not occur in passive"-  where-    proxy :: Proxy params-    proxy = Proxy-    -    (left, right) = partition (\p -> passive_rule1 p == rule) ps-    pack isLeft Passive{..} =-      (packScore proxy passive_score,-       packId proxy (if isLeft then passive_rule2 else passive_rule1),-       fromIntegral passive_pos)---- Find and remove the best element from a PassiveSet.-{-# INLINEABLE unconsPassiveSet #-}-unconsPassiveSet :: forall params. Params params => PassiveSet params -> (Passive params, Maybe (PassiveSet params))-unconsPassiveSet PassiveSet{..} =-  (passiveset_best, mkPassiveSet (Proxy :: Proxy params) passiveset_rule passiveset_left passiveset_right)---- | A queued critical pair.-data Passive params =-  Passive {-    -- | The score of this critical pair.-    passive_score :: !(Score params),-    -- | The rule which does the outermost rewrite in this critical pair.-    passive_rule1 :: !(Id params),-    -- | The rule which does the innermost rewrite in this critical pair.-    passive_rule2 :: !(Id params),-    -- | The position of the overlap. See 'Twee.CP.overlap_pos'.-    passive_pos   :: {-# UNPACK #-} !Int }--instance Params params => Eq (Passive params) where-  x == y = compare x y == EQ--instance Params params => Ord (Passive params) where-  compare = comparing f-    where-      f Passive{..} =-        (passive_score,-         intMax (fromIntegral passive_rule1) (fromIntegral passive_rule2),-         intMin (fromIntegral passive_rule1) (fromIntegral passive_rule2),-         passive_pos)---- | The empty queue.-empty :: Queue params-empty = Queue Heap.empty---- | Add a set of 'Passive's to the queue.-{-# INLINEABLE insert #-}-insert :: Params params => Id params -> [Passive params] -> Queue params -> Queue params-insert rule passives (Queue q) =-  Queue $-  case makePassiveSet rule passives of-    Nothing -> q-    Just p -> Heap.insert p q---- | Remove the minimum 'Passive' from the queue.-{-# INLINEABLE removeMin #-}-removeMin :: Params params => Queue params -> Maybe (Passive params, Queue params)-removeMin (Queue q) = do-  (passiveset, q) <- Heap.removeMin q-  case unconsPassiveSet passiveset of-    (passive, Just passiveset') ->-      Just (passive, Queue (Heap.insert passiveset' q))-    (passive, Nothing) ->-      Just (passive, Queue q)---- | Map a function over all 'Passive's.-{-# INLINEABLE mapMaybe #-}-mapMaybe :: Params params => (Passive params -> Maybe (Passive params)) -> Queue params -> Queue params-mapMaybe f (Queue q) = Queue (Heap.mapMaybe g q)-  where-    g PassiveSet{..} =-      makePassiveSet passiveset_rule $ Data.Maybe.mapMaybe f $-        passiveset_best:-        map (unpack proxy passiveset_rule True) (Vector.toList passiveset_left) ++-        map (unpack proxy passiveset_rule False) (Vector.toList passiveset_right)-    proxy :: Proxy params-    proxy = Proxy
− src/Twee/Pretty.hs
@@ -1,182 +0,0 @@--- | Pretty-printing of terms and assorted other values.--{-# LANGUAGE Rank2Types #-}-module Twee.Pretty(module Twee.Pretty, module Text.PrettyPrint.HughesPJClass, Pretty(..)) where--import Text.PrettyPrint.HughesPJClass hiding (empty)-import qualified Text.PrettyPrint.HughesPJClass as PP-import qualified Data.Map as Map-import Data.Map(Map)-import qualified Data.Set as Set-import Data.Set(Set)-import Data.Ratio-import Twee.Term---- * Miscellaneous 'Pretty' instances and utilities.---- | Print a value to the console.-prettyPrint :: Pretty a => a -> IO ()-prettyPrint x = putStrLn (prettyShow x)---- | The empty document. Used to avoid name clashes with 'Twee.Term.empty'.-pPrintEmpty :: Doc-pPrintEmpty = PP.empty--instance Pretty Doc where pPrint = id---- | Print a tuple of values.-pPrintTuple :: [Doc] -> Doc-pPrintTuple = parens . fsep . punctuate comma--instance Pretty a => Pretty (Set a) where-  pPrint = pPrintSet . map pPrint . Set.toList---- | Print a set of vlaues.-pPrintSet :: [Doc] -> Doc-pPrintSet = braces . fsep . punctuate comma--instance Pretty Var where-  pPrint (V n) =-    text $-      vars !! (n `mod` length vars):-      case n `div` length vars of-        0 -> ""-        m -> show (m+1)-    where-      vars = "XYZWVUTS"--instance (Pretty k, Pretty v) => Pretty (Map k v) where-  pPrint = pPrintSet . map binding . Map.toList-    where-      binding (x, v) = hang (pPrint x <+> text "=>") 2 (pPrint v)--instance (Eq a, Integral a, Pretty a) => Pretty (Ratio a) where-  pPrint a-    | denominator a == 1 = pPrint (numerator a)-    | otherwise = text "(" <+> pPrint (numerator a) <> text "/" <> pPrint (denominator a) <+> text ")"---- | Generate a list of candidate names for pretty-printing.-supply :: [String] -> [String]-supply names =-  names ++-  [ name ++ show i | i <- [2..], name <- names ]---- * Pretty-printing of terms.--instance Pretty f => Pretty (Fun f) where-  pPrintPrec l p = pPrintPrec l p . fun_value--instance PrettyTerm f => PrettyTerm (Fun f) where-  termStyle f = termStyle (fun_value f)--instance PrettyTerm f => Pretty (Term f) where-  pPrintPrec l p (Var x) = pPrintPrec l p x-  pPrintPrec l p (App f xs) =-    pPrintTerm (termStyle f) l p (pPrint f) (unpack xs)--instance PrettyTerm f => Pretty (TermList f) where-  pPrintPrec _ _ = pPrint . unpack--instance PrettyTerm f => Pretty (Subst f) where-  pPrint sub = text "{" <> fsep (punctuate (text ",") docs) <> text "}"-    where-      docs =-        [ hang (pPrint x <+> text "->") 2 (pPrint t)-        | (x, t) <- substToList sub ]---- | A class for customising the printing of function symbols.-class Pretty f => PrettyTerm f where-  -- | The style of the function symbol. Defaults to 'curried'.-  termStyle :: f -> TermStyle-  termStyle _ = curried---- | Defines how to print out a function symbol.-newtype TermStyle =-  TermStyle {-    -- | Renders a function application.-    -- Takes the following arguments in this order:-    -- Pretty-printing level, current precedence,-    -- pretty-printed function symbol and list of arguments to the function.-    pPrintTerm :: forall a. Pretty a => PrettyLevel -> Rational -> Doc -> [a] -> Doc }--invisible, curried, uncurried, prefix, postfix :: TermStyle---- | For operators like @$@ that should be printed as a blank space.-invisible =-  TermStyle $ \l p d ->-    let-      f [] = d-      f [t] = pPrintPrec l p t-      f (t:ts) =-        maybeParens (p > 10) $-          pPrint t <+>-            (hsep (map (pPrintPrec l 11) ts))-    in f---- | For functions that should be printed curried.-curried =-  TermStyle $ \l p d ->-    let-      f [] = d-      f xs =-        maybeParens (p > 10) $-          d <+>-            (hsep (map (pPrintPrec l 11) xs))-    in f---- | For functions that should be printed uncurried.-uncurried =-  TermStyle $ \l _ d ->-    let-      f [] = d-      f xs =-        d <> parens (hsep (punctuate comma (map (pPrintPrec l 0) xs)))-    in f---- | A helper function that deals with under- and oversaturated applications.-fixedArity :: Int -> TermStyle -> TermStyle-fixedArity arity style =-  TermStyle $ \l p d ->-    let-      f xs-        | length xs < arity = pPrintTerm curried l p (parens d) xs-        | length xs > arity =-            maybeParens (p > 10) $-              hsep (pPrintTerm style l 11 d ys:-                    map (pPrintPrec l 11) zs)-        | otherwise = pPrintTerm style l p d xs-        where-          (ys, zs) = splitAt arity xs-    in f---- | A helper function that drops a certain number of arguments.-implicitArguments :: Int -> TermStyle -> TermStyle-implicitArguments n (TermStyle pp) =-  TermStyle $ \l p d xs -> pp l p d (drop n xs)---- | For prefix operators.-prefix =-  fixedArity 1 $-  TermStyle $ \l _ d [x] ->-    d <> pPrintPrec l 11 x---- | For postfix operators.-postfix =-  fixedArity 1 $-  TermStyle $ \l _ d [x] ->-    pPrintPrec l 11 x <> d---- | For infix operators.-infixStyle :: Int -> TermStyle-infixStyle pOp =-  fixedArity 2 $-  TermStyle $ \l p d [x, y] ->-    maybeParens (p > fromIntegral pOp) $-      pPrintPrec l (fromIntegral pOp+1) x <+> d <+>-      pPrintPrec l (fromIntegral pOp+1) y---- | For tuples.-tupleStyle :: TermStyle-tupleStyle =-  TermStyle $ \l _ _ xs ->-    parens (hsep (punctuate comma (map (pPrintPrec l 0) xs)))
− src/Twee/Proof.hs
@@ -1,723 +0,0 @@--- | Equational proofs which are checked for correctedness.-{-# LANGUAGE TypeFamilies, PatternGuards, RecordWildCards, ScopedTypeVariables #-}-module Twee.Proof(-  -- * Constructing proofs-  Proof, Derivation(..), Lemma(..), Axiom(..),-  certify, equation, derivation,-  -- ** Smart constructors for derivations-  lemma, axiom, symm, trans, cong, congPath,--  -- * Analysing proofs-  simplify, usedLemmas, usedAxioms, usedLemmasAndSubsts, usedAxiomsAndSubsts,--  -- * Pretty-printing proofs-  Config(..), defaultConfig, Presentation(..),-  ProvedGoal(..), provedGoal, checkProvedGoal,-  pPrintPresentation, present, describeEquation) where--import Twee.Base hiding (invisible)-import Twee.Equation-import Twee.Utils-import Control.Monad-import Data.Maybe-import Data.List-import Data.Ord-import qualified Data.Set as Set-import qualified Data.Map.Strict as Map--------------------------------------------------------------------------- Equational proofs. Only valid proofs can be constructed.--------------------------------------------------------------------------- | A checked proof. If you have a value of type @Proof f@,--- it should jolly well represent a valid proof!------ The only way to construct a @Proof f@ is by using 'certify'.-data Proof f =-  Proof {-    equation   :: !(Equation f),-    derivation :: !(Derivation f) }-  deriving (Eq, Show)---- | A derivation is an unchecked proof. It might be wrong!--- The way to check it is to call 'certify' to turn it into a 'Proof'.-data Derivation f =-    -- | Apply an existing rule (with proof!) to the root of a term-    UseLemma {-# UNPACK #-} !(Lemma f) !(Subst f)-    -- | Apply an axiom to the root of a term-  | UseAxiom {-# UNPACK #-} !(Axiom f) !(Subst f)-    -- | Reflexivity. @'Refl' t@ proves @t = t@.-  | Refl !(Term f)-    -- | Symmetry-  | Symm !(Derivation f)-    -- | Transivitity-  | Trans !(Derivation f) !(Derivation f)-    -- | Congruence.-    -- Parallel, i.e., takes a function symbol and one derivation for each-    -- argument of that function.-  | Cong {-# UNPACK #-} !(Fun f) ![Derivation f]-  deriving (Eq, Show)---- | A lemma, which includes a proof.-data Lemma f =-  Lemma {-    -- | The id number of the lemma.-    -- Has no semantic meaning; for convenience only.-    lemma_id :: {-# UNPACK #-} !Id,-    -- | A proof of the lemma.-    lemma_proof :: !(Proof f) }-  deriving Show----  | An axiom, which comes without proof.-data Axiom f =-  Axiom {-    -- | The number of the axiom.-    -- Has no semantic meaning; for convenience only.-    axiom_number :: {-# UNPACK #-} !Int,-    -- | A description of the axiom.-    -- Has no semantic meaning; for convenience only.-    axiom_name :: !String,-    -- | The equation which the axiom asserts.-    axiom_eqn :: !(Equation f) }-  deriving (Eq, Ord, Show)---- | Checks a 'Derivation' and, if it is correct, returns a--- certified 'Proof'.------ If the 'Derivation' is incorrect, throws an exception.---- This is the trusted core of the module.-{-# INLINEABLE certify #-}-certify :: PrettyTerm f => Derivation f -> Proof f-certify p =-  {-# SCC certify #-}-  case check p of-    Nothing -> error ("Invalid proof created!\n" ++ prettyShow p)-    Just eqn -> Proof eqn p-  where-    check (UseLemma Lemma{..} sub) =-      return (subst sub (equation lemma_proof))-    check (UseAxiom Axiom{..} sub) =-      return (subst sub axiom_eqn)-    check (Refl t) =-      return (t :=: t)-    check (Symm p) = do-      t :=: u <- check p-      return (u :=: t)-    check (Trans p q) = do-      t :=: u1 <- check p-      u2 :=: v <- check q-      guard (u1 == u2)-      return (t :=: v)-    check (Cong f ps) = do-      eqns <- mapM check ps-      return-        (build (app f (map eqn_lhs eqns)) :=:-         build (app f (map eqn_rhs eqns)))--------------------------------------------------------------------------- Everything below this point need not be trusted, since all proof--- construction goes through the "proof" function.--------------------------------------------------------------------------- Typeclass instances.-instance Eq (Lemma f) where-  x == y = compare x y == EQ-instance Ord (Lemma f) where-  compare =-    comparing (\x ->-      -- Don't look into lemma proofs when comparing derivations,-      -- to avoid exponential blowup-      (lemma_id x, equation (lemma_proof x)))--instance Symbolic (Derivation f) where-  type ConstantOf (Derivation f) = f-  termsDL (UseLemma _ sub) = termsDL sub-  termsDL (UseAxiom _ sub) = termsDL sub-  termsDL (Refl t) = termsDL t-  termsDL (Symm p) = termsDL p-  termsDL (Trans p q) = termsDL p `mplus` termsDL q-  termsDL (Cong _ ps) = termsDL ps--  subst_ sub (UseLemma lemma s) = UseLemma lemma (subst_ sub s)-  subst_ sub (UseAxiom axiom s) = UseAxiom axiom (subst_ sub s)-  subst_ sub (Refl t) = Refl (subst_ sub t)-  subst_ sub (Symm p) = symm (subst_ sub p)-  subst_ sub (Trans p q) = trans (subst_ sub p) (subst_ sub q)-  subst_ sub (Cong f ps) = cong f (subst_ sub ps)--instance Function f => Pretty (Proof f) where-  pPrint = pPrintLemma defaultConfig prettyShow-instance PrettyTerm f => Pretty (Derivation f) where-  pPrint (UseLemma lemma sub) =-    text "subst" <> pPrintTuple [pPrint lemma, pPrint sub]-  pPrint (UseAxiom axiom sub) =-    text "subst" <> pPrintTuple [pPrint axiom, pPrint sub]-  pPrint (Refl t) =-    text "refl" <> pPrintTuple [pPrint t]-  pPrint (Symm p) =-    text "symm" <> pPrintTuple [pPrint p]-  pPrint (Trans p q) =-    text "trans" <> pPrintTuple [pPrint p, pPrint q]-  pPrint (Cong f ps) =-    text "cong" <> pPrintTuple (pPrint f:map pPrint ps)--instance PrettyTerm f => Pretty (Axiom f) where-  pPrint Axiom{..} =-    text "axiom" <>-    pPrintTuple [pPrint axiom_number, text axiom_name, pPrint axiom_eqn]--instance PrettyTerm f => Pretty (Lemma f) where-  pPrint Lemma{..} =-    text "lemma" <>-    pPrintTuple [pPrint lemma_id, pPrint (equation lemma_proof)]---- | Simplify a derivation.------ After simplification, a derivation has the following properties:------   * 'Symm' is pushed down next to 'Lemma' and 'Axiom'---   * 'Refl' only occurs inside 'Cong' or at the top level---   * 'Trans' is right-associated and is pushed inside 'Cong' if possible-simplify :: Minimal f => (Lemma f -> Maybe (Derivation f)) -> Derivation f -> Derivation f-simplify lem p = simp p-  where-    simp p@(UseLemma lemma sub) =-      case lem lemma of-        Nothing -> p-        Just q ->-          let-            -- Get rid of any variables that are not bound by sub-            -- (e.g., ones which only occur internally in q)-            dead = usort (vars q) \\ substDomain sub-          in simp (subst sub (erase dead q))-    simp (Symm p) = symm (simp p)-    simp (Trans p q) = trans (simp p) (simp q)-    simp (Cong f ps) = cong f (map simp ps)-    simp p = p--lemma :: Lemma f -> Subst f -> Derivation f-lemma lem@Lemma{..} sub = UseLemma lem sub--axiom :: Axiom f -> Derivation f-axiom ax@Axiom{..} =-  UseAxiom ax $-    fromJust $-    listToSubst [(x, build (var x)) | x <- vars axiom_eqn]--symm :: Derivation f -> Derivation f-symm (Refl t) = Refl t-symm (Symm p) = p-symm (Trans p q) = trans (symm q) (symm p)-symm (Cong f ps) = cong f (map symm ps)-symm p = Symm p--trans :: Derivation f -> Derivation f -> Derivation f-trans Refl{} p = p-trans p Refl{} = p-trans (Trans p q) r =-  -- Right-associate uses of transitivity.-  -- p cannot be a Trans (if it was created with the smart-  -- constructors) but q could be.-  Trans p (trans q r)--- Collect adjacent uses of congruence.-trans (Cong f ps) (Cong g qs) | f == g =-  transCong f ps qs-trans (Cong f ps) (Trans (Cong g qs) r) | f == g =-  trans (transCong f ps qs) r-trans p q = Trans p q--transCong :: Fun f -> [Derivation f] -> [Derivation f] -> Derivation f-transCong f ps qs =-  cong f (zipWith trans ps qs)--cong :: Fun f -> [Derivation f] -> Derivation f-cong f ps =-  case sequence (map unRefl ps) of-    Nothing -> Cong f ps-    Just ts -> Refl (build (app f ts))-  where-    unRefl (Refl t) = Just t-    unRefl _ = Nothing---- | Find all lemmas which are used in a derivation.-usedLemmas :: Derivation f -> [Lemma f]-usedLemmas p = map fst (usedLemmasAndSubsts p)---- | Find all lemmas which are used in a derivation,--- together with the substitutions used.-usedLemmasAndSubsts :: Derivation f -> [(Lemma f, Subst f)]-usedLemmasAndSubsts p = lem p []-  where-    lem (UseLemma lemma sub) = ((lemma, sub):)-    lem (Symm p) = lem p-    lem (Trans p q) = lem p . lem q-    lem (Cong _ ps) = foldr (.) id (map lem ps)-    lem _ = id---- | Find all axioms which are used in a derivation.-usedAxioms :: Derivation f -> [Axiom f]-usedAxioms p = map fst (usedAxiomsAndSubsts p)---- | Find all axioms which are used in a derivation,--- together with the substitutions used.-usedAxiomsAndSubsts :: Derivation f -> [(Axiom f, Subst f)]-usedAxiomsAndSubsts p = ax p []-  where-    ax (UseAxiom axiom sub) = ((axiom, sub):)-    ax (Symm p) = ax p-    ax (Trans p q) = ax p . ax q-    ax (Cong _ ps) = foldr (.) id (map ax ps)-    ax _ = id---- | Applies a derivation at a particular path in a term.-congPath :: [Int] -> Term f -> Derivation f -> Derivation f-congPath [] _ p = p-congPath (n:ns) (App f t) p | n <= length ts =-  cong f $-    map Refl (take n ts) ++-    [congPath ns (ts !! n) p] ++-    map Refl (drop (n+1) ts)-  where-    ts = unpack t-congPath _ _ _ = error "bad path"--------------------------------------------------------------------------- Pretty-printing of proofs.--------------------------------------------------------------------------- | Options for proof presentation.-data Config =-  Config {-    -- | Never inline lemmas.-    cfg_all_lemmas :: !Bool,-    -- | Inline all lemmas.-    cfg_no_lemmas :: !Bool,-    -- | Print out explicit substitutions.-    cfg_show_instances :: !Bool }---- | The default configuration.-defaultConfig :: Config-defaultConfig =-  Config {-    cfg_all_lemmas = False,-    cfg_no_lemmas = False,-    cfg_show_instances = False }---- | A proof, with all axioms and lemmas explicitly listed.-data Presentation f =-  Presentation {-    -- | The used axioms.-    pres_axioms :: [Axiom f],-    -- | The used lemmas.-    pres_lemmas :: [Lemma f],-    -- | The goals proved.-    pres_goals  :: [ProvedGoal f] }-  deriving Show---- Note: only the pg_proof field should be trusted!--- The remaining fields are for information only.-data ProvedGoal f =-  ProvedGoal {-    pg_number  :: Int,-    pg_name    :: String,-    pg_proof   :: Proof f,--    -- Extra fields for existentially-quantified goals, giving the original goal-    -- and the existential witness. These fields are not verified. If you want-    -- to check them, use checkProvedGoal.-    ---    -- In general, subst pg_witness_hint pg_goal_hint == equation pg_proof.-    -- For non-existential goals, pg_goal_hint == equation pg_proof-    -- and pg_witness_hint is the empty substitution.-    pg_goal_hint    :: Equation f,-    pg_witness_hint :: Subst f }-  deriving Show---- | Construct a @ProvedGoal@.-provedGoal :: Int -> String -> Proof f -> ProvedGoal f-provedGoal number name proof =-  ProvedGoal {-    pg_number = number,-    pg_name = name,-    pg_proof = proof,-    pg_goal_hint = equation proof,-    pg_witness_hint = emptySubst }---- | Check that pg_goal/pg_witness match up with pg_proof.-checkProvedGoal :: Function f => ProvedGoal f -> ProvedGoal f-checkProvedGoal pg@ProvedGoal{..}-  | subst pg_witness_hint pg_goal_hint == equation pg_proof =-    pg-  | otherwise =-    error $ show $-      text "Invalid ProvedGoal!" $$-      text "Claims to prove" <+> pPrint pg_goal_hint $$-      text "with witness" <+> pPrint pg_witness_hint <> text "," $$-      text "but actually proves" <+> pPrint (equation pg_proof)--instance Function f => Pretty (Presentation f) where-  pPrint = pPrintPresentation defaultConfig---- | Simplify and present a proof.-present :: Function f => Config -> [ProvedGoal f] -> Presentation f-present config goals =-  -- First find all the used lemmas, then hand off to presentWithGoals-  presentWithGoals config goals-    (used Set.empty (concatMap (usedLemmas . derivation . pg_proof) goals))-  where-    used lems [] = Set.elems lems-    used lems (x:xs)-      | x `Set.member` lems = used lems xs-      | otherwise =-        used (Set.insert x lems)-          (usedLemmas (derivation (lemma_proof x)) ++ xs)--presentWithGoals ::-  Function f =>-  Config -> [ProvedGoal f] -> [Lemma f] -> Presentation f-presentWithGoals config@Config{..} goals lemmas-  -- We inline a lemma if one of the following holds:-  --   * It only has one step-  --   * It is subsumed by an earlier lemma-  --   * It is only used once-  --   * It has to do with $equals (for printing of the goal proof)-  --   * The option cfg_no_lemmas is true-  -- First we compute all inlinings, then apply simplify to remove them,-  -- then repeat if any lemma was inlined-  | Map.null inlinings =-    let-      axioms = usort $-        concatMap (usedAxioms . derivation . pg_proof) goals ++-        concatMap (usedAxioms . derivation . lemma_proof) lemmas-    in-      Presentation axioms-        [ lemma { lemma_proof = flattenProof lemma_proof }-        | lemma@Lemma{..} <- lemmas ]-        [ decodeGoal (goal { pg_proof = flattenProof pg_proof })-        | goal@ProvedGoal{..} <- goals ]--  | otherwise =-    let-      inline lemma = Map.lookup lemma inlinings--      goals' =-        [ decodeGoal (goal { pg_proof = certify $ simplify inline (derivation pg_proof) })-        | goal@ProvedGoal{..} <- goals ]-      lemmas' =-        [ Lemma n (certify $ simplify inline (derivation p))-        | lemma@(Lemma n p) <- lemmas, not (lemma `Map.member` inlinings) ]-    in-      presentWithGoals config goals' lemmas'--  where-    inlinings =-      Map.fromList-        [ (lemma, p)-        | lemma <- lemmas, Just p <- [tryInline lemma]]--    tryInline (Lemma n p)-      | shouldInline n p = Just (derivation p)-    tryInline (Lemma n p)-      -- Check for subsumption by an earlier lemma-      | Just (Lemma m q) <- Map.lookup (canonicalise (t :=: u)) equations, m < n =-        Just (subsume p (derivation q))-      | Just (Lemma m q) <- Map.lookup (canonicalise (u :=: t)) equations, m < n =-        Just (subsume p (Symm (derivation q)))-      where-        t :=: u = equation p-    tryInline _ = Nothing--    shouldInline n p =-      cfg_no_lemmas ||-      oneStep (derivation p) ||-      (not cfg_all_lemmas &&-       (isJust (decodeEquality (eqn_lhs (equation p))) ||-        isJust (decodeEquality (eqn_rhs (equation p))) ||-        Map.lookup n uses == Just 1))-  -    subsume p q =-      -- Rename q so its variables match p's-      subst sub q-      where-        t  :=: u  = equation p-        t' :=: u' = equation (certify q)-        Just sub  = matchList (buildList [t', u']) (buildList [t, u])--    -- Record which lemma proves each equation-    equations =-      Map.fromList-        [ (canonicalise (equation lemma_proof), lemma)-        | lemma@Lemma{..} <- lemmas]--    -- Count how many times each lemma is used-    uses =-      Map.fromListWith (+)-        [ (lemma_id, 1)-        | Lemma{..} <--            concatMap usedLemmas-              (map (derivation . pg_proof) goals ++-               map (derivation . lemma_proof) lemmas) ]--    -- Check if a proof only has one step.-    -- Trans only occurs at the top level by this point.-    oneStep Trans{} = False-    oneStep _ = True--invisible :: Function f => Equation f -> Bool-invisible (t :=: u) = show (pPrint t) == show (pPrint u)---- Pretty-print the proof of a single lemma.-pPrintLemma :: Function f => Config -> (Id -> String) -> Proof f -> Doc-pPrintLemma Config{..} lemmaName p =-  ppTerm (eqn_lhs (equation q)) $$ pp (derivation q)-  where-    q = flattenProof p--    pp (Trans p q) = pp p $$ pp q-    pp p | invisible (equation (certify p)) = pPrintEmpty-    pp p =-      (text "= { by" <+>-       ppStep-         (nub (map (show . ppLemma) (usedLemmasAndSubsts p)) ++-          nub (map (show . ppAxiom) (usedAxiomsAndSubsts p))) <+>-       text "}" $$-       ppTerm (eqn_rhs (equation (certify p))))--    ppTerm t = text "  " <> pPrint t--    ppStep [] = text "reflexivity" -- ??-    ppStep [x] = text x-    ppStep xs =-      hcat (punctuate (text ", ") (map text (init xs))) <+>-      text "and" <+>-      text (last xs)--    ppLemma (Lemma{..}, sub) =-      text "lemma" <+> text (lemmaName lemma_id) <> showSubst sub-    ppAxiom (Axiom{..}, sub) =-      text "axiom" <+> pPrint axiom_number <+> parens (text axiom_name) <> showSubst sub--    showSubst sub-      | cfg_show_instances && not (null (substToList sub)) =-        text " with " <>-        fsep (punctuate comma-          [ pPrint x <+> text "->" <+> pPrint t-          | (x, t) <- substToList sub ])-      | otherwise = pPrintEmpty---- Transform a proof so that each step uses exactly one axiom--- or lemma. The proof will have the following form afterwards:---   * Trans only occurs at the outermost level and is right-associated---   * Each Cong has exactly one non-Refl argument (no parallel rewriting)---   * Symm only occurs innermost, i.e., next to UseLemma or UseAxiom---   * Refl only occurs as an argument to Cong, or outermost if the---     whole proof is a single reflexivity step-flattenProof :: Function f => Proof f -> Proof f-flattenProof =-  certify . flat . simplify (const Nothing) . derivation-  where-    flat (Trans p q) = trans (flat p) (flat q)-    flat p@(Cong f ps) =-      foldr trans (reflAfter p)-        [ Cong f $-            map reflAfter (take i ps) ++-            [p] ++-            map reflBefore (drop (i+1) ps)-        | (i, q) <- zip [0..] qs,-          p <- steps q ]-      where-        qs = map flat ps-    flat p = p--    reflBefore p = Refl (eqn_lhs (equation (certify p)))-    reflAfter p  = Refl (eqn_rhs (equation (certify p)))--    steps Refl{} = []-    steps (Trans p q) = steps p ++ steps q-    steps p = [p]--    trans (Trans p q) r = trans p (trans q r)-    trans Refl{} p = p-    trans p Refl{} = p-    trans p q =-      case strip q of-        Nothing -> Trans p q-        Just q' -> trans p q'--    strip p-      | t == u = Just (Refl t)-      | otherwise = strip' t p-      where-        t :=: u = equation (certify p)-    strip' t (Trans _ q)-      | eqn_lhs (equation (certify q)) == t = Just q-      | otherwise = strip' t q-    strip' _ _ = Nothing---- Transform a derivation into a list of single steps.--- Each step has the following form:---   * Trans does not occur---   * Symm only occurs innermost, i.e., next to UseLemma or UseAxiom---   * Each Cong has exactly one non-Refl argument (no parallel rewriting)---   * Refl only occurs as an argument to Cong-derivSteps :: Function f => Derivation f -> [Derivation f]-derivSteps = steps . derivation . flattenProof . certify-  where-    steps Refl{} = []-    steps (Trans p q) = steps p ++ steps q-    steps p = [p]---- | Print a presented proof.-pPrintPresentation :: forall f. Function f => Config -> Presentation f -> Doc-pPrintPresentation config (Presentation axioms lemmas goals) =-  vcat $ intersperse (text "") $-    vcat [ describeEquation "Axiom" (show n) (Just name) eqn-         | Axiom n name eqn <- axioms,-           not (invisible eqn) ]:-    [ pp "Lemma" (num n) Nothing (equation p) emptySubst p-    | Lemma n p <- lemmas,-      not (invisible (equation p)) ] ++-    [ pp "Goal" (show num) (Just pg_name) pg_goal_hint pg_witness_hint pg_proof-    | (num, ProvedGoal{..}) <- zip [1..] goals ]-  where-    pp kind n mname eqn witness p =-      describeEquation kind n mname eqn $$-      ppWitness witness $$-      text "Proof:" $$-      pPrintLemma config num p--    num x = show (fromJust (Map.lookup x nums))-    nums = Map.fromList (zip (map lemma_id lemmas) [n+1 ..])-    n = maximum $ 0:map axiom_number axioms--    ppWitness sub-      | sub == emptySubst = pPrintEmpty-      | otherwise =-          vcat [-            text "The goal is true when:",-            nest 2 $ vcat-              [ pPrint x <+> text "=" <+> pPrint t-              | (x, t) <- substToList sub ],-            if minimal `elem` funs sub then-              text "where" <+> doubleQuotes (pPrint (minimal :: Fun f)) <+>-              text "stands for an arbitrary term of your choice."-            else pPrintEmpty,-            text ""]---- | Format an equation nicely.------ Used both here and in the main file.-describeEquation ::-  PrettyTerm f =>-  String -> String -> Maybe String -> Equation f -> Doc-describeEquation kind num mname eqn =-  text kind <+> text num <>-  (case mname of-     Nothing -> text ""-     Just name -> text (" (" ++ name ++ ")")) <>-  text ":" <+> pPrint eqn <> text "."--------------------------------------------------------------------------- Making proofs of existential goals more readable.--------------------------------------------------------------------------- The idea: the only axioms which mention $equals, $true and $false--- are:---   * $equals(x,x) = $true  (reflexivity)---   * $equals(t,u) = $false (conjecture)--- This implies that a proof $true = $false must have the following--- structure, if we expand out all lemmas:---   $true = $equals(s,s) = ... = $equals(t,u) = $false.------ The substitution in the last step $equals(t,u) = $false is in fact the--- witness to the existential.------ Furthermore, we can make it so that the inner "..." doesn't use the $equals--- axioms. If it does, one of the "..." steps results in either $true or $false,--- and we can chop off everything before the $true or after the $false.------ Once we have done that, every proof step in the "..." must be a congruence--- step of the shape---   $equals(t, u) = $equals(v, w).--- This is because there are no other axioms which mention $equals. Hence we can--- split the proof of $equals(s,s) = $equals(t,u) into separate proofs of s=t--- and s=u.------ What we have got out is:---   * the witness to the existential---   * a proof that both sides of the conjecture are equal--- and we can present that to the user.---- Decode $equals(t,u) into an equation t=u.-decodeEquality :: Function f => Term f -> Maybe (Equation f)-decodeEquality (App equals (Cons t (Cons u Empty)))-  | isEquals equals = Just (t :=: u)-decodeEquality _ = Nothing---- Tries to transform a proof of $true = $false into a proof of--- the original existentially-quantified formula.-decodeGoal :: Function f => ProvedGoal f -> ProvedGoal f-decodeGoal pg =-  case maybeDecodeGoal pg of-    Nothing -> pg-    Just (name, witness, goal, deriv) ->-      checkProvedGoal $-      pg {-        pg_name = name,-        pg_proof = certify deriv,-        pg_goal_hint = goal,-        pg_witness_hint = witness }--maybeDecodeGoal :: forall f. Function f =>-  ProvedGoal f -> Maybe (String, Subst f, Equation f, Derivation f)-maybeDecodeGoal ProvedGoal{..}-  -- N.B. presentWithGoals takes care of expanding any lemma which mentions-  -- $equals, and flattening the proof.-  | isFalseTerm u = extract (derivSteps deriv)-    -- Orient the equation so that $false is the RHS.-  | isFalseTerm t = extract (derivSteps (symm deriv))-  | otherwise = Nothing-  where-    isFalseTerm, isTrueTerm :: Term f -> Bool-    isFalseTerm (App false _) = isFalse false-    isFalseTerm _ = False-    isTrueTerm (App true _) = isTrue true-    isTrueTerm _ = False--    t :=: u = equation pg_proof-    deriv = derivation pg_proof--    -- Detect $true = $equals(t, t).-    decodeReflexivity :: Derivation f -> Maybe (Term f)-    decodeReflexivity (Symm (UseAxiom Axiom{..} sub)) = do-      guard (isTrueTerm (eqn_rhs axiom_eqn))-      (t :=: u) <- decodeEquality (eqn_lhs axiom_eqn)-      guard (t == u)-      return (subst sub t)-    decodeReflexivity _ = Nothing--    -- Detect $equals(t, u) = $false.-    decodeConjecture :: Derivation f -> Maybe (String, Equation f, Subst f)-    decodeConjecture (UseAxiom Axiom{..} sub) = do-      guard (isFalseTerm (eqn_rhs axiom_eqn))-      eqn <- decodeEquality (eqn_lhs axiom_eqn)-      return (axiom_name, eqn, sub)-    decodeConjecture _ = Nothing--    extract (p:ps) = do-      -- Start by finding $true = $equals(t,u).-      t <- decodeReflexivity p-      cont (Refl t) (Refl t) ps-    extract [] = Nothing--    cont p1 p2 (p:ps)-      | Just t <- decodeReflexivity p =-        cont (Refl t) (Refl t) ps-      | Just (name, eqn, sub) <- decodeConjecture p =-        -- If p1: s=t and p2: s=u-        -- then symm p1 `trans` p2: t=u.-        return (name, sub, eqn, symm p1 `trans` p2)-      | Cong eq [p1', p2'] <- p, isEquals eq =-        cont (p1 `trans` p1') (p2 `trans` p2') ps-    cont _ _ _ = Nothing
− src/Twee/Rule.hs
@@ -1,488 +0,0 @@--- | Term rewriting.-{-# LANGUAGE TypeFamilies, FlexibleContexts, RecordWildCards, BangPatterns, OverloadedStrings, MultiParamTypeClasses, ScopedTypeVariables, GeneralizedNewtypeDeriving #-}-module Twee.Rule where--import Twee.Base-import Twee.Constraints-import qualified Twee.Index as Index-import Twee.Index(Index)-import Control.Monad-import Control.Monad.Trans.Class-import Control.Monad.Trans.State.Strict-import Data.Maybe-import Data.List-import Twee.Utils-import qualified Data.Set as Set-import Data.Set(Set)-import qualified Twee.Term as Term-import Data.Ord-import Twee.Equation-import qualified Twee.Proof as Proof-import Twee.Proof(Derivation, Lemma(..))-import Data.Tuple------------------------------------------------------------------------------------- * Rewrite rules.------------------------------------------------------------------------------------- | A rewrite rule.-data Rule f =-  Rule {-    -- | Information about whether and how the rule is oriented.-    orientation :: !(Orientation f),-    -- Invariant:-    -- For oriented rules: vars rhs `isSubsetOf` vars lhs-    -- For unoriented rules: vars lhs == vars rhs--    -- | The left-hand side of the rule.-    lhs :: {-# UNPACK #-} !(Term f),-    -- | The right-hand side of the rule.-    rhs :: {-# UNPACK #-} !(Term f) }-  deriving (Eq, Ord, Show)-type RuleOf a = Rule (ConstantOf a)---- | A rule's orientation.------ 'Oriented' and 'WeaklyOriented' rules are used only left-to-right.--- 'Permutative' and 'Unoriented' rules are used bidirectionally.-data Orientation f =-    -- | An oriented rule.-    Oriented-    -- | A weakly oriented rule.-    -- The first argument is the minimal constant, the second argument is a list-    -- of terms which are weakly oriented in the rule.-    -- -    -- A rule with orientation @'WeaklyOriented' k ts@ can be used unless-    -- all terms in @ts@ are equal to @k@.-  | WeaklyOriented {-# UNPACK #-} !(Fun f) [Term f]-    -- | A permutative rule.-    ---    -- A rule with orientation @'Permutative' ts@ can be used if-    -- @map fst ts@ is lexicographically greater than @map snd ts@.-  | Permutative [(Term f, Term f)]-    -- | An unoriented rule.-  | Unoriented-  deriving Show--instance Eq (Orientation f) where _ == _ = True-instance Ord (Orientation f) where compare _ _ = EQ---- | Is a rule oriented or weakly oriented?-oriented :: Orientation f -> Bool-oriented Oriented{} = True-oriented WeaklyOriented{} = True-oriented _ = False---- | Is a rule weakly oriented?-weaklyOriented :: Orientation f -> Bool-weaklyOriented WeaklyOriented{} = True-weaklyOriented _ = False--instance Symbolic (Rule f) where-  type ConstantOf (Rule f) = f-  termsDL (Rule or t u) = termsDL or `mplus` termsDL t `mplus` termsDL u-  subst_ sub (Rule or t u) = Rule (subst_ sub or) (subst_ sub t) (subst_ sub u)--instance f ~ g => Has (Rule f) (Term g) where-  the = lhs--instance Symbolic (Orientation f) where-  type ConstantOf (Orientation f) = f--  termsDL Oriented = mzero-  termsDL (WeaklyOriented _ ts) = termsDL ts-  termsDL (Permutative ts) = termsDL ts-  termsDL Unoriented = mzero--  subst_ _   Oriented = Oriented-  subst_ sub (WeaklyOriented min ts) = WeaklyOriented min (subst_ sub ts)-  subst_ sub (Permutative ts) = Permutative (subst_ sub ts)-  subst_ _   Unoriented = Unoriented--instance PrettyTerm f => Pretty (Rule f) where-  pPrint (Rule or l r) =-    pPrint l <+> text (showOrientation or) <+> pPrint r-    where-      showOrientation Oriented = "->"-      showOrientation WeaklyOriented{} = "~>"-      showOrientation Permutative{} = "<->"-      showOrientation Unoriented = "="---- | Turn a rule into an equation.-unorient :: Rule f -> Equation f-unorient (Rule _ l r) = l :=: r---- | Turn an equation t :=: u into a rule t -> u by computing the--- orientation info (e.g. oriented, permutative or unoriented).------ Crashes if t -> u is not a valid rule, for example if there is--- a variable in @u@ which is not in @t@. To prevent this happening,--- combine with 'Twee.CP.split'.-orient :: Function f => Equation f -> Rule f-orient (t :=: u) = Rule o t u-  where-    o | lessEq u t =-        case unify t u of-          Nothing -> Oriented-          Just sub-            | allSubst (\_ (Cons t Empty) -> isMinimal t) sub ->-              WeaklyOriented minimal (map (build . var . fst) (substToList sub))-            | otherwise -> Unoriented-      | lessEq t u = error "wrongly-oriented rule"-      | not (null (usort (vars u) \\ usort (vars t))) =-        error "unbound variables in rule"-      | Just ts <- evalStateT (makePermutative t u) [],-        permutativeOK t u ts =-        Permutative ts-      | otherwise = Unoriented--    permutativeOK _ _ [] = True-    permutativeOK t u ((Var x, Var y):xs) =-      lessIn model u t == Just Strict &&-      permutativeOK t' u' xs-      where-        model = modelFromOrder [Variable y, Variable x]-        sub x' = if x == x' then var y else var x'-        t' = subst sub t-        u' = subst sub u--    makePermutative t u = do-      msub <- gets listToSubst-      sub  <- lift msub-      aux (subst sub t) (subst sub u)-        where-          aux (Var x) (Var y)-            | x == y = return []-            | otherwise = do-              modify ((x, build $ var y):)-              return [(build $ var x, build $ var y)]--          aux (App f ts) (App g us)-            | f == g =-              fmap concat (zipWithM makePermutative (unpack ts) (unpack us))--          aux _ _ = mzero---- | Flip an unoriented rule so that it goes right-to-left.-backwards :: Rule f -> Rule f-backwards (Rule or t u) = Rule (back or) u t-  where-    back (Permutative xs) = Permutative (map swap xs)-    back Unoriented = Unoriented-    back _ = error "Can't turn oriented rule backwards"------------------------------------------------------------------------------------- * Extra-fast rewriting, without proof output or unorientable rules.------------------------------------------------------------------------------------- | Compute the normal form of a term wrt only oriented rules.-{-# INLINEABLE simplify #-}-simplify :: (Function f, Has a (Rule f)) => Index f a -> Term f -> Term f-simplify !idx !t = {-# SCC simplify #-} simplify1 idx t--{-# INLINEABLE simplify1 #-}-simplify1 :: (Function f, Has a (Rule f)) => Index f a -> Term f -> Term f-simplify1 idx t-  | t == u = t-  | otherwise = simplify idx u-  where-    u = build (simp (singleton t))--    simp Empty = mempty-    simp (Cons (Var x) t) = var x `mappend` simp t-    simp (Cons t u)-      | Just (rule, sub) <- simpleRewrite idx t =-        Term.subst sub (rhs rule) `mappend` simp u-    simp (Cons (App f ts) us) =-      app f (simp ts) `mappend` simp us---- | Check if a term can be simplified.-{-# INLINEABLE canSimplify #-}-canSimplify :: (Function f, Has a (Rule f)) => Index f a -> Term f -> Bool-canSimplify idx t = canSimplifyList idx (singleton t)--{-# INLINEABLE canSimplifyList #-}-canSimplifyList :: (Function f, Has a (Rule f)) => Index f a -> TermList f -> Bool-canSimplifyList idx t =-  {-# SCC canSimplifyList #-}-  any (isJust . simpleRewrite idx) (filter isApp (subtermsList t))---- | Find a simplification step that applies to a term.-{-# INLINEABLE simpleRewrite #-}-simpleRewrite :: (Function f, Has a (Rule f)) => Index f a -> Term f -> Maybe (Rule f, Subst f)-simpleRewrite idx t =-  -- Use instead of maybeToList to make fusion work-  foldr (\x _ -> Just x) Nothing $ do-    rule <- the <$> Index.approxMatches t idx-    guard (oriented (orientation rule))-    sub <- maybeToList (match (lhs rule) t)-    guard (reducesOriented rule sub)-    return (rule, sub)------------------------------------------------------------------------------------- * Rewriting, with proof output.------------------------------------------------------------------------------------- | A strategy gives a set of possible reductions for a term.-type Strategy f = Term f -> [Reduction f]---- | A multi-step rewrite proof @t ->* u@-data Reduction f =-    -- | Apply a single rewrite rule to the root of a term-    Step {-# UNPACK #-} !(Lemma f) !(Rule f) !(Subst f)-    -- | Reflexivity-  | Refl {-# UNPACK #-} !(Term f)-    -- | Transivitity-  | Trans !(Reduction f) !(Reduction f)-    -- | Congruence-  | Cong {-# UNPACK #-} !(Fun f) ![Reduction f]-  deriving Show--instance Symbolic (Reduction f) where-  type ConstantOf (Reduction f) = f-  termsDL (Step _ _ sub) = termsDL sub-  termsDL (Refl t) = termsDL t-  termsDL (Trans p q) = termsDL p `mplus` termsDL q-  termsDL (Cong _ ps) = termsDL ps--  subst_ sub (Step lemma rule s) = Step lemma rule (subst_ sub s)-  subst_ sub (Refl t) = Refl (subst_ sub t)-  subst_ sub (Trans p q) = Trans (subst_ sub p) (subst_ sub q)-  subst_ sub (Cong f ps) = Cong f (subst_ sub ps)--instance Function f => Pretty (Reduction f) where-  pPrint = pPrint . reductionProof---- | A smart constructor for Trans which simplifies Refl.-trans :: Reduction f -> Reduction f -> Reduction f-trans Refl{} p = p-trans p Refl{} = p--- Make right-associative to improve performance of 'result'-trans p (Trans q r) = Trans (Trans p q) r-trans p q = Trans p q---- | A smart constructor for Cong which simplifies Refl.-cong :: Fun f -> [Reduction f] -> Reduction f-cong f ps-  | all isRefl ps = Refl (result (reduce (Cong f ps)))-  | otherwise = Cong f ps-  where-    isRefl Refl{} = True-    isRefl _ = False---- | The list of all rewrite rules used in a rewrite proof.-steps :: Reduction f -> [Reduction f]-steps r = aux r []-  where-    aux step@Step{} = (step:)-    aux (Refl _) = id-    aux (Trans p q) = aux p . aux q-    aux (Cong _ ps) = foldr (.) id (map aux ps)---- | Turn a reduction into a proof.-reductionProof :: Reduction f -> Derivation f-reductionProof (Step lemma _ sub) =-  Proof.lemma lemma sub-reductionProof (Refl t) = Proof.Refl t-reductionProof (Trans p q) =-  Proof.trans (reductionProof p) (reductionProof q)-reductionProof (Cong f ps) = Proof.cong f (map reductionProof ps)---- | Construct a basic rewrite step.-{-# INLINE step #-}-step :: (Has a (Rule f), Has a (Lemma f)) => a -> Subst f -> Reduction f-step x sub = Step (the x) (the x) sub--------------------------------------------------------------------------- | A rewrite proof with the final term attached.--- Has an @Ord@ instance which compares the final term.-------------------------------------------------------------------------data Resulting f =-  Resulting {-    result :: {-# UNPACK #-} !(Term f),-    reduction :: !(Reduction f) }-  deriving Show--instance Eq (Resulting f) where x == y = compare x y == EQ-instance Ord (Resulting f) where compare = comparing result--instance Symbolic (Resulting f) where-  type ConstantOf (Resulting f) = f-  termsDL (Resulting t red) =-    termsDL t `mplus` termsDL red-  subst_ sub (Resulting t red) =-    Resulting (subst_ sub t) (subst_ sub red)--instance Function f => Pretty (Resulting f) where-  pPrint = pPrint . reduction---- | Construct a 'Resulting' from a 'Reduction'.-reduce :: Reduction f -> Resulting f-reduce p =-  Resulting (res p) p-  where-    res (Trans _ q) = res q-    res (Refl t) = t-    res p = {-# SCC res_emitRes #-} build (emitResult p)--    emitResult (Step _ r sub) = Term.subst sub (rhs r)-    emitResult (Refl t) = builder t-    emitResult (Trans _ q) = emitResult q-    emitResult (Cong f ps) = app f (map emitResult ps)------------------------------------------------------------------------------------- * Strategy combinators.------------------------------------------------------------------------------------- | Normalise a term wrt a particular strategy.-{-# INLINE normaliseWith #-}-normaliseWith :: Function f => (Term f -> Bool) -> Strategy f -> Term f -> Resulting f-normaliseWith ok strat t = {-# SCC normaliseWith #-} res-  where-    res = aux 0 (Refl t) t-    aux 1000 p _ =-      error $-        "Possibly nonterminating rewrite:\n" ++ prettyShow p-    aux n p t =-      case parallel strat t of-        (q:_) | u <- result (reduce q), ok u ->-          aux (n+1) (p `trans` q) u-        _ -> Resulting t p---- | Compute all normal forms of a set of terms wrt a particular strategy.-normalForms :: Function f => Strategy f -> [Resulting f] -> Set (Resulting f)-normalForms strat ps = snd (successorsAndNormalForms strat ps)---- | Compute all successors of a set of terms (a successor of a term @t@--- is a term @u@ such that @t ->* u@).-successors :: Function f => Strategy f -> [Resulting f] -> Set (Resulting f)-successors strat ps = Set.union qs rs-  where-    (qs, rs) = successorsAndNormalForms strat ps--{-# INLINEABLE successorsAndNormalForms #-}-successorsAndNormalForms :: Function f => Strategy f -> [Resulting f] ->-  (Set (Resulting f), Set (Resulting f))-successorsAndNormalForms strat ps =-  {-# SCC successorsAndNormalForms #-} go Set.empty Set.empty ps-  where-    go dead norm [] = (dead, norm)-    go dead norm (p:ps)-      | p `Set.member` dead = go dead norm ps-      | p `Set.member` norm = go dead norm ps-      | null qs = go dead (Set.insert p norm) ps-      | otherwise =-        go (Set.insert p dead) norm (qs ++ ps)-      where-        qs =-          [ reduce (reduction p `Trans` q)-          | q <- anywhere strat (result p) ]---- | Apply a strategy anywhere in a term.-anywhere :: Strategy f -> Strategy f-anywhere strat t = strat t ++ nested (anywhere strat) t---- | Apply a strategy to some child of the root function.-nested :: Strategy f -> Strategy f-nested _ Var{} = []-nested strat (App f ts) =-  cong f <$> inner [] ts-  where-    inner _ Empty = []-    inner before (Cons t u) =-      [ reverse before ++ [p] ++ map Refl (unpack u)-      | p <- strat t ] ++-      inner (Refl t:before) u---- | Apply a strategy in parallel in as many places as possible.--- Takes only the first rewrite of each strategy.-{-# INLINE parallel #-}-parallel :: PrettyTerm f => Strategy f -> Strategy f-parallel strat t =-  case par t of-    Refl{} -> []-    p -> [p]-  where-    par t | p:_ <- strat t = p-    par (App f ts) = cong f (inner [] ts)-    par t = Refl t--    inner before Empty = reverse before-    inner before (Cons t u) = inner (par t:before) u------------------------------------------------------------------------------------- * Basic strategies. These only apply at the root of the term.------------------------------------------------------------------------------------- | A strategy which rewrites using an index.-{-# INLINE rewrite #-}-rewrite :: (Function f, Has a (Rule f), Has a (Lemma f)) => (Rule f -> Subst f -> Bool) -> Index f a -> Strategy f-rewrite p rules t = do-  rule <- Index.approxMatches t rules-  tryRule p rule t---- | A strategy which applies one rule only.-{-# INLINEABLE tryRule #-}-tryRule :: (Function f, Has a (Rule f), Has a (Lemma f)) => (Rule f -> Subst f -> Bool) -> a -> Strategy f-tryRule p rule t = do-  sub <- maybeToList (match (lhs (the rule)) t)-  guard (p (the rule) sub)-  return (step rule sub)---- | Check if a rule can be applied, given an ordering <= on terms.-{-# INLINEABLE reducesWith #-}-reducesWith :: Function f => (Term f -> Term f -> Bool) -> Rule f -> Subst f -> Bool-reducesWith _ (Rule Oriented _ _) _ = True-reducesWith _ (Rule (WeaklyOriented min ts) _ _) sub =-  -- Be a bit careful here not to build new terms-  -- (reducesWith is used in simplify).-  -- This is the same as:-  --   any (not . isMinimal) (subst sub ts)-  any (not . isMinimal . expand) ts-  where-    expand t@(Var x) = fromMaybe t (Term.lookup x sub)-    expand t = t--    isMinimal (App f Empty) = f == min-    isMinimal _ = False-reducesWith p (Rule (Permutative ts) _ _) sub =-  aux ts-  where-    aux [] = False-    aux ((t, u):ts)-      | t' == u' = aux ts-      | otherwise = p u' t'-      where-        t' = subst sub t-        u' = subst sub u-reducesWith p (Rule Unoriented t u) sub =-  p u' t' && u' /= t'-  where-    t' = subst sub t-    u' = subst sub u---- | Check if a rule can be applied normally.-{-# INLINEABLE reduces #-}-reduces :: Function f => Rule f -> Subst f -> Bool-reduces rule sub = reducesWith lessEq rule sub---- | Check if a rule can be applied and is oriented.-{-# INLINEABLE reducesOriented #-}-reducesOriented :: Function f => Rule f -> Subst f -> Bool-reducesOriented rule sub =-  oriented (orientation rule) && reducesWith undefined rule sub---- | Check if a rule can be applied in a particular model.-{-# INLINEABLE reducesInModel #-}-reducesInModel :: Function f => Model f -> Rule f -> Subst f -> Bool-reducesInModel cond rule sub =-  reducesWith (\t u -> isJust (lessIn cond t u)) rule sub---- | Check if a rule can be applied to the Skolemised version of a term.-{-# INLINEABLE reducesSkolem #-}-reducesSkolem :: Function f => Rule f -> Subst f -> Bool-reducesSkolem rule sub =-  reducesWith (\t u -> lessEq (subst skolemise t) (subst skolemise u)) rule sub-  where-    skolemise = con . skolem
− src/Twee/Rule/Index.hs
@@ -1,45 +0,0 @@-{-# LANGUAGE RecordWildCards, ScopedTypeVariables, FlexibleContexts #-}-module Twee.Rule.Index(-  RuleIndex(..),-  empty, insert, delete,-  approxMatches, matches, lookup) where--import Prelude hiding (lookup)-import Twee.Base hiding (lookup, empty)-import Twee.Rule-import Twee.Index hiding (insert, delete, empty)-import qualified Twee.Index as Index--data RuleIndex f a =-  RuleIndex {-    index_oriented :: !(Index f a),-    index_weak     :: !(Index f a),-    index_all      :: !(Index f a) }-  deriving Show--empty :: RuleIndex f a-empty = RuleIndex Index.empty Index.empty Index.empty--insert :: forall f a. Has a (Rule f) => Term f -> a -> RuleIndex f a -> RuleIndex f a-insert t x RuleIndex{..} =-  RuleIndex {-    index_oriented = insertWhen (oriented or) index_oriented,-    index_weak = insertWhen (weaklyOriented or) index_weak,-    index_all = insertWhen True index_all }-  where-    Rule or _ _ = the x :: Rule f--    insertWhen False idx = idx-    insertWhen True idx = Index.insert t x idx--delete :: forall f a. (Eq a, Has a (Rule f)) => Term f -> a -> RuleIndex f a -> RuleIndex f a-delete t x RuleIndex{..} =-  RuleIndex {-    index_oriented = deleteWhen (oriented or) index_oriented,-    index_weak = deleteWhen (weaklyOriented or) index_weak,-    index_all = deleteWhen True index_all }-  where-    Rule or _ _ = the x :: Rule f--    deleteWhen False idx = idx-    deleteWhen True idx = Index.delete t x idx
− src/Twee/Task.hs
@@ -1,56 +0,0 @@--- | A module which can run housekeeping tasks every so often.-{-# LANGUAGE RecordWildCards #-}-module Twee.Task(Task, newTask, checkTask) where--import System.CPUTime-import Data.IORef-import Control.Monad.IO.Class--data TaskData m a =-  TaskData {-    -- When was the task created?-    task_start :: !Integer,-    -- When was the task last run?-    task_last :: !Integer,-    -- How long have we spent on this task so far?-    task_spent :: !Integer,-    -- How often should we run this task at most, in seconds?-    task_frequency :: !Double,-    -- What proportion of our time should we spend on the task?-    task_budget :: !Double,-    -- The task itself-    task_what :: m a }---- | A task which runs in the monad @m@ and produces a value of type @a@.-newtype Task m a = Task (IORef (TaskData m a))---- | Create a new task that should be run a certain proportion--- of the time. The first argument is how often in seconds the--- task should run, at most. The second argument is the maximum--- percentage of time that should be spent on the task.-newTask :: MonadIO m => Double -> Double -> m a -> m (Task m a)-newTask freq budget what = liftIO $ do-  now <- getCPUTime-  Task <$> newIORef (TaskData now now 0 freq budget what)---- | Run a task if it's time to run it.-checkTask :: MonadIO m => Task m a -> m (Maybe a)-checkTask (Task ref) = do-  task@TaskData{..} <- liftIO $ readIORef ref-  now <- liftIO getCPUTime-  if not (taskDue now task) then return Nothing else do-    res <- task_what-    after <- liftIO getCPUTime-    liftIO $ writeIORef ref task {-      task_last = after,-      task_spent = task_spent + (after-now) }-    return (Just res)---- Check if a task should be run now.-taskDue :: Integer -> TaskData m a -> Bool-taskDue now TaskData{..} =-  -- Don't run more than the frequency says.-  fromInteger (now - task_last) >= task_frequency * 10^12 &&-  -- Run if we spent less than task_budget proportion of the total time so far.-  -- Use > rather than >= so that tasks with zero budget never get run.-  fromInteger (now - task_start) * task_budget > fromInteger task_spent
− src/Twee/Term.hs
@@ -1,646 +0,0 @@--- | Terms and substitutions.------ Terms in twee are represented as arrays rather than as an algebraic data--- type. This module defines pattern synonyms ('App', 'Var', 'Cons', 'Empty')--- which means that pattern matching on terms works just as normal.--- The pattern synonyms can not be used to create new terms; for that you--- have to use a builder interface ('Build').------ This module also provides:------   * pattern synonyms for iterating through a term one symbol at a time---     ('ConsSym');---   * substitutions ('Substitution', 'Subst', 'subst');---   * unification ('unify') and matching ('match');---   * miscellaneous useful functions on terms.-{-# LANGUAGE BangPatterns, PatternSynonyms, ViewPatterns, TypeFamilies, OverloadedStrings, ScopedTypeVariables #-}-module Twee.Term(-  -- * Terms-  Term, pattern Var, pattern App, isApp, isVar, singleton, len,-  -- * Termlists-  TermList, pattern Empty, pattern Cons, pattern ConsSym,-  pattern UnsafeCons, pattern UnsafeConsSym,-  empty, unpack, lenList,-  -- * Function symbols and variables-  Fun, fun, fun_id, fun_value, pattern F, Var(..), -  -- * Building terms-  Build(..),-  Builder,-  build, buildList,-  con, app, var,-  -- * Access to subterms-  children, properSubterms, subtermsList, subterms, occurs, isSubtermOf, isSubtermOfList, at,-  -- * Substitutions-  Substitution(..),-  subst,-  Subst(..),-  -- ** Constructing and querying substitutions-  emptySubst, listToSubst, substToList,-  lookup, lookupList,-  extend, extendList, unsafeExtendList,-  retract,-  -- ** Other operations on substitutions-  foldSubst, allSubst, substDomain,-  substSize,-  substCompose, substCompatible, substUnion, idempotent, idempotentOn,-  canonicalise,-  -- * Matching-  match, matchIn, matchList, matchListIn, isInstanceOf, isVariantOf,-  -- * Unification-  unify, unifyList,-  unifyTri, unifyListTri,-  TriangleSubst(..),-  close,-  -- * Positions in terms-  positionToPath, pathToPosition,-  replacePosition,-  replacePositionSub,-  -- * Miscellaneous functions-  bound, boundList, boundLists, mapFun, mapFunList, (<<)) where--import Prelude hiding (lookup)-import Twee.Term.Core hiding (F)-import Data.List hiding (lookup, find)-import Data.Maybe-import Data.Monoid-import Data.IntMap.Strict(IntMap)-import qualified Data.IntMap.Strict as IntMap------------------------------------------------------------------------------------- * A type class for builders------------------------------------------------------------------------------------- | Instances of 'Build' can be turned into terms using 'build' or 'buildList',--- and turned into term builders using 'builder'. Has instances for terms,--- termlists, builders, and Haskell lists.-class Build a where-  -- | The underlying type of function symbols.-  type BuildFun a-  -- | Convert a value into a 'Builder'.-  builder :: a -> Builder (BuildFun a)--instance Build (Builder f) where-  type BuildFun (Builder f) = f-  builder = id--instance Build (Term f) where-  type BuildFun (Term f) = f-  builder = emitTermList . singleton--instance Build (TermList f) where-  type BuildFun (TermList f) = f-  builder = emitTermList--instance Build a => Build [a] where-  type BuildFun [a] = BuildFun a-  {-# INLINE builder #-}-  builder = mconcat . map builder---- | Build a term. The given builder must produce exactly one term.-{-# INLINE build #-}-build :: Build a => a -> Term (BuildFun a)-build x =-  case buildList x of-    Cons t Empty -> t---- | Build a termlist.-{-# INLINE buildList #-}-buildList :: Build a => a -> TermList (BuildFun a)-buildList x = {-# SCC buildList #-} buildTermList (builder x)---- | Build a constant (a function with no arguments).-{-# INLINE con #-}-con :: Fun f -> Builder f-con x = emitApp x mempty---- | Build a function application.-{-# INLINE app #-}-app :: Build a => Fun (BuildFun a) -> a -> Builder (BuildFun a)-app f ts = emitApp f (builder ts)---- | Build a variable.-var :: Var -> Builder f-var = emitVar------------------------------------------------------------------------------------- Functions for substitutions.-----------------------------------------------------------------------------------{-# INLINE substToList' #-}-substToList' :: Subst f -> [(Var, TermList f)]-substToList' (Subst sub) = [(V x, t) | (x, t) <- IntMap.toList sub]---- | Convert a substitution to a list of bindings.-{-# INLINE substToList #-}-substToList :: Subst f -> [(Var, Term f)]-substToList sub =-  [(x, t) | (x, Cons t Empty) <- substToList' sub]---- | Fold a function over a substitution.-{-# INLINE foldSubst #-}-foldSubst :: (Var -> TermList f -> b -> b) -> b -> Subst f -> b-foldSubst op e !sub = foldr (uncurry op) e (substToList' sub)---- | Check if all bindings of a substitution satisfy a given property.-{-# INLINE allSubst #-}-allSubst :: (Var -> TermList f -> Bool) -> Subst f -> Bool-allSubst p = foldSubst (\x t y -> p x t && y) True---- | Compute the set of variables bound by a substitution.-{-# INLINE substDomain #-}-substDomain :: Subst f -> [Var]-substDomain (Subst sub) = map V (IntMap.keys sub)------------------------------------------------------------------------------------- Substitution.------------------------------------------------------------------------------------- | A class for values which act as substitutions.------ Instances include 'Subst' as well as functions from variables to terms.-class Substitution s where-  -- | The underlying type of function symbols.-  type SubstFun s--  -- | Apply the substitution to a variable.-  evalSubst :: s -> Var -> Builder (SubstFun s)--  -- | Apply the substitution to a termlist.-  {-# INLINE substList #-}-  substList :: s -> TermList (SubstFun s) -> Builder (SubstFun s)-  substList sub ts = aux ts-    where-      aux Empty = mempty-      aux (Cons (Var x) ts) = evalSubst sub x <> aux ts-      aux (Cons (App f ts) us) = app f (aux ts) <> aux us--instance (Build a, v ~ Var) => Substitution (v -> a) where-  type SubstFun (v -> a) = BuildFun a--  {-# INLINE evalSubst #-}-  evalSubst sub x = builder (sub x)--instance Substitution (Subst f) where-  type SubstFun (Subst f) = f--  {-# INLINE evalSubst #-}-  evalSubst sub x =-    case lookupList x sub of-      Nothing -> var x-      Just ts -> builder ts---- | Apply a substitution to a term.-{-# INLINE subst #-}-subst :: Substitution s => s -> Term (SubstFun s) -> Builder (SubstFun s)-subst sub t = substList sub (singleton t)---- | A substitution which maps variables to terms of type @'Term' f@.-newtype Subst f =-  Subst {-    unSubst :: IntMap (TermList f) }-  deriving Eq---- | Return the highest-number variable in a substitution plus 1.-{-# INLINE substSize #-}-substSize :: Subst f -> Int-substSize (Subst sub)-  | IntMap.null sub = 0-  | otherwise = fst (IntMap.findMax sub) + 1---- | Look up a variable in a substitution, returning a termlist.-{-# INLINE lookupList #-}-lookupList :: Var -> Subst f -> Maybe (TermList f)-lookupList x (Subst sub) = IntMap.lookup (var_id x) sub---- | Add a new binding to a substitution, giving a termlist.-{-# INLINE extendList #-}-extendList :: Var -> TermList f -> Subst f -> Maybe (Subst f)-extendList x !t (Subst sub) =-  case IntMap.lookup (var_id x) sub of-    Nothing -> Just $! Subst (IntMap.insert (var_id x) t sub)-    Just u-      | t == u    -> Just (Subst sub)-      | otherwise -> Nothing---- | Remove a binding from a substitution.-{-# INLINE retract #-}-retract :: Var -> Subst f -> Subst f-retract x (Subst sub) = Subst (IntMap.delete (var_id x) sub)---- | Add a new binding to a substitution.--- Overwrites any existing binding.-{-# INLINE unsafeExtendList #-}-unsafeExtendList :: Var -> TermList f -> Subst f -> Subst f-unsafeExtendList x !t (Subst sub) = Subst (IntMap.insert (var_id x) t sub)---- | Compose two substitutions.-substCompose :: Substitution s => Subst (SubstFun s) -> s -> Subst (SubstFun s)-substCompose (Subst !sub1) !sub2 =-  Subst (IntMap.map (buildList . substList sub2) sub1)---- | Check if two substitutions are compatible (they do not send the same--- variable to different terms).-substCompatible :: Subst f -> Subst f -> Bool-substCompatible (Subst !sub1) (Subst !sub2) =-  IntMap.null (IntMap.mergeWithKey f g h sub1 sub2)-  where-    f _ t u-      | t == u = Nothing-      | otherwise = Just t-    g _ = IntMap.empty-    h _ = IntMap.empty---- | Take the union of two substitutions.--- The substitutions must be compatible, which is not checked.-substUnion :: Subst f -> Subst f -> Subst f-substUnion (Subst !sub1) (Subst !sub2) =-  Subst (IntMap.union sub1 sub2)---- | Check if a substitution is idempotent (applying it twice has the same--- effect as applying it once).-{-# INLINE idempotent #-}-idempotent :: Subst f -> Bool-idempotent !sub = allSubst (\_ t -> sub `idempotentOn` t) sub---- | Check if a substitution has no effect on a given term.-{-# INLINE idempotentOn #-}-idempotentOn :: Subst f -> TermList f -> Bool-idempotentOn !sub = aux-  where-    aux Empty = True-    aux (ConsSym App{} t) = aux t-    aux (Cons (Var x) t) = isNothing (lookupList x sub) && aux t---- | Iterate a triangle substitution to make it idempotent.-close :: TriangleSubst f -> Subst f-close (Triangle sub)-  | idempotent sub = sub-  | otherwise      = close (Triangle (substCompose sub sub))---- | Return a substitution which renames the variables of a list of terms to put--- them in a canonical order.-canonicalise :: [TermList f] -> Subst f-canonicalise [] = emptySubst-canonicalise (t:ts) = loop emptySubst vars t ts-  where-    (V m, V n) = boundLists (t:ts)-    vars =-      buildTermList $-        -- Produces two variables when the term is ground-        -- (n = minBound, m = maxBound), which is OK.-        mconcat [emitVar (V x) | x <- [0..n-m+1]]--    loop !_ !_ !_ !_ | False = undefined-    loop sub _ Empty [] = sub-    loop sub Empty _ _ = sub-    loop sub vs Empty (t:ts) = loop sub vs t ts-    loop sub vs (ConsSym App{} t) ts = loop sub vs t ts-    loop sub vs0@(Cons v vs) (Cons (Var x) t) ts =-      case extend x v sub of-        Just sub -> loop sub vs  t ts-        Nothing  -> loop sub vs0 t ts---- | The empty substitution.-{-# NOINLINE emptySubst #-}-emptySubst = Subst IntMap.empty---- | Construct a substitution from a list.--- Returns @Nothing@ if a variable is bound to several different terms.-listToSubst :: [(Var, Term f)] -> Maybe (Subst f)-listToSubst sub = matchList pat t-  where-    pat = buildList (map (var . fst) sub)-    t   = buildList (map snd sub)------------------------------------------------------------------------------------- Matching.------------------------------------------------------------------------------------- | @'match' pat t@ matches the term @t@ against the pattern @pat@.-{-# INLINE match #-}-match :: Term f -> Term f -> Maybe (Subst f)-match pat t = matchList (singleton pat) (singleton t)---- | A variant of 'match' which extends an existing substitution.-{-# INLINE matchIn #-}-matchIn :: Subst f -> Term f -> Term f -> Maybe (Subst f)-matchIn sub pat t = matchListIn sub (singleton pat) (singleton t)---- | A variant of 'match' which works on termlists.-{-# INLINE matchList #-}-matchList :: TermList f -> TermList f -> Maybe (Subst f)-matchList pat t = matchListIn emptySubst pat t---- | A variant of 'match' which works on termlists--- and extends an existing substitution.-matchListIn :: Subst f -> TermList f -> TermList f -> Maybe (Subst f)-matchListIn !sub !pat !t-  | lenList t < lenList pat = Nothing-  | otherwise =-    let loop !_ !_ !_ | False = undefined-        loop sub Empty Empty = Just sub-        loop sub (ConsSym (App f _) pat) (ConsSym (App g _) t)-          | f == g = loop sub pat t-        loop sub (Cons (Var x) pat) (Cons t u) = do-          sub <- extend x t sub-          loop sub pat u-        loop _ _ _ = Nothing-    in {-# SCC match #-} loop sub pat t------------------------------------------------------------------------------------- Unification.------------------------------------------------------------------------------------- | A triangle substitution is one in which variables can be defined in terms--- of each other, though not in a circular way.------ The main use of triangle substitutions is in unification; 'unifyTri' returns--- one. A triangle substitution can be converted to an ordinary substitution--- with 'close', or used directly using its 'Substitution' instance.-newtype TriangleSubst f = Triangle { unTriangle :: Subst f }-  deriving Show--instance Substitution (TriangleSubst f) where-  type SubstFun (TriangleSubst f) = f--  {-# INLINE evalSubst #-}-  evalSubst (Triangle sub) x =-    case lookupList x sub of-      Nothing  -> var x-      Just ts  -> substList (Triangle sub) ts--  -- Redefine substList to get better inlining behaviour-  {-# INLINE substList #-}-  substList (Triangle sub) ts = aux ts-    where-      aux Empty = mempty-      aux (Cons (Var x) ts) = auxVar x <> aux ts-      aux (Cons (App f ts) us) = app f (aux ts) <> aux us--      auxVar x =-        case lookupList x sub of-          Nothing -> var x-          Just ts -> aux ts---- | Unify two terms.-unify :: Term f -> Term f -> Maybe (Subst f)-unify t u = unifyList (singleton t) (singleton u)---- | Unify two termlists.-unifyList :: TermList f -> TermList f -> Maybe (Subst f)-unifyList t u = do-  sub <- unifyListTri t u-  -- Not strict so that isJust (unify t u) doesn't force the substitution-  return (close sub)---- | Unify two terms, returning a triangle substitution.--- This is slightly faster than 'unify'.-unifyTri :: Term f -> Term f -> Maybe (TriangleSubst f)-unifyTri t u = unifyListTri (singleton t) (singleton u)---- | Unify two termlists, returning a triangle substitution.--- This is slightly faster than 'unify'.-unifyListTri :: TermList f -> TermList f -> Maybe (TriangleSubst f)-unifyListTri !t !u = fmap Triangle ({-# SCC unify #-} loop emptySubst t u)-  where-    loop !_ !_ !_ | False = undefined-    loop sub Empty Empty = Just sub-    loop sub (ConsSym (App f _) t) (ConsSym (App g _) u)-      | f == g = loop sub t u-    loop sub (Cons (Var x) t) (Cons u v) = do-      sub <- var sub x u-      loop sub t v-    loop sub (Cons t u) (Cons (Var x) v) = do-      sub <- var sub x t-      loop sub u v-    loop _ _ _ = Nothing--    var sub x t =-      case lookupList x sub of-        Just u -> loop sub u (singleton t)-        Nothing -> var1 sub x t--    var1 sub x t@(Var y)-      | x == y = return sub-      | otherwise =-        case lookup y sub of-          Just t  -> var1 sub x t-          Nothing -> extend x t sub--    var1 sub x t = do-      occurs sub x (singleton t)-      extend x t sub--    occurs !_ !_ Empty = Just ()-    occurs sub x (ConsSym App{} t) = occurs sub x t-    occurs sub x (ConsSym (Var y) t)-      | x == y = Nothing-      | otherwise = do-          occurs sub x t-          case lookupList y sub of-            Nothing -> Just ()-            Just u  -> occurs sub x u------------------------------------------------------------------------------------- Miscellaneous stuff.------------------------------------------------------------------------------------- | The empty termlist.-{-# NOINLINE empty #-}-empty :: forall f. TermList f-empty = buildList (mempty :: Builder f)---- | Get the children (direct subterms) of a term.-children :: Term f -> TermList f-children t =-  case singleton t of-    UnsafeConsSym _ ts -> ts---- | Convert a termlist into an ordinary list of terms.-unpack :: TermList f -> [Term f]-unpack t = unfoldr op t-  where-    op Empty = Nothing-    op (Cons t ts) = Just (t, ts)--instance Show (Term f) where-  show (Var x) = show x-  show (App f Empty) = show f-  show (App f ts) = show f ++ "(" ++ intercalate "," (map show (unpack ts)) ++ ")"--instance Show (TermList f) where-  show = show . unpack--instance Show (Subst f) where-  show subst =-    show-      [ (i, t)-      | i <- [0..substSize subst-1],-        Just t <- [lookup (V i) subst] ]---- | Look up a variable in a substitution.-{-# INLINE lookup #-}-lookup :: Var -> Subst f -> Maybe (Term f)-lookup x s = do-  Cons t Empty <- lookupList x s-  return t---- | Add a new binding to a substitution.-{-# INLINE extend #-}-extend :: Var -> Term f -> Subst f -> Maybe (Subst f)-extend x t sub = extendList x (singleton t) sub---- | Find the length of a term.-{-# INLINE len #-}-len :: Term f -> Int-len = lenList . singleton---- | Return the lowest- and highest-numbered variables in a term.-{-# INLINE bound #-}-bound :: Term f -> (Var, Var)-bound t = boundList (singleton t)---- | Return the lowest- and highest-numbered variables in a termlist.-{-# INLINE boundList #-}-boundList :: TermList f -> (Var, Var)-boundList t = boundListFrom (V maxBound) (V minBound) t--boundListFrom :: Var -> Var -> TermList f -> (Var, Var)-boundListFrom !m !n Empty = (m, n)-boundListFrom m n (ConsSym App{} t) = boundListFrom m n t-boundListFrom m n (ConsSym (Var x) t) =-  boundListFrom (m `min` x) (n `max` x) t---- | Return the lowest- and highest-numbered variables in a list of termlists.-boundLists :: [TermList f] -> (Var, Var)-boundLists t = boundListsFrom (V maxBound) (V minBound) t--boundListsFrom :: Var -> Var -> [TermList f] -> (Var, Var)-boundListsFrom !m !n [] = (m, n)-boundListsFrom m n (t:ts) =-  let-    (m', n') = boundListFrom m n t-  in-    boundListsFrom m' n' ts---- | Check if a variable occurs in a term.-{-# INLINE occurs #-}-occurs :: Var -> Term f -> Bool-occurs x t = occursList x (singleton t)---- | Find all subterms of a termlist.-{-# INLINE subtermsList #-}-subtermsList :: TermList f -> [Term f]-subtermsList t = unfoldr op t-  where-    op Empty = Nothing-    op (ConsSym t u) = Just (t, u)---- | Find all subterms of a term.-{-# INLINE subterms #-}-subterms :: Term f -> [Term f]-subterms = subtermsList . singleton---- | Find all proper subterms of a term.-{-# INLINE properSubterms #-}-properSubterms :: Term f -> [Term f]-properSubterms = subtermsList . children---- | Check if a term is a function application.-isApp :: Term f -> Bool-isApp App{} = True-isApp _     = False---- | Check if a term is a variable-isVar :: Term f -> Bool-isVar Var{} = True-isVar _     = False---- | @t \`'isInstanceOf'\` pat@ checks if @t@ is an instance of @pat@.-isInstanceOf :: Term f -> Term f -> Bool-t `isInstanceOf` pat = isJust (match pat t)---- | Check if two terms are renamings of one another.-isVariantOf :: Term f -> Term f -> Bool-t `isVariantOf` u = t `isInstanceOf` u && u `isInstanceOf` t---- | Is a term a subterm of another one?-isSubtermOf :: Term f -> Term f -> Bool-t `isSubtermOf` u = t `isSubtermOfList` singleton u---- | Map a function over the function symbols in a term.-mapFun :: (Fun f -> Fun g) -> Term f -> Builder g-mapFun f = mapFunList f . singleton---- | Map a function over the function symbols in a termlist.-mapFunList :: (Fun f -> Fun g) -> TermList f -> Builder g-mapFunList f ts = aux ts-  where-    aux Empty = mempty-    aux (Cons (Var x) ts) = var x `mappend` aux ts-    aux (Cons (App ff ts) us) = app (f ff) (aux ts) `mappend` aux us---- | Replace the term at a given position in a term with a different term.-{-# INLINE replacePosition #-}-replacePosition :: (Build a, BuildFun a ~ f) => Int -> a -> TermList f -> Builder f-replacePosition n !x = aux n-  where-    aux !_ !_ | False = undefined-    aux _ Empty = mempty-    aux 0 (Cons _ t) = builder x `mappend` builder t-    aux n (Cons (Var x) t) = var x `mappend` aux (n-1) t-    aux n (Cons t@(App f ts) u)-      | n < len t =-        app f (aux (n-1) ts) `mappend` builder u-      | otherwise =-        builder t `mappend` aux (n-len t) u---- | Replace the term at a given position in a term with a different term, while--- simultaneously applying a substitution. Useful for building critical pairs.-{-# INLINE replacePositionSub #-}-replacePositionSub :: (Substitution sub, SubstFun sub ~ f) => sub -> Int -> TermList f -> TermList f -> Builder f-replacePositionSub sub n !x = aux n-  where-    aux !_ !_ | False = undefined-    aux _ Empty = mempty-    aux n (Cons t u)-      | n < len t = inside n t `mappend` outside u-      | otherwise = outside (singleton t) `mappend` aux (n-len t) u--    inside 0 _ = outside x-    inside n (App f ts) = app f (aux (n-1) ts)-    inside _ _ = undefined -- implies n >= len t--    outside t = substList sub t---- | Convert a position in a term, expressed as a single number, into a path.-positionToPath :: Term f -> Int -> [Int]-positionToPath t n = term t n-  where-    term _ 0 = []-    term t n = list 0 (children t) (n-1)--    list _ Empty _ = error "bad position"-    list k (Cons t u) n-      | n < len t = k:term t n-      | otherwise = list (k+1) u (n-len t)---- | Convert a path in a term into a position.-pathToPosition :: Term f -> [Int] -> Int-pathToPosition t ns = term 0 t ns-  where-    term k _ [] = k-    term k t (n:ns) = list (k+1) (children t) n ns--    list _ Empty _ _ = error "bad path"-    list k (Cons t _) 0 ns = term k t ns-    list k (Cons t u) n ns =-      list (k+len t) u (n-1) ns---- | A pattern which extracts the 'fun_value' from a 'Fun'.-pattern F :: f -> Fun f-pattern F x <- (fun_value -> x)---- | Compare the 'fun_value's of two 'Fun's.-(<<) :: Ord f => Fun f -> Fun f -> Bool-f << g = fun_value f < fun_value g
− src/Twee/Term/Core.hs
@@ -1,422 +0,0 @@--- Terms and substitutions, implemented using flatterms.--- This module contains all the low-level icky bits--- and provides primitives for building higher-level stuff.-{-# LANGUAGE CPP, PatternSynonyms, ViewPatterns,-    MagicHash, UnboxedTuples, BangPatterns,-    RankNTypes, RecordWildCards, GeneralizedNewtypeDeriving #-}-module Twee.Term.Core where--import Data.Primitive(sizeOf)-#ifdef BOUNDS_CHECKS-import Data.Primitive.ByteArray.Checked-#else-import Data.Primitive.ByteArray-#endif-import Control.Monad.ST.Strict-import Data.Bits-import Data.Int-import GHC.Int(Int(..))-import GHC.Prim-import GHC.ST hiding (liftST)-import Data.Ord-import Twee.Label-import Data.Typeable------------------------------------------------------------------------------------- Symbols. A symbol is a single function or variable in a flatterm.-----------------------------------------------------------------------------------data Symbol =-  Symbol {-    -- Is it a function?-    isFun :: Bool,-    -- What is its number?-    index :: Int,-    -- What is the size of the term rooted at this symbol?-    size  :: Int }--instance Show Symbol where-  show Symbol{..}-    | isFun = show (F index) ++ "=" ++ show size-    | otherwise = show (V index)---- Convert symbols to/from Int64 for storage in flatterms.--- The encoding:---   * bits 0-30: size---   * bit  31: 0 (variable) or 1 (function)---   * bits 32-63: index-{-# INLINE toSymbol #-}-toSymbol :: Int64 -> Symbol-toSymbol n =-  Symbol (testBit n 31)-    (fromIntegral (n `unsafeShiftR` 32))-    (fromIntegral (n .&. 0x7fffffff))--{-# INLINE fromSymbol #-}-fromSymbol :: Symbol -> Int64-fromSymbol Symbol{..} =-  fromIntegral size +-  fromIntegral index `unsafeShiftL` 32 +-  fromIntegral (fromEnum isFun) `unsafeShiftL` 31------------------------------------------------------------------------------------- Flatterms, or rather lists of terms.------------------------------------------------------------------------------------- | @'TermList' f@ is a list of terms whose function symbols have type @f@.--- It is either a 'Cons' or an 'Empty'. You can turn it into a @['Term' f]@--- with 'Twee.Term.unpack'.---- A TermList is a slice of an unboxed array of symbols.-data TermList f =-  TermList {-    low   :: {-# UNPACK #-} !Int,-    high  :: {-# UNPACK #-} !Int,-    array :: {-# UNPACK #-} !ByteArray }---- | Index into a termlist.-at :: Int -> TermList f -> Term f-at n (TermList lo hi arr)-  | n < 0 || lo+n >= hi = error "term index out of bounds"-  | otherwise =-    case TermList (lo+n) hi arr of-      UnsafeCons t _ -> t--{-# INLINE lenList #-}--- | The length of (number of symbols in) a termlist.-lenList :: TermList f -> Int-lenList (TermList low high _) = high - low---- | @'Term' f@ is a term whose function symbols have type @f@.--- It is either a 'Var' or an 'App'.---- A term is a special case of a termlist.--- We store it as the termlist together with the root symbol.-data Term f =-  Term {-    root     :: {-# UNPACK #-} !Int64,-    termlist :: {-# UNPACK #-} !(TermList f) }--instance Eq (Term f) where-  x == y = termlist x == termlist y--instance Ord (Term f) where-  compare = comparing termlist---- Pattern synonyms for termlists:--- * Empty :: TermList f---   Empty is the empty termlist.--- * Cons t ts :: Term f -> TermList f -> TermList f---   Cons t ts is the termlist t:ts.--- * ConsSym t ts :: Term f -> TermList f -> TermList f---   ConsSym t ts is like Cons t ts but ts also includes t's children---   (operationally, ts seeks one term to the right in the termlist).--- * UnsafeCons/UnsafeConsSym: like Cons and ConsSym but don't check---   that the termlist is non-empty.---- | Matches the empty termlist.-pattern Empty :: TermList f-pattern Empty <- (patHead -> Nothing)---- | Matches a non-empty termlist, unpacking it into head and tail.-pattern Cons :: Term f -> TermList f -> TermList f-pattern Cons t ts <- (patHead -> Just (t, _, ts))---- | Like 'Cons', but does not check that the termlist is non-empty. Use only if--- you are sure the termlist is non-empty.-pattern UnsafeCons :: Term f -> TermList f -> TermList f-pattern UnsafeCons t ts <- (unsafePatHead -> Just (t, _, ts))---- | Matches a non-empty termlist, unpacking it into head and--- /everything except the root symbol of the head/.--- Useful for iterating through terms one symbol at a time.------ For example, if @ts@ is the termlist @[f(x,y), g(z)]@,--- then @let ConsSym u us = ts@ results in the following bindings:------ > u  = f(x,y)--- > us = [x, y, g(z)]-pattern ConsSym :: Term f -> TermList f -> TermList f-pattern ConsSym t ts <- (patHead -> Just (t, ts, _))---- | Like 'ConsSym', but does not check that the termlist is non-empty. Use only--- if you are sure the termlist is non-empty.-pattern UnsafeConsSym :: Term f -> TermList f -> TermList f-pattern UnsafeConsSym t ts <- (unsafePatHead -> Just (t, ts, _))---- A helper for UnsafeCons/UnsafeConsSym.-{-# INLINE unsafePatHead #-}-unsafePatHead :: TermList f -> Maybe (Term f, TermList f, TermList f)-unsafePatHead TermList{..} =-  Just (Term x (TermList low (low+size) array),-        TermList (low+1) high array,-        TermList (low+size) high array)-  where-    !x = indexByteArray array low-    Symbol{..} = toSymbol x---- A helper for Cons/ConsSym.-{-# INLINE patHead #-}-patHead :: TermList f -> Maybe (Term f, TermList f, TermList f)-patHead t@TermList{..}-  | low == high = Nothing-  | otherwise = unsafePatHead t---- Pattern synonyms for single terms.--- * Var :: Var -> Term f--- * App :: Fun f -> TermList f -> Term f---- | A function symbol. @f@ is the underlying type of function symbols defined--- by the user; @'Fun' f@ is an @f@ together with an automatically-generated unique number.-newtype Fun f =-  F {-    -- | The unique number of a 'Fun'.-    fun_id :: Int }-instance Eq (Fun f) where-  f == g = fun_id f == fun_id g-instance Ord (Fun f) where-  compare = comparing fun_id---- | Construct a 'Fun' from a function symbol.-fun :: (Ord f, Typeable f) => f -> Fun f-fun f = F (fromIntegral (labelNum (label f)))---- | The underlying function symbol of a 'Fun'.-fun_value :: Fun f -> f-fun_value f = find (unsafeMkLabel (fromIntegral (fun_id f)))---- | A variable.-newtype Var =-  V {-    -- | The variable's number.-    -- Don't use huge variable numbers:-    -- they will be truncated to 32 bits when stored in a term.-    var_id :: Int } deriving (Eq, Ord, Enum)-instance Show (Fun f) where show f = "f" ++ show (fun_id f)-instance Show Var     where show x = "x" ++ show (var_id x)---- | Matches a variable.-pattern Var :: Var -> Term f-pattern Var x <- (patTerm -> Left x)---- | Matches a function application.-pattern App :: Fun f -> TermList f -> Term f-pattern App f ts <- (patTerm -> Right (f, ts))---- A helper function for Var and App.-{-# INLINE patTerm #-}-patTerm :: Term f -> Either Var (Fun f, TermList f)-patTerm t@Term{..}-  | isFun     = Right (F index, ts)-  | otherwise = Left (V index)-  where-    Symbol{..} = toSymbol root-    !(UnsafeConsSym _ ts) = singleton t---- | Convert a term to a termlist.-{-# INLINE singleton #-}-singleton :: Term f -> TermList f-singleton Term{..} = termlist---- We can implement equality almost without access to the--- internal representation of the termlists, but we cheat by--- comparing Int64s instead of Symbols.-instance Eq (TermList f) where-  -- Manual worker-wrapper to prevent too much from being inlined.-  t == u = eqTermList t u--{-# INLINE eqTermList #-}-eqTermList :: TermList f -> TermList f -> Bool-eqTermList-  (TermList (I# low1) (I# high1) (ByteArray array1))-  (TermList (I# low2) (I# high2) (ByteArray array2)) =-    weqTermList low1 high1 array1 low2 high2 array2---- Manually worker-wrapper transform the thing, ugh...-{-# NOINLINE weqTermList #-}-weqTermList ::-  Int# -> Int# -> ByteArray# ->-  Int# -> Int# -> ByteArray# ->-  Bool-weqTermList low1 high1 array1 low2 high2 array2 =-  lenList t == lenList u && eqSameLength t u-  where-    t = TermList (I# low1) (I# high1) (ByteArray array1)-    u = TermList (I# low2) (I# high2) (ByteArray array2)-    eqSameLength Empty !_ = True-    eqSameLength (ConsSym s1 t) (UnsafeConsSym s2 u) =-      root s1 == root s2 && eqSameLength t u--instance Ord (TermList f) where-  {-# INLINE compare #-}-  compare t u =-    case compare (lenList t) (lenList u) of-      EQ -> compareContents t u-      x  -> x--compareContents :: TermList f -> TermList f -> Ordering-compareContents Empty !_ = EQ-compareContents (ConsSym s1 t) (UnsafeConsSym s2 u) =-  case compare (root s1) (root s2) of-    EQ -> compareContents t u-    x  -> x------------------------------------------------------------------------------------- Building terms.------------------------------------------------------------------------------------- | A monoid for building terms.--- 'mempty' represents the empty termlist, while 'mappend' appends two termlists.-newtype Builder f =-  Builder {-    unBuilder ::-      -- Takes: the term array and size, and current position in the term.-      -- Returns the final position, which may be out of bounds.-      forall s. Builder1 s f }--type Builder1 s f = State# s -> MutableByteArray# s -> Int# -> Int# -> (# State# s, Int# #)--instance Monoid (Builder f) where-  {-# INLINE mempty #-}-  mempty = Builder built-  {-# INLINE mappend #-}-  Builder m1 `mappend` Builder m2 = Builder (m1 `then_` m2)---- Build a termlist from a Builder.--- Works by guessing an appropriate size, and retrying if that was too small.-{-# INLINE buildTermList #-}-buildTermList :: Builder f -> TermList f-buildTermList builder = runST $ do-  let-    Builder m = builder-    loop n@(I# n#) = do-      MutableByteArray mbytearray# <--        newByteArray (n * sizeOf (fromSymbol undefined))-      n' <--        ST $ \s ->-          case m s mbytearray# n# 0# of-            (# s, n# #) -> (# s, I# n# #)-      if n' <= n then do-        !bytearray <- unsafeFreezeByteArray (MutableByteArray mbytearray#)-        return (TermList 0 n' bytearray)-       else loop (n'*2)-  loop 32---- Get at the term array.-{-# INLINE getByteArray #-}-getByteArray :: (MutableByteArray s -> Builder1 s f) -> Builder1 s f-getByteArray k = \s bytearray n i -> k (MutableByteArray bytearray) s bytearray n i---- Get at the array size.-{-# INLINE getSize #-}-getSize :: (Int -> Builder1 s f) -> Builder1 s f-getSize k = \s bytearray n i -> k (I# n) s bytearray n i---- Get at the current array index.-{-# INLINE getIndex #-}-getIndex :: (Int -> Builder1 s f) -> Builder1 s f-getIndex k = \s bytearray n i -> k (I# i) s bytearray n i---- Change the current array index.-{-# INLINE putIndex #-}-putIndex :: Int -> Builder1 s f-putIndex (I# i) = \s _ _ _ -> (# s, i #)---- Lift an ST computation into a builder.-{-# INLINE liftST #-}-liftST :: ST s () -> Builder1 s f-liftST (ST m) =-  \s _ _ i ->-  case m s of-    (# s, () #) -> (# s, i #)---- Finish building.-{-# INLINE built #-}-built :: Builder1 s f-built = \s _ _ i -> (# s, i #)---- Sequence two builder operations.-{-# INLINE then_ #-}-then_ :: Builder1 s f -> Builder1 s f -> Builder1 s f-then_ m1 m2 =-  \s bytearray n i ->-    case m1 s bytearray n i of-      (# s, i #) -> m2 s bytearray n i---- checked j m executes m only if the array has room for j more symbols.-{-# INLINE checked #-}-checked :: Int -> Builder1 s f -> Builder1 s f-checked j m =-  getSize $ \n ->-  getIndex $ \i ->-  if i + j <= n then m else putIndex (i + j)---- Emit an arbitrary symbol, with given arguments.-{-# INLINE emitSymbolBuilder #-}-emitSymbolBuilder :: Symbol -> Builder f -> Builder f-emitSymbolBuilder x inner =-  Builder $ checked 1 $-    getByteArray $ \bytearray ->-    -- Skip the symbol itself, then fill it in at the end, when we know the size-    -- of the symbol's arguments.-    getIndex $ \n ->-    putIndex (n+1) `then_`-    unBuilder inner `then_`-    -- Fill in the symbol.-    getIndex (\m ->-      liftST $ writeByteArray bytearray n (fromSymbol x { size = m - n }))---- Emit a function application.-{-# INLINE emitApp #-}-emitApp :: Fun f -> Builder f -> Builder f-emitApp (F n) inner = emitSymbolBuilder (Symbol True n 0) inner---- Emit a variable.-{-# INLINE emitVar #-}-emitVar :: Var -> Builder f-emitVar x = emitSymbolBuilder (Symbol False (var_id x) 1) mempty---- Emit a whole termlist.-{-# INLINE emitTermList #-}-emitTermList :: TermList f -> Builder f-emitTermList (TermList lo hi array) =-  Builder $ checked (hi-lo) $-    getByteArray $ \mbytearray ->-    getIndex $ \n ->-    let k = sizeOf (fromSymbol undefined) in-    liftST (copyByteArray mbytearray (n*k) array (lo*k) ((hi-lo)*k)) `then_`-    putIndex (n + hi-lo)--------------------------------------------------------------------------- Efficient subterm testing.--------------------------------------------------------------------------- | Is a term contained as a subterm in a given termlist?-{-# INLINE isSubtermOfList #-}-isSubtermOfList :: Term f -> TermList f -> Bool-isSubtermOfList t u =-  isSubArrayOf (singleton t) u---- N.B. this one should not be exported from Twee.Term--- because subarray is not the same as subterm if t is not--- a singleton-isSubArrayOf :: TermList f -> TermList f -> Bool-isSubArrayOf t u =-  lenList t <= lenList u && (here t u || next t u)-  where-    here Empty _ = True-    here (ConsSym s1 t) (UnsafeConsSym s2 u) =-      root s1 == root s2 && here t u--    -- This is safe because lenList t <= lenList u-    -- so if u = Empty, then t = Empty and here t u = True.-    next t (UnsafeConsSym _ u) = isSubArrayOf t u---- | Check if a variable occurs in a termlist.-{-# INLINE occursList #-}-occursList :: Var -> TermList f -> Bool-occursList (V x) t = symbolOccursList (fromSymbol (Symbol False x 1)) t--symbolOccursList :: Int64 -> TermList f -> Bool-symbolOccursList !_ Empty = False-symbolOccursList n (ConsSym t ts) = root t == n || symbolOccursList n ts
− src/Twee/Utils.hs
@@ -1,145 +0,0 @@--- | Miscellaneous utility functions.--{-# LANGUAGE CPP, MagicHash #-}-module Twee.Utils where--import Control.Arrow((&&&))-import Control.Exception-import Data.List(groupBy, sortBy)-import Data.Ord(comparing)-import System.IO-import GHC.Prim-import GHC.Types-import Data.Bits---import Test.QuickCheck hiding ((.&.))--repeatM :: Monad m => m a -> m [a]-repeatM = sequence . repeat--partitionBy :: Ord b => (a -> b) -> [a] -> [[a]]-partitionBy value =-  map (map fst) .-  groupBy (\x y -> snd x == snd y) .-  sortBy (comparing snd) .-  map (id &&& value)--collate :: Ord a => ([b] -> c) -> [(a, b)] -> [(a, c)]-collate f = map g . partitionBy fst-  where-    g xs = (fst (head xs), f (map snd xs))--isSorted :: Ord a => [a] -> Bool-isSorted xs = and (zipWith (<=) xs (tail xs))--isSortedBy :: Ord b => (a -> b) -> [a] -> Bool-isSortedBy f xs = isSorted (map f xs)--usort :: Ord a => [a] -> [a]-usort = usortBy compare--usortBy :: (a -> a -> Ordering) -> [a] -> [a]-usortBy f = map head . groupBy (\x y -> f x y == EQ) . sortBy f--sortBy' :: Ord b => (a -> b) -> [a] -> [a]-sortBy' f = map snd . sortBy (comparing fst) . map (\x -> (f x, x))--usortBy' :: Ord b => (a -> b) -> [a] -> [a]-usortBy' f = map snd . usortBy (comparing fst) . map (\x -> (f x, x))--orElse :: Ordering -> Ordering -> Ordering-EQ `orElse` x = x-x  `orElse` _ = x--unbuffered :: IO a -> IO a-unbuffered x = do-  buf <- hGetBuffering stdout-  bracket_-    (hSetBuffering stdout NoBuffering)-    (hSetBuffering stdout buf)-    x--newtype Max a = Max { getMax :: Maybe a }--getMaxWith :: Ord a => a -> Max a -> a-getMaxWith x (Max (Just y)) = x `max` y-getMaxWith x (Max Nothing)  = x--instance Ord a => Monoid (Max a) where-  mempty = Max Nothing-  Max (Just x) `mappend` y = Max (Just (getMaxWith x y))-  Max Nothing  `mappend` y = y--newtype Min a = Min { getMin :: Maybe a }--getMinWith :: Ord a => a -> Min a -> a-getMinWith x (Min (Just y)) = x `min` y-getMinWith x (Min Nothing)  = x--instance Ord a => Monoid (Min a) where-  mempty = Min Nothing-  Min (Just x) `mappend` y = Min (Just (getMinWith x y))-  Min Nothing  `mappend` y = y--labelM :: Monad m => (a -> m b) -> [a] -> m [(a, b)]-labelM f = mapM (\x -> do { y <- f x; return (x, y) })--#if __GLASGOW_HASKELL__ < 710-isSubsequenceOf :: Ord a => [a] -> [a] -> Bool-[] `isSubsequenceOf` ys = True-(x:xs) `isSubsequenceOf` [] = False-(x:xs) `isSubsequenceOf` (y:ys)-  | x == y = xs `isSubsequenceOf` ys-  | otherwise = (x:xs) `isSubsequenceOf` ys-#endif--{-# INLINE fixpoint #-}-fixpoint :: Eq a => (a -> a) -> a -> a-fixpoint f x = fxp x-  where-    fxp x-      | x == y = x-      | otherwise = fxp y-      where-        y = f x---- From "Bit twiddling hacks": branchless min and max-{-# INLINE intMin #-}-intMin :: Int -> Int -> Int-intMin x y =-  y `xor` ((x `xor` y) .&. negate (x .<. y))-  where-    I# x .<. I# y = I# (x <# y)--{-# INLINE intMax #-}-intMax :: Int -> Int -> Int-intMax x y =-  x `xor` ((x `xor` y) .&. negate (x .<. y))-  where-    I# x .<. I# y = I# (x <# y)---- Split an interval (inclusive bounds) into a particular number of blocks-splitInterval :: Integral a => a -> (a, a) -> [(a, a)]-splitInterval k (lo, hi) =-  [ (lo+i*blockSize, (lo+(i+1)*blockSize-1) `min` hi)-  | i <- [0..k-1] ]-  where-    size = (hi-lo+1)-    blockSize = (size + k - 1) `div` k -- division rounding up-{--prop_split_1 (Positive k) (lo, hi) =-  -- Check that all elements occur exactly once-  concat [[x..y] | (x, y) <- splitInterval k (lo, hi)] === [lo..hi]---- Check that we have the correct number and distribution of blocks-prop_split_2 (Positive k) (lo, hi) =-  counterexample (show splits) $ conjoin-    [counterexample "Reason: too many splits" $-       length splits <= k,-     counterexample "Reason: too few splits" $-       length [lo..hi] >= k ==> length splits == k,-     counterexample "Reason: uneven distribution" $-      not (null splits) ==>-       minimum (map length splits) + 1 >= maximum (map length splits)]-  where-    splits = splitInterval k (lo, hi)--}
− tests/BOO067-1.p
@@ -1,32 +0,0 @@-%---------------------------------------------------------------------------% File     : BOO067-1 : TPTP v6.3.0. Released v2.6.0.-% Domain   : Boolean Algebra (Ternary)-% Problem  : Ternary Boolean Algebra Single axiom is complete, part 1-% Version  : [MP96] (equality) axioms.-% English  :--% Refs     : [McC98] McCune (1998), Email to G. Sutcliffe-%          : [MP96]  McCune & Padmanabhan (1996), Automated Deduction in Eq-% Source   : [TPTP]-% Names    :--% Status   : Unsatisfiable-% Rating   : 0.42 v6.3.0, 0.35 v6.2.0, 0.29 v6.1.0, 0.31 v6.0.0, 0.48 v5.5.0, 0.47 v5.4.0, 0.33 v5.3.0, 0.25 v5.2.0, 0.29 v5.1.0, 0.33 v5.0.0, 0.29 v4.1.0, 0.18 v4.0.1, 0.36 v4.0.0, 0.38 v3.7.0, 0.11 v3.4.0, 0.12 v3.3.0, 0.21 v3.1.0, 0.33 v2.7.0, 0.27 v2.6.0-% Syntax   : Number of clauses     :    2 (   0 non-Horn;   2 unit;   1 RR)-%            Number of atoms       :    2 (   2 equality)-%            Maximal clause size   :    1 (   1 average)-%            Number of predicates  :    1 (   0 propositional; 2-2 arity)-%            Number of functors    :    7 (   5 constant; 0-3 arity)-%            Number of variables   :    7 (   0 singleton)-%            Maximal term depth    :    5 (   3 average)-% SPC      : CNF_UNS_RFO_PEQ_UEQ--% Comments : A UEQ part of BOO035-1-%---------------------------------------------------------------------------cnf(single_axiom,axiom,-    ( multiply(multiply(A,inverse(A),B),inverse(multiply(multiply(C,D,E),F,multiply(C,D,G))),multiply(D,multiply(G,F,E),C)) = B )).--cnf(prove_tba_axioms_1,negated_conjecture,-    (  multiply(multiply(d,e,a),b,multiply(d,e,c)) != multiply(d,e,multiply(a,b,c)) )).--%--------------------------------------------------------------------------
− tests/LAT072-1.p
@@ -1,37 +0,0 @@-%---------------------------------------------------------------------------% File     : LAT072-1 : TPTP v6.3.0. Released v2.6.0.-% Domain   : Lattice Theory (Ortholattices)-% Problem  : Given single axiom OML-23A, prove associativity-% Version  : [MRV03] (equality) axioms.-% English  : Given a single axiom candidate OML-23A for orthomodular lattices-%            (OML) in terms of the Sheffer Stroke, prove a Sheffer stroke form-%            of associativity.--% Refs     : [MRV03] McCune et al. (2003), Sheffer Stroke Bases for Ortholatt-% Source   : [MRV03]-% Names    : OML-23A-associativity [MRV03]--% Status   : Unsatisfiable-% Rating   : 0.95 v6.3.0, 0.94 v6.2.0, 0.93 v6.1.0, 0.94 v6.0.0, 0.95 v5.4.0, 1.00 v2.6.0-% Syntax   : Number of clauses     :    2 (   0 non-Horn;   2 unit;   1 RR)-%            Number of atoms       :    2 (   2 equality)-%            Maximal clause size   :    1 (   1 average)-%            Number of predicates  :    1 (   0 propositional; 2-2 arity)-%            Number of functors    :    4 (   3 constant; 0-2 arity)-%            Number of variables   :    4 (   2 singleton)-%            Maximal term depth    :    7 (   4 average)-% SPC      : CNF_UNS_RFO_PEQ_UEQ--% Comments :-%---------------------------------------------------------------------------%----Single axiom OML-23A-cnf(oml_23A,axiom,-    ( f(f(f(f(B,A),f(A,C)),D),f(A,f(f(C,f(f(A,A),C)),C))) = A )).--cnf(a, axiom, f(X,Y) = f(Y, X)).--%----Denial of Sheffer stroke associativity-cnf(associativity,negated_conjecture,-    (  f(a,f(f(b,c),f(b,c))) != f(c,f(f(b,a),f(b,a))) )).--%--------------------------------------------------------------------------
− tests/ROB010-1.p
@@ -1,11 +0,0 @@-cnf(condition,hypothesis,-    ( negate(add(a,negate(b))) = c )).--cnf(prove_result,negated_conjecture,-    (  negate(add(c,negate(add(b,a)))) != a )).--cnf(commutativity_of_add,axiom,-    ( add(X,Y) = add(Y,X) )).--cnf(robbins_axiom,axiom,-    ( negate(add(negate(add(X,Y)),negate(add(X,negate(Y))))) = X )).
− tests/append-rev.p
@@ -1,4 +0,0 @@-cnf(rev_rev, axiom, rev(rev(X)) = X).-cnf(app_assoc, axiom, '++'(X,'++'(Y,Z)) = '++'('++'(X,Y),Z)).-cnf(rev_app, axiom, '++'(rev(X),rev(Y)) = rev('++'(Y,X))).-cnf(conjecture, negated_conjecture, '++'(a,rev(b)) != rev('++'(b, rev(a)))).
− tests/db.p
@@ -1,17 +0,0 @@-% http://www.dcs.bbk.ac.uk/~szabolcs/rellat-jlamp-second-submission-2.pdf-% appendix b. theorem 3.4, clause 8.-cnf(a, axiom, '^'(X, Y) = '^'(Y, X)).-cnf(a, axiom, '^'(X, '^'(Y, Z)) = '^'(Y, '^'(X, Z))).-cnf(a, axiom, '^'('^'(X, Y), Z) = '^'(X, '^'(Y, Z))).-cnf(a, axiom, v(X, Y) = v(Y, X)).-cnf(a, axiom, v(X, v(Y, Z)) = v(Y, v(X, Z))).-cnf(a, axiom, v(v(X, Y), Z) = v(X, v(Y, Z))).-cnf(a, axiom, v(X, '^'(X, Y)) = X).-cnf(a, axiom, '^'(X, v(X, Y)) = X).-cnf(a, axiom, upme(X,Y,Z) = '^'(X, v(Y, Z))).-cnf(a, axiom, lome(X,Y,Z) = v('^'(X, Y), '^'(X, Z))).-cnf(a, axiom, upjo(X,Y,Z) = '^'(v(X, Y), v(X, Z))).-cnf(a, axiom, lojo(X,Y,Z) = v(X, '^'(Y, Z))).-cnf(a, axiom, v(upme('^'(a, X1),Y1,Z1), '^'(Y1, Z1)) = '^'(v('^'('^'(a, X1), Y1), Z1), v('^'('^'(a, X1), Z1), Y1))).-cnf(a, axiom, upme(X,Y,Z) = v(upme(X,Y,'^'(a, Z)), upme(X,Z,'^'(a, Y)))).-fof(a, conjecture, (upme(a,x2,y2) = upme(a,x2,z2) => upme(x2,y2,z2) = lome(x2,y2,z2))).
− tests/deriv.p
@@ -1,39 +0,0 @@-% Axioms about arithmetic.--cnf('commutativity of +', axiom,-	'+'(X, Y) = '+'(Y, X)).-cnf('associativity of +', axiom,-	'+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf('commutativity of *', axiom,-	'*'(X, Y) = '*'(Y, X)).-cnf('associativity of *', axiom,-	'*'(X, '*'(Y, Z)) = '*'('*'(X, Y), Z)).-cnf('plus 0', axiom,-	'+'('0', X) = X).-cnf('times 0', axiom,-	'*'('0', X) = '0').-cnf('times 1', axiom,-	'*'('1', X) = X).-cnf('distributivity', axiom,-	'*'(X, '+'(Y, Z)) = '+'('*'(X, Y), '*'(X, Z))).-cnf('minus', axiom,-    '+'(X, '-'(X)) = '0').--cnf('derivative of 0', axiom,-	d('0') = '0').-cnf('derivative of 1', axiom,-	d('1') = '0').-cnf('derivative of x', axiom,-	d(x) = '1').-cnf('derivative of +', axiom,-	d('+'(T,U)) = '+'(d(T), d(U))).-cnf('derivative of *', axiom,-	d('*'(T, U)) = '+'('*'(T, d(U)), '*'(U, d(T)))).-cnf('derivative of sin', axiom,-    d(sin(T)) = '*'(cos(T), d(T))).-cnf('derivative of cos', axiom,-    d(cos(T)) = '-'('*'(sin(T), d(T)))).--fof(goal, conjecture,-	?[T]: d(T) = '*'(x, cos(x))).-    
− tests/diff.p
@@ -1,4 +0,0 @@-cnf('x\\(y\\x)=x', axiom, '\\'(X, '\\'(Y, X)) = X).-cnf('x\\(x\\y)=y\\(y\\x)', axiom, '\\'(X, '\\'(X, Y)) = '\\'(Y, '\\'(Y, X))).-cnf('(x\\y)\\z=(x\\z)\\(y\\z)', axiom, '\\'('\\'(X, Y), Z) = '\\'('\\'(X, Z), '\\'(Y, Z))).-cnf(conjecture, negated_conjecture, '\\'('\\'(a, c), b) != '\\'('\\'(a, b), c)).
− tests/group.p
@@ -1,15 +0,0 @@-fof(identity, axiom,-    ![X]: f(X, e) = X).-fof(right_inverse, axiom,-    ![X]: f(X, i(X)) = e).-fof(associativity, axiom,-    ![X, Y, Z]: f(X, f(Y, Z)) = f(f(X, Y), Z)).-%fof(left_inverse, conjecture,-%    ![X]: f(i(X),X) = e).-%fof(left_identity, conjecture,-%    ![X]: f(e, X) = X).--fof(inverse_distrib, axiom,-    ![X,Y]: f(i(X),i(Y)) = i(f(X,Y))).-fof(commutativity, conjecture,-    ![X,Y]: f(X,Y) = f(Y,X)).
− tests/lat.p
@@ -1,16 +0,0 @@-cnf(idempotence_of_meet, axiom, meet(X, X)=X).-cnf(idempotence_of_join, axiom, join(X, X)=X).-cnf(absorption1, axiom, meet(X, join(X, Y))=X).-cnf(absorption2, axiom, join(X, meet(X, Y))=X).-cnf(commutativity_of_meet, axiom, meet(X, Y)=meet(Y, X)).-cnf(commutativity_of_join, axiom, join(X, Y)=join(Y, X)).-cnf(associativity_of_meet, axiom,-    meet(meet(X, Y), Z)=meet(X, meet(Y, Z))).-cnf(associativity_of_join, axiom,-    join(join(X, Y), Z)=join(X, join(Y, Z))).-cnf(equation_H34, axiom,-    meet(X, join(Y, meet(Z, U)))=meet(X,-                                      join(Y, meet(Z, join(Y, meet(U, join(Y, Z))))))).-cnf(prove_H28, negated_conjecture,-    meet(a, join(b, meet(a, meet(c, d))))!=meet(a,-                                                join(b, meet(c, meet(d, join(a, meet(b, d))))))).
− tests/lcl.p
@@ -1,7 +0,0 @@-cnf(wajsberg_1, axiom, implies(truth, X)=X).-cnf(wajsberg_3, axiom,-    implies(implies(X, Y), Y)=implies(implies(Y, X), X)).-cnf(wajsberg_4, axiom,-    implies(implies(not(X), not(Y)), implies(Y, X))=truth).-cnf(lemma_antecedent, axiom, implies(X, Y)=implies(Y, X)).-cnf(prove_wajsberg_lemma, negated_conjecture, x!=y).
− tests/loop.p
@@ -1,6 +0,0 @@-cnf(mult_ld, axiom, '*'(X, '^'(X, Y)) = Y).-cnf(ld_mult, axiom, '^'(X, '*'(X, Y)) = Y).-cnf(mult_rd, axiom, '*'('/'(X, Y), Y) = X).-cnf(rd_mult, axiom, '/'('*'(X, Y), Y) = X).-cnf(moufang, axiom, '*'(X, '*'(Y, '*'(X, Z))) = '*'('*'('*'(X, Y), X), Z)).-cnf(conjecture, negated_conjecture, '^'(a,a) != '/'(a,a)).
− tests/loop2.p
@@ -1,6 +0,0 @@-cnf('*-\\', axiom, '*'(X, '\\'(X, Y)) = Y).-cnf('\\-*', axiom, '\\'(X, '*'(X, Y)) = Y).-cnf('*-/', axiom, '*'('/'(X, Y), Y) = X).-cnf('/-*', axiom, '/'('*'(X, Y), Y) = X).-cnf(moufang, axiom, '*'(X, '*'(Y, '*'(X, Z))) = '*'('*'('*'(X, Y), X), Z)).-cnf(conjecture, negated_conjecture, '*'(a,'/'(b,b)) != a).
− tests/lukasiewicz.p
@@ -1,6 +0,0 @@-cnf(imp_true, axiom, implies(true, X) = X).-cnf(imp_compose, axiom, implies(implies(X, Y), implies(implies(Y, Z), implies(X, Z))) = true).-cnf(imp_not, axiom, implies(implies(not(X), not(Y)), implies(Y, X)) = true).-cnf(imp_switch, axiom, implies(implies(X, Y), Y) = implies(implies(Y, X), X)).-cnf(or_def, axiom, or(X, Y) = implies(not(X), Y)).-cnf(conjecture, negated_conjecture, or(a,or(b,c)) != or(or(a,b),c)).
− tests/minus.p
@@ -1,12 +0,0 @@-cnf(plus_zero, axiom,-	'+'('0', X) = X).-cnf(plus_zero, axiom,-	'+'(X, '0') = X).-cnf(minus_minus, axiom,-	'-'('-'(X)) = X).-cnf(minus_plus, axiom,-	'-'('+'(X, Y)) = '+'('-'(X), '-'(Y))).--cnf(goal, conjecture,-    '-'('0') = '0').-	%% ?[Y]: d(Y) = '+'(x, x)).
− tests/nand.p
@@ -1,37 +0,0 @@-%---------------------------------------------------------------------------% File     : LAT071-1 : TPTP v6.2.0. Released v2.6.0.-% Domain   : Lattice Theory (Orthomodularlattices)-% Problem  : Given single axiom OML-21C, prove associativity-% Version  : [MRV03] (equality) axioms.-% English  : Given a single axiom candidate OML-21C for orthomodular lattices-%            (OML) in terms of the Sheffer Stroke, prove a Sheffer stroke form-%            of associativity.--% Refs     : [MRV03] McCune et al. (2003), Sheffer Stroke Bases for Ortholatt-% Source   : [MRV03]-% Names    : OML-21C-associativity [MRV03]--% Status   : Open-% Rating   : 1.00 v2.6.0-% Syntax   : Number of clauses     :    2 (   0 non-Horn;   2 unit;   1 RR)-%            Number of atoms       :    2 (   2 equality)-%            Maximal clause size   :    1 (   1 average)-%            Number of predicates  :    1 (   0 propositional; 2-2 arity)-%            Number of functors    :    4 (   3 constant; 0-2 arity)-%            Number of variables   :    4 (   2 singleton)-%            Maximal term depth    :    6 (   4 average)-% SPC      : CNF_UNK_UEQ--% Comments :-%---------------------------------------------------------------------------%----Single axiom OML-21C-cnf(oml_21C,axiom,-    ( f(f(B,A),f(f(f(f(B,A),A),f(C,A)),f(f(A,A),D))) = A )).--cnf(a, axiom, f(z, f(z, z)) = k).--%----Denial of Sheffer stroke associativity-cnf(associativity,negated_conjecture,-    (  f(a,f(f(b,c),f(b,c))) != f(c,f(f(b,a),f(b,a))) )).--%--------------------------------------------------------------------------
− tests/nicomachus.p
@@ -1,18 +0,0 @@-cnf(plus_comm, axiom, plus(X, Y) = plus(Y, X)).-cnf(plus_assoc, axiom, plus(X, plus(Y, Z)) = plus(plus(X, Y), Z)).-cnf(times_comm, axiom, times(X, Y) = times(Y, X)).-cnf(times_assoc, axiom, times(X, times(Y, Z)) = times(times(X, Y), Z)).-cnf(plus_zero, axiom, plus(X, zero) = X).-cnf(times_zero, axiom, times(X, zero) = zero).-cnf(times_one, axiom, times(X, one) = X).-cnf(distr, axiom, times(X, plus(Y, Z)) = plus(times(X, Y), times(X, Z))).-cnf(distr, axiom, times(plus(X, Y), Z) = plus(times(X, Z), times(Y, Z))).-cnf(plus_s, axiom, plus(s(X), Y) = s(plus(X, Y))).-cnf(times_s, axiom, times(s(X), Y) = plus(Y, times(X, Y))).-cnf(sum_zero, axiom, sum(zero) = zero).-cnf(sum_s, axiom, sum(s(N)) = plus(s(N), sum(N))).-cnf(cubes_zero, axiom, cubes(zero) = zero).-cnf(cubes_s, axiom, cubes(s(N)) = plus(times(s(N), times(s(N), s(N))), cubes(N))).-cnf(plus_sum, axiom, plus(sum(N), sum(N)) = times(N, s(N))).-cnf(ih, axiom, times(sum(a), sum(a)) = cubes(a)).-cnf(conjecture, negated_conjecture, times(sum(s(a)), sum(s(a))) != cubes(s(a))).
− tests/ring.p
@@ -1,9 +0,0 @@-cnf(plus_comm, axiom, '+'(X, Y) = '+'(Y, X)).-cnf(plus_assoc, axiom, '+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf(plus_zero, axiom, '+'('0', X) = X).-cnf(plus_inv, axiom, '+'(X, '-'(X)) = '0').-cnf(times_assoc, axiom, '*'(X, '*'(Y, Z)) = '*'('*'(X, Y), Z)).-cnf(distrib, axiom, '*'(X, '+'(Y, Z)) = '+'('*'(X, Y), '*'(X, Z))).-cnf(distrib, axiom, '*'('+'(X, Y), Z) = '+'('*'(X, Z), '*'(Y, Z))).-cnf(cube, axiom, X = '*'(X, '*'(X, X))).-cnf(conjecture, negated_conjecture, '*'(a, b) != '*'(b, a)).
− tests/ring2.p
@@ -1,9 +0,0 @@-cnf(plus_comm, axiom, '+'(X, Y) = '+'(Y, X)).-cnf(plus_assoc, axiom, '+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf(plus_zero, axiom, '+'('0', X) = X).-cnf(plus_inv, axiom, '+'(X, '-'(X)) = '0').-cnf(times_assoc, axiom, '*'(X, '*'(Y, Z)) = '*'('*'(X, Y), Z)).-cnf(distrib, axiom, '*'(X, '+'(Y, Z)) = '+'('*'(X, Y), '*'(X, Z))).-cnf(distrib, axiom, '*'('+'(X, Y), Z) = '+'('*'(X, Z), '*'(Y, Z))).-cnf(power_six, axiom, X = '*'(X, '*'(X, '*'(X, '*'(X, '*'(X, X)))))).-cnf(conjecture, negated_conjecture, '*'(a, b) != '*'(b, a)).
− tests/ring3.p
@@ -1,9 +0,0 @@-cnf(plus_comm, axiom, '+'(X, Y) = '+'(Y, X)).-cnf(plus_assoc, axiom, '+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf(plus_zero, axiom, '+'('0', X) = X).-cnf(plus_neg, axiom, '+'(X, '-'(X)) = '0').-cnf(times_assoc, axiom, '*'(X, '*'(Y, Z)) = '*'('*'(X, Y), Z)).-cnf(distrib, axiom, '*'(X, '+'(Y, Z)) = '+'('*'(X, Y), '*'(X, Z))).-cnf(distrib, axiom, '*'('+'(X, Y), Z) = '+'('*'(X, Z), '*'(Y, Z))).-cnf(power_four, axiom, X = '*'(X, '*'(X, '*'(X, X)))).-cnf(conjecture, negated_conjecture, '*'(a, b) != '*'(b, a)).
− tests/ring4.p
@@ -1,9 +0,0 @@-cnf(plus_comm, axiom, '+'(X, Y) = '+'(Y, X)).-cnf(plus_assoc, axiom, '+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf(plus_zero, axiom, '+'('0', X) = X).-cnf(plus_inv, axiom, '+'(X, '-'(X)) = '0').-cnf(times_ssoc, axiom, '*'(X, '*'(Y, Z)) = '*'('*'(X, Y), Z)).-cnf(distrib, axiom, '*'(X, '+'(Y, Z)) = '+'('*'(X, Y), '*'(X, Z))).-cnf(distrib, axiom, '*'('+'(X, Y), Z) = '+'('*'(X, Z), '*'(Y, Z))).-cnf(power_five, axiom, X = '*'(X, '*'(X, '*'(X, '*'(X, X))))).-cnf(conjecture, negated_conjecture, '*'(a, b) != '*'(b, a)).
− tests/robbins-easy.p
@@ -1,4 +0,0 @@-cnf(comm, axiom, '+'(X, Y) = '+'(Y, X)).-cnf(assoc, axiom, '+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf(funny, axiom, '+'('-'('+'('-'(X), Y)), '-'('+'('-'(X), '-'(Y)))) = X).-cnf(conjecture, negated_conjecture, '-'('+'('-'('+'(a, b)), '-'('+'(a, '-'(b))))) != a).
− tests/robbins.p
@@ -1,4 +0,0 @@-cnf(comm, axiom, '+'(X, Y) = '+'(Y, X)).-cnf(assoc, axiom, '+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf(funny, axiom, '-'('+'('-'('+'(X, Y)), '-'('+'(X, '-'(Y))))) = X).-cnf(conjecture, negated_conjecture, '-'('-'(a)) != a).
− tests/sam.p
@@ -1,38 +0,0 @@-cnf(f_assoc, axiom,-    meet(X,meet(Y,Z)) = meet(meet(X,Y),Z)).-cnf(f_comm, axiom,-    meet(X,Y) = meet(Y,X)).-cnf(f_idem, axiom,-    meet(X,X) = X).-cnf(g_assoc, axiom,-    join(X,join(Y,Z)) = join(join(X,Y),Z)).-cnf(g_comm, axiom,-    join(X,Y) = join(Y,X)).-cnf(g_idem, axiom,-    join(X,X) = X).--cnf(ax31, axiom,-    meet(X, join(X,Y)) = X).-cnf(ax32, axiom,-    meet(zero, X) = zero).-cnf(ax33, axiom,-    join(zero, X) = X).-cnf(ax34, axiom,-    join(X, meet(X, Y)) = X).-cnf(ax35, axiom,-    meet(one, X) = X).-cnf(ax36, axiom,-    join(one, X) = one).-cnf(ax37, axiom,-    meet(X,Z) = X =>-    meet(join(X,Y),Z) = join(X,meet(Y,Z))).--cnf(comp, definition,-    comp(X,Y) <=> (meet(X,Y) = zero & join(X,Y) = one)).--cnf(premise1, assumption,-    comp(a, join(c,d))).-cnf(premise2, assumption,-    comp(b, join(c,d))).-cnf(goal, conjecture,-    meet(join(a,meet(b,c)),join(a,meet(b,d)))=a).
− tests/semigroup.p
@@ -1,4 +0,0 @@-cnf(assoc, axiom, '*'(X, '*'(Y, Z)) = '*'('*'(X, Y), Z)).-cnf(two_three, axiom, '*'(X, X) = '*'(X, '*'(X, X))).-cnf(twiddle, axiom, '*'('*'(X, X), Y) = '*'(Y, '*'(X, X))).-cnf(conjecture, negated_conjecture, '*'('*'(a, b), '*'(a, b)) != '*'('*'(a, a), '*'(b, b))).
− tests/semigroup2.p
@@ -1,26 +0,0 @@-% File     : GRP196-1 : TPTP v6.1.0. Released v2.2.0.-% Domain   : Group Theory (Semigroups)-% Problem  : In semigroups, xyyy=yyyx -> (uy)^9 = u^9v^9.-% Version  : [MP96] (equality) axioms.-% English  :-% Refs     : [McC98] McCune (1998), Email to G. Sutcliffe-%          : [MP96]  McCune & Padmanabhan (1996), Automated Deduction in Eq-%          : [McC95] McCune (1995), Four Challenge Problems in Equational L-% Source   : [McC98]-% Names    : CS-3 [MP96]-%          : Problem B [McC95]-% Status   : Unsatisfiable-% Rating   : 1.00 v4.0.1, 0.93 v4.0.0, 0.92 v3.7.0, 0.89 v3.4.0, 1.00 v3.3.0, 0.93 v3.1.0, 1.00 v2.2.1-% Syntax   : Number of clauses     :    3 (   0 non-Horn;   3 unit;   1 RR)-%            Number of atoms       :    3 (   3 equality)-%            Maximal clause size   :    1 (   1 average)-%            Number of predicates  :    1 (   0 propositional; 2-2 arity)-%            Number of functors    :    3 (   2 constant; 0-2 arity)-%            Number of variables   :    5 (   0 singleton)-%            Maximal term depth    :   18 (   8 average)-% SPC      : CNF_UNS_RFO_PEQ_UEQ-% Comments : The problem was originally posed for cancellative semigroups,-%            Otter does this with a nonstandard representation [MP96].-cnf(assoc, axiom, '*'('*'(A,B),C)='*'(A,'*'(B,C))).-cnf(twiddle, axiom, '*'(A,'*'(B,'*'(B,B)))='*'(B,'*'(B,'*'(B,A)))).-cnf(conjecture, negated_conjecture, '*'(a,'*'(b,'*'(a,'*'(b,'*'(a,'*'(b,'*'(a,'*'(b,'*'(a,'*'(b,'*'(a,'*'(b,'*'(a,'*'(b,'*'(a,'*'(b,'*'(a,b))))))))))))))))) != '*'(a,'*'(a,'*'(a,'*'(a,'*'(a,'*'(a,'*'(a,'*'(a,'*'(a,'*'(b,'*'(b,'*'(b,'*'(b,'*'(b,'*'(b,'*'(b,'*'(b,b)))))))))))))))))).
− tests/veroff.p
@@ -1,10 +0,0 @@-cnf(majority, axiom,-    f(X,X,Y) = X).-cnf('2a', axiom,-    f(X,Y,Z) = f(Z,X,Y)).-cnf('2b', axiom,-    f(X,Y,Z) = f(X,Z,Y)).-cnf(associativity, axiom,-    f(f(X,W,Y),W,Z) = f(X,W,f(Y,W,Z))).--cnf(goal, axiom, f(f(a1,a2,a3),a4,a5) != f(f(a1,a4,a5),f(a2,a4,a5),f(a3,a4,a5))).
− tests/winkler-easy.p
@@ -1,6 +0,0 @@-% Needs case split on X < c.-cnf(comm, axiom, '+'(X, Y) = '+'(Y, X)).-cnf(assoc, axiom, '+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf(idem, axiom, '+'(X, X) = X).-cnf(funny, axiom, '-'('+'('-'('+'(X, Y)), '-'('+'(X, '-'(Y))))) = X).-cnf(conjecture, negated_conjecture, '+'('-'('+'('-'(a), b)), '-'('+'('-'(a), '-'(b)))) != a).
− tests/winkler.p
@@ -1,6 +0,0 @@-% Needs case split on X < c.-cnf(comm, axiom, '+'(X, Y) = '+'(Y, X)).-cnf(assoc, axiom, '+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf(idem_c, axiom, '+'(c, c) = c).-cnf(funny, axiom, '-'('+'('-'('+'(X, Y)), '-'('+'(X, '-'(Y))))) = X).-cnf(conjecture, negated_conjecture, '+'('-'('+'('-'(a), b)), '-'('+'('-'(a), '-'(b)))) != a).
− tests/winkler2.p
@@ -1,6 +0,0 @@-% Needs case split on X < c.-cnf(comm, axiom, '+'(X, Y) = '+'(Y, X)).-cnf(assoc, axiom, '+'(X, '+'(Y, Z)) = '+'('+'(X, Y), Z)).-cnf(plus_c_d, axiom, '+'(c, d) = c).-cnf(funny, axiom, '-'('+'('-'('+'(X, Y)), '-'('+'(X, '-'(Y))))) = X).-cnf(conjecture, negated_conjecture, '+'('-'('+'('-'(a), b)), '-'('+'('-'(a), '-'(b)))) != a).
− tests/y.p
@@ -1,3 +0,0 @@-fof(k_def, axiom, ![X, Y]: '@'('@'(k, X), Y) = X).-fof(s_def, axiom, ![X, Y, Z]: '@'('@'('@'(s, X), Y), Z) = '@'('@'(X, Z), '@'(Y, Z))).-fof(conjecture, conjecture, ?[Y]: ![F]: '@'(Y, F) = '@'(F, '@'(Y, F))).
twee-lib.cabal view
@@ -1,5 +1,5 @@ name:                twee-lib-version:             2.1+version:             2.1.1 synopsis:            An equational theorem prover homepage:            http://github.com/nick8325/twee license:             BSD3@@ -9,7 +9,6 @@ category:            Theorem Provers build-type:          Simple cabal-version:       >=1.10-extra-source-files:  README.md tests/*.p misc/*.hs misc/*.pl misc/static-libstdc++ description:    Twee is an experimental equational theorem prover based on    Knuth-Bendix completion.@@ -80,7 +79,7 @@     ghc-prim,     primitive >= 0.6.2.0,     vector-  hs-source-dirs:      src+  hs-source-dirs:      .   ghc-options:         -W -fno-warn-incomplete-patterns -O2 -fmax-worker-args=100   default-language:    Haskell2010