Checkpoint-1

System #0

You are a physics research assistant specializing in solving complex, research-level problems using precise, step-by-step reasoning.

Input Problems will be provided in Markdown format.

Output (Markdown format)

  1. Step-by-Step Derivation - Show every non-trivial step in the solution. Justify steps using relevant physical laws, theorems, mathematical identities or numerical codes.
  2. Mathematical Typesetting - Use LaTeX for all mathematics: $...$ for inline expressions, $$...$$ for display equations.
  3. Conventions and Units - Follow the unit system and conventions specified in the problem.
  4. Final Answer - At the end of the solution, start a new line with “Final Answer:”, and present the final result.

    For final answers involving values, follow the precision requirements specified in the problem. If no precision is specified: - If an exact value is possible, provide it (e.g., \$\sqrt(2)\$, \$\pi/4\$). - If exact form is not feasible, retain at least 12 significant digits in the result.

  5. Formatting Compliance - If the user requests a specific output format (e.g., code, table), provide the final answer accordingly.

User #1

Problem setup:

In quantum error correction, you encode quantum states into logical states made of many qubits in order to improve their resilience to errors. In quantum error detection, you do the same but can only detect the presence of errors and not correct them. In this problem, we will consider a single [[4,2,2]] quantum error detection code, which encodes two logical qubits into four physical qubits, and investigate how robust logical quantum operations in this code are to quantum errors.

Our convention is that the four physical qubits in the [[4,2,2]] code are labelled 0,1,2,3. The two logical qubits are labelled A and B. The stabilizers are \(XXXX\) and \(ZZZZ\), where \(X\) and \(Z\) are Pauli matrices. The logical \(X\) and \(Z\) operators on the two qubits are \(X_A = XIXI\), \(X_B=XXII\), \(Z_A = ZZII\), \(Z_B = ZIZI\), up to multiplication by stabilizers.

We will consider different state preparation circuits consisting of controlled not \(CNOT_{ij}\) gates, where \(CNOT_{ij}\) has control qubit \(i\) and target qubit \(j\). As a simple model of quantum errors in hardware, we will suppose that each \(CNOT_{ij}\) gate in the circuit has a two qubit depolarizing error channel following it that produces one of the 15 non-identity two-qubit Paulis with equal probability \(p/15\). The probability \(p\) indicates the probability of an error in a single two-qubit gate. We will assess the logical infidelity of certain state preparation protocols as a function of the physical infidelity \(p\).

Checkpoints

Checkpoint 1

Suppose that we wish to prepare a logical two-qubit GHZ state \((|00\rangle_{AB}+|11\rangle_{AB})/\sqrt{2}\) in the [[4,2,2]] code. To do so, we use the following state preparation circuit:

\[ (CNOT_{03}) (H_0) (CNOT_{21}) (H_2). \]

Note that this equation is written in matrix multiplication order, while the quantum operations in the circuit occur in the reverse order (from right-to-left in the above equation). \(H\) is a single-qubit Hadamard gate.

What is the physical state fidelity of the final physical 4-qubit state at the end of the circuit as a function of the two-qubit gate error rate \(p\)?

Assistant #2
Tool Call (code to execute)
import numpy as np

# Pauli matrices
I = np.eye(2)
X = np.array([[0,1],[1,0]], dtype=complex)
Y = np.array([[0,-1j],[1j,0]], dtype=complex)
Z = np.array([[1,0],[0,-1]], dtype=complex)
H = (1/np.sqrt(2))*np.array([[1,1],[1,-1]], dtype=complex)

# Tensor product utility
from functools import reduce

def kron(*ops):
    return reduce(np.kron, ops)

# 4-qubit basis: qubits ordered (0,1,2,3)

# Build CNOT_ij unitary on 4 qubits

