ideas-0.7: src/Domain/Math/Power/Equation/Rules.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)
--
-----------------------------------------------------------------------------
module Domain.Math.Power.Equation.Rules
( -- * Power equation rules
commonPower, nthRoot, sameBase, equalsOne, greatestPower
, approxPower, reciprocalFor
) where
import Common.Transformation
import Common.Rewriting
import Common.View hiding (simplify)
import Control.Monad
import Domain.Math.Approximation (precision)
import qualified Domain.Math.Data.PrimeFactors as PF
import Domain.Math.Data.Relation
import Domain.Math.Expr
import Domain.Math.Numeric.Views
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)))
-- -- root a x = b => a = b^x
-- nthPower :: Rule (Equation Expr)
-- nthPower = makeSimpleRule (powereq, "nth-power") $ \(lhs :==: rhs) -> do
-- guard $ hasSomeVar lhs
-- (a, x) <- match rootView lhs
-- return $ a :==: rhs .^. 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 .~=.) . Number . precision n
f (d :==: Var x) =
match doubleView d >>= Just . (.~=. Var x) . Number . precision n
f _ = Nothing
-- -- a*x + c = b*y + d => a*x - b*y = d - c (move vars to the left, cons to the right)
-- varLeftConRight :: Rule (Equation Expr)
-- varLeftConRight = makeSimpleRule (powereq, "var-left-con-right") $
-- \(lhs :==: rhs) -> do
-- (xs, cs) <- fmap (partition hasSomeVar) (match sumView lhs)
-- (ys, ds) <- fmap (partition hasSomeVar) (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)
-- 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
-- this reciprocal rule is more strict, it demands a same base on the lhs
-- of the equation. Perhaps do this via the enviroment?
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