# This code is part of Qiskit.
#
# (C) Copyright IBM 2021.
#
# 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.
"""Restless mixin class."""
import logging
from typing import Callable, Sequence, Optional
from qiskit.qobj.utils import MeasLevel, MeasReturnType
from qiskit.utils.deprecation import deprecate_func
from qiskit.providers import Backend
from qiskit_experiments.framework import Options
from qiskit_experiments.data_processing.data_processor import DataProcessor
from qiskit_experiments.data_processing.exceptions import DataProcessorError
from qiskit_experiments.data_processing.nodes import ProjectorType
from qiskit_experiments.data_processing import nodes
from qiskit_experiments.data_processing.processor_library import get_kerneled_processor
from qiskit_experiments.framework.base_analysis import BaseAnalysis
LOG = logging.getLogger(__name__)
[docs]
class RestlessMixin:
"""A mixin to facilitate restless experiments.
This class defines the following methods:
- :meth:`~.RestlessMixin.enable_restless`
- :meth:`~.RestlessMixin._get_restless_processor`
- :meth:`~.RestlessMixin._t1_check`
A restless enabled experiment is an experiment that can be run in a restless
measurement setting. In restless measurements, the qubit is not reset after
each measurement. Instead, the outcome of the previous quantum non-demolition
measurement is the initial state for the current circuit. Restless measurements
therefore require special data processing which is provided by sub-classes of
the :class:`.RestlessNode`. Restless experiments are a fast alternative for
several calibration and characterization tasks, for details see
https://arxiv.org/pdf/2202.06981.pdf.
This class makes it possible for users to enter a restless run mode without having
to manually set all the required run options and the data processor. The required options
are ``rep_delay``, ``init_qubits``, ``memory``, and ``meas_level``. Furthermore,
subclasses can override the :meth:`_get_restless_processor` method if they require more
complex restless data processing such as two-qubit calibrations. In addition, this
class makes it easy to determine if restless measurements are supported for a given
experiment.
User Manual
:doc:`/manuals/measurement/restless_measurements`
"""
analysis: BaseAnalysis
_default_run_options: Options()
set_run_options: Callable
_backend: Backend
_physical_qubits: Sequence[int]
_num_qubits: int
[docs]
@deprecate_func(
since="0.8",
package_name="qiskit-experiments",
additional_msg=("Support for restless experiments has been deprecated."),
)
def enable_restless(
self,
rep_delay: Optional[float] = None,
override_processor_by_restless: bool = True,
suppress_t1_error: bool = False,
):
"""Enables a restless experiment by setting the restless run options and the
restless data processor.
Args:
rep_delay: The repetition delay. This is the delay between a measurement
and the subsequent quantum circuit. Since the backends have
dynamic repetition rates, the repetition delay can be set to a small
value which is required for restless experiments. Typical values are
1 us or less.
override_processor_by_restless: If False, a data processor that is specified in the
analysis options of the experiment is not overridden by the restless data
processor. The default is True.
suppress_t1_error: If True, the default is False, then no error will be raised when
``rep_delay`` is larger than the T1 times of the qubits. Instead, a warning will
be logged as restless measurements may have a large amount of noise.
Raises:
DataProcessorError: If the attribute rep_delay_range is not defined for the backend.
DataProcessorError: If a data processor has already been set but
override_processor_by_restless is True.
DataProcessorError: If the experiment analysis does not have the data_processor
option.
DataProcessorError: If the rep_delay is equal to or greater than the
T1 time of one of the physical qubits in the experiment and the flag
``ignore_t1_check`` is False.
"""
try:
if not rep_delay:
# BackendV1 only; BackendV2 does not support this
rep_delay = self._backend.configuration().rep_delay_range[0]
except AttributeError as error:
raise DataProcessorError(
"The restless experiment can not be enabled because "
"the attribute rep_delay_range is not defined for this backend "
"and a minimum rep_delay can not be set."
) from error
# Check the rep_delay compared to the T1 time.
if not self._t1_check(rep_delay):
msg = (
f"The specified repetition delay {rep_delay} is equal to or greater "
f"than the T1 time of one of the physical qubits"
f"{self._physical_qubits} in the experiment. Consider choosing "
f"a smaller repetition delay for the restless experiment."
)
if suppress_t1_error:
LOG.warning(msg)
else:
raise DataProcessorError(msg)
# The excited state promotion readout analysis option is set to
# False because it is not compatible with a restless experiment.
meas_level = self._default_run_options().get("meas_level", MeasLevel.CLASSIFIED)
meas_return = self._default_run_options().get("meas_return", MeasReturnType.SINGLE)
if not self.analysis.options.get("data_processor", None):
self.set_run_options(
rep_delay=rep_delay,
init_qubits=False,
memory=True,
meas_level=meas_level,
meas_return=meas_return,
use_measure_esp=False,
)
if hasattr(self.analysis.options, "data_processor"):
self.analysis.set_options(
data_processor=self._get_restless_processor(meas_level=meas_level)
)
else:
raise DataProcessorError(
"The restless data processor can not be set since the experiment analysis"
"does not have the data_processor option."
)
else:
if not override_processor_by_restless:
self.set_run_options(
rep_delay=rep_delay,
init_qubits=False,
memory=True,
meas_level=meas_level,
meas_return=meas_return,
use_measure_esp=False,
)
else:
raise DataProcessorError(
"Cannot enable restless. Data processor has already been set and "
"override_processor_by_restless is True."
)
def _get_restless_processor(self, meas_level: int = MeasLevel.CLASSIFIED) -> DataProcessor:
"""Returns the restless experiments data processor.
Notes:
Sub-classes can override this method if they need more complex data processing.
"""
outcome = self.analysis.options.get("outcome", "1" * self._num_qubits)
meas_return = self.analysis.options.get("meas_return", MeasReturnType.SINGLE)
normalize = self.analysis.options.get("normalization", True)
dimensionality_reduction = self.analysis.options.get(
"dimensionality_reduction", ProjectorType.SVD
)
if meas_level == MeasLevel.KERNELED:
return get_kerneled_processor(
dimensionality_reduction, meas_return, normalize, [nodes.RestlessToIQ()]
)
else:
return DataProcessor(
"memory",
[
nodes.RestlessToCounts(self._num_qubits),
nodes.Probability(outcome),
],
)
def _t1_check(self, rep_delay: float) -> bool:
"""Check that repetition delay < T1 of the physical qubits in the experiment.
Args:
rep_delay: The repetition delay. This is the delay between a measurement
and the subsequent quantum circuit.
Returns:
True if the repetition delay is smaller than the qubit T1 times.
Raises:
DataProcessorError: If the T1 values are not defined for the qubits of
the used backend.
"""
try:
t1_values = [
self._backend_data.qubit_t1(physical_qubit)
for physical_qubit in self._physical_qubits
]
if all(rep_delay / t1_value < 1.0 for t1_value in t1_values):
return True
except AttributeError as error:
raise DataProcessorError(
"The restless experiment can not be enabled since "
"T1 values are not defined for the qubits of the used backend."
) from error
return False