module Number.ResidueClass.Check where
import qualified Number.ResidueClass as Res
import qualified Algebra.PrincipalIdealDomain as PID
import qualified Algebra.IntegralDomain as Integral
import qualified Algebra.Field as Field
import qualified Algebra.Ring as Ring
import qualified Algebra.Additive as Additive
import qualified Algebra.ZeroTestable as ZeroTestable
import Algebra.ZeroTestable(isZero)
import qualified Data.Function.HT as Func
import Data.Maybe.HT (toMaybe, )
import Text.Show.HT (showsInfixPrec, )
import Text.Read.HT (readsInfixPrec, )
import NumericPrelude.Base
import NumericPrelude.Numeric (Int, Integer, mod, (*), )
infix 7 /:, `Cons`
data T a
= Cons {modulus :: !a
,representative :: !a
}
factorPrec :: Int
factorPrec = read "7"
instance (Show a) => Show (T a) where
showsPrec prec (Cons m r) = showsInfixPrec "/:" factorPrec prec r m
instance (Read a, Integral.C a) => Read (T a) where
readsPrec prec = readsInfixPrec "/:" factorPrec prec (/:)
(/:) :: (Integral.C a) => a -> a -> T a
(/:) r m = Cons m (mod r m)
isCompatible :: (Eq a) => T a -> T a -> Bool
isCompatible x y = modulus x == modulus y
maybeCompatible :: (Eq a) => T a -> T a -> Maybe a
maybeCompatible x y =
let mx = modulus x
my = modulus y
in toMaybe (mx==my) mx
fromRepresentative :: (Integral.C a) => a -> a -> T a
fromRepresentative m x = Cons m (mod x m)
lift1 :: (Eq a) => (a -> a -> a) -> T a -> T a
lift1 f x =
let m = modulus x
in Cons m (f m (representative x))
lift2 :: (Eq a) => (a -> a -> a -> a) -> T a -> T a -> T a
lift2 f x y =
maybe
(errIncompat)
(\m -> Cons m (f (modulus x) (representative x) (representative y)))
(maybeCompatible x y)
errIncompat :: a
errIncompat = error "Residue class: Incompatible operands"
zero :: (Additive.C a) => a -> T a
zero m = Cons m Additive.zero
one :: (Ring.C a) => a -> T a
one m = Cons m Ring.one
fromInteger :: (Integral.C a) => a -> Integer -> T a
fromInteger m x = fromRepresentative m (Ring.fromInteger x)
instance (Eq a) => Eq (T a) where
(==) x y =
maybe errIncompat
(const (representative x == representative y))
(maybeCompatible x y)
instance (ZeroTestable.C a) => ZeroTestable.C (T a) where
isZero (Cons _ r) = isZero r
instance (Eq a, Integral.C a) => Additive.C (T a) where
zero = error "no generic zero in a residue class, use ResidueClass.zero"
(+) = lift2 Res.add
() = lift2 Res.sub
negate = lift1 Res.neg
instance (Eq a, Integral.C a) => Ring.C (T a) where
one = error "no generic one in a residue class, use ResidueClass.one"
(*) = lift2 Res.mul
fromInteger = error "no generic integer in a residue class, use ResidueClass.fromInteger"
x^n = Func.powerAssociative (*) (one (modulus x)) x n
instance (Eq a, PID.C a) => Field.C (T a) where
(/) = lift2 Res.divide
recip = lift1 (flip Res.divide Ring.one)
fromRational' = error "no conversion from rational to residue class"