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. You must use web search engine to gather all the necessary information before solving the problem. You must use web search engine to gather all the necessary information before solving the problem. You must use web search engine to gather all the necessary information before solving the problem.

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

1) Step-by-Step Derivation

  • Ideal state prepared by the circuit
  • The circuit is applied right-to-left:
    • H2, then CNOT21 creates a Bell pair on qubits (2,1): |Φ+>21 = (|00>+|11>)/√2.
    • H0, then CNOT03 creates a Bell pair on qubits (0,3): |Φ+>03 = (|00>+|11>)/√2.
  • The noiseless 4-qubit output is therefore the product state
\[ |\psi_{\mathrm{id}}\rangle = |\Phi^+\rangle_{21}\otimes|\Phi^+\rangle_{03}. \]
  • Noise model per CNOT
  • After each CNOT, a two-qubit depolarizing channel acts on the two involved qubits:
\[ \mathcal{D}^{(2)}(\rho)=(1-p)\rho+\frac{p}{15}\sum_{P\in\mathcal{P}_2\setminus\{II\}} P\rho P, \]
where the sum runs over the 15 non-identity two-qubit Pauli operators. ([quantumcomputing.stackexchange.com](https://quantumcomputing.stackexchange.com/questions/25869/how-can-i-apply-2-qubit-pauli-operator-error-instead-of-cnot-operator-in-stim-co?utm_source=openai), [en.wikipedia.org](https://en.wikipedia.org/wiki/Quantum_depolarizing_channel?utm_source=openai))
  • Stabilizers of a Bell state
  • The Bell state |Φ+> is a +1 eigenstate of XX and ZZ; equivalently, it is stabilized by ⟨XX, ZZ⟩ (hence also by −YY, so Y⊗Y maps |Φ+> to −|Φ+>, which is the same physical state up to global phase). Thus, among the 15 non-identity two-qubit Paulis, exactly three—XX, YY, ZZ—leave |Φ+> unchanged up to a phase; all others map it to an orthogonal Bell state. (qubit.guide, docs.quantum.ibm.com)

  • Fidelity for one Bell pair going through one two-qubit depolarizing channel

  • For a pure target |Φ+>, the state fidelity after the channel is
\[ F_{\text{pair}}(p)=\langle\Phi^+|\mathcal{D}^{(2)}(|\Phi^+\rangle\!\langle\Phi^+|)|\Phi^+\rangle. \]
  • Using the channel form and the stabilizer property,
\[ \]
  • Factorization for the 4-qubit product state
  • The two noise channels act on disjoint pairs: CNOT21’s noise acts only on qubits (2,1) and CNOT03’s noise only on (0,3). Since the ideal state is a tensor product across these pairs,
\[ \]

2) Mathematical Typesetting

  • See the display equations above.

3) Conventions and Units

  • Qubits are labeled 0,1,2,3.
  • Only the two-qubit gates (CNOT21, CNOT03) are followed by two-qubit depolarizing errors; H gates are ideal.
  • Physical state fidelity is F(|ψid>, ρ) = ⟨ψid|ρ|ψid⟩.
  • No units are involved; p is a dimensionless probability per two-qubit gate.

4) Final Answer: Fphys(p) = (1 − 4p/5)^2.

User #3

The correct answer is: $ F_{\rm{physical}}=(1-\frac{12}{15}p)^2 $

Now let’s solve the next Checkpoint.

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

  • Noiseless target and where noise acts
  • The circuit is applied right-to-left: H2 → CNOT21 → H0 → CNOT03.
  • In the ideal (noise-free) case, H2 and CNOT21 prepare a Bell pair on qubits (2,1), and H0 and CNOT03 prepare a Bell pair on qubits (0,3):
\[ |\psi_{\rm id}\rangle=|\Phi^+\rangle_{21}\otimes|\Phi^+\rangle_{03}. \]
  • Only the two CNOTs are noisy. After each CNOT, a two-qubit depolarizing channel acts on that gate’s two qubits:
