{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Algorithms/CL/Auxiliary.hs" #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
module Quipper.Algorithms.CL.Auxiliary where
import Quipper
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.Internal
import Data.Maybe
import Control.Monad
assert :: Bool -> String -> a -> a
assert condition error_message x = if condition then x else error error_message
assertM :: (Monad m) => Bool -> String -> m ()
assertM b errorstring = if b then return () else error errorstring
sequence_until :: (Monad m) => (a -> Bool) -> [m a] -> m (Maybe a)
sequence_until _ [] = return Nothing
sequence_until p (m0:ms) = do
a0 <- m0
if p a0 then return (Just a0) else sequence_until p ms
all_eq :: (Eq a) => [a] -> Bool
all_eq [] = True
all_eq [a] = True
all_eq (a:b:rest) = (a == b) && all_eq (b:rest)
while :: (a -> Bool) -> (a -> a) -> a -> a
while cond func x = if (cond x) then while cond func (func x) else x
bounded_while :: (Integral int) => (a -> Bool) -> int -> (a -> a) -> a -> a
bounded_while cond bound func x
| bound < 0 = error "bounded_while: negative bound"
| bound == 0 && (not $ cond x) = x
| bound == 0 = error "bounded_while: last iteration doesn't satisfy condition"
| otherwise =
bounded_while cond (bound-1) func x'
where x' = if (cond x) then func x else x
bounded_iterate :: (Integral int) => int -> (a -> a) -> a -> [a]
bounded_iterate bound func x
| bound < 0 = error "negative bound in bounded_iterate"
| bound == 0 = [x]
| otherwise =
x : bounded_iterate (bound-1) (func) (func x)
primes :: (Integral a) => [a]
primes = primesn (2 : [ k*2+1 | k <- [1..] ])
where primesn (n:xs) =
n : (primesn (filter (\k -> k `mod` n /= 0) xs))
primesn [] = undefined
primes_to :: (Integral a) => a -> [a]
primes_to k = takeWhile (<= k) primes
is_square_free :: (Integral a) => a -> Bool
is_square_free n =
(n /= 0) &&
(not $ any (\p -> (p*p) `divides` n) $ takeWhile (\x -> x^2 <= (abs n)) [2..])
jacobi_symbol :: (Integral a, Num b) => a -> a -> b
jacobi_symbol a p =
jacobi_symbol' a p
where
jacobi_symbol' a p
| a == 0 = 0
| a == 1 = 1
| a == 2 = if (p `mod` 8 == 1 || p `mod` 8 == 7) then 1 else -1
| a >= p = jacobi_symbol (a `mod` p) p
| 2 `divides` a = (jacobi_symbol (a `div` 2) p) * (jacobi_symbol 2 p)
| otherwise = (if p `mod` 4 == 3 && a `mod` 4 == 3 then -1 else 1)
* (jacobi_symbol p a)
mod_with_max :: (Integral a) => a -> a -> a -> a
mod_with_max x y max = max - ((max - x) `mod` y)
divchk :: (Show a, Integral a) => a -> a -> a
divchk nom denom =
if (nom `mod` denom == 0)
then nom `div` denom
else error ("divchk: " ++ show denom ++ " does not divide " ++ show nom ++ "!")
extended_euclid :: Integral a => a -> a -> (a, a, a)
extended_euclid a b =
if (b == 0) then (a, 1, 0) else (d, x, y)
where
(d', x', y') = extended_euclid b (a `mod` b)
(d, x, y ) = (d', y', x' - (a `div` b)*y')
divides :: (Integral a) => a -> a -> Bool
divides denom nom = (nom `mod` denom == 0)
is_int :: (RealFrac a, Eq a) => a -> Bool
is_int x = x == (fromIntegral $ round x)
continued_list :: (Integral int) => int -> int -> [int]
continued_list _ 0 = []
continued_list num denom =
int_part : continued_list denom num'
where
int_part = num `div` denom
num' = num - int_part*denom
convergents :: (Integral int, Fractional a) => [int] -> [a]
convergents as = recursive (0,1) (1,0) as
where
recursive (h0, k0) (h1, k1) [] = []
recursive (h0, k0) (h1, k1) (a2:as) = b2 : recursive (h1, k1) (h2, k2) as
where
h2 = a2 * h1 + h0
k2 = a2 * k1 + k0
b2 = (fromIntegral h2) / (fromIntegral k2)
blackbox :: (QData qa, QData qb) => String -> qb -> qa -> Circ (qa,qb)
blackbox n out_shape = box n $ \qx -> do
qy <- qinit $ qc_false out_shape
(qx,qy) <- named_gate n (qx,qy)
return (qx,qy)
arithbox :: (QCData qa, QCData qb, QCurry qa_qb qa qb) => String -> qa_qb -> qa_qb
arithbox n = box ("Arith." ++ n)
q_ext_euclid :: QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt,QDInt,QDInt)
q_ext_euclid = arithbox "q_ext_euclid" Arith.q_ext_euclid
q_add :: QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt)
q_add = arithbox "q_add" Arith.q_add
q_mult :: (QCData qa, QNum qa)
=> qa -> qa -> Circ (qa,qa,qa)
q_mult = arithbox "q_mult" Arith.q_mult
q_div_exact :: QDInt -> QDInt -> Circ (QDInt, QDInt, QDInt)
q_div_exact = arithbox "q_div_exact" Arith.q_div_exact
q_add_in_place :: QDInt -> QDInt -> Circ (QDInt, QDInt)
q_add_in_place = arithbox "q_add_in_place" Arith.q_add_in_place
q_add_param_in_place ::IntM -> QDInt -> Circ QDInt
q_add_param_in_place = Arith.q_add_param_in_place
q_div :: QDInt -> QDInt -> Circ (QDInt, QDInt, QDInt)
q_div = arithbox "q_div" Arith.q_div
q_mult_param :: IntM -> QDInt -> Circ (QDInt, QDInt)
q_mult_param = Arith.q_mult_param
q_mod_unsigned :: QDInt -> QDInt -> Circ (QDInt, QDInt, QDInt)
q_mod_unsigned = arithbox "q_mod_unsigned" Arith.q_mod_unsigned
q_sub_in_place :: QDInt -> QDInt -> Circ (QDInt, QDInt)
q_sub_in_place = arithbox "q_sub_in_place" Arith.q_sub_in_place
q_increment :: QDInt -> Circ QDInt
q_increment = arithbox "q_increment" Arith.q_increment
fprealq_of_QDInt_with_shape :: FPRealQ -> QDInt -> Circ (QDInt, FPRealQ)
fprealq_of_QDInt_with_shape = blackbox "fprealq_of_QDInt_with_shape"
q_div2 :: QDInt -> Circ QDInt
q_div2 = return . qdint_of_qulist_bh . rotate . qulist_of_qdint_bh
where
rotate as = last as:init as
q_square :: QDInt -> Circ (QDInt,QDInt)
q_square qx = do
qx' <- qc_copy qx
(qx,qx',qxqx) <- q_mult qx qx'
qx <- qc_uncopy_fun qx qx'
return (qx,qxqx)
q_gt_param :: QDInt -> IntM -> Circ (QDInt,Qubit)
q_gt_param qx y = do
let y' = intm_promote y qx "q_gt_param: qx and y must be of the same length"
qy <- qinit y'
(qx, qy, qx_gt_y) <- q_gt qx qy
qterm y' qy
return (qx, qx_gt_y)
q_ge_param :: QDInt -> IntM -> Circ (QDInt,Qubit)
q_ge_param qx y = do
let y' = intm_promote y qx "q_ge_param: qx and y must be of the same length"
qy <- qinit y'
(qx, qy, qx_ge_y) <- q_ge qx qy
qterm y' qy
return (qx, qx_ge_y)
q_mod_semi_signed :: QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt)
q_mod_semi_signed = box "mod" $ \x y -> do
x_mod_y <- with_computed
(do
sign_x <- case qdint_length x of
0 -> qinit False
_ -> qc_copy $ head $ qulist_of_qdint_bh x
x <- q_negate_in_place x `controlled` sign_x
x <- q_decrement x `controlled` sign_x
(_, _, x') <- q_mod_unsigned x y
x' <- q_increment x' `controlled` sign_x
x' <- q_negate_in_place x' `controlled` sign_x
(y,x') <- q_add_in_place y x' `controlled` sign_x
return x')
qc_copy
return (x, y, x_mod_y)
q_mod_with_max :: QDInt -> QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt,QDInt)
q_mod_with_max x y m = do
x_modmax_y <- with_computed
(do
(_, _, x') <- q_sub m x
(_, _, x'_mod_y) <- q_mod_semi_signed x' y
(_, _, x_modmax_y) <- q_sub m x'_mod_y
return x_modmax_y)
qc_copy
return (x, y, m, x_modmax_y)
q_mod_2times_buggy :: QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt)
q_mod_2times_buggy x a = do
x_mod_2a <- with_computed ( do
a' <- qc_copy a
(a,two_a) <- q_add_in_place a a'
x' <- qc_copy x
(x_mod_2a,two_a,x_div_2a) <- q_moddiv_unsigned_in_place x' two_a
return x_mod_2a
) ( \x_mod_2a -> do
x_mod_2a' <- qc_copy x_mod_2a
return x_mod_2a'
)
return (x,a,x_mod_2a)
q_bounded_while_with_garbage :: (QData qa, QCData qb) =>
(qa -> Circ (qa,Qubit))
-> Int
-> qa
-> (qa -> Circ (qa,qb))
-> Circ (qa,qa)
q_bounded_while_with_garbage _ 0 x _ = qc_copy_fun x
q_bounded_while_with_garbage test bound x body = do
(x, x_really_out) <- with_computed_fun x
(\x -> do
x_out <- qinit $ qc_false x
failed_before <- qinit False
(x_final, x_out, failed_ever, loop_garbage) <- loopM bound (x, x_out, failed_before, [])
(\(x_cur, x_out, failed_before, garbage) -> do
(x_cur, good_now) <- test x_cur
(x_out, x_cur) <- controlled_not x_out x_cur `controlled` good_now .==. 0 .&&. failed_before .==. 0
failed_now <- qinit True
failed_now <- qnot failed_now `controlled` good_now .==. 1 .&&. failed_before .==. 0
(x_cur, new_garbage) <- body x_cur
return (x_cur, x_out, failed_now, (good_now, failed_before, new_garbage):garbage))
(x_out, x_final) <- controlled_not x_out x_final `controlled` failed_ever .==. 0
return (x_out, (x_final, failed_ever, loop_garbage)))
(\(x_out, garbage) -> do
(x_out, x_really_out) <- qc_copy_fun x_out
return ((x_out, garbage), x_really_out))
return (x, x_really_out)
q_bounded_while :: (QCData qa) =>
(qa -> Circ (qa,Qubit))
-> Int
-> qa
-> (qa -> Circ qa)
-> Circ (qa,qa)
q_bounded_while _ 0 x _ = qc_copy_fun x
q_bounded_while test bound x body =
with_computed_fun x
(\x -> do
(x,c) <- test x
x <- body x `controlled` c
return (x,c))
(\(x,c) -> bw_aux (bound-1) x c)
where
bw_aux 0 x c = do (x,x') <- qc_copy_fun x; return ((x,c),x')
bw_aux bound x c = do
with_computed_fun (x,c)
(\(x,c) -> do
(x,c') <- test x
c'' <- qinit False
c'' <- qnot c'' `controlled` [c,c']
x <- body x `controlled` c''
return (x,c,c',c''))
(\(x,c,c',c'') -> do
((x,c''),x') <- bw_aux (bound-1) x c''
return ((x,c,c',c''),x'))
q_bounded_while_productive :: (QCData qa, QCData qb) =>
(qa -> Circ (qa,Qubit))
-> Int
-> qa
-> (qa -> Circ (qa,qb))
-> Circ (qa,qa,[qb])
q_bounded_while_productive test bound x body = do
((x,[]),(x',ys)) <-
q_bounded_while
(\(x,ys) -> do (x,c) <- test x; return ((x,ys),c))
bound
(x,[])
(\(x,ys) -> do (x,y_new) <- body x; return (x,y_new:ys))
return (x,x',ys)
q_do_until :: (QCData qa) =>
Int
-> qa
-> (qa -> Circ (qa,Qubit))
-> Circ (qa,qa)
q_do_until bound x body = do
with_computed_fun x body
(\(x,c) -> do_aux (bound-1) x c)
where
do_aux 0 x c = do (x,x') <- qc_copy_fun x; return ((x,c),x')
do_aux bound x c = do
with_computed_fun (x,c)
(\(x,c) -> do
(x,c') <- body x `controlled` c
c'' <- qinit False
c'' <- qnot c'' `controlled` [c,c']
return (x,c,c',c''))
(\(x,c,c',c'') -> do
((x,c''),x') <- do_aux (bound-1) x c''
return ((x,c,c',c''),x'))