def CNOT_ij(i,j):
    # Build projector form: |0><0|_i ⊗ I + |1><1|_i ⊗ X_j
    P0 = np.array([[1,0],[0,0]], dtype=complex)
    P1 = np.array([[0,0],[0,1]], dtype=complex)
    ops0 = [I,I,I,I]
    ops1 = [I,I,I,I]
    ops0[i] = P0
    ops1[i] = P1
    # X on j for second term
    ops1[j] = X
    return kron(*ops0) + kron(*ops1)

# Hadamard on qubit q (others identity)

def H_q(q):
    ops = [I,I,I,I]
    ops[q] = H
    return kron(*ops)

# Two-qubit Pauli labels and matrices
Psingle = [I, X, Y, Z]
Pnames = ['I','X','Y','Z']

# Build two-qubit Pauli on a specified pair (a,b) with order qubit index 0..3

def two_qubit_pauli_on_pair(a,b, pa, pb):
    ops = [I,I,I,I]
    ops[a] = Psingle[pa]
    ops[b] = Psingle[pb]
    return kron(*ops)

# Circuit unitaries (ideal): U = CNOT_03 * H0 * CNOT_21 * H2
U = CNOT_ij(0,3) @ H_q(0) @ CNOT_ij(2,1) @ H_q(2)

# Initial |0000>
zero = np.array([[1],[0]], dtype=complex)
psi0 = kron(zero, zero, zero, zero)
psi_ideal = U @ psi0
rho_ideal = psi_ideal @ psi_ideal.conj().T

# Build the noisy rho(p) symbolically as sum over errors with weights
# But we'll just compute the coefficient of fidelity as a function of p by summing contributions

# Enumerate two-qubit paulis on pair (2,1) and (0,3)
non_id_pairs = []
for a in range(4):
    for b in range(4):
        name = Pnames[a]+Pnames[b]
        non_id_pairs.append((a,b,name))

# Build the list of 16 two-qubit paulies and classify which are identity
pairs = non_id_pairs

# Let's compute the probability weight that maps to fidelity 1: we check for each pair of errors whether
# E03 * U * E21 * ... acting on |0000> equals psi_ideal up to global phase. We can test overlap squared ~1.

# Build E for pair (2,1) and (0,3)

import math

def fidelity_weight():
    # We'll compute count of (pauli on 03, on 21) that leave the state invariant up to phase.
    survivors = []
    for a03 in range(4):
        for b03 in range(4):
            E03 = two_qubit_pauli_on_pair(0,3, a03, b03)
            for a21 in range(4):
                for b21 in range(4):
                    E21 = two_qubit_pauli_on_pair(2,1, a21, b21)
                    # Build final state with this error model: errors applied after CNOTs
                    # That is: first H2, then CNOT21, then error E21, then H0, then CNOT03, then error E03
                    psi = E03 @ CNOT_ij(0,3) @ H_q(0) @ E21 @ CNOT_ij(2,1) @ H_q(2) @ psi0
                    # Overlap magnitude
                    overlap = (psi_ideal.conj().T @ psi)[0,0]
                    if np.allclose(abs(overlap), 1.0, atol=1e-12):
                        survivors.append(((a03,b03),(a21,b21)))
    return survivors

survivors = fidelity_weight()
len_survivors, survivors[:10]
Tool #3
Traceback (most recent call last):
  File "<stdin>", line 99, in <module>
NameError: name 'len_survivors' is not defined. Did you mean: 'survivors'?
Assistant #4
len(survivors), survivors[:20]
Tool #5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'survivors' is not defined
Assistant #6
# Re-run the computation quickly
import numpy as np
I = np.eye(2); X = np.array([[0,1],[1,0]], complex)
Y = np.array([[0,-1j],[1j,0]], complex)
Z = np.array([[1,0],[0,-1]], complex)
H = (1/np.sqrt(2))*np.array([[1,1],[1,-1]], complex)
from functools import reduce

def kron(*ops):
    return reduce(np.kron, ops)

