Tutorial › Part G · Semantics: which gate the pulses make › G4

Lean is loading

CX from MS

Part G, lesson G4. You need lessons G1 to G3.

The only entangling operation of the machine is the Mølmer-Sørensen pulse. Every CNOT of a circuit becomes four one-ion pulses around one MS(π/2). This lesson proves that exactly, including the phase e^(−iπ/4) the identity carries; says what "equal up to a global phase" means, and why it is the right equality for a whole programme and the wrong one for a building block; and proves the CNOT that the Bell certificate's witness stands for.

*Lessons G1 to G3 are restated, unseen, above this line: the numbers and cis; matrices with *, • and dagger; PX, PY, PZ, I2, I4; the pulses R θ φ, VZ λ, MS θ (angles in eighths of a turn); kron A B, with A on qubit 0; the Hadamard H and lesson G3's h_witness : VZ 4 * R 2 (-2) = H; mul_zero_right; and lesson F1's Bell certificate bell.*

1. The target

def CX : Matrix (Fin 4) (Fin 4) ℂ := !![1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 0, 1; 0, 0, 1, 0]

QCCDC.Pulse.Native's CNOT, qubit 0 the control: it swaps the basis states 10 and 11.

2. Five pulses and a phase

QCCDC.Pulse.Decompose states it as "CX = e^{−iπ/4} · [Ry(−π/2)⊗I] · [Rx(−π/2)⊗Rx(−π/2)] · MS(π/2) · [Ry(π/2)⊗I]", with "Matrix order: the rightmost factor is the first pulse in time. One MS gate and four single-qubit pulses":

theorem cx_decomp :
    CX =
      Complex.exp ((-(Real.pi / 4) : ℝ) * Complex.I) •
        (kron (Ry (-(Real.pi / 2))) 1
          * kron (Rx (-(Real.pi / 2))) (Rx (-(Real.pi / 2)))
          * MS (Real.pi / 2)
          * kron (Ry (Real.pi / 2)) 1)

Rx θ is R θ 0 and Ry θ is R θ (π/2). The compiler's lowering, decompose_cx, emits the same five pulses in time order, the reverse of the matrix order, and records the phase:

let decompose_cx ~(control : int) ~(target : int) : decomposed =
  {
    pulses =
      [
        Beam { theta = pi /. 2.0; phi = pi /. 2.0; qubit = control };
        Ms { theta = pi /. 2.0; a = control; b = target };
        Beam { theta = -.pi /. 2.0; phi = 0.0; qubit = control };
        Beam { theta = -.pi /. 2.0; phi = 0.0; qubit = target };
        Beam { theta = -.pi /. 2.0; phi = pi /. 2.0; qubit = control };
      ];
    phase = -.pi /. 4.0;
  }

In eighths of a turn: π/2 is 2, −π/4 is −1. In QCCDC.Pulse.Decompose the proof is Mathlib algebra, with cos (π/4) kept symbolic and the heartbeat limit raised (set_option maxHeartbeats 2000000); here it is a computation.

Exercise 1 ★ cx_decomp_exact open

Prove cx_decomp over our numbers.

3. Equal up to a global phase

So the five pulses do not make CX. They make e^(iπ/4)·CX: every amplitude of every output turned by the same eighth of a turn. Nothing can measure that. A measurement's probabilities are the squared sizes of amplitudes, and |c·a|² = |a|² when |c| = 1. Two matrices that differ by such a factor are the same gate as far as any experiment on them can tell:

This is the equality the semantic check, check_cert, uses when it compares full matrices (same_up_to_phase: "Is a = e^{iα}·b?", with a tolerance of 10⁻⁸ on every entry), and the one a stabilizer tableau has built in (lesson G5). An ∃ is proved by naming the witness: ⟨c, p, q⟩ gives c and proofs of the two facts about it.

Exercise 2 ★★ cx_up_to_phase open

Prove the five pulses are CX up to a global phase: name the phase, prove it has size one, and use Exercise 1.

4. When a phase is not global

Then why does the compiler track the phase at all? Its lowering says, where it defines a decomposed gate:

(* A decomposed gate: its pulses in TIME order, plus the global phase the identity
   carries.  The phase is tracked rather than dropped because a gate that later becomes
   controlled needs it, and because dropping it silently is the classic way to get a
   compiler that is right on every benchmark and wrong on the one that matters. *)

