ideas-1.0: src/Domain/Math/Power/Equation/Rules.hs
-----------------------------------------------------------------------------
-- Copyright 2011, 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)
--
-----------------------------------------------------------------------------
module Domain.Math.Power.Equation.Rules
-- ( -- * Power equation rules
-- commonPower, nthRoot, sameBase, equalsOne, greatestPower
-- , approxPower, reciprocalFor, coverUpRootWith, coverUpRoot
-- )
where
import Common.Library hiding (simplify)
import Control.Monad
--import Data.List (partition)
import Domain.Math.Approximation (precision)
import Domain.Math.Data.Relation
import Domain.Math.Equation.CoverUpRules
import Domain.Math.Expr
import Domain.Math.Numeric.Views
import qualified Domain.Math.Data.PrimeFactors as PF
--import Domain.Math.CleanUp (collectLikeTerms)
import Domain.Math.Polynomial.Rules (distributeTimes, distributeDivisionT)
import Domain.Math.Power.Utils
import Domain.Math.Power.Views
import Domain.Math.Simplification (simplify)
-- | Identifier prefix --------------------------------------------------------
powereq :: String
powereq = "algebra.manipulation.exponents.equation"
-- | Power relation rules -----------------------------------------------------
-- | a^x = b^y => a^(x/c) = b^(y/c) where c = gcd x y
commonPower :: Rule (Equation Expr)
commonPower = makeSimpleRule (powereq, "common-power") $ \expr -> do
let v = eqView (powerView >>> second integerView)
((a, x), (b, y)) <- match v expr
let c = gcd x y
guard $ c > 1
return $ build v ((a, x `div` c), (b, y `div` c))
-- | a^x = n => a^x = b^e
greatestPower :: Rule (Equation Expr)
greatestPower = makeSimpleRule (powereq, "greatest-power") $ \(lhs :==: rhs) -> do
n <- match integerView rhs
(_, x) <- match (powerView >>> second integerView) lhs
(b, e) <- PF.greatestPower n
guard $ gcd x e > 1
return $ lhs :==: fromInteger b .^. fromInteger e
-- a^x = c*b^y => a = c*b^(y/x)
nthRoot :: Rule (Equation Expr)
nthRoot = makeSimpleRule (powereq, "nth-root") $ \(lhs :==: rhs) -> do
guard $ hasSomeVar lhs
(a, x) <- match powerView lhs
(c, (b, y)) <- match unitPowerView rhs
return $ a :==: build unitPowerView (c, (b, simplify (y ./. x)))
-- x = a^x => x ~= d
approxPower :: Rule (Relation Expr)
approxPower = makeRule (powereq, "approx-power") $ approxPowerT 2
-- x = a^x => x ~= d
approxPowerT :: Int -> Transformation (Relation Expr)
approxPowerT n = makeTrans $ \ expr ->
match equationView expr >>= f
where
f (Var x :==: d) =
match doubleView d >>= Just . (Var x .~=.) . fromDouble . precision n
f (d :==: Var x) =
match doubleView d >>= Just . (.~=. Var x) . fromDouble . precision n
f _ = Nothing
-- a^x = a^y => x = y
sameBase :: Rule (Equation Expr)
sameBase = makeSimpleRule (powereq, "same-base") $ \ expr -> do
((a, x), (b, y)) <- match (eqView powerView) expr
guard $ a == b
return $ x :==: y
-- | c*a^x = d*(1/a)^y => c*a^x = d*a^-y
reciprocalFor :: Rule (Equation Expr)
reciprocalFor = makeSimpleRule (powereq, "reciprocal-for-base") $
\ (lhs :==: rhs) -> do
(_, (a, _)) <- match unitPowerView lhs
(one, _) <- match divView rhs
(d, (a'', y)) <- match consPowerView rhs
guard $ one == 1 && a'' == a
return $ lhs :==: d .*. a'' .^. negate y
-- | a^x = 1 => x = 0
equalsOne :: Rule (Equation Expr)
equalsOne = makeSimpleRule (powereq, "equals-one") $ \ (lhs :==: rhs) -> do
guard $ rhs == 1
(_, x) <- match powerView lhs
return $ x :==: 0
----------------------- Move these funcs to right place ----------------------
-- add these two functions to coverUpRules?
coverUpRootWith :: ConfigCoverUp -> Rule (Equation Expr)
coverUpRootWith = coverUpBinaryRule "root" (isBinary rootSymbol) (.^.)
coverUpRoot :: Rule (Equation Expr)
coverUpRoot = coverUpRootWith configCoverUp
-- | Negations are pushed inside
myCoverUpTimesWith :: ConfigCoverUp -> Rule (Equation Expr)
myCoverUpTimesWith = doAfter f . coverUpTimesWith
where
f (lhs :==: rhs) =
lhs :==: applyD distributeDivisionT (applyD distributeTimes rhs)
condXisRight :: Rule (Equation Expr)
condXisRight = describe "flip condition" $ checkRule $ \(lhs :==: rhs) ->
hasVar "x" rhs && withoutVar "x" lhs
--xToLeft = makeRule (powereq, "x -to-left") $ toLeftRightT $ elem "x" . vars
-- toLeftRightT :: (Expr -> Bool) -> Transformation (Equation Expr)
-- toLeftRightT p = makeTrans $
-- \ (lhs :==: rhs) -> do
-- (xs, cs) <- fmap (partition p) (match sumView lhs)
-- (ys, ds) <- fmap (partition p) (match sumView rhs)
-- guard $ length cs > 0 || length ys > 0
-- return $ fmap collectLikeTerms $
-- build sumView (xs ++ map neg ys) :==: build sumView (ds ++ map neg cs)