{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Algorithms/CL/Types.hs" #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Quipper.Algorithms.CL.Types where
import Quipper
import Quipper.Internal
import Data.Typeable
import Data.Ratio
import Quipper.Libraries.Arith hiding (q_mult_param)
import Quipper.Libraries.FPReal
import Quipper.Algorithms.CL.Auxiliary
type CLInt = IntM
type CLIntP = Integer
type CLRational = Rational
type CLReal = FPReal
bigD_of_d :: Integral a => a -> a
bigD_of_d d = case (d `mod` 4) of
1 -> d
_ -> 4*d
d_of_bigD :: Integral a => a -> a
d_of_bigD bigD = case (bigD `mod` 4) of
0 -> bigD `div` 4
_ -> bigD
is_valid_d :: (Integral a) => a -> Bool
is_valid_d d = d > 1 && is_square_free d
is_valid_bigD :: (Integral a) => a -> Bool
is_valid_bigD bigD = bigD > 1 && case (bigD `mod` 4) of
1 -> is_square_free bigD
0 -> (d `mod` 4 == 2 || d `mod` 4 == 3) && is_square_free d
where d = bigD `div` 4
_ -> False
all_small_ds :: (Integral int) => [int]
all_small_ds = filter (\n -> is_valid_d n) [2..]
all_bigDs :: (Integral int) => [int]
all_bigDs = map bigD_of_d all_small_ds
data AlgNumGen a = AlgNum a a CLIntP | AlgNum_indet a deriving (Show)
type AlgNum = AlgNumGen CLRational
fst_AlgNum :: AlgNumGen a -> a
fst_AlgNum (AlgNum u _ _) = u
fst_AlgNum (AlgNum_indet u) = u
snd_AlgNum :: (Num a) => AlgNumGen a -> a
snd_AlgNum (AlgNum _ v _) = v
snd_AlgNum (AlgNum_indet _) = 0
instance (Eq a, Num a) => Eq (AlgNumGen a) where
(AlgNum a b bigD) == (AlgNum a' b' bigD') =
if bigD == bigD' then a == a' && b == b'
else error "Operation = on AlgNum: operands must have same Δ."
(AlgNum a b bigD) == (AlgNum_indet a') = (AlgNum a b bigD) == (AlgNum a' 0 bigD)
(AlgNum_indet a) == (AlgNum a' b' bigD') = (AlgNum a 0 bigD') == (AlgNum a' b' bigD')
(AlgNum_indet a) == (AlgNum_indet a') = a == a'
pretty_show_AlgNum :: Show a => AlgNumGen a -> String
pretty_show_AlgNum (AlgNum a b bigD) = (show a) ++ " + " ++ (show b) ++ " √" ++ show bigD
pretty_show_AlgNum (AlgNum_indet a) = show a
floating_of_AlgNum :: (Real a, Floating b) => AlgNumGen a -> b
floating_of_AlgNum (AlgNum a b bigD) = (realToFrac a) + (realToFrac b) * (sqrt $ fromIntegral bigD)
floating_of_AlgNum (AlgNum_indet a) = (realToFrac a)
number_promote :: Num a => AlgNumGen a -> AlgNumGen b -> ErrMsg -> AlgNumGen a
number_promote (AlgNum a b bigD) (AlgNum _ _ bigD') e =
if bigD == bigD' then AlgNum a b bigD
else error $ e "mismatched Δ."
number_promote (AlgNum_indet a) (AlgNum _ _ bigD') _ = AlgNum a 0 bigD'
number_promote n (AlgNum_indet _) _ = n
instance (Ord a, Num a) => Ord (AlgNumGen a) where
compare (AlgNum a b bigD) (AlgNum a' b' bigD') =
if bigD == bigD' then
case (compare a a', compare b b') of
(EQ,y) -> y
(x,EQ) -> x
(GT,GT) -> GT
(LT,LT) -> LT
(GT,LT) -> compare ((a-a')^2) ((b-b')^2 * fromInteger bigD)
(LT,GT) -> compare ((b-b')^2 * fromInteger bigD) ((a-a')^2)
else
error "compare // AlgNumGen: mismatched Δ."
compare (AlgNum a b bigD) (AlgNum_indet a') = compare (AlgNum a b bigD) (AlgNum a' 0 bigD)
compare (AlgNum_indet a) (AlgNum a' b' bigD') = compare (AlgNum a 0 bigD') (AlgNum a' b' bigD')
compare (AlgNum_indet a) (AlgNum_indet a') = compare a a'
instance (Ord a, Num a) => Num (AlgNumGen a) where
(AlgNum a b bigD) + (AlgNum a' b' bigD') =
if bigD == bigD' then AlgNum (a+a') (b+b') bigD
else error "Operation + on AlgNum: operands must have same Δ."
(AlgNum a b bigD) + (AlgNum_indet a') = (AlgNum a b bigD) + (AlgNum a' 0 bigD)
(AlgNum_indet a) + (AlgNum a' b' bigD') = (AlgNum a 0 bigD') + (AlgNum a' b' bigD')
(AlgNum_indet a) + (AlgNum_indet a') = (AlgNum_indet (a + a'))
(AlgNum a b bigD) * (AlgNum a' b' bigD') =
if bigD == bigD' then AlgNum (a*a' + b*b'*(fromIntegral bigD)) (a*b' + a'*b) bigD
else error "Operation * on AlgNum: operands must have same Δ."
(AlgNum a b bigD) * (AlgNum_indet a') = (AlgNum a b bigD) * (AlgNum a' 0 bigD)
(AlgNum_indet a) * (AlgNum a' b' bigD') = (AlgNum a 0 bigD') * (AlgNum a' b' bigD')
(AlgNum_indet a) * (AlgNum_indet a') = (AlgNum_indet (a * a'))
(AlgNum a b bigD) - (AlgNum a' b' bigD') =
if bigD == bigD' then AlgNum (a-a') (b-b') bigD
else error "Operation - on AlgNum: operands must have same Δ."
(AlgNum a b bigD) - (AlgNum_indet a') = (AlgNum a b bigD) - (AlgNum a' 0 bigD)
(AlgNum_indet a) - (AlgNum a' b' bigD') = (AlgNum a 0 bigD') - (AlgNum a' b' bigD')
(AlgNum_indet a) - (AlgNum_indet a') = (AlgNum_indet (a - a'))
abs n = if (n >= 0) then n else -n
signum n = number_promote (if n > 0 then 1 else if n == 0 then 0 else (-1)) n
(const "CL.Types: internal error (signum // AlgNum)")
fromInteger = AlgNum_indet . fromInteger
instance (Real a) => Real (AlgNumGen a) where
toRational = toRational . floating_of_AlgNum
instance (Ord a, Fractional a) => Fractional (AlgNumGen a) where
fromRational = AlgNum_indet . fromRational
recip (AlgNum a b bigD) =
let c = (a^2) - (b^2 * (fromIntegral bigD))
in assert (c /= 0) (if (a == 0 && b == 0) then "CL.Types: divide-by-zero error"
else if is_valid_bigD bigD then "CL.Types: internal error (AlgNum // recip)"
else error "CL.Types: " ++ show bigD ++ " not a valid discriminant")
(AlgNum (a/c) (-b/c) bigD)
recip (AlgNum_indet a) = AlgNum_indet $ recip a
instance (RealFrac a) => RealFrac (AlgNumGen a) where
properFraction x = (x',x - fromIntegral x')
where x' = truncate $ floating_of_AlgNum x
conjugate :: (Num a) => AlgNumGen a -> AlgNumGen a
conjugate (AlgNum a b bigD) = (AlgNum a (-b) bigD)
conjugate (AlgNum_indet a) = (AlgNum_indet a)
is_alg_int :: (Ord a, RealFrac a) => AlgNumGen a -> Bool
is_alg_int (AlgNum a b bigD) = is_int n && is_int m
where
n = 2 * b
m = a - b * fromIntegral bigD
is_alg_int (AlgNum_indet a) = is_int a
is_unit :: (Ord a, RealFrac a) => AlgNumGen a -> Bool
is_unit n = if n == 0 then False else (is_alg_int n) && (is_alg_int (recip n))
omega_of_bigD :: CLIntP -> AlgNum
omega_of_bigD bigD =
if (bigD `mod` 4 == 1)
then (AlgNum (1/2) (1/2) bigD)
else (AlgNum 0 1 bigD)
data IdealX x = Ideal CLIntP (XInt x) (XInt x) (XInt x) (XInt x)
deriving (Show, Eq, Typeable)
type Ideal = IdealX Bool
type IdealQ = IdealX Qubit
type IdealC = IdealX Bit
type instance QCType x y (IdealX z) = IdealX (QCType x y z)
type instance QTypeB Ideal = IdealQ
instance Show Ideal where
show (Ideal bigD m l a b) =
"Ideal "
++ show bigD ++ " "
++ show m ++ " "
++ show l ++ " "
++ show a ++ " "
++ show b
instance QCLeaf x => QCData (IdealX x) where
qcdata_mapM ~(Ideal _ msh lsh ash bsh) f g (Ideal bigD m l a b) = do
m' <- qcdata_mapM msh f g m
l' <- qcdata_mapM lsh f g l
a' <- qcdata_mapM ash f g a
b' <- qcdata_mapM bsh f g b
return (Ideal bigD m' l' a' b')
qcdata_zip ~(Ideal _ msh lsh ash bsh) q c q' c' (Ideal bigD m l a b) (Ideal bigD' m' l' a' b') e
| bigD /= bigD'
= error (e "Ideal exponent mismatch")
| otherwise
= (Ideal bigD m'' l'' a'' b'')
where
m'' = qcdata_zip msh q c q' c' m m' errmsg
l'' = qcdata_zip lsh q c q' c' l l' errmsg
a'' = qcdata_zip ash q c q' c' a a' errmsg
b'' = qcdata_zip bsh q c q' c' b b' errmsg
errmsg x = e ("in Ideal: " ++ x)
qcdata_promote (Ideal bigD m l a b) (Ideal bigD' m' l' a' b') e
| bigD /= bigD'
= error (e "Ideal exponent mismatch")
| otherwise
= (Ideal bigD m'' l'' a'' b'')
where
m'' = qcdata_promote m m' errmsg
l'' = qcdata_promote l l' errmsg
a'' = qcdata_promote a a' errmsg
b'' = qcdata_promote b b' errmsg
errmsg x = e ("in Ideal: " ++ x)
instance QCLeaf x => Labelable (IdealX x) String where
label_rec (Ideal _ qm ql qa qb) s = do
label_rec qm s `dotted_indexed` "m"
label_rec ql s `dotted_indexed` "l"
label_rec qa s `dotted_indexed` "a"
label_rec qb s `dotted_indexed` "b"
instance Labelable IdealQ (String, String, String, String) where
label_rec (Ideal _ qm ql qa qb) (sm, sl, sa, sb) = do
label_rec qm sm
label_rec ql sl
label_rec qa sa
label_rec qb sb
instance Eq Ideal where
i1@(Ideal bigD m l a b) == i2@(Ideal bigD' m' l' a' b')
= if (bigD /= bigD')
then error error_string
else (m == m' && l' == l' && a == a' && b == b')
where error_string = "Comparing two ideals of different Δ: " ++ (show i1) ++ "," ++ (show i2)
data IdealRedX x = IdealRed CLIntP (XInt x) (XInt x)
deriving (Show, Typeable)
type IdealRed = IdealRedX Bool
type IdealRedQ = IdealRedX Qubit
type IdealRedC = IdealRedX Bit
instance Show IdealRed where
show (IdealRed bigD a b) =
"IdealRed "
++ show bigD ++ " "
++ show a ++ " "
++ show b
instance Eq IdealRed where
i1@(IdealRed bigD a b) == i2@(IdealRed bigD' a' b')
= if (bigD /= bigD')
then error error_string
else (a == a' && b == b')
where error_string = "Comparing two reduced ideals of different Δ: "
++ (show i1) ++ "," ++ (show i2)
type instance QCType x y (IdealRedX z) = IdealRedX (QCType x y z)
type instance QTypeB IdealRed = IdealRedQ
instance QCLeaf x => QCData (IdealRedX x) where
qcdata_mapM ~(IdealRed _ ash bsh) f g (IdealRed bigD a b) = do
a' <- qcdata_mapM ash f g a
b' <- qcdata_mapM bsh f g b
return (IdealRed bigD a' b')
qcdata_zip ~(IdealRed _ ash bsh) q c q' c' (IdealRed bigD a b) (IdealRed bigD' a' b') e
| bigD /= bigD'
= error (e "IdealRed exponent mismatch")
| otherwise
= (IdealRed bigD a'' b'')
where
a'' = qcdata_zip ash q c q' c' a a' errmsg
b'' = qcdata_zip bsh q c q' c' b b' errmsg
errmsg x = e ("in IdealRed: " ++ x)
qcdata_promote (IdealRed bigD a b) (IdealRed bigD' a' b') e
| bigD /= bigD'
= error (e "IdealRed exponent mismatch")
| otherwise
= (IdealRed bigD a'' b'')
where
a'' = qcdata_promote a a' errmsg
b'' = qcdata_promote b b' errmsg
errmsg x = e ("in IdealRed: " ++ x)
instance QCLeaf x => Labelable (IdealRedX x) String where
label_rec (IdealRed _ qa qb) s = do
label_rec qa s `dotted_indexed` "a"
label_rec qb s `dotted_indexed` "b"
instance QCLeaf x => Labelable (IdealRedX x) (String, String) where
label_rec (IdealRed _ qa qb) (sa, sb) = do
label_rec qa sa
label_rec qb sb
type IdDist = (Ideal,FPReal)
type IdDistQ = (IdealQ,FPRealQ)
type IdRedDist = (IdealRed,FPReal)
type IdRedDistQ = (IdealRedQ,FPRealQ)
d_of_Ideal :: IdealX a -> CLIntP
d_of_Ideal (Ideal bigD _ _ _ _) = d_of_bigD bigD
d_of_IdealRed :: IdealRedX a -> CLIntP
d_of_IdealRed (IdealRed bigD _ _) = d_of_bigD bigD
bigD_of_Ideal :: IdealX a -> CLIntP
bigD_of_Ideal (Ideal bigD _ _ _ _) = bigD
bigD_of_IdealRed :: IdealRedX a -> CLIntP
bigD_of_IdealRed (IdealRed bigD _ _) = bigD
delta :: IdDist -> CLReal
delta (Ideal _ _ _ _ _, del) = del
tau :: (Integral int, Integral int') => int' -> int -> int -> int
tau bigD b a = mod_with_max b (2*a) max
where
max = if a > root_bigD then a else root_bigD
root_bigD = floor $ sqrt $ fromIntegral bigD
is_standard :: Ideal -> Bool
is_standard (Ideal bigD m l a b) =
(a > 0) && (l > 0) && (m > 0)
&& ((bigD - (fromIntegral b)^2) `mod` (4 * (fromIntegral a)) == 0)
&& b == tau bigD b a
is_reduced :: Ideal -> Bool
is_reduced (Ideal bigD m l a b) = (m == 1) && (l == a) && (b >= 0) && (b + root_bigD > 2 * a)
where root_bigD = ceiling $ sqrt $ fromIntegral bigD
is_really_reduced :: IdealRed -> Bool
is_really_reduced (IdealRed bigD a b) = (b >= 0) && (b + root_bigD > 2 * a)
where root_bigD = ceiling $ sqrt $ fromIntegral bigD
forget_reduced :: IdealRed -> Ideal
forget_reduced (IdealRed bigD a b) = (Ideal bigD 1 a a b)
to_reduced :: Ideal -> IdealRed
to_reduced ii@(Ideal bigD m l a b) =
if is_reduced ii then (IdealRed bigD a b)
else error $ "to_reduced: (" ++ (show ii) ++ ") is not reduced."
assert_reduced :: Ideal -> a -> a
assert_reduced ii =
assert (is_reduced ii) ("assert_reduced: (" ++ (show ii) ++ ") is not reduced.")
assert_really_reduced :: IdealRed -> a -> a
assert_really_reduced ii =
assert (is_really_reduced ii) ("assert_really_reduced: (" ++ (show ii) ++ ") is not reduced.")
q_tau :: CLIntP -> QDInt -> QDInt -> Circ (QDInt, QDInt, QDInt)
q_tau bigD = box ("tau, Δ = " ++ show bigD) $ \a b -> do
let root_bigD = floor $ sqrt $ fromIntegral bigD
t <- with_computed
(do
(_, a_gt_rtD) <- q_gt_param a root_bigD
max <- qinit $ qc_false a
(max, _) <- controlled_not max a `controlled` a_gt_rtD
max <- bool_controlled_not max (intm_promote root_bigD max "q_tau: internal error") `controlled` (a_gt_rtD .==. False)
(_, twice_a) <- q_mult_param 2 a
(_, _, _, t) <- q_mod_with_max b twice_a max
return t)
qc_copy
return (a,b,t)
q_is_reduced :: IdealQ -> Circ (IdealQ,Qubit)
q_is_reduced = box "is_reduced" $ \qii ->
let bigD = bigD_of_Ideal qii in
with_computed_fun qii
(\(Ideal bigD qm ql qa qb) -> do
test1 <- qinit False
test1 <- qnot test1 `controlled` qm .==. 1
(ql,qa,test2) <- q_is_equal ql qa
(qb,test3) <- q_ge_param qb 0
(qa, q2a) <- q_mult_param 2 qa
qx <- q_sub_param_in_place (ceiling $ sqrt $ fromIntegral bigD) q2a
(qb, qx, test4) <- q_gt qb qx
return ([test1,test2,test3,test4], (qm,ql,qa,qb,qx)))
(\(tests, rest) -> do
test_out <- qinit False
test_out <- qnot test_out `controlled` tests
return ((tests, rest), test_out))
q_is_really_reduced :: IdealRedQ -> Circ (IdealRedQ,Qubit)
q_is_really_reduced = box "is_really_reduced" $ \qii ->
let bigD = bigD_of_IdealRed qii in
with_computed_fun qii
(\(IdealRed bigD qa qb) -> do
(qb,test1) <- q_ge_param qb 0
(qa, q2a) <- q_mult_param 2 qa
qx <- q_sub_param_in_place (ceiling $ sqrt $ fromIntegral bigD) q2a
(qb, qx, test2) <- q_gt qb qx
return ([test1,test2], (qa,qb,qx)))
(\(tests, rest) -> do
test_out <- qinit False
test_out <- qnot test_out `controlled` tests
return ((tests, rest), test_out))
q_forget_reduced :: IdealRedQ -> Circ IdealQ
q_forget_reduced = box "forget_reduced" $ \(IdealRed bigD a b) -> do
let a_bits = qulist_of_qdint_bh a
n = length a_bits
m <- qinit (intm n 1)
(a,l) <- qc_copy_fun a
return (Ideal bigD m l a b)
q_assert_reduced :: IdealQ -> Circ IdealRedQ
q_assert_reduced = box "assert_reduced" $ \x@(Ideal bigD m l a b) -> do
x_red <- reverse_generic q_forget_reduced (IdealRed bigD a b) x
q_assert_really_reduced x_red
q_assert_really_reduced :: IdealRedQ -> Circ IdealRedQ
q_assert_really_reduced = box "assert_really_reduced" $ \ii -> do
(ii,test) <- q_is_really_reduced ii
qterm True test
return ii
length_for_ab :: CLIntP -> Int
length_for_ab bigD = 3 + (ceiling $ logBase 2 $ fromIntegral bigD)
length_for_ml :: CLIntP -> Int
length_for_ml = length_for_ab
n_of_bigD :: (Integral int) => CLIntP -> int
n_of_bigD bigD =
ceiling $ logBase 2 $ 32 * (fromIntegral bigD) * (log $ fromIntegral bigD) / 3
precision_for_fN :: CLIntP -> Int -> Int -> Int
precision_for_fN _ n l = 2 * (n + l)
fix_sizes_Ideal :: Ideal -> Ideal
fix_sizes_Ideal (Ideal bigD m l a b) = (Ideal bigD (f m) (f l) (f a) (f b))
where
f x = intm_promote x (intm n 0) "set_sizes_Ideal: lengths already fixed incompatibly"
n = max (length_for_ml bigD) (length_for_ab bigD)
fix_sizes_IdealRed :: IdealRed -> IdealRed
fix_sizes_IdealRed (IdealRed bigD a b) = (IdealRed bigD (f a) (f b))
where
f x = intm_promote x (intm n 0) "set_sizes_Ideal: lengths already fixed incompatibly"
n = max (length_for_ml bigD) (length_for_ab bigD)