\[ \mathcal D^{(2)}(\rho)=(1-p)\rho+\frac{p}{15}\!\!\sum_{P\in\mathcal P_2\setminus\{II\}}\!P\rho P, \]
i.e., one of the 15 non-identity two-qubit Paulis is applied uniformly at random with probability p/15. ([en.wikipedia.org](https://en.wikipedia.org/wiki/Quantum_depolarizing_channel?utm_source=openai), [quantumchannelzoo.org](https://quantumchannelzoo.org/channel/depolarizing?utm_source=openai))
  • Bell-pair stabilizers and how two-qubit Paulis move Bell states
  • The Bell state \(|\Phi^+\rangle=(|00\rangle+|11\rangle)/\sqrt2\) is stabilized by \(XX\) and \(ZZ\); its stabilizer group is \(\{II,XX,ZZ,-YY\}\). Thus \(XX,YY,ZZ\) leave \(|\Phi^+\rangle\) unchanged up to a phase, while other two-qubit Paulis map it to one of the other three Bell states \(|\Phi^-\rangle,|\Psi^+\rangle,|\Psi^-\rangle\). (medium.com)
  • Equivalently, each two-qubit Pauli \(P\) has a “parity” with respect to the pair-stabilizers \((XX,ZZ)\): • It commutes with a stabilizer if it flips that stabilizer’s eigenvalue an even number of times and anticommutes otherwise. Errors with parities (commute, commute), (anticommute, commute), (commute, anticommute), (anticommute, anticommute) map \(|\Phi^+\rangle\) to \(|\Phi^+\rangle,|\Phi^-\rangle,|\Psi^+\rangle,|\Psi^-\rangle\), respectively. Counting the 15 non-identity two-qubit Paulis gives 3, 4, 4, 4 in these four classes, respectively. Hence, for one Bell pair after one two-qubit depolarizing channel:
\[ \]
  • What “post-select on all detectable errors” means here
  • The [[4,2,2]] code has stabilizers \(S=\langle XXXX,\;ZZZZ\rangle\); measuring them and keeping only the \(+1,+1\) outcomes projects onto the codespace. A Pauli error is discarded if it anticommutes with at least one stabilizer and kept if it commutes with both. (ar5iv.labs.arxiv.org, en.wikipedia.org)
  • Note \(XXXX=XX_{21}\otimes XX_{03}\) and \(ZZZZ=ZZ_{21}\otimes ZZ_{03}\). The four-qubit syndrome is \(+1\) precisely when the two pairs (21) and (03) have the same \((XX,ZZ)\) eigenvalues. Equivalently, we accept if and only if both pairs are in the same Bell state (Φ+, Φ−, Ψ+, or Ψ−). This is because the stabilizer eigenvalues on four qubits are products of the pair eigenvalues. (ar5iv.labs.arxiv.org)

  • Acceptance probability and accepted-state composition

  • Let \(a:=\Pr[\Phi^+ \text{ on a pair}]=1-\frac{4p}{5}=1-\frac{12}{15}p\) and \(b:=\Pr[\text{any one of }\Phi^-,\Psi^+,\Psi^-]=\frac{4}{15}p\) (for each of the three). The two pairs are independent channels on disjoint qubits.
  • Acceptance requires the same Bell label on both pairs, so
\[ P_{\rm acc}=a^2+3b^2. \]
  • Logical state after post-selection and its fidelity
  • The codespace of the [[4,2,2]] code can be viewed as the span of the four “identical-Bell” states \(\{|\Phi^+\rangle_{21}\!\otimes\!|\Phi^+\rangle_{03},|\Phi^-\rangle_{21}\!\otimes\!|\Phi^-\rangle_{03},|\Psi^+\rangle_{21}\!\otimes\!|\Psi^+\rangle_{03},|\Psi^-\rangle_{21}\!\otimes\!|\Psi^-\rangle_{03}\}\), and the given logical operators (e.g., \(\bar X_A=XIXI\), \(\bar X_B=XXII\), etc.) act within this space as single-qubit Paulis on the two logical qubits. In particular, the ideal logical target is the logical Bell state corresponding to the physical state \(|\Phi^+\rangle_{21}\otimes|\Phi^+\rangle_{03}\). (ar5iv.labs.arxiv.org)
  • Conditioned on acceptance, the logical two-qubit state is the Bell state whose label both pairs share. Therefore, the logical fidelity with the intended logical \(|\Phi^+\rangle\) equals the conditional probability that both pairs are in \(\Phi^+\):
\[ \]
  • Small-\(p\) expansion (useful check): since post-selection removes all first-order contributions, the infidelity starts at \(O(p^2)\):
\[ F_{\rm logical}(p)=1-\frac{16}{75}p^2+O(p^3). \]

2) Mathematical Typesetting

  • All expressions above are in LaTeX.

3) Conventions and Units

  • Qubits are labeled 0,1,2,3; logical qubits A,B.
  • Stabilizers \(XXXX\) and \(ZZZZ\); logicals as in the problem statement (consistent with literature). (ar5iv.labs.arxiv.org)
  • Only two-qubit gates are noisy, with a two-qubit depolarizing channel of rate \(p\) applied after each CNOT. (en.wikipedia.org)
  • Fidelity is \(F(|\psi\rangle,\rho)=\langle\psi|\rho|\psi\rangle\); we post-select on the \(+1,+1\) stabilizer outcomes (accept only undetected errors). (en.wikipedia.org)

