content: {- |
  Module      : Language.Egison.Math.Arith
  Licence     : MIT
  
  This module defines some basic arithmetic operations for Egison's computer
  algebra system.
  -}
  
  module Language.Egison.Math.Arith
    ( mathPlus
    , mathMinus
    , mathMult
    , mathDiv
    , mathPower
    , mathNumerator
    , mathDenominator
    ) where
  
  import           Language.Egison.Math.Expr
  import           Language.Egison.Math.Normalize
  
  mathPlus :: ScalarData -> ScalarData -> ScalarData
  mathPlus (Div m1 n1) (Div m2 n2) = mathNormalize' $ Div (mathPlusPoly (mathMultPoly m1 n2) (mathMultPoly m2 n1)) (mathMultPoly n1 n2)
  
  mathPlusPoly :: PolyExpr -> PolyExpr -> PolyExpr
  mathPlusPoly (Plus ts1) (Plus ts2) = Plus (ts1 ++ ts2)
  
  mathMinus :: ScalarData -> ScalarData -> ScalarData
  mathMinus s1 s2 = mathPlus s1 (mathNegate s2)
  
  mathMult :: ScalarData -> ScalarData -> ScalarData
  mathMult (Div m1 n1) (Div m2 n2) = mathNormalize' $ Div (mathMultPoly m1 m2) (mathMultPoly n1 n2)
  
  mathMultPoly :: PolyExpr -> PolyExpr -> PolyExpr
  mathMultPoly (Plus []) (Plus _)    = Plus []
  mathMultPoly (Plus _) (Plus [])    = Plus []
  mathMultPoly (Plus ts1) (Plus ts2) = foldl mathPlusPoly (Plus []) (map (\(Term a xs) -> Plus (map (\(Term b ys) -> Term (a * b) (xs ++ ys)) ts2)) ts1)
  
  mathDiv :: ScalarData -> ScalarData -> ScalarData
  mathDiv s (Div p1 p2) = mathMult s (Div p2 p1)
  
  mathPower :: ScalarData -> Integer -> ScalarData
  mathPower _ 0          = SingleTerm 1 []
  mathPower s 1          = s
  mathPower s n | n >= 2 = mathMult s (mathPower s (n - 1))
  
  mathNumerator :: ScalarData -> ScalarData
  mathNumerator (Div m _) = Div m (Plus [Term 1 []])
  
  mathDenominator :: ScalarData -> ScalarData
  mathDenominator (Div _ n) = Div n (Plus [Term 1 []])
  