{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Libraries/QuipperASCIIParser/ASCIICirc.hs" #-}
module Quipper.Libraries.QuipperASCIIParser.ASCIICirc where
import Quipper.Libraries.QuipperASCIIParser.CircInfo hiding (run,do_gate)
import Quipper
import Quipper.Internal.Circuit
import Quipper.Internal.Monad
import Quipper.Internal.Generic
import Data.List
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.Map (Map)
import qualified Data.Map as Map
import Control.Monad.State
data WireState = WireState {
wire_map :: IntMap (Wire,Wiretype),
in_sub :: Bool,
subroutines_in_scope :: Map BoxId Sub
}
empty_wirestate :: Map BoxId Sub -> WireState
empty_wirestate subs = WireState {wire_map = IntMap.empty, in_sub = False,
subroutines_in_scope = subs}
type ASCIICirc a = StateT WireState Circ a
set_in_sub :: ASCIICirc ()
set_in_sub = do
state <- get
put (state {in_sub = True})
provide_qubit :: Int -> ASCIICirc Qubit
provide_qubit r = do
state <- get
case (in_sub state) of
False -> do
let ws = wire_map state
case IntMap.lookup r ws of
Just (w,Qbit) -> return (qubit_of_wire w)
Just (w,Cbit) -> error ("Quantum wire " ++ show r ++ " bound as classical " ++ show w)
Nothing -> error ("Quantum wire " ++ show r ++ " not in scope")
True -> return (qubit_of_wire r)
provide_bit :: Int -> ASCIICirc Bit
provide_bit r = do
state <- get
case (in_sub state) of
False -> do
let ws = wire_map state
case IntMap.lookup r ws of
Just (w,Cbit) -> return (bit_of_wire w)
Just (w,Qbit) -> error ("Classical wire " ++ show r ++ " bound as quantum " ++ show w)
Nothing -> error ("Classical wire " ++ show r ++ " not in scope")
True -> return (bit_of_wire r)
provide_wire :: Int -> ASCIICirc Wire
provide_wire r = do
state <- get
case (in_sub state) of
False -> do
let ws = wire_map state
case IntMap.lookup r ws of
Just (w,_) -> return w
Nothing -> do
q <- provide_qubit r
return (wire_of_qubit q)
True -> return r
add_qubit :: Int -> Qubit -> ASCIICirc ()
add_qubit w q = do
state <- get
let ws = wire_map state
let ws' = IntMap.insert w (wire_of_qubit q,Qbit) ws
put (state {wire_map = ws'})
add_bit :: Int -> Bit -> ASCIICirc ()
add_bit w b = do
state <- get
let ws = wire_map state
let ws' = IntMap.insert w (wire_of_bit b,Cbit) ws
put (state {wire_map = ws'})
remove_wire :: Int -> ASCIICirc ()
remove_wire w = do
state <- get
let ws = wire_map state
let ws' = IntMap.delete w ws
put (state {wire_map = ws'})
provide_control :: Signed Int -> ASCIICirc (Signed Wire)
provide_control (Signed r val) = do
w <- provide_wire r
return (Signed w val)
provide_controls :: [Signed Int] -> ASCIICirc [Signed Wire]
provide_controls = mapM provide_control
lift_ncf :: Bool -> Circ a -> ASCIICirc a
lift_ncf False ca = lift ca
lift_ncf True ca = lift $ without_controls ca
do_gate :: Gate -> ASCIICirc ()
do_gate (QGate name iflg ws1 ws2 wbs ncf) = do
qs1 <- mapM provide_qubit ws1
qs2 <- mapM provide_qubit ws2
cs <- provide_controls wbs
lift_ncf ncf $ named_gate_qulist name iflg qs1 qs2 `controlled` cs
return ()
do_gate (QRot name iflg theta ws1 ws2 wbs ncf) = do
qs1 <- mapM provide_qubit ws1
qs2 <- mapM provide_qubit ws2
cs <- provide_controls wbs
lift_ncf ncf $ named_rotation_qulist name iflg theta qs1 qs2 `controlled` cs
return ()
do_gate (GPhase ts ws wbs ncf) = do
qs <- mapM provide_qubit ws
cs <- provide_controls wbs
lift_ncf ncf $ global_phase_anchored_list ts (map (\w -> endpoint_of_wire w Qbit) (map wire_of_qubit qs)) `controlled` cs
return ()
do_gate (CNot w wbs ncf) = do
b <- provide_bit w
cs <- provide_controls wbs
lift_ncf ncf $ cnot_at b `controlled` cs
do_gate (CGate name w ws ncf) = do
bs <- mapM provide_bit ws
b <- lift_ncf ncf $ cgate name bs
add_bit w b
do_gate (CGateInv name w ws ncf) = do
b <- provide_bit w
bs <- mapM provide_bit ws
lift_ncf ncf $ cgateinv name b bs
do_gate (CSwap w1 w2 wbs ncf) = do
b1 <- provide_bit w1
b2 <- provide_bit w2
cs <- provide_controls wbs
lift_ncf ncf $ swap b1 b2 `controlled` cs
return ()
do_gate (QPrep w ncf) = do
b <- provide_bit w
q <- lift_ncf ncf $ prepare_qubit b
add_qubit w q
do_gate (QUnprep w ncf) = do
q <- provide_qubit w
b <- lift_ncf ncf $ unprepare_qubit q
add_bit w b
do_gate (QInit val w ncf) = do
q <- lift_ncf ncf $ qinit val
add_qubit w q
do_gate (CInit val w ncf) = do
b <- lift_ncf ncf $ cinit val
add_bit w b
do_gate (QTerm val w ncf) = do
q <- provide_qubit w
lift_ncf ncf $ qterm val q
remove_wire w
do_gate (CTerm val w ncf) = do
b <- provide_bit w
lift_ncf ncf $ cterm val b
remove_wire w
do_gate (QMeas w) = do
q <- provide_qubit w
b <- lift $ measure q
add_bit w b
do_gate (QDiscard w) = do
q <- provide_qubit w
lift $ qdiscard q
remove_wire w
do_gate (CDiscard w) = do
b <- provide_bit w
lift $ cdiscard b
remove_wire w
do_gate (Subroutine boxid iflg ws_in _ ws_out _ wbs ncf _ (RepeatFlag rf)) = do
state <- get
let subs = subroutines_in_scope state
case (Map.lookup boxid subs) of
Nothing -> error ("Subroutine " ++ show boxid ++ " has not been defined in: " ++ show (Map.keys subs))
Just sub -> do
let ins = inputs sub
let (_,in_as) = unzip ins
let in_wa = zip ws_in in_as
es_in <- mapM (\(w,wt) ->
case wt of
Qbit -> do
q <- provide_qubit w
let wire = endpoint_of_wire (wire_of_qubit q) Qbit
return wire
Cbit -> do
b <- provide_bit w
let wire = endpoint_of_wire (wire_of_bit b) Cbit
return wire
) in_wa
cs <- provide_controls wbs
let outs = outputs sub
let es_out = map (\(w,wt) -> endpoint_of_wire w wt) outs
let gates = reverse (circuit sub)
let ascii_circ = \_ -> set_in_sub >> (mapM_ do_gate gates) >> return es_out
let circ = run_asciicirc subs ascii_circ
let boxid = BoxId (name sub) (shape sub)
let error_message = \e -> "ASCIICirc.do_gate : " ++ e
let f = \x -> do
provide_subroutine_generic error_message boxid False circ x
call_subroutine boxid (RepeatFlag rf) x
es_out' <- case iflg of
False -> lift_ncf ncf $ f es_in `controlled` cs
True -> do
let (_,out_as) = unzip outs
let out_wa = zip ws_in out_as
es_out <- mapM (\(w,wt) ->
case wt of
Qbit -> do
q <- provide_qubit w
let wire = endpoint_of_wire (wire_of_qubit q) Qbit
return wire
Cbit -> do
b <- provide_bit w
let wire = endpoint_of_wire (wire_of_bit b) Cbit
return wire
) out_wa
lift_ncf ncf $ (reverse_generic f es_in) es_out `controlled` cs
state <- get
let wires = wire_map state
let wires' = foldr (\w ws -> IntMap.delete w ws) wires (if iflg then ws_out else ws_in)
let wires'' = foldr (\(w,e) ws -> IntMap.insert w
(case e of
Endpoint_Qubit q -> (wire_of_qubit q, Qbit)
Endpoint_Bit b -> (wire_of_bit b, Cbit)) ws) wires'
(zip (if iflg then ws_in else ws_out) es_out')
put (state {wire_map = if (in_sub state) then wires else wires''})
do_gate (Comment c iflg wlabels) = do
qlabels <- mapM (\(w,l) ->
do
pw <- provide_wire w
return (pw,l) ) wlabels
lift $ comment_label c iflg qlabels
do_gate (DTerm val w) = do
b <- provide_bit w
lift $ dterm_bit val b
remove_wire w
allocate_input :: (Endpoint,Endpoint) -> ASCIICirc ()
allocate_input (i,e@(Endpoint_Qubit _)) = add_qubit (wire_of_endpoint e) (qubit_of_wire (wire_of_endpoint i))
allocate_input (i,e@(Endpoint_Bit _)) = add_bit (wire_of_endpoint e) (bit_of_wire (wire_of_endpoint i))
run_gates :: [Gate] -> Maybe [(Wire,Wiretype)] -> [Endpoint] -> [Endpoint] -> ASCIICirc [Endpoint]
run_gates gates d_outs es ins = do
mapM_ (\i -> allocate_input i) (zip ins es)
mapM_ (\g -> do_gate g) gates
state <- get
let ws_in_scope = IntMap.elems $ wire_map state
let es_in_scope = map (\(w,wt) -> endpoint_of_wire w wt) ws_in_scope
case d_outs of
Nothing -> return es_in_scope
Just out_ws -> do
es_out <- mapM (\(w,wt) -> do
w' <- provide_wire w
return (endpoint_of_wire w' wt)) out_ws
let es_in_scope' = sortBy (\e1 e2 -> compare (wire_of_endpoint e1) (wire_of_endpoint e2)) es_in_scope
let es_out' = sortBy (\e1 e2 -> compare (wire_of_endpoint e1) (wire_of_endpoint e2)) es_out
case es_in_scope' == es_out' of
True -> return es_out'
False -> return es_in_scope'
run_asciicirc :: Map BoxId Sub -> (a -> ASCIICirc b) -> a -> Circ b
run_asciicirc subs f es = evalStateT (f es) (empty_wirestate subs)
run :: Maybe [(Wire,Wiretype)] -> [Gate] -> Map BoxId Sub -> CircInfoState -> ([Endpoint],[Endpoint] -> Circ [Endpoint])
run mins gates subs cis = (ins,circ)
where
d_ins = defined_inputs cis
d_outs = defined_outputs cis
u_ins = map set_qubit (undefined_inputs cis)
d_es = map (\(w,wt) -> endpoint_of_wire w wt) d_ins
u_es = map (\(w,wt) -> endpoint_of_wire w wt) u_ins
ins = case mins of
Nothing -> (d_es ++ sortBy (\e1 e2 -> compare (wire_of_endpoint e1) (wire_of_endpoint e2)) u_es)
Just wts -> map (\(w,wt) -> endpoint_of_wire w wt) wts
asciicirc = run_gates gates d_outs ins
circ = run_asciicirc subs asciicirc
set_qubit :: (Wire,Maybe Wiretype) -> (Wire,Wiretype)
set_qubit (w,Just wt) = (w,wt)
set_qubit (w,Nothing) = (w,Qbit)