{-# LANGUAGE NoImplicitPrelude #-}
module Algebra.IntegralDomain (
C,
div, mod, divMod,
divModZero,
divides,
sameResidueClass,
divChecked, safeDiv,
even,
odd,
divUp,
roundDown,
roundUp,
decomposeVarPositional,
decomposeVarPositionalInf,
propInverse,
propMultipleDiv,
propMultipleMod,
propProjectAddition,
propProjectMultiplication,
propUniqueRepresentative,
propZeroRepresentative,
propSameResidueClass,
) where
import qualified Algebra.Ring as Ring
import qualified Algebra.ZeroTestable as ZeroTestable
import Algebra.Ring ((*), fromInteger, )
import Algebra.Additive (zero, (+), (-), negate, )
import Algebra.ZeroTestable (isZero, )
import Data.Bool.HT (implies, )
import Data.List (mapAccumL, )
import Test.QuickCheck ((==>), Property)
import Data.Int (Int, Int8, Int16, Int32, Int64, )
import Data.Word (Word, Word8, Word16, Word32, Word64, )
import NumericPrelude.Base
import Prelude (Integer, )
import qualified Prelude as P
infixl 7 `div`, `mod`
class (Ring.C a) => C a where
{-# MINIMAL divMod | (div, mod) #-}
div, mod :: a -> a -> a
divMod :: a -> a -> (a,a)
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div a b = fst (divMod a b)
mod a b = snd (divMod a b)
divMod a b = (div a b, mod a b)
{-# INLINE divides #-}
divides :: (C a, ZeroTestable.C a) => a -> a -> Bool
divides y x = isZero (mod x y)
{-# INLINE sameResidueClass #-}
sameResidueClass :: (C a, ZeroTestable.C a) => a -> a -> a -> Bool
sameResidueClass m x y = divides m (x-y)
decomposeVarPositional :: (C a, ZeroTestable.C a) => [a] -> a -> [a]
decomposeVarPositional bs x =
map fst $
takeWhile (not . isZero . snd) $
decomposeVarPositionalInfAux bs x
decomposeVarPositionalInf :: (C a) => [a] -> a -> [a]
decomposeVarPositionalInf bs =
map fst . decomposeVarPositionalInfAux bs
decomposeVarPositionalInfAux :: (C a) => [a] -> a -> [(a,a)]
decomposeVarPositionalInfAux bs x =
let (endN,digits) =
mapAccumL
(\n b -> let (q,r) = divMod n b in (q,(r,n)))
x bs
in digits ++ [(endN,endN)]
{-# INLINE divChecked #-}
divChecked, safeDiv :: (ZeroTestable.C a, C a) => a -> a -> a
divChecked a b =
let (q,r) = divMod a b
in if isZero r
then q
else error "safeDiv: indivisible term"
{-# DEPRECATED safeDiv "use divChecked instead" #-}
safeDiv = divChecked
{-# INLINE divModZero #-}
divModZero :: (C a, ZeroTestable.C a) => a -> a -> (a,a)
divModZero x y =
if isZero y
then (zero,x)
else divMod x y
{-# INLINE even #-}
{-# INLINE odd #-}
even, odd :: (C a, ZeroTestable.C a) => a -> Bool
even n = divides 2 n
odd = not . even
roundDown :: C a => a -> a -> a
roundDown n m = n - mod n m
roundUp :: C a => a -> a -> a
roundUp n m = n + mod (-n) m
divUp :: C a => a -> a -> a
divUp n m = - div (-n) m
instance C Integer where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Int where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Int8 where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Int16 where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Int32 where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Int64 where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Word where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Word8 where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Word16 where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Word32 where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
instance C Word64 where
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE divMod #-}
div = P.div
mod = P.mod
divMod = P.divMod
propInverse :: (Eq a, C a, ZeroTestable.C a) => a -> a -> Property
propMultipleDiv :: (Eq a, C a, ZeroTestable.C a) => a -> a -> Property
propMultipleMod :: (Eq a, C a, ZeroTestable.C a) => a -> a -> Property
propProjectAddition :: (Eq a, C a, ZeroTestable.C a) => a -> a -> a -> Property
propProjectMultiplication :: (Eq a, C a, ZeroTestable.C a) => a -> a -> a -> Property
propSameResidueClass :: (Eq a, C a, ZeroTestable.C a) => a -> a -> a -> Property
propUniqueRepresentative :: (Eq a, C a, ZeroTestable.C a) => a -> a -> a -> Property
propZeroRepresentative :: (Eq a, C a, ZeroTestable.C a) => a -> Property
propInverse m a =
not (isZero m) ==> (a `div` m) * m + (a `mod` m) == a
propMultipleDiv m a =
not (isZero m) ==> (a*m) `div` m == a
propMultipleMod m a =
not (isZero m) ==> (a*m) `mod` m == 0
propProjectAddition m a b =
not (isZero m) ==>
(a+b) `mod` m == ((a`mod`m)+(b`mod`m)) `mod` m
propProjectMultiplication m a b =
not (isZero m) ==>
(a*b) `mod` m == ((a`mod`m)*(b`mod`m)) `mod` m
propUniqueRepresentative m k a =
not (isZero m) ==>
(a+k*m) `mod` m == a `mod` m
propZeroRepresentative m =
not (isZero m) ==>
zero `mod` m == zero
propSameResidueClass m a b =
not (isZero m) ==>
a `mod` m == b `mod` m `implies` sameResidueClass m a b