Checkpoint-3

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\).

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
  1. Step-by-Step Derivation
  • Ideal output state and its stabilizer:
  • The circuit (right-to-left) is:
    • Apply H on qubit 2, then CNOT2→1: prepares a Bell state on qubits (2,1), stabilized by {X2X1, Z2Z1}.
    • Apply H on qubit 0, then CNOT0→3: prepares a Bell state on qubits (0,3), stabilized by {X0X3, Z0Z3}.
  • The final ideal 4-qubit state is thus a tensor product of two Bell pairs (on 21 and 03). A convenient set of 4 independent stabilizers for this pure state is
\[ \{\,X_2X_1,\; Z_2Z_1,\; X_0X_3,\; Z_0Z_3\,\}. \]
This is equivalent (by products) to the code stabilizers XXXX, ZZZZ together with IXXI and IZZI, and it encodes the logical Bell state (|00⟩AB+|11⟩AB)/√2.
  • Noise model localization and propagation:
  • A two-qubit depolarizing channel is applied after each CNOT gate.
  • After CNOT2→1, the noise acts only on qubits (2,1). The remaining gates (H0 and CNOT0→3) act on qubits (0,3) only, so this error does not propagate or change.
  • After CNOT0→3, the noise acts only on qubits (0,3) and there are no further gates.
  • Therefore, the final error operator has the form
\[ F = P_{(2,1)} \otimes Q_{(0,3)}, \]
where P acts on qubits (2,1) and Q acts on qubits (0,3).
  • Fidelity for a stabilizer state under Pauli errors:
  • For a pure stabilizer state |ψ⟩, and a Pauli error F, the overlap is
\[ 1,& F \in \mathcal{S}(\psi),\\ 0,& F \notin \mathcal{S}(\psi), \]
where 𝒮(ψ) is the stabilizer group of |ψ⟩.
  • Hence, the physical state fidelity equals the total probability that the net error F lies in the stabilizer group of the ideal state.

  • Membership condition on each pair:

  • The subgroup on qubits (2,1) leaving the Bell state invariant is generated by X2X1 and Z2Z1, hence it is
\[ \{\,I\!I,\; X_2X_1,\; Z_2Z_1,\; Y_2Y_1\,\}. \]
  • Similarly, on qubits (0,3) the invariant subgroup is
\[ \{\,I\!I,\; X_0X_3,\; Z_0Z_3,\; Y_0Y_3\,\}. \]
  • Because the final state is a tensor product of the two Bell pairs, the full stabilizer group is the direct product of these two subgroups. Therefore,
\[ F \in \mathcal{S} \iff \big(P_{(2,1)} \in \{I\!I, X\!X, Y\!Y, Z\!Z\}\big)\ \text{and}\ \big(Q_{(0,3)} \in \{I\!I, X\!X, Y\!Y, Z\!Z\}\big). \]
  • Counting “good” errors from the depolarizing channel:
  • Each two-qubit depolarizing channel yields:
    • Identity with probability 1−p,
    • Each of the 15 non-identity two-qubit Paulis with probability p/15.
  • Among these 16 possibilities, the ones that keep the Bell state invariant on a given pair are exactly {II, XX, YY, ZZ}, i.e., 1 (identity) + 3 non-identity.
  • Hence, for one channel,
\[ \Pr[\text{good on a given pair}] = (1-p) + 3\cdot\frac{p}{15} = 1 - \frac{4p}{5}. \]
  • Independence across the two CNOTs:
  • The two error channels act on disjoint pairs and are independent, so the total fidelity is the product of the “good” probabilities:
\[ F_{\text{phys}}(p) = \left(1 - \frac{4p}{5}\right)^2. \]
  1. Mathematical Typesetting
  • All expressions above are typeset in LaTeX.
  1. Conventions and Units
  • Qubit labels and gate conventions follow the problem statement. The Hadamards are assumed ideal; only the two CNOTs are followed by depolarizing noise.
  1. Final Answer: F_phys(p) = (1 - 4p/5)^2.
User #3

Checkpoint 2

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 logical state fidelity of the final 2-qubit logical state at the end of the circuit as a function of the two-qubit gate error rate \(p\), assuming the state is post-selected on all detectable errors in the code?

