{-# Language UnboxedTuples #-}
module Advent.Chinese (Mod(..), toMod, chinese) where
import Control.Monad (foldM)
import GHC.Num.Integer (integerGcde)
data Mod = Mod { Mod -> Integer
residue, Mod -> Integer
modulus :: !Integer }
deriving (Mod -> Mod -> Bool
(Mod -> Mod -> Bool) -> (Mod -> Mod -> Bool) -> Eq Mod
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Mod -> Mod -> Bool
== :: Mod -> Mod -> Bool
$c/= :: Mod -> Mod -> Bool
/= :: Mod -> Mod -> Bool
Eq, ReadPrec [Mod]
ReadPrec Mod
Int -> ReadS Mod
ReadS [Mod]
(Int -> ReadS Mod)
-> ReadS [Mod] -> ReadPrec Mod -> ReadPrec [Mod] -> Read Mod
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS Mod
readsPrec :: Int -> ReadS Mod
$creadList :: ReadS [Mod]
readList :: ReadS [Mod]
$creadPrec :: ReadPrec Mod
readPrec :: ReadPrec Mod
$creadListPrec :: ReadPrec [Mod]
readListPrec :: ReadPrec [Mod]
Read, Int -> Mod -> ShowS
[Mod] -> ShowS
Mod -> String
(Int -> Mod -> ShowS)
-> (Mod -> String) -> ([Mod] -> ShowS) -> Show Mod
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Mod -> ShowS
showsPrec :: Int -> Mod -> ShowS
$cshow :: Mod -> String
show :: Mod -> String
$cshowList :: [Mod] -> ShowS
showList :: [Mod] -> ShowS
Show)
toMod ::
Integer ->
Integer ->
Mod
toMod :: Integer -> Integer -> Mod
toMod Integer
r Integer
m
| Integer
m Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
0 = Integer -> Integer -> Mod
Mod (Integer
r Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
m) Integer
m
| Bool
otherwise = String -> Mod
forall a. HasCallStack => String -> a
error (String
"toMod: invalid modulus " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
show Integer
m)
chinese' :: Mod -> Mod -> Maybe Mod
chinese' :: Mod -> Mod -> Maybe Mod
chinese' (Mod Integer
n1 Integer
m1) (Mod Integer
n2 Integer
m2)
| Integer
d Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1
= Mod -> Maybe Mod
forall a. a -> Maybe a
Just (Mod -> Maybe Mod) -> Mod -> Maybe Mod
forall a b. (a -> b) -> a -> b
$! Integer -> Integer -> Mod
toMod (Integer
m2 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
n1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
v Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
m1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
n2 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
u) (Integer
m1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
m2)
| (Integer
n1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
n2) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`rem` Integer
d Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0
= Mod -> Maybe Mod
forall a. a -> Maybe a
Just (Mod -> Maybe Mod) -> Mod -> Maybe Mod
forall a b. (a -> b) -> a -> b
$! Integer -> Integer -> Mod
toMod (Integer
m2 Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
d Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
n1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
v Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
m1 Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
d Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
n2 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
u) (Integer
m1 Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
d Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
m2)
| Bool
otherwise = Maybe Mod
forall a. Maybe a
Nothing
where
(Integer
d, Integer
u, Integer
v) = Integer -> Integer -> (Integer, Integer, Integer)
integerGcde Integer
m1 Integer
m2
chinese :: [Mod] -> Maybe Integer
chinese :: [Mod] -> Maybe Integer
chinese [] = Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
0
chinese (Mod
x:[Mod]
xs) = Mod -> Integer
residue (Mod -> Integer) -> Maybe Mod -> Maybe Integer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Mod -> Mod -> Maybe Mod) -> Mod -> [Mod] -> Maybe Mod
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM Mod -> Mod -> Maybe Mod
chinese' Mod
x [Mod]
xs