Skip to content

Add basic error correction codes in qutip-qip algorithms #277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/qutip_qip/algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
from .qft import *
from .qpe import *
from .error_correction.bit_flip import *
from .error_correction.phase_flip import *
from .error_correction.shor_code import *
112 changes: 112 additions & 0 deletions src/qutip_qip/algorithms/error_correction/bit_flip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# bit_flip_code.py

import numpy as np
from qutip import Qobj, tensor, basis, sigmax, sigmay
from qutip_qip.operations import Gate
from qutip_qip.circuit import QubitCircuit

__all__ = ["BitFlipCode"]


class BitFlipCode:
"""
Implementation of the 3-qubit bit-flip code.

The bit-flip code protects against X (bit-flip) errors by encoding
a single logical qubit across three physical qubits:
|0⟩ → |000⟩
|1⟩ → |111⟩
"""

@staticmethod
def encode_circuit():
"""
Create a circuit for encoding a single qubit into the 3-qubit bit-flip code.

Returns
-------
qc : instance of QubitCircuit
Encoding circuit for the bit-flip code.
"""
qc = QubitCircuit(3)
qc.add_gate("CNOT", controls=0, targets=1)
qc.add_gate("CNOT", controls=0, targets=2)
return qc

@staticmethod
def syndrome_measurement_circuit():
"""
Create a circuit for syndrome measurement of the 3-qubit bit-flip code.

Returns
-------
qc : instance of QubitCircuit
Syndrome measurement circuit that uses two ancilla qubits.
"""
qc = QubitCircuit(5) # 3 data qubits + 2 syndrome qubits

# First syndrome measurement: Parity of qubits 0 and 1
qc.add_gate("CNOT", controls=0, targets=3)
qc.add_gate("CNOT", controls=1, targets=3)

# Second syndrome measurement: Parity of qubits 1 and 2
qc.add_gate("CNOT", controls=1, targets=4)
qc.add_gate("CNOT", controls=2, targets=4)

return qc

@staticmethod
def correction_circuit(syndrome):
"""
Create a circuit for error correction based on syndrome measurement.

Parameters
----------
syndrome : tuple
Two-bit syndrome measurement result (s1, s2).

Returns
-------
qc : instance of QubitCircuit
Correction circuit applying X gates as needed.
"""
qc = QubitCircuit(3)
s1, s2 = syndrome

# Syndrome interpretation:
# s1=0, s2=0: No error
# s1=1, s2=0: Error on qubit 0
# s1=1, s2=1: Error on qubit 1
# s1=0, s2=1: Error on qubit 2

if s1 == 1 and s2 == 0:
# Error on qubit 0
qc.add_gate("X", targets=0)
elif s1 == 1 and s2 == 1:
# Error on qubit 1
qc.add_gate("X", targets=1)
elif s1 == 0 and s2 == 1:
# Error on qubit 2
qc.add_gate("X", targets=2)

return qc

@staticmethod
def decode_circuit():
"""
Create a circuit for decoding the 3-qubit bit-flip code.

Returns
-------
qc : instance of QubitCircuit
Decoding circuit for the bit-flip code.
"""
qc = QubitCircuit(3)
qc.add_gate("CNOT", controls=0, targets=2)
qc.add_gate("CNOT", controls=0, targets=1)

# Add a Toffoli gate to verify the parity
# If all qubits have the same value, the result is stored in qubit 0
qc.add_gate("TOFFOLI", controls=[1, 2], targets=0)

return qc
131 changes: 131 additions & 0 deletions src/qutip_qip/algorithms/error_correction/phase_flip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import numpy as np
from qutip import Qobj, tensor, basis, sigmax, sigmay, sigmaz
from qutip_qip.operations import Gate
from qutip_qip.circuit import QubitCircuit

__all__ = ["PhaseFlipCode"]


class PhaseFlipCode:
"""
Implementation of the 3-qubit phase-flip code.
The phase-flip code protects against Z (phase-flip) errors by encoding
a single logical qubit across three physical qubits:
|0⟩ → |+++⟩
|1⟩ → |---⟩

This is accomplished by applying Hadamard gates to transform the bit-flip code
into the phase-flip code, as phase errors in the Hadamard basis appear as bit-flips.
"""

@staticmethod
def encode_circuit():
"""
Create a circuit for encoding a single qubit into the 3-qubit phase-flip code.

Returns
-------
qc : instance of QubitCircuit
Encoding circuit for the phase-flip code.
"""
qc = QubitCircuit(3)

# First apply Hadamard to the input qubit
qc.add_gate("SNOT", targets=0)

# Then use the bit-flip encoding structure
qc.add_gate("CNOT", controls=0, targets=1)
qc.add_gate("CNOT", controls=0, targets=2)

# Apply Hadamard gates to all qubits
qc.add_gate("SNOT", targets=0)
qc.add_gate("SNOT", targets=1)
qc.add_gate("SNOT", targets=2)