Assistant #4
  1. Step-by-Step Derivation
  • Circuit and ideal output:
  • Gates (right-to-left): H2, CNOT2→1 prepare a Bell pair on qubits (2,1); H0, CNOT0→3 prepare a Bell pair on qubits (0,3).
  • Ideal 4-qubit state: |Φ+⟩21 ⊗ |Φ+⟩03, stabilized by {X2X1, Z2Z1} and {X0X3, Z0Z3}.
  • This state lies in the [[4,2,2]] code space (stabilizers XXXX, ZZZZ) and encodes the logical Bell state (|00⟩AB + |11⟩AB)/√2.

  • Noise model and error structure:

  • After each CNOT, a 2-qubit depolarizing channel acts on the corresponding pair: on (2,1) and on (0,3), independently.
  • Each channel outputs:
    • II with probability 1 − p,
    • each of the 15 non-identity 2-qubit Paulis with probability p/15.
  • Let P act on (2,1) and Q on (0,3). The net physical error is E = P ⊗ Q.

  • Post-selection (detectable errors discarded):

  • We “accept” (keep) runs that yield +1 for both code stabilizers XXXX and ZZZZ.
  • Since XXXX = (X2X1)(X0X3) and ZZZZ = (Z2Z1)(Z0Z3), commutation with E factorizes by pairs.
  • For a two-qubit Pauli R, define sX(R) = +1 if R commutes with X⊗X, and −1 if it anticommutes; sZ(R) = +1 if R commutes with Z⊗Z, and −1 if it anticommutes.
  • Acceptance condition is equivalently sX(P) = sX(Q) and sZ(P) = sZ(Q).

  • Classifying two-qubit Paulis by (sX, sZ):

  • Using single-qubit commutation (I: ++, X: +−, Z: −+, Y: −−), the 16 two-qubit Paulis partition into four classes:
    • ++ : {II, XX, YY, ZZ} (4 total; 3 non-identity),
    • +− : {IX, XI, ZY, YZ} (4),
    • −+ : {IZ, ZI, XY, YX} (4),
    • −− : {IY, YI, XZ, ZX} (4).
  • Acceptance requires P and Q be in the same class (including the identity, which is in ++).

  • Acceptance probability Ppass:

  • Cases contributing to acceptance: 1) No error: (1 − p)^2. 2) Exactly one non-identity error: must be in ++ (3 of 15) to pass; either pair can have it: 2 × (1 − p) × (3p/15) = 2(1 − p)(p/5). 3) Two non-identity errors: both must be in the same class:
    • ++: 3 × 3 = 9 pairs,
    • +−: 4 × 4 = 16,
    • −+: 4 × 4 = 16,
    • −−: 4 × 4 = 16, total 57, giving 57(p/15)^2.
  • Therefore
\[ \]
  • Logical action of accepted errors and “good” events:
  • The target logical state |Φ+⟩AB is stabilized by X_A X_B and Z_A Z_B (and hence also by Y_A Y_B).
  • Errors that are logically harmless (i.e., keep |Φ+⟩AB unchanged) are those whose logical action is in the set
\[ \mathcal{G} = \{I,\; X_A X_B,\; Z_A Z_B,\; Y_A Y_B\} \times \mathcal{S}, \]
where 𝒮 is the code stabilizer.
  • For class ++ on a single pair:
    • On (2,1): XX = X2X1 = X_A X_B, ZZ = Z2Z1 = Z_A Z_B, YY = Y2Y1 = Y_A Y_B (up to phases); similarly on (0,3).
    • Hence any accepted event with P, Q ∈ ++ (including identity on either side) yields E ∈ 𝒮 × 𝒢 and is logically harmless.
  • For the other classes:
    • +− on both pairs yields a single logical X (either X_A or X_B) up to 𝒮 (e.g., P=XI on (2,1), Q=XI on (0,3) gives E = X0X1 = X_B).
    • −+ on both pairs yields a single logical Z (either Z_A or Z_B) up to 𝒮.
    • −− on both pairs yields a single logical Y (either Y_A or Y_B) up to 𝒮.
    • Any single-logical Pauli flips at least one of {X_A X_B, Z_A Z_B}, thus maps |Φ+⟩AB to an orthogonal Bell state.
  • Therefore, among accepted events, the only “good” ones (that keep the logical state) are exactly those with P,Q ∈ ++ (including identity).
  • Probability of “good” accepted events:
\[ \]
  • Logical state fidelity conditioned on acceptance:
\[ \]
  • Small-p behavior (useful check): since first-order errors are detected, the leading infidelity is quadratic:
\[ F_{\text{logical}}(p) = 1 - \frac{16}{75}p^2 + O(p^3). \]
  1. Mathematical Typesetting

All equations have been typeset in LaTeX.

  1. Conventions and Units
  • Qubit labels and logical operator identifications follow the problem statement.
  • Only the two CNOT gates are noisy; Hadamards are ideal; post-selection is assumed perfect.
  1. Final Answer: F_logical(p) = [(1 - 4p/5)^2] / [1 - (8/5)p + (64/75)p^2], with small-p expansion F_logical(p) = 1 - (16/75)p^2 + O(p^3).
User #5

Checkpoint 3

Suppose that we prepare a logical two-qubit \(|00\rangle_{AB}\) state in the [[4,2,2]] code. To do so, we introduce an ancilla qubit, qubit 4, and use the following state preparation circuit:

