module QIO.Qio where
import Data.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
import Control.Applicative (Applicative(..))
import Control.Monad (liftM, ap)
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''
)
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)))))
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!"
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, pureState :: 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 Functor Prob where
fmap = liftM
instance Applicative Prob where
pure = Prob . return
(<*>) = ap
instance Monad Prob where
return = pure
(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