{- |
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 :: ScalarData -> ScalarData -> ScalarData
mathPlus (Div PolyExpr
m1 PolyExpr
n1) (Div PolyExpr
m2 PolyExpr
n2) = ScalarData -> ScalarData
mathNormalize' (ScalarData -> ScalarData) -> ScalarData -> ScalarData
forall a b. (a -> b) -> a -> b
$ PolyExpr -> PolyExpr -> ScalarData
Div (PolyExpr -> PolyExpr -> PolyExpr
mathPlusPoly (PolyExpr -> PolyExpr -> PolyExpr
mathMultPoly PolyExpr
m1 PolyExpr
n2) (PolyExpr -> PolyExpr -> PolyExpr
mathMultPoly PolyExpr
m2 PolyExpr
n1)) (PolyExpr -> PolyExpr -> PolyExpr
mathMultPoly PolyExpr
n1 PolyExpr
n2)

mathPlusPoly :: PolyExpr -> PolyExpr -> PolyExpr
mathPlusPoly :: PolyExpr -> PolyExpr -> PolyExpr
mathPlusPoly (Plus [TermExpr]
ts1) (Plus [TermExpr]
ts2) = [TermExpr] -> PolyExpr
Plus ([TermExpr]
ts1 [TermExpr] -> [TermExpr] -> [TermExpr]
forall a. [a] -> [a] -> [a]
++ [TermExpr]
ts2)

mathMinus :: ScalarData -> ScalarData -> ScalarData
mathMinus :: ScalarData -> ScalarData -> ScalarData
mathMinus ScalarData
s1 ScalarData
s2 = ScalarData -> ScalarData -> ScalarData
mathPlus ScalarData
s1 (ScalarData -> ScalarData
mathNegate ScalarData
s2)

mathMult :: ScalarData -> ScalarData -> ScalarData
mathMult :: ScalarData -> ScalarData -> ScalarData
mathMult (Div PolyExpr
m1 PolyExpr
n1) (Div PolyExpr
m2 PolyExpr
n2) = ScalarData -> ScalarData
mathNormalize' (ScalarData -> ScalarData) -> ScalarData -> ScalarData
forall a b. (a -> b) -> a -> b
$ PolyExpr -> PolyExpr -> ScalarData
Div (PolyExpr -> PolyExpr -> PolyExpr
mathMultPoly PolyExpr
m1 PolyExpr
m2) (PolyExpr -> PolyExpr -> PolyExpr
mathMultPoly PolyExpr
n1 PolyExpr
n2)

mathMultPoly :: PolyExpr -> PolyExpr -> PolyExpr
mathMultPoly :: PolyExpr -> PolyExpr -> PolyExpr
mathMultPoly (Plus []) (Plus [TermExpr]
_)    = [TermExpr] -> PolyExpr
Plus []
mathMultPoly (Plus [TermExpr]
_) (Plus [])    = [TermExpr] -> PolyExpr
Plus []
mathMultPoly (Plus [TermExpr]
ts1) (Plus [TermExpr]
ts2) = (PolyExpr -> PolyExpr -> PolyExpr)
-> PolyExpr -> [PolyExpr] -> PolyExpr
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl PolyExpr -> PolyExpr -> PolyExpr
mathPlusPoly ([TermExpr] -> PolyExpr
Plus []) ((TermExpr -> PolyExpr) -> [TermExpr] -> [PolyExpr]
forall a b. (a -> b) -> [a] -> [b]
map (\(Term Integer
a Monomial
xs) -> [TermExpr] -> PolyExpr
Plus ((TermExpr -> TermExpr) -> [TermExpr] -> [TermExpr]
forall a b. (a -> b) -> [a] -> [b]
map (\(Term Integer
b Monomial
ys) -> Integer -> Monomial -> TermExpr
Term (Integer
a Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
b) (Monomial
xs Monomial -> Monomial -> Monomial
forall a. [a] -> [a] -> [a]
++ Monomial
ys)) [TermExpr]
ts2)) [TermExpr]
ts1)

mathDiv :: ScalarData -> ScalarData -> ScalarData
mathDiv :: ScalarData -> ScalarData -> ScalarData
mathDiv ScalarData
s (Div PolyExpr
p1 PolyExpr
p2) = ScalarData -> ScalarData -> ScalarData
mathMult ScalarData
s (PolyExpr -> PolyExpr -> ScalarData
Div PolyExpr
p2 PolyExpr
p1)

mathPower :: ScalarData -> Integer -> ScalarData
mathPower :: ScalarData -> Integer -> ScalarData
mathPower ScalarData
_ Integer
0          = Integer -> Monomial -> ScalarData
SingleTerm Integer
1 []
mathPower ScalarData
s Integer
1          = ScalarData
s
mathPower ScalarData
s Integer
n | Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
2 = ScalarData -> ScalarData -> ScalarData
mathMult ScalarData
s (ScalarData -> Integer -> ScalarData
mathPower ScalarData
s (Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
1))

mathNumerator :: ScalarData -> ScalarData
mathNumerator :: ScalarData -> ScalarData
mathNumerator (Div PolyExpr
m PolyExpr
_) = PolyExpr -> PolyExpr -> ScalarData
Div PolyExpr
m ([TermExpr] -> PolyExpr
Plus [Integer -> Monomial -> TermExpr
Term Integer
1 []])

mathDenominator :: ScalarData -> ScalarData
mathDenominator :: ScalarData -> ScalarData
mathDenominator (Div PolyExpr
_ PolyExpr
n) = PolyExpr -> PolyExpr -> ScalarData
Div PolyExpr
n ([TermExpr] -> PolyExpr
Plus [Integer -> Monomial -> TermExpr
Term Integer
1 []])