def CNOT_ij(i,j):
    P0 = np.array([[1,0],[0,0]], complex)
    P1 = np.array([[0,0],[0,1]], complex)
    ops0 = [I,I,I,I]
    ops1 = [I,I,I,I]
    ops0[i] = P0
    ops1[i] = P1
    ops1[j] = X
    return kron(*ops0) + kron(*ops1)

def H_q(q):
    ops = [I,I,I,I]
    ops[q] = H
    return kron(*ops)

Psingle = [I,X,Y,Z]

U = CNOT_ij(0,3) @ H_q(0) @ CNOT_ij(2,1) @ H_q(2)
zero = np.array([[1],[0]], complex)
psi0 = kron(zero,zero,zero,zero)
psi_ideal = U @ psi0

survivors = []
for a03 in range(4):
    for b03 in range(4):
        E03 = kron(Psingle[a03], I, I, Psingle[b03])
        for a21 in range(4):
            for b21 in range(4):
                E21 = kron(I, Psingle[b21], Psingle[a21], I)  # careful: pair (2,1)
                psi = E03 @ CNOT_ij(0,3) @ H_q(0) @ E21 @ CNOT_ij(2,1) @ H_q(2) @ psi0
                overlap = (psi_ideal.conj().T @ psi)[0,0]
                if np.allclose(abs(overlap), 1.0, atol=1e-10):
                    survivors.append(((a03,b03),(a21,b21)))

len(survivors), survivors[:12]
Tool #7
''
Assistant #8
Tool Call (code to execute)
print(len(survivors))
print(survivors[:16])
Tool #9
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'survivors' is not defined
Assistant #10
# Recompute succinctly and print
import numpy as np
I = np.eye(2); X = np.array([[0,1],[1,0]], complex); Y = np.array([[0,-1j],[1j,0]], complex); Z = np.array([[1,0],[0,-1]], complex)
H = (1/np.sqrt(2))*np.array([[1,1],[1,-1]], complex)
from functools import reduce

def kron(*ops):
    return reduce(np.kron, ops)

def CNOT_ij(i,j):
    P0 = np.array([[1,0],[0,0]], complex)
    P1 = np.array([[0,0],[0,1]], complex)
    ops0 = [I,I,I,I]
    ops1 = [I,I,I,I]
    ops0[i] = P0
    ops1[i] = P1
    ops1[j] = X
    return kron(*ops0) + kron(*ops1)

def H_q(q):
    ops = [I,I,I,I]
    ops[q] = H
    return kron(*ops)

Psingle = [I,X,Y,Z]
U = CNOT_ij(0,3) @ H_q(0) @ CNOT_ij(2,1) @ H_q(2)
zero = np.array([[1],[0]], complex)
psi0 = kron(zero,zero,zero,zero)
psi_ideal = U @ psi0

survivors = []
for a03 in range(4):
    for b03 in range(4):
        E03 = kron(Psingle[a03], np.eye(2), np.eye(2), Psingle[b03])
        for a21 in range(4):
            for b21 in range(4):
                E21 = kron(np.eye(2), Psingle[b21], Psingle[a21], np.eye(2))
                psi = E03 @ CNOT_ij(0,3) @ H_q(0) @ E21 @ CNOT_ij(2,1) @ H_q(2) @ psi0
                ov = (psi_ideal.conj().T @ psi)[0,0]
                if np.allclose(abs(ov), 1.0, atol=1e-10):
                    survivors.append(((a03,b03),(a21,b21)))