\[ M_4 (CNOT_{04}) (CNOT_{34}) (CNOT_{23}) (CNOT_{10}) (CNOT_{12}) (H_1) \]

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 and \(M\) is a single-qubit measurement. The ancilla is used to detect errors in the state preparation circuit and makes the circuit fault-tolerant. If the ancilla measurement is \(|0\rangle\) (\(|1\rangle\)), the state preparation succeeds (fails).

What is the logical state fidelity of the final 2-qubit logical state at the end of the circuit as a function of two-qubit gate error rate \(p\), assuming the state is post-selected on all detectable errors in the code and on the ancilla qubit measuring \(|0\rangle\)?

Assistant #6
Tool Call (code to execute)
from itertools import product
from fractions import Fraction

# Number of qubits: 5 (0..3 data, 4 ancilla)
N = 5

def pauli_vec_from_label_on_pair(q1, q2, label):
    # label is a pair like 'IX','ZY', etc on the ordered tuple (q1,q2)
    # returns (x,z) as lists of 0/1 length N
    x = [0]*N
    z = [0]*N
    for idx, q in enumerate((q1, q2)):
        ch = label[idx]
        if ch == 'I':
            pass
        elif ch == 'X':
            x[q] ^= 1
        elif ch == 'Z':
            z[q] ^= 1
        elif ch == 'Y':
            x[q] ^= 1
            z[q] ^= 1
        else:
            raise ValueError('bad')
    return tuple(x), tuple(z)

# Conjugation by CNOT(c->t):
# x_c' = x_c; x_t' = x_t ^ x_c
# z_c' = z_c ^ z_t; z_t' = z_t

def conj_cnot(x, z, c, t):
    x = list(x)
    z = list(z)
    # x_t ^= x_c
    x[t] ^= x[c]
    # z_c ^= z_t
    z[c] ^= z[t]
    return tuple(x), tuple(z)

# Multiplying two Paulis ignoring phase: XOR the x,z bits

def mul_paulixz(a, b):
    x1, z1 = a
    x2, z2 = b
    return tuple((x1[i]^x2[i]) for i in range(N)), tuple((z1[i]^z2[i]) for i in range(N))

# Build all 2-qubit Pauli labels on a pair
singles = ['I','X','Y','Z']
labels_pair = [a+b for a in singles for b in singles]
# Remove 'II' later when needed

# Gates in chronological order (right-to-left execution):
# After each of these CNOTs there is a noise channel
cnot_list = [(1,2), (1,0), (2,3), (3,4), (0,4)]
num_gates = len(cnot_list)

# Precompute pushforward of each pair-Pauli at each location to the end
pushforward = []  # list of dict: label->(x,z)
for i, (c,t) in enumerate(cnot_list):
    mp = {}
    for lab in labels_pair:
        # Build Pauli supported on the pair
        x,z = pauli_vec_from_label_on_pair(c,t,lab)
        # Conjugate by subsequent CNOTs (i+1..end)
        for (c2,t2) in cnot_list[i+1:]:
            x,z = conj_cnot(x,z,c2,t2)
        mp[lab] = (x,z)
    pushforward.append(mp)

# Build the 16-element stabilizer group of the target logical |00>_AB on data qubits
# Generators: XXXX, ZZZZ, ZZII, ZIZI on qubits 0..3

def pauli_from_str_data(s):
    # s is 4-char over IXYZ for data 0..3
    x = [0]*N
    z = [0]*N
    for q,ch in enumerate(s):
        if ch=='I':
            pass
        elif ch=='X':
            x[q]=1
        elif ch=='Z':
            z[q]=1
        elif ch=='Y':
            x[q]=1; z[q]=1
    return (tuple(x), tuple(z))

# Data-only Paulis (ancilla bits zero)
S1 = pauli_from_str_data('XXXX')
S2 = pauli_from_str_data('ZZZZ')
S3 = pauli_from_str_data('ZZII')
S4 = pauli_from_str_data('ZIZI')

# Generate group
T = set()
for a in [0,1]:
    for b in [0,1]:
        for c in [0,1]:
            for d in [0,1]:
                x = [0]*N; z = [0]*N
                for (flag, P) in ((a,S1),(b,S2),(c,S3),(d,S4)):
                    if flag:
                        x = [x[i]^P[0][i] for i in range(N)]
                        z = [z[i]^P[1][i] for i in range(N)]
                T.add((tuple(x),tuple(z)))
# Sanity: should be 16 elements
# print('Size T:', len(T))

# Functions to test acceptance

def ancilla_accept(x,z):
    # accept if no X (or Y) on qubit 4, i.e., x[4]==0
    return (x[4] == 0)

def code_accept(x,z):
    # accept if data X parity even and data Z parity even
    sx = sum(x[:4]) % 2
    sz = sum(z[:4]) % 2
    return (sx==0 and sz==0)

