Skip to content

Commit

Permalink
Merge branch 'feature/curve_analysis_baseclass' of github.com:nkanaza…
Browse files Browse the repository at this point in the history
…wa1989/qiskit-experiments into feature/curve_analysis_baseclass
  • Loading branch information
nkanazawa1989 committed Apr 26, 2022
2 parents 72d82e5 + 9a92d1e commit 5f20a7b
Show file tree
Hide file tree
Showing 38 changed files with 2,191 additions and 1,301 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ jobs:
run: python -m pip install -U tox setuptools virtualenv wheel
- name: Install and Run Tests
run: tox -e py
if: runner.os != 'macOS'
- name: Install and Run Tests
run: tox -e py
if: runner.os == 'macOS'
env:
OMP_NUM_THREADS: 1

lint:
name: lint
Expand Down
13 changes: 2 additions & 11 deletions docs/tutorials/calibrating_armonk.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
"outputs": [],
"source": [
"library = FixedFrequencyTransmon(default_values={\"duration\": 320})\n",
"cals = Calibrations.from_backend(backend, library)"
"cals = Calibrations.from_backend(backend, libraries=[library])"
]
},
{
Expand Down Expand Up @@ -900,16 +900,7 @@
"execution_count": 27,
"id": "317994db",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/daniel/Documents/IBM/qiskit/qiskit-experiments/qiskit_experiments/calibration_management/calibrations.py:1333: UserWarning: Schedules are only saved in text format. They cannot be re-loaded.\n",
" warnings.warn(\"Schedules are only saved in text format. They cannot be re-loaded.\")\n"
]
}
],
"outputs": [],
"source": [
"cals.save(file_type=\"csv\", overwrite=True, file_prefix=\"Armonk\")"
]
Expand Down
94 changes: 63 additions & 31 deletions qiskit_experiments/calibration_management/calibrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,25 @@ def __init__(
coupling_map: Optional[List[List[int]]] = None,
control_channel_map: Optional[Dict[Tuple[int, ...], List[ControlChannel]]] = None,
library: Optional[Union[BasisGateLibrary, List[BasisGateLibrary]]] = None,
libraries: Optional[List[BasisGateLibrary]] = None,
add_parameter_defaults: bool = True,
backend_name: Optional[str] = None,
backend_version: Optional[str] = None,
):
"""Initialize the calibrations.
Calibrations can be initialized from a basis gate library, i.e. a subclass of
Calibrations can be initialized from a list of basis gate libraries, i.e. a subclass of
:class:`BasisGateLibrary`. As example consider the following code:
.. code-block:: python
cals = Calibrations(
library=FixedFrequencyTransmon(
basis_gates=["x", "sx"],
default_values={duration: 320}
)
libraries=[
FixedFrequencyTransmon(
basis_gates=["x", "sx"],
default_values={duration: 320}
)
]
)
Args:
Expand All @@ -99,27 +102,41 @@ def __init__(
keys are tuples of qubits and the values are a list of ControlChannels
that correspond to the qubits in the keys. If a control_channel_map is given
then the qubits must be in the coupling_map.
library: A library instance from which to get template schedules to register as well
as default parameter values.
library (deprecated): A library instance from which to get template schedules to
register as well as default parameter values.
libraries: A list of library instance from which to get template schedules to register
as well as default parameter values.
add_parameter_defaults: A boolean to indicate weather the default parameter values of
the given library should be used to populate the calibrations. By default this
the given libraries should be used to populate the calibrations. By default this
value is True but can be set to false when deserializing a calibrations object.
backend_name: The name of the backend that these calibrations are attached to.
backend_version: The version of the backend that these calibrations are attached to.
Raises:
NotImplementedError: if a list of libraries is given. This will be implemented in
the future.
CalibrationError: if both library and libraries are given. Note that library will be
removed in future versions.
"""
self._backend_name = backend_name
self._backend_version = backend_version

