module Numeric.Domain.Internal where
import Data.Maybe(fromJust)
import Numeric.Additive.Group
import Numeric.Algebra.Class
import Numeric.Algebra.Commutative
import Numeric.Algebra.Division
import Numeric.Natural (Natural)
import Numeric.Semiring.ZeroProduct
import Numeric.Algebra.Unital.UnitNormalForm
import Numeric.Ring.Class
import Numeric.Decidable.Zero
import Numeric.Decidable.Units
import Prelude (Integer, Maybe (..), Bool(..),
otherwise, fst, snd, ($), (.))
import qualified Prelude as P
infixl 7 `quot`, `rem`
infix 7 `divide`, `divides`, `maybeQuot`
class (ZeroProductSemiring d, Ring d) => Domain d
instance (ZeroProductSemiring d, Ring d) => Domain d
class (Domain d, Commutative d) => IntegralDomain d where
divides :: d -> d -> Bool
default divides :: (Euclidean d) => d -> d -> Bool
m `divides` n
| isZero m = False
| otherwise = isZero (n `rem` m)
maybeQuot :: d -> d -> Maybe d
default maybeQuot :: (Euclidean d) => d -> d -> Maybe d
m `maybeQuot` n
| isZero n = Nothing
| otherwise = let (q,r) = m `divide` n in
if isZero r then Just q else Nothing
instance IntegralDomain Integer
class (IntegralDomain d, UnitNormalForm d, DecidableZero d) => GCDDomain d where
gcd :: d -> d -> d
default gcd :: (PID d) => d -> d -> d
gcd a b = let (r,_,_) = egcd a b in r
reduceFraction :: d -> d -> (d,d)
reduceFraction a b =
let c = gcd a b in
(fromJust (a `maybeQuot` c), fromJust (b `maybeQuot` c))
lcm :: d -> d -> d
lcm p q = fromJust $ (p * q) `maybeQuot` (gcd p q)
instance GCDDomain Integer
class (GCDDomain d) => UFD d
instance UFD Integer
class (UFD d) => PID d where
egcd :: d -> d -> (d,d,d)
default egcd :: (Euclidean d) => d -> d -> (d,d,d)
egcd a b = P.head (euclid a b)
instance PID Integer
class (PID d) => Euclidean d where
degree :: d -> Maybe Natural
default degree :: (Division d) => d -> Maybe Natural
degree a | isZero a = Nothing
| otherwise = Just zero
divide :: d
-> d
-> (d,d)
default divide :: (Division d) => d -> d -> (d,d)
divide a b = let q = a/b in (q,P.seq q zero)
quot :: d -> d -> d
quot a b = fst $ a `divide` b
rem :: d -> d -> d
rem a b = snd $ a `divide` b
instance Euclidean Integer where
degree = Just . P.fromInteger . P.abs
divide = P.divMod
euclid :: (Euclidean d) => d -> d -> [(d,d,d)]
euclid f g =
let (ug, g') = splitUnit g
Just t' = recipUnit ug
(uf, f') = splitUnit f
Just s = recipUnit uf
in step [(g', zero, t'), (f', s, zero)]
where
step acc@((r',s',t'):(r,s,t):_)
| isZero r' = P.tail acc
| otherwise =
let q = r `quot` r'
(ur, r'') = splitUnit $ r q * r'
Just u = recipUnit ur
s'' = (s q * s') * u
t'' = (t q * t') * u
in step ((r'', s'', t'') : acc)
step _ = P.error "cannot happen!"