Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,12 +424,11 @@ release notes.

#### Adding deprecation warnings

We use the deprecation wrappers in [Qiskit
Utilities](https://docs.quantum.ibm.com/api/qiskit/utils) to add warnings:
We use deprecation wrappers in `qiskit_experiments.framework.deprecation` to add warnings:

```python

from qiskit.utils.deprecation import deprecate_func
from qiskit_experiments.framework.deprecation import deprecate_func

@deprecate_func(
since="0.5",
Expand Down
8 changes: 8 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,12 @@ def setup(app):
# Should come up with better way to address this

from qiskit_experiments.curve_analysis import ParameterRepr
from qiskit_experiments.framework import MeasLevel, MeasReturnType


def maybe_skip_member(app, what, name, obj, skip, options):
if skip:
return True
skip_names = [
"analysis",
"set_run_options",
Expand All @@ -234,6 +237,11 @@ def maybe_skip_member(app, what, name, obj, skip, options):
ParameterRepr.repr,
ParameterRepr.unit,
]
if (
not name.isupper() and
(getattr(MeasLevel, name, None) == obj or getattr(MeasReturnType, name, None) == obj)
):
return True
if not skip:
return (name in skip_names or obj in skip_members) and what == "attribute"
return skip
3 changes: 1 addition & 2 deletions docs/manuals/characterization/t1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ for qubit 0.
.. jupyter-execute::

import numpy as np
from qiskit.qobj.utils import MeasLevel
from qiskit_experiments.framework import ParallelExperiment
from qiskit_experiments.framework import MeasLevel, ParallelExperiment
from qiskit_experiments.library import T1
from qiskit_experiments.library.characterization.analysis.t1_analysis import T1KerneledAnalysis

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/custom_experiment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ perfect symmetrical results between :math:`|0000\rangle` and :math:`|1111\rangle

.. jupyter-execute::

expdata_ideal = exp.run(AerSimulator(), shots=shots)
expdata_ideal = exp.run(backend_ideal, shots=shots)
counts_ideal = expdata_ideal.analysis_results("counts").value
print(counts_ideal)

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ supports can be set:

.. jupyter-execute::

from qiskit.qobj.utils import MeasLevel
from qiskit_experiments.framework import MeasLevel

exp.set_run_options(shots=1000,
meas_level=MeasLevel.CLASSIFIED)
Expand Down
2 changes: 1 addition & 1 deletion qiskit_experiments/curve_analysis/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
import lmfit
import numpy as np
import pandas as pd
from qiskit.utils.deprecation import deprecate_func
from qiskit.utils import detach_prefix
from uncertainties import UFloat, wrap as wrap_function
from uncertainties import unumpy

from qiskit_experiments.curve_analysis.curve_data import CurveFitResult
from qiskit_experiments.exceptions import AnalysisError, QiskitError
from qiskit_experiments.framework import AnalysisResultData
from qiskit_experiments.framework.deprecation import deprecate_func


UNUMPY_FUNCS = {fn: getattr(unumpy, fn) for fn in unumpy.__all__}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@


import math
import warnings
from typing import Optional, List, Tuple, Iterable, Callable, Union, Dict
import numpy as np

Expand Down Expand Up @@ -53,6 +54,8 @@ def __init__(
Raises:
QiskitError: matrices sizes do not agree with number of qubits
"""
if assignment_matrices is None and backend is None:
raise QiskitError("Either assignment_matrices or backend must be provided.")
if assignment_matrices is None:
assignment_matrices = self._from_backend(backend, qubits)
else:
Expand Down Expand Up @@ -293,7 +296,14 @@ def stddev_upper_bound(self, shots: int, qubits: List[int] = None):

def _from_backend(self, backend, qubits):
"""Calculates amats from backend properties readout_error"""
backend_qubits = backend.properties().qubits
try:
backend_qubits = backend.properties().qubits
except AttributeError as exc:
raise QiskitError(
"Either assignment_matrices must be passed or a backend "
"supporting backend.properties().qubits"
) from exc

if qubits is not None:
if any(qubit >= len(backend_qubits) for qubit in qubits):
raise QiskitError("The chosen backend does not contain the specified qubits.")
Expand All @@ -304,13 +314,20 @@ def _from_backend(self, backend, qubits):
amats = np.zeros([num_qubits, 2, 2], dtype=float)

for qubit_idx, qubit_prop in enumerate(backend_qubits):
props_to_find = {"prob_meas0_prep1", "prob_meas1_prep0"}
for prop in qubit_prop:
if prop.name == "prob_meas0_prep1":
props_to_find.discard(prop.name)
(amats[qubit_idx])[0, 1] = prop.value
(amats[qubit_idx])[1, 1] = 1 - prop.value
if prop.name == "prob_meas1_prep0":
props_to_find.discard(prop.name)
(amats[qubit_idx])[1, 0] = prop.value
(amats[qubit_idx])[0, 0] = 1 - prop.value
if props_to_find:
warnings.warn(
f"Expected readout error properties were missing: {','.join(props_to_find)}"
)

return amats

Expand Down
3 changes: 2 additions & 1 deletion qiskit_experiments/data_processing/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from uncertainties import unumpy as unp, ufloat

from qiskit.result.postprocess import format_counts_memory
from qiskit.utils import deprecate_func
from qiskit_experiments.framework.deprecation import deprecate_func
from qiskit_experiments.data_processing.data_action import DataAction, TrainableDataAction
from qiskit_experiments.data_processing.exceptions import DataProcessorError
from qiskit_experiments.data_processing.discriminator import BaseDiscriminator
Expand Down Expand Up @@ -921,6 +921,7 @@ class RestlessNode(DataAction, ABC):
"processor on an experiment."
),
package_name="qiskit-experiments",
stacklevel=3,
)
def __init__(
self, validate: bool = True, memory_allocation: ShotOrder = ShotOrder.circuit_first
Expand Down
3 changes: 1 addition & 2 deletions qiskit_experiments/data_processing/processor_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@

import warnings
from typing import Union, Optional, List
from qiskit.qobj.utils import MeasLevel, MeasReturnType

from qiskit_experiments.framework import ExperimentData, Options
from qiskit_experiments.framework import ExperimentData, MeasLevel, MeasReturnType, Options
from qiskit_experiments.data_processing.exceptions import DataProcessorError
from qiskit_experiments.data_processing.data_action import DataAction
from qiskit_experiments.data_processing.data_processor import DataProcessor
Expand Down
14 changes: 13 additions & 1 deletion qiskit_experiments/framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@
Job
BaseJob
ExtendedJob
MeasLevel
MeasReturnType

.. _composite-experiment:

Expand Down Expand Up @@ -145,6 +147,17 @@
FigureData,
FigureType,
)
from .provider_interfaces import (
BaseJob,
BaseProvider,
ExtendedJob,
IBMProvider,
Job,
MeasLevel,
MeasReturnType,
Provider,
)

from .base_analysis import BaseAnalysis
from .base_experiment import BaseExperiment
from .backend_timing import BackendTiming
Expand All @@ -159,4 +172,3 @@
CompositeAnalysis,
)
from .json import ExperimentEncoder, ExperimentDecoder
from .provider_interfaces import BaseJob, BaseProvider, ExtendedJob, IBMProvider, Job, Provider
56 changes: 37 additions & 19 deletions qiskit_experiments/framework/backend_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,19 @@
"""
Backend data access helper class

Since `BackendV1` and `BackendV2` do not share the same interface, this
class unifies data access for various data fields.
This class was introduced to unify backend data access to either `BackendV1` and `BackendV2`
objects, wrapped by an object of this class. With the removal of `BackendV1` in Qiskit 2.0,
this class will not serve any useful purpose once support for Qiskit 1 is dropped.

TODO: remove this class
"""
import os
import sys
import warnings
from qiskit.providers.models import PulseBackendConfiguration # pylint: disable=no-name-in-module
from qiskit.providers import BackendV1, BackendV2

from qiskit.providers import BackendV2

import qiskit_experiments


class BackendData:
Expand All @@ -27,22 +34,33 @@ def __init__(self, backend):
"""Inits the backend and verifies version"""

self._backend = backend
self._v1 = isinstance(backend, BackendV1)
self._v1 = False
self._v2 = isinstance(backend, BackendV2)

if self._v2:
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore", message=".*qiskit.qobj.pulse_qobj.*", category=DeprecationWarning
)
self._parse_additional_data()

def _parse_additional_data(self):
# data specific parsing not done yet in upstream qiskit
if hasattr(self._backend, "_conf_dict") and self._backend._conf_dict["open_pulse"]:
if "u_channel_lo" not in self._backend._conf_dict:
self._backend._conf_dict["u_channel_lo"] = [] # to avoid qiskit bug
self._pulse_conf = PulseBackendConfiguration.from_dict(self._backend._conf_dict)
if not self._v2:
try:
from qiskit.providers import BackendV1

self._v1 = isinstance(backend, BackendV1)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should at least add deprecation warning in here. I prefer completely removing BackendV1 usage because we cannot guarantee the rest of our software properly works with this backend.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The release note had a line about support for BackendV1 being removed in a future release, but I added an explicit deprecations entry about it as well. Also, I added a deprecation warning here. It is hard to do because this code gets called at varying levels of the stack and Python by default only shows deprecation warnings if the stack level is right. Python 3.12 added a cool skip_file_prefixes option so I used that and it seemed to work well on 3.12+ -- it showed my user level code as responsible for the warning whether I created BackendData directly or created a T1 experiment that creates BackendData four levels lower down in the stack. Users on <=3.11 might not see the warning depending on how they are using BackendV1.

My thought was that we are not planning much change to the repo in the near term and it was easy enough to hide the import here. Qiskit 1 will go out of support in six months and we don't need to support unsupported Qiskit versions, I think. I specified this in the deprecation note.


if self._v1:
if sys.version_info[:2] >= (3, 12):
kwargs = {
"skip_file_prefixes": (os.path.dirname(qiskit_experiments.__file__),)
}
else:
kwargs = {}
warnings.warn(
(
"Support for BackendV1 with Qiskit Experiments is "
"deprecated and will be removed in a future release. "
"Please update to using BackendV2 backends."
),
DeprecationWarning,
stacklevel=2,
**kwargs,
)
except ImportError:
pass

@property
def name(self):
Expand Down
3 changes: 1 addition & 2 deletions qiskit_experiments/framework/base_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@
from qiskit import transpile, QuantumCircuit
from qiskit.providers import Job, Backend
from qiskit.exceptions import QiskitError
from qiskit.qobj.utils import MeasLevel
from qiskit.providers.options import Options
from qiskit.primitives.base import BaseSamplerV2
from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit_experiments.framework import BackendData
from qiskit_experiments.framework import BackendData, MeasLevel
from qiskit_experiments.framework.store_init_args import StoreInitArgs
from qiskit_experiments.framework.base_analysis import BaseAnalysis
from qiskit_experiments.framework.experiment_data import ExperimentData
Expand Down
Loading