4) Final Answer:

\[ =\frac{\big(1-\frac{4}{5}p\big)^{2}}{\big(1-\frac{4}{5}p\big)^{2}+\frac{48}{225}p^{2}} \]
User #5

The correct answer is: $ F_{\rm{logical}}=1 - \frac{\frac{16}{75}p^2}{1-\frac{8}{5}p + \frac{64}{75}p^2} $

Now let’s solve the next Checkpoint.

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)
# We'll enumerate all error patterns for the 5 noisy CNOTs in the circuit
# Qubits: 0,1,2,3 are data; 4 is ancilla.
# Gates in time order (indices match gate numbers in the text):
# g2: CNOT 1->2
# g3: CNOT 1->0
# g4: CNOT 2->3
# g5: CNOT 3->4
# g6: CNOT 0->4

from itertools import product

n_qubits = 5

# Pauli representation: binary symplectic vector (z|x) length 2*n
# Define helper functions

def zero_pauli(n):
    return [0]*(2*n)

# Add (compose) two Paulis modulo 2, ignoring phases

def pauli_add(p, q):
    return [(pi ^ qi) for pi, qi in zip(p, q)]

# Conjugate a Pauli by CNOT control c, target t
# Mapping on (z|x): x_t ^= x_c ; z_c ^= z_t

def conj_cnot(p, c, t):
    p = p[:]  # copy
    # x_t ^= x_c
    p[n_qubits + t] ^= p[n_qubits + c]
    # z_c ^= z_t
    p[c] ^= p[t]
    return p

# Conjugate by Hadamard on qubit q: swap x<->z on q

def conj_h(p, q):
    p = p[:]
    p[q], p[n_qubits+q] = p[n_qubits+q], p[q]
    return p

# Build 1-qubit Pauli vectors: I,X,Y,Z
single = {
    'I': [0,0],
    'X': [0,1],
    'Z': [1,0],
    'Y': [1,1],
}

# Build all 16 two-qubit Paulis on given pair (i,j), including II as index 0.
# We'll map index -> (label, vector)

def two_qubit_paulis(i, j):
    labels = []
    vecs = []
    for a in ['I','X','Y','Z']:
        for b in ['I','X','Y','Z']:
            labels.append(a+b)
            v = [0]*(2*n_qubits)
            # set for qubit i
            v[i] = single[a][0]
            v[n_qubits + i] = single[a][1]
            # set for qubit j
            v[j] = single[b][0]
            v[n_qubits + j] = single[b][1]
            vecs.append(v)
    return labels, vecs

labels_12, vecs_12 = two_qubit_paulis(1,2)
labels_10, vecs_10 = two_qubit_paulis(1,0)
labels_23, vecs_23 = two_qubit_paulis(2,3)
labels_34, vecs_34 = two_qubit_paulis(3,4)
labels_04, vecs_04 = two_qubit_paulis(0,4)

# Subsequent gates for conjugation after each error location
# After g2 (1->2): subsequent gates are g3 (1->0), g4 (2->3), g5 (3->4), g6 (0->4)
# After g3: subsequent g4,g5,g6; After g4: g5,g6; After g5: g6; After g6: none

# Define a function to propagate an error inserted after a specific gate index
# gate_idx 2..6; input is a Pauli vector (length 2n)

