{-# LANGUAGE RebindableSyntax #-}
module Algebra.PrincipalIdealDomain (
C,
extendedGCD,
gcd,
lcm,
coprime,
euclid,
extendedEuclid,
extendedGCDMulti,
diophantine,
diophantineMin,
diophantineMulti,
chineseRemainder,
chineseRemainderMulti,
propMaximalDivisor,
propGCDDiophantine,
propExtendedGCDMulti,
propDiophantine,
propDiophantineMin,
propDiophantineMulti,
propDiophantineMultiMin,
propChineseRemainder,
propDivisibleGCD,
propDivisibleLCM,
propGCDIdentity,
propGCDCommutative,
propGCDAssociative,
propGCDHomogeneous,
propGCD_LCM,
) where
import qualified Algebra.Units as Units
import qualified Algebra.IntegralDomain as Integral
import qualified Algebra.ZeroTestable as ZeroTestable
import qualified Algebra.Laws as Laws
import Algebra.Units (stdAssociate, stdUnitInv)
import Algebra.IntegralDomain (mod, divChecked, divMod, divides, divModZero)
import Algebra.Ring (one, (*), scalarProduct)
import Algebra.Additive (zero, (+), (-))
import Algebra.ZeroTestable (isZero)
import Data.Maybe.HT (toMaybe, )
import Control.Monad (foldM, liftM)
import Data.List (mapAccumL, mapAccumR, unfoldr)
import Data.Int (Int, Int8, Int16, Int32, Int64, )
import NumericPrelude.Base
import Prelude (Integer, )
import Test.QuickCheck ((==>), Property)
class (Units.C a, ZeroTestable.C a) => C a where
extendedGCD :: a -> a -> (a,(a,a))
extendedGCD = (a -> a -> (a, a)) -> a -> a -> (a, (a, a))
forall a. (C a, C a) => (a -> a -> (a, a)) -> a -> a -> (a, (a, a))
extendedEuclid a -> a -> (a, a)
forall a. C a => a -> a -> (a, a)
divMod
gcd :: a -> a -> a
gcd a
x a
y = (a, (a, a)) -> a
forall a b. (a, b) -> a
fst ((a, (a, a)) -> a) -> (a, (a, a)) -> a
forall a b. (a -> b) -> a -> b
$ a -> a -> (a, (a, a))
forall a. C a => a -> a -> (a, (a, a))
extendedGCD a
x a
y
lcm :: a -> a -> a
lcm a
x a
y =
if a -> Bool
forall a. C a => a -> Bool
isZero a
x
then a
x
else a -> a -> a
forall a. (C a, C a) => a -> a -> a
divChecked a
x (a -> a -> a
forall a. C a => a -> a -> a
gcd a
x a
y) a -> a -> a
forall a. C a => a -> a -> a
* a
y
coprime :: (C a) => a -> a -> Bool
coprime :: a -> a -> Bool
coprime a
x a
y =
a -> Bool
forall a. C a => a -> Bool
Units.isUnit (a -> a -> a
forall a. C a => a -> a -> a
gcd a
x a
y)
euclid :: (Units.C a, ZeroTestable.C a) =>
(a -> a -> a) -> a -> a -> a
euclid :: (a -> a -> a) -> a -> a -> a
euclid a -> a -> a
genMod =
let aux :: a -> a -> a
aux a
x a
y =
if a -> Bool
forall a. C a => a -> Bool
isZero a
y
then a -> a
forall a. C a => a -> a
stdAssociate a
x
else a -> a -> a
aux a
y (a
x a -> a -> a
`genMod` a
y)
in a -> a -> a
aux
extendedEuclid :: (Units.C a, ZeroTestable.C a) =>
(a -> a -> (a,a)) -> a -> a -> (a,(a,a))
extendedEuclid :: (a -> a -> (a, a)) -> a -> a -> (a, (a, a))
extendedEuclid a -> a -> (a, a)
genDivMod =
let aux :: a -> a -> (a, (a, a))
aux a
x a
y =
if a -> Bool
forall a. C a => a -> Bool
isZero a
y
then (a -> a
forall a. C a => a -> a
stdAssociate a
x, (a -> a
forall a. C a => a -> a
stdUnitInv a
x, a
forall a. C a => a
zero))
else
let (a
d,a
m) = a
x a -> a -> (a, a)
`genDivMod` a
y
(a
g,(a
a,a
b)) = a -> a -> (a, (a, a))
aux a
y a
m
in (a
g,(a
b,a
aa -> a -> a
forall a. C a => a -> a -> a
-a
ba -> a -> a
forall a. C a => a -> a -> a
*a
d))
in a -> a -> (a, (a, a))
aux
extendedGCDMulti :: C a => [a] -> (a,[a])
extendedGCDMulti :: [a] -> (a, [a])
extendedGCDMulti [a]
xs =
let (a
g,[(a, a)]
cs) = (a -> a -> (a, (a, a))) -> a -> [a] -> (a, [(a, a)])
forall (t :: * -> *) a b c.
Traversable t =>
(a -> b -> (a, c)) -> a -> t b -> (a, t c)
mapAccumL a -> a -> (a, (a, a))
forall a. C a => a -> a -> (a, (a, a))
extendedGCD a
forall a. C a => a
zero [a]
xs
in (a
g, (a, [a]) -> [a]
forall a b. (a, b) -> b
snd ((a, [a]) -> [a]) -> (a, [a]) -> [a]
forall a b. (a -> b) -> a -> b
$ (a -> (a, a) -> (a, a)) -> a -> [(a, a)] -> (a, [a])
forall (t :: * -> *) a b c.
Traversable t =>
(a -> b -> (a, c)) -> a -> t b -> (a, t c)
mapAccumR (\a
acc (a
c0,a
c1) -> (a
acca -> a -> a
forall a. C a => a -> a -> a
*a
c0,a
acca -> a -> a
forall a. C a => a -> a -> a
*a
c1)) a
forall a. C a => a
one [(a, a)]
cs)
diophantine :: C a => a -> a -> a -> Maybe (a,a)
diophantine :: a -> a -> a -> Maybe (a, a)
diophantine a
z a
x a
y =
((a, (a, a)) -> (a, a)) -> Maybe (a, (a, a)) -> Maybe (a, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, (a, a)) -> (a, a)
forall a b. (a, b) -> b
snd (Maybe (a, (a, a)) -> Maybe (a, a))
-> Maybe (a, (a, a)) -> Maybe (a, a)
forall a b. (a -> b) -> a -> b
$ a -> a -> a -> Maybe (a, (a, a))
forall a. C a => a -> a -> a -> Maybe (a, (a, a))
diophantineAux a
z a
x a
y
diophantineMin :: C a => a -> a -> a -> Maybe (a,a)
diophantineMin :: a -> a -> a -> Maybe (a, a)
diophantineMin a
z a
x a
y =
((a, (a, a)) -> (a, a)) -> Maybe (a, (a, a)) -> Maybe (a, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((a -> (a, a) -> (a, a)) -> (a, (a, a)) -> (a, a)
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((a, a) -> a -> (a, a) -> (a, a)
forall a. C a => (a, a) -> a -> (a, a) -> (a, a)
minimizeFirstOperand (a
x,a
y))) (Maybe (a, (a, a)) -> Maybe (a, a))
-> Maybe (a, (a, a)) -> Maybe (a, a)
forall a b. (a -> b) -> a -> b
$
a -> a -> a -> Maybe (a, (a, a))
forall a. C a => a -> a -> a -> Maybe (a, (a, a))
diophantineAux a
z a
x a
y
minimizeFirstOperand :: C a => (a,a) -> a -> (a,a) -> (a,a)
minimizeFirstOperand :: (a, a) -> a -> (a, a) -> (a, a)
minimizeFirstOperand (a
x,a
y) a
g (a
a,a
b) =
if a -> Bool
forall a. C a => a -> Bool
isZero a
g
then (a
forall a. C a => a
zero,a
forall a. C a => a
zero)
else
let xl :: a
xl = a -> a -> a
forall a. (C a, C a) => a -> a -> a
divChecked a
x a
g
yl :: a
yl = a -> a -> a
forall a. (C a, C a) => a -> a -> a
divChecked a
y a
g
(a
d,a
aRed) = a -> a -> (a, a)
forall a. (C a, C a) => a -> a -> (a, a)
divModZero a
a a
yl
in (a
aRed, a
b a -> a -> a
forall a. C a => a -> a -> a
+ a
da -> a -> a
forall a. C a => a -> a -> a
*a
xl)
diophantineAux :: C a => a -> a -> a -> Maybe (a, (a,a))
diophantineAux :: a -> a -> a -> Maybe (a, (a, a))
diophantineAux a
z a
x a
y =
let (a
g,(a
a,a
b)) = a -> a -> (a, (a, a))
forall a. C a => a -> a -> (a, (a, a))
extendedGCD a
x a
y
(a
q,a
r) = a -> a -> (a, a)
forall a. (C a, C a) => a -> a -> (a, a)
divModZero a
z a
g
in Bool -> (a, (a, a)) -> Maybe (a, (a, a))
forall a. Bool -> a -> Maybe a
toMaybe (a -> Bool
forall a. C a => a -> Bool
isZero a
r) (a
g, (a
qa -> a -> a
forall a. C a => a -> a -> a
*a
a, a
qa -> a -> a
forall a. C a => a -> a -> a
*a
b))
diophantineMulti :: C a => a -> [a] -> Maybe [a]
diophantineMulti :: a -> [a] -> Maybe [a]
diophantineMulti a
z [a]
xs =
let (a
g,[a]
as) = [a] -> (a, [a])
forall a. C a => [a] -> (a, [a])
extendedGCDMulti [a]
xs
(a
q,a
r) = a -> a -> (a, a)
forall a. (C a, C a) => a -> a -> (a, a)
divModZero a
z a
g
in Bool -> [a] -> Maybe [a]
forall a. Bool -> a -> Maybe a
toMaybe (a -> Bool
forall a. C a => a -> Bool
isZero a
r) ((a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (a
qa -> a -> a
forall a. C a => a -> a -> a
*) [a]
as)
diophantineMultiMin :: C a => a -> [a] -> Maybe [a]
diophantineMultiMin :: a -> [a] -> Maybe [a]
diophantineMultiMin a
z [a]
xs =
do [a]
as <- a -> [a] -> Maybe [a]
forall a. C a => a -> [a] -> Maybe [a]
diophantineMulti a
z [a]
xs
[a] -> Maybe [a]
forall (m :: * -> *) a. Monad m => a -> m a
return ([a] -> Maybe [a]) -> [a] -> Maybe [a]
forall a b. (a -> b) -> a -> b
$ ([(a, a)] -> Maybe (a, [(a, a)])) -> [(a, a)] -> [a]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr
(\[(a, a)]
as' -> case [(a, a)]
as' of
((a
x0,a
a0):(a
x1,a
a1):[(a, a)]
aRest) ->
let (a
b0,a
b1) = (a, a) -> a -> (a, a) -> (a, a)
forall a. C a => (a, a) -> a -> (a, a) -> (a, a)
minimizeFirstOperand (a
x0,a
x1) (a -> a -> a
forall a. C a => a -> a -> a
gcd a
x0 a
x1) (a
a0,a
a1)
in (a, [(a, a)]) -> Maybe (a, [(a, a)])
forall a. a -> Maybe a
Just (a
b0, (a
x1,a
b1)(a, a) -> [(a, a)] -> [(a, a)]
forall a. a -> [a] -> [a]
:[(a, a)]
aRest)
(a
_,a
a):[] -> (a, [(a, a)]) -> Maybe (a, [(a, a)])
forall a. a -> Maybe a
Just (a
a,[])
[] -> Maybe (a, [(a, a)])
forall a. Maybe a
Nothing) ([(a, a)] -> [a]) -> [(a, a)] -> [a]
forall a b. (a -> b) -> a -> b
$
[a] -> [a] -> [(a, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip [a]
xs [a]
as
chineseRemainder :: C a => (a,a) -> (a,a) -> Maybe (a,a)
chineseRemainder :: (a, a) -> (a, a) -> Maybe (a, a)
chineseRemainder (a
m0,a
a0) (a
m1,a
a1) =
((a, a) -> (a, a)) -> Maybe (a, a) -> Maybe (a, a)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (\(a
k,a
_) -> let m :: a
m = a -> a -> a
forall a. C a => a -> a -> a
lcm a
m0 a
m1 in (a
m, a -> a -> a
forall a. C a => a -> a -> a
mod (a
a0a -> a -> a
forall a. C a => a -> a -> a
-a
ka -> a -> a
forall a. C a => a -> a -> a
*a
m0) a
m)) (Maybe (a, a) -> Maybe (a, a)) -> Maybe (a, a) -> Maybe (a, a)
forall a b. (a -> b) -> a -> b
$
a -> a -> a -> Maybe (a, a)
forall a. C a => a -> a -> a -> Maybe (a, a)
diophantineMin (a
a0a -> a -> a
forall a. C a => a -> a -> a
-a
a1) a
m0 a
m1
chineseRemainderMulti :: C a => [(a,a)] -> Maybe (a,a)
chineseRemainderMulti :: [(a, a)] -> Maybe (a, a)
chineseRemainderMulti [(a, a)]
congs =
case [(a, a)]
congs of
[] -> Maybe (a, a)
forall a. Maybe a
Nothing
((a, a)
c:[(a, a)]
cs) -> ((a, a) -> (a, a) -> Maybe (a, a))
-> (a, a) -> [(a, a)] -> Maybe (a, a)
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM (a, a) -> (a, a) -> Maybe (a, a)
forall a. C a => (a, a) -> (a, a) -> Maybe (a, a)
chineseRemainder (a, a)
c [(a, a)]
cs
instance C Integer where
gcd :: Integer -> Integer -> Integer
gcd = (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer
forall a. (C a, C a) => (a -> a -> a) -> a -> a -> a
euclid Integer -> Integer -> Integer
forall a. C a => a -> a -> a
mod
instance C Int where
gcd :: Int -> Int -> Int
gcd = (Int -> Int -> Int) -> Int -> Int -> Int
forall a. (C a, C a) => (a -> a -> a) -> a -> a -> a
euclid Int -> Int -> Int
forall a. C a => a -> a -> a
mod
instance C Int8 where
gcd :: Int8 -> Int8 -> Int8
gcd = (Int8 -> Int8 -> Int8) -> Int8 -> Int8 -> Int8
forall a. (C a, C a) => (a -> a -> a) -> a -> a -> a
euclid Int8 -> Int8 -> Int8
forall a. C a => a -> a -> a
mod
instance C Int16 where
gcd :: Int16 -> Int16 -> Int16
gcd = (Int16 -> Int16 -> Int16) -> Int16 -> Int16 -> Int16
forall a. (C a, C a) => (a -> a -> a) -> a -> a -> a
euclid Int16 -> Int16 -> Int16
forall a. C a => a -> a -> a
mod
instance C Int32 where
gcd :: Int32 -> Int32 -> Int32
gcd = (Int32 -> Int32 -> Int32) -> Int32 -> Int32 -> Int32
forall a. (C a, C a) => (a -> a -> a) -> a -> a -> a
euclid Int32 -> Int32 -> Int32
forall a. C a => a -> a -> a
mod
instance C Int64 where
gcd :: Int64 -> Int64 -> Int64
gcd = (Int64 -> Int64 -> Int64) -> Int64 -> Int64 -> Int64
forall a. (C a, C a) => (a -> a -> a) -> a -> a -> a
euclid Int64 -> Int64 -> Int64
forall a. C a => a -> a -> a
mod
propGCDIdentity :: (Eq a, C a) => a -> Bool
propGCDAssociative :: (Eq a, C a) => a -> a -> a -> Bool
propGCDCommutative :: (Eq a, C a) => a -> a -> Bool
propGCDDiophantine :: (Eq a, C a) => a -> a -> Bool
propExtendedGCDMulti :: (Eq a, C a) => [a] -> Bool
propDiophantineGen :: (Eq a, C a) =>
(a -> a -> a -> Maybe (a,a)) -> a -> a -> a -> a -> Bool
propDiophantine :: (Eq a, C a) => a -> a -> a -> a -> Bool
propDiophantineMin :: (Eq a, C a) => a -> a -> a -> a -> Bool
propDiophantineMultiGen :: (Eq a, C a) =>
(a -> [a] -> Maybe [a]) -> [(a,a)] -> Bool
propDiophantineMulti :: (Eq a, C a) => [(a,a)] -> Bool
propDiophantineMultiMin :: (Eq a, C a) => [(a,a)] -> Bool
propDivisibleGCD :: C a => a -> a -> Bool
propDivisibleLCM :: C a => a -> a -> Bool
propGCD_LCM :: (Eq a, C a) => a -> a -> Bool
propGCDHomogeneous :: (Eq a, C a) => a -> a -> a -> Bool
propMaximalDivisor :: C a => a -> a -> a -> Property
propChineseRemainder :: (Eq a, C a) => a -> a -> [a] -> Property
propMaximalDivisor :: a -> a -> a -> Property
propMaximalDivisor a
x a
y a
z =
a -> a -> Bool
forall a. (C a, C a) => a -> a -> Bool
divides a
z a
x Bool -> Bool -> Bool
&& a -> a -> Bool
forall a. (C a, C a) => a -> a -> Bool
divides a
z a
y Bool -> Bool -> Property
forall prop. Testable prop => Bool -> prop -> Property
==> a -> a -> Bool
forall a. (C a, C a) => a -> a -> Bool
divides a
z (a -> a -> a
forall a. C a => a -> a -> a
gcd a
x a
y)
propGCDDiophantine :: a -> a -> Bool
propGCDDiophantine a
x a
y =
let (a
g,(a
a,a
b)) = a -> a -> (a, (a, a))
forall a. C a => a -> a -> (a, (a, a))
extendedGCD a
x a
y
in a
g a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a -> a -> a
forall a. C a => a -> a -> a
gcd a
x a
y Bool -> Bool -> Bool
&& a
g a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
aa -> a -> a
forall a. C a => a -> a -> a
*a
xa -> a -> a
forall a. C a => a -> a -> a
+a
ba -> a -> a
forall a. C a => a -> a -> a
*a
y
propExtendedGCDMulti :: [a] -> Bool
propExtendedGCDMulti [a]
xs =
let (a
g,[a]
as) = [a] -> (a, [a])
forall a. C a => [a] -> (a, [a])
extendedGCDMulti [a]
xs
in a
g a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== [a] -> [a] -> a
forall a. C a => [a] -> [a] -> a
scalarProduct [a]
as [a]
xs Bool -> Bool -> Bool
&&
(a -> Bool
forall a. C a => a -> Bool
isZero a
g Bool -> Bool -> Bool
|| (a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (a -> a -> Bool
forall a. (C a, C a) => a -> a -> Bool
divides a
g) [a]
xs)
propDiophantineGen :: (a -> a -> a -> Maybe (a, a)) -> a -> a -> a -> a -> Bool
propDiophantineGen a -> a -> a -> Maybe (a, a)
dio a
a a
b a
x a
y =
let z :: a
z = a
aa -> a -> a
forall a. C a => a -> a -> a
*a
xa -> a -> a
forall a. C a => a -> a -> a
+a
ba -> a -> a
forall a. C a => a -> a -> a
*a
y
in Bool -> ((a, a) -> Bool) -> Maybe (a, a) -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (\(a
a',a
b') -> a
z a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
a'a -> a -> a
forall a. C a => a -> a -> a
*a
xa -> a -> a
forall a. C a => a -> a -> a
+a
b'a -> a -> a
forall a. C a => a -> a -> a
*a
y) (a -> a -> a -> Maybe (a, a)
dio a
z a
x a
y)
propDiophantine :: a -> a -> a -> a -> Bool
propDiophantine = (a -> a -> a -> Maybe (a, a)) -> a -> a -> a -> a -> Bool
forall a.
(Eq a, C a) =>
(a -> a -> a -> Maybe (a, a)) -> a -> a -> a -> a -> Bool
propDiophantineGen a -> a -> a -> Maybe (a, a)
forall a. C a => a -> a -> a -> Maybe (a, a)
diophantine
propDiophantineMin :: a -> a -> a -> a -> Bool
propDiophantineMin = (a -> a -> a -> Maybe (a, a)) -> a -> a -> a -> a -> Bool
forall a.
(Eq a, C a) =>
(a -> a -> a -> Maybe (a, a)) -> a -> a -> a -> a -> Bool
propDiophantineGen a -> a -> a -> Maybe (a, a)
forall a. C a => a -> a -> a -> Maybe (a, a)
diophantineMin
propDiophantineMultiGen :: (a -> [a] -> Maybe [a]) -> [(a, a)] -> Bool
propDiophantineMultiGen a -> [a] -> Maybe [a]
dio [(a, a)]
axs =
let ([a]
as,[a]
xs) = [(a, a)] -> ([a], [a])
forall a b. [(a, b)] -> ([a], [b])
unzip [(a, a)]
axs
z :: a
z = [a] -> [a] -> a
forall a. C a => [a] -> [a] -> a
scalarProduct [a]
as [a]
xs
in Bool -> ([a] -> Bool) -> Maybe [a] -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (\[a]
as' -> a
z a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== [a] -> [a] -> a
forall a. C a => [a] -> [a] -> a
scalarProduct [a]
as' [a]
xs) (a -> [a] -> Maybe [a]
dio a
z [a]
xs)
propDiophantineMulti :: [(a, a)] -> Bool
propDiophantineMulti = (a -> [a] -> Maybe [a]) -> [(a, a)] -> Bool
forall a.
(Eq a, C a) =>
(a -> [a] -> Maybe [a]) -> [(a, a)] -> Bool
propDiophantineMultiGen a -> [a] -> Maybe [a]
forall a. C a => a -> [a] -> Maybe [a]
diophantineMulti
propDiophantineMultiMin :: [(a, a)] -> Bool
propDiophantineMultiMin = (a -> [a] -> Maybe [a]) -> [(a, a)] -> Bool
forall a.
(Eq a, C a) =>
(a -> [a] -> Maybe [a]) -> [(a, a)] -> Bool
propDiophantineMultiGen a -> [a] -> Maybe [a]
forall a. C a => a -> [a] -> Maybe [a]
diophantineMultiMin
propDivisibleGCD :: a -> a -> Bool
propDivisibleGCD a
x a
y = a -> a -> Bool
forall a. (C a, C a) => a -> a -> Bool
divides (a -> a -> a
forall a. C a => a -> a -> a
gcd a
x a
y) a
x
propDivisibleLCM :: a -> a -> Bool
propDivisibleLCM a
x a
y = a -> a -> Bool
forall a. (C a, C a) => a -> a -> Bool
divides a
x (a -> a -> a
forall a. C a => a -> a -> a
lcm a
x a
y)
propGCDIdentity :: a -> Bool
propGCDIdentity = (a -> a -> a) -> a -> a -> Bool
forall a. Eq a => (a -> a -> a) -> a -> a -> Bool
Laws.identity a -> a -> a
forall a. C a => a -> a -> a
gcd a
forall a. C a => a
zero (a -> Bool) -> (a -> a) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. C a => a -> a
stdAssociate
propGCDCommutative :: a -> a -> Bool
propGCDCommutative = (a -> a -> a) -> a -> a -> Bool
forall a b. Eq a => (b -> b -> a) -> b -> b -> Bool
Laws.commutative a -> a -> a
forall a. C a => a -> a -> a
gcd
propGCDAssociative :: a -> a -> a -> Bool
propGCDAssociative = (a -> a -> a) -> a -> a -> a -> Bool
forall a. Eq a => (a -> a -> a) -> a -> a -> a -> Bool
Laws.associative a -> a -> a
forall a. C a => a -> a -> a
gcd
propGCDHomogeneous :: a -> a -> a -> Bool
propGCDHomogeneous = (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
forall a b.
Eq a =>
(a -> b -> a) -> (a -> a -> a) -> b -> a -> a -> Bool
Laws.leftDistributive a -> a -> a
forall a. C a => a -> a -> a
(*) a -> a -> a
forall a. C a => a -> a -> a
gcd (a -> a -> a -> Bool) -> (a -> a) -> a -> a -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. C a => a -> a
stdAssociate
propGCD_LCM :: a -> a -> Bool
propGCD_LCM a
x a
y = a -> a -> a
forall a. C a => a -> a -> a
gcd a
x a
y a -> a -> a
forall a. C a => a -> a -> a
* a -> a -> a
forall a. C a => a -> a -> a
lcm a
x a
y a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x a -> a -> a
forall a. C a => a -> a -> a
* a
y
propChineseRemainder :: a -> a -> [a] -> Property
propChineseRemainder a
k a
x [a]
ms =
Bool -> Bool
not ([a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a]
ms) Bool -> Bool -> Bool
&& (a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Bool -> Bool
not (Bool -> Bool) -> (a -> Bool) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Bool
forall a. C a => a -> Bool
isZero) [a]
ms Bool -> Bool -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
let congs :: [(a, a)]
congs = [a] -> [a] -> [(a, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip [a]
ms ((a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (a -> a -> a
forall a. C a => a -> a -> a
mod a
x) [a]
ms)
in Bool -> ((a, a) -> Bool) -> Maybe (a, a) -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False
(\(a
mGlob,a
y) ->
let yk :: a
yk = a
ya -> a -> a
forall a. C a => a -> a -> a
+a
mGloba -> a -> a
forall a. C a => a -> a -> a
*a
k
in ((a, a) -> Bool) -> [(a, a)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\(a
m,a
a) -> a -> a -> a -> Bool
forall a. (C a, C a) => a -> a -> a -> Bool
Integral.sameResidueClass a
m a
a a
yk) [(a, a)]
congs)
([(a, a)] -> Maybe (a, a)
forall a. C a => [(a, a)] -> Maybe (a, a)
chineseRemainderMulti [(a, a)]
congs)