{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LINE 1 "Quipper/Libraries/Simulation/ClassicalSimulation.hs" #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Quipper.Libraries.Simulation.ClassicalSimulation where
import Quipper
import Quipper.Internal
import Quipper.Internal.Transformer (bind_list, bindings_empty, unbind_list, Bindings, transform_bcircuit_id)
import Quipper.Internal.Circuit (RepeatFlag(..), TypedSubroutine(..), OCircuit(..), reverse_ocircuit, ControllableFlag(..), BCircuit)
import Quipper.Internal.Generic (qc_bind, qc_unbind, encapsulate_generic)
import Quipper.Utils.Auxiliary
import Data.List
import qualified Data.Map as Map
controls :: [Signed (B_Endpoint Bool Bool)] -> Bool
controls [] = True
controls ((Signed (Endpoint_Qubit c) b):t) = (c == b) && controls t
controls ((Signed (Endpoint_Bit c) b):t) = (c == b) && controls t
simulate_cgate :: String -> [Bool] -> Bool
simulate_cgate "if" [a,b,c] = if a then b else c
simulate_cgate "if" list = error ("simulate_cgate: \"if\" needs 3 arguments, not " ++ show (length list))
simulate_cgate "and" list = and list
simulate_cgate "or" list = or list
simulate_cgate "xor" list = foldl' bool_xor False list
simulate_cgate "eq" [a,b] = (a == b)
simulate_cgate "eq" list = error ("simulate_cgate: \"eq\" needs 2 arguments, not " ++ show (length list))
simulate_cgate "not" [a] = not a
simulate_cgate "not" list = error ("simulate_cgate: \"not\" needs 1 argument, not " ++ show (length list))
simulate_cgate name list = error ("simulate_cgate: gate \"" ++ name ++ "\" not known")
simulate_classical :: Transformer Id Bool Bool
simulate_classical (T_CNot ncf f) = f $
\q c -> Id (if controls c then not q else q, c)
simulate_classical (T_CSwap ncf f) = f $
\w v c -> Id (if controls c then (v,w,c) else (w,v,c))
simulate_classical (T_CInit b ncf f) = f $
Id b
simulate_classical (T_CTerm b ncf f) = f $
\q -> Id (if b==q then () else error "simulate_classical: CTerm assertion not met")
simulate_classical (T_CDiscard f) = f $
\b -> Id ()
simulate_classical (T_DTerm b f) = f $
\b -> Id ()
simulate_classical (T_CGate name ncf f) = f $
\list -> Id (simulate_cgate name list, list)
simulate_classical (T_CGateInv name ncf f) = f $
\q list -> if q == simulate_cgate name list
then Id list
else error ("simulate_classical: CGateInv failed assertion " ++ show q ++ " == " ++ name ++ show list)
simulate_classical (T_QGate "not" 1 0 _ ncf f) = f $
\[q] [] c -> if controls c then Id([not q], [], c) else Id([q], [], c)
simulate_classical (T_QGate "multinot" _ 0 _ ncf f) = f $
\qs [] c -> Id (if controls c then map not qs else qs, [], c)
simulate_classical (T_QGate "swap" 2 0 _ ncf f) = f $
\[w,v] [] c -> Id (if controls c then ([v,w], [], c) else ([w,v], [] ,c))
simulate_classical g@(T_QGate "H" 1 0 _ _ _) =
error ("simulate_classical: gate not classical: " ++ show g)
simulate_classical g@(T_QGate "W" 2 0 _ _ _) =
error ("simulate_classical: gate not classical: " ++ show g)
simulate_classical g@(T_QGate name _ _ inv ncf f) = f $
\qs gctls c -> case (name, inv, qs, gctls) of
("X", _, [q], []) ->
if controls c then Id([not q], [], c) else Id([q], [], c)
("Y", _, [q], []) ->
if controls c then Id([not q], [], c) else Id([q], [], c)
("Z", _, [q], []) -> Id([q], [], c)
("S", _, [q], []) -> Id([q], [], c)
("T", _, [q], []) -> Id([q], [], c)
("omega", _, [q], []) -> Id([q], [], c)
("iX", _, [q], []) ->
if controls c then Id([not q], [], c) else Id([q], [], c)
_ -> error ("simulate_classical: unimplemented gate: " ++ show g)
simulate_classical g@(T_QRot name _ _ inv t ncf f) = f $
\qs gctls c -> case (name, inv, qs, gctls) of
("R(2pi/%)", _, [q], []) -> Id([q], [], c)
("exp(-i%Z)", _, [q], []) -> Id([q], [], c)
_ -> error ("simulate_classical: unimplemented gate: " ++ show g)
simulate_classical g@(T_GPhase t ncf f) = f $
\q c -> Id c
simulate_classical (T_QInit b ncf f) = f $
Id b
simulate_classical (T_QTerm b ncf f) = f $
\q -> if b==q then Id() else error "simulate_classical: QTerm assertion not met"
simulate_classical (T_QDiscard f) = f $
\b -> Id()
simulate_classical (T_Comment s inv f) = f $
\b -> Id()
simulate_classical g@(T_QPrep ncf f) = f $
\w -> Id w
simulate_classical g@(T_QUnprep ncf f) = f $
\w -> Id w
simulate_classical g@(T_QMeas f) = f $
\w -> Id w
simulate_classical g@(T_Subroutine sub inv ncf scf ws_pat a1_pat vs_pat a2_pat (RepeatFlag repeat) f) = f $
\namespace in_values c -> Id $
case Map.lookup sub namespace of
Just (TypedSubroutine sub_ocirc _ _ _) ->
let OCircuit (in_wires, sub_circ, out_wires) = if inv then reverse_ocircuit sub_ocirc else sub_ocirc
in_bindings = bind_list in_wires in_values bindings_empty
out_bindings =
if (case scf of {AllCtl -> True; OnlyClassicalCtl -> True; NoCtl -> False})
then if controls c then foldl' (\in_b _ -> run_classical (sub_circ, namespace) in_b) in_bindings [1..repeat] else in_bindings
else if length c == 0
then foldl' (\in_b _ -> run_classical (sub_circ, namespace) in_b) in_bindings [1..repeat]
else error $ "simulate_classical: attempt to control non-controllable subroutine " ++ show sub
in (unbind_list out_bindings out_wires, c)
Nothing -> error $ "simulate_classical: subroutine " ++ show sub ++ " not found"
run_classical :: BCircuit -> Bindings Bool Bool -> Bindings Bool Bool
run_classical = transform_bcircuit_id simulate_classical
run_classical_errmsg :: (QCData qa, QCData qb) => ErrMsg -> (qa -> Circ qb) -> BType qa -> BType qb
run_classical_errmsg e (f :: qa -> Circ qb) input = output where
shape = qcdata_makeshape (dummy :: qa) (dummy :: Bool) (dummy :: Bool) input
(qa, circuit, qb) = encapsulate_generic e f shape
valuation_in = qc_bind qa input
valuation_out = run_classical circuit valuation_in
output = qc_unbind valuation_out qb
run_classical_unary :: (QCData qa, QCData qb) => (qa -> Circ qb) -> BType qa -> BType qb
run_classical_unary = run_classical_errmsg errmsg
where
errmsg x = "run_classical_unary: operation not currently permitted by simulator: " ++ x
run_classical_generic :: (QCData qa, QCData qb, QCurry qfun qa qb, Curry fun (BType qa) (BType qb)) => qfun -> fun
run_classical_generic f = g where
f1 = quncurry f
g1 = run_classical_errmsg errmsg f1
g = mcurry g1
errmsg x = "run_classical_generic: operation not currently permitted by simulator: " ++ x