Skip to content

Commit

Permalink
A example of Qec using Shor's Code (#2922)
Browse files Browse the repository at this point in the history
This is an example of using Shor's code to do quantum error correction and fault tolerant operations.

There is a base class for one qubit code, which encodes one physical qubit with several ancilla qubits and some gates. The Shor's Code class will be derived from the base one qubit class. Then it's easy for us to add other codes in the future. 
There are multi-qubit codes that take in multiple physical qubits and call one qubit class for each of the input qubits. The class also takes in the original circuit of the original physical qubits and transforms it into fault-tolerate operations on the encoded circuits. 

The files are under examples/qec
  | __init__.py |  
  | onequbit_qec.py |  
  | multiqubit_qec.py |  
  | shors_code.py |  
  | fault_tolerate_operations.py |  
 
The tests are added to the end of existing examples_test.py
  • Loading branch information
crystalzhaizhai authored Aug 19, 2020
1 parent 656e388 commit 3e00896
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ qubit to another.
* [Super dense coding](https://github.com/quantumlib/Cirq/blob/master/examples/superdense_coding.py)
Transmit 2 classical bits using one quantum bit.

## Introductory Error Correction

* [Shor's Code](https://github.com/quantumlib/Cirq/blob/master/examples/shors_code.py)
Quantum error correction with Shor's Code

## Intermediate Textbook Algorithms

Expand Down
22 changes: 22 additions & 0 deletions examples/examples_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import examples.simon_algorithm
import examples.superdense_coding
import examples.swap_networks
from examples.shors_code import OneQubitShorsCode


def test_example_runs_bernstein_vazirani():
Expand Down Expand Up @@ -271,3 +272,24 @@ def test_example_runs_shor_valid(n):
def test_example_runs_shor_invalid(n):
with pytest.raises(ValueError):
examples.shor.main(n=n)


def test_example_qec_single_qubit():
mycode1 = OneQubitShorsCode()
my_circuit1 = cirq.Circuit(mycode1.encode())
my_circuit1 += cirq.Circuit(mycode1.correct())
my_circuit1 += cirq.measure(mycode1.physical_qubits[0])
sim1 = cirq.DensityMatrixSimulator()
result1 = sim1.run(my_circuit1, repetitions=1)
assert result1.measurements['0'] == [[0]]

mycode2 = OneQubitShorsCode()
my_circuit2 = cirq.Circuit(mycode2.apply_gate(cirq.X, 0))
with pytest.raises(IndexError):
mycode2.apply_gate(cirq.Z, 89)
my_circuit2 += cirq.Circuit(mycode2.encode())
my_circuit2 += cirq.Circuit(mycode2.correct())
my_circuit2 += cirq.measure(mycode2.physical_qubits[0])
sim2 = cirq.DensityMatrixSimulator()
result2 = sim2.run(my_circuit2, repetitions=1)
assert result2.measurements['0'] == [[1]]
118 changes: 118 additions & 0 deletions examples/shors_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
""" Shor's code is a stabilizer code for quantum error correction.
It uses 9 qubits to encode 1 logic qubit and is able to correct
at most one bit flip and one sign flip or their combination.
(0, 0): ───@───@───H───@───@───@───@───X───H───@───@───X───M───
│ │ │ │ │ │ │ │ │ │
(0, 1): ───┼───┼───────X───┼───X───┼───@───────┼───┼───┼───M───
│ │ │ │ │ │ │ │
(0, 2): ───┼───┼───────────X───────X───@───────┼───┼───┼───M───
│ │ │ │ │
(0, 3): ───X───┼───H───@───@───@───@───X───H───X───┼───@───M───
│ │ │ │ │ │ │ │
(0, 4): ───────┼───────X───┼───X───┼───@───────────┼───┼───M───
│ │ │ │ │ │
(0, 5): ───────┼───────────X───────X───@───────────┼───┼───M───
│ │ │
(0, 6): ───────X───H───@───@───@───@───X───H───────X───@───M───
│ │ │ │ │
(0, 7): ───────────────X───┼───X───┼───@───────────────────M───
│ │ │
(0, 8): ───────────────────X───────X───@───────────────────M───
reference: P. W. Shor, Phys. Rev. A, 52, R2493 (1995).
"""

import random

import cirq


class OneQubitShorsCode:

def __init__(self):
self.num_physical_qubits = 9
self.physical_qubits = cirq.LineQubit.range(self.num_physical_qubits)

def encode(self):
yield cirq.ops.Moment(
[cirq.CNOT(self.physical_qubits[0], self.physical_qubits[3])])
yield cirq.ops.Moment(
[cirq.CNOT(self.physical_qubits[0], self.physical_qubits[6])])
yield cirq.ops.Moment([
cirq.H(self.physical_qubits[0]),
cirq.H(self.physical_qubits[3]),
cirq.H(self.physical_qubits[6])
])
yield cirq.ops.Moment([
cirq.CNOT(self.physical_qubits[0], self.physical_qubits[1]),
cirq.CNOT(self.physical_qubits[3], self.physical_qubits[4]),
cirq.CNOT(self.physical_qubits[6], self.physical_qubits[7])
])
yield cirq.ops.Moment([
cirq.CNOT(self.physical_qubits[0], self.physical_qubits[2]),
cirq.CNOT(self.physical_qubits[3], self.physical_qubits[5]),
cirq.CNOT(self.physical_qubits[6], self.physical_qubits[8])
])

def apply_gate(self, gate: cirq.Gate, pos: int):
if pos > self.num_physical_qubits:
raise IndexError
else:
return gate(self.physical_qubits[pos])

def correct(self):
yield cirq.ops.Moment([
cirq.CNOT(self.physical_qubits[0], self.physical_qubits[1]),
cirq.CNOT(self.physical_qubits[3], self.physical_qubits[4]),
cirq.CNOT(self.physical_qubits[6], self.physical_qubits[7])
])
yield cirq.ops.Moment([
cirq.CNOT(self.physical_qubits[0], self.physical_qubits[2]),
cirq.CNOT(self.physical_qubits[3], self.physical_qubits[5]),
cirq.CNOT(self.physical_qubits[6], self.physical_qubits[8])
])
yield cirq.ops.Moment([
cirq.CCNOT(self.physical_qubits[1], self.physical_qubits[2],
self.physical_qubits[0]),
cirq.CCNOT(self.physical_qubits[4], self.physical_qubits[5],
self.physical_qubits[3]),
cirq.CCNOT(self.physical_qubits[7], self.physical_qubits[8],
self.physical_qubits[6])
])
yield cirq.ops.Moment([
cirq.H(self.physical_qubits[0]),
cirq.H(self.physical_qubits[3]),
cirq.H(self.physical_qubits[6])
])
yield cirq.ops.Moment(
[cirq.CNOT(self.physical_qubits[0], self.physical_qubits[3])])
yield cirq.ops.Moment(
[cirq.CNOT(self.physical_qubits[0], self.physical_qubits[6])])
yield cirq.ops.Moment([
cirq.CCNOT(self.physical_qubits[3], self.physical_qubits[6],
self.physical_qubits[0])
])


if __name__ == '__main__':
# coverage: ignore

# create circuit with 9 physical qubits
code = OneQubitShorsCode()

circuit = cirq.Circuit(code.apply_gate(cirq.X**(1 / 4), 0))
print(cirq.dirac_notation(circuit.final_state_vector(initial_state=0)))

circuit += cirq.Circuit(code.encode())
print(cirq.dirac_notation(circuit.final_state_vector(initial_state=0)))

# create error
circuit += cirq.Circuit(
code.apply_gate(cirq.X, random.randint(0,
code.num_physical_qubits - 1)))
print(cirq.dirac_notation(circuit.final_state_vector(initial_state=0)))

# correct error and decode
circuit += cirq.Circuit(code.correct())
print(cirq.dirac_notation(circuit.final_state_vector(initial_state=0)))

0 comments on commit 3e00896

Please sign in to comment.