A phase is global only for the whole programme. Make a gate controlled, and its phase applies when the control is 1 and not when it is 0: it has become a relative phase, which experiments do see. Take X and ω·X: the same gate on their own. Controlled, they are not. ctrl U is the 4×4 matrix that does U to qubit 1 when qubit 0 is 1 (the semantic check's helper ctrl).

To prove two matrices are not equal up to a phase you must rule out every c, a number nobody names. The way in: if A = c·B then every entry of A is c times the same entry of B. So if two entries of B are equal, the same two entries of A must be equal too, whatever c is. That needs one fact about • that holds for every matrix and every c.

Exercise 3 ★★★ entry_smul open

Prove entry (i, j) of c·A is c times entry (i, j) of A. Two inductions: one on a row, for nth of vscale (past the end both sides are 0, by mul_zero_right), and one on the matrix, for row of c • A. c • A unfolds to A.map (vscale c), so the cases are rfl or the induction hypothesis.

Exercise 4 ★★ not_phase_of_ratio open

Prove the refutation rule: if entries (i, j) and (k, l) of B are equal and those of A are not, no phase takes B to A. Suppose one did (intro ⟨c, _, h⟩), and rewrite the two entries of A with h and entry_smul.

Exercise 5 ★★ phase_matters open

Prove both: X and ω·X are equal up to a phase, and their controlled versions are not. For the second, apply not_phase_of_ratio at the entries (0, 0) and (2, 3); the four facts it needs are computations.

The same rule with a zero entry is the one lesson G7 needs: if B is 0 somewhere A is not, no phase takes B to A, since c·0 = 0 for every c.

5. The CNOT of the Bell certificate

Lesson F1's certificate has a witness for the CNOT: op 1, at cycle 8, in trap C0, on ions q0 and q1, q0 (qubit 0) the control. The compiler wrote its pulses beside it in bell.qcert.json, in time order:

"pulses":["R(1.5708,1.5708)@q0","MS(1.5708)@q0,q1","R(-1.5708,0)@q0",
          "R(-1.5708,0)@q1","R(-1.5708,1.5708)@q0"]

These are decompose_cx's five, with qubit 0 on ion q0 and qubit 1 on q1. The programme fires the two −π/2 beams as two instructions, one per ion, where the theorem has one kron. Here is the witness, at its cycle, in the studio: the proved checker's row says the two ions are together in a trap that can gate, and are the op's own. Which gate the five pulses make is Exercise 6.

This figure is drawn from Lean's own replay of bell; it appears when Lean has checked the lesson.

Exercise 6 ★ bell_cnot_witness open

Prove the witness's pulses, each on its own ion, in reverse time order, make CX with the compiler's phase.

Exercise 7 ★ middle_beams open

Prove the two −π/2 beams on different ions commute, and together are the theorem's single kron.

6. CZ

Most other two-qubit gates are built from the CNOT. The compiler's lowering of composite gates writes cz as a CNOT between two Hadamards on the target:

  | "cz", [ c; t ], _ -> seq [ named "h" t; cxg c t; named "h" t ]

seq adds the parts' phases: 0 + (−π/4) + 0. The Compilation page's cz example (cz q[0],q[1];) has these nine pulses in its one witness:

"R(1.5708,-1.5708)@q1","VZ(3.14159)@q1","R(1.5708,1.5708)@q0","MS(1.5708)@q0,q1",
"R(-1.5708,0)@q0","R(-1.5708,0)@q1","R(-1.5708,1.5708)@q0","R(1.5708,-1.5708)@q1",
"VZ(3.14159)@q1"

Exercise 8 ★ cz_lowering open

Prove the lowering exact: CZ = (1⊗H)·CX·(1⊗H). The Hadamards here are the target's, qubit 1.

Exercise 9 ★★ cz_from_witnesses open

The nine pulses are the Hadamard's two on q1, the CNOT's five, and the Hadamard's two again. Prove they make CZ with the phase e^(−iπ/4), grouping each Hadamard's two pulses by ion, without multiplying a single 4×4 matrix: rewrite with h_witness, turn the CNOT's pulses back into CX with Exercise 6 (rw [← bell_cnot_witness]), and finish with Exercise 8. Proofs compose: three facts already checked make a fourth.

7. What this lesson proved

The CNOT is five native pulses times e^(−iπ/4), exactly; that is equality up to a global phase, the right equality for a whole programme and the wrong one for a part that will be controlled. The Bell certificate's CNOT witness carries pulses that make the CNOT. Lesson G5 checks the same pulses the way check_cert does, with a stabilizer tableau, which cannot see a phase at all.

The Lean on this page is Lean 4 (Apache-2.0), compiled to WebAssembly by the cauli/lean4 browser build (Lean 4.33, Apache-2.0), hosted here byte for byte. The proved checker it loads is the repository's QCCDC.Cert, carried to that Lean by a mechanical port: module syntax, and two tail-recursive functions each proved equal to the one it replaces; it gives the repository checker's verdict on every published certificate. The first time a lesson in this part opens, your browser downloads Lean (about 58 MB, kept for next time); a desktop browser is needed.