def good_data(x,z):
    # Check if data part (qubits 0..3) lies in T
    # Zero out ancilla bits
    x0 = list(x); z0 = list(z)
    x0[4]=0; z0[4]=0
    return (tuple(x0),tuple(z0)) in T

# Now enumerate all error combinations. We will accumulate coefficients of polynomial in p
# Probability weight for each per-gate error choice is (1-p) if 'II', else (p/15)
# The total accepted probability is sum_k coef[k] * p^k, where coef[k] rational numbers

from collections import defaultdict
coef_pass = defaultdict(Fraction)
coef_good = defaultdict(Fraction)

# Precompute list of labels and their (k, weight_factor)
# Represent (k, c) where k = number of non-identity errors contributed (0 or 1 per gate), and c = fractional coefficient (1 for identity, 1/15 for non-identity)
choices = []
for lab in labels_pair:
    if lab == 'II':
        choices.append((lab, 0, Fraction(1,1)))
    else:
        choices.append((lab, 1, Fraction(1,15)))

# For speed, we can precompute for each gate i and each label the pushed (x,z)
# Already in pushforward

# Enumerate
cnt=0
for labs in product(range(len(choices)), repeat=num_gates):
    # Build final E_total
    x = tuple([0]*N)
    z = tuple([0]*N)
    k_total = 0
    weight = Fraction(1,1)
    for i, choice_idx in enumerate(labs):
        lab, k, fac = choices[choice_idx]
        k_total += k
        weight *= fac
        # pushforward to end
        x_i, z_i = pushforward[i][lab]
        # multiply
        x = tuple((x[j]^x_i[j]) for j in range(N))
        z = tuple((z[j]^z_i[j]) for j in range(N))
    # Now acceptance tests
    if ancilla_accept(x,z) and code_accept(x,z):
        coef_pass[k_total] += weight
        if good_data(x,z):
            coef_good[k_total] += weight
    cnt += 1

# Now build polynomials P_pass(p) = sum_k coef_pass[k]*(1-p)^{5-k}*(p)^k factoring 1/15^k; But we already included 1/15^k in weight.
# Actually our weight is product over gates of either 1 for identity or 1/15 for non-identity, but missing the (1-p) and p factors.
# The total probability contribution of all cases with exactly k non-identity errors is weight * (1-p)^{5-k} * p^k.

# Let's express polynomials as rational coefficients for powers of p
# Expand sum_k A_k * (1-p)^{5-k} * p^k where A_k = coef_pass[k]

from math import comb

def expand_poly(A):
    # A: dict k->Fraction coefficient
    # Returns dict deg->Fraction for polynomial in p up to degree 5
    P = defaultdict(Fraction)
    for k, Ak in A.items():
        # (1-p)^{5-k} * p^k = sum_{m=0}^{5-k} C(5-k,m)*(-p)^m * p^k = sum_{m} C(5-k,m)*(-1)^m * p^{k+m}
        for m in range(0, 5-k+1):
            deg = k + m
            coeff = Ak * Fraction(comb(5-k, m), 1) * (Fraction(-1,1) if (m%2==1) else Fraction(1,1))
            P[deg] += coeff
    return P

P_pass = expand_poly(coef_pass)
P_good = expand_poly(coef_good)

# Convert to simplified Fractions
# Show polynomials
maxdeg = 5
#print('P_pass coeffs by degree:')
#for d in range(maxdeg+1):
#    print(d, P_pass.get(d, Fraction(0,1)))
#print('P_good coeffs by degree:')
#for d in range(maxdeg+1):
#    print(d, P_good.get(d, Fraction(0,1)))

# Let's format as rational numbers
P_pass_list = [P_pass.get(d, Fraction(0,1)) for d in range(maxdeg+1)]
P_good_list = [P_good.get(d, Fraction(0,1)) for d in range(maxdeg+1)]

P_pass_list, P_good_list, sum(P_pass_list)
Tool #7
''
Assistant #8
Tool Call (code to execute)
from itertools import product
from fractions import Fraction
from math import comb
from collections import defaultdict

N = 5

def pauli_vec_from_label_on_pair(q1, q2, label):
    x = [0]*N
    z = [0]*N
    for idx, q in enumerate((q1, q2)):
        ch = label[idx]
        if ch == 'I':
            pass
        elif ch == 'X':
            x[q] ^= 1
        elif ch == 'Z':
            z[q] ^= 1
        elif ch == 'Y':
            x[q] ^= 1
            z[q] ^= 1
        else:
            raise ValueError('bad')
    return tuple(x), tuple(z)

def conj_cnot(x, z, c, t):
    x = list(x)
    z = list(z)
    x[t] ^= x[c]
    z[c] ^= z[t]
    return tuple(x), tuple(z)

def mul_paulixz(a, b):
    x1, z1 = a
    x2, z2 = b
    return tuple((x1[i]^x2[i]) for i in range(N)), tuple((z1[i]^z2[i]) for i in range(N))