return qc

@staticmethod
def syndrome_measurement_circuit():
"""
Create a circuit for syndrome measurement of the 3-qubit phase-flip code.

Returns
-------
qc : instance of QubitCircuit
Syndrome measurement circuit that uses two ancilla qubits.
"""
qc = QubitCircuit(5) # 3 data qubits + 2 syndrome qubits

qc.add_gate("SNOT", targets=0)
qc.add_gate("SNOT", targets=1)
qc.add_gate("SNOT", targets=2)

qc.add_gate("CNOT", controls=0, targets=3)
qc.add_gate("CNOT", controls=1, targets=3)

qc.add_gate("CNOT", controls=1, targets=4)
qc.add_gate("CNOT", controls=2, targets=4)

qc.add_gate("SNOT", targets=0)
qc.add_gate("SNOT", targets=1)
qc.add_gate("SNOT", targets=2)

return qc

@staticmethod
def correction_circuit(syndrome):
"""
Create a circuit for error correction based on syndrome measurement.

Parameters
----------
syndrome : tuple
Two-bit syndrome measurement result (s1, s2).

Returns
-------
qc : instance of QubitCircuit
Correction circuit applying Z gates as needed.
"""
qc = QubitCircuit(3)
s1, s2 = syndrome

# Syndrome interpretation:
# s1=0, s2=0: No error
# s1=1, s2=0: Error on qubit 0
# s1=1, s2=1: Error on qubit 1
# s1=0, s2=1: Error on qubit 2

if s1 == 1 and s2 == 0:
qc.add_gate("Z", targets=0)
elif s1 == 1 and s2 == 1:
qc.add_gate("Z", targets=1)
elif s1 == 0 and s2 == 1:
qc.add_gate("Z", targets=2)

return qc

@staticmethod
def decode_circuit():
"""
Create a circuit for decoding the 3-qubit phase-flip code.

Returns
-------
qc : instance of QubitCircuit
Decoding circuit for the phase-flip code.
"""
qc = QubitCircuit(3)

qc.add_gate("SNOT", targets=0)
qc.add_gate("SNOT", targets=1)
qc.add_gate("SNOT", targets=2)

qc.add_gate("CNOT", controls=0, targets=2)
qc.add_gate("CNOT", controls=0, targets=1)

qc.add_gate("TOFFOLI", controls=[1, 2], targets=0)

qc.add_gate("SNOT", targets=0)

return qc
66 changes: 66 additions & 0 deletions src/qutip_qip/algorithms/error_correction/shor_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import numpy as np
from qutip import Qobj, tensor, basis, sigmax, sigmay, sigmaz
from qutip_qip.operations import Gate
from qutip_qip.circuit import QubitCircuit

__all__ = ["ShorCode"]


class ShorCode:
"""
Implementation of the 9-qubit Shor code.

The Shor code protects against arbitrary single-qubit errors by combining
the 3-qubit phase-flip code with the 3-qubit bit-flip code.

The logical states are encoded as:
|0⟩ → (|000⟩ + |111⟩)(|000⟩ + |111⟩)(|000⟩ + |111⟩) / 2√2
|1⟩ → (|000⟩ - |111⟩)(|000⟩ - |111⟩)(|000⟩ - |111⟩) / 2√2

This encoding allows correction of any single-qubit error (bit-flip, phase-flip,
or both) on any of the 9 physical qubits.
"""

@staticmethod
def encode_circuit():
"""
Create a circuit for encoding a single qubit into the 9-qubit Shor code.

The encoding process:
1. Apply phase-flip encoding to the input (creating |+++⟩ or |---⟩)
2. Apply bit-flip encoding to each of the three qubits

Returns
-------
qc : instance of QubitCircuit
Encoding circuit for the Shor code.
"""
qc = QubitCircuit(9)

# Step 1: Phase-flip encoding on the first qubit
# Apply Hadamard to the input qubit
qc.add_gate("SNOT", targets=0)

# Create the GHZ-like state by using CNOTs
qc.add_gate("CNOT", controls=0, targets=3)
qc.add_gate("CNOT", controls=0, targets=6)

# Apply Hadamard to all three qubits
qc.add_gate("SNOT", targets=0)
qc.add_gate("SNOT", targets=3)
qc.add_gate("SNOT", targets=6)

# Step 2: Bit-flip encoding for each of the three blocks
# First block: qubits 0,1,2
qc.add_gate("CNOT", controls=0, targets=1)
qc.add_gate("CNOT", controls=0, targets=2)

# Second block: qubits 3,4,5
qc.add_gate("CNOT", controls=3, targets=4)
qc.add_gate("CNOT", controls=3, targets=5)

# Third block: qubits 6,7,8
qc.add_gate("CNOT", controls=6, targets=7)
qc.add_gate("CNOT", controls=6, targets=8)

return qc
Loading
Loading