module Math.NumberTheory.Canon (
makeCanon, makeC,
canonToGCR, cToGCR,
cMult, cDiv, cAdd, cSubtract, cExp,
cReciprocal,
cGCD, cLCM, cMod, cOdd, cTotient, cPhi,
cLog, cLogDouble,
cNegative, cPositive,
cIntegral, cRational, cIrrational,
cSimplify, cSimplified,
cDepth,
cSplit, cNumerator, cDenominator,
cCanonical, cBare, cBareStatus, cValueType,
cIsPrimeTower, cPrimeTowerLevel,
cTetration, cPentation, cHexation, cHyperOp,
(>^), (<^), (%), (<^>), (<<^>>), (<<<^>>>)
)
where
import Math.NumberTheory.Primes.Testing (isPrime)
import Data.List (intersperse)
import GHC.Real (Ratio(..))
import Math.NumberTheory.Canon.Internals
import Math.NumberTheory.Canon.Additive
import Math.NumberTheory.Canon.AurifCyclo (CycloMap, crCycloInitMap)
import Math.NumberTheory.Canon.Simple (CanonConv(..))
data CanonValueType = IntegralC | NonIntRationalC | IrrationalC deriving (Eq, Ord, Show)
type GCR_ = [GCRE_]
type GCRE_ = (Integer, Canon)
data Canon = Bare Integer BareStatus | Canonical GCR_ CanonValueType
data BareStatus = Simplified | NotSimplified deriving (Eq, Ord, Show)
makeCanon, makeC, makeCanonFull, makeDefCanonForExpnt :: Integer -> Canon
makeCanon n = makeCanonI n False
makeC = makeCanon
makeCanonFull n = makeCanonI n True
makeCanonI :: Integer -> Bool -> Canon
makeCanonI n b = crToC (crFromI n) b
cCutoff :: Integer
cCutoff = 1000000
makeDefCanonForExpnt e | e > cCutoff = Bare e (getBareStatus e)
| otherwise = makeCanonFull e
crToC :: CR_ -> Bool -> Canon
crToC POne _ = Bare 1 Simplified
crToC c b | crSimplified c = Bare (fst $ head c) Simplified
| otherwise = Canonical g (gcrCVT g)
where g = map (\(p,e) -> (p, convPred e)) c
convPred e | b = makeCanonFull e
| otherwise = makeDefCanonForExpnt e
instance Eq Canon where
x == y = cEq x y
instance Show Canon where
show (Bare n NotSimplified) = "(" ++ (show n) ++ ")"
show (Bare n Simplified) = show n
show c | denom == c1 = s numer False
| otherwise = s numer True ++ " / " ++ s denom True
where (numer, denom) = cSplit c
s (Bare n f) _ = show $ Bare n f
s v w | w = "(" ++ catList ++ ")"
| otherwise = catList
where catList = concat $ intersperse " * " $ map sE $ cToGCR v
sE (p, e) | ptLevel > 2 = sp ++ " <^> " ++ s (makeCanonFull $ ptLevel) True
| otherwise = case e of
Bare 1 _ -> sp
Bare _ _ -> sp ++ "^" ++ se
_ -> sp ++ " ^ (" ++ se ++ ")"
where ptLevel = cPrimeTowerLevelI e p 1
sp = show p
se = show e
instance Enum Canon where
toEnum n = makeCanon $ fromIntegral n
fromEnum c = fromIntegral $ cToI c
instance Ord Canon where
compare x y = cCmp x y
instance Real Canon where
toRational c | cIrrational c = toRational $ cToD c
| otherwise = (cToI $ cNumerator c) :% (cToI $ cDenominator c)
instance Integral Canon where
toInteger c | cIntegral c = cToI c
| otherwise = floor $ cToD c
quotRem n m = fst $ cQuotRem n m crCycloInitMap
mod n m = cMod n m
instance Fractional Canon where
fromRational (n :% d) = makeCanon n / makeCanon d
(/) x y = fst $ cDiv x y crCycloInitMap
instance Num Canon where
fromInteger n = makeCanon n
x + y = fst $ cAdd x y crCycloInitMap
x y = fst $ cSubtract x y crCycloInitMap
x * y = fst $ cMult x y crCycloInitMap
negate x = cNegate x
abs x = cAbs x
signum x = cSignum x
cCanonical :: Canon -> Bool
cCanonical (Canonical _ _ ) = True
cCanonical _ = False
cBare :: Canon -> Bool
cBare (Bare _ _ ) = True
cBare _ = False
cBareStatus :: Canon -> BareStatus
cBareStatus (Bare _ b) = b
cBareStatus _ = error "cBareStatus: Can only checked for 'Bare' Canons"
cValueType :: Canon -> CanonValueType
cValueType (Bare _ _ ) = IntegralC
cValueType (Canonical _ v ) = v
cSplit :: Canon -> (Canon, Canon)
cSplit c = (cNumerator c, cDenominator c)
cEq:: Canon -> Canon -> Bool
cEq (Bare x _ ) (Bare y _ ) = x == y
cEq (Bare _ Simplified) (Canonical _ _ ) = False
cEq (Canonical _ _ ) (Bare _ Simplified) = False
cEq (Bare x NotSimplified) y | cValueType y /= IntegralC = False
| otherwise = cEq (makeCanon x) y
cEq x (Bare y NotSimplified) | cValueType x /= IntegralC = False
| otherwise = cEq x (makeCanon y)
cEq (Canonical x a ) (Canonical y b) = if a /= b then False else gcrEqCheck x y
cOdd :: Canon -> Bool
cOdd (Bare x _) = mod x 2 == 1
cOdd (Canonical c IntegralC ) = gcrOdd c
cOdd (Canonical _ _ ) = False
cGCD, cLCM :: Canon -> Canon -> Canon
cGCD x y = cLGApply gcrGCD x y
cLCM x y = cLGApply gcrLCM x y
cLog :: Canon -> Rational
cLog x = gcrLog $ cToGCR x
cLogDouble :: Canon -> Double
cLogDouble x = gcrLogDouble $ cToGCR x
cCmp :: Canon -> Canon -> Ordering
cCmp (Bare x _) (Bare y _) = compare x y
cCmp x y = gcrCmp (cToGCR x) (cToGCR y)
cQuotRem :: Canon -> Canon -> CycloMap -> ((Canon, Canon), CycloMap)
cQuotRem x y m | cIntegral x && cIntegral y = ((gcrToC q', md'), m'')
| otherwise = error "cQuotRem: Must both parameters must be integral"
where (q', md', m'') = case gcrDiv (cToGCR x) gy of
Left _ -> (q, md, m')
Right quotient -> (quotient, c0, m)
where gy = cToGCR y
md = cMod x y
q = gcrDivStrict (cToGCR d) gy
(d, m') = cSubtract x md m
cMod :: Canon -> Canon -> Canon
cMod c m = if (cIntegral c) && (cIntegral m) then (makeCanon $ cModI c (cToI m))
else error "cMod: Must both parameters must be integral"
cModI :: Canon -> Integer -> Integer
cModI _ 0 = error "cModI: Divide by zero error when computing n mod 0"
cModI _ 1 = 0
cModI _ (1) = 0
cModI Pc1 PIntPos = 1
cModI Pc0 _ = 0
cModI c m | cn && mn = 1 * cModI (cAbs c) (abs m)
| (cn && not mn) ||
(mn && not cn) = (signum m) * ( (abs m) (cModI' (cAbs c) (abs m)) )
| otherwise = cModI' c m
where cn = cNegative c
mn = m < 0
cModI' :: Canon -> Integer -> Integer
cModI' (Bare n _ ) m = mod n m
cModI' (Canonical c IntegralC ) m = mod (product $ map (\x -> pmI (fst x) (mmt $ snd x) m) c) m
where tm = totient m
mmt e = cModI e tm
cModI' (Canonical _ _ ) _ = error "cModI': Logic error: Canonical var has to be integral at this point"
cTotient, cPhi :: Canon -> CycloMap -> (Canon, CycloMap)
cTotient c m | (not $ cIntegral c) || cNegative c = error "Not defined for non-integral or negative numbers"
| c == c0 = (c0, m)
| otherwise = f (cToGCR c) c1 m
where f [] prd m' = (prd, m')
f ((p,e):gs) prd m' = f gs wp mw
where cp = makeC p
(pM1, mp) = cSubtract cp c1 m'
(eM1, me) = cSubtract e c1 mp
(pxeM1, mpm) = cExp cp eM1 False me
(nprd, mprd) = cMult pM1 pxeM1 mpm
(wp, mw) = cMult prd nprd mprd
cPhi = cTotient
infixr 9 <^>, <<^>>, <<<^>>>
(<^>), (<<^>>), (<<<^>>>) :: Canon -> Integer -> Canon
a <^> b = fst $ cTetration a b crCycloInitMap
a <<^>> b = fst $ cPentation a b crCycloInitMap
a <<<^>>> b = fst $ cHexation a b crCycloInitMap
cTetration, cPentation, cHexation :: Canon -> Integer -> CycloMap -> (Canon, CycloMap)
cTetration = cHyperOp 4
cPentation = cHyperOp 5
cHexation = cHyperOp 6
cHyperOp :: Integer -> Canon -> Integer -> CycloMap -> (Canon, CycloMap)
cHyperOp n a b m | b < 1 = error "Hyperoperations not defined when b < -1"
| n < 0 = error "Hyperoperations require the level n >= 0"
| a /= c0 && a /= c1 &&
b > 1 && (a /= c2 && b == 2) = c n cb m
| otherwise = (sp n a b, m)
where cb = makeCanon b
c 1 b' m' = cAdd a b' m'
c 2 b' m' = cMult a b' m'
c 3 b' m' = (a <^ b', m')
c _ Pc1 m' = (a, m')
c n' b' m' = c (n'1) r m''
where (r, m'') = c n' (b'1) m'
sp 0 Pc0 b' = makeCanon (b' + 1)
sp 1 Pc0 b' = makeCanon b'
sp 2 Pc0 _ = c0
sp 3 Pc0 b' = if b' == 0 then c1 else c0
sp _ Pc0 b' = if (mod b' 2) == 1 then c0 else c1
sp 0 _ 0 = c1
sp 1 a' 0 = a'
sp 2 _ 0 = c0
sp _ _ 0 = c1
sp 0 _ (1) = c0
sp 1 a' (1) = a' 1
sp 2 a' (1) = cNegate a'
sp 3 a' (1) = cReciprocal a'
sp _ _ (1) = c0
sp h Pc2 2 | h == 0 = makeCanon 3
| otherwise = makeCanon 4
sp _ Pc1 _ = c1
sp _ a' 1 = a'
sp _ _ _ = error "Can't compute this hyperoperation. b must be >= -1"
infixl 7 %
(%) :: (Integral a) => a -> a -> a
n % m = mod n m
infixr 9 <^
class CanonExpnt a b c | a b -> c where
(<^) :: a -> b -> c
instance CanonExpnt Canon Canon Canon where
p <^ e = fst $ cExp p e True crCycloInitMap
instance CanonExpnt Integer Integer Canon where
p <^ e = fst $ cExp (makeCanon p) (makeDefCanonForExpnt e) True crCycloInitMap
instance CanonExpnt Canon Integer Canon where
p <^ e = fst $ cExp p (makeDefCanonForExpnt e) True crCycloInitMap
instance CanonExpnt Integer Canon Canon where
p <^ e = fst $ cExp (makeCanon p) e True crCycloInitMap
infixr 9 >^
class CanonRoot a b c | a b -> c where
(>^) :: a -> b -> c
instance CanonRoot Canon Canon Canon where
r >^ n = cRoot n r
instance CanonRoot Integer Integer Canon where
r >^ n = cRoot (makeCanon n) (makeCanon r)
instance CanonRoot Integer Canon Canon where
r >^ n = cRoot n (makeCanon r)
instance CanonRoot Canon Integer Canon where
r >^ n = cRoot (makeCanon n) r
crSimplified :: CR_ -> Bool
crSimplified POne = True
crSimplified PZero = True
crSimplified PN1 = True
crSimplified c = crPrime c
cToCR :: Canon -> CR_
cToCR (Canonical c v) | v /= IrrationalC = gcrToCR c
| otherwise = error "cToCR: Cannot convert irrational canons to underlying data structure"
cToCR (Bare 1 _ ) = cr1
cToCR (Bare n NotSimplified) = crFromI n
cToCR (Bare n Simplified) = [(n,1)]
gcrToC :: GCR_ -> Canon
gcrToC g | gcrBare g = Bare (gcrToI g) Simplified
| otherwise = Canonical g (gcrCVT g)
gcrCVT :: GCR_ -> CanonValueType
gcrCVT POne = IntegralC
gcrCVT g = g' g IntegralC
where g' _ IrrationalC = IrrationalC
g' POne v = v
g' ((_,ce):cs) v = g' cs (dcv v ce)
g' _ _ = error "gcrCVT : Logic error. Patterns should have been exhaustive"
dcv IrrationalC _ = IrrationalC
dcv _ (Canonical _ IrrationalC) = IrrationalC
dcv _ (Canonical _ NonIntRationalC) = IrrationalC
dcv IntegralC (Bare n _ ) = if n < 0 then NonIntRationalC else IntegralC
dcv v (Bare _ _ ) = v
dcv v c = if cNegative c then NonIntRationalC else v
c1, c0, cN1, c2 :: Canon
c1 = makeCanon 1
c0 = makeCanon 0
cN1 = makeCanon (1)
c2 = makeCanon 2
cToI :: Canon -> Integer
cToI (Bare i _ ) = i
cToI (Canonical c v) | v == IntegralC = gcrToI c
| otherwise = error "Can't convert non-integral canon to an integer"
cToD :: Canon -> Double
cToD (Bare i _ ) = fromIntegral i
cToD (Canonical c _ ) = gcrToD c
cMult :: Canon -> Canon -> CycloMap -> (Canon, CycloMap)
cMult Pc0 _ m = (c0, m)
cMult _ Pc0 m = (c0, m)
cMult Pc1 y m = (y, m)
cMult x Pc1 m = (x, m)
cMult x y m = (gcrToC g, m')
where (g, m') = gcrMult (cToGCR x) (cToGCR y) m
cAdd, cSubtract :: Canon -> Canon -> CycloMap -> (Canon, CycloMap)
cAdd = cApplyAdtvOp True
cSubtract = cApplyAdtvOp False
cApplyAdtvOp :: Bool -> Canon -> Canon -> CycloMap -> (Canon, CycloMap)
cApplyAdtvOp _ x Pc0 m = (x, m)
cApplyAdtvOp True Pc0 y m = (y, m)
cApplyAdtvOp False Pc0 y m = (negate y, m)
cApplyAdtvOp b x y m = (gcd' * r, m')
where gcd' = cGCD x y
x' = x / gcd'
y' = y / gcd'
r = crToC c False
(c, m') = crApplyAdtvOptConv b (cToCR x') (cToCR y') m
cExp :: Canon -> Canon -> Bool -> CycloMap -> (Canon, CycloMap)
cExp c e b m | cNegative e && (not b)
= error "Per param flag, negative exponentiation is not allowed here."
| cIrrational c && cIrrational e
= error "cExp: Raising an irrational number to an irrational power is not currently supported."
| otherwise = cExp' c e m
where cExp' Pc0 e' m' | cPositive e' = (c0, m')
| otherwise = error "0^e where e <= 0 is either undefined or illegal"
cExp' Pc1 _ m' = (c1, m')
cExp' _ Pc0 m' = (c1, m')
cExp' c' e' m' = (gcrToC g, mg)
where (g, mg) = gE (cToGCR c') e' m'
gE :: GCR_ -> Canon -> CycloMap -> (GCR_, CycloMap)
gE g' e' m' | gcrNegative g'
= case cValueType e' of
IntegralC -> if cOdd e' then (gcreN1:absTail, m'')
else (absTail, m'')
NonIntRationalC -> if cOdd d then (gcreN1:absTail, m'')
else error "gE: Imaginary numbers not supported"
IrrationalC -> error "gE: Raising neg numbers to irr. powers not supported"
| otherwise
= f g' m'
where (absTail, m'') = gE (gcrAbs g') e' m'
(_, d) = cSplit e'
f [] mf = ([], mf)
f ((p,x):gs) mf = (fp, mf')
where (prd, mx) = cMult e' x mf
(t, mn) = f gs mx
(fp, mf') = gcrMult [(p, prd)] t mn
cNegative, cPositive :: Canon -> Bool
cNegative (Bare n _ ) = n < 0
cNegative (Canonical c _ ) = gcrNegative c
cPositive (Bare n _ ) = n > 0
cPositive (Canonical c _ ) = gcrPositive c
cNegate, cAbs, cSignum :: Canon -> Canon
cNegate (Bare 0 _) = c0
cNegate (Bare 1 _) = cN1
cNegate (Bare x Simplified) = Canonical (gcreN1 : [(x, c1)]) IntegralC
cNegate (Bare x NotSimplified) = Bare (1 * x) NotSimplified
cNegate (Canonical x v) = gcrNegateCanonical x v
cAbs x | cNegative x = cNegate x
| otherwise = x
cSignum (Bare 0 _) = c0
cSignum g | cNegative g = cN1
| otherwise = c1
cLGApply :: (GCR_ -> GCR_ -> GCR_) -> Canon -> Canon -> Canon
cLGApply _ Pc0 y = y
cLGApply _ x Pc0 = x
cLGApply f x y | cNegative x ||
cNegative y = gcrToC $ f (cToGCR $ cAbs x) (cToGCR $ cAbs y)
| otherwise = gcrToC $ f (cToGCR x) (cToGCR y)
cDiv :: Canon -> Canon -> CycloMap -> (Canon, CycloMap)
cDiv _ Pc0 _ = error "cDiv: Division by zero error"
cDiv x y m = cMult (cReciprocal y) x m
cReciprocal :: Canon -> Canon
cReciprocal x = fst $ cExp x cN1 True crCycloInitMap
cIntegral, cIrrational, cRational, cSimplified, cIsPrimeTower :: Canon -> Bool
cIntegral (Bare _ _ ) = True
cIntegral (Canonical _ v ) = v == IntegralC
cIrrational (Canonical _ IrrationalC ) = True
cIrrational _ = False
cRational c = not $ cIrrational c
cSimplified (Bare _ Simplified) = True
cSimplified (Bare _ NotSimplified) = True
cSimplified (Canonical c _ ) = gcrSimplified c
cIsPrimeTower c = cPrimeTowerLevel c > 0
cNumerator, cDenominator :: Canon -> Canon
cNumerator (Canonical c _ ) = gcrToC $ filter (\x -> cPositive $ snd x) c
cNumerator b = b
cDenominator (Canonical c _ ) = gcrToC $ map (\(p,e) -> (p, cN1 * e)) $ filter (\(_,e) -> cNegative e) c
cDenominator _ = c1
cDepth :: Canon-> Integer
cDepth (Bare _ _ ) = 1
cDepth (Canonical c _ ) = 1 + gcrDepth c
cSimplify :: Canon -> Canon
cSimplify (Bare n NotSimplified) = makeCanonFull n
cSimplify (Canonical c _ ) = gcrToC $ gcrSimplify c
cSimplify g = g
cRoot :: Canon -> Canon -> Canon
cRoot c r | cNegative r = error "r-th roots are not allowed when r <= 0"
| otherwise = gcrToC $ gcrRootI (cToGCR c) (cToGCR r)
cPrimeTowerLevel :: Canon -> Integer
cPrimeTowerLevel (Bare _ Simplified) = 1
cPrimeTowerLevel (Canonical g IntegralC) = case gcrPrimePower g of
False -> 0
True -> cPrimeTowerLevelI (snd $ head g) (fst $ head g) (1 :: Integer)
cPrimeTowerLevel _ = 0
cPrimeTowerLevelI :: Canon -> Integer -> Integer -> Integer
cPrimeTowerLevelI (Bare b _ ) n l | b == n = l + 1
| otherwise = 0
cPrimeTowerLevelI (Canonical g IntegralC) n l | gcrPrimePower g == False = 0
| n /= (fst $ head g) = 0
| otherwise = cPrimeTowerLevelI (snd $ head g) n (l+1)
cPrimeTowerLevelI _ _ _ = 0
canonToGCR, cToGCR :: Canon -> GCR_
canonToGCR (Canonical x _) = x
canonToGCR (Bare x NotSimplified) = canonToGCR $ makeCanon x
canonToGCR (Bare x Simplified) | x == 1 = gcr1
| otherwise = [(x, c1)]
cToGCR = canonToGCR
gcrNegateCanonical :: GCR_ -> CanonValueType -> Canon
gcrNegateCanonical g v | gcrNegative g = case gcrPrime (tail g) of
True -> Bare (fst $ head $ tail g) Simplified
False -> Canonical (tail g) v
| otherwise = Canonical (gcreN1 : g) v
gcrNegate :: GCR_ -> GCR_
gcrNegate Pg0 = gcr0
gcrNegate x | gcrNegative x = tail x
| otherwise = gcreN1 : x
gcrNegative :: GCR_ -> Bool
gcrNegative PgNeg = True
gcrNegative _ = False
gcrPositive :: GCR_ -> Bool
gcrPositive PNeg = False
gcrPositive PZero = False
gcrPositive _ = True
gcrMult :: GCR_ -> GCR_ -> CycloMap -> (GCR_, CycloMap)
gcrMult x POne m = (x, m)
gcrMult POne y m = (y, m)
gcrMult _ Pg0 m = (gcr0, m)
gcrMult Pg0 _ m = (gcr0, m)
gcrMult x@(xh@(xp,xe):xs) y@(yh@(yp,ye):ys) m = case compare xp yp of
LT -> (xh:g, m')
where (g, m') = gcrMult xs y m
EQ -> if gcrNegative x || expSum == c0
then gcrMult xs ys m
else ((xp, expSum):gf, mf)
where (expSum, m') = cAdd xe ye m
(gf, mf) = gcrMult xs ys m'
GT -> (yh:g, m')
where (g, m') = gcrMult x ys m
gcrMult x y _ = error e
where e = "Non-exhaustive pattern error in gcrMult. Params: " ++ (show x) ++ "*" ++ (show y)
gcr1, gcr0 :: GCR_
gcr1 = []
gcr0 = [(0, c1)]
gcreN1 :: GCRE_
gcreN1 = (1, c1)
gcrToI :: GCR_ -> Integer
gcrToI g = product $ map f g
where f (p, e) | ce > 0 = p ^ ce
| otherwise = error negExpErr
where ce = cToI e
negExpErr = "gcrToI: Negative exponent found trying to convert " ++ (show g)
gcrToD :: GCR_ -> Double
gcrToD g = product $ map (\(p,e) -> (fromIntegral p) ** cToD e) g
gcrCmp :: GCR_ -> GCR_ -> Ordering
gcrCmp POne y = gcrCmpTo1 y True
gcrCmp x POne = gcrCmpTo1 x False
gcrCmp x y | x == y = EQ
| xN && yN = compare (gcrToC $ tail y) (gcrToC $ tail x)
| xN = LT
| yN = GT
| gcrIsZero x = LT
| gcrIsZero y = GT
| otherwise = case compare (gcrLogDouble x) (gcrLogDouble y) of
EQ -> compare (gcrLog'' x) (gcrLog'' y)
cmp -> cmp
where xN = gcrNegative x
yN = gcrNegative y
gcrLog'' g = sum $ map f g
f (p,e) = (toRational $ logDouble $ fromIntegral p) * (toRational e)
logDouble :: Double -> Double
logDouble n = log n
gcrCmpTo1 :: GCR_ -> Bool -> Ordering
gcrCmpTo1 PNeg b = if b then GT else LT
gcrCmpTo1 Pg0 b = if b then GT else LT
gcrCmpTo1 _ b = if b then LT else GT
gcrLog :: GCR_ -> Rational
gcrLog g = crLog $ gcrToCR g
gcrGCD, gcrLCM :: GCR_ -> GCR_ -> GCR_
gcrGCD POne _ = gcr1
gcrGCD _ POne = gcr1
gcrGCD x y = case compare xp yp of
LT -> gcrGCD xs y
EQ -> (xp, min xe ye) : gcrGCD xs ys
GT -> gcrGCD x ys
where ((xp,xe):xs) = x
((yp,ye):ys) = y
gcrLCM POne y = y
gcrLCM x POne = x
gcrLCM x y = case compare xp yp of
LT -> xh : gcrLCM xs y
EQ -> (xp, max xe ye) : gcrLCM xs ys
GT -> yh : gcrLCM x ys
where (xh@(xp,xe) : xs) = x
(yh@(yp,ye) : ys) = y
gcrLogDouble :: GCR_ -> Double
gcrLogDouble g = sum $ map (\(p,e) -> (log $ fromIntegral p) * (cToD e)) g
divisionError :: String
divisionError = "gcrDiv: As requested per param, the dividend must be a multiple of the divisor."
divByZeroError :: String
divByZeroError = "gcrDiv: Division by zero error!"
zeroDivZeroError :: String
zeroDivZeroError = "gcrDiv: Zero divided by zero is undefined!"
gcrDivStrict :: GCR_ -> GCR_ -> GCR_
gcrDivStrict x y = case (gcrDiv x y) of
Left errorMsg -> error errorMsg
Right results -> results
gcrDiv :: GCR_ -> GCR_ -> Either String GCR_
gcrDiv Pg0 Pg0 = Left zeroDivZeroError
gcrDiv Pg0 _ = Right gcr0
gcrDiv _ Pg0 = Left divByZeroError
gcrDiv n d = g' n d
where g' x POne = Right x
g' POne _ = Left divisionError
g' x y
| gcrNegative y = g' (gcrNegate x) (gcrAbs y)
| otherwise = case compare xp yp of
LT -> case (g' xs y) of
Left _ -> Left divisionError
Right res -> Right ((xp, xe) : res)
EQ | xe > ye -> case (g' xs ys) of
Left _ -> Left divisionError
Right res -> Right ((xp, xe ye) : res)
EQ | xe == ye -> gcrDiv xs ys
_ -> Left divisionError
where ((xp,xe):xs) = x
((yp,ye):ys) = y
gcrAbs :: GCR_ -> GCR_
gcrAbs x | gcrNegative x = tail x
| otherwise = x
gcrToCR :: GCR_ -> CR_
gcrToCR c = map (\(p,e) -> (p, cToI e)) c
gcrBare :: GCR_ -> Bool
gcrBare PBare = True
gcrBare POne = True
gcrBare _ = False
gcrPrime :: GCR_ -> Bool
gcrPrime PgPrime = True
gcrPrime _ = False
gcrPrimePower :: GCR_ -> Bool
gcrPrimePower PgPPower = True
gcrPrimePower _ = False
gcrIsZero :: GCR_ -> Bool
gcrIsZero Pg0 = True;
gcrIsZero _ = False
gcrOdd, gcrEven :: GCR_ -> Bool
gcrOdd Pg0 = False
gcrOdd POne = True
gcrOdd c | gcrNegative c = gcrOdd (gcrAbs c)
| otherwise = cp /= 2
where (cp,_):_ = c
gcrEven g = not (gcrOdd g)
gcrEqCheck :: GCR_ -> GCR_ -> Bool
gcrEqCheck POne POne = True
gcrEqCheck POne _ = False
gcrEqCheck _ POne = False
gcrEqCheck ((xp,xe):xs) ((yp,ye):ys) | xp /= yp || xe /= ye = False
| otherwise = gcrEqCheck xs ys
gcrEqCheck x y = error e
where e = "Non-exhaustive patterns in gcrEqCheck comparing " ++ (show x) ++ " to " ++ (show y)
gcrDepth :: GCR_ -> Integer
gcrDepth g = maximum $ map (\(_,e) -> cDepth e) g
gcrSimplified :: GCR_ -> Bool
gcrSimplified g = all (\(_,e) -> cSimplified e) g
gcrSimplify :: GCR_ -> GCR_
gcrSimplify g = map (\(p,e) -> (p, cSimplify e)) g
gcrRootI :: GCR_ -> GCR_ -> GCR_
gcrRootI POne _ = gcr1
gcrRootI c r | not $ gcrNegative c = case gcrDiv (cToGCR ce) r of
Left _ -> error e
Right quotient -> (cp, gcrToC quotient) : gcrRootI cs r
| gcrEven r = error "Imaginary numbers not allowed: Even root of negative number requested."
| otherwise = gcreN1 : gcrRootI (gcrAbs c) r
where ((cp,ce):cs) = c
e = "gcrRootI: All expnts must be multiples of " ++ (show r) ++ ". Not so with " ++ (show c)
getBareStatus :: Integer -> BareStatus
getBareStatus n | n < 1 = NotSimplified
| n <= 1 || isPrime n = Simplified
| otherwise = NotSimplified
instance CanonConv Canon where
toSC c = toSC $ cToCR c
toRC c = toRC $ cToCR c
pattern PBare :: forall t. [(t, Canon)]
pattern PBare <- [(_, Bare 1 _)]
pattern PgPPower :: forall t a. (Num a, Ord a) => [(a, t)]
pattern PgPPower <- [(compare 1 -> LT, _ )]
pattern PgPrime :: forall a. (Num a, Ord a) => [(a, Canon)]
pattern PgPrime <- [(compare 1 -> LT, Bare 1 _)]
pattern PgNeg :: forall a. (Num a, Eq a) => [(a, Canon)]
pattern PgNeg <- ((1, Bare 1 _):_)
pattern Pg0 :: forall a. (Num a, Eq a) => [(a, Canon)]
pattern Pg0 <- [(0, Bare 1 _)]
pattern Pc0 :: Canon
pattern Pc0 <- Bare 0 _
pattern Pc1 :: Canon
pattern Pc1 <- Bare 1 _
pattern Pc2 :: Canon
pattern Pc2 <- Bare 2 _