{-# LANGUAGE FlexibleContexts #-}
module Quipper.Internal.Classical where
import Quipper.Internal.Generic
import Quipper.Internal.QData
import Quipper.Internal.Monad
import Quipper.Internal.Control
import Quipper.Internal.Transformer
import Data.Map (Map)
import qualified Data.Map as Map
import qualified Data.IntMap as IntMap
cgate_to_cnot_transformer :: Transformer Circ Qubit Bit
cgate_to_cnot_transformer (T_CGate name ncf f) = f $
\qs -> without_controls_if ncf $ do
q <- cinit False
translate_cgate name q qs
return (q, qs)
cgate_to_cnot_transformer (T_CGateInv name ncf f) = f $
\q qs -> without_controls_if ncf $ do
reverse_generic_imp (translate_cgate name) q qs
cterm False q
return qs
cgate_to_cnot_transformer gate = identity_transformer gate
translate_cgate :: String -> Bit -> [Bit] -> Circ ()
translate_cgate "if" q [a,b,c] = do
cnot_at q `controlled` a .==. True .&&. b .==. True
cnot_at q `controlled` a .==. False .&&. c .==. True
translate_cgate "if" q list = do
error ("translate_cgate: \"if\" needs 3 arguments, not " ++ show (length list))
translate_cgate "and" q list = do
cnot_at q `controlled` list
translate_cgate "or" q list = do
cnot_at q `controlled` [ x .==. 0 | x <- list]
cnot_at q
translate_cgate "xor" q list = do
sequence_ [cnot_at q `controlled` c | c <- list]
translate_cgate "eq" q [a,b] = do
cnot_at q `controlled` a .==. True
cnot_at q `controlled` b .==. False
translate_cgate "eq" q list = do
error ("translate_cgate: \"eq\" needs 2 arguments, not " ++ show (length list))
translate_cgate "not" q [a] = do
cnot_at q `controlled` a .==. False
translate_cgate "not" q list = do
error ("translate_cgate: \"not\" needs 1 argument, not " ++ show (length list))
translate_cgate name q list = do
error ("translate_cgate: gate \"" ++ name ++ "\" not known")
classical_to_cnot :: (QCData qa, QCData qb, QCurry qfun qa qb) => qfun -> qfun
classical_to_cnot = transform_generic cgate_to_cnot_transformer
trivial_endpoint :: B_Endpoint Qubit Qubit -> Qubit
trivial_endpoint (Endpoint_Qubit q) = q
trivial_endpoint (Endpoint_Bit q) = q
classical_to_quantum_transformer :: Transformer Circ Qubit Qubit
classical_to_quantum_transformer (T_CNot ncf f) = f $
\q c -> without_controls_if ncf $ do
q' <- qnot q `controlled` c
return (q', c)
classical_to_quantum_transformer (T_CSwap ncf f) = f $
\w v c -> without_controls_if ncf $ do
(w',v') <- swap w v `controlled` c
return (w',v',c)
classical_to_quantum_transformer (T_CInit b ncf f) = f $
without_controls_if ncf $ do
w <- qinit b
return w
classical_to_quantum_transformer (T_CTerm b ncf f) = f $
\w -> without_controls_if ncf $ do
qterm b w
return ()
classical_to_quantum_transformer (T_CDiscard f) = f $
\w -> do
qdiscard w
return ()
classical_to_quantum_transformer (T_DTerm b f) = f $
\w -> do
qdiscard w
return ()
classical_to_quantum_transformer (T_CGate name ncf f) = f $
classical_to_quantum . classical_to_cnot $
\ws -> without_controls_if ncf $ do
v <- cgate name ws
return (v, ws)
classical_to_quantum_transformer (T_CGateInv name ncf f) = f $
classical_to_quantum . classical_to_cnot $
\v ws -> without_controls_if ncf $ do
cgateinv name v ws
return ws
classical_to_quantum_transformer (T_QPrep ncf f) = f $
\w -> return w
classical_to_quantum_transformer (T_QUnprep ncf f) = f $
\w -> return w
classical_to_quantum_transformer (T_QMeas f) = f $
\w -> return w
classical_to_quantum_transformer (T_QGate name _ _ inv ncf f) = f $
\ws vs c -> without_controls_if ncf $ do
(ws', vs') <- named_gate_qulist name inv ws vs `controlled` c
return (ws', vs', c)
classical_to_quantum_transformer (T_QRot name _ _ inv t ncf f) = f $
\ws vs c -> without_controls_if ncf $ do
(ws', vs') <- named_rotation_qulist name inv t ws vs `controlled` c
return (ws', vs', c)
classical_to_quantum_transformer (T_GPhase t ncf f) = f $
\q c -> without_controls_if ncf $ do
global_phase_anchored_list t (map fix_endpoint q) `controlled` c
return c
where
fix_endpoint (Endpoint_Qubit q) = (Endpoint_Qubit q)
fix_endpoint (Endpoint_Bit q) = (Endpoint_Qubit q)
classical_to_quantum_transformer (T_QInit b ncf f) = f $
without_controls_if ncf $ do
w <- qinit_qubit b
return w
classical_to_quantum_transformer (T_QTerm b ncf f) = f $
\w -> without_controls_if ncf $ do
qterm_qubit b w
return ()
classical_to_quantum_transformer (T_QDiscard f) = f $
\w -> do
qdiscard_qubit w
return ()
classical_to_quantum_transformer (T_Subroutine n inv ncf scf ws_pat a1_pat vs_pat a2_pat repeat f) = f $
\namespace ws c -> without_controls_if ncf $ do
provide_subroutines namespace
v <- subroutine n inv scf repeat ws_pat a1_pat vs_pat a2_pat (map fix_endpoint ws) `controlled` c
return (map fix_endpoint v,c)
where
fix_endpoint (Endpoint_Qubit q) = Endpoint_Qubit q
fix_endpoint (Endpoint_Bit q) =
error "classical_to_quantum: classical subroutine not permitted"
classical_to_quantum_transformer (T_Comment s inv f) = f $
\ws -> do
comment_label s inv [ (fix_endpoint e, s) | (e,s) <- ws ]
return ()
where
fix_endpoint (Endpoint_Qubit q) = wire_of_qubit q
fix_endpoint (Endpoint_Bit q) = wire_of_qubit q
classical_to_quantum_unary :: (QCData qa, QCData qb) => (qa -> Circ qb) -> (QType qa -> Circ (QType qb))
classical_to_quantum_unary f x = transform_unary_shape classical_to_quantum_transformer f shape x
where
shape = qcdata_makeshape (dummy :: qa) qubit qubit x
classical_to_quantum :: (QCData qa, QCData qb, QCurry qfun qa qb, QCurry qfun' (QType qa) (QType qb)) => qfun -> qfun'
classical_to_quantum f = g where
f1 = quncurry f
g1 = classical_to_quantum_unary f1
g = qcurry g1
classical_to_reversible :: (QCData qa, QCData qb) => (qa -> Circ qb) -> ((qa,qb) -> Circ (qa,qb))
classical_to_reversible f (input, target) = do
with_computed (f input) $ \output -> do
controlled_not target output
return (input, target)