{- |
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 []])
