packages feed

twee-lib (empty) → 2.1

raw patch · 64 files changed

+8401/−0 lines, 64 filesdep +basedep +containersdep +dlistsetup-changed

Dependencies added: base, containers, dlist, ghc-prim, pretty, primitive, transformers, vector

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015-2017, Nick Smallbone++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Nick Smallbone nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,25 @@+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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ misc/analyse_trace.pl view
@@ -0,0 +1,32 @@+:- 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 view
@@ -0,0 +1,74 @@+{-# 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 view
@@ -0,0 +1,801 @@+:- 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 view
@@ -0,0 +1,977 @@+:- 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++ view
@@ -0,0 +1,24 @@+#!/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 view
@@ -0,0 +1,161 @@+{-# 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 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
+ src/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')
+ src/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
+ src/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
+ src/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+  
+ src/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
+ src/Twee.hs view
@@ -0,0 +1,610 @@+-- | 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 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
+ src/Twee/CP.hs view
@@ -0,0 +1,328 @@+-- | 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 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
+ src/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)
+ src/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)
+ src/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
+ src/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
+ src/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
+ src/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
+ src/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)))
+ src/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
+ src/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
+ src/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
+ src/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
+ src/Twee/Term.hs view
@@ -0,0 +1,646 @@+-- | 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 view
@@ -0,0 +1,422 @@+-- 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 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)+-}
+ tests/BOO067-1.p view
@@ -0,0 +1,32 @@+%--------------------------------------------------------------------------+% 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 view
@@ -0,0 +1,37 @@+%--------------------------------------------------------------------------+% 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 view
@@ -0,0 +1,11 @@+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 view
@@ -0,0 +1,4 @@+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 view
@@ -0,0 +1,17 @@+% 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 view
@@ -0,0 +1,39 @@+% 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 view
@@ -0,0 +1,4 @@+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 view
@@ -0,0 +1,15 @@+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 view
@@ -0,0 +1,16 @@+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 view
@@ -0,0 +1,7 @@+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 view
@@ -0,0 +1,6 @@+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 view
@@ -0,0 +1,6 @@+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 view
@@ -0,0 +1,6 @@+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 view
@@ -0,0 +1,12 @@+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 view
@@ -0,0 +1,37 @@+%--------------------------------------------------------------------------+% 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 view
@@ -0,0 +1,18 @@+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 view
@@ -0,0 +1,9 @@+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 view
@@ -0,0 +1,9 @@+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 view
@@ -0,0 +1,9 @@+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 view
@@ -0,0 +1,9 @@+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 view
@@ -0,0 +1,4 @@+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 view
@@ -0,0 +1,4 @@+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 view
@@ -0,0 +1,38 @@+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 view
@@ -0,0 +1,4 @@+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 view
@@ -0,0 +1,26 @@+% 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 view
@@ -0,0 +1,10 @@+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 view
@@ -0,0 +1,6 @@+% 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 view
@@ -0,0 +1,6 @@+% 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 view
@@ -0,0 +1,6 @@+% 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 view
@@ -0,0 +1,3 @@+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
@@ -0,0 +1,94 @@+name:                twee-lib+version:             2.1+synopsis:            An equational theorem prover+homepage:            http://github.com/nick8325/twee+license:             BSD3+license-file:        LICENSE+author:              Nick Smallbone+maintainer:          nicsma@chalmers.se+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.+   .+   Given a set of equational axioms and a set of equational+   conjectures it will try to prove the conjectures.+   It will terminate if the conjectures are true but normally+   fail to terminate if they are false.+   .+   The input problem should be in TPTP format (see+   http://www.tptp.org). You can use types and quantifiers, but apart+   from that the problem must be equational.+   .+   This package contains only the library part of twee.++source-repository head+  type:     git+  location: git://github.com/nick8325/twee.git+  branch:   master++flag static+  description: Build a static binary.+  default: False++flag static-cxx+  description: Build a binary which statically links against libstdc++.+  default: False++flag llvm+  description: Build using LLVM backend for faster code.+  default: False++flag bounds-checks+  description: Use bounds checks for all array operations.+  default: False++library+  exposed-modules:+    Twee+    Twee.Base+    Twee.Constraints+    Twee.CP+    Twee.Equation+    Twee.Index+    Twee.Join+    Twee.KBO+    Twee.Label+    Twee.PassiveQueue+    Twee.Pretty+    Twee.Proof+    Twee.Rule+    Twee.Rule.Index+    Twee.Term+    Twee.Task+    Twee.Utils+  other-modules:+    Data.ChurchList+    Data.DynamicArray+    Data.Heap+    Twee.Term.Core++  build-depends:+    base >= 4 && < 5,+    containers,+    transformers,+    dlist,+    pretty,+    ghc-prim,+    primitive >= 0.6.2.0,+    vector+  hs-source-dirs:      src+  ghc-options:         -W -fno-warn-incomplete-patterns -O2 -fmax-worker-args=100+  default-language:    Haskell2010++  if flag(llvm)+    ghc-options: -fllvm+  if flag(bounds-checks)+    cpp-options: -DBOUNDS_CHECKS+    exposed-modules:+      Data.Primitive.SmallArray.Checked+      Data.Primitive.ByteArray.Checked+      Data.Primitive.Checked