singles = ['I','X','Y','Z']
labels_pair = [a+b for a in singles for b in singles]

cnot_list = [(1,2), (1,0), (2,3), (3,4), (0,4)]
num_gates = len(cnot_list)

pushforward = []
for i, (c,t) in enumerate(cnot_list):
    mp = {}
    for lab in labels_pair:
        x,z = pauli_vec_from_label_on_pair(c,t,lab)
        for (c2,t2) in cnot_list[i+1:]:
            x,z = conj_cnot(x,z,c2,t2)
        mp[lab] = (x,z)
    pushforward.append(mp)

# target stabilizer group T on data only

def pauli_from_str_data(s):
    x = [0]*N
    z = [0]*N
    for q,ch in enumerate(s):
        if ch=='I':
            pass
        elif ch=='X':
            x[q]=1
        elif ch=='Z':
            z[q]=1
        elif ch=='Y':
            x[q]=1; z[q]=1
    return (tuple(x), tuple(z))

S1 = pauli_from_str_data('XXXX')
S2 = pauli_from_str_data('ZZZZ')
S3 = pauli_from_str_data('ZZII')
S4 = pauli_from_str_data('ZIZI')

T = set()
for a in [0,1]:
    for b in [0,1]:
        for c in [0,1]:
            for d in [0,1]:
                x = [0]*N; z = [0]*N
                for (flag, P) in ((a,S1),(b,S2),(c,S3),(d,S4)):
                    if flag:
                        x = [x[i]^P[0][i] for i in range(N)]
                        z = [z[i]^P[1][i] for i in range(N)]
                T.add((tuple(x),tuple(z)))


def ancilla_accept(x,z):
    return (x[4] == 0)

def code_accept(x,z):
    sx = sum(x[:4]) % 2
    sz = sum(z[:4]) % 2
    return (sx==0 and sz==0)

def good_data(x,z):
    x0 = list(x); z0 = list(z)
    x0[4]=0; z0[4]=0
    return (tuple(x0),tuple(z0)) in T

coef_pass = defaultdict(Fraction)
coef_good = defaultdict(Fraction)

choices = []
for lab in labels_pair:
    if lab == 'II':
        choices.append((lab, 0, Fraction(1,1)))
    else:
        choices.append((lab, 1, Fraction(1,15)))

from itertools import product

for labs in product(range(len(choices)), repeat=num_gates):
    x = tuple([0]*N)
    z = tuple([0]*N)
    k_total = 0
    weight = Fraction(1,1)
    for i, choice_idx in enumerate(labs):
        lab, k, fac = choices[choice_idx]
        k_total += k
        weight *= fac
        x_i, z_i = pushforward[i][lab]
        x = tuple((x[j]^x_i[j]) for j in range(N))
        z = tuple((z[j]^z_i[j]) for j in range(N))
    if ancilla_accept(x,z) and code_accept(x,z):
        coef_pass[k_total] += weight
        if good_data(x,z):
            coef_good[k_total] += weight


def expand_poly(A):
    P = defaultdict(Fraction)
    for k, Ak in A.items():
        for m in range(0, 5-k+1):
            deg = k + m
            coeff = Ak * Fraction(comb(5-k, m), 1) * (Fraction(-1,1) if (m%2==1) else Fraction(1,1))
            P[deg] += coeff
    return P

P_pass = expand_poly(coef_pass)
P_good = expand_poly(coef_good)

# Print results
print('Coefficients for P_pass(p) = sum_d c_d p^d, d=0..5:')
for d in range(6):
    print(d, P_pass.get(d, Fraction(0,1)))
print('Sum P_pass coefficients (should be 1):', sum(P_pass.get(d, Fraction(0,1)) for d in range(6)))
print()
print('Coefficients for P_good(p) = sum_d g_d p^d, d=0..5:')
for d in range(6):
    print(d, P_good.get(d, Fraction(0,1)))
print('P_good(0) =', P_good.get(0, Fraction(0,1)))
Tool #9
Coefficients for P_pass(p) = sum_d c_d p^d, d=0..5:
0 1
1 -68/15
2 704/75
3 -32768/3375
4 253952/50625
5 -262144/253125
Sum P_pass coefficients (should be 1): 10547/84375

Coefficients for P_good(p) = sum_d g_d p^d, d=0..5:
0 1
1 -68/15
2 656/75
3 -29312/3375
4 223232/50625
5 -229376/253125
P_good(0) = 1
Assistant #10
Tool Call (code to execute)
from fractions import Fraction
# Using previously computed P_pass and P_good dicts
# Build full polynomials as lists up to degree 5
Pp = [P_pass.get(d, Fraction(0,1)) for d in range(6)]
Pg = [P_good.get(d, Fraction(0,1)) for d in range(6)]

