Skip to content

Commit

Permalink
Fix CompleteMeasFitter not imported in QuantumInstance (#6782) (#6790)
Browse files Browse the repository at this point in the history
* Fix CompleteMeasFitter not imported in QuantumInstance

* Update releasenotes/notes/completemeasfitter-386e94a271ba0180.yaml

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>

* added unit test

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
(cherry picked from commit fbf389f)

Co-authored-by: Manoel Marques <Manoel.Marques@ibm.com>
  • Loading branch information
mergify[bot] and manoelmarques authored Jul 22, 2021
1 parent cfc7e1c commit fce0cd0
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 27 deletions.
77 changes: 60 additions & 17 deletions qiskit/utils/quantum_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
""" Quantum Instance module """

from typing import Optional, List, Union, Dict, Callable, Tuple
from enum import Enum
import copy
import logging
import time
Expand All @@ -34,6 +35,59 @@
logger = logging.getLogger(__name__)


class _MeasFitterType(Enum):
"""Meas Fitter Type."""

COMPLETE_MEAS_FITTER = 0
TENSORED_MEAS_FITTER = 1

@staticmethod
def type_from_class(meas_class):
"""
Returns fitter type from class
"""
try:
from qiskit.ignis.mitigation.measurement import (
CompleteMeasFitter,
TensoredMeasFitter,
)
except ImportError as ex:
raise MissingOptionalLibraryError(
libname="qiskit-ignis",
name="QuantumInstance",
pip_install="pip install qiskit-ignis",
) from ex
if meas_class == CompleteMeasFitter:
return _MeasFitterType.COMPLETE_MEAS_FITTER
elif meas_class == TensoredMeasFitter:
return _MeasFitterType.TENSORED_MEAS_FITTER
else:
raise QiskitError(f"Unknown fitter {meas_class}")

@staticmethod
def type_from_instance(meas_instance):
"""
Returns fitter type from instance
"""
try:
from qiskit.ignis.mitigation.measurement import (
CompleteMeasFitter,
TensoredMeasFitter,
)
except ImportError as ex:
raise MissingOptionalLibraryError(
libname="qiskit-ignis",
name="QuantumInstance",
pip_install="pip install qiskit-ignis",
) from ex
if isinstance(meas_instance, CompleteMeasFitter):
return _MeasFitterType.COMPLETE_MEAS_FITTER
elif isinstance(meas_instance, TensoredMeasFitter):
return _MeasFitterType.TENSORED_MEAS_FITTER
else:
raise QiskitError(f"Unknown fitter {meas_instance}")


class QuantumInstance:
"""Quantum Backend including execution setting."""

Expand Down Expand Up @@ -534,28 +588,15 @@ def _find_save_state(data):
cals_result = result

logger.info("Building calibration matrix for measurement error mitigation.")
try:
from qiskit.ignis.mitigation.measurement import (
CompleteMeasFitter,
TensoredMeasFitter,
)
except ImportError as ex:
raise MissingOptionalLibraryError(
libname="qiskit-ignis",
name="execute",
pip_install="pip install qiskit-ignis",
) from ex
if self._meas_error_mitigation_cls == CompleteMeasFitter:
meas_type = _MeasFitterType.type_from_class(self._meas_error_mitigation_cls)
if meas_type == _MeasFitterType.COMPLETE_MEAS_FITTER:
meas_error_mitigation_fitter = self._meas_error_mitigation_cls(
cals_result, state_labels, qubit_list=qubit_index, circlabel=circuit_labels
)
elif self._meas_error_mitigation_cls == TensoredMeasFitter:
elif meas_type == _MeasFitterType.TENSORED_MEAS_FITTER:
meas_error_mitigation_fitter = self._meas_error_mitigation_cls(
cals_result, mit_pattern=state_labels, circlabel=circuit_labels
)
else:
raise QiskitError(f"Unknown fitter {self._meas_error_mitigation_cls}")

self._meas_error_mitigation_fitters[qubit_index_str] = (
meas_error_mitigation_fitter,
time.time(),
Expand Down Expand Up @@ -607,7 +648,9 @@ def _find_save_state(data):
tmp_result.results = [result.results[i] for i in c_idx]
if curr_qubit_index == qubit_index:
tmp_fitter = meas_error_mitigation_fitter
elif isinstance(meas_error_mitigation_fitter, CompleteMeasFitter):
elif _MeasFitterType.COMPLETE_MEAS_FITTER == _MeasFitterType.type_from_instance(
meas_error_mitigation_fitter
):
tmp_fitter = meas_error_mitigation_fitter.subset_fitter(curr_qubit_index)
else:
raise QiskitError(
Expand Down
14 changes: 7 additions & 7 deletions qiskit/utils/run_circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ def _maybe_split_qobj_by_gates(qobjs: List[QasmQobj], qobj: QasmQobj) -> List[Qa
if MAX_GATES_PER_JOB is not None:
max_gates_per_job = int(MAX_GATES_PER_JOB)
total_num_gates = 0
for j in range(len(qobj.experiments)):
total_num_gates += len(qobj.experiments[j].instructions)
for experiment in qobj.experiments:
total_num_gates += len(experiment.instructions)
# split by gates if total number of gates in a qobj exceed MAX_GATES_PER_JOB
if total_num_gates > max_gates_per_job:
qobj_template = QasmQobj(
Expand All @@ -117,17 +117,17 @@ def _maybe_split_qobj_by_gates(qobjs: List[QasmQobj], qobj: QasmQobj) -> List[Qa
temp_qobj.qobj_id = str(uuid.uuid4())
temp_qobj.experiments = []
num_gates = 0
for i in range(len(qobj.experiments)):
num_gates += len(qobj.experiments[i].instructions)
for experiment in qobj.experiments:
num_gates += len(experiment.instructions)
if num_gates <= max_gates_per_job:
temp_qobj.experiments.append(qobj.experiments[i])
temp_qobj.experiments.append(experiment)
else:
qobjs.append(temp_qobj)
# Initialize for next temp_qobj
temp_qobj = copy.deepcopy(qobj_template)
temp_qobj.qobj_id = str(uuid.uuid4())
temp_qobj.experiments.append(qobj.experiments[i])
num_gates = len(qobj.experiments[i].instructions)
temp_qobj.experiments.append(experiment)
num_gates = len(experiment.instructions)

qobjs.append(temp_qobj)
else:
Expand Down
7 changes: 7 additions & 0 deletions releasenotes/notes/completemeasfitter-386e94a271ba0180.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
Fixed an issue where the :class:`~qiskit.utils.QuantumInstance` class would potentially
try to use the :class:`~qiskit.ignis.qiskit.ignis.mitigation.CompleteMeasFitter` class
before it was imported resulting in an error.
Fixed `#6774 <https://github.com/Qiskit/qiskit-terra/issues/6774>`__
70 changes: 67 additions & 3 deletions test/python/algorithms/test_measure_error_mitigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@

from test.python.algorithms import QiskitAlgorithmsTestCase
from ddt import ddt, data
import numpy as np
import retworkx as rx
from qiskit import QuantumCircuit
from qiskit.quantum_info import Pauli
from qiskit.exceptions import QiskitError
from qiskit.utils import QuantumInstance, algorithm_globals
from qiskit.algorithms import VQE
from qiskit.opflow import I, X, Z
from qiskit.algorithms.optimizers import SPSA
from qiskit.algorithms import VQE, QAOA
from qiskit.opflow import I, X, Z, PauliSumOp
from qiskit.algorithms.optimizers import SPSA, COBYLA
from qiskit.circuit.library import EfficientSU2

try:
Expand Down Expand Up @@ -148,6 +151,67 @@ def test_measurement_error_mitigation_with_vqe(self, config):
quantum_instance.reset_execution_results()
self.assertAlmostEqual(result.eigenvalue.real, -1.86, delta=0.05)

def _get_operator(self, weight_matrix):
"""Generate Hamiltonian for the max-cut problem of a graph.
Args:
weight_matrix (numpy.ndarray) : adjacency matrix.
Returns:
PauliSumOp: operator for the Hamiltonian
float: a constant shift for the obj function.
"""
num_nodes = weight_matrix.shape[0]
pauli_list = []
shift = 0
for i in range(num_nodes):
for j in range(i):
if weight_matrix[i, j] != 0:
x_p = np.zeros(num_nodes, dtype=bool)
z_p = np.zeros(num_nodes, dtype=bool)
z_p[i] = True
z_p[j] = True
pauli_list.append([0.5 * weight_matrix[i, j], Pauli((z_p, x_p))])
shift -= 0.5 * weight_matrix[i, j]
opflow_list = [(pauli[1].to_label(), pauli[0]) for pauli in pauli_list]
return PauliSumOp.from_list(opflow_list), shift

def test_measurement_error_mitigation_qaoa(self):
"""measurement error mitigation test with QAOA"""
if _ERROR_MITIGATION_IMPORT_ERROR is not None:
self.skipTest(
f"Package doesn't appear to be installed. Error: '{_ERROR_MITIGATION_IMPORT_ERROR}'"
)
return

algorithm_globals.random_seed = 167

# build noise model
noise_model = noise.NoiseModel()
read_err = noise.errors.readout_error.ReadoutError([[0.9, 0.1], [0.25, 0.75]])
noise_model.add_all_qubit_readout_error(read_err)

backend = Aer.get_backend("aer_simulator")
quantum_instance = QuantumInstance(
backend=backend,
seed_simulator=algorithm_globals.random_seed,
seed_transpiler=algorithm_globals.random_seed,
noise_model=noise_model,
measurement_error_mitigation_cls=CompleteMeasFitter,
)
w = rx.adjacency_matrix(
rx.undirected_gnp_random_graph(5, 0.5, seed=algorithm_globals.random_seed)
)
qubit_op, _ = self._get_operator(w)
qaoa = QAOA(
optimizer=COBYLA(maxiter=1),
quantum_instance=quantum_instance,
initial_point=np.asarray([0.0, 0.0]),
)
result = qaoa.compute_minimum_eigenvalue(operator=qubit_op)
self.assertAlmostEqual(result.eigenvalue.real, 3.49, delta=0.05)


if __name__ == "__main__":
unittest.main()

0 comments on commit fce0cd0

Please sign in to comment.