packages feed

ideas-0.7: src/Common/Rewriting/Axioms.hs

-----------------------------------------------------------------------------
-- Copyright 2010, Open Universiteit Nederland. This file is distributed 
-- under the terms of the GNU General Public License. For more information, 
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-- Group axioms specified as rewrite rules (directed).
--
-----------------------------------------------------------------------------
module Common.Rewriting.Axioms 
   ( -- Semigroup
     leftAssociative, rightAssociative, associative
     -- Monoid
   , leftIdentity, rightIdentity
     -- Group
   , leftInverse, rightInverse
   , inverseIdentity, inverseTwice
   , flippedInverseDistribution
   , groupAxioms
     -- Abelian group
   , commutative, inverseDistribution
   ) where

import Common.Id
import Common.Rewriting.Group
import Common.Rewriting.RewriteRule

-- helper
rule :: (IsMagma m, IsId n, RuleBuilder f a, Rewrite a) => m a -> n -> f -> RewriteRule a
rule m s = rewriteRule (getId (toMagma m), s)

-------------------------------------------------------------------
-- * SemiGroup

leftAssociative :: (IsSemiGroup m, Different a, Rewrite a) => m a -> RewriteRule a
leftAssociative m = rule m "associative.left" $ 
   \x y z -> x.(y.z) :~> (x.y).z
 where 
   (.) = operation m

rightAssociative :: (IsSemiGroup m, Different a, Rewrite a) => m a -> RewriteRule a
rightAssociative m = rule m "associative.right" $ 
   \x y z -> (x.y).z :~> x.(y.z)
 where 
   (.) = operation m

associative :: (IsSemiGroup m, Different a, Rewrite a) => m a -> RewriteRule a
associative m
   | leftIsPreferred m = leftAssociative m
   | otherwise         = rightAssociative m

-------------------------------------------------------------------
-- * Monoid

leftIdentity :: (IsMonoid m, Different a, Rewrite a) => m a -> RewriteRule a
leftIdentity m = rule m "identity.left" $ 
   \x -> e.x :~> x
 where 
   (.) = operation m
   e   = identity m

rightIdentity :: (IsMonoid m, Different a, Rewrite a) => m a -> RewriteRule a
rightIdentity m = rule m "identity.right" $ 
   \x -> x.e :~> x
 where 
   (.) = operation m
   e   = identity m

-------------------------------------------------------------------
-- * Group

leftInverse :: (IsGroup m, Different a, Rewrite a) => m a -> RewriteRule a
leftInverse m = rule m "inverse.left" $ 
   \x -> f x.x :~> e
 where 
   (.) = operation m
   e   = identity m
   f   = inverse m

rightInverse :: (IsGroup m, Different a, Rewrite a) => m a -> RewriteRule a
rightInverse m = rule m "inverse.right" $ 
   \x -> x.f x :~> e
 where 
   (.) = operation m
   e   = identity m
   f   = inverse m

inverseIdentity :: (IsGroup m, Different a, Rewrite a) => m a -> RewriteRule a
inverseIdentity m = rule m "inverse.identity" $ 
   f e :~> e
 where
   e = identity m
   f = inverse m

inverseTwice :: (IsGroup m, Different a, Rewrite a) => m a -> RewriteRule a
inverseTwice m = rule m "inverse.twice" $ 
   \x -> f (f x) :~> x
 where 
   f = inverse m

flippedInverseDistribution :: (IsGroup m, Different a, Rewrite a) => m a -> RewriteRule a
flippedInverseDistribution m = rule m "inverse.distribution.flipped" $ 
   \x y -> f (x.y) :~> f y.f x
 where 
   (.) = operation m
   f   = inverse m

groupAxioms :: (IsGroup m, Different a, Rewrite a) => m a -> [RewriteRule a]
groupAxioms g = map ($ g)
   [ associative, leftIdentity, rightIdentity
   , leftInverse, rightInverse
   , inverseIdentity, inverseTwice, flippedInverseDistribution
   ] ++ extra
 where
   extra 
      | leftIsPreferred g =
           [ rule g "group1" $ \x y -> (y.x).f x :~> y
           , rule g "group2" $ \x y -> (y.f x).x :~> y
           ]
      | otherwise = 
           [ rule g "group3" $ \x y -> f x.(x.y) :~> y
           , rule g "group4" $ \x y -> x.(f x.y) :~> y
           ]
   (.) = operation g
   f   = inverse g

-------------------------------------------------------------------
-- * Abelian Group

-- The type class constraint IsAbelianGroup could be relaxed to 
-- IsCommutative (or something similar)
commutative :: (IsAbelianGroup m, Different a, Rewrite a) => m a -> RewriteRule a
commutative m = rule m "commutative" $ 
   \x y -> x.y :~> y.x
 where 
   (.) = operation m
   
inverseDistribution :: (IsAbelianGroup m, Different a, Rewrite a) => m a -> RewriteRule a
inverseDistribution m = rule m "inverse.distribution" $ 
   \x y -> f (x.y) :~> f x.f y
 where 
   (.) = operation m
   f   = inverse m