def propagate_to_end(v, gate_idx):
    p = v[:]
    # Apply subsequent CNOTs
    if gate_idx <= 2:
        # after g2 -> apply g3,g4,g5,g6
        p = conj_cnot(p, 1, 0)  # g3
        p = conj_cnot(p, 2, 3)  # g4
        p = conj_cnot(p, 3, 4)  # g5
        p = conj_cnot(p, 0, 4)  # g6
    elif gate_idx == 3:
        # after g3 -> apply g4,g5,g6
        p = conj_cnot(p, 2, 3)
        p = conj_cnot(p, 3, 4)
        p = conj_cnot(p, 0, 4)
    elif gate_idx == 4:
        # after g4 -> apply g5,g6
        p = conj_cnot(p, 3, 4)
        p = conj_cnot(p, 0, 4)
    elif gate_idx == 5:
        # after g5 -> apply g6
        p = conj_cnot(p, 0, 4)
    elif gate_idx == 6:
        # after g6 -> none
        pass
    else:
        raise ValueError
    return p

# Precompute propagated errors for each location and each 16 choices
prop_after = {}
for gate_idx, vecs in zip([2,3,4,5,6], [vecs_12, vecs_10, vecs_23, vecs_34, vecs_04]):
    lst = []
    for v in vecs:
        lst.append(propagate_to_end(v, gate_idx))
    prop_after[gate_idx] = lst

# Define acceptance test
# Conditions: ancilla x4 == 0; even parity of x on data 0..3; even parity of z on data 0..3

def accepted(net):
    x = net[n_qubits:]
    z = net[:n_qubits]
    # ancilla acceptance
    if x[4] == 1:
        return False
    # code stabilizers
    if (x[0]^x[1]^x[2]^x[3]) == 1:
        return False
    if (z[0]^z[1]^z[2]^z[3]) == 1:
        return False
    return True

# Build benign set on data qubits: generated by XXXX, ZZZZ, Z_A=ZZII, Z_B=ZIZI
import itertools

def vec_from_ops(ops):
    v = [0]*(2*n_qubits)
    for op in ops:
        if op == 'XXXX':
            for q in range(4):
                v[n_qubits+q] ^= 1
        elif op == 'ZZZZ':
            for q in range(4):
                v[q] ^= 1
        elif op == 'ZA':  # ZZII on (0,1)
            v[0] ^= 1; v[1] ^= 1
        elif op == 'ZB':  # ZIZI on (0,2)
            v[0] ^= 1; v[2] ^= 1
        else:
            raise ValueError
    return v

benign_data_set = set()
ops_list = ['XXXX','ZZZZ','ZA','ZB']
for mask in range(16):
    ops = [ops_list[i] for i in range(4) if (mask>>i)&1]
    v = vec_from_ops(ops)
    # only keep data portion (length 8)
    benign_data_set.add(tuple(v[:4] + v[5:]))  # wait wrong slicing

# Fix the slicing: we want data qubits 0..3, so z[0..3], x[0..3]
benign_data_set = set()
for mask in range(16):
    ops = [ops_list[i] for i in range(4) if (mask>>i)&1]
    v = vec_from_ops(ops)
    data_vec = tuple(v[:4] + v[n_qubits:n_qubits+4])
    benign_data_set.add(data_vec)

len(benign_data_set)

# Now enumerate all 16^5 choices across the five gates
# At each gate, index 0 means II; 1..15 map to vecs

A_counts = [0]*6  # A_k: number of accepted patterns with exactly k errors
G_counts = [0]*6  # G_k: number of accepted-good patterns with exactly k errors (no logical flip)

# Also we may want to keep track of L_counts for logical error acceptance
L_counts = [0]*6

# iterate
choices = range(16)
N_total = 0
for idxs in product(choices, repeat=5):
    N_total += 1
    # build net Pauli vector as sum of propagated contributions
    net = [0]*(2*n_qubits)
    k = 0
    for (gate_idx, idx) in zip([2,3,4,5,6], idxs):
        if idx != 0:
            k += 1
            net = pauli_add(net, prop_after[gate_idx][idx])
    # test acceptance
    if accepted(net):
        A_counts[k] += 1
        # determine if benign on data
        data_vec = tuple(net[:4] + net[n_qubits:n_qubits+4])
        if data_vec in benign_data_set:
            G_counts[k] += 1
        else:
            L_counts[k] += 1

