packages feed

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)