{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Algorithms/QLS/QDouble.hs" #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Quipper.Algorithms.QLS.QDouble where
import qualified Data.Ratio as Ratio
import Data.Typeable
import Quipper
import Quipper.Internal
import Quipper.Libraries.Arith
import Quipper.Libraries.Simulation
import Quipper.Algorithms.QLS.Utils
import Quipper.Algorithms.QLS.QSignedInt
import Quipper.Utils.Auxiliary (getId, mmap)
data XDouble x = XDouble Int (SignedInt x)
deriving (Show, Typeable)
type FDouble = XDouble Bool
type QDouble = XDouble Qubit
type CDouble = XDouble Bit
integer_power :: Int -> Int -> Integer
integer_power x y = (fromIntegral x) ^ y
double_power :: Int -> Int -> Double
double_power x y
| y >= 0 = (fromIntegral x) ^ y
| otherwise = 1 / ((fromIntegral x) ^ (-y))
div_round :: Integer -> Integer -> Integer
div_round x y = round (x Ratio.% y)
xdouble_exponent :: XDouble x -> Int
xdouble_exponent (XDouble k _) = k
xdouble_length :: XDouble x -> Int
xdouble_length (XDouble _ n) = sint_length n
xdouble_extent :: XDouble x -> (Int, Int)
xdouble_extent x = (m-k, -k) where
m = xdouble_length x
k = xdouble_exponent x
xdouble_pad_left :: (Monad m) => m x -> Int -> XDouble x -> m (XDouble x)
xdouble_pad_left zero n (XDouble k (SInt digits s)) = do
pad <- sequence $ replicate n zero
let digits' = pad ++ digits
return $ XDouble k (SInt (digits') s)
xdouble_pad_right :: (Monad m) => m x -> Int -> XDouble x -> m (XDouble x)
xdouble_pad_right zero n (XDouble k (SInt digits s)) = do
pad <- sequence $ replicate n zero
let digits' = digits ++ pad
return $ XDouble (k+n) (SInt (digits') s)
xdouble_pad_to_extent :: (Monad m) => m x -> (Int, Int) -> XDouble x -> m (XDouble x)
xdouble_pad_to_extent zero (hi, lo) x
| lo <= lo_x && hi_x <= hi
= xdouble_pad_left zero (hi - hi_x) =<< xdouble_pad_right zero (lo_x - lo) x
| otherwise
= error "qdouble_pad_to_extent: bad extent"
where
(hi_x, lo_x) = xdouble_extent x
xdouble_truncate_right :: Int -> QDouble -> QDouble
xdouble_truncate_right n (XDouble k (SInt digits s)) = (XDouble k' (SInt digits' s))
where
k' = k - n
digits' | length digits >= n = reverse $ drop n $ reverse digits
| otherwise = error "xdouble_truncate_right"
xdouble_of_sint :: SignedInt x -> XDouble x
xdouble_of_sint n = XDouble 0 n
qdouble_pad_left :: Int -> QDouble -> Circ QDouble
qdouble_pad_left = xdouble_pad_left (qinit False)
qdouble_pad_right :: Int -> QDouble -> Circ QDouble
qdouble_pad_right = xdouble_pad_right (qinit False)
qdouble_pad_to_extent :: (Int, Int) -> QDouble -> Circ QDouble
qdouble_pad_to_extent = xdouble_pad_to_extent (qinit False)
qdouble_truncate_right :: Int -> QDouble -> QDouble
qdouble_truncate_right = xdouble_truncate_right
fdouble_pad_right :: Int -> FDouble -> FDouble
fdouble_pad_right k x = getId $ xdouble_pad_right (return False) k x
fdouble_pad_to_extent :: (Int, Int) -> FDouble -> FDouble
fdouble_pad_to_extent extent x = getId $ xdouble_pad_to_extent (return False) extent x
fdouble_of_double :: Int -> Int -> Double -> FDouble
fdouble_of_double k m x
| abs n >= integer_power 2 m
= error "fdouble_of_double: number too large"
| otherwise
= XDouble k (fsint_of_integer m n)
where
d = double_power 2 k
n = round (d * x)
double_of_fdouble :: FDouble -> Double
double_of_fdouble (XDouble k n) = (fromIntegral x) / (double_power 2 k)
where
x = integer_of_fsint n
fdouble_of_fsint :: FSignedInt -> FDouble
fdouble_of_fsint = xdouble_of_sint
fdouble_of_integer :: Int -> Int -> Integer -> FDouble
fdouble_of_integer k m a = XDouble k (fsint_of_integer m a)
fdouble :: Double -> FDouble
fdouble x = fromRational $ toRational x
show_fdouble :: FDouble -> String
show_fdouble x@(XDouble k (SInt digits s)) = sign ++ binary ++ " (" ++ (show float) ++ ")"
where
float = double_of_fdouble x
sign = if s then "-" else "+"
m = length digits
binary_full = [ if h then '1' else '0' | h <- digits ]
binary | k < 0 = binary_full ++ "e" ++ show (-k)
| k > m = "." ++ binary_full ++ "e" ++ show (m-k)
| otherwise = binary1 ++ "." ++ binary2
(binary1,binary2) = splitAt ((fromIntegral m) - k) binary_full
fdouble_align :: FDouble -> FDouble -> (Int, FSignedInt, FSignedInt)
fdouble_align (XDouble h m) (XDouble k n)
| h <= k = (k, fsint_shift (k-h) m, n)
| otherwise = (h, m, fsint_shift (h-k) n)
instance Eq FDouble where
x == y = m == n where (k,m,n) = fdouble_align x y
instance Ord FDouble where
compare x y = compare m n where (k,m,n) = fdouble_align x y
instance Real FDouble where
toRational (XDouble h n)
| h >= 0 = (Ratio.%) nx (integer_power 2 h)
| otherwise = fromInteger (nx * integer_power 2 (-h))
where
nx = integer_of_fsint n
instance Num FDouble where
x + y = XDouble k (m + n) where (k,m,n) = fdouble_align x y
x - y = XDouble k (m - n) where (k,m,n) = fdouble_align x y
abs x = XDouble k (abs m) where XDouble k m = x
signum x = fdouble_of_fsint (signum m) where XDouble k m = x
fromInteger = fdouble_pad_right after_radix_length . fdouble_of_fsint . fromInteger
x * y | k >= 0 = fdouble_of_integer k len (a*b `div_round` integer_power 2 k)
| otherwise = fdouble_of_integer k len (a*b * integer_power 2 (-k))
where
(k,m,n) = fdouble_align x y
a = integer_of_fsint m
b = integer_of_fsint n
len = max (sint_length m) (sint_length n)
instance Fractional FDouble where
x / y | k >= 0 = fdouble_of_integer k len ((a * integer_power 2 k) `div_round` b)
| otherwise = fdouble_of_integer k len (a `div_round` (b * integer_power 2 (-k)))
where
(k,m,n) = fdouble_align x y
a = integer_of_fsint m
b = integer_of_fsint n
len = max (sint_length m) (sint_length n)
fromRational x = fdouble_of_double before_radix_length (before_radix_length+after_radix_length) ((fromInteger $ Ratio.numerator x) / (fromInteger $ Ratio.denominator x))
instance RealFrac FDouble where
properFraction x
| k <= 0 = (0, x)
| otherwise = (fromInteger q, fdouble_of_integer k len r)
where
XDouble k m = x
a = integer_of_fsint m
len = sint_length m
(q, r) = a `quotRem` integer_power 2 k
type instance QCType x y (XDouble z) = XDouble (QCType x y z)
type instance QTypeB FDouble = QDouble
instance QCLeaf x => QCData (XDouble x) where
qcdata_mapM ~(XDouble _ shape) f g (XDouble n xs) =
mmap (XDouble n) $ qcdata_mapM shape f g xs
qcdata_zip ~(XDouble _ shape) q c q' c' (XDouble n xs) (XDouble m ys) e
| n == m
= XDouble n $ qcdata_zip shape q c q' c' xs ys (const $ e "XDouble length mismatch")
| otherwise
= error (e "XDouble exponent mismatch")
qcdata_promote (XDouble n b) (XDouble m q) e
| n == m
= XDouble n $ qcdata_promote b q (const $ e "XDouble length mismatch")
| otherwise
= error (e "XDouble exponent mismatch")
instance QCLeaf x => Labelable (XDouble x) String where
label_rec (XDouble k (SInt digits sign)) s = do
label_rec sign s `dotted_indexed` "sign"
sequence_ [ label_rec d s `indexed` show i | (d,i) <- zip rdigits [-k,-k+1..] ]
where
rdigits = reverse digits
instance CircLiftingUnpack (Circ QDouble) (Circ QDouble) where
pack x = x
unpack x = x
qdouble_of_qsint :: QSignedInt -> Circ QDouble
qdouble_of_qsint x = do
(_,y) <- qc_copy_fun x
return $ xdouble_of_sint y
instance QOrd QDouble where
q_less x y | kx < ky = do
x <- qdouble_pad_right (ky-kx) x
compare_right x y
| kx > ky = do
y <- qdouble_pad_right (kx-ky) y
compare_right x y
| otherwise = compare_right x y
where
kx = xdouble_exponent x
ky = xdouble_exponent y
compare_right :: QDouble -> QDouble -> Circ Qubit
compare_right (XDouble _ n) (XDouble _ m) = q_less n m
qdouble_align :: QDouble -> QDouble -> Circ (Int, QSignedInt, QSignedInt)
qdouble_align (XDouble h m) (XDouble k n)
| h <= k = do
m <- qsint_shift (k-h) m
return (k, m, n)
| otherwise = do
n <- qsint_shift (h-k) n
return (k, m, n)
instance QNum QDouble where
q_add x y = do
(k,m,n) <- qdouble_align x y
(_, _, r) <- q_add m n
return (x, y, XDouble k r)
q_sub x y = do
(k,m,n) <- qdouble_align x y
(_, _, r) <- q_sub m n
return (x, y, XDouble k r)
q_abs x = do
let XDouble k m = x
(_, r) <- q_abs m
return (x, XDouble k r)
q_negate x = do
let XDouble k m = x
(_, r) <- q_negate m
return (x, XDouble k r)
q_signum x = do
let XDouble k m = x
(_, r) <- q_signum m
y <- qdouble_of_qsint r
return (x, y)
q_fromQDInt x = do
(_,y) <- q_fromQDInt x
z <- qdouble_of_qsint y
w <- qdouble_pad_right after_radix_length z
return (x,w)
q_mult x y = let m = max (xdouble_exponent x) (xdouble_exponent y) in
let s = (xdouble_exponent x) + (xdouble_exponent y) in
do
ext_x <- qdouble_pad_left m x
ext_y <- qdouble_pad_left m y
let XDouble kx nx = ext_x
let XDouble ky ny = ext_y
(_,_,nz) <- q_mult nx ny
let z = XDouble s nz
return (x,y,qdouble_truncate_right (s-m) z)
instance Eq QDouble where
XDouble a b == XDouble a' b' = (a,b) == (a',b')
instance Eq QSignedInt where
(SInt b c) == (SInt b' c') = (b,c) == (b',c')
q_fromIntegral :: QSignedInt -> Circ QDouble
q_fromIntegral x = do
x' <- qsint_shift after_radix_length x
return $ XDouble after_radix_length x'
q_ceiling :: QDouble -> Circ QSignedInt
q_ceiling (XDouble k (SInt x b)) = return $ SInt (reverse . drop k . reverse $ x) b
q_div_real :: QDouble -> QDouble -> Circ QDouble
q_div_real (XDouble kx (SInt x bx)) (XDouble ky (SInt y by)) =
if (kx /= ky) then error "q_div_real"
else
let k = kx in do
pad_x <- qinit (replicate k False)
pad_y <- qinit (replicate k False)
let ext_x = x ++ pad_x
let ext_y = pad_y ++ y
(_,_,ext_z) <- q_quot (qdint_of_qulist_bh ext_x)
(qdint_of_qulist_bh ext_y)
let z = reverse $ drop k $ reverse $ qulist_of_qdint_bh ext_z
bz <- qinit False
qnot_at bz `controlled` bx
qnot_at bz `controlled` by
return (XDouble k (SInt z bz))
my_test = let x = fromRational $ toRational (12345.34) in
let y = fromRational $ toRational (323.1) in
let last (x,y,z) = z in
do
putStrLn $ show_fdouble x
putStrLn $ show_fdouble y
putStrLn $ show_fdouble $ snd $ run_classical_generic q_negate x
instance Num (FDouble,FDouble) where
x + y = undefined
x * y = undefined
x - y = undefined
fromInteger x = undefined
abs x = undefined
signum x = undefined
instance QNum (QDouble,QDouble) where
q_add (x1,x2) (y1,y2) = do
(_,_,z1) <- q_add x1 y1
(_,_,z2) <- q_add x2 y2
return ((x1,x2),(y1,y2),(z1,z2))
q_mult (x1,x2) (y1,y2) = do
(_,_,a) <- q_mult x1 y1
(_,_,b) <- q_mult x2 y2
(_,_,z1) <- q_sub a b
(_,_,c) <- q_mult x1 y2
(_,_,d) <- q_mult x2 y1
(_,_,z2) <- q_add c d
return ((x1,x2),(y1,y2),(z1,z2))
q_sub (x1,x2) (y1,y2) = do
(_,_,z1) <- q_sub x1 y1
(_,_,z2) <- q_sub x2 y2
return ((x1,x2),(y1,y2),(z1,z2))
q_abs x = do z <- qinit $ qc_false x; named_gate "abs" (x,z)
q_negate x = do z <- qinit $ qc_false x; named_gate "neg" (x,z)
q_signum x = do z <- qinit $ qc_false x; named_gate "sigNum" (x,z)
q_fromQDInt x = undefined