ideas-0.7: src/Domain/Math/Power/Utils.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 : alex.gerdes@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-- some of these help functions may have a broader scope and could be
-- moved to other parts of the framework (eg. Common)
--
-----------------------------------------------------------------------------
module Domain.Math.Power.Utils where
import Prelude hiding (repeat, replicate)
import Common.Context
import Common.Rewriting
import Common.Strategy hiding (not)
import Common.Transformation
import Common.View
import Control.Monad
import Data.List hiding (repeat, replicate)
import Data.Ratio
import qualified Domain.Math.Data.PrimeFactors as PF
import Domain.Math.Data.Relation
import Domain.Math.Expr
import Domain.Math.Numeric.Rules
import Domain.Math.Numeric.Views
-- | Strategy functions -------------------------------------------------------
exhaustiveStrategy :: IsTerm a => [Rule a] -> Strategy (Context a)
exhaustiveStrategy = exhaustiveSomewhere . map liftToContext
exhaustiveUse :: (IsTerm a, IsTerm b) => [Rule a] -> Strategy (Context b)
exhaustiveUse = exhaustiveSomewhere . map use
exhaustiveSomewhere :: IsStrategy f => [f (Context a)] -> Strategy (Context a)
exhaustiveSomewhere = repeat . somewhere . alternatives
-- | Rule functions -----------------------------------------------------------
smartRule :: Rule Expr -> Rule Expr
smartRule = doAfter f
where
f (a :*: b) = a .*. b
f (a :/: b) = a ./. b
f (Negate a) = neg a
f (a :+: b) = a .+. b
f (a :-: b) = a .-. b
f e = e
mergeConstantsWith :: (Expr -> Bool) -> Expr -> Expr
mergeConstantsWith p = simplifyWith f productView
where
f (sign, xs) =
let (cs, ys) = partition p xs
c = simplify rationalView $ build productView (False, cs)
in if maybe False (> 1) (match rationalView c)
then (sign, c:ys)
else (sign, xs)
mergeConstants :: Expr -> Expr
mergeConstants = mergeConstantsWith (`belongsTo` rationalView)
-- | View functions -----------------------------------------------------------
(<&>) :: (MonadPlus m) => ViewM m a b -> ViewM m a b -> ViewM m a b
v <&> w = makeView (\x -> match v x `mplus` match w x) (build v)
infixl 1 <&>
plainNatView :: View Expr Integer
plainNatView = makeView f Nat
where
f (Nat n) = Just n
f _ = Nothing
myIntegerView :: View Expr Integer
myIntegerView = makeView f fromInteger
where
f (Nat n) = Just n
f (Negate (Nat n)) = Just $ negate n
f _ = Nothing
plainRationalView :: View Rational (Integer, Integer)
plainRationalView =
makeView (\x -> return (numerator x, denominator x)) (uncurry (%))
eqView :: View a b -> View (Equation a) (b, b)
eqView v = eqv >>> v *** v
where
eqv = makeView (\(lhs :==: rhs) -> Just (lhs, rhs)) (uncurry (:==:))
-- | Rule collections ---------------------------------------------------------
naturalRules :: [Rule Expr]
naturalRules =
[ calcPlusWith "nat" plainNatView, calcMinusWith "nat" plainNatView
, calcTimesWith "nat" plainNatView, calcDivisionWith "nat" plainNatView
, doubleNegate, negateZero , plusNegateLeft, plusNegateRight
-- , minusNegateLeft
, minusNegateRight, timesNegateLeft, timesNegateRight, divisionNegateLeft
, divisionNegateRight
]
rationalRules :: [Rule Expr]
rationalRules =
[ calcPlusWith "rational" rationalRelaxedForm
, calcMinusWith "rational" rationalRelaxedForm
, calcTimesWith "rational" rationalRelaxedForm
, calcDivisionWith "integer" integerNormalForm
, doubleNegate, negateZero, divisionDenominator, divisionNumerator
, simplerFraction
]
fractionRules :: [Rule Expr]
fractionRules =
[ fractionPlus, fractionPlusScale, fractionTimes
, calcPlusWith "integer" integerNormalForm
, calcMinusWith "integer" integerNormalForm
, calcTimesWith "integer" integerNormalForm -- not needed?
, calcDivisionWith "integer" integerNormalForm
, doubleNegate, negateZero, smartRule divisionDenominator
, smartRule divisionNumerator, simplerFraction
]
-- | Common functions ---------------------------------------------------------
takeRoot :: Integer -> Integer -> Maybe Integer
takeRoot n x = do
y <- if (abs n == 1)
then Just 1
else lookup x $ map swap $ PF.allPowers (abs n)
guard $ n > 0 || (n < 0 && odd x)
return $ if n > 0 then y else negate y
swap :: (a, b) -> (b, a)
swap (a, b) = (b, a)
split :: (Eq a) => (a -> a -> t) -> [a] -> [(t, [a])]
split op xs = f xs
where
f (y:ys) | not (null ys) = [(y `op` z, xs \\ [y, z]) | z <- ys] ++ f ys
| otherwise = []
f [] = []
toMaybe :: (a -> Bool) -> a -> Maybe a
toMaybe p x = if p x then Just x else Nothing
joinBy :: Eq a => (a -> a -> Bool) -> [a] -> [[a]]
joinBy _ [] = []
joinBy eq xs = ys : joinBy eq (xs \\ ys)
where
ys = dropUntil eq xs
dropUntil :: (a -> a -> Bool) -> [a] -> [a]
dropUntil _ [] = []
dropUntil _ [x] = [x]
dropUntil p (x:y:ys) | p x y = x : dropUntil p (y:ys)
| otherwise = [x]
holes :: [a] -> [(a, [a], a -> [a])]
holes xs = map f [0 .. length xs - 1]
where
f i = let (ys, z:zs) = splitAt i xs
in (z, ys ++ zs, \x -> ys ++ x:zs)
twoNonAdjacentHoles :: [a] -> [((a, a), a -> [a])]
twoNonAdjacentHoles xs = concatMap g pairs
where
pairs = [(x, y) | x <- [0 .. length xs - 1], y <- [x + 1 .. length xs - 1]]
g (x, y) = let (ys, z:zs) = splitAt x xs
(ps, q:qs) = splitAt (y - x - 1) zs
in if null ps
then [ ((z, q), \a -> ys ++ a:ps ++ qs) ]
else [ ((z, q), \a -> ys ++ a:ps ++ qs)
, ((z, q), \a -> ys ++ ps ++ a:qs) ]