Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove deprecated features in 0.46 in primitives #11576

Merged
merged 10 commits into from
Feb 1, 2024
68 changes: 0 additions & 68 deletions qiskit/primitives/base/base_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,17 +150,14 @@

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
Expand Down Expand Up @@ -203,27 +200,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 +269,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
Copy link
Contributor

Choose a reason for hiding this comment

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

In case someone stumbles over this (like I did): these are removed w/o deprecation warning since the deprecation PR went into stable/0.46 directly -- as is the change from BasePrimitiveResult to _BasePrimitiveResult.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, introduced by #11054

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)
22 changes: 0 additions & 22 deletions qiskit/primitives/base/base_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,12 @@

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

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

Expand Down Expand Up @@ -173,26 +171,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
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
54 changes: 1 addition & 53 deletions qiskit/primitives/primitive_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,11 @@
Job implementation for the reference implementations of Primitives.
"""

import time
import uuid
from concurrent.futures import ThreadPoolExecutor
from typing import Callable, Optional

from qiskit.providers import JobError, JobStatus, JobTimeoutError
from qiskit.providers import JobError, JobStatus
from qiskit.providers.jobstatus import JOB_FINAL_STATES
from qiskit.utils.deprecation import deprecate_func

from .base.base_primitive_job import BasePrimitiveJob, ResultT

Expand Down Expand Up @@ -82,52 +79,3 @@ def cancelled(self) -> bool:

def in_final_state(self) -> bool:
return self.status() in JOB_FINAL_STATES

@deprecate_func(since="0.46.0")
def submit(self):
"""Submit a job.

.. deprecated:: 0.46.0
``submit`` method is deprecated as of Qiskit 0.46 and will be removed
no earlier than 3 months after the release date.

"""
self._submit()

@deprecate_func(since="0.46.0")
def wait_for_final_state(
self, timeout: Optional[float] = None, wait: float = 5, callback: Optional[Callable] = None
) -> None:
"""Poll the job status until it progresses to a final state such as ``DONE`` or ``ERROR``.

.. deprecated:: 0.46.0
``wait_for_final_state`` method is deprecated as of Qiskit 0.46 and will be removed
no earlier than 3 months after the release date.

Args:
timeout: Seconds to wait for the job. If ``None``, wait indefinitely.
wait: Seconds between queries.
callback: Callback function invoked after each query.
The following positional arguments are provided to the callback function:

* job_id: Job ID
* job_status: Status of the job from the last query
* job: This BaseJob instance

Note: different subclass might provide different arguments to
the callback function.

Raises:
JobTimeoutError: If the job does not reach a final state before the
specified timeout.
"""
start_time = time.time()
status = self.status()
while status not in JOB_FINAL_STATES:
elapsed_time = time.time() - start_time
if timeout is not None and elapsed_time >= timeout:
raise JobTimeoutError(f"Timeout while waiting for job {self.job_id()}.")
if callback:
callback(self.job_id(), status, self)
time.sleep(wait)
status = self.status()
4 changes: 2 additions & 2 deletions qiskit/primitives/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from qiskit.circuit import Instruction, QuantumCircuit
from qiskit.circuit.bit import Bit
from qiskit.circuit.library.data_preparation import Initialize
from qiskit.quantum_info import SparsePauliOp, Statevector, PauliList
from qiskit.quantum_info import SparsePauliOp, Statevector
from qiskit.quantum_info.operators.base_operator import BaseOperator
from qiskit.quantum_info.operators.symplectic.base_pauli import BasePauli
from qiskit.exceptions import QiskitError
Expand Down Expand Up @@ -61,7 +61,7 @@ def init_observable(observable: BaseOperator | str) -> SparsePauliOp:
if isinstance(observable, SparsePauliOp):
return observable
elif isinstance(observable, BaseOperator) and not isinstance(observable, BasePauli):
return SparsePauliOp.from_operator(observable)
raise QiskitError(f"observable type not supported: {type(observable)}")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was directly introduced into 0.46: #11535

else:
if isinstance(observable, PauliList):
raise QiskitError(f"observable type not supported: {type(observable)}")
Expand Down
Loading
Loading