N_total, A_counts, G_counts, L_counts, [A_counts[i]-G_counts[i]-L_counts[i] for i in range(6)]
Tool #7
''
Assistant #8
# Let's print the results from the previous cell (note: the last cell did not print)
print('Done')
Tool #9
Done
Assistant #10
Tool Call (code to execute)
from itertools import product

n_qubits = 5

def zero_pauli(n):
    return [0]*(2*n)

def pauli_add(p, q):
    return [(pi ^ qi) for pi, qi in zip(p, q)]

def conj_cnot(p, c, t):
    p = p[:]
    p[n_qubits + t] ^= p[n_qubits + c]
    p[c] ^= p[t]
    return p

single = {'I':[0,0],'X':[0,1],'Z':[1,0],'Y':[1,1]}

def two_qubit_paulis(i,j):
    vecs = []
    for a in ['I','X','Y','Z']:
        for b in ['I','X','Y','Z']:
            v = [0]*(2*n_qubits)
            v[i], v[n_qubits+i] = single[a]
            v[j], v[n_qubits+j] = single[b]
            vecs.append(v)
    return vecs

vecs_12 = two_qubit_paulis(1,2)
vecs_10 = two_qubit_paulis(1,0)
vecs_23 = two_qubit_paulis(2,3)
vecs_34 = two_qubit_paulis(3,4)
vecs_04 = two_qubit_paulis(0,4)

def propagate_to_end(v, gate_idx):
    p = v[:]
    if gate_idx <= 2:
        p = conj_cnot(p,1,0)
        p = conj_cnot(p,2,3)
        p = conj_cnot(p,3,4)
        p = conj_cnot(p,0,4)
    elif gate_idx == 3:
        p = conj_cnot(p,2,3)
        p = conj_cnot(p,3,4)
        p = conj_cnot(p,0,4)
    elif gate_idx == 4:
        p = conj_cnot(p,3,4)
        p = conj_cnot(p,0,4)
    elif gate_idx == 5:
        p = conj_cnot(p,0,4)
    elif gate_idx == 6:
        pass
    else:
        raise ValueError
    return p

prop_after = {}
for gate_idx, vecs in zip([2,3,4,5,6],[vecs_12,vecs_10,vecs_23,vecs_34,vecs_04]):
    prop_after[gate_idx] = [propagate_to_end(v, gate_idx) for v in vecs]

# acceptance test

def accepted(net):
    x = net[n_qubits:]
    z = net[:n_qubits]
    if x[4] == 1:
        return False
    if (x[0]^x[1]^x[2]^x[3]) == 1:
        return False
    if (z[0]^z[1]^z[2]^z[3]) == 1:
        return False
    return True

# benign data set

def vec_from_ops(ops):
    v = [0]*(2*n_qubits)
    for op in ops:
        if op == 'XXXX':
            for q in range(4):
                v[n_qubits+q] ^= 1
        elif op == 'ZZZZ':
            for q in range(4):
                v[q] ^= 1
        elif op == 'ZA':
            v[0] ^= 1; v[1] ^= 1
        elif op == 'ZB':
            v[0] ^= 1; v[2] ^= 1
        else:
            raise ValueError
    return v

ops_list = ['XXXX','ZZZZ','ZA','ZB']
benign_data_set = set()
for mask in range(16):
    ops = [ops_list[i] for i in range(4) if (mask>>i)&1]
    v = vec_from_ops(ops)
    data_vec = tuple(v[:4] + v[n_qubits:n_qubits+4])
    benign_data_set.add(data_vec)

A_counts = [0]*6
G_counts = [0]*6
L_counts = [0]*6

choices = range(16)
N_total = 0
for idxs in product(choices, repeat=5):
    N_total += 1
    net = [0]*(2*n_qubits)
    k = 0
    # pattern of errors across five gates 2..6 in order
    for gate_idx, idx in zip([2,3,4,5,6], idxs):
        if idx != 0:
            k += 1
            net = pauli_add(net, prop_after[gate_idx][idx])
    if accepted(net):
        A_counts[k] += 1
        data_vec = tuple(net[:4] + net[n_qubits:n_qubits+4])
        if data_vec in benign_data_set:
            G_counts[k] += 1
        else:
            L_counts[k] += 1