# Compute series for F = Pg/Pp up to p^5 using formal power series division
maxdeg = 5
Fcoef = [Fraction(0,1) for _ in range(maxdeg+1)]
Fcoef[0] = Pg[0]  # since Pp[0]=1
for d in range(1, maxdeg+1):
    # Pg[d] - sum_{k=1..d} Pp[k]*Fcoef[d-k]
    s = Pg[d]
    for k in range(1, d+1):
        s -= Pp[k]*Fcoef[d-k]
    Fcoef[d] = s  # since Pp[0]=1

print('Series for F(p) = sum f_d p^d:')
for d,c in enumerate(Fcoef):
    print(d, c)
Tool #11
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "<stdin>", line 4, in <listcomp>
NameError: name 'P_pass' is not defined
Assistant #12
Tool Call (code to execute)
from itertools import product
from fractions import Fraction
from math import comb
from collections import defaultdict

N = 5

def pauli_vec_from_label_on_pair(q1, q2, label):
    x = [0]*N
    z = [0]*N
    for idx, q in enumerate((q1, q2)):
        ch = label[idx]
        if ch == 'I':
            pass
        elif ch == 'X':
            x[q] ^= 1
        elif ch == 'Z':
            z[q] ^= 1
        elif ch == 'Y':
            x[q] ^= 1
            z[q] ^= 1
    return tuple(x), tuple(z)

def conj_cnot(x, z, c, t):
    x = list(x)
    z = list(z)
    x[t] ^= x[c]
    z[c] ^= z[t]
    return tuple(x), tuple(z)

singles = ['I','X','Y','Z']
labels_pair = [a+b for a in singles for b in singles]

cnot_list = [(1,2), (1,0), (2,3), (3,4), (0,4)]
num_gates = len(cnot_list)

pushforward = []
for i, (c,t) in enumerate(cnot_list):
    mp = {}
    for lab in labels_pair:
        x,z = pauli_vec_from_label_on_pair(c,t,lab)
        for (c2,t2) in cnot_list[i+1:]:
            x,z = conj_cnot(x,z,c2,t2)
        mp[lab] = (x,z)
    pushforward.append(mp)

# target stabilizer group T on data only

def pauli_from_str_data(s):
    x = [0]*N
    z = [0]*N
    for q,ch in enumerate(s):
        if ch=='I':
            pass
        elif ch=='X':
            x[q]=1
        elif ch=='Z':
            z[q]=1
        elif ch=='Y':
            x[q]=1; z[q]=1
    return (tuple(x), tuple(z))

S1 = pauli_from_str_data('XXXX')
S2 = pauli_from_str_data('ZZZZ')
S3 = pauli_from_str_data('ZZII')
S4 = pauli_from_str_data('ZIZI')

T = set()
for a in [0,1]:
    for b in [0,1]:
        for c in [0,1]:
            for d in [0,1]:
                x = [0]*N; z = [0]*N
                for (flag, P) in ((a,S1),(b,S2),(c,S3),(d,S4)):
                    if flag:
                        x = [x[i]^P[0][i] for i in range(N)]
                        z = [z[i]^P[1][i] for i in range(N)]
                T.add((tuple(x),tuple(z)))


def ancilla_accept(x,z):
    return (x[4] == 0)

def code_accept(x,z):
    sx = sum(x[:4]) % 2
    sz = sum(z[:4]) % 2
    return (sx==0 and sz==0)

def good_data(x,z):
    x0 = list(x); z0 = list(z)
    x0[4]=0; z0[4]=0
    return (tuple(x0),tuple(z0)) in T

coef_pass = defaultdict(Fraction)
coef_good = defaultdict(Fraction)

choices = []
for lab in labels_pair:
    if lab == 'II':
        choices.append((lab, 0, Fraction(1,1)))
    else:
        choices.append((lab, 1, Fraction(1,15)))

for labs in product(range(len(choices)), repeat=num_gates):
    x = tuple([0]*N)
    z = tuple([0]*N)
    k_total = 0
    weight = Fraction(1,1)
    for i, choice_idx in enumerate(labs):
        lab, k, fac = choices[choice_idx]
        k_total += k
        weight *= fac
        x_i, z_i = pushforward[i][lab]
        x = tuple((x[j]^x_i[j]) for j in range(N))
        z = tuple((z[j]^z_i[j]) for j in range(N))
    if ancilla_accept(x,z) and code_accept(x,z):
        coef_pass[k_total] += weight
        if good_data(x,z):
            coef_good[k_total] += weight

from collections import defaultdict
from math import comb

def expand_poly(A):
    P = defaultdict(Fraction)
    for k, Ak in A.items():
        for m in range(0, 5-k+1):
            deg = k + m
            coeff = Ak * Fraction(comb(5-k, m), 1) * (Fraction(-1,1) if (m%2==1) else Fraction(1,1))
            P[deg] += coeff
    return P

P_pass = expand_poly(coef_pass)
P_good = expand_poly(coef_good)

