module Quantum.Synthesis.Diophantine (
diophantine,
diophantine_dyadic,
diophantine_associate,
find_factor,
relatively_prime_factors,
power_mod,
root_of_negative_one,
root_mod,
) where
import Quantum.Synthesis.StepComp
import Quantum.Synthesis.EuclideanDomain
import Quantum.Synthesis.Ring
import System.Random
import Control.Exception
diophantine :: (RandomGen g) => g -> ZRootTwo -> StepComp (Maybe ZOmega)
diophantine g xi
| xi == 0 = return (Just 0)
| xi < 0 = return Nothing
| adj2 xi < 0 = return Nothing
| otherwise = do
t <- diophantine_associate g xi
case t of
Nothing -> return Nothing
Just t -> do
let xi_associate = zroottwo_of_zomega (adj t * t)
let u = euclid_div xi xi_associate
case zroottwo_root u of
Nothing -> return Nothing
Just v -> return (Just (fromZRootTwo v * t))
diophantine_dyadic :: (RandomGen g) => g -> DRootTwo -> StepComp (Maybe DOmega)
diophantine_dyadic g xi = do
let k = denomexp xi
let (k',k'') = k `divMod` 2
let xi' = to_whole ((lambda * roottwo)^k'' * 2^k' * xi)
t' <- diophantine g xi'
case t' of
Nothing -> return Nothing
Just t' -> return (Just (u^k'' * roothalf^k' * from_whole t'))
where
u = roothalf * (omega i)
lambda = 1 + roottwo
diophantine_associate :: (RandomGen g) => g -> ZRootTwo -> StepComp (Maybe ZOmega)
diophantine_associate g xi
| xi == 0 = return (Just 0)
| otherwise = do
let d = euclid_gcd xi (adj2 xi)
let xi' = euclid_div xi d
res <- parallel_maybe (dioph_zroottwo_selfassociate g1 d) (dioph_zroottwo_assoc g2 xi')
case res of
Nothing -> return Nothing
Just (t1, t2) -> return (Just (t1*t2))
where
(g1, g2) = split g
find_factor :: (RandomGen g) => g -> Integer -> StepComp Integer
find_factor g n
| even n && n > 2 = return 2
| otherwise = tick >> aux 2 (f 2)
where
(a, g2) = randomR (1, n1) g
f x = (x^2 + a) `mod` n
aux x y
| d == 1 = tick >> aux (f x) (f (f y))
| d == n = find_factor g2 n
| otherwise = return d
where
d = gcd (xy) n
relatively_prime_factors :: (EuclideanDomain a) => a -> a -> (a, [(a, Integer)])
relatively_prime_factors a b = aux 1 [a,b] [] where
aux u [] fs = (u, fs)
aux u (h:t) fs
| is_unit h = aux (h*u) t fs
aux u (h:t) fs = aux (u'*u) (hs ++ t) fs' where
(u', hs, fs') = aux2 h fs
aux2 h [] = (1, [], [(h,1)])
aux2 h ((f,k) : fs)
| euclid_associates h f = (u', [], (f,k+1) : fs)
| is_unit d = (u, hs, (f,k) : fs')
| otherwise = (1, [h `euclid_div` d, d] ++ replicate (fromInteger k) (f `euclid_div` d) ++ replicate (fromInteger k) d, fs)
where
d = euclid_gcd h f
(u, hs, fs') = aux2 h fs
u' = h `euclid_div` f
power_mod :: Integer -> Integer -> Integer -> Integer
power_mod a k n
| k == 0 = 1
| k == 1 = a `mod` n
| even k = (b*b) `mod` n
| otherwise = (b*b*a) `mod` n
where
b = power_mod a (k `div` 2) n
root_of_negative_one :: (RandomGen g) => g -> Integer -> StepComp Integer
root_of_negative_one g n = do
tick
let (b, g') = randomR (1, n1) g
let h = power_mod b ((n1) `div` 4) n
let r = (h*h) `mod` n
if r == n1 then
return h
else
if r /= 1 then
diverge
else
root_of_negative_one g' n
root_mod :: (RandomGen g) => g -> Integer -> Integer -> StepComp Integer
root_mod g n a
| a `mod` n == 1
= root_of_negative_one g n
| otherwise = tick >> res
where
(b, g') = randomR (0, n1) g
(r,s) = (2*b `mod` n, b^2a `mod` n)
(c,d) = pow (1,0) ((n1) `div` 2)
res = case inv_mod n c of
Just c'
| (t1^2 a) `mod` n == 0 -> return t1
where
t = (1d) * c'
t1 = (t+b) `mod` n
_ -> root_mod g' n a
mul :: (Integer, Integer) -> (Integer, Integer) -> (Integer, Integer)
mul (a,b) (c,d) = (a'',b'') where
(x,y,z) = (a*c, a*d+b*c, b*d)
(a',b') = (y x*r,z x*s)
(a'',b'') = (a' `mod` n, b' `mod` n)
pow :: (Integer, Integer) -> Integer -> (Integer, Integer)
pow x m
| m <= 0 = (0,1)
| odd m = x `mul` (x `pow` (m1))
| otherwise = y `mul` y where y = x `pow` (m `div` 2)
dioph_int_assoc_prime :: (RandomGen g) => g -> Integer -> StepComp (Maybe ZOmega)
dioph_int_assoc_prime g n
| n < 0 = dioph_int_assoc_prime g (n)
| n == 0 = return (Just 0)
| n == 2 = return (Just roottwo)
| n_mod_4 == 1 = do
h <- root_of_negative_one g n
let t = euclid_gcd (fromInteger h+i) (fromInteger n) :: ZOmega
assert (adj t * t == fromInteger n) $ return (Just t)
| n_mod_8 == 3 = do
h <- root_mod g n (2)
let t = euclid_gcd (fromInteger h+i*roottwo) (fromInteger n) :: ZOmega
assert (adj t * t == fromInteger n) $ return (Just t)
| n_mod_8 == 7 = do
h <- root_mod g n 2
return Nothing
| otherwise = error "dioph_int_assoc_prime"
where
n_mod_4 = n `mod` 4
n_mod_8 = n `mod` 8
dioph_int_assoc :: (RandomGen g) => g -> Integer -> StepComp (Maybe ZOmega)
dioph_int_assoc g n
| n < 0 = dioph_int_assoc g (n)
| n == 0 = return (Just 0)
| n == 1 = return (Just 1)
| otherwise = interleave prime_solver factor_solver where
interleave p f = do
p <- subtask 4 p
case p of
Done res -> return res
_ -> do
f <- subtask 1000 f
case f of
Done (a, k) -> do
let b = n `div` a
let (u, facs) = relatively_prime_factors a b
forward (k `div` 2) $ dioph_int_assoc_powers g3 facs
_ -> interleave p f
(g1, g') = split g
(g2, g3) = split g'
prime_solver = dioph_int_assoc_prime g1 n
factor_solver = with_counter $ speedup 30 $ find_factor g2 n
dioph_int_assoc_powers :: (RandomGen g) => g -> [(Integer, Integer)] -> StepComp (Maybe ZOmega)
dioph_int_assoc_powers g facs = do
res <- parallel_list_maybe [dioph_int_assoc_power g (n,k) | (n,k) <- facs]
case res of
Nothing -> return Nothing
Just sols -> return (Just (product sols))
dioph_int_assoc_power :: (RandomGen g) => g -> (Integer, Integer) -> StepComp (Maybe ZOmega)
dioph_int_assoc_power g (n,k)
| even k = return (Just (fromInteger (n^(k `div` 2))))
| otherwise = do
t <- dioph_int_assoc g n
case t of
Nothing -> return Nothing
Just t -> return (Just (t^k))
dioph_zroottwo_selfassociate :: (RandomGen g) => g -> ZRootTwo -> StepComp (Maybe ZOmega)
dioph_zroottwo_selfassociate g xi
| xi == 0 = return (Just 0)
| otherwise = do
res <- dioph_int_assoc g n
case res of
Nothing -> return Nothing
Just t -> if euclid_divides roottwo r then
return (Just ((1+omega) * t))
else
return (Just t)
where
RootTwo a b = xi
n = gcd a b
r = euclid_div xi (fromInteger n)
dioph_zroottwo_assoc_prime :: (RandomGen g) => g -> ZRootTwo -> StepComp (Maybe ZOmega)
dioph_zroottwo_assoc_prime g xi
| xi == 0 = return (Just 0)
| n_mod_8 == 1 = do
h <- root_of_negative_one g n
let t = euclid_gcd (fromInteger h+i) (fromZRootTwo xi) :: ZOmega
assert ((adj t * t) `euclid_associates` fromZRootTwo xi) $ return (Just t)
| n_mod_8 == 7 = return Nothing
| otherwise = diverge
where
n_mod_8 = n `mod` 8
n = abs (norm xi)
dioph_zroottwo_assoc :: (RandomGen g) => g -> ZRootTwo -> StepComp (Maybe ZOmega)
dioph_zroottwo_assoc g xi
| xi == 0 = return (Just 0)
| otherwise = interleave prime_solver factor_solver where
interleave p f = do
p <- subtask 4 p
case p of
Done res -> return res
_ -> do
f <- subtask 1000 f
case f of
Done (a, k) -> do
let alpha = euclid_gcd xi (fromInteger a)
let beta = xi `euclid_div` alpha
let (u, facs) = relatively_prime_factors alpha beta
forward (k `div` 2) $ dioph_zroottwo_assoc_powers g3 facs
_ -> interleave p f
(g1, g') = split g
(g2, g3) = split g'
prime_solver = dioph_zroottwo_assoc_prime g1 xi
factor_solver = with_counter $ speedup 30 $ find_factor g2 n
n = abs (norm xi)
dioph_zroottwo_assoc_powers :: (RandomGen g) => g -> [(ZRootTwo, Integer)] -> StepComp (Maybe ZOmega)
dioph_zroottwo_assoc_powers g facs = do
res <- parallel_list_maybe [dioph_zroottwo_assoc_power g (q,k) | (q,k) <- facs]
case res of
Nothing -> return Nothing
Just sols -> return (Just (product sols))
dioph_zroottwo_assoc_power :: (RandomGen g) => g -> (ZRootTwo, Integer) -> StepComp (Maybe ZOmega)
dioph_zroottwo_assoc_power g (xi,k)
| even k = return (Just (fromZRootTwo (xi^(k `div` 2))))
| otherwise = do
t <- dioph_zroottwo_assoc g xi
case t of
Nothing -> return Nothing
Just t -> return (Just (t^k))