-- | This library contains special decompositions of particular gates -- into particular gate bases. It also contains functions for -- decomposing multiple controls. -- -- For example, we provide particular decompositions of the Toffoli, -- Fredkin, doubly-controlled /iX/-gate, and certain other controlled -- Clifford gates, into the Clifford+/T/ base. In some cases, we -- provide more than one decomposition. -- -- Many of these decompositions are taken or adapted from the -- literature, for example, from: -- -- * M. A. Nielsen and I. L. Chuang, -- /Quantum Computation and Quantum Information/, -- Cambridge University Press, 2002. -- -- * M. Amy, D. Maslov, M. Mosca, and M. Roetteler, -- /A meet-in-the-middle algorithm for fast synthesis/ -- /of depth-optimal quantum circuits/, -- <http://arxiv.org/abs/1206.0758>. -- -- * P. Selinger, /Quantum circuits of T-depth one/, -- <http://arxiv.org/abs/1210.0974>. module QuipperLib.GateDecompositions where import Quipper import Control.Monad -- ---------------------------------------------------------------------- -- * Decomposition of gates -- | Decomposition of the Toffoli gate into the Clifford+/T/ base, -- from Nielsen and Chuang (Figure 4.9). The first argument is the -- target, and the other two are the controls. The controls can be -- positive or negative. -- -- \[image toffoli_NC.png] toffoli_NC_at :: Qubit -> Signed Qubit -> Signed Qubit -> Circ () toffoli_NC_at q c1 c2 = do comment_with_label "ENTER: toffoli_NC" (q,c1,c2) ("q","c1","c2") let x = get_sign c1 y = get_sign c2 w1 = from_signed c1 w2 = from_signed c2 hadamard_at q qnot_at q `controlled` w1 reverse_imp_if (not x) gate_T_inv_at q qnot_at q `controlled` w2 reverse_imp_if (x `xor` y) gate_T_at q qnot_at q `controlled` w1 reverse_imp_if (not y) gate_T_inv_at q qnot_at q `controlled` w2 gate_T_at q reverse_imp_if (not x) gate_T_inv_at w1 hadamard_at q qnot_at w1 `controlled` w2 reverse_imp_if (x `xor` y) gate_T_inv_at w1 qnot_at w1 `controlled` w2 reverse_imp_if (not x) gate_S_at w1 reverse_imp_if (not y) gate_T_at w2 comment_with_label "EXIT: toffoli_NC" (q,c1,c2) ("q","c1","c2") where xor = (/=) -- | Decomposition of the Toffoli gate into the Clifford+/T/ base, -- from Amy et al. (<http://arxiv.org/abs/1206.0758v3>, Figure -- 13). The first argument is the target, and the other two are the -- controls. The controls can be positive or negative. -- -- \[image toffoli_AMMR.png] toffoli_AMMR_at :: Qubit -> Signed Qubit -> Signed Qubit -> Circ () toffoli_AMMR_at q c1 c2 = do comment_with_label "ENTER: toffoli_AMMR" (q,c1,c2) ("q","c1","c2") without_comments $ do hadamard_at q ccZ_AMMR_at q c1 c2 hadamard_at q comment_with_label "EXIT: toffoli_AMMR" (q,c1,c2) ("q","c1","c2") -- | Decomposition of the Toffoli gate using controlled Clifford -- operators, from Nielsen and Chuang (Figure 4.8). The controls can be -- positive or negative. -- -- \[image toffoli_V.png] toffoli_V_at :: Qubit -> Signed Qubit -> Signed Qubit -> Circ () toffoli_V_at q c1 c2 = do comment_with_label "ENTER: toffoli_V" (q,c1,c2) ("q","c1","c2") let q1 = from_signed c1 let q2 = from_signed c2 gate_V_at q `controlled` c1 qnot_at q1 `controlled` c2 gate_V_inv_at q `controlled` c1 qnot_at q1 `controlled` c2 gate_V_at q `controlled` c2 comment_with_label "EXIT: toffoli_V" (q,c1,c2) ("q","c1","c2") -- | Decomposition of the doubly-controlled /iX/-gate into the -- Clifford+/T/ base, using /T/-count 4 and /T/-depth 2. Adapted from -- (<http://arxiv.org/abs/1210.0974>, Figure 10). The first argument -- is the target, and the other two are the controls. The controls can -- be positive or negative. -- -- \[image cc_iX.png] cc_iX_at :: Qubit -> Signed Qubit -> Signed Qubit -> Circ () cc_iX_at q c1 c2 = do comment_with_label "ENTER: cc_iX" (q,c1,c2) ("q","c1","c2") let x = get_sign c1 y = get_sign c2 w1 = from_signed c1 w2 = from_signed c2 hadamard_at q qnot_at w1 `controlled` q qnot_at w2 `controlled` w1 reverse_imp_if (not x) gate_T_at w1 reverse_imp_if (x `xor` y) gate_T_inv_at w2 qnot_at w1 `controlled` q qnot_at w2 `controlled` w1 gate_T_inv_at q reverse_imp_if (not y) gate_T_at w2 qnot_at w2 `controlled` q hadamard_at q when (not x && not y) $ do -- need a phase correction gate_omega_at w1 gate_omega_at w2 comment_with_label "EXIT: cc_iX" (q,c1,c2) ("q","c1","c2") where xor = (/=) -- | Decomposition of the doubly-controlled /iX/-gate into the -- Clifford+/T/ base, using /T/-count 4, and using the control qubits -- only as controls. Derived from Nielsen and Chuang (Figure 4.9). The -- controls can be positive or negative. -- -- \[image cc_iX_simple.png] cc_iX_simple_at :: Qubit -> Signed Qubit -> Signed Qubit -> Circ () cc_iX_simple_at q c1 c2 = do comment_with_label "ENTER: cc_iX_simple" (q,c1,c2) ("q","c1","c2") hadamard_at q qnot_at q `controlled` c1 gate_T_at q qnot_at q `controlled` c2 gate_T_inv_at q qnot_at q `controlled` c1 gate_T_at q qnot_at q `controlled` c2 gate_T_inv_at q hadamard_at q comment_with_label "EXIT: cc_iX_simple" (q,c1,c2) ("q","c1","c2") -- | Decomposition of the doubly-controlled /Z/-gate into the -- Clifford+/T/ base. Adapted from Amy et -- al. (<http://arxiv.org/abs/1206.0758v3>, Figure 13). The controls can -- be positive or negative. -- -- \[image ccZ_AMMR.png] ccZ_AMMR_at :: Qubit -> Signed Qubit -> Signed Qubit -> Circ () ccZ_AMMR_at q c1 c2 = do comment_with_label "ENTER: ccZ_AMMR" (q,c1,c2) ("q","c1","c2") let x = get_sign c1 y = get_sign c2 w1 = from_signed c1 w2 = from_signed c2 gate_T_at q reverse_imp_if (not x) gate_T_at w1 reverse_imp_if (not y) gate_T_at w2 qnot_at w2 `controlled` w1 qnot_at w1 `controlled` q qnot_at q `controlled` w2 reverse_imp_if (not x) gate_T_inv_at w1 reverse_imp_if (x `xor` y) gate_T_at q qnot_at w1 `controlled` w2 reverse_imp_if (not y) gate_T_inv_at w1 reverse_imp_if (x `xor` y) gate_T_inv_at w2 qnot_at w1 `controlled` q qnot_at q `controlled` w2 qnot_at w2 `controlled` w1 comment_with_label "EXIT: ccZ_AMMR" (q,c1,c2) ("q","c1","c2") where xor = (/=) -- | Decomposition of the Fredkin (controlled-Swap) gate into the -- Clifford+/T/ base. The first two arguments are the targets, and the -- last one the control. The controls can be positive or negative. -- -- \[image fredkin.png] fredkin_at :: Qubit -> Qubit -> Signed Qubit -> Circ () fredkin_at q1 q2 c = do comment_with_label "ENTER: fredkin" (q1,q2,c) ("q1","q2","c") without_controls $ do qnot_at q2 `controlled` q1 toffoli_AMMR_at q1 (Signed q2 True) c qnot_at q2 `controlled` q1 comment_with_label "EXIT: fredkin" (q1,q2,c) ("q1","q2","c") -- | Decomposition of a controlled /H/-gate into the Clifford+/T/ -- base. From Amy et al. (<http://arxiv.org/abs/1206.0758v3>, Figure -- 5(a)). The first argument is the target and the second one the -- control. The control can be positive or negative. -- -- \[image cH_AMMR.png] cH_AMMR_at :: Qubit -> Signed Qubit -> Circ () cH_AMMR_at q c = do comment_with_label "ENTER: cH_AMMR" (q,c) ("q","c") gate_S_inv_at q hadamard_at q gate_T_inv_at q qnot_at q `controlled` c gate_T_at q hadamard_at q gate_S_at q comment_with_label "EXIT: cH_AMMR" (q,c) ("q","c") -- | Decomposition of a controlled /W/-gate into the Clifford+/T/ -- base. The first two arguments are the targets, and the last -- argument is the control. The control can be positive or negative. -- -- \[image controlled_W.png] controlled_W_at :: Qubit -> Qubit -> Signed Qubit -> Circ () controlled_W_at q1 q2 c = do comment_with_label "ENTER: controlled_W" (q1,q2,c) ("W1","W2","c") without_comments $ do qnot_at q2 `controlled` q1 gate_S_inv_at q1 hadamard_at q1 gate_T_inv_at q1 toffoli_AMMR_at q1 (Signed q2 True) c gate_T_at q1 hadamard_at q1 gate_S_at q1 qnot_at q2 `controlled` q1 comment_with_label "EXIT: controlled_W" (q1,q2,c) ("W1","W2","c") -- | Decomposition of a /W/-gate into the Clifford+/T/ base. -- -- \[image gate_W_CliffordT.png] gate_W_CliffordT_at :: Qubit -> Qubit -> Circ () gate_W_CliffordT_at q1 q2 = do comment_with_label "ENTER: gate_W_CliffordT" (q1,q2) ("W1","W2") without_comments $ do qnot_at q2 `controlled` q1 cH_AMMR_at q1 (Signed q2 True) qnot_at q2 `controlled` q1 comment_with_label "EXIT: gate_W_CliffordT" (q1,q2) ("W1","W2") -- | Decomposition of a controlled /iX/-gate into the Clifford+/T/ -- base. The first argument is the target, and the second one is the -- control. The control can be positive or negative. -- -- \[image controlled_iX.png] controlled_iX_at :: Qubit -> Signed Qubit -> Circ () controlled_iX_at q c = do comment_with_label "ENTER: controlled_iX" (q,c) ("q","c") let x = get_sign c w = from_signed c qnot_at q `controlled` c reverse_imp_if (not x) gate_S_at w when (not x) $ do -- need a phase correction gate_omega_at q gate_omega_at w comment_with_label "EXIT: controlled_iX" (q,c) ("q","c") -- | Decomposition of a controlled /S/-gate into the Clifford+/T/ -- base. From Amy et al. (<http://arxiv.org/abs/1206.0758v3>, Figure -- 5(b)). The first argument is the target, and the second one is the -- control. The control can be positive or negative. -- -- \[image controlled_S.png] controlled_S_at :: Qubit -> Signed Qubit -> Circ () controlled_S_at q c = do comment_with_label "ENTER: controlled_S" (q,c) ("q","c") let x = get_sign c w = from_signed c qnot w `controlled` q reverse_imp_if (not x) gate_T_inv_at w qnot w `controlled` q reverse_imp_if (not x) gate_T_at w gate_T_at q comment_with_label "EXIT: controlled_S" (q,c) ("q","c") -- | Decomposition of a controlled /T/-gate into the Clifford+/T/ -- base. The first argument is the target, and the second one is the -- control. The control can be positive or negative. -- -- \[image controlled_T.png] controlled_T_at :: Qubit -> Signed Qubit -> Circ () controlled_T_at q c = do comment_with_label "ENTER: controlled_T" (q,c) ("q","c") without_comments $ do with_ancilla_init False $ \r -> do cc_iX_at r (Signed q True) c gate_T_at r reverse_generic_imp cc_iX_at r (Signed q True) c comment_with_label "EXIT: controlled_T" (q,c) ("q","c") -- | Decomposition of a controlled /V/-gate into the Clifford+/T/ -- base. Adapted from Amy et al. (<http://arxiv.org/abs/1206.0758v3>, -- Figure 5(c)). Our /V/-gate is /H//S/[sup †]/H/ as in Nielsen and -- Chuang. The first argument is the target, and the second one is the -- control. The control can be positive or negative. -- -- \[image controlled_V.png] controlled_V_at :: Qubit -> Signed Qubit -> Circ () controlled_V_at q c = do comment_with_label "ENTER: controlled_V" (q,c) ("q","c") let x = get_sign c w = from_signed c hadamard_at q reverse_imp_if (not x) gate_T_inv_at w qnot w `controlled` q reverse_imp_if (not x) gate_T_at w gate_T_inv_at q qnot w `controlled` q hadamard_at q comment_with_label "EXIT: controlled_V" (q,c) ("q","c") -- | Decomposition of a controlled /E/-gate into the Clifford+/T/ -- base. Currently not implemented; this function exists here as a -- placeholder. controlled_E_at :: Qubit -> Signed Qubit -> Circ () controlled_E_at q c = do error "controlled_E_at: not implemented" -- | A \"plain\" Toffoli gate, not decomposed. This is provided for -- convenience, for example to use with 'with_combined_controls'. toffoli_plain_at :: Qubit -> Signed Qubit -> Signed Qubit -> Circ () toffoli_plain_at q c1 c2 = do qnot_at q `controlled` (c1,c2) -- | A \"plain\" doubly-controlled /iX/-gate, not decomposed. This is -- provided for convenience, for example to use with -- 'with_combined_controls'. cc_iX_plain_at :: Qubit -> Signed Qubit -> Signed Qubit -> Circ () cc_iX_plain_at q c1 c2 = do gate_iX_at q `controlled` (c1,c2) -- ---------------------------------------------------------------------- -- * Decomposition of controls -- | Partition a list of controls into quantum and classical. partition_controls :: [Signed Endpoint] -> ([Signed Qubit], [Signed Bit]) partition_controls cs = (qcs, ccs) where qcs = [ Signed q b | Signed (Endpoint_Qubit q) b <- cs ] ccs = [ Signed c b | Signed (Endpoint_Bit c) b <- cs ] -- | Decompose quantum controls recursively until at most /n/ remain, -- and then pass these reduced controls to the given circuit. -- Precondition: /n/ ≥ 1. -- -- The decomposition is done using a Toffoli-like gate that is given -- as the first argument. This should be either a Toffoli gate, a -- doubly-controlled /iX/-gate, a decomposition thereof, or any other -- reversible ternary gate with the behavior -- -- * |000〉 ↦ |0〉|φ[sub 0]〉 -- -- * |001〉 ↦ |0〉|φ[sub 1]〉 -- -- * |010〉 ↦ |0〉|φ[sub 2]〉 -- -- * |011〉 ↦ |1〉|φ[sub 3]〉, -- -- where the states |φ[sub 0]〉, …, |φ[sub 3]〉 are arbitrary. -- -- For example, when /n/=2, this typically yields a circuit such as -- the following (here shown using the doubly-controlled /iX/-gate): -- -- \[image with_combined_controls2.png] -- -- And for /n/=1, the circuit typically looks like this: -- -- \[image with_combined_controls1.png] -- -- Classical controls are not decomposed, but are applied to the -- resulting circuit directly. with_combined_controls :: (Qubit -> Signed Qubit -> Signed Qubit -> Circ ()) -> Int -> [Signed Endpoint] -> ([Signed Qubit] -> Circ a) -> Circ a with_combined_controls my_toffoli_at n cs code = circ where (qcs, ccs) = partition_controls cs len = length qcs -- m is the number of qcs to remove. m = if len <= n then 0 else len - n circ = with_controls ccs $ do aux m qcs code aux 0 qcs code = code qcs aux n [] code = code [] aux n [c] code = code [c] aux n (c1:c2:qcs) code = do with_computed (quantum_and c1 c2) $ \c -> do aux (n-1) (qcs ++ [Signed c True]) code quantum_and :: Signed Qubit -> Signed Qubit -> Circ Qubit quantum_and c1 c2 = do q <- qinit 0 my_toffoli_at q c1 c2 return q