print('number survivors =', len(survivors))
# Show which two-qubit paulis on each pair survive (indexes 0:I,1:X,2:Y,3:Z)
print(survivors[:20])
Tool #11
number survivors = 16
[((0, 0), (0, 0)), ((0, 0), (1, 1)), ((0, 0), (2, 2)), ((0, 0), (3, 3)), ((1, 1), (0, 0)), ((1, 1), (1, 1)), ((1, 1), (2, 2)), ((1, 1), (3, 3)), ((2, 2), (0, 0)), ((2, 2), (1, 1)), ((2, 2), (2, 2)), ((2, 2), (3, 3)), ((3, 3), (0, 0)), ((3, 3), (1, 1)), ((3, 3), (2, 2)), ((3, 3), (3, 3))]
Assistant #12
Tool Call (code to execute)
import numpy as np
I = np.eye(2); X = np.array([[0,1],[1,0]], complex); Y = np.array([[0,-1j],[1j,0]], complex); Z = np.array([[1,0],[0,-1]], complex)
H = (1/np.sqrt(2))*np.array([[1,1],[1,-1]], complex)
from functools import reduce

def kron(*ops):
    return reduce(np.kron, ops)

def CNOT_ij(i,j):
    P0 = np.array([[1,0],[0,0]], complex)
    P1 = np.array([[0,0],[0,1]], complex)
    ops0 = [I,I,I,I]
    ops1 = [I,I,I,I]
    ops0[i] = P0
    ops1[i] = P1
    ops1[j] = X
    return kron(*ops0) + kron(*ops1)

def H_q(q):
    ops = [I,I,I,I]
    ops[q] = H
    return kron(*ops)

Psingle = [I,X,Y,Z]
U = CNOT_ij(0,3) @ H_q(0) @ CNOT_ij(2,1) @ H_q(2)
zero = np.array([[1],[0]], complex)
psi0 = kron(zero,zero,zero,zero)
psi_ideal = U @ psi0
rho_ideal = psi_ideal @ psi_ideal.conj().T

# Build final density matrix under the channel parameter p

def rho_of_p(p):
    rho = np.zeros((16,16), complex)
    # enumerate E21 and E03 errors and accumulate weights
    for a03 in range(4):
        for b03 in range(4):
            weight03 = (1-p) if (a03==0 and b03==0) else (p/15)
            E03 = kron(Psingle[a03], I, I, Psingle[b03])
            for a21 in range(4):
                for b21 in range(4):
                    weight21 = (1-p) if (a21==0 and b21==0) else (p/15)
                    E21 = kron(I, Psingle[b21], Psingle[a21], I)
                    psi = E03 @ CNOT_ij(0,3) @ H_q(0) @ E21 @ CNOT_ij(2,1) @ H_q(2) @ psi0
                    rho += weight03 * weight21 * (psi @ psi.conj().T)
    return rho

for p in [0.0, 0.01, 0.1, 0.2, 0.5, 1.0]:
    rho = rho_of_p(p)
    F = (psi_ideal.conj().T @ rho @ psi_ideal)[0,0].real
    print(p, F, 'vs formula', (1 - 4*p/5)**2)
Tool #13
0.0 0.9999999999999992 vs formula 1.0
0.01 0.9840639999999993 vs formula 0.9840639999999999
0.1 0.8463999999999989 vs formula 0.8464
0.2 0.7056000000000002 vs formula 0.7055999999999999
0.5 0.3599999999999996 vs formula 0.36

1.0 0.039999999999999994 vs formula 0.03999999999999998
Assistant #14
  1. Step-by-Step Derivation
  • Ideal state prepared by the circuit
  • Start from |0000⟩.
  • Apply H2: puts qubit 2 in (|0⟩ + |1⟩)/√2.
  • Apply CNOT21 (control 2 → target 1): prepares a Bell pair on qubits (2,1), |Φ+⟩21 = (|00⟩ + |11⟩)/√2.
  • Apply H0 and then CNOT03 (control 0 → target 3): prepares a Bell pair on qubits (0,3), |Φ+⟩03 = (|00⟩ + |11⟩)/√2.
  • Hence the ideal final state is the product of two Bell pairs
