Skip to content

Commit

Permalink
Merge pull request #153 from Qiskit-Partners/update_faulty_qubits
Browse files Browse the repository at this point in the history
[WIP] Relax faulty qubit checking
  • Loading branch information
nonhermitian authored Mar 24, 2023
2 parents b37a7b0 + 23e40a2 commit 8e9cbf1
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,4 @@ mthree/version.py
docs/*.json
docs/stubs/*
docs/tutorials/
bad_cals.json
42 changes: 34 additions & 8 deletions mthree/mitigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ def __init__(self, system=None, iter_threshold=4096):
self._job_error = None
# Holds the cals file
self.cals_file = None
# faulty qubits
self.faulty_qubits = []

def __getattribute__(self, attr):
"""This allows for checking the status of the threaded cals call
Expand Down Expand Up @@ -197,6 +199,7 @@ def cals_from_file(self, cals_file):
self.cal_shots = None
self.single_qubit_cals = [np.asarray(cal) if cal else None
for cal in loaded_data]
self.faulty_qubits = _faulty_qubit_checker(self.single_qubit_cals)

def cals_to_file(self, cals_file=None):
"""Save calibration data to JSON file.
Expand All @@ -213,7 +216,7 @@ def cals_to_file(self, cals_file=None):
if not self.single_qubit_cals:
raise M3Error('Mitigator is not calibrated.')
save_dict = {'timestamp': self.cal_timestamp,
'backend': self.system_info["name"],
'backend': self.system_info.get("name", None),
'shots': self.cal_shots,
'cals': self.single_qubit_cals}
with open(cals_file, 'wb') as fd:
Expand Down Expand Up @@ -247,6 +250,7 @@ def cals_from_matrices(self, matrices):
raise M3Error('Input list length not equal to'
' number of qubits {} != {}'.format(len(matrices), self.num_qubits))
self.single_qubit_cals = matrices
self.faulty_qubits = _faulty_qubit_checker(self.single_qubit_cals)

def cals_to_matrices(self):
"""Return single qubit cals as list of NumPy arrays
Expand Down Expand Up @@ -383,6 +387,15 @@ def apply_correction(self, counts, qubits, distance=None,
if len(qubits) != len(counts):
raise M3Error('Length of counts does not match length of qubits.')

# Check if using faulty qubits
bad_qubits = set()
for item in qubits:
for qu in item:
if qu in self.faulty_qubits:
bad_qubits.add(qu)
if any(bad_qubits):
raise M3Error('Using faulty qubits: {}'.format(bad_qubits))

quasi_out = []
for idx, cnts in enumerate(counts):

Expand Down Expand Up @@ -743,19 +756,32 @@ def _job_thread(job, mit, method, qubits, num_cal_qubits, cal_strings):
else:
cal[1, 1] += good_prep[kk] / denom

for jj, cal in enumerate(cals):
for cal in cals:
cal[1, 0] = 1.0 - cal[0, 0]
cal[0, 1] = 1.0 - cal[1, 1]

if cal[0, 1] >= cal[0, 0]:
bad_list.append(qubits[jj])

for idx, cal in enumerate(cals):
mit.single_qubit_cals[qubits[idx]] = cal

# save cals to file, if requested
if mit.cals_file:
mit.cals_to_file(mit.cals_file)
# Return list of faulty qubits, if any
if any(bad_list):
mit._job_error = M3Error('Faulty qubits detected: {}'.format(bad_list))
# faulty qubits, if any
mit.faulty_qubits = _faulty_qubit_checker(mit.single_qubit_cals)


def _faulty_qubit_checker(cals):
"""Find faulty qubits in cals
Parameters:
cals (list): Input list of calibrations
Returns:
list: Faulty qubits
"""
faulty_qubits = []
for idx, cal in enumerate(cals):
if cal is not None:
if cal[0, 1] >= cal[0, 0]:
faulty_qubits.append(idx)
return faulty_qubits
53 changes: 53 additions & 0 deletions mthree/test/test_faulty.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# This code is part of Mthree.
#
# (C) Copyright IBM 2023.
#
# 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.
# pylint: disable=no-name-in-module

"""Test faulty qubits handling"""
import numpy as np
import pytest

import mthree


def test_faulty_logic():
"""Test faulty qubits block correction"""

mit = mthree.M3Mitigation(None)
mit.single_qubit_cals = [np.array([[0.9819, 0.043],
[0.0181, 0.957]]),
np.array([[0.4849, 0.5233],
[0.5151, 0.4767]]),
np.array([[0.9092, 0.4021],
[0.0908, 0.5979]]),
np.array([[0.4117, 0.8101],
[0.5883, 0.1899]])]
mit.faulty_qubits = [1, 3]
counts = {"00": 0.4, "01": 0.1, "11": 0.5}
with pytest.raises(mthree.exceptions.M3Error) as _:
_ = mit.apply_correction(counts, qubits=[3, 2])


def test_faulty_io():
"""Check round-tripping IO still has faulty qubits"""
mit = mthree.M3Mitigation(None)
mit.single_qubit_cals = [np.array([[0.9819, 0.043],
[0.0181, 0.957]]),
np.array([[0.4849, 0.5233],
[0.5151, 0.4767]]),
np.array([[0.9092, 0.4021],
[0.0908, 0.5979]]),
np.array([[0.4117, 0.8101],
[0.5883, 0.1899]])]
mit.cals_to_file('bad_cals.json')
mit2 = mthree.M3Mitigation(None)
mit2.cals_from_file('bad_cals.json')
assert mit2.faulty_qubits == [1, 3]
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from Cython.Build import cythonize

MAJOR = 2
MINOR = 2
MINOR = 3
MICRO = 0

ISRELEASED = False
Expand Down

0 comments on commit 8e9cbf1

Please sign in to comment.