Skip to content
This repository was archived by the owner on Jun 12, 2023. It is now read-only.
Merged
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
1,056 changes: 1,056 additions & 0 deletions examples/repetition_code_tutorial.ipynb

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions qiskit/ignis/verification/topological_codes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.


"""
Error correction benchmarking module
"""

from .circuits import RepetitionCode
from .fitters import GraphDecoder
from .fitters import lookuptable_decoding
from .fitters import postselection_decoding
188 changes: 188 additions & 0 deletions qiskit/ignis/verification/topological_codes/circuits.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

'''
Generates circuits for quantum error correction
'''

from qiskit import QuantumRegister, ClassicalRegister
from qiskit import QuantumCircuit


class RepetitionCode():
'''
Implementation of a distance d repetition code, implemented over
T syndrome measurement rounds.
'''

def __init__(self, d, T=0):
'''
Creates the circuits corresponding to a logical 0 and 1 encoded
using a repetition code.

Args:
d: Number of code qubits (and hence repetitions) used.
T: Number of rounds of ancilla-assited syndrome measurement.


Additional information:
No measurements are added to the circuit if `T=0`. Otherwise
`T` rounds are added, followed by measurement of the code
qubits (corresponding to a logical measurement and final
syndrome measurement round).
'''

self.d = d
self.T = 0

self.code_qubit = QuantumRegister(d, 'code_qubit')
self.link_qubit = QuantumRegister((d - 1), 'link_qubit')
self.qubit_registers = {'code_qubit', 'link_qubit'}

self.link_bits = []
self.code_bit = ClassicalRegister(d, 'code_bit')

self.circuit = {}
for log in ['0', '1']:
self.circuit[log] = QuantumCircuit(
self.link_qubit, self.code_qubit, name=log)

self._preparation()

for _ in range(T):
self.syndrome_measurement()

if T != 0:
self.readout()

def get_circuit_list(self):
'''
Returns:
circuit_list: self.circuit as a list, with
circuit_list[0] = circuit['0']
circuit_list[1] = circuit['1']
'''
circuit_list = [self.circuit[log] for log in ['0', '1']]
return circuit_list

def x(self, logs=('0', '1')):
'''
Applies a logical x to the circuits for the given logical values.

Args:
logs: List or tuple of logical values expressed as strings.
'''
for log in logs:
for j in range(self.d):
self.circuit[log].x(self.code_qubit[j])
self.circuit[log].barrier()

def _preparation(self):
'''
Prepares logical bit states by applying an x to the circuit that will
encode a 1.
'''
self.x(['1'])

def syndrome_measurement(self):
'''
Application of a syndrome measurement round.
'''

self.link_bits.append(ClassicalRegister(
(self.d - 1), 'round_' + str(self.T) + '_link_bit'))

for log in ['0', '1']:

self.circuit[log].add_register(self.link_bits[-1])

for j in range(self.d - 1):
self.circuit[log].cx(self.code_qubit[j], self.link_qubit[j])

for j in range(self.d - 1):
self.circuit[log].cx(
self.code_qubit[j + 1], self.link_qubit[j])

for j in range(self.d - 1):
self.circuit[log].measure(
self.link_qubit[j], self.link_bits[self.T][j])
self.circuit[log].reset(self.link_qubit[j])

self.circuit[log].barrier()

self.T += 1

def readout(self):
'''
Readout of all code qubits, which corresponds to a logical measurement
as well as allowing for a measurement of the syndrome to be inferred.
'''
for log in ['0', '1']:
self.circuit[log].add_register(self.code_bit)
self.circuit[log].measure(self.code_qubit, self.code_bit)

def process_results(self, raw_results):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The philosophy is to have anything processing results be in the fitter

'''
Args:
raw_results: A dictionary whose keys are logical values, and whose
values are standard counts dictionaries, (as obtained from the
`get_counts` method of a qiskit.Result object).

Returns:
results: Dictionary with the same structure as the input, but with
the bit strings used as keys in the counts dictionaries converted
to the form required by the decoder.

Additional information:
The circuits must be executed outside of this class, so that
their is full freedom to compile, choose a backend, use a
noise model, etc. The results from these executions should then
be used to create the input for this method.
'''
results = {}
for log in raw_results:
results[log] = {}
for string in raw_results[log]:

# logical readout taken from
measured_log = string[0] + ' ' + string[self.d - 1]

# final syndrome deduced from final code qubit readout
full_syndrome = ''
for j in range(self.d - 1):
full_syndrome += '0' * (string[j] == string[j + 1]) \
+ '1' * (string[j] != string[j + 1])
# results from all other syndrome measurements then added
full_syndrome = full_syndrome + string[self.d:]

# changes between one syndrome and the next then calculated
syndrome_list = full_syndrome.split(' ')
syndrome_changes = ''
for t in range(self.T + 1):
for j in range(self.d - 1):
if t == 0:
change = (syndrome_list[-1][j] != '0')
else:
change = (syndrome_list[-t][j]
!= syndrome_list[-t - 1][j])
syndrome_changes += '0' * (not change) + '1' * change
syndrome_changes += ' '

# the space separated string of syndrome changes then gets a
# double space separated logical value on the end
new_string = measured_log + ' ' + syndrome_changes[:-1]

results[log][new_string] = raw_results[log][string]

return results
Loading