\[ |\psi_{\text{ideal}}\rangle = |\Phi^+\rangle_{03}\otimes|\Phi^+\rangle_{21}. \]
In the computational basis (qubits ordered 0,1,2,3):
\[ |\psi_{\text{ideal}}\rangle = \tfrac{1}{2}\big(|0000\rangle + |0110\rangle + |1001\rangle + |1111\rangle\big). \]
  • This state is a code state stabilized by the given code stabilizers \(XXXX\), \(ZZZZ\) and by the logical Bell stabilizers \(Z_AZ_B=IZZI\) and \(X_AX_B=IXXI\).

  • Noise model and where it acts

  • A two-qubit depolarizing channel acts after each CNOT:
    • After CNOT21, a channel on qubits (2,1).
    • After CNOT03, a channel on qubits (0,3).
  • Each channel applies \(II\) with probability \(1-p\), and one of the 15 non-identity two-qubit Paulis with probability \(p/15\) each.
  • The two channels are independent and act on disjoint pairs, so the total error is \(E_{03}\otimes E_{21}\).

  • Fidelity for a Bell pair under two-qubit depolarizing noise

  • For a Bell state \(|\Phi^+\rangle\), the Pauli operators that leave the state invariant (up to an irrelevant global phase) are precisely
\[ \{II,\; XX,\; YY,\; ZZ\}. \]
  • Therefore, for a single two-qubit depolarizing channel with parameter \(p\),
\[ F_{\text{pair}}(p) = \Pr(II) + \Pr(XX) + \Pr(YY) + \Pr(ZZ) = (1-p) + 3\cdot \frac{p}{15} = 1 - \frac{4}{5}p. \]
  • Total four-qubit fidelity
  • Since the ideal state is a product \(|\Phi^+\rangle_{03}\otimes|\Phi^+\rangle_{21}\) and the two channels are independent on the two disjoint pairs, the total fidelity factorizes:
\[ F_{\text{phys}}(p) = \big(F_{\text{pair}}(p)\big)^2 = \left(1 - \frac{4}{5}p\right)^2. \]
  1. Mathematical Typesetting
  • Final expression:
\[ F_{\text{phys}}(p) = \left(1 - \frac{4}{5}p\right)^2 = 1 - \frac{8}{5}p + \frac{16}{25}p^2. \]
  1. Conventions and Units
  • Probabilities are dimensionless. The parameter \(p\in[0,1]\) is the error probability per two-qubit gate.
  1. Final Answer: \(F_{\text{phys}}(p) = \left(1 - \dfrac{4}{5}p\right)^2 = 1 - \dfrac{8}{5}p + \dfrac{16}{25}p^2.\)
User #15

Populate your final answer into the code template provided below. This step is purely for formatting/display purposes. No additional reasoning or derivation should be performed. Do not import any modules or packages beyond what is provided in the template.

import sympy as sp

p = sp.symbols('p')

def answer(p):
    r"""
    Return the expression of the physical state fidelity of the final physical 4-qubit state
    at the end of the circuit as a function of the two-qubit gate error rate $p$.

    Inputs
    ----------
    p: sympy.Symbol, two-qubit gate error rate $p$

    Outputs
    ----------
    F_physical: sympy.Expr, the physical state fidelity of the final physical 4-qubit state
    """

    # ------------------ FILL IN YOUR RESULTS BELOW ------------------
    F_physical = ...  # a SymPy expression of inputs
    # ---------------------------------------------------------------

    return F_physical
Assistant #16
import sympy as sp

p = sp.symbols('p')

def answer(p):
    r"""
    Return the expression of the physical state fidelity of the final physical 4-qubit state
    at the end of the circuit as a function of the two-qubit gate error rate $p$.

    Inputs
    ----------
    p: sympy.Symbol, two-qubit gate error rate $p$

    Outputs
    ----------
    F_physical: sympy.Expr, the physical state fidelity of the final physical 4-qubit state
    """

    # ------------------ FILL IN YOUR RESULTS BELOW ------------------
    F_physical = (1 - sp.Rational(4, 5)*p)**2  # a SymPy expression of inputs
    # ---------------------------------------------------------------

    return F_physical