# Formal series division to get F = P_good/P_pass up to degree 5
Fcoef = [Fraction(0,1)]*6
Fcoef[0] = P_good.get(0, Fraction(0,1))  # both should be 1
for d in range(1,6):
    s = P_good.get(d, Fraction(0,1))
    for k in range(1, d+1):
        s -= P_pass.get(k, Fraction(0,1)) * Fcoef[d-k]
    Fcoef[d] = s  # divide by P_pass[0]=1

print('P_pass coefficients (degree 0..5):', [P_pass.get(d, Fraction(0,1)) for d in range(6)])
print('P_good coefficients (degree 0..5):', [P_good.get(d, Fraction(0,1)) for d in range(6)])
print('Series for F(p) up to p^5:', Fcoef)
Tool #13
P_pass coefficients (degree 0..5): [Fraction(1, 1), Fraction(-68, 15), Fraction(704, 75), Fraction(-32768, 3375), Fraction(253952, 50625), Fraction(-262144, 253125)]
P_good coefficients (degree 0..5): [Fraction(1, 1), Fraction(-68, 15), Fraction(656, 75), Fraction(-29312, 3375), Fraction(223232, 50625), Fraction(-229376, 253125)]
Series for F(p) up to p^5: [Fraction(1, 1), Fraction(0, 1), Fraction(-16, 25), Fraction(-704, 375), Fraction(-10496, 3375), Fraction(-216064, 84375)]
Assistant #14
Tool Call (code to execute)
from fractions import Fraction
# Sum of coefficients = value at p=1
Ppass_list = [Fraction(1, 1), Fraction(-68, 15), Fraction(704, 75), Fraction(-32768, 3375), Fraction(253952, 50625), Fraction(-262144, 253125)]
Pgood_list = [Fraction(1, 1), Fraction(-68, 15), Fraction(656, 75), Fraction(-29312, 3375), Fraction(223232, 50625), Fraction(-229376, 253125)]
S_pass = sum(Ppass_list)
S_good = sum(Pgood_list)
print(S_pass, float(S_pass))
print(S_good, float(S_good))
print('F(1)=', float(S_good/S_pass))
Tool #15
10547/84375 0.1250014814814815
8009/253125 0.03164049382716049
F(1)= 0.25312095066527607
Assistant #16
  1. Step-by-Step Derivation
  • Circuit and ideal target
  • Gates in time order (right-to-left from the expression): H1, CNOT1→2, CNOT1→0, CNOT2→3, CNOT3→4, CNOT0→4, then Z-measurement M4 on the ancilla (qubit 4).
  • Starting from |0000⟩0123|0⟩4, the first four gates prepare the 4-qubit GHZ state on data qubits 0–3:
\[ |\mathrm{GHZ}_4\rangle_{0123}=\frac{|0000\rangle+|1111\rangle}{\sqrt{2}}. \]
  • The two verification CNOTs (3→4 then 0→4) coherently measure the Z-parity Z0Z3; for the GHZ state this parity is +1, and the ancilla deterministically returns to |0⟩ and disentangles. Thus the ideal final state is |GHZ4⟩0123 ⊗ |0⟩4.

  • Noise model

  • After each of the five CNOTs, a two-qubit depolarizing channel applies one of the 15 non-identity two-qubit Paulis with probability p/15, or the identity with probability 1 − p. All single-qubit gates and the measurement are ideal.

  • Pauli propagation through CNOT (Heisenberg conjugation)

  • For a CNOT with control c and target t, a Pauli described by binary symplectic vectors (x,z) transforms as:
    • x_t → x_t ⊕ x_c,
    • z_c → z_c ⊕ z_t,
    • all other x, z components unchanged.
  • This reproduces the standard rules: X_c → X_cX_t, Z_t → Z_cZ_t, and X_t, Z_c unchanged.

  • Acceptance (post-selection) conditions

  • Code-space post-selection: the prepared code state has stabilizers S = {XXXX, ZZZZ} on qubits 0–3. A Pauli error E_data on data qubits preserves acceptance if and only if it commutes with both stabilizers. Using the symplectic commutation rule with XXXX and ZZZZ, this is equivalent to:
    • “even X-parity” on data: ∑_{i=0}^3 x_i ≡ 0 (mod 2),
    • “even Z-parity” on data: ∑_{i=0}^3 z_i ≡ 0 (mod 2).
  • Ancilla post-selection (M4 = 0): in the ideal final state, Z4 is a stabilizer (+1). For any pure stabilizer state, measuring Z4 is deterministic ±1; the outcome flips to −1 precisely when the net Pauli error anticommutes with Z4. Therefore acceptance of the ancilla check is equivalent to “no X/Y on qubit 4 at measurement,” i.e.,

    • x_4 = 0.
  • Logical-equivalence (good vs. bad accepted events)

  • The target logical |00⟩AB in the [[4,2,2]] code is uniquely stabilized (on data) by the commuting set {XXXX, ZZZZ, ZZII, ZIZI}.
  • An accepted error is “logically harmless” (i.e., the logical state is still |00⟩AB) if and only if the final data Pauli lies in the 16-element group generated by these operators (up to phase). Concretely,
