-- | This module implements various functions that return a probabilistic result, -- defined as unitary operators, and quantum computations. module QIO.QIORandom where import Data.Monoid as Monoid import QIO.QioSyn import QIO.Qdata import QIO.Qio import Data.Complex -- | The exponentiated Pauli-X rotation rX :: RR -> Rotation rX r (x,y) = if x==y then (cos (r/2):+0) else (0:+ (-(sin (r/2)))) -- | The exponentiated Pauli-Y rotation rY :: RR -> Rotation rY r (x,y) = if x==y then (cos (r/2):+0) else (s * sin (r/2):+0) where s = if x then 1 else -1 -- | Applies a Hadamard rotation to each qubit in the given list of qubits hadamards :: [Qbit] -> U hadamards [] = mempty hadamards (q:qs) = uhad q `mappend` hadamards qs -- | returns the highest integer power of 2 that is less than or equal to \x\ pow2 :: Int -> Int pow2 x = pow2' 0 where pow2' y | 2^(y+1) > x = 2^y | otherwise = pow2' (y+1) -- | A rotation that, given a qubit in state 0, leaves it in a super-position of -- 0 and 1, such that the probability of measuring as state 0 is \ps\. weightedU :: RR -> Qbit -> U weightedU ps q | sqrt ps <= 1 = rot q (rX (2*(acos (sqrt ps)))) | otherwise = error ("weightedU: Invalid Probability: " ++ show ps) -- | A QIO computation that uses the "weightedU" unitary, to return a Bool that -- has a probablity of \pf\ of being False. weightedBool :: RR -> QIO Bool weightedBool pf = do q <- mkQbit False applyU (weightedU pf q) measQ q -- | removes any leading Falses from a list of booleans rlf :: [Bool] -> [Bool] rlf (False:bs) = rlf bs rlf bs = bs -- | removes any leading Falses from the (big-endian) bit-wise representation -- of the given Int. rlf_l :: Int -> [Bool] rlf_l x = rlf (reverse (int2bits x)) -- | returns the number of bits left after calling the "flf_l" function rlf_n :: Int -> Int rlf_n x = length (rlf_l x) -- | Given an Int \max\ that is the largest number required to be represented in -- a quantum register, this function trims the front off the given register, to -- leave the number of qubits required to represent \max\. trim :: Int -> [Qbit] -> [Qbit] trim max qbs = drop ((length qbs)-(rlf_n max)) qbs -- | Given an Int \max\, and a quantum register in the state \max\, this function -- defines a unitary operation that will leave the quantum register in state that -- has equal probability of being measured in any of the states 0 to \max\. randomU :: Int -> [Qbit] -> U randomU max qbs = randomU' max (trim max qbs) where randomU' _ [] = mempty randomU' 0 _ = mempty randomU' max (q:qbs) = weightedU (fromIntegral ((max+1)-p)/fromIntegral (max+1)) q `mappend` condQ q (\x -> if x then (randomU (max-p) qbs) else (hadamards qbs)) where p = pow2 max -- | A quantum computation that will return a quantum integer in a state that -- has equal probabilities of being measured in any of the state 0 to \max\. randomQInt :: Int -> QIO QInt randomQInt max = do qbs <- mkQ (reverse (int2bits max)) applyU (randomU max qbs) return (QInt (reverse qbs)) -- | A quantum computation that will return a quantum integer in a state that -- has equal probabilities of being measured in any of the state \min\ to \max\. randomQIO :: (Int,Int) -> QIO Int randomQIO (min,max) = do q <- randomInt (max-min) return (q + min) -- | A quantum computation that measures the outcome of "randomQInt" randomInt :: Int -> QIO Int randomInt max = do q <- randomQInt max measQ q -- | A quantum computation that returns an integer that is equally likely to be -- any number in the range 0 to \x\-1 random :: Int -> QIO Int random x = randomInt (x-1) -- | This function uses a Quantum computation to simulate the roll of a dice dice :: IO Int dice = do x <- run (randomInt 5) return (x+1) -- | This function simulates the given number of repitions of dice rolls dice_rolls :: Int -> IO [Int] dice_rolls 0 = return [] dice_rolls y = do x <- dice xs <- dice_rolls (y-1) return (x:xs) -- | Returns the number of occurences of 1 through 6 in the given list of Ints occs :: [Int] -> (Int,Int,Int,Int,Int,Int) occs rs = (rs' 1,rs' 2,rs' 3,rs' 4,rs' 5,rs' 6) where rs' x = length ([y|y<-rs,y==x]) -- | Returns the number of occurences of 1 through 6 in the given number of -- rolls of the dice. probs' :: Int -> IO (Int,Int,Int,Int,Int,Int) probs' x = do xs <- dice_rolls x return (occs xs) -- | Returns the percentage of occurences of 1 through 6, after the given number -- of rolls of the dice. probs :: Int -> IO (RR,RR,RR,RR,RR,RR) probs x = do (a,b,c,d,e,f) <- probs' x return (fromIntegral a/x',fromIntegral b/x',fromIntegral c/x',fromIntegral d/x',fromIntegral e/x',fromIntegral f/x') where x' = fromIntegral x