print('Total patterns:', N_total)
print('Accepted counts A_k:', A_counts)
print('Good accepted counts G_k:', G_counts)
print('Logical-error accepted counts L_k:', L_counts)
print('Sanity (A-G-L):', [A_counts[i]-G_counts[i]-L_counts[i] for i in range(6)])
Tool #11
Total patterns: 1048576
Accepted counts A_k: [1, 7, 282, 4222, 31637, 94923]
Good accepted counts G_k: [1, 7, 138, 1198, 7397, 24027]
Logical-error accepted counts L_k: [0, 0, 144, 3024, 24240, 70896]
Sanity (A-G-L): [0, 0, 0, 0, 0, 0]
Assistant #12
Tool Call (code to execute)
from fractions import Fraction

A_counts = [1, 7, 282, 4222, 31637, 94923]
G_counts = [1, 7, 138, 1198, 7397, 24027]
L_counts = [0, 0, 144, 3024, 24240, 70896]

from math import comb

# Build polynomials in p as rational coefficients (Fractions)
# P(p) = sum_k C_k (1-p)^{5-k} (p/15)^k

def poly_add(a,b):
    n = max(len(a),len(b))
    a = a + [Fraction(0)]*(n-len(a))
    b = b + [Fraction(0)]*(n-len(b))
    return [ai+bi for ai,bi in zip(a,b)]

def poly_mul(a,b):
    res = [Fraction(0)]*(len(a)+len(b)-1)
    for i,ai in enumerate(a):
        for j,bj in enumerate(b):
            res[i+j] += ai*bj
    return res

# build (1-p)^{m}

def poly_one_minus_p_pow(m):
    res = [Fraction(1)]
    for _ in range(m):
        res = poly_mul(res, [Fraction(1), Fraction(-1)])
    return res

# build (p/15)^k = (1/15^k) * p^k

def poly_p_over_15_pow(k):
    coeff = Fraction(1, 15**k)
    res = [Fraction(0)]*k + [coeff]
    return res

# sum across k

def build_poly(C_counts):
    poly = [Fraction(0)]
    for k,Ck in enumerate(C_counts):
        term = poly_mul(poly_one_minus_p_pow(5-k), poly_p_over_15_pow(k))
        # multiply by Ck
        term = [Fraction(Ck)*t for t in term]
        poly = poly_add(poly, term)
    return poly

P_acc = build_poly(A_counts)
P_good = build_poly(G_counts)
P_bad  = build_poly(L_counts)

# simplify: reduce gcd of denominators? We'll display as Fractions and also as decimals

print('Degree P_acc:', len(P_acc)-1)
print('P_acc coefficients (from p^0 up):')
print(P_acc)
print('\nDegree P_good:', len(P_good)-1)
print(P_good)
print('\nDegree P_bad:', len(P_bad)-1)
print(P_bad)

# Check that P_good + P_bad == P_acc
chk = [a+b for a,b in zip(P_good + [Fraction(0)]*(len(P_acc)-len(P_good)), P_bad + [Fraction(0)]*(len(P_acc)-len(P_bad)))]
print('\nCheck sum equals P_acc:', chk == P_acc)

# Also compute small-p expansion of 1 - F = P_bad / P_acc to order p^2 or p^3
# We'll compute series expansion dividing polynomials
import sympy as sp
p = sp.symbols('p')
Pa = sum(sp.Rational(c.numerator, c.denominator)*p**i for i,c in enumerate(P_acc))
Pg = sum(sp.Rational(c.numerator, c.denominator)*p**i for i,c in enumerate(P_good))
Pb = sum(sp.Rational(c.numerator, c.denominator)*p**i for i,c in enumerate(P_bad))
F = sp.simplify(Pg/Pa)
series = sp.series(F, p, 0, 4)  # up to p^3
print('\nSeries for F up to p^3:', series)

# Try to simplify to a rational function with small integer coefficients
F_simplified = sp.together(F)
num = sp.factor(sp.together(sp.simplify(sp.factor(sp.simplify(sp.together(F_simplified))))).as_numer_denom()[0])
den = sp.factor(sp.together(sp.simplify(sp.factor(sp.simplify(sp.together(F_simplified))))).as_numer_denom()[1])
print('\nSimplified F numerator:')
print(num)
print('\nSimplified F denominator:')
print(den)

