packages feed

guarded-rewriting-0.1: performance/Common/Arith.hs

{-# LANGUAGE DeriveDataTypeable   #-}
{-# LANGUAGE TypeOperators        #-}
{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE TypeSynonymInstances #-}

module Common.Arith where

import Control.Monad
import Data.Ratio
import Data.Maybe
import Data.Typeable
import Test.QuickCheck
import System.Random
import Common.GuardedRewriting

propGen :: Int -> Gen (Prop (Equation Expr))
propGen n
   | n == 0 = frequency 
        [ (5, liftM VarP (sized eqGen))
        , (1, return T)
        , (1, return F)
        ]
   | otherwise = oneof 
        [ propGen 0
        , liftM2 (:\/:) rec rec
        , liftM2 (:/\:) rec rec
        , liftM  Not    rec 
        ]
 where
   rec = propGen (n `div` 2)

eqGen :: Int -> Gen (Equation Expr)
eqGen n = liftM2 (:==:) (exprGen n) constGen

-- Expression with exactly one variable
exprGen :: Int -> Gen Expr
exprGen 0 = return (Varia "x")
exprGen n = oneof
   [ return (Varia "x")
   , liftM2 (:+:) rec constGen, liftM2 (:+:) constGen rec
   , liftM2 (:-:) rec constGen, liftM2 (:-:) constGen rec
   , liftM2 (:**:) rec constGen, liftM2 (:**:) constGen rec
   , liftM2 (:/:) rec constGen, liftM2 (:/:) constGen rec
   , liftM2 (\a n -> a :^: Const (fromInteger (succ $ abs n))) rec arbitrary
   ]
 where
   rec = exprGen (n `div` 2)
   
constGen :: Gen Expr
constGen = liftM (Const . fromInteger) arbitrary

isSolved :: Prop (Equation Expr) -> Bool
isSolved prop =
   case prop of
      p :\/: q -> isSolved p && isSolved q
      p :/\: q -> isSolved p && isSolved q
      Not p    -> isSolved p
      VarP p    -> isSolvedEq p 
      _        -> True

isSolvedEq :: Equation Expr -> Bool
isSolvedEq (Varia _ :==: b) = noVaria b
isSolvedEq (a       :==: b) = noVaria a && noVaria b

repeatM :: Monad m => m a -> m [a]
repeatM m = liftM2 (:) m (repeatM m)

formula :: [Prop (Equation Expr)]
formula = generate 100 (mkStdGen 280578) (repeatM (sized propGen))

formulas :: [Prop (Equation Expr)]
formulas = take 10000 formula

-----------------------------------

data Prop a = VarP a | T | F 
            | Prop a :\/: Prop a 
            | Prop a :/\: Prop a 
            | Not (Prop a)
   deriving (Show, Typeable, Eq)

data Equation a = a :==: a
   deriving (Show, Typeable, Eq)

infix  2 :==: 
infixl 6 :+:, :-: 
infixl 7 :**:, :/: 
infixr 8 :^:

data Expr = Const Rational
          | Varia String
          | Expr :+: Expr
          | Expr :-: Expr
          | Expr :**: Expr
          | Expr :/: Expr
          | Expr :^: Expr
   deriving (Eq, Show, Typeable)

instance Functor Prop where
   fmap f (VarP a)    = VarP (f a)
   fmap f T          = T
   fmap f F          = F
   fmap f (p :\/: q) = fmap f p :\/: fmap f q
   fmap f (p :/\: q) = fmap f p :/\: fmap f q
   fmap f (Not p)    = Not (fmap f p)
   
instance Functor Equation where
   fmap f (a :==: b) = f a :==: f b


isEven, isOdd :: Rational -> Bool
isEven r = denominator r == 1 && even (numerator r)
isOdd  r = denominator r == 1 && odd  (numerator r)

hasDivisionByZero :: Expr -> Bool
hasDivisionByZero expr =
   case expr of
      _ :/: Const 0 -> True
      a :+: b  -> hasDivisionByZero a || hasDivisionByZero b
      a :-: b  -> hasDivisionByZero a || hasDivisionByZero b
      a :**: b -> hasDivisionByZero a || hasDivisionByZero b
      a :/: b  -> hasDivisionByZero a || hasDivisionByZero b
      a :^: b  -> hasDivisionByZero a || hasDivisionByZero b
      _ -> False

noVaria, hasVaria :: Expr -> Bool
noVaria = not . hasVaria
hasVaria expr = 
   case expr of
      Const _  -> False
      Varia _  -> True
      a :+: b  -> hasVaria a || hasVaria b
      a :-: b  -> hasVaria a || hasVaria b
      a :**: b -> hasVaria a || hasVaria b
      a :/: b  -> hasVaria a || hasVaria b
      a :^: b  -> hasVaria a || hasVaria b

applyD :: (a -> Maybe a) -> a -> a
applyD f a = fromMaybe a (f a)

applyOne :: [a -> Maybe a] -> a -> Maybe a
applyOne fs a = case mapMaybe ($ a) fs of
                   hd:_ -> Just hd
                   _    -> Nothing
                   

applyBin :: (a -> Maybe a) -> (a -> a -> b) -> a -> a -> Maybe b
applyBin rec op a b = 
   case (rec a, rec b) of
      (Nothing, Nothing) -> Nothing
      (ma, mb) -> Just (fromMaybe a ma `op` fromMaybe b mb)

somewhereProp :: (Prop a -> Maybe (Prop a)) -> Prop a -> Maybe (Prop a)
somewhereProp f = rec
 where
   rec prop = 
      let make op a b = case applyBin rec op a b of
                           Just c  -> Just (applyD f c)
                           Nothing -> f prop
      in case prop of
            p :\/: q -> make (:\/:) p q
            p :/\: q -> make (:/\:) p q
            Not p    -> case rec p of
                           Just p2 -> Just $ applyD f p2
                           Nothing -> f prop
            _        -> f prop

somewhereExpr :: (Expr -> Maybe Expr) -> Expr -> Maybe Expr
somewhereExpr f = rec 
 where
   rec expr = 
      let make2 op a b = case applyBin rec op a b of
                           Just c  -> Just (applyD f c)
                           Nothing -> f expr
      in case expr of
            a :+: b  -> make2 (:+:) a b
            a :-: b  -> make2 (:-:) a b
            a :**: b -> make2 (:**:) a b
            a :/: b  -> make2 (:/:) a b
            a :^: b  -> make2 (:^:) a b
            _        -> f expr

liftToEq :: (a -> Maybe a) -> Equation a -> Maybe (Equation a)
liftToEq f (a :==: b) =
   case (f a, f b) of
      (Nothing, Nothing) -> Nothing
      (ma, mb) -> Just $ fromMaybe a ma :==: fromMaybe b mb

liftToProp :: (a -> Maybe a) -> Prop a -> Maybe (Prop a)
liftToProp f = rec 
 where
   rec prop =
      case prop of
         p :\/: q  -> applyBin rec (:\/:) p q
         p :/\: q  -> applyBin rec (:/\:) p q
         Not p     -> liftM Not (rec p)
         VarP a    -> liftM VarP (f a)
         _         -> Nothing

transformExpr :: (Expr -> Expr) -> Expr -> Expr
transformExpr f = rec 
 where
   rec expr = f $
      case expr of
         a :+: b  -> rec a :+: rec b
         a :-: b  -> rec a :-: rec b
         a :**: b -> rec a :**: rec b
         a :/: b  -> rec a :/: rec b
         a :^: b  -> rec a :^: rec b
         _        -> expr

simplify :: Expr -> Expr
simplify = transformExpr f
 where
   f (Const a :+: Const b)  = Const (a+b)
   f (Const a :-: Const b)  = Const (a-b)
   f (Const a :**: Const b) = Const (a*b)
   f (Const a :/: Const b)  = Const (a/b)
   f (Const a :^: Const b) | denominator b == 1 
      = Const (a^numerator b)
   f a = a

-- Also counts the number of rules that hvae been applied (successfully)
solve :: [Prop (Equation Expr) -> Maybe (Prop (Equation Expr))]
         -> Prop (Equation Expr) -> Prop (Equation Expr)
solve rules = rec where
   rec p = 
      case applyOne rules p of
         Just a  -> rec a
         Nothing -> p

-- Examples
ex :: Prop (Equation Expr)
ex = VarP p :\/: VarP q
 where
   x = Varia "x"
   p = (((x :-: Const 3) :^: Const 2) :/: Const 4) :==: Const 25
   q = (Const 1 :-: (Const 2 :/: (Const 1 :+: (x :**: Const 5)))) :==: Const 4 
ex2 = ((VarP (Const (5 % 1) :/: Varia "x" :==: Const (4 % 1)) :\/: VarP ((Const (6 % 1)
 :/: (Const ((-4) % 1) :+: Varia "x")) :^: Const (3 % 1) :==: Const ((-6) % 1)))
 :\/: VarP (Const ((-7) % 1) :**: (Const ((-5) % 1) :**: Varia "x") :==: Const (4 %
 1))) :\/: (VarP (Varia "x" :==: Const ((-7) % 1)) :\/: VarP (Const (0 % 1) :/: ((Varia "x" :-: Const (0 % 1)) :+: Const (2 % 1)) :==: Const ((-3) % 1)))
 
-- Generic representation
instance (Representable a) => Representable (Prop a) where
  type Rep (Prop a) =      Var a
                      :+: U
                      :+: U
                      :+: Rec (Prop a) :*: Rec (Prop a)
                      :+: Rec (Prop a) :*: Rec (Prop a)
                      :+: Rec (Prop a)
  
  from (VarP x)   = L (Var x)
  from T          = R (L U)
  from F          = R (R (L U))
  from (p :\/: q) = R (R (R (L (Rec p :*: Rec q))))
  from (p :/\: q) = R (R (R (R (L (Rec p :*: Rec q)))))
  from (Not p)    = R (R (R (R (R (Rec p)))))
  
  to (L (Var x))                           = VarP x
  to (R (L U))                             = T
  to (R (R (L U)))                         = F
  to (R (R (R (L (Rec p :*: Rec q)))))     = p :\/: q
  to (R (R (R (R (L (Rec p :*: Rec q)))))) = p :/\: q
  to (R (R (R (R (R (Rec p))))))           = p

instance (Representable a) => Representable (Equation a) where
  type Rep (Equation a) = Var a :*: Var a
  
  from (x :==: y) = Var x :*: Var y
  to (Var x :*: Var y) = x :==: y

instance Representable Expr where
  type Rep Expr =      Var Rational
                  :+: Var String
                  :+: Rec Expr :*: Rec Expr
                  :+: Rec Expr :*: Rec Expr
                  :+: Rec Expr :*: Rec Expr
                  :+: Rec Expr :*: Rec Expr
                  :+: Rec Expr :*: Rec Expr
  
  from (Const r) = L (Var r)
  from (Varia s) = R (L (Var s))
  from (e1 :+: e2)  = R (R (L (Rec e1 :*: Rec e2)))
  from (e1 :-: e2)  = R (R (R (L (Rec e1 :*: Rec e2))))
  from (e1 :**: e2) = R (R (R (R (L (Rec e1 :*: Rec e2)))))
  from (e1 :/: e2)  = R (R (R (R (R (L (Rec e1 :*: Rec e2))))))
  from (e1 :^: e2)  = R (R (R (R (R (R (Rec e1 :*: Rec e2))))))
  
  to (L (Var r)) = Const r
  to (R (L (Var s))) = Varia s
  to (R (R (L (Rec e1 :*: Rec e2)))) = e1 :+: e2
  to (R (R (R (L (Rec e1 :*: Rec e2))))) = e1 :-: e2
  to (R (R (R (R (L (Rec e1 :*: Rec e2)))))) = e1 :**: e2
  to (R (R (R (R (R (L (Rec e1 :*: Rec e2))))))) = e1 :/: e2
  to (R (R (R (R (R (R (Rec e1 :*: Rec e2))))))) = e1 :^: e2

 
instance (Rewritable a) => Rewritable (Prop a)
instance (Rewritable a) => Rewritable (Equation a)
instance Rewritable Expr
instance Rewritable String