Skip to content

Commit 5f20a7b

Browse files
committed
Merge branch 'feature/curve_analysis_baseclass' of github.com:nkanazawa1989/qiskit-experiments into feature/curve_analysis_baseclass
2 parents 72d82e5 + 9a92d1e commit 5f20a7b

38 files changed

+2191
-1301
lines changed

.github/workflows/main.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ jobs:
4141
run: python -m pip install -U tox setuptools virtualenv wheel
4242
- name: Install and Run Tests
4343
run: tox -e py
44+
if: runner.os != 'macOS'
45+
- name: Install and Run Tests
46+
run: tox -e py
47+
if: runner.os == 'macOS'
48+
env:
49+
OMP_NUM_THREADS: 1
4450

4551
lint:
4652
name: lint

docs/tutorials/calibrating_armonk.ipynb

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@
150150
"outputs": [],
151151
"source": [
152152
"library = FixedFrequencyTransmon(default_values={\"duration\": 320})\n",
153-
"cals = Calibrations.from_backend(backend, library)"
153+
"cals = Calibrations.from_backend(backend, libraries=[library])"
154154
]
155155
},
156156
{
@@ -900,16 +900,7 @@
900900
"execution_count": 27,
901901
"id": "317994db",
902902
"metadata": {},
903-
"outputs": [
904-
{
905-
"name": "stderr",
906-
"output_type": "stream",
907-
"text": [
908-
"/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",
909-
" warnings.warn(\"Schedules are only saved in text format. They cannot be re-loaded.\")\n"
910-
]
911-
}
912-
],
903+
"outputs": [],
913904
"source": [
914905
"cals.save(file_type=\"csv\", overwrite=True, file_prefix=\"Armonk\")"
915906
]

qiskit_experiments/calibration_management/calibrations.py

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,25 @@ def __init__(
7373
coupling_map: Optional[List[List[int]]] = None,
7474
control_channel_map: Optional[Dict[Tuple[int, ...], List[ControlChannel]]] = None,
7575
library: Optional[Union[BasisGateLibrary, List[BasisGateLibrary]]] = None,
76+
libraries: Optional[List[BasisGateLibrary]] = None,
7677
add_parameter_defaults: bool = True,
7778
backend_name: Optional[str] = None,
7879
backend_version: Optional[str] = None,
7980
):
8081
"""Initialize the calibrations.
8182
82-
Calibrations can be initialized from a basis gate library, i.e. a subclass of
83+
Calibrations can be initialized from a list of basis gate libraries, i.e. a subclass of
8384
:class:`BasisGateLibrary`. As example consider the following code:
8485
8586
.. code-block:: python
8687
8788
cals = Calibrations(
88-
library=FixedFrequencyTransmon(
89-
basis_gates=["x", "sx"],
90-
default_values={duration: 320}
91-
)
89+
libraries=[
90+
FixedFrequencyTransmon(
91+
basis_gates=["x", "sx"],
92+
default_values={duration: 320}
93+
)
94+
]
9295
)
9396
9497
Args:
@@ -99,27 +102,41 @@ def __init__(
99102
keys are tuples of qubits and the values are a list of ControlChannels
100103
that correspond to the qubits in the keys. If a control_channel_map is given
101104
then the qubits must be in the coupling_map.
102-
library: A library instance from which to get template schedules to register as well
103-
as default parameter values.
105+
library (deprecated): A library instance from which to get template schedules to
106+
register as well as default parameter values.
107+
libraries: A list of library instance from which to get template schedules to register
108+
as well as default parameter values.
104109
add_parameter_defaults: A boolean to indicate weather the default parameter values of
105-
the given library should be used to populate the calibrations. By default this
110+
the given libraries should be used to populate the calibrations. By default this
106111
value is True but can be set to false when deserializing a calibrations object.
107112
backend_name: The name of the backend that these calibrations are attached to.
108113
backend_version: The version of the backend that these calibrations are attached to.
109114
110115
Raises:
111-
NotImplementedError: if a list of libraries is given. This will be implemented in
112-
the future.
116+
CalibrationError: if both library and libraries are given. Note that library will be
117+
removed in future versions.
118+
113119
"""
114120
self._backend_name = backend_name
115121
self._backend_version = backend_version
116122

117-
if isinstance(library, list):
118-
raise NotImplementedError(
119-
"Passing a list of libraries from which to instantiate "
120-
"will be supported in future releases."
123+
if library:
124+
warnings.warn(
125+
"library has been deprecated, please provide `libraries` instead."
126+
"The `library` argument along with this warning will be removed "
127+
"in Qiskit Experiments 0.4.",
128+
DeprecationWarning,
129+
stacklevel=2,
121130
)
122131

132+
if libraries:
133+
raise CalibrationError("Cannot supply both library and libraries.")
134+
135+
if not isinstance(library, list):
136+
libraries = [library]
137+
else:
138+
libraries = library
139+
123140
# Mapping between qubits and their control channels.
124141
self._control_channel_map = control_channel_map if control_channel_map else {}
125142

@@ -149,18 +166,18 @@ def __init__(
149166
self._hash_to_counter_map = {}
150167
self._parameter_counter = 0
151168

152-
self._library = None
153-
if library is not None:
154-
self._library = library
169+
self._libraries = libraries
170+
if libraries is not None:
171+
for lib in libraries:
155172

156-
# Add the basis gates
157-
for gate in library.basis_gates:
158-
self.add_schedule(library[gate], num_qubits=library.num_qubits(gate))
173+
# Add the basis gates
174+
for gate in lib.basis_gates:
175+
self.add_schedule(lib[gate], num_qubits=lib.num_qubits(gate))
159176

160-
# Add the default values
161-
if add_parameter_defaults:
162-
for param_conf in library.default_values():
163-
self.add_parameter_value(*param_conf, update_inst_map=False)
177+
# Add the default values
178+
if add_parameter_defaults:
179+
for param_conf in lib.default_values():
180+
self.add_parameter_value(*param_conf, update_inst_map=False)
164181

165182
# This internal parameter is False so that if a schedule is added after the
166183
# init it will be set to True and serialization will raise an error.
@@ -220,6 +237,7 @@ def from_backend(
220237
cls,
221238
backend: Backend,
222239
library: Optional[BasisGateLibrary] = None,
240+
libraries: Optional[List[BasisGateLibrary]] = None,
223241
add_parameter_defaults: bool = True,
224242
) -> "Calibrations":
225243
"""Create an instance of Calibrations from a backend.
@@ -228,8 +246,10 @@ def from_backend(
228246
backend: A backend instance from which to extract the qubit and readout frequencies
229247
(which will be added as first guesses for the corresponding parameters) as well
230248
as the coupling map.
231-
library: A library instance from which to get template schedules to register as well
232-
as default parameter values.
249+
library: A library or list thereof from which to get template schedules to register as
250+
well as default parameter values.
251+
libraries: A list of libraries from which to get template schedules to register as
252+
well as default parameter values.
233253
add_parameter_defaults: A boolean to indicate whether the default parameter values of
234254
the given library should be used to populate the calibrations. By default this
235255
value is ``True``.
@@ -246,6 +266,7 @@ def from_backend(
246266
getattr(backend.configuration(), "coupling_map", []),
247267
getattr(backend.configuration(), "control_channels", None),
248268
library,
269+
libraries,
249270
add_parameter_defaults,
250271
backend_name,
251272
getattr(backend, "version", None),
@@ -264,9 +285,20 @@ def from_backend(
264285
return cals
265286

266287
@property
267-
def library(self) -> Optional[BasisGateLibrary]:
268-
"""Return the name of the library, e.g. for experiment metadata."""
269-
return self._library
288+
def libraries(self) -> Optional[List[BasisGateLibrary]]:
289+
"""Return the libraries used to initialize the calibrations."""
290+
return self._libraries
291+
292+
@property
293+
def library(self) -> Optional[List[BasisGateLibrary]]:
294+
"""Return the libraries used to initialize the calibrations."""
295+
warnings.warn(
296+
"library has been deprecated, use libraries instead."
297+
"This warning will be removed with backport in Qiskit Experiments 0.4.",
298+
DeprecationWarning,
299+
stacklevel=2,
300+
)
301+
return self._libraries
270302

271303
def _get_operated_qubits(self) -> Dict[int, List[int]]:
272304
"""Get a dict describing qubit couplings.
@@ -1609,7 +1641,7 @@ def __eq__(self, other: "Calibrations") -> bool:
16091641
- The backends have the same name.
16101642
- The backends have the same version.
16111643
- The calibrations contain the same schedules.
1612-
- The stored paramters have the same values.
1644+
- The stored parameters have the same values.
16131645
"""
16141646
if self.backend_name != other.backend_name:
16151647
return False
@@ -1654,7 +1686,7 @@ def config(self) -> Dict[str, Any]:
16541686
kwargs = {
16551687
"coupling_map": self._coupling_map,
16561688
"control_channel_map": ControlChannelMap(self._control_channel_map),
1657-
"library": self.library,
1689+
"libraries": self.libraries,
16581690
"add_parameter_defaults": False, # the parameters will be added outside of the init
16591691
"backend_name": self._backend_name,
16601692
"backend_version": self._backend_version,

qiskit_experiments/database_service/db_experiment_data.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -516,25 +516,37 @@ def _run_analysis_callback(
516516
# If not ready cancel the callback before running
517517
if cancel:
518518
self._analysis_callbacks[callback_id].status = AnalysisStatus.CANCELLED
519-
LOG.warning("Cancelled analysis callback [Analysis ID: %s]", callback_id)
519+
LOG.info(
520+
"Cancelled analysis callback [Experiment ID: %s][Analysis Callback ID: %s]",
521+
self.experiment_id,
522+
callback_id,
523+
)
520524
return callback_id, False
521525

522526
# Run callback function
523527
self._analysis_callbacks[callback_id].status = AnalysisStatus.RUNNING
524528
try:
525529
LOG.debug(
526-
"Running analysis callback '%s' [Analysis ID: %s]",
530+
"Running analysis callback '%s' [Experiment ID: %s][Analysis Callback ID: %s]",
527531
self._analysis_callbacks[callback_id].name,
532+
self.experiment_id,
528533
callback_id,
529534
)
530535
callback(self, **kwargs)
531536
self._analysis_callbacks[callback_id].status = AnalysisStatus.DONE
532-
LOG.debug("Analysis callback finished [Analysis ID: %s]", callback_id)
537+
LOG.debug(
538+
"Analysis callback finished [Experiment ID: %s][Analysis Callback ID: %s]",
539+
self.experiment_id,
540+
callback_id,
541+
)
533542
return callback_id, True
534543
except Exception as ex: # pylint: disable=broad-except
535544
self._analysis_callbacks[callback_id].status = AnalysisStatus.ERROR
536545
tb_text = "".join(traceback.format_exception(type(ex), ex, ex.__traceback__))
537-
error_msg = f"Analysis callback failed [Analysis ID: {callback_id}]:\n{tb_text}"
546+
error_msg = (
547+
f"Analysis callback failed [Experiment ID: {self.experiment_id}]"
548+
f"[Analysis Callback ID: {callback_id}]:\n{tb_text}"
549+
)
538550
self._analysis_callbacks[callback_id].error_msg = error_msg
539551
LOG.warning(error_msg)
540552
return callback_id, False
@@ -1172,7 +1184,12 @@ def cancel_analysis(self, ids: Optional[Union[str, List[str]]] = None) -> bool:
11721184
# Check for running callback that can't be cancelled
11731185
if callback.status == AnalysisStatus.RUNNING:
11741186
all_cancelled = False
1175-
LOG.warning("Unable to cancel running analysis callback [Analysis ID: %s]", cid)
1187+
LOG.warning(
1188+
"Unable to cancel running analysis callback [Experiment ID: %s]"
1189+
"[Analysis Callback ID: %s]",
1190+
self.experiment_id,
1191+
cid,
1192+
)
11761193
else:
11771194
not_running.append(cid)
11781195

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

14721489
return "".join(errors)
14731490

qiskit_experiments/library/tomography/__init__.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,21 @@
6666
basis.PauliPreparationBasis
6767
basis.Pauli6PreparationBasis
6868
69-
Custom tensor product basis classes
69+
Custom local tensor product basis classes
7070
7171
.. autosummary::
7272
:toctree: ../stubs/
7373
74-
basis.TomographyMeasurementBasis
75-
basis.TomographyPreparationBasis
76-
basis.FitterMeasurementBasis
77-
basis.FitterPreparationBasis
74+
basis.LocalMeasurementBasis
75+
basis.LocalPreparationBasis
7876
7977
Abstract base classes
8078
8179
.. autosummary::
8280
:toctree: ../stubs/
8381
84-
basis.BaseTomographyMeasurementBasis
85-
basis.BaseTomographyPreparationBasis
86-
basis.BaseFitterMeasurementBasis
87-
basis.BaseFitterPreparationBasis
82+
basis.MeasurementBasis
83+
basis.PreparationBasis
8884
8985
.. warning::
9086
The API for tomography fitters and bases is still under development so may

qiskit_experiments/library/tomography/basis/__init__.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,6 @@
1212

1313
"""Tomography experiment basis classes."""
1414

15-
# Abstract base classes for bases
16-
from .base_basis import (
17-
BaseFitterMeasurementBasis,
18-
BaseFitterPreparationBasis,
19-
BaseTomographyMeasurementBasis,
20-
BaseTomographyPreparationBasis,
21-
)
22-
23-
# Tensor product bases classes
24-
from .fitter_basis import FitterMeasurementBasis, FitterPreparationBasis
25-
from .tomography_basis import TomographyMeasurementBasis, TomographyPreparationBasis
15+
from .base_basis import MeasurementBasis, PreparationBasis
16+
from .local_basis import LocalPreparationBasis, LocalMeasurementBasis
2617
from .pauli_basis import PauliMeasurementBasis, PauliPreparationBasis, Pauli6PreparationBasis

0 commit comments

Comments
 (0)