{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Algorithms/CL/RegulatorClassical.hs" #-}
module Quipper.Algorithms.CL.RegulatorClassical where
import Data.Maybe
import Quipper.Libraries.Arith
import Quipper.Libraries.FPReal
import Quipper.Algorithms.CL.Auxiliary
import Quipper.Algorithms.CL.Types
unit_ideal :: CLIntP -> Ideal
unit_ideal = forget_reduced . unit_idealRed
unit_idealRed :: CLIntP -> IdealRed
unit_idealRed bigD = assert (is_valid_bigD bigD) ("unit_idealRed: " ++ show bigD ++ " not valid discriminant")
$ IdealRed bigD 1 (tau bigD (fromIntegral bigD) 1)
c_of_ideal :: Ideal -> CLInt
c_of_ideal i@(Ideal bigD m l a b) =
if (num `mod` denom == 0) then num `div` denom
else error error_string
where num = abs ((fromIntegral bigD) - b*b)
denom = 4*a
error_string = "rho of ideal [" ++ show i ++ "] produces non-integer c"
gamma_of_ideal :: Ideal -> AlgNum
gamma_of_ideal (Ideal bigD m l a b) = AlgNum a' b' bigD
where
a' = (fromIntegral b / fromIntegral (2*a)) :: CLRational
b' = (fromIntegral 1 / fromIntegral (2*a)) :: CLRational
rho :: Ideal -> Ideal
rho ii@(Ideal bigD m l a b) = (Ideal bigD m'' l'' a' b')
where
m' = m * a
l' = l * a'
m'' = m' `div` (gcd m' l')
l'' = l' `div` (gcd m' l')
a' = c_of_ideal ii
b' = tau bigD (-b) a'
rho_inv :: Ideal -> Ideal
rho_inv (Ideal bigD m l a b) = (Ideal bigD m'' l'' a'' b'')
where
m' = m * a
l' = l * a''
m'' = m' `div` (gcd m' l')
l'' = l' `div` (gcd m' l')
b' = tau bigD (-b) a
a'' = ((fromIntegral bigD) - b'*b') `divchk` (4*a)
b'' = tau bigD b' a''
rho_red :: IdealRed -> IdealRed
rho_red = to_reduced . rho . forget_reduced
rho_inv_red :: IdealRed -> IdealRed
rho_inv_red = to_reduced . rho_inv . forget_reduced
rho_d :: IdDist -> IdDist
rho_d (ii, del) = (rho ii, del + del_change)
where
gamma = gamma_of_ideal ii
gamma_bar_by_gamma = (floating_of_AlgNum $ conjugate gamma) / (floating_of_AlgNum gamma)
del_change = (log $ abs gamma_bar_by_gamma) / 2
rho_inv_d :: IdDist -> IdDist
rho_inv_d (ii, del) = (ii', del - del_change)
where
ii' = rho_inv ii
gamma = gamma_of_ideal ii'
gamma_bar_by_gamma = (floating_of_AlgNum $ conjugate gamma) / (floating_of_AlgNum gamma)
del_change = (log $ abs gamma_bar_by_gamma) / 2
rho_num :: (Ideal,AlgNum) -> (Ideal,AlgNum)
rho_num (ii, gen) = (rho ii, gen / (gamma_of_ideal ii))
rho_red_num :: (IdealRed,AlgNum) -> (IdealRed,AlgNum)
rho_red_num (ii, gen) = (rho_red ii, gen / (gamma_of_ideal $ forget_reduced ii))
reduce :: Ideal -> IdealRed
reduce ii = to_reduced $ while (not . is_reduced) rho ii
bounded_reduce :: IdDist -> IdDist
bounded_reduce k@(ideal@(Ideal bigD m l a b),dist) =
fst $ bounded_while condition bound func (k,0)
where
bound = ceiling $ bound_log + 1
bound_log = (logBase 2 ((fromIntegral bound_a)
/ (sqrt $ fromIntegral $ bigD_of_Ideal $ ideal)))
bound_a = 2 ^ (fromJust (intm_length $ a))
condition (k,itr) = not $ is_reduced $ fst k
func (k,itr) = ((rho_d k),(itr+1))
bounded_step :: (IdDist -> Bool) -> (IdDist -> IdDist) -> IdDist -> IdDist
bounded_step condition step_function ideal =
bounded_while condition bound step_function ideal
where
bound = ceiling $ (3 * (log $ fromIntegral $ bigD_of_Ideal $ fst ideal)) / (2 * log 2)
bounded_step_delta :: (CLReal -> Bool) -> (IdDist -> IdDist) -> IdDist -> IdDist
bounded_step_delta condition step_function ideal =
bounded_step new_condition step_function ideal
where new_condition = (\k -> condition (delta k))
dot :: IdDist -> IdDist -> IdDist
dot i1@(Ideal bigD1 m1 l1 a1 b1, delta1) i2@(Ideal bigD2 m2 l2 a2 b2, delta2) =
assert_reduced (fst i1) $
assert_reduced (fst i2) $
(Ideal bigD1 m l a3 b3, del)
where
sqrtd :: CLReal
sqrtd = sqrt (fromIntegral bigD1)
(k', u', v') = extended_euclid a1 a2
(k, x, w ) = extended_euclid k' ((b1 + b2) `divchk` 2)
a3 = (a1 * a2) `divchk` (k * k)
t1 = x * u' * a1 * b2
t2 = x * v' * a2 * b1
t3 = w*(b1 * b2 + (fromIntegral bigD1)) `divchk` 2
t = (t1 + t2 + t3) `divchk` k
b3 = tau bigD1 t a3
m = k
l = a3
del = ((delta i1) + (delta i2))
dot' :: IdDist -> IdDist
dot' i1@(Ideal bigD1 m1 l1 a1 b1, delta1) =
assert_reduced (fst i1) $
(Ideal bigD1 m l a3 b3, del)
where
sqrtd :: CLReal
sqrtd = sqrt (fromIntegral bigD1)
(k, u, w) = extended_euclid (abs a1) (abs b1)
a3 = (a1 * a1) `divchk` (k * k)
t1 = u * a1 * b1
t3 = w*(b1 * b1 + (fromIntegral bigD1)) `divchk` 2
t = (t1 + t3) `divchk` k
b3 = tau bigD1 t a3
m = k
l = 1
del = ((delta i1) + (delta i1))
star :: IdDist -> IdDist -> IdDist
star i j =
if (delta k1 <= delta i_dot_j)
then bounded_step_delta (<= delta i_dot_j) rho_d k1
else rho_d $ bounded_step_delta (>= delta i_dot_j) rho_inv_d k1
where
i_dot_j = i `dot` j
k1 = bounded_reduce i_dot_j
compute_injl :: (Integral int) => CLInt -> int -> CLInt -> int -> CLReal
compute_injl i nn j ll =
(fromIntegral i)/(fromIntegral nn) + (fromIntegral j)/(fromIntegral ll)
fN :: (Integral int) => CLInt -> CLInt -> int -> int -> CLIntP -> (Ideal, CLInt)
fN i j nn ll bigD =
let ((ideal_J, _), diff) = fN_d i j nn ll bigD
in (ideal_J, diff)
fN_d :: (Integral int) => CLInt -> CLInt -> int -> int -> CLIntP -> (IdDist, CLInt)
fN_d i j nn ll bigD =
(j_star_19, floor $ (fromIntegral nn) * (toRational $ injl - (snd j_star_19)))
where
injl = compute_injl i nn j ll
j1 = rho_d $ rho_d $ (unit_ideal bigD, 0)
jks = takeWhile (\jk -> (delta jk) <= injl) $
bounded_iterate bound_jks
(\jk -> jk `star` jk) j1
where
max_i = 2^(fromJust (intm_length $ i))
bound_jks = ceiling $
(log $ fromIntegral max_i) /
((fromIntegral nn) * (delta j1))
j_star_14 = foldr1 applyJkIfConditionHolds jks
applyJkIfConditionHolds :: IdDist -> IdDist -> IdDist
applyJkIfConditionHolds jk jstar =
if (delta (jstar `star` jk) <= injl) then jstar `star` jk else jstar
j_star_17 = bounded_step_delta (< injl) (rho_d.rho_d) j_star_14
j_star_19 = if (delta (rho_inv_d j_star_17) >= injl)
then rho_inv_d j_star_17
else j_star_17
fJN :: IdDist -> CLInt -> CLInt -> CLInt -> CLInt -> CLIntP -> (Ideal, CLInt)
fJN ideal_J i j nn ll bigD =
let ((ideal_J', _), diff) = fJN_d ideal_J i j nn ll bigD
in (ideal_J', diff)
fJN_d :: IdDist -> CLInt -> CLInt -> CLInt -> CLInt -> CLIntP -> (IdDist, CLInt)
fJN_d ideal_J i j nn ll bigD =
(ideal_KFinal, floor $ (fromIntegral nn) * (injl - (delta ideal_KFinal)))
where
injl = compute_injl i nn j ll
ideal_I = fst (fN_d i j nn ll bigD)
ideal_K = bounded_reduce (ideal_I `dot` ideal_J)
ideal_KFinal =
if (delta ideal_K <= injl)
then bounded_step_delta (< injl) (rho_d) ideal_K
else rho_d $ bounded_step_delta (>= injl) (rho_inv_d) ideal_K
order :: (Eq a) => (a -> a) -> a -> Int
order = order_with_projection id
order_with_projection :: (Eq b) => (a -> b) -> (a -> a) -> a -> Int
order_with_projection p f x = 1 + (length $ takeWhile (\y -> p y /= p x) (tail $ iterate f x))
first_return_with_projection :: (Eq b) => (a -> b) -> (a -> a) -> a -> a
first_return_with_projection p f x = head $ dropWhile (\y -> p y /= p x) $ tail $ iterate f x
first_return_with_proj_bdd :: (Eq b) => Int -> (a -> b) -> (a -> a) -> a -> Maybe a
first_return_with_proj_bdd b p f x = listToMaybe $ dropWhile (\y -> p y /= p x) $ take b $ tail $ iterate f x
period :: (Eq a, Integral int) => (int -> a) -> int
period f = minimum [ n | n <- [1..], f n == f 0 ]
regulator :: CLIntP -> FPReal
regulator bigD = snd $ head $ dropWhile (\(ii,_) -> ii /= calO) $ tail $ iterate rho_d $ (calO,0)
where calO = unit_ideal bigD
fundamental_unit :: CLIntP -> AlgNum
fundamental_unit bigD = maximum [eps, -eps, 1/eps, -1/eps]
where eps = snd $ first_return_with_projection fst rho_num (calO,1)
calO = unit_ideal bigD
fundamental_solution :: CLIntP -> (Integer,Integer)
fundamental_solution d = head pell_solutions
where bigD = bigD_of_d d
eps0 = fundamental_unit bigD
pell_solutions =
[ (round x, round y) | n <- [1..],
let eps@(AlgNum a b _) = eps0^n,
a >= 0, b >= 0,
let x = a,
let y = if bigD == d then b else 2*b,
is_int x, is_int y,
eps * (conjugate eps) == 1]
regulator_fixed_prec :: Int -> CLIntP -> Maybe FPReal
regulator_fixed_prec b bigD = fmap snd (first_return_with_proj_bdd b' fst rho_d (calO,zero))
where calO = fix_sizes_Ideal $ unit_ideal bigD
n = n_of_bigD bigD
i = 1 + b + n
q = 2 + 2 * i
l = 4 + q + n
p = precision_for_fN bigD n l
zero = fprealx (-p) (intm (q - n + p) 0)
b' = ceiling $ 2 * sqrt(2) * (fromIntegral 2^b)