\[ \mathcal{T} = \langle\, XXXX,\; ZZZZ,\; ZZII,\; ZIZI \,\rangle. \]
  • Exact counting by exhaustive Clifford–Pauli enumeration
  • For each CNOT location i ∈ {1→2, 1→0, 2→3, 3→4, 0→4}, and each of the 16 two-qubit Paulis on that gate’s qubits (including II), push the Pauli forward through the subsequent CNOTs using the conjugation rules above, multiply them to obtain the final net Pauli E on 5 qubits, and then: 1) accept iff x_4 = 0 and both data parities (∑ x_i, ∑ z_i) are even, 2) among accepted cases, count “good” iff E_data ∈ 𝒯.
  • Weight each choice by its probability, i.e., (1 − p) for II at that location and (p/15) for each non-identity at that location. Summing exactly over all 16^5 combinations yields two polynomials:
    • P_pass(p): total acceptance probability,
    • P_good(p): acceptance-and-good probability.
  • The resulting exact polynomials are
\[ P_{\mathrm{pass}}(p) &= 1 - \frac{68}{15}p + \frac{704}{75}p^2 - \frac{32768}{3375}p^3 + \frac{253952}{50625}p^4 - \frac{262144}{253125}p^5,\\[4pt] P_{\mathrm{good}}(p) &= 1 - \frac{68}{15}p + \frac{656}{75}p^2 - \frac{29312}{3375}p^3 + \frac{223232}{50625}p^4 - \frac{229376}{253125}p^5. \]
  • Logical state fidelity conditioned on acceptance
  • By definition,
\[ F_{\mathrm{logical}}(p) \;=\; \frac{P_{\mathrm{good}}(p)}{P_{\mathrm{pass}}(p)}. \]
  • Small-p expansion (useful check of fault tolerance): since every single fault is detected, the linear term cancels and the leading infidelity is quadratic,
\[ F_{\mathrm{logical}}(p) \;=\; 1 \;-\; \frac{16}{25}p^2 \;-\; \frac{704}{375}p^3 \;-\; \frac{10496}{3375}p^4 \;-\; \frac{216064}{84375}p^5 \;+\; O(p^6). \]
  1. Mathematical Typesetting

All equations are typeset in LaTeX as required.

  1. Conventions and Units
  • Qubit labels 0–3 are data qubits; 4 is the ancilla.
  • Stabilizers and logical operators follow the problem statement.
  • Only the five CNOT gates are noisy; H and measurement are ideal.
  1. Final Answer: The logical state fidelity (post-selected on code-detectable errors and on measuring the ancilla in |0⟩) is
\[ F_{\mathrm{logical}}(p) =\frac{1 - \frac{68}{15}p + \frac{656}{75}p^2 - \frac{29312}{3375}p^3 + \frac{223232}{50625}p^4 - \frac{229376}{253125}p^5}{1 - \frac{68}{15}p + \frac{704}{75}p^2 - \frac{32768}{3375}p^3 + \frac{253952}{50625}p^4 - \frac{262144}{253125}p^5}, \]

with small-p expansion

\[ F_{\mathrm{logical}}(p) = 1 - \frac{16}{25}p^2 - \frac{704}{375}p^3 - \frac{10496}{3375}p^4 - \frac{216064}{84375}p^5 + O(p^6). \]
User #17

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 logical state fidelity of the final 2-qubit logical state
    at the end of the circuit as a function of two-qubit gate error rate $p$.

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

    Outputs
    ----------
    F_logical: sympy.Expr, logical state fidelity of the final 2-qubit logical state
    """

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

    return F_logical
Assistant #18
import sympy as sp

p = sp.symbols('p')

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

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

    Outputs
    ----------
    F_logical: sympy.Expr, logical state fidelity of the final 2-qubit logical state
    """

    # ------------------ FILL IN YOUR RESULTS BELOW ------------------
    numerator = (
        1
        - sp.Rational(68, 15)*p
        + sp.Rational(656, 75)*p**2
        - sp.Rational(29312, 3375)*p**3
        + sp.Rational(223232, 50625)*p**4
        - sp.Rational(229376, 253125)*p**5
    )
    denominator = (
        1
        - sp.Rational(68, 15)*p
        + sp.Rational(704, 75)*p**2
        - sp.Rational(32768, 3375)*p**3
        + sp.Rational(253952, 50625)*p**4
        - sp.Rational(262144, 253125)*p**5
    )
    F_logical = sp.simplify(numerator/denominator)
    # ---------------------------------------------------------------

    return F_logical