{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Algorithms/CL/RegulatorQuantum.hs" #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Quipper.Algorithms.CL.RegulatorQuantum where
import Quipper
import Quipper.Internal
import Quipper.Libraries.Arith hiding (q_ext_euclid, q_add, q_mult, q_div_exact,
q_add_in_place, q_add_param_in_place, q_div,
q_mult_param, q_mod_unsigned, q_sub_in_place,
q_increment)
import qualified Quipper.Libraries.Arith as Arith
import Quipper.Libraries.FPReal
import Quipper.Algorithms.CL.Auxiliary
import Quipper.Algorithms.CL.Types
import Quipper.Algorithms.CL.RegulatorClassical
import Control.Monad (foldM)
q_normalize :: IdDistQ -> Circ (IdDistQ,IdDistQ)
q_normalize = box "q_normalize" $ \((Ideal bigD k l a b), dist) -> do
let k_bits = qulist_of_qdint_bh k
n = length k_bits
k' <- qinit (intm n 1)
(a,l') <- qc_copy_fun a
(a,a') <- qc_copy_fun a
(b,b') <- qc_copy_fun b
((k,l,a,dist), dist') <- with_computed_fun
(k,l,a,dist)
(\(k,l,a,dist) -> do
(k,k_clreal) <- q_fromQDInt k
(l,l_clreal) <- q_fromQDInt l
(a,a_clreal) <- q_fromQDInt a
(k_clreal,log_k) <- fprealq_log_with_shape dist k_clreal
(l_clreal,log_l) <- fprealq_log_with_shape dist l_clreal
(a_clreal,log_a) <- fprealq_log_with_shape dist a_clreal
(log_k, dist) <- fprealq_sub_in_place log_k dist
(log_l, dist) <- fprealq_add_in_place log_l dist
(log_a, dist) <- fprealq_sub_in_place log_a dist
return (((k,l,a),(k_clreal,l_clreal,a_clreal),(log_k,log_l,log_a)), dist))
(\(various, dist) -> do
(dist,dist') <- qc_copy_fun dist
return ((various,dist), dist'))
return ((Ideal bigD k l a b, dist), (Ideal bigD k' l' a' b', dist'))
q_rho_d :: IdDistQ -> Circ (IdDistQ,IdDistQ)
q_rho_d = box "rho" $ \iid@(Ideal bigD m l a b, del) -> do
rho_iid <- with_computed
(do
(_,_,b_sq) <- q_mult b b
b_sq' <- q_sub_param_in_place (fromIntegral bigD) b_sq
(_,c_num) <- q_abs b_sq'
(_,c_denom) <- q_mult_param 4 a
(_,_,c) <- q_div_exact c_num c_denom
let a' = c
(_,b_neg) <- q_negate b
(_,_,b') <- q_tau bigD b_neg a'
(_,_,m') <- q_mult m a
(_,_,l') <- q_mult l a'
(_,_,_,_,d) <- q_ext_euclid m' l'
(_,_,m'') <- q_div_exact m' d
(_,_,l'') <- q_div_exact l' d
let ii' = Ideal bigD a' b' m'' l''
(_,b_fp) <- fprealq_of_QDInt_with_shape del b
b_fp <- fprealq_add_param_in_place (negate $ sqrt $ fromIntegral bigD) b_fp
(_,_,b_fp_sq) <- q_mult b_fp b_fp
(_,del_change_1) <- fprealq_log_with_shape del b_fp_sq
(_,del_change_2) <- fprealq_log_with_shape del (fprealx 0 c_num)
del' <- qc_copy del
(_,del') <- fprealq_add_in_place del_change_1 del'
(_,del') <- fprealq_sub_in_place del_change_2 del'
return (ii', del'))
qc_copy
return (iid, rho_iid)
q_rho_inv_d :: IdDistQ -> Circ (IdDistQ, IdDistQ)
q_rho_inv_d = box "rho_inv" $ \iid@(Ideal bigD m l a b, del) -> do
rho_inv_iid <- with_computed
(do
(_, b_neg) <- q_negate b
(_, _, b') <- q_tau bigD b_neg a
(_, b'_sq) <- q_square b'
(_, a''_num) <- q_negate b'_sq
a''_num <- q_add_param_in_place (fromIntegral bigD) a''_num
(_, a''_denom) <- q_mult_param 4 a
(_, _, a'') <- q_div_exact a''_num a''_denom
(_, _, b'') <- q_tau bigD b' a''
(_, _, m') <- q_mult m a
(_, _, l') <- q_mult l a''
(_,_,_,_, d) <- q_ext_euclid m' l'
(_, _, m'') <- q_div_exact m' d
(_, _, l'') <- q_div_exact l' d
let ii' = Ideal bigD a'' b'' m'' l''
(_,b_fp) <- fprealq_of_QDInt_with_shape del b''
b_fp <- fprealq_add_param_in_place (negate $ sqrt $ fromIntegral bigD) b_fp
(_,_,b_fp_sq) <- q_mult b_fp b_fp
(_,del_change_1) <- fprealq_log_with_shape del b_fp_sq
(_,_,b_sq) <- q_mult b'' b''
b_sq' <- q_sub_param_in_place (fromIntegral bigD) b_sq
(_,c_num) <- q_abs b_sq'
(_,del_change_2) <- fprealq_log_with_shape del (fprealx 0 c_num)
del' <- qc_copy del
(_,del') <- fprealq_sub_in_place del_change_1 del'
(_,del') <- fprealq_add_in_place del_change_2 del'
return (ii', del'))
qc_copy
return (iid, rho_inv_iid)
q_rho_red_d :: IdRedDistQ -> Circ (IdRedDistQ,IdRedDistQ)
q_rho_red_d (ii,del) = do
ii <- q_forget_reduced ii
((ii,del), (ii',del')) <- q_rho_d (ii,del)
ii <- q_assert_reduced ii
ii' <- q_assert_reduced ii'
return ((ii,del), (ii',del'))
q_rho_inv_red_d :: IdRedDistQ -> Circ (IdRedDistQ,IdRedDistQ)
q_rho_inv_red_d (ii,del) = do
ii <- q_forget_reduced ii
((ii,del), (ii',del')) <- q_rho_inv_d (ii,del)
ii <- q_assert_reduced ii
ii' <- q_assert_reduced ii'
return ((ii,del), (ii',del'))
q_dot_prod :: IdealRedQ -> IdealRedQ -> Circ (IdealRedQ,IdealRedQ,IdealQ)
q_dot_prod = box "q_dot_prod" $ \(IdealRed bigD1 a1 b1) (IdealRed bigD2 a2 b2) -> do
assertM (all_eq [bigD1,bigD2]) "Error: mismatched Δ’s in q_dot_prod."
let bigD = bigD1
n = qdint_length a1
label (a1,b1,a2,b2) ("a1","b1","a2","b2")
((a1,a2,b1,b2),(k,l,a3,b3)) <- with_computed_fun (a1,a2,b1,b2)
(\(a1,a2,b1,b2) -> do
comment "q_dot_prod, step 1: (khat,uhat,vhat) <- ExtendedEuclid(a1,a2)"
(a1,a2,khat,uhat,vhat) <- q_ext_euclid a1 a2
label (khat,uhat,vhat) ("khat","uhat","vhat")
comment "q_dot_prod, step 2: (k,u,v) <- ExtendedEuclid(khat,(b1+b2)/2)"
(b1,b2,b1b2) <- q_add b1 b2
b1b2 <- q_div2 b1b2
label (b1b2) ("(b1 + b2)/2")
(khat,b1b2,k,x,w) <- q_ext_euclid khat b1b2
label (k,x,w) ("k","x","w")
comment "q_dot_prod, step 3: a3 := a1a2/k^2. [This should always be an integer.]"
(a1,a2,a1a2) <- q_mult a1 a2
label (a1a2) ("a1*a2")
(k,k_sq) <- q_square k
label (k_sq) ("k^2")
(a1a2,k_sq,a3) <- q_div_exact a1a2 k_sq
label (a1a2,k_sq,a3) ("a3")
comment "q_dot_prod, step 4: t = (long formula, requiring many intermediate calculations)"
(((a1,b1,a2,b2),(uhat,vhat,k,x,w)),t) <- with_computed_fun
((a1,b1,a2,b2),(uhat,vhat,k,x,w))
(\((a1,b1,a2,b2),(uhat,vhat,k,x,w)) -> do
comment "q_dot_prod, step 4, first summand: x * uhat * a1 * b2"
(x,uhat,x_uhat) <- q_mult x uhat
label x_uhat "x * uhat"
(x_uhat,a1,x_uhat_a1) <- q_mult x_uhat a1
label x_uhat_a1 "x * uhat * a1"
(x_uhat_a1,b2,x_uhat_a1_b2) <- q_mult x_uhat_a1 b2
label x_uhat_a1_b2 "x * uhat * a1 * b2"
comment "q_dot_prod, step 4, second summand: x * vhat * a2 * b1"
(x,vhat,x_vhat) <- q_mult x vhat
label x_vhat "x * vhat"
(x_vhat,a2,x_vhat_a2) <- q_mult x_vhat a2
label x_vhat_a2 "x * vhat * a2"
(x_vhat_a2,b1,x_vhat_a2_b1) <- q_mult x_vhat_a2 b1
label x_vhat_a2_b1 "x * vhat * a2 * b1"
comment "q_dot_prod, step 4, third summand: w * (b1 * b2 + Delta) / 2"
(b1,b2,b1_b2) <- q_mult b1 b2
label b1_b2 "b1 * b2"
b1_b2_D <- q_add_param_in_place (fromInteger $ toInteger bigD) b1_b2
label b1_b2_D "b1 * b2 + Delta"
b1_b2_D_by2 <- q_div2 b1_b2_D
label b1_b2_D_by2 "(b1 * b2 + Delta) / 2"
(w,b1_b2_D_by2,w_b1_b2_D_by2) <- q_mult w b1_b2_D_by2
label b1_b2_D_by2 "w * (b1 * b2 + Delta) / 2"
comment "q_dot_prod, step 4, sum of all summands:"
(x_uhat_a1_b2,x_vhat_a2_b1,s) <- q_add x_uhat_a1_b2 x_vhat_a2_b1
(w_b1_b2_D_by2,s) <- q_add_in_place w_b1_b2_D_by2 s
label s "big sum from step 4"
return ((a1,b1,a2,b2),
(uhat,vhat,k,x,w),
(x_uhat,x_uhat_a1,x_uhat_a1_b2),
(x_vhat,x_vhat_a2,x_vhat_a2_b1),
(b1_b2_D_by2,w_b1_b2_D_by2),
s))
(\(inputs, (uhat,vhat,k,x,w), subterm1, subterm2, subterm3, s) -> do
comment "q_dot_prod, step 4, final division: t := (big sum) / k"
(s,k,t) <- q_div s k
label t "t"
return ((inputs, (uhat,vhat,k,x,w), subterm1, subterm2, subterm3, s), t))
comment "q_dot_prod, step 5: set b3 <- (t mod 2a3) - (a3 - 1)."
(a3,twice_a3) <- q_mult_param 2 a3
(t,twice_a3,b3) <- q_mod_unsigned t twice_a3
(a3,b3) <- q_sub_in_place a3 b3
b3 <- q_increment b3
label b3 "b3"
comment "q_dot_prod, step 6: test if (a3 > root Delta), store result as case_a3"
(a3,case_a3) <- q_gt_param a3 (floor (sqrt (fromIntegral bigD)))
label case_a3 "case_a3"
comment "q_dot_prod, step 7: if (a3 > root Delta), then b3 <- b3 + (floor root Delta) - a3"
b3 <- q_add_param_in_place
(floor (sqrt (fromIntegral bigD)))
b3 `controlled` case_a3
(a3,b3) <- q_sub_in_place a3 b3 `controlled` case_a3
return ((a1,a2,b1,b2),(khat,uhat,vhat),(k,x,w),(a1a2,b1b2,k_sq,t,case_a3,twice_a3),(a3,b3)))
(\(inputs,temp1,(k,x,w),temp3,(a3,b3)) -> do
comment "q_dot_prod, step 8: copy computed values into place for I3 = I1.I2"
(a3,a3_out) <- qc_copy_fun a3
(b3,b3_out) <- qc_copy_fun b3
(k,k_out) <- qc_copy_fun k
l_out <- qinit (intm n 1)
label (k_out,l_out,a3_out,b3_out) "I3"
comment "q_dot_prod: uncompute garbage."
return ((inputs,temp1,(k,x,w),temp3,(a3,b3))
,(k_out,l_out,a3_out,b3_out)))
return (IdealRed bigD1 a1 b1, IdealRed bigD1 a2 b2, Ideal bigD1 k l a3 b3)
q_dot_prod_with_dist :: IdRedDistQ -> IdRedDistQ -> Circ (IdRedDistQ, IdRedDistQ, IdDistQ)
q_dot_prod_with_dist = box "q_dot_prod_with_dist" $ \(ii,dist_ii) (jj,dist_jj) -> do
(ii, jj, ii_jj) <- q_dot_prod ii jj
(dist_ii, dist_jj, dist_ii_jj) <- q_mult dist_ii dist_jj
return ( (ii,dist_ii), (jj,dist_jj), (ii_jj,dist_ii_jj) )
q_star_prod :: IdRedDistQ -> IdRedDistQ -> Circ (IdRedDistQ, IdRedDistQ, IdRedDistQ)
q_star_prod = box "q_star_prod" $ \iid jjd -> do
let bigD = bigD_of_IdealRed $ fst iid
((iid,jjd), kkd_out) <- with_computed_fun
(iid,jjd)
(\(iid,jjd) -> do
comment "q_star_prod, step 1: K <- 1/ka (I . J)"
label (iid,jjd) (("I","δ(I)"),("J","δ(J)"))
(iid,jjd,ii_jjd) <- q_dot_prod_with_dist iid jjd
label (ii_jjd) ("II.JJ")
(ii_jjd,kkd) <- q_normalize ii_jjd
label (kkd) ("1/ka (II.JJ)")
comment "q_star_prod, step 2: while K not reduced, set K <- rho(K)"
(kkd_initial,kkd_reduced) <- q_bounded_while_with_garbage
(\(kk,dist) -> do
comment "q_star_prod, step 2, loop conditional: is K reduced yet?"
(kk,c) <- q_is_reduced kk
c <- qnot c
return ((kk,dist),c))
((ceiling $ (logBase 2 $ fromIntegral bigD) / 2) + 1)
kkd
(\kkd_old -> do
comment "q_star_prod, step 2, loop body: compute ρ(Κ)"
(kkd_old,kkd_new) <- q_rho_d kkd_old
return (kkd_new,kkd_old))
let (ii_jj,dist_ij) = ii_jjd
(kk_reduced,dist_k) = kkd_reduced
comment "q_star_prod, step 2c: assert that K is now reduced."
kk <- q_assert_reduced kk_reduced
comment "q_star_prod, step 3: pull K backwards or forwards to be as close as possible to I.J"
(dist_k, dist_ij, k_lt_ij) <- q_lt dist_k dist_ij
label k_lt_ij "Initially, δ(K) ≤ δ(I.J)?"
let ii_jjd = (ii_jj,dist_ij)
kkd = (kk,dist_k)
comment "q_star_prod, step 3a: pull-forwards loop"
((dist_ij, kkd), (dij', kkd_forwards)) <- q_bounded_while_with_garbage
(\(dist_ij,(kk,dist_k)) -> do
comment "q_star_prod, step 3a, loop condition: is δ(K) ≤ δ(II.JJ) still?"
(dist_k, dist_ij, k_lt_ij) <- q_lt dist_k dist_ij
return ((dist_ij,(kk,dist_k)),k_lt_ij))
(ceiling $ 3 * (logBase 2 $ fromIntegral bigD) / 2)
(dist_ij,kkd)
(\(dij,kkd_old) -> do
comment "q_star_prod, step 3a, loop body: compute ρ(Κ)"
(kkd_old,kkd_new) <- q_rho_red_d kkd_old
return ((dij,kkd_new),kkd_old))
comment "q_star_prod, step 3b: pull-backwards loop"
((dist_ij, kkd), (dij'', kkd_too_far_back)) <- q_bounded_while_with_garbage
(\(dist_ij,(kk,dist_k)) -> do
comment "q_star_prod, step 3b, loop condition: is δ(K) ≥ δ(II.JJ) still?"
(dist_k, dist_ij, k_gt_ij) <- q_gt dist_k dist_ij
return ((dist_ij,(kk,dist_k)),k_gt_ij))
(ceiling $ 3 * (logBase 2 $ fromIntegral bigD) / 2)
(dist_ij,kkd)
(\(dij,kkd_old) -> do
comment "q_star_prod, step 3b, loop body: compute ρ^-1(Κ)"
(kkd_old,kkd_new) <- q_rho_inv_red_d kkd_old
return ((dij,kkd_new),kkd_old))
comment "q_star_prod, step 3b, cleanup: apply ρ once to the output of this loop"
(kkd_too_far_back, kkd_back) <- q_rho_red_d kkd_too_far_back
return ((iid, jjd, ii_jjd, kkd_initial, kkd, dij', dij'', kkd_too_far_back), k_lt_ij, kkd_forwards, kkd_back))
(\(stuff, k_lt_ij, kkd_forwards, kkd_back) -> do
comment "q_star_prod, step 4: Return the result of either first or second loop, depending on test."
kkd_out <- qinit $ qc_false kkd_forwards
(kkd_out,kkd_forwards) <- controlled_not kkd_out kkd_forwards `controlled` k_lt_ij .==. True
(kkd_out,kkd_backwards) <- controlled_not kkd_out kkd_back `controlled` k_lt_ij .==. False
label kkd_out "kkd_out"
return ((stuff, k_lt_ij, kkd_forwards, kkd_back),kkd_out))
return (iid, jjd, kkd_out)
q_star_square :: IdRedDistQ -> Circ (IdRedDistQ, IdRedDistQ)
q_star_square = \iid -> with_computed_fun iid qc_copy_fun
(\(iid, iid_copy) -> do
(iid, iid_copy, iid_square) <- q_star_prod iid iid_copy
return ((iid, iid_copy), iid_square))
q_fN :: CLIntP -> Int -> Int -> QDInt -> IntM -> Circ (QDInt,(IdealRedQ,FPRealQ))
q_fN bigD n l qi j = do
let p = precision_for_fN bigD n l
nn = 2^n
ll = 2^l
q = qdint_length qi
(qi, (jj, diff)) <- with_computed_fun
qi
(\qi -> do
comment "q_fN, step 1: Precompute x := i/N + j/L, as it used many times."
qi <- return $ fprealx (-n) qi
qj <- qinit (fprealx (-l) j)
(qi,qj,qx) <- fprealq_add_het (-p) (q - n + p) qi qj
label qx "x := i/N + j/L"
comment "q_fN, step 2: J <- ρ^2(O)."
oo <- qinit $ fix_sizes_IdealRed $ unit_idealRed bigD
dist_o <- qinit $ (fprealx (-p) (intm (q - n + p) 0))
let ood = (oo,dist_o)
label ood ("O", "δ_O = 0")
(ood,jjd0) <- q_rho_red_d ood
label jjd0 ("J0", "δ_J0)")
(jjd0,jjd1) <- q_rho_red_d jjd0
label jjd1 ("J1", "δ_J1)")
comment "q_fN, step 3: compute the iterated squares of (J1,δ_J1)."
jjds <- loop_with_indexM
(ceiling $ (fromIntegral q) * (log 2) / (nn *
(snd $ rho_d $ rho_d $ (unit_ideal bigD, 0))))
[jjd1]
(\i (jjd_prev:jjds_earlier) -> do
(jjd_prev,jjd_new) <- q_star_square jjd_prev
label jjd_new ("J_" ++ show (i+2), "δ_" ++ show (i+2))
return (jjd_new:jjd_prev:jjds_earlier))
comment "q_fN, step 4: compute the greatest product of these ≤ x"
let jjd_star = ood
label jjd_star ("J_*, δ_*")
(qx, jjd_star, garbage) <- foldM
(\(qx, jjd_star_old, garbage) jjd_k -> do
(jjd_star_old, jjd_k, jjd_star_candidate) <- q_star_prod jjd_star_old jjd_k
let (jj_star_candidate, dist_candidate) = jjd_star_candidate
(dist_candidate, qx, test) <- q_lt dist_candidate qx
let jjd_star_candidate = (jj_star_candidate, dist_candidate)
jjd_star_new <- qinit (qc_false jjd_star_old)
(jjd_star_new, jjd_star_candidate) <-
controlled_not jjd_star_new jjd_star_candidate `controlled` test .==. True
(jjd_star_new, jjd_star_old) <-
controlled_not jjd_star_new jjd_star_old `controlled` test .==. False
label jjd_star_new ("J_*, δ(J_*)")
return (qx, jjd_star_new, (jjd_star_old,jjd_star_candidate,jjd_k,test):garbage))
(qx, jjd_star, [])
jjds
label jjd_star ("J_*, δ_*)")
comment "q_fN: (J_*,δ_*) is now the greatest ideal/distance pair ≤ x constructible from the iterated star-squares (J_k,δ_k)."
comment "q_fN, step 5: apply ρ^2 to (J_*,δ_*) as long as δ_* ≤ x."
((jjd_star_initial, qx), (jjd_star, qx_copy)) <- q_bounded_while_with_garbage
(\((jj_star, dist_star), qx) -> do
(dist_star, qx, test) <- q_le dist_star qx
return (((jj_star, dist_star), qx), test))
(ceiling $ 3 * logBase 2 (fromIntegral bigD) / 2)
(jjd_star, qx)
(\(jjd_star_old, qx) -> do
(jjd_star_old, rho_jjd_star_old) <- q_rho_red_d jjd_star_old
(rho_jjd_star_old, jjd_star_new) <- q_rho_red_d rho_jjd_star_old
return ((jjd_star_new, qx), (jjd_star_old, rho_jjd_star_old)))
qx <- qc_uncopy_fun qx qx_copy
comment "q_fN, step 6: apply ρ^{-1} once more if necessary."
(jjd_star_candidate1, jjd_star_candidate2) <- q_rho_inv_red_d jjd_star
let (jj_star_candidate1, dist_star_candidate1) = jjd_star_candidate1
(dist_star_candidate1, qx, final_test) <- q_le dist_star_candidate1 qx
let jjd_star_candidate1 = (jj_star_candidate1, dist_star_candidate1)
return (qx, jjd_star_candidate1, jjd_star_candidate2, final_test,
(qi, qj, garbage, jjd0, jjd1, jjd_star_initial, jjd_star_initial)))
(\(qx, jjd_star_candidate1, jjd_star_candidate2, test, irrelevant) -> do
jjd_star_out <- qinit (qc_false jjd_star_candidate1)
(jjd_star_out, jjd_star_candidate1) <- controlled_not jjd_star_out jjd_star_candidate1 `controlled` test .==. False
(jjd_star_out, jjd_star_candidate1) <- controlled_not jjd_star_out jjd_star_candidate2 `controlled` test .==. True
let (jj_out, dist_jj) = jjd_star_out
(qx,diff_out) <- fprealq_sub_in_place qx dist_jj
return ((qx, jjd_star_candidate1, jjd_star_candidate2, test, irrelevant),
(jj_out, diff_out)))
return (qi, (jj, diff))