-- | 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