if isinstance(library, list):
raise NotImplementedError(
"Passing a list of libraries from which to instantiate "
"will be supported in future releases."
if library:
warnings.warn(
"library has been deprecated, please provide `libraries` instead."
"The `library` argument along with this warning will be removed "
"in Qiskit Experiments 0.4.",
DeprecationWarning,
stacklevel=2,
)

if libraries:
raise CalibrationError("Cannot supply both library and libraries.")

if not isinstance(library, list):
libraries = [library]
else:
libraries = library

# Mapping between qubits and their control channels.
self._control_channel_map = control_channel_map if control_channel_map else {}

Expand Down Expand Up @@ -149,18 +166,18 @@ def __init__(
self._hash_to_counter_map = {}
self._parameter_counter = 0

self._library = None
if library is not None:
self._library = library
self._libraries = libraries
if libraries is not None:
for lib in libraries:

# Add the basis gates
for gate in library.basis_gates:
self.add_schedule(library[gate], num_qubits=library.num_qubits(gate))
# Add the basis gates
for gate in lib.basis_gates:
self.add_schedule(lib[gate], num_qubits=lib.num_qubits(gate))

# Add the default values
if add_parameter_defaults:
for param_conf in library.default_values():
self.add_parameter_value(*param_conf, update_inst_map=False)
# Add the default values
if add_parameter_defaults:
for param_conf in lib.default_values():
self.add_parameter_value(*param_conf, update_inst_map=False)

# This internal parameter is False so that if a schedule is added after the
# init it will be set to True and serialization will raise an error.
Expand Down Expand Up @@ -220,6 +237,7 @@ def from_backend(
cls,
backend: Backend,
library: Optional[BasisGateLibrary] = None,
libraries: Optional[List[BasisGateLibrary]] = None,
add_parameter_defaults: bool = True,
) -> "Calibrations":
"""Create an instance of Calibrations from a backend.
Expand All @@ -228,8 +246,10 @@ def from_backend(
backend: A backend instance from which to extract the qubit and readout frequencies
(which will be added as first guesses for the corresponding parameters) as well
as the coupling map.
library: A library instance from which to get template schedules to register as well
as default parameter values.
library: A library or list thereof from which to get template schedules to register as
well as default parameter values.
libraries: A list of libraries from which to get template schedules to register as
well as default parameter values.
add_parameter_defaults: A boolean to indicate whether the default parameter values of
the given library should be used to populate the calibrations. By default this
value is ``True``.
Expand All @@ -246,6 +266,7 @@ def from_backend(
getattr(backend.configuration(), "coupling_map", []),
getattr(backend.configuration(), "control_channels", None),
library,
libraries,
add_parameter_defaults,
backend_name,
getattr(backend, "version", None),
Expand All @@ -264,9 +285,20 @@ def from_backend(
return cals

@property
def library(self) -> Optional[BasisGateLibrary]:
"""Return the name of the library, e.g. for experiment metadata."""
return self._library
def libraries(self) -> Optional[List[BasisGateLibrary]]:
"""Return the libraries used to initialize the calibrations."""
return self._libraries

@property
def library(self) -> Optional[List[BasisGateLibrary]]:
"""Return the libraries used to initialize the calibrations."""
warnings.warn(
"library has been deprecated, use libraries instead."
"This warning will be removed with backport in Qiskit Experiments 0.4.",
DeprecationWarning,
stacklevel=2,
)
return self._libraries

def _get_operated_qubits(self) -> Dict[int, List[int]]:
"""Get a dict describing qubit couplings.
Expand Down Expand Up @@ -1609,7 +1641,7 @@ def __eq__(self, other: "Calibrations") -> bool:
- The backends have the same name.
- The backends have the same version.
- The calibrations contain the same schedules.
- The stored paramters have the same values.
- The stored parameters have the same values.
"""
if self.backend_name != other.backend_name:
return False
Expand Down Expand Up @@ -1654,7 +1686,7 @@ def config(self) -> Dict[str, Any]:
kwargs = {
"coupling_map": self._coupling_map,
"control_channel_map": ControlChannelMap(self._control_channel_map),
"library": self.library,
"libraries": self.libraries,
"add_parameter_defaults": False, # the parameters will be added outside of the init
"backend_name": self._backend_name,
"backend_version": self._backend_version,
Expand Down
29 changes: 23 additions & 6 deletions qiskit_experiments/database_service/db_experiment_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,25 +516,37 @@ def _run_analysis_callback(
# If not ready cancel the callback before running
if cancel:
self._analysis_callbacks[callback_id].status = AnalysisStatus.CANCELLED
LOG.warning("Cancelled analysis callback [Analysis ID: %s]", callback_id)
LOG.info(
"Cancelled analysis callback [Experiment ID: %s][Analysis Callback ID: %s]",
self.experiment_id,
callback_id,
)
return callback_id, False

# Run callback function
self._analysis_callbacks[callback_id].status = AnalysisStatus.RUNNING
try:
LOG.debug(
"Running analysis callback '%s' [Analysis ID: %s]",
"Running analysis callback '%s' [Experiment ID: %s][Analysis Callback ID: %s]",
self._analysis_callbacks[callback_id].name,
self.experiment_id,
callback_id,
)
callback(self, **kwargs)
self._analysis_callbacks[callback_id].status = AnalysisStatus.DONE
LOG.debug("Analysis callback finished [Analysis ID: %s]", callback_id)
LOG.debug(
"Analysis callback finished [Experiment ID: %s][Analysis Callback ID: %s]",
self.experiment_id,
callback_id,
)
return callback_id, True
except Exception as ex: # pylint: disable=broad-except
self._analysis_callbacks[callback_id].status = AnalysisStatus.ERROR
tb_text = "".join(traceback.format_exception(type(ex), ex, ex.__traceback__))
error_msg = f"Analysis callback failed [Analysis ID: {callback_id}]:\n{tb_text}"
error_msg = (
f"Analysis callback failed [Experiment ID: {self.experiment_id}]"
f"[Analysis Callback ID: {callback_id}]:\n{tb_text}"
)
self._analysis_callbacks[callback_id].error_msg = error_msg
LOG.warning(error_msg)
return callback_id, False
Expand Down Expand Up @@ -1172,7 +1184,12 @@ def cancel_analysis(self, ids: Optional[Union[str, List[str]]] = None) -> bool:
# Check for running callback that can't be cancelled
if callback.status == AnalysisStatus.RUNNING:
all_cancelled = False
LOG.warning("Unable to cancel running analysis callback [Analysis ID: %s]", cid)
LOG.warning(
"Unable to cancel running analysis callback [Experiment ID: %s]"
"[Analysis Callback ID: %s]",
self.experiment_id,
cid,
)
else:
not_running.append(cid)

Expand Down Expand Up @@ -1467,7 +1484,7 @@ def analysis_errors(self) -> str:
# Get any callback errors
for cid, callback in self._analysis_callbacks.items():
if callback.status == AnalysisStatus.ERROR:
errors.append(f"\n[Analysis ID: {cid}]: {callback.error_msg}")
errors.append(f"\n[Analysis Callback ID: {cid}]: {callback.error_msg}")

return "".join(errors)

Expand Down
14 changes: 5 additions & 9 deletions qiskit_experiments/library/tomography/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,21 @@
basis.PauliPreparationBasis
basis.Pauli6PreparationBasis
Custom tensor product basis classes
Custom local tensor product basis classes
.. autosummary::
:toctree: ../stubs/
basis.TomographyMeasurementBasis
basis.TomographyPreparationBasis
basis.FitterMeasurementBasis
basis.FitterPreparationBasis
basis.LocalMeasurementBasis
basis.LocalPreparationBasis
Abstract base classes
.. autosummary::
:toctree: ../stubs/
basis.BaseTomographyMeasurementBasis
basis.BaseTomographyPreparationBasis
basis.BaseFitterMeasurementBasis
basis.BaseFitterPreparationBasis
basis.MeasurementBasis
basis.PreparationBasis
.. warning::
The API for tomography fitters and bases is still under development so may
Expand Down
13 changes: 2 additions & 11 deletions qiskit_experiments/library/tomography/basis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,6 @@

"""Tomography experiment basis classes."""

# Abstract base classes for bases
from .base_basis import (
BaseFitterMeasurementBasis,
BaseFitterPreparationBasis,
BaseTomographyMeasurementBasis,
BaseTomographyPreparationBasis,
)

# Tensor product bases classes
from .fitter_basis import FitterMeasurementBasis, FitterPreparationBasis
from .tomography_basis import TomographyMeasurementBasis, TomographyPreparationBasis
from .base_basis import MeasurementBasis, PreparationBasis
from .local_basis import LocalPreparationBasis, LocalMeasurementBasis
from .pauli_basis import PauliMeasurementBasis, PauliPreparationBasis, Pauli6PreparationBasis
Loading

0 comments on commit 5f20a7b

Please sign in to comment.