module QIO.Qio where
import List
import qualified System.Random as Random
import Data.Monoid as Monoid
import Data.Maybe as Maybe
import Control.Monad.State
import QIO.QioSyn
import QIO.Vec
import QIO.VecEq
import QIO.Heap
type Pure = VecEqL CC HeapMap
updateP :: Pure -> Qbit -> Bool -> Pure
updateP p x b = VecEqL (map (\ (h,pa) -> (update h x b,pa)) (unVecEqL p))
newtype Unitary = U {unU :: Int -> HeapMap -> Pure }
instance Monoid Unitary where
mempty = U (\ fv h -> unEmbed $ return h)
mappend (U f) (U g) = U (\ fv h -> unEmbed $ do h' <- Embed $ f fv h
h'' <- Embed $ g fv h'
return h''
)
uRot :: Qbit -> Rotation -> Unitary
uRot q r = if (unitaryRot r) then (uMatrix q (r (False,False),
r (False,True),
r (True,False),
r (True,True)))
else error "Non unitary Rotation!"
unitaryRot :: Rotation -> Bool
unitaryRot r = True
uMatrix :: Qbit -> (CC,CC,CC,CC) -> Unitary
uMatrix q (m00,m01,m10,m11) = U (\ fv h -> (if (fromJust(h ? q))
then (m01 <*> (unEmbed $ return (update h q False)))
<+> (m11 <*> (unEmbed $ return h))
else (m00 <*> (unEmbed $ return h))
<+> (m10 <*> (unEmbed $ return (update h q True)))))
uSwap :: Qbit -> Qbit -> Unitary
uSwap x y = U (\ fv h -> unEmbed $ return (hswap h x y ))
uCond :: Qbit -> (Bool -> Unitary) -> Unitary
uCond x us = U (\ fv h -> unU (us (fromJust(h ? x))) fv h )
uLet :: Bool -> (Qbit -> Unitary) -> Unitary
uLet b ux = U (\fv h -> unU (ux (Qbit fv)) (fv + 1) (update h (Qbit fv) b))
runU :: U -> Unitary
runU UReturn = mempty
runU (Rot x a u) = uRot x a `mappend` runU u
runU (Swap x y u) = uSwap x y `mappend` runU u
runU (Cond x us u) = uCond x (runU.us) `mappend` runU u
runU (Ulet b xu u) = uLet b (runU.xu) `mappend` runU u
data StateQ = StateQ { free :: Int, pure :: Pure }
initialStateQ :: StateQ
initialStateQ = StateQ 0 (unEmbed $ return initial)
pa :: Pure -> RR
pa (VecEqL as) = foldr (\ (_,k) p -> p + amp k) 0 as
data Split = Split { p :: RR, ifTrue,ifFalse :: Pure }
split :: Pure -> Qbit -> Split
split (VecEqL as) x =
let pas = pa (VecEqL as)
(ift',iff') = partition (\ (h,_) -> (fromJust(h ? x))) as
ift = VecEqL ift'
iff = VecEqL iff'
p_ift = if pas==0 then 0 else (pa ift)/pas
in Split p_ift ift iff
class Monad m => PMonad m where
merge :: RR -> m a -> m a -> m a
instance PMonad IO where
merge pr ift iff = do pp <- Random.randomRIO (0,1.0)
if pr > pp then ift else iff
data Prob a = Prob {unProb :: Vec RR a}
instance Show a => Show (Prob a) where
show (Prob (Vec ps)) = show (filter (\ (a,p) -> p>0) ps)
instance Monad Prob where
return = Prob . return
(Prob ps) >>= f = Prob (ps >>= unProb . f)
instance PMonad Prob where
merge pr (Prob ift) (Prob iff) = Prob ((pr <**> ift) <++> ((1pr) <**> iff))
evalWith :: PMonad m => QIO a -> State StateQ (m a)
evalWith (QReturn a) = return (return a)
evalWith (MkQbit b g) = do (StateQ f p) <- get
put (StateQ (f+1) (updateP p (Qbit f) b))
evalWith (g (Qbit f))
evalWith (ApplyU u q) = do (StateQ f p) <- get
put (StateQ f (unEmbed $ do x <- Embed $ p
x' <-Embed $ uu f x
return x'
)
)
evalWith q
where U uu = runU u
evalWith (Meas x g) = do (StateQ f p) <- get
(let Split pr ift iff = split p x
in if pr < 0 || pr > 1 then error "pr < 0 or >1"
else do put (StateQ f ift)
pift <- evalWith (g True)
put (StateQ f iff)
piff <- evalWith (g False)
return (merge pr pift piff))
eval :: PMonad m => QIO a -> m a
eval p = evalState (evalWith p) initialStateQ
run :: QIO a -> IO a
run = eval
sim :: QIO a -> Prob a
sim = eval