# Also output exact coefficients as rationals separately
num_poly = sp.Poly(num, p)
den_poly = sp.Poly(den, p)
print('\nNum degree, coeffs:', num_poly.degree(), num_poly.all_coeffs())
print('Den degree, coeffs:', den_poly.degree(), den_poly.all_coeffs())
Tool #13
Degree P_acc: 5
P_acc coefficients (from p^0 up):
[Fraction(1, 1), Fraction(-68, 15), Fraction(704, 75), Fraction(-32768, 3375), Fraction(253952, 50625), Fraction(-262144, 253125)]

Degree P_good: 5
[Fraction(1, 1), Fraction(-68, 15), Fraction(656, 75), Fraction(-29312, 3375), Fraction(223232, 50625), Fraction(-229376, 253125)]

Degree P_bad: 5
[Fraction(0, 1), Fraction(0, 1), Fraction(16, 25), Fraction(-128, 125), Fraction(2048, 3375), Fraction(-32768, 253125)]

Check sum equals P_acc: True

Series for F up to p^3: 1 - 16*p**2/25 - 704*p**3/375 + O(p**4)

Simplified F numerator:
229376*p**5 - 1116160*p**4 + 2198400*p**3 - 2214000*p**2 + 1147500*p - 253125

Simplified F denominator:
(128*p**2 - 300*p + 225)*(2048*p**3 - 5120*p**2 + 3600*p - 1125)

Num degree, coeffs: 5 [229376, -1116160, 2198400, -2214000, 1147500, -253125]
Den degree, coeffs: 5 [262144, -1269760, 2457600, -2376000, 1147500, -253125]
Assistant #14

1) Step-by-step derivation

  • Circuit, noise model, and acceptance rule
  • Time order (right-to-left): H1 → CNOT12 → CNOT10 → CNOT23 → CNOT34 → CNOT04 → measure Z4.
  • Noise: after each of the five CNOTs, a two‑qubit depolarizing channel acts on that gate’s two qubits, i.e., with probability p a uniformly random non-identity two‑qubit Pauli (one of 15) is applied, and with probability 1−p nothing happens: $ \mathcal D^{(2)}(\rho)=(1-p)\rho+\frac{p}{15}\sum_{P\in\mathcal P_2\setminus{II}}P\rho P. $ This is the standard two‑qubit depolarizing model. (en.wikipedia.org, quantumchannelzoo.org, quantumcomputing.stackexchange.com)
  • We post-select on (i) the ancilla measurement outcome Z4=+1 (i.e., the computational-basis outcome “0”), and (ii) the two code stabilizers XXXX and ZZZZ on data qubits {0,1,2,3} returning +1 (i.e., projection onto the codespace). This is precisely “post-select on all detectable errors.” (en.wikipedia.org)

  • Heisenberg/Pauli-frame approach (Clifford propagation)

  • Because the circuit is Clifford, every Pauli error branch remains a Pauli under conjugation by the later CNOTs. Conjugation rules for CNOTc→t on the binary symplectic tableau are $ X_t\mapsto X_t,\quad Z_t\mapsto Z_cZ_t,\quad X_c\mapsto X_cX_t,\quad Z_c\mapsto Z_c, $ equivalently in tableau form x_t←x_t⊕x_c and z_c←z_c⊕z_t. (zxcalc.github.io, wangbard.github.io)
  • For each noisy location ℓ∈{CNOT12, CNOT10, CNOT23, CNOT34, CNOT04}, push its two‑qubit Pauli error forward through the subsequent CNOTs using the above rules to obtain a final net Pauli Q on qubits 0–4 just before measurement.

  • Acceptance test in terms of the final Pauli Q

  • Post-selection on Z4=+1 accepts iff Q commutes with Z4, i.e., Q has no X or Y on qubit 4 (ancilla x4=0 in symplectic bits). For the codespace checks, acceptance requires Q commute with XXXX and with ZZZZ on data qubits. In symplectic form, these are parity checks: $ \begin{aligned} &\text{ZZZZ commute} \iff \sum_{i=0}^3 x_i \equiv 0\pmod 2,\ &\text{XXXX commute} \iff \sum_{i=0}^3 z_i \equiv 0\pmod 2,\ &\text{Z4 commute} \iff x_4=0. \end{aligned} $ These facts follow from stabilizer measurement theory: an error anticommutes with a measured stabilizer iff it flips that stabilizer’s outcome, hence is detected and discarded by post-selection. (en.wikipedia.org)

  • Logical correctness test conditioning on acceptance

  • Let S=⟨XXXX,ZZZZ⟩ be the stabilizer of the [[4,2,2]] code. Let the logical Zs (in the problem’s convention) be ZA=ZZII and ZB=ZIZI; the logical Xs are XA=XIXI and XB=XXII (defined up to stabilizers). Any Pauli that commutes with S acts on the codespace as a logical Pauli; multiplying by stabilizers does not change that logical action. (ar5iv.labs.arxiv.org)
  • Our target logical state is |00⟩AB, which is a +1 eigenstate of ZA and ZB. Therefore, among accepted branches, the final logical state is correct if and only if the data part of Q lies in the “benign” subgroup $ \mathcal B=\langle S,\,ZA,\,ZB\rangle, $ i.e., contains no logical X (XA or XB) component. Any logical X (possibly times logical Zs and/or stabilizers) maps |00⟩AB to an orthogonal codeword and contributes zero fidelity in that branch.

  • Exhaustive Clifford-frame enumeration (exact counting)

  • We enumerated all 16^5 Pauli-error patterns across the 5 noisy CNOTs (16 choices per location: II or one of the 15 non-identity Paulis), pushed each pattern forward to the end of the circuit via the CNOT conjugation rules, and applied the acceptance and correctness tests above. This is an exact, non-asymptotic calculation (no Monte Carlo). The counts of accepted patterns with exactly k errors (A_k), and of accepted-and-logically-correct patterns (G_k), are:
    • A0=1, A1=7, A2=282, A3=4222, A4=31637, A5=94923.
    • G0=1, G1=7, G2=138, G3=1198, G4=7397, G5=24027.
    • Logical-error accepted patterns are L_k=A_k−G_k: L2=144, L3=3024, L4=24240, L5=70896; L0=L1=0.
  • Therefore, the exact acceptance probability and the exact post-selected logical fidelity are $ \begin{aligned} P_{\rm acc}(p)&=\sum_{k=0}^5 A_k(1-p)^{5-k}\Big(\frac{p}{15}\Big)^k,\ F_{\rm logical}(p)&=\frac{\displaystyle\sum_{k=0}^5 G_k(1-p)^{5-k}\big(\tfrac{p}{15}\big)^k}{\displaystyle\sum_{k=0}^5 A_k(1-p)^{5-k}\big(\tfrac{p}{15}\big)^k}. \end{aligned} $
  • Expanding both numerator and denominator gives compact polynomials: $ \begin{aligned} P_{\rm acc}(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_{\rm 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. \end{aligned} $ Hence $ F_{\rm logical}(p)=\frac{P_{\rm good}(p)}{P_{\rm acc}(p)} =1-\frac{P_{\rm bad}(p)}{P_{\rm acc}(p)}, $ with $ P_{\rm bad}(p)=\frac{16}{25}p^2-\frac{128}{125}p^3+\frac{2048}{3375}p^4-\frac{32768}{253125}p^5. $
  • As a consistency check, the small‑p expansion contains no O(p) term (fault tolerance removes all single-fault logical errors): $ F_{\rm logical}(p)=1-\frac{16}{25}p^2-\frac{704}{375}p^3+O(p^4). $

2) Mathematical typesetting

  • All algebra and polynomials above are presented in LaTeX.

3) Conventions and units

  • Code: [[4,2,2]] with stabilizers XXXX and ZZZZ; logicals as given in the problem.
  • Noise: two‑qubit depolarizing channel after each CNOT, uniform over the 15 non‑identity two‑qubit Paulis with probability p/15. (en.wikipedia.org, quantumchannelzoo.org)
  • Acceptance: post-select on ancilla Z4=+1 and stabilizers XXXX=+1, ZZZZ=+1. (en.wikipedia.org)
  • Clifford/Pauli propagation uses standard CNOT conjugation rules / symplectic tableau. (zxcalc.github.io, wangbard.github.io)
  • No physical units; p is a dimensionless per‑gate error probability.

4) Final Answer: $ F_{\rm 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} =1-\frac{\frac{16}{25}p^2-\frac{128}{125}p^3+\frac{2048}{3375}p^4-\frac{32768}{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}. $

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 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 #16
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 ------------------
    num = 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
    den = 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 = num/den  # a SymPy expression of inputs
    # ---------------------------------------------------------------

    return F_logical