{-# LANGUAGE ViewPatterns #-} -- | Chinese Remainder for Rational numbers. -- -- Since 0.4.0.0 module Algebra.Algorithms.ChineseRemainder ( recoverRat , rationalChineseRemainder ) where import Algebra.Instances () import AlgebraicPrelude import Data.List (findIndices) import Numeric.Domain.Euclidean (euclid) import Numeric.Domain.Euclidean (chineseRemainder) import qualified Prelude as P -- | Recovers rational number from Z/pZ. recoverRat :: Integer -- ^ Bound for numerator -> Integer -- ^ modulus -> Integer -- ^ integer corresponds to the rational number. -> Maybe (Fraction Integer) -- ^ recovered rational number recoverRat (abs -> k) m g | g == 0 = Just 0 | otherwise = let ps = euclid m g ixs = findIndices (\(rj, _, _) -> P.abs rj < k) ps in if null ixs then Nothing else let j = last ixs (r, _, t) = ps !! j (r0,_ , t0) = ps !! (j + 1) q | j == 0 = 0 | otherwise = head $ filter (\v -> r0 - v*r < k && k <= r0 - (v-1)*r) [1..] (r', t') = (r0 - q * r, t0 - q * t) in if gcd r t == 1 then Just (r % t) else if gcd r' t' == 1 && abs t' <= m `quot` k then Just (r' % t') else Nothing -- | Chinese Remainder for raional numbers. rationalChineseRemainder :: Integer -> [(Integer, Integer)] -> Maybe (Fraction Integer) rationalChineseRemainder k mvs = let m = product $ map fst mvs g = chineseRemainder mvs in recoverRat k m g