Skip to content

Commit

Permalink
Remove deprecated features in 0.46 in primitives (#11576)
Browse files Browse the repository at this point in the history
* Deprecate BasePrimitiveResult (#11054)

Deprecates the unnecessary base class BasePrimitiveResult so we can have a clean break in defining new ones in Qiskit 1.0. Also deprecates the common utility methods `decompose`, `experiments`, and `num_experimetns` this base class adds to SamplerResult and EstimatorResult.

Add jakes suggestion

* Remove deprecated features in 0.46 in Primitives

* lint

* lint

---------

Co-authored-by: Christopher J. Wood <cjwood@us.ibm.com>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
  • Loading branch information
3 people authored Feb 1, 2024
1 parent 9e4ecb9 commit 6141d74
Show file tree
Hide file tree
Showing 11 changed files with 23 additions and 302 deletions.
69 changes: 0 additions & 69 deletions qiskit/primitives/base/base_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,21 +150,17 @@

from __future__ import annotations

import warnings
from abc import abstractmethod, ABC
from collections.abc import Iterable, Sequence
from copy import copy
from typing import Generic, TypeVar

import numpy as np
from numpy.typing import NDArray

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.parametertable import ParameterView
from qiskit.providers import JobV1 as Job
from qiskit.quantum_info.operators import SparsePauliOp
from qiskit.quantum_info.operators.base_operator import BaseOperator
from qiskit.utils.deprecation import deprecate_func

from ..containers import (
make_data_bin,
Expand Down Expand Up @@ -203,27 +199,6 @@ def __init__(
"""
super().__init__(options)

def __getattr__(self, name: str) -> any:
# Work around to enable deprecation of the init attributes in BaseEstimator incase
# existing subclasses depend on them (which some do)
dep_defaults = {
"_circuits": [],
"_observables": [],
"_parameters": [],
}
if name not in dep_defaults:
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")

warnings.warn(
f"The init attribute `{name}` in BaseEstimator is deprecated as of Qiskit 0.46."
" To continue to use this attribute in a subclass and avoid this warning the"
" subclass should initialize it itself.",
DeprecationWarning,
stacklevel=2,
)
setattr(self, name, dep_defaults[name])
return getattr(self, name)

def run(
self,
circuits: Sequence[QuantumCircuit] | QuantumCircuit,
Expand Down Expand Up @@ -293,50 +268,6 @@ def _run(
) -> T:
raise NotImplementedError("The subclass of BaseEstimator must implement `_run` method.")

@staticmethod
@deprecate_func(since="0.46.0")
def _validate_observables(
observables: Sequence[BaseOperator | str] | BaseOperator | str,
) -> tuple[SparsePauliOp, ...]:
return validation._validate_observables(observables)

@staticmethod
@deprecate_func(since="0.46.0")
def _cross_validate_circuits_observables(
circuits: tuple[QuantumCircuit, ...], observables: tuple[BaseOperator, ...]
) -> None:
return validation._cross_validate_circuits_observables(circuits, observables)

@property
@deprecate_func(since="0.46.0", is_property=True)
def circuits(self) -> tuple[QuantumCircuit, ...]:
"""Quantum circuits that represents quantum states.
Returns:
The quantum circuits.
"""
return tuple(self._circuits)

@property
@deprecate_func(since="0.46.0", is_property=True)
def observables(self) -> tuple[SparsePauliOp, ...]:
"""Observables to be estimated.
Returns:
The observables.
"""
return tuple(self._observables)

@property
@deprecate_func(since="0.46.0", is_property=True)
def parameters(self) -> tuple[ParameterView, ...]:
"""Parameters of the quantum circuits.
Returns:
Parameters, where ``parameters[i][j]`` is the j-th parameter of the i-th circuit.
"""
return tuple(self._parameters)


BaseEstimator = BaseEstimatorV1

Expand Down
29 changes: 0 additions & 29 deletions qiskit/primitives/base/base_primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,8 @@
from __future__ import annotations

from abc import ABC
from collections.abc import Sequence

from qiskit.circuit import QuantumCircuit
from qiskit.providers import Options
from qiskit.utils.deprecation import deprecate_func

from . import validation


class BasePrimitive(ABC):
Expand All @@ -48,27 +43,3 @@ def set_options(self, **fields):
**fields: The fields to update the options
"""
self._run_options.update_options(**fields)

@staticmethod
@deprecate_func(since="0.46.0")
def _validate_circuits(
circuits: Sequence[QuantumCircuit] | QuantumCircuit,
) -> tuple[QuantumCircuit, ...]:
return validation._validate_circuits(circuits)

@staticmethod
@deprecate_func(since="0.46.0")
def _validate_parameter_values(
parameter_values: Sequence[Sequence[float]] | Sequence[float] | float | None,
default: Sequence[Sequence[float]] | Sequence[float] | None = None,
) -> tuple[tuple[float, ...], ...]:
return validation._validate_parameter_values(parameter_values, default=default)

@staticmethod
@deprecate_func(since="0.46.0")
def _cross_validate_circuits_parameter_values(
circuits: tuple[QuantumCircuit, ...], parameter_values: tuple[tuple[float, ...], ...]
) -> None:
return validation._cross_validate_circuits_parameter_values(
circuits, parameter_values=parameter_values
)
4 changes: 2 additions & 2 deletions qiskit/primitives/base/base_primitive_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
from typing import Generic, TypeVar, Union

from ..containers import PrimitiveResult
from .base_result import BasePrimitiveResult
from .base_result import _BasePrimitiveResult

ResultT = TypeVar("ResultT", bound=Union[BasePrimitiveResult, PrimitiveResult])
ResultT = TypeVar("ResultT", bound=Union[_BasePrimitiveResult, PrimitiveResult])
StatusT = TypeVar("StatusT")


Expand Down
42 changes: 10 additions & 32 deletions qiskit/primitives/base/base_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,18 @@
from __future__ import annotations

from abc import ABC
from collections.abc import Iterator, Sequence
from collections.abc import Sequence
from dataclasses import fields
from typing import Any, Dict

from numpy import ndarray


ExperimentData = Dict[str, Any]


class BasePrimitiveResult(ABC):
"""Primitive result abstract base class.
Base class for Primitive results meant to provide common functionality to all inheriting
result dataclasses.
class _BasePrimitiveResult(ABC):
"""
Base class for deprecated Primitive result methods.
"""

def __post_init__(self) -> None:
Expand All @@ -45,43 +42,24 @@ def __post_init__(self) -> None:
TypeError: If one of the data fields is not a Sequence or ``numpy.ndarray``.
ValueError: Inconsistent number of experiments across data fields.
"""
num_experiments = None
for value in self._field_values: # type: Sequence
if num_experiments is None:
num_experiments = len(value)
# TODO: enforce all data fields to be tuples instead of sequences
if not isinstance(value, (Sequence, ndarray)) or isinstance(value, (str, bytes)):
raise TypeError(
f"Expected sequence or `numpy.ndarray`, provided {type(value)} instead."
)
if len(value) != self.num_experiments:
if len(value) != num_experiments:
raise ValueError("Inconsistent number of experiments across data fields.")

@property # TODO: functools.cached_property when py37 is droppped
def num_experiments(self) -> int:
"""Number of experiments in any inheriting result dataclass."""
value: Sequence = self._field_values[0]
return len(value)

@property # TODO: functools.cached_property when py37 is droppped
def experiments(self) -> tuple[ExperimentData, ...]:
"""Experiment data dicts in any inheriting result dataclass."""
return tuple(self._generate_experiments())

def _generate_experiments(self) -> Iterator[ExperimentData]:
"""Generate experiment data dicts in any inheriting result dataclass."""
names: tuple[str, ...] = self._field_names
for values in zip(*self._field_values):
yield dict(zip(names, values))

def decompose(self) -> Iterator[BasePrimitiveResult]:
"""Generate single experiment result objects from self."""
for values in zip(*self._field_values):
yield self.__class__(*[(v,) for v in values])

@property # TODO: functools.cached_property when py37 is droppped
@property # TODO: functools.cached_property when py37 is dropped
def _field_names(self) -> tuple[str, ...]:
"""Tuple of field names in any inheriting result dataclass."""
return tuple(field.name for field in fields(self))

@property # TODO: functools.cached_property when py37 is droppped
@property # TODO: functools.cached_property when py37 is dropped
def _field_values(self) -> tuple:
"""Tuple of field values in any inheriting result dataclass."""
return tuple(getattr(self, name) for name in self._field_names)
53 changes: 1 addition & 52 deletions qiskit/primitives/base/base_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,13 @@

from __future__ import annotations

import warnings
from abc import abstractmethod, ABC
from abc import ABC, abstractmethod
from collections.abc import Iterable, Sequence
from copy import copy
from typing import Generic, TypeVar

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.parametertable import ParameterView
from qiskit.providers import JobV1 as Job
from qiskit.utils.deprecation import deprecate_func

from ..containers.primitive_result import PrimitiveResult
from ..containers.pub_result import PubResult
Expand Down Expand Up @@ -173,26 +170,6 @@ def __init__(
"""
super().__init__(options)

def __getattr__(self, name: str) -> any:
# Work around to enable deprecation of the init attributes in BaseSampler incase
# existing subclasses depend on them (which some do)
dep_defaults = {
"_circuits": [],
"_parameters": [],
}
if name not in dep_defaults:
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")

warnings.warn(
f"The init attribute `{name}` in BaseSampler is deprecated as of Qiskit 0.46."
" To continue to use this attribute in a subclass and avoid this warning the"
" subclass should initialize it itself.",
DeprecationWarning,
stacklevel=2,
)
setattr(self, name, dep_defaults[name])
return getattr(self, name)

def run(
self,
circuits: QuantumCircuit | Sequence[QuantumCircuit],
Expand Down Expand Up @@ -235,34 +212,6 @@ def _run(
) -> T:
raise NotImplementedError("The subclass of BaseSampler must implement `_run` method.")

@classmethod
@deprecate_func(since="0.46.0")
def _validate_circuits(
cls,
circuits: Sequence[QuantumCircuit] | QuantumCircuit,
) -> tuple[QuantumCircuit, ...]:
return validation._validate_circuits(circuits, requires_measure=True)

@property
@deprecate_func(since="0.46.0", is_property=True)
def circuits(self) -> tuple[QuantumCircuit, ...]:
"""Quantum circuits to be sampled.
Returns:
The quantum circuits to be sampled.
"""
return tuple(self._circuits)

@property
@deprecate_func(since="0.46.0", is_property=True)
def parameters(self) -> tuple[ParameterView, ...]:
"""Parameters of quantum circuits.
Returns:
List of the parameters in each quantum circuit.
"""
return tuple(self._parameters)


BaseSampler = BaseSamplerV1

Expand Down
4 changes: 2 additions & 2 deletions qiskit/primitives/base/estimator_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any

from .base_result import BasePrimitiveResult
from .base_result import _BasePrimitiveResult

if TYPE_CHECKING:
import numpy as np


@dataclass(frozen=True)
class EstimatorResult(BasePrimitiveResult):
class EstimatorResult(_BasePrimitiveResult):
"""Result of Estimator.
.. code-block:: python
Expand Down
4 changes: 2 additions & 2 deletions qiskit/primitives/base/sampler_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@

from qiskit.result import QuasiDistribution

from .base_result import BasePrimitiveResult
from .base_result import _BasePrimitiveResult


@dataclass(frozen=True)
class SamplerResult(BasePrimitiveResult):
class SamplerResult(_BasePrimitiveResult):
"""Result of Sampler.
.. code-block:: python
Expand Down
Loading

0 comments on commit 6141d74

Please sign in to comment.