module Numeric.Domain.Euclidean (Euclidean(..), euclid, prs, chineseRemainder) where
import Numeric.Additive.Group
import Numeric.Algebra.Class
import Numeric.Algebra.Unital
import Numeric.Decidable.Zero
import Numeric.Domain.Internal
import Prelude (otherwise)
import qualified Prelude as P
prs :: Euclidean r => r -> r -> [(r, r, r)]
prs f g = step [(g, zero, one), (f, one, zero)]
where
step acc@((r',s',t'):(r,s,t):_)
| isZero r' = P.tail acc
| otherwise =
let q = r `quot` r'
s'' = (s q * s')
t'' = (t q * t')
in step ((r q * r', s'', t'') : acc)
step _ = P.error "cannot happen!"
chineseRemainder :: Euclidean r
=> [(r, r)]
-> r
chineseRemainder mvs =
let (ms, _) = P.unzip mvs
m = product ms
in sum [((vi*s) `rem` mi)*n | (mi, vi) <- mvs
, let n = m `quot` mi
, let (_, s, _) : _ = euclid n mi
]