{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Libraries/Arith.hs" #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Quipper.Libraries.Arith (
XInt,
QDInt,
CInt,
IntM,
qulist_of_qdint_bh,
qdint_of_qulist_bh,
qulist_of_qdint_lh,
qdint_of_qulist_lh,
qdint_length,
qdint_extend_unsigned,
qdint_extend_signed,
bitlist_of_cint_bh,
cint_of_bitlist_bh,
bitlist_of_cint_lh,
cint_of_bitlist_lh,
cint_length,
cint_extend_unsigned,
cint_extend_signed,
boollist_of_intm_bh,
intm_of_boollist_bh,
intm_length,
integer_of_intm_unsigned,
integer_of_intm_signed,
intm_with_length,
intm_of_integer,
intm,
intm_promote,
intm_interval_signed,
intm_interval_unsigned,
intm_extend_unsigned,
intm_extend_signed,
qdint_shape,
cint_shape,
xint_maybe_length,
list_of_xint_bh,
xint_of_list_bh,
list_of_xint_lh,
xint_of_list_lh,
QNum(..),
q_increment,
q_decrement,
q_add_in_place,
q_sub_in_place,
q_negate_in_place,
q_add_param,
q_sub_param,
q_add_param_in_place,
q_sub_param_in_place,
q_mult_param,
q_le_unsigned,
q_le_signed,
q_lt_signed,
q_negative,
q_moddiv_unsigned_in_place,
q_mod_unsigned,
q_divrem_unsigned,
q_div_unsigned,
q_div,
q_quot,
q_div_exact_unsigned,
q_div_exact,
q_ext_euclid,
template_symb_plus_,
) where
import Quipper
import Quipper.Internal
import Quipper.Utils.Sampling
import Quipper.Utils.Auxiliary
import Control.Monad
import Data.Typeable
data XInt x = XInt [x] | XInt_indet Integer (Identity Bool x)
deriving (Show, Typeable)
type QDInt = XInt Qubit
instance Show QDInt where
show (XInt l) = "#" ++ show l
show (XInt_indet n id) = error "IntM: internal error"
type CInt = XInt Bit
type IntM = XInt Bool
instance Show IntM where
show (XInt l) = "intm " ++ show (length l) ++ " " ++ show (int_of_boollist_signed_bh l)
show (XInt_indet n id) = show n
instance Interval IntM where
interval x y = intm_interval_unsigned x y
instance Zero IntM where
zero x = intm_with_length (intm_length x) 0
xint_of_list_bh :: [x] -> XInt x
xint_of_list_bh xs = XInt xs
intm_of_integer :: Integer -> IntM
intm_of_integer n = XInt_indet n reflexivity
xint_case :: XInt x -> Either [x] (Integer, Identity Bool x)
xint_case (XInt xs) = Left xs
xint_case (XInt_indet n id) = Right (n, id)
xint_set_length :: Int -> XInt x -> String -> XInt x
xint_set_length m x errmsg | m < 0 =
error "xint_set_length: negative length not permitted"
xint_set_length m x errmsg =
case xint_case x of
Left xs | m == length xs -> x
| otherwise -> error errmsg
Right (n, id) -> XInt xs where
xs = [ identity id b | b <- boollist_of_int_bh m n ]
xint_is_determinate :: XInt x -> Bool
xint_is_determinate x =
case xint_case x of
Left _ -> True
Right _ -> False
list_of_xint_bh :: XInt x -> [x]
list_of_xint_bh x =
case xint_case x of
Left xs -> xs
Right _ -> error "list_of_xint_bh: integer has indeterminate length"
xint_maybe_length :: XInt x -> Maybe Int
xint_maybe_length x =
case xint_case x of
Left xs -> Just (length xs)
Right _ -> Nothing
integer_of_intm_unsigned :: IntM -> Integer
integer_of_intm_unsigned x =
case xint_case x of
Left xs -> int_of_boollist_unsigned_bh xs
Right (n, id) -> n
integer_of_intm_signed :: IntM -> Integer
integer_of_intm_signed x =
case xint_case x of
Left xs -> int_of_boollist_signed_bh xs
Right (n, id) -> n
xint_equals :: (Eq x) => XInt x -> XInt x -> Bool
xint_equals x y =
case (xint_case x, xint_case y) of
(Left xs, Left ys)
| length xs == length ys -> xs == ys
| otherwise -> error "Equality test on XInt: operands must be of equal length"
(_, Left ys) -> xint_equals (xint_set_length m x "xint_equals") y
where m = length ys
(Left xs, _) -> xint_equals x (xint_set_length m y "xint_equals")
where m = length xs
(Right (n, _), Right (n', _)) -> n == n'
xint_length :: XInt x -> Int
xint_length x =
case xint_maybe_length x of
Just m -> m
Nothing -> error "xint_length: integer has indeterminate length"
list_of_xint_lh :: XInt x -> [x]
list_of_xint_lh = reverse . list_of_xint_bh
xint_of_list_lh :: [x] -> XInt x
xint_of_list_lh = xint_of_list_bh . reverse
xint_extend_unsigned :: (Monad m) => Int -> m x -> XInt x -> m (XInt x)
xint_extend_unsigned len zero x
| len < m =
error "pad_xint: requested length is shorter than current length"
| otherwise = do
pad <- sequence (replicate extra zero)
return $ xint_of_list_bh (pad ++ digits)
where
digits = list_of_xint_bh x
m = length digits
extra = len - m
xint_extend_signed :: (Monad m) => Int -> m x -> (x -> m x) -> XInt x -> m (XInt x)
xint_extend_signed len zero copy x
| len < m
= error "pad_xint: requested length is shorter than current length"
| m == 0
= xint_extend_unsigned len zero x
| otherwise = do
pad <- sequence (replicate extra (copy sign))
return $ xint_of_list_bh (pad ++ digits)
where
digits = list_of_xint_bh x
m = length digits
extra = len - m
sign = head digits
intm_length :: IntM -> Maybe Int
intm_length = xint_maybe_length
boollist_of_intm_bh :: IntM -> [Bool]
boollist_of_intm_bh = list_of_xint_bh
intm_of_boollist_bh :: [Bool] -> IntM
intm_of_boollist_bh = xint_of_list_bh
intm :: Int -> Integer -> IntM
intm m n = intm_set_length m (intm_of_integer n) "intm: internal error"
intm_set_length :: Int -> IntM -> String -> IntM
intm_set_length = xint_set_length
intm_extend_unsigned :: Int -> IntM -> IntM
intm_extend_unsigned len x =
getId $ xint_extend_unsigned len (return False) x
intm_extend_signed :: Int -> IntM -> IntM
intm_extend_signed len x =
getId $ xint_extend_signed len (return False) (return) x
bitlist_of_cint_bh :: CInt -> [Bit]
bitlist_of_cint_bh = list_of_xint_bh
cint_of_bitlist_bh :: [Bit] -> CInt
cint_of_bitlist_bh = xint_of_list_bh
bitlist_of_cint_lh :: CInt -> [Bit]
bitlist_of_cint_lh = list_of_xint_lh
cint_of_bitlist_lh :: [Bit] -> CInt
cint_of_bitlist_lh = xint_of_list_lh
cint_length :: CInt -> Int
cint_length = xint_length
cint_extend_unsigned :: Int -> CInt -> Circ CInt
cint_extend_unsigned len x =
xint_extend_unsigned len (cinit False) x
cint_extend_signed :: Int -> CInt -> Circ CInt
cint_extend_signed len x =
xint_extend_signed len (cinit False) (qc_copy) x
qulist_of_qdint_bh :: QDInt -> [Qubit]
qulist_of_qdint_bh = list_of_xint_bh
qdint_of_qulist_bh :: [Qubit] -> QDInt
qdint_of_qulist_bh = xint_of_list_bh
qulist_of_qdint_lh :: QDInt -> [Qubit]
qulist_of_qdint_lh = list_of_xint_lh
qdint_of_qulist_lh :: [Qubit] -> QDInt
qdint_of_qulist_lh = xint_of_list_lh
qdint_length :: QDInt -> Int
qdint_length = xint_length
qdint_extend_unsigned :: Int -> QDInt -> Circ QDInt
qdint_extend_unsigned len x =
xint_extend_unsigned len (qinit False) x
qdint_extend_signed :: Int -> QDInt -> Circ QDInt
qdint_extend_signed len x =
xint_extend_signed len (qinit False) (qc_copy) x
qdint_shape :: Int -> QDInt
qdint_shape m = xint_of_list_bh (replicate m qubit)
cint_shape :: Int -> CInt
cint_shape m = xint_of_list_bh (replicate m bit)
combine_length :: String -> Maybe Int -> Maybe Int -> Maybe Int
combine_length s Nothing m = m
combine_length s m Nothing = m
combine_length s (Just m) (Just m') | m == m' = Just m
| otherwise = error s
intm_promote :: IntM -> XInt x -> String -> IntM
intm_promote bi xi errmsg =
case xint_maybe_length xi of
Nothing -> bi
Just m -> intm_set_length m bi errmsg
type instance QCType x y (XInt z) = XInt (QCType x y z)
type instance QTypeB IntM = QDInt
instance QCLeaf x => QCData (XInt x) where
qcdata_mapM shape f g xs =
mmap xint_of_list_bh $ qcdata_mapM (list_of_xint_bh shape) f g (list_of_xint_bh xs)
qcdata_zip shape q c q' c' xs ys e =
xint_of_list_bh $ qcdata_zip (list_of_xint_bh shape) q c q' c' (list_of_xint_bh xs) (list_of_xint_bh ys) (const $ e "XInt length mismatch")
qcdata_promote b q e = intm_promote b q (e "IntM length mismatch")
instance QCLeaf x => Labelable (XInt x) String where
label_rec qa = label_rec (list_of_xint_lh qa)
instance CircLiftingUnpack (Circ QDInt) (Circ QDInt) where
pack x = x
unpack x = x
integers_of_intms_signed :: [IntM] -> String -> (Maybe Int, [Integer])
integers_of_intms_signed xs s = (m, is) where
m = foldl (combine_length s) Nothing [ intm_length x | x <- xs ]
is = [ integer_of_intm_signed x | x <- xs ]
integers_of_intms_unsigned :: [IntM] -> String -> (Maybe Int, [Integer])
integers_of_intms_unsigned xs s = (m, is) where
m = foldl (combine_length s) Nothing [ intm_length x | x <- xs ]
is = [ integer_of_intm_unsigned x | x <- xs ]
intm_with_length :: Maybe Int -> Integer -> IntM
intm_with_length (Just m) n = intm m n
intm_with_length Nothing n = intm_of_integer n
intm_binop :: (Integer -> Integer -> Integer) -> String -> IntM -> IntM -> IntM
intm_binop op opname x y = intm_with_length m (op x' y') where
(m, [x',y']) = integers_of_intms_signed [x, y] ("Binary operation " ++ opname ++ " on IntM: operands must be of equal length")
intm_unop :: (Integer -> Integer) -> IntM -> IntM
intm_unop op x = intm_with_length xm (op x') where
xm = intm_length x
x' = integer_of_intm_signed x
instance Eq x => Eq (XInt x) where
x == y = xint_equals x y
instance Num IntM where
(+) = intm_binop (+) "+"
(*) = intm_binop (*) "*"
(-) = intm_binop (-) "-"
abs = intm_unop abs
signum = intm_unop signum
fromInteger = intm_of_integer
instance Ord IntM where
compare x y = compare (toInteger x) (toInteger y)
instance Real IntM where
toRational = toRational . integer_of_intm_signed
instance Enum IntM where
succ = intm_unop succ
pred = intm_unop pred
toEnum = intm_of_integer . fromIntegral
fromEnum = fromIntegral . integer_of_intm_signed
enumFrom x = map (intm_with_length m) [x'..] where
(m, [x']) = integers_of_intms_signed [x] "enumeration: IntM"
enumFromThen x y = map (intm_with_length m) [x',y'..] where
(m, [x',y']) = integers_of_intms_signed [x,y] "enumeration: IntM operands must be of equal length"
enumFromTo x y = map (intm_with_length m) [x'..y'] where
(m, [x',y']) = integers_of_intms_signed [x,y] "enumeration: IntM operands must be of equal length"
enumFromThenTo x y z = map (intm_with_length m) [x',y'..z'] where
(m, [x',y',z']) = integers_of_intms_signed [x,y,z] "enumeration: IntM operands must be of equal length"
intm_interval_signed :: IntM -> IntM -> [IntM]
intm_interval_signed x y = [x..y]
intm_interval_unsigned :: IntM -> IntM -> [IntM]
intm_interval_unsigned x y = map (intm_with_length m) [x'..y'] where
(m, [x',y']) = integers_of_intms_unsigned [x,y] "intm_interval: operands must be of equal length"
instance Integral IntM where
toInteger = integer_of_intm_signed
quotRem x y = (intm_with_length m q', intm_with_length m r') where
(m, [x',y']) = integers_of_intms_signed [x, y] "Division on IntM: operands must be of equal length"
(q',r') = quotRem x' y'
common_value :: (Eq a) => String -> [a] -> a
common_value _ [] = error "common_value: no inputs given"
common_value _ [n] = n
common_value error_str (n:ns) = if common_value error_str ns == n then n else error error_str
common_length :: String -> [QDInt] -> Int
common_length error_str xs = common_value error_str $ map qdint_length xs
q_increment :: QDInt -> Circ QDInt
q_increment = mmap xint_of_list_bh . q_increment_qulist . list_of_xint_bh
q_increment_qulist :: [Qubit] -> Circ [Qubit]
q_increment_qulist [] = return []
q_increment_qulist [x_0] = do x_0 <- qnot x_0; return [x_0]
q_increment_qulist [x_1,x_0] = do x_0 <- qnot x_0; x_1 <- qnot x_1 `controlled` (x_0 .==. 0); return [x_1,x_0]
q_increment_qulist [x_2,x_1,x_0] = do
x_0 <- qnot x_0
x_1 <- qnot x_1 `controlled` (x_0 .==. 0)
x_2 <- qnot x_2 `controlled` (x_0 .==. 0) .&&. (x_1 .==. 0)
return [x_2,x_1,x_0]
q_increment_qulist x_bits = do
let x_0 = last x_bits
x_1 = last $ init x_bits
x_higher = init $ init $ x_bits
x_0 <- qnot x_0
x_1 <- qnot x_1 `controlled` (x_0 .==. 0)
(x_higher,x_1,x_0) <- with_ancilla (\c -> do
c <- qnot c `controlled` (x_0 .==. 0) .&&. (x_1 .==. 0)
(c,rev_x_higher) <- q_increment_qulist_aux c (reverse x_higher)
c <- qnot c `controlled` (x_0 .==. 0) .&&. (x_1 .==. 0)
return (reverse rev_x_higher, x_1, x_0))
return (x_higher ++ [x_1,x_0])
where
q_increment_qulist_aux :: Qubit -> [Qubit] -> Circ (Qubit,[Qubit])
q_increment_qulist_aux b [] = return (b,[])
q_increment_qulist_aux b [x_0] =
do x_0 <- qnot x_0 `controlled` b; return (b,[x_0])
q_increment_qulist_aux b [x_0,x_1] = do
x_0 <- qnot x_0 `controlled` b
x_1 <- qnot x_1 `controlled` b .&&. (x_0 .==. 0)
return (b,[x_0,x_1])
q_increment_qulist_aux b (x_0:x_higher) = do
x_0 <- qnot x_0 `controlled` b
(b,x_0,x_higher) <- with_ancilla (\c -> do
c <- qnot c `controlled` b .&&. (x_0 .==. 0)
(c,x_higher) <- q_increment_qulist_aux c x_higher
c <- qnot c `controlled` b .&&. (x_0 .==. 0)
return (b,x_0,x_higher))
return (b, (x_0:x_higher))
q_decrement :: QDInt -> Circ QDInt
q_decrement = reverse_generic_endo q_increment
q_add_qdint :: QDInt -> QDInt -> Circ (QDInt, QDInt, QDInt)
q_add_qdint x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(x', y', z') <- q_add_qulist x' y'
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
let z = xint_of_list_bh z'
return (x, y, z)
q_add_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit], [Qubit], [Qubit])
q_add_qulist x y = do
let l = length x
when (l /= length y) $ do
error "q_add_qdint: cannot add QDInts of different lengths"
((x,y),s_out) <- with_computed_fun (x,y)
(\(x,y) -> do
s <- qinit (replicate l False)
c <- qinit (replicate l False)
x <- return $ reverse x
y <- return $ reverse y
s <- return $ reverse s
c <- return $ reverse c
(x,y,s,c) <- loop_with_indexM (l-1) (x,y,s,c) (\j (x,y,s,c) -> do
let c_j1 = c !! (j+1)
let s_j = s !! j
c_j1 <- qnot c_j1 `controlled` (x!!j .&&. y!!j)
c_j1 <- qnot c_j1 `controlled` (x!!j .&&. c!!j)
c_j1 <- qnot c_j1 `controlled` (y!!j .&&. c!!j)
s_j <- qnot s_j `controlled` (x!!j)
s_j <- qnot s_j `controlled` (y!!j)
s_j <- qnot s_j `controlled` (c!!j)
c <- return $ overwriteAt (j+1) c_j1 c
s <- return $ overwriteAt j s_j s
return (x,y,s,c))
let s_l1 = s !! (l-1)
s_l1 <- qnot s_l1 `controlled` (x!!(l-1))
s_l1 <- qnot s_l1 `controlled` (y!!(l-1))
s_l1 <- qnot s_l1 `controlled` (c!!(l-1))
s <- return $ overwriteAt (l-1) s_l1 s
x <- return $ reverse x
y <- return $ reverse y
s <- return $ reverse s
c <- return $ reverse c
return (x,y,s,c))
(\(x,y,s,c) -> do
(s,s_out) <- qc_copy_fun s
return ((x,y,s,c), s_out))
return (x, y, s_out)
q_sub_qdint :: QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt)
q_sub_qdint x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(x', y', z') <- q_sub_qulist x' y'
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
let z = xint_of_list_bh z'
return (x, y, z)
q_sub_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit], [Qubit], [Qubit])
q_sub_qulist x y = do
let l = length x
when (l /= length y) $ do
error "q_sub_qdint: cannot subtract QDInts of different lengths"
((x,y),d_out) <- with_computed_fun (x,y)
(\(x,y) -> do
d <- qinit (replicate l False)
b <- qinit (replicate l False)
x <- return $ reverse x
y <- return $ reverse y
d <- return $ reverse d
b <- return $ reverse b
(x,y,d,b) <- loop_with_indexM (l-1) (x,y,d,b) (\j (x,y,d,b) -> do
let b_j1 = b !! (j+1)
let d_j = d !! j
b_j1 <- qnot b_j1 `controlled` (x!!j .==. 0) .&&. (y!!j .==. 1)
b_j1 <- qnot b_j1 `controlled` (x!!j .==. 0) .&&. (b!!j .==. 1)
b_j1 <- qnot b_j1 `controlled` (y!!j .==. 1) .&&. (b!!j .==. 1)
d_j <- qnot d_j `controlled` (x!!j)
d_j <- qnot d_j `controlled` (y!!j)
d_j <- qnot d_j `controlled` (b!!j)
b <- return $ overwriteAt (j+1) b_j1 b
d <- return $ overwriteAt j d_j d
return (x,y,d,b))
let d_l1 = d !! (l-1)
d_l1 <- qnot d_l1 `controlled` (x!!(l-1))
d_l1 <- qnot d_l1 `controlled` (y!!(l-1))
d_l1 <- qnot d_l1 `controlled` (b!!(l-1))
d <- return $ overwriteAt (l-1) d_l1 d
x <- return $ reverse x
y <- return $ reverse y
d <- return $ reverse d
b <- return $ reverse b
return (x,y,d,b))
(\(x,y,d,b) -> do
(d,d_out) <- qc_copy_fun d
return ((x,y,d,b), d_out))
return (x, y, d_out)
q_add_in_place :: QDInt -> QDInt -> Circ (QDInt,QDInt)
q_add_in_place x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(x', y') <- q_add_in_place_qulist x' y'
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
return (x, y)
q_add_in_place_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit], [Qubit])
q_add_in_place_qulist [] [] = return ([], [])
q_add_in_place_qulist [x0] [y0] = do
y0 <- qnot y0 `controlled` x0
return ([x0], [y0])
q_add_in_place_qulist x y = do
let (x0:x_higher) = reverse x
(y0:y_higher) = reverse y
y0 <- qnot y0 `controlled` x0
((x0,y0),(x_higher,y_higher)) <- with_computed_fun (x0,y0)
(\(x0,y0) -> do
c <- qinit False
c <- qnot c `controlled` (x0 .==. 1) .&&. (y0 .==. 0)
return (x0,y0,c))
(\(x0,y0,c) -> do
(x_higher,y_higher,c) <- q_add_aux (x_higher) (y_higher) c
return ((x0,y0,c),(x_higher,y_higher)))
return (reverse (x0:x_higher), reverse (y0:y_higher))
where
q_add_aux :: [Qubit] -> [Qubit] -> Qubit -> Circ ([Qubit],[Qubit],Qubit)
q_add_aux [] [] c = return ([],[],c)
q_add_aux [x0] [y0] c = do
y0 <- qnot y0 `controlled` x0
y0 <- qnot y0 `controlled` c
return ([x0],[y0],c)
q_add_aux (x0:xs) (y0:ys) c = do
y0 <- qnot y0 `controlled` x0
y0 <- qnot y0 `controlled` c
((x0,y0,c),(xs,ys)) <- with_computed_fun (x0,y0,c)
(\(x0,y0,c) -> do
c' <- qinit False
c' <- qnot c' `controlled` (x0 .==. 1) .&&. (y0 .==. 0)
c' <- qnot c' `controlled` (x0 .==. 1) .&&. (c .==. 1)
c' <- qnot c' `controlled` (y0 .==. 0) .&&. (c .==. 1)
return (x0,y0,c,c'))
(\(x0,y0,c,c') -> do
(xs,ys,c') <- q_add_aux xs ys c'
return ((x0,y0,c,c'),(xs,ys)))
return (x0:xs,y0:ys,c)
q_add_aux _ _ _ = error "q_add_in_place: cannot add integers of different sizes."
q_sub_in_place :: QDInt -> QDInt -> Circ (QDInt,QDInt)
q_sub_in_place x y = reverse_generic_endo (\(x,d) -> q_add_in_place x d) (x,y)
q_sub_in_place_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit],[Qubit])
q_sub_in_place_qulist x y = reverse_generic_endo (\(x,d) -> q_add_in_place_qulist x d) (x,y)
q_add_param :: IntM -> QDInt -> Circ (QDInt,QDInt)
q_add_param x1 y = do
let x = intm_promote x1 y "q_add_param: inputs must have equal length"
let x' = boollist_of_intm_bh x
let y' = list_of_xint_bh y
(y', z') <- q_add_param_qulist x' y'
let y = xint_of_list_bh y'
let z = xint_of_list_bh z'
return (y, z)
q_add_param_qulist :: [Bool] -> [Qubit] -> Circ ([Qubit], [Qubit])
q_add_param_qulist x y = do
let l = length x
(y,s_out) <- with_computed_fun y
(\y -> do
s <- qinit (replicate l False)
c <- qinit (replicate l False)
x <- return $ reverse x
y <- return $ reverse y
s <- return $ reverse s
c <- return $ reverse c
(y,s,c) <- loop_with_indexM (l-1) (y,s,c) (\j (y,s,c) -> do
let c_j1 = c !! (j+1)
let s_j = s !! j
c_j1 <- qnot c_j1 `controlled` (x!!j .&&. y!!j)
c_j1 <- qnot c_j1 `controlled` (x!!j .&&. c!!j)
c_j1 <- qnot c_j1 `controlled` (y!!j .&&. c!!j)
s_j <- qnot s_j `controlled` (x!!j)
s_j <- qnot s_j `controlled` (y!!j)
s_j <- qnot s_j `controlled` (c!!j)
c <- return $ overwriteAt (j+1) c_j1 c
s <- return $ overwriteAt j s_j s
return (y,s,c))
let s_l1 = s !! (l-1)
s_l1 <- qnot s_l1 `controlled` (x!!(l-1))
s_l1 <- qnot s_l1 `controlled` (y!!(l-1))
s_l1 <- qnot s_l1 `controlled` (c!!(l-1))
s <- return $ overwriteAt (l-1) s_l1 s
x <- return $ reverse x
y <- return $ reverse y
s <- return $ reverse s
c <- return $ reverse c
return (y,s,c))
(\(y,s,c) -> do
(s,s_out) <- qc_copy_fun s
return ((y,s,c), s_out))
return (y, s_out)
q_sub_param :: IntM -> QDInt -> Circ (QDInt,QDInt)
q_sub_param x y = q_add_param (-x) y
q_add_param_in_place :: IntM -> QDInt -> Circ QDInt
q_add_param_in_place x1 y = do
let x = intm_promote x1 y "q_add_param_in_place: inputs must have equal length"
let x' = boollist_of_intm_bh x
let y' = list_of_xint_bh y
y' <- q_add_param_in_place_qulist x' y'
let y = xint_of_list_bh y'
return y
q_add_param_in_place_qulist :: [Bool] -> [Qubit] -> Circ [Qubit]
q_add_param_in_place_qulist [] [] = return []
q_add_param_in_place_qulist [False] [y0] = return [y0]
q_add_param_in_place_qulist [True] [y0] = do
y0 <- qnot y0
return [y0]
q_add_param_in_place_qulist x y = do
let l = length x
let (x0:x_higher) = reverse x
(y0:y_higher) = reverse y
y0 <- qnot y0 `controlled` x0
(y0,y_higher) <- with_computed_fun y0
(\y0 -> do
c <- qinit False
c <- qnot c `controlled` (x0 == 1) .&&. (y0 .==. 0)
return (y0,c))
(\(y0,c) -> do
(y_higher,c) <- q_add_aux x_higher y_higher c
return ((y0,c),y_higher))
return (reverse (y0:y_higher))
where
q_add_aux :: [Bool] -> [Qubit] -> Qubit -> Circ ([Qubit],Qubit)
q_add_aux [] [] c = return ([],c)
q_add_aux [x0] [y0] c = do
y0 <- qnot y0 `controlled` x0
y0 <- qnot y0 `controlled` c
return ([y0],c)
q_add_aux (x0:xs) (y0:ys) c = do
y0 <- qnot y0 `controlled` x0
y0 <- qnot y0 `controlled` c
((y0,c),ys) <- with_computed_fun (y0,c)
(\(y0,c) -> do
c' <- qinit False
c' <- qnot c' `controlled` (x0 == 1) .&&. (y0 .==. 0)
c' <- qnot c' `controlled` (x0 == 1) .&&. (c .==. 1)
c' <- qnot c' `controlled` (y0 .==. 0) .&&. (c .==. 1)
return (y0,c,c'))
(\(y0,c,c') -> do
(ys,c') <- q_add_aux xs ys c'
return ((y0,c,c'),ys))
return (y0:ys,c)
q_add_aux _ _ _ = error "q_add_in_place: cannot add integers of different sizes."
q_sub_param_in_place :: IntM -> QDInt -> Circ QDInt
q_sub_param_in_place x = q_add_param_in_place (-x)
q_mult_param :: IntM -> QDInt -> Circ (QDInt,QDInt)
q_mult_param x1 y = do
let x = intm_promote x1 y "q_add_param: inputs must have equal length"
let x' = boollist_of_intm_bh x
let y' = list_of_xint_bh y
(y', z') <- q_mult_param_qulist x' y'
let y = xint_of_list_bh y'
let z = xint_of_list_bh z'
return (y, z)
q_mult_param_qulist :: [Bool] -> [Qubit] -> Circ ([Qubit],[Qubit])
q_mult_param_qulist [] [] = return ([], [])
q_mult_param_qulist xs ys = do
let x0 = last xs
x_higher = init xs
y_high = head ys
y_lower = tail ys
(y_lower, p_higher)
<- q_mult_param_qulist x_higher y_lower
p0 <- qinit False
let y = y_high:y_lower
p = p_higher ++ [p0]
(y,p) <- if x0 then q_add_in_place_qulist y p else return (y,p)
return (y, p)
q_negate_in_place :: QDInt -> Circ QDInt
q_negate_in_place x = do
x <- mapUnary qnot x
x <- q_increment x
return x
q_negate_in_place_qulist :: [Qubit] -> Circ [Qubit]
q_negate_in_place_qulist = mmap list_of_xint_bh . q_negate_in_place . xint_of_list_bh
q_negate_qdint :: QDInt -> Circ (QDInt,QDInt)
q_negate_qdint x = do
(x,nx) <- qc_copy_fun x
nx <- q_negate_in_place nx
return (x,nx)
q_abs_qdint :: QDInt -> Circ (QDInt,QDInt)
q_abs_qdint x = do
let x' = list_of_xint_bh x
(x', a') <- q_abs_qulist x'
let x = xint_of_list_bh x'
let a = xint_of_list_bh a'
return (x, a)
q_abs_qulist :: [Qubit] -> Circ ([Qubit],[Qubit])
q_abs_qulist [] = return ([], [])
q_abs_qulist (x_high:x_lower) = do
a_high <- qinit False
(x_lower,a_lower) <- qc_copy_fun x_lower
a_lower <- mapUnary qnot a_lower `controlled` x_high
let a = a_high:a_lower
a <- q_increment_qulist a `controlled` x_high
return (x_high:x_lower, a)
q_signum_qdint :: QDInt -> Circ (QDInt,QDInt)
q_signum_qdint x = do
let x' = list_of_xint_bh x
(x', a') <- q_signum_qulist x'
let x = xint_of_list_bh x'
let a = xint_of_list_bh a'
return (x, a)
q_signum_qulist :: [Qubit] -> Circ ([Qubit],[Qubit])
q_signum_qulist [] = return ([], [])
q_signum_qulist x = do
let l = length x
(s_higher, s_low) <- qinit (replicate (l-1) False, False)
s_low <- qnot s_low
s_higher <- mapUnary qnot s_higher `controlled` (head x)
s_low <- qnot s_low `controlled` (x .==. replicate l 0)
return (x,s_higher ++ [s_low])
q_le_unsigned :: QDInt -> QDInt -> Circ (QDInt,QDInt,Qubit)
q_le_unsigned x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(x',y',le_out) <- q_le_unsigned_qulist x' y'
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
return (x,y,le_out)
q_le_unsigned_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit],[Qubit],Qubit)
q_le_unsigned_qulist x y = do
((x,y),le_out) <- with_computed_fun (x,y) q_le_unsigned_aux
(\(x,y,(le,garbage)) -> do
(le,le_out) <- qc_copy_fun le
return ((x,y,(le,garbage)),le_out))
return (x,y,le_out)
q_le_unsigned_aux :: ([Qubit], [Qubit]) -> Circ ([Qubit],[Qubit],(Qubit,[Qubit]))
q_le_unsigned_aux ([], []) = do q <- qinit True; return ([], [], (q,[]))
q_le_unsigned_aux (x_high:x_lower, y_high:y_lower) = do
(x_lower, y_lower, (le_lower, garbage)) <- q_le_unsigned_aux (x_lower, y_lower)
(x_high,y_high,eq_high) <- q_is_equal x_high y_high
le <- qinit False
le <- qnot le `controlled` (x_high .==. 0) .&&. (y_high .==. 1)
le <- qnot le `controlled` eq_high .&&. le_lower
return (x_high:x_lower, y_high:y_lower, (le, eq_high:le_lower:garbage))
q_le_unsigned_aux _ = error "q_le // QDInt: cannot compare QDInt’s of different lengths."
q_le_signed :: QDInt -> QDInt -> Circ (QDInt,QDInt,Qubit)
q_le_signed x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(x',y',le_out) <- q_le_signed_qulist x' y'
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
return (x,y,le_out)
q_le_signed_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit],[Qubit],Qubit)
q_le_signed_qulist [] [] = do q <- qinit True; return ([], [], q)
q_le_signed_qulist (x_high:x_lower) (y_high:y_lower) = do
((x,y), x_le_y) <- with_computed_fun (x_high:x_lower, y_high:y_lower)
(\(x_high:x_lower, y_high:y_lower) -> do
(x_lower, y_lower, (le_lower, garbage)) <- q_le_unsigned_aux (x_lower, y_lower)
(x_high,y_high,eq_high) <- q_is_equal x_high y_high
return (x_high, y_high, x_lower, y_lower, le_lower, eq_high, garbage))
(\(x_high, y_high, x_lower, y_lower, le_lower, eq_high, garbage) -> do
le <- qinit False
le <- qnot le `controlled` (x_high .==. 1) .&&. (y_high .==. 0)
le <- qnot le `controlled` eq_high .&&. le_lower
return ((x_high, y_high, x_lower, y_lower, le_lower, eq_high, garbage), le))
return (x,y,x_le_y)
q_le_signed_qulist _ _ = error "q_le // QDInt: cannot compare QDInt’s of different lengths."
q_lt_signed :: QDInt -> QDInt -> Circ (QDInt,QDInt,Qubit)
q_lt_signed x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(y',x',y_le_x) <- q_le_signed_qulist y' x'
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
x_lt_y <- qnot y_le_x
return (x,y,x_lt_y)
q_negative :: QDInt -> Circ (QDInt,Qubit)
q_negative x = do
let (x_high:x_lower) = list_of_xint_bh x
(x_high,x_neg) <- qc_copy_fun x_high
return (xint_of_list_bh (x_high:x_lower),x_neg)
instance QOrd QDInt where
q_less qx qy = do (qx,qy,q) <- q_lt_signed qx qy; return q
q_leq qx qy = do (qx,qy,q) <- q_le_signed qx qy; return q
q_mult_qdint :: QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt)
q_mult_qdint x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(x', y', z') <- q_mult_qulist x' y'
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
let z = xint_of_list_bh z'
return (x, y, z)
q_mult_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit],[Qubit],[Qubit])
q_mult_qulist [] [] = return ([], [], [])
q_mult_qulist xs ys = do
let x0 = last xs
x_higher = init xs
y_high = head ys
y_lower = tail ys
(x_higher, y_lower, p_higher)
<- q_mult_qulist x_higher y_lower
p0 <- qinit False
let y = y_high:y_lower
p = p_higher ++ [p0]
(y,p) <- q_add_in_place_qulist y p `controlled` x0
return (x_higher ++ [x0], y, p)
q_moddiv_unsigned_in_place :: QDInt -> QDInt -> Circ (QDInt, QDInt,QDInt)
q_moddiv_unsigned_in_place x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(r', y', q') <- q_moddiv_unsigned_in_place_qulist x' y'
let r = xint_of_list_bh r'
let y = xint_of_list_bh y'
let q = xint_of_list_bh q'
return (r, y, q)
q_moddiv_unsigned_in_place_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit], [Qubit],[Qubit])
q_moddiv_unsigned_in_place_qulist x y = do
let l = common_value "q_divrem_unsigned_in_place: arguments must be same length" $ map length [x,y]
quot_bits <- qinit (replicate l False)
let rem = x
with_ancilla_init (replicate (l-1) False) (\scratch -> do
(y,scratch,quot_bits,rem) <- loop_with_indexM l (y,scratch,quot_bits,rem)
(\i (y,scratch,quot_bits,rem) -> do
let j = l-1-i
let y_init = take j y
y_2j = (drop j y) ++ (take j scratch)
scratch_tail = drop j scratch
((y_init,y_2j,rem,quot_bits),()) <- with_computed_fun
(y_init,y_2j,rem,quot_bits)
(\(y_init,y_2j,rem,quot_bits) -> do
le1 <- qinit False
le1 <- qnot le1 `controlled` (y_init .==. replicate (length y_init) False)
(y_2j,rem,le2) <- q_le_unsigned_qulist y_2j rem
return (y_init,y_2j,rem,quot_bits,le1,le2))
(\(y_init,y_2j,rem,quot_bits,le1,le2) -> do
q_j <- qnot (quot_bits !! (l-1-j)) `controlled` le1 .&&. le2
return ((y_init,y_2j,rem,(overwriteAt (l-1-j) q_j quot_bits),le1,le2),()))
(y_2j,rem) <- q_sub_in_place_qulist y_2j rem `controlled` quot_bits !! (l-1-j)
let y = y_init ++ (take (l-j) y_2j)
scratch = (drop (l-j) y_2j) ++ scratch_tail
return (y,scratch,quot_bits,rem))
return (rem, y, quot_bits))
q_mod_unsigned :: QDInt -> QDInt -> Circ (QDInt, QDInt,QDInt)
q_mod_unsigned x y = do
((x,y),x_mod_y) <- with_computed_fun (x,y)
(\(x,y) -> q_moddiv_unsigned_in_place x y)
(\(x_mod_y, y, x_div_y) -> do
(x_mod_y, x_mod_y_out) <- qc_copy_fun x_mod_y
return ((x_mod_y, y, x_div_y), x_mod_y_out))
return (x,y,x_mod_y)
q_divrem_unsigned :: QDInt -> QDInt -> Circ (QDInt, QDInt,QDInt,QDInt)
q_divrem_unsigned x y = do
(x,rem) <- qc_copy_fun x
(rem,y,quot) <- q_moddiv_unsigned_in_place rem y
return (x,y,quot,rem)
q_div_unsigned :: QDInt -> QDInt -> Circ (QDInt, QDInt,QDInt)
q_div_unsigned x y = do
(x,y,quot,rem) <- q_divrem_unsigned x y
((x,y,quot),()) <- with_computed_fun (x,y,quot)
(\(x,y,quot) -> do
(y,quot,y_quot) <- q_mult y quot
(x,y_quot,rem_copy) <- q_sub x y_quot
return (x,y,quot,y_quot,rem_copy))
(\(x,y,quot,y_quot,rem_copy) -> do
rem_copy <- qc_uncopy_fun rem_copy rem
return ((x,y,quot,y_quot,rem_copy),()))
return (x,y,quot)
q_div_unsigned_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit], [Qubit], [Qubit])
q_div_unsigned_qulist x' y' = do
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
(x, y, q) <- q_div_unsigned x y
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
let q' = list_of_xint_bh q
return (x', y', q')
q_div :: QDInt -> QDInt -> Circ (QDInt, QDInt, QDInt)
q_div x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(x', y', q') <- q_div_qulist x' y'
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
let q = xint_of_list_bh q'
return (x, y, q)
q_div_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit], [Qubit], [Qubit])
q_div_qulist [] [] = return ([], [], [])
q_div_qulist (x_high:x_lower) y = do
with_ancilla_init False (\fake_x_high -> do
x_lower <- mapUnary qnot x_lower `controlled` x_high
let x' = fake_x_high:x_lower
(x',y,quot) <- q_div_unsigned_qulist x' y
let fake_x_high:x_lower = x'
x_lower <- mapUnary qnot x_lower `controlled` x_high
quot <- mapUnary qnot quot `controlled` x_high
return (x_high:x_lower, y, quot))
q_div_qulist _ _ = error "q_div: arguments must have same length."
q_quot :: QDInt -> QDInt -> Circ (QDInt, QDInt, QDInt)
q_quot x y = do
let x' = list_of_xint_bh x
let y' = list_of_xint_bh y
(x', y', q') <- q_quot_qulist x' y'
let x = xint_of_list_bh x'
let y = xint_of_list_bh y'
let q = xint_of_list_bh q'
return (x, y, q)
q_quot_qulist :: [Qubit] -> [Qubit] -> Circ ([Qubit], [Qubit], [Qubit])
q_quot_qulist [] [] = return ([], [], [])
q_quot_qulist (x_high:x_lower) y = do
with_ancilla_init False (\fake_x_high -> do
x_lower <- q_negate_in_place_qulist x_lower `controlled` x_high
let x' = fake_x_high:x_lower
(x',y,quot) <- q_div_unsigned_qulist x' y
let fake_x_high:x_lower = x'
x_lower <- q_negate_in_place_qulist x_lower `controlled` x_high
quot <- q_negate_in_place_qulist quot `controlled` x_high
return (x_high:x_lower, y, quot))
q_quot_qulist _ _ = error "q_quot: arguments must have same length."
q_div_exact_unsigned :: QDInt -> QDInt -> Circ (QDInt, QDInt,QDInt)
q_div_exact_unsigned x y = do
(x,y,quot,rem) <- q_divrem_unsigned x y
qterm 0 rem
return (x,y,quot)
q_div_exact :: QDInt -> QDInt -> Circ (QDInt, QDInt,QDInt)
q_div_exact x y = do
(x,(y,quot)) <- with_computed_fun x
(\x -> do
(x,x_neg) <- q_negative x
x' <- q_negate_in_place x `controlled` x_neg
return (x',x_neg))
(\(x',x_neg) -> do
(x',y,quot) <- q_div_exact_unsigned x' y
quot <- q_negate_in_place quot `controlled` x_neg
return ((x',x_neg),(y,quot)))
return (x,y,quot)
class (QData qa) => QNum qa where
q_add :: qa -> qa -> Circ (qa,qa,qa)
q_mult :: qa -> qa -> Circ (qa,qa,qa)
q_sub :: qa -> qa -> Circ (qa,qa,qa)
q_abs :: qa -> Circ (qa,qa)
q_negate :: qa -> Circ (qa,qa)
q_signum :: qa -> Circ (qa,qa)
q_fromQDInt :: QDInt -> Circ (QDInt,qa)
instance QNum QDInt where
q_add = q_add_qdint
q_mult = q_mult_qdint
q_sub = q_sub_qdint
q_abs = q_abs_qdint
q_negate = q_negate_qdint
q_signum = q_signum_qdint
q_fromQDInt = qc_copy_fun
q_ext_euclid :: QDInt -> QDInt -> Circ (QDInt,QDInt,QDInt,QDInt,QDInt)
q_ext_euclid a b = do
let l = common_length "q_ext_euclid: inputs must have equal length" [a,b]
((a,b),(x,y)) <- with_computed_fun (a,b) (\(a,b) -> do
x0 <- qinit (intm l 1)
y0 <- qinit (intm l 0)
x1 <- qinit (intm l 0)
y1 <- qinit (intm l 1)
done_yet <- qinit False
x_final <- qinit (intm l 0)
y_final <- qinit (intm l 0)
(stuff1, stuff2, stuff3, (done_yet, x_final, y_final))
<- loopM (euclid_bound l) ((a,b,x0,x1,y0,y1),[],[],(done_yet,x_final,y_final))
(\((a_i, a_i1, x_i, x_i1, y_i, y_i1), quots_scratch, tests_scratch, (done_yet, x_final, y_final)) -> do
(a_i2, a_i1, q_i) <- q_moddiv_unsigned_in_place a_i a_i1
((x_i1, y_i1, q_i), (x_i2, y_i2)) <- with_computed_fun
(x_i1, y_i1, q_i)
(\(x_i1, y_i1, q_i) -> do
(q_i, x_i1, qx) <- q_mult q_i x_i1
(q_i, y_i1, qy) <- q_mult q_i y_i1
return (x_i1, y_i1, q_i, qx, qy))
(\(x_i1, y_i1, q_i, qx, qy) -> do
(qx,x_i2) <- q_sub_in_place qx x_i
(qy,y_i2) <- q_sub_in_place qy y_i
return ((x_i1, y_i1, q_i, qx, qy),(x_i2,y_i2)))
done_this_time <- qinit False
done_this_time <- qnot done_this_time `controlled` (a_i2 .==. 0) .&&. (done_yet .==. False)
(x_i1,x_final) <- controlled_not x_final x_i1 `controlled` done_this_time
(y_i1,y_final) <- controlled_not y_final y_i1 `controlled` done_this_time
done_yet <- qnot done_yet `controlled` done_this_time
return ((a_i1, a_i2, x_i1, x_i2, y_i1, y_i2),
(q_i:quots_scratch), (done_this_time:tests_scratch),
(done_yet, x_final, y_final)))
qterm True done_yet
return (x_final,y_final,(stuff1, stuff2, stuff3)))
(\(x_final, y_final, stuff) -> do
(x_final,x) <- qc_copy_fun x_final
(y_final,y) <- qc_copy_fun y_final
return ((x_final, y_final, stuff),(x,y)))
((a,b,x,y),gcd) <- with_computed_fun
(a,b,x,y)
(\(a,b,x,y) -> do
(a,x,ax) <- q_mult a x
(b,y,by) <- q_mult b y
return (a,b,x,y,ax,by))
(\(a,b,x,y,ax,by) -> do
(ax,by,gcd) <- q_add ax by
return ((a,b,x,y,ax,by),gcd))
return (a,b,x,y,gcd)
where
euclid_bound :: Int -> Int
euclid_bound l = 2 + ceiling ( (fromIntegral l) / (logBase 2 phi) )
phi = (1+sqrt(5))/2
template_symb_plus_ :: (QNum qa) => Circ (qa -> Circ (qa -> Circ qa))
template_symb_plus_ = return $ \qx -> return $ \qy -> do (qx,qy,qz) <- q_add qx qy; return qz