diff --git a/qiskit/primitives/base/base_estimator.py b/qiskit/primitives/base/base_estimator.py index 4750b0e2cec5..61d3faa7119c 100644 --- a/qiskit/primitives/base/base_estimator.py +++ b/qiskit/primitives/base/base_estimator.py @@ -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, @@ -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, @@ -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 diff --git a/qiskit/primitives/base/base_primitive.py b/qiskit/primitives/base/base_primitive.py index c161ca8094fa..4519f6eb24e3 100644 --- a/qiskit/primitives/base/base_primitive.py +++ b/qiskit/primitives/base/base_primitive.py @@ -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): @@ -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 - ) diff --git a/qiskit/primitives/base/base_primitive_job.py b/qiskit/primitives/base/base_primitive_job.py index b7d721c19031..64f9e73cb872 100644 --- a/qiskit/primitives/base/base_primitive_job.py +++ b/qiskit/primitives/base/base_primitive_job.py @@ -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") diff --git a/qiskit/primitives/base/base_result.py b/qiskit/primitives/base/base_result.py index 2c23ea1d7b59..b14c682a83f0 100644 --- a/qiskit/primitives/base/base_result.py +++ b/qiskit/primitives/base/base_result.py @@ -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: @@ -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) diff --git a/qiskit/primitives/base/base_sampler.py b/qiskit/primitives/base/base_sampler.py index ef495ac640c2..064907e9b5c3 100644 --- a/qiskit/primitives/base/base_sampler.py +++ b/qiskit/primitives/base/base_sampler.py @@ -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 @@ -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], @@ -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 diff --git a/qiskit/primitives/base/estimator_result.py b/qiskit/primitives/base/estimator_result.py index 9ac811fb6f17..88dbf1862d49 100644 --- a/qiskit/primitives/base/estimator_result.py +++ b/qiskit/primitives/base/estimator_result.py @@ -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 diff --git a/qiskit/primitives/base/sampler_result.py b/qiskit/primitives/base/sampler_result.py index 5dbb12d20898..4a472f0e2df9 100644 --- a/qiskit/primitives/base/sampler_result.py +++ b/qiskit/primitives/base/sampler_result.py @@ -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 diff --git a/qiskit/primitives/primitive_job.py b/qiskit/primitives/primitive_job.py index 0a3497b5d2bb..5dddda27d98b 100644 --- a/qiskit/primitives/primitive_job.py +++ b/qiskit/primitives/primitive_job.py @@ -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 @@ -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() diff --git a/qiskit/primitives/utils.py b/qiskit/primitives/utils.py index be4b932ec768..d94e3355d201 100644 --- a/qiskit/primitives/utils.py +++ b/qiskit/primitives/utils.py @@ -21,10 +21,10 @@ 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.exceptions import QiskitError +from qiskit.quantum_info import PauliList, 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 def init_circuit(state: QuantumCircuit | Statevector) -> QuantumCircuit: @@ -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)}") else: if isinstance(observable, PauliList): raise QiskitError(f"observable type not supported: {type(observable)}") diff --git a/test/python/primitives/test_estimator.py b/test/python/primitives/test_estimator.py index cfba5132aac4..e9a8516c2ab3 100644 --- a/test/python/primitives/test_estimator.py +++ b/test/python/primitives/test_estimator.py @@ -23,7 +23,7 @@ from qiskit.primitives import Estimator, EstimatorResult from qiskit.primitives.base import validation from qiskit.primitives.utils import _observable_key -from qiskit.quantum_info import Operator, Pauli, PauliList, SparsePauliOp +from qiskit.quantum_info import Pauli, SparsePauliOp from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -253,22 +253,6 @@ def test_run_numpy_params(self): self.assertEqual(len(result.metadata), k) np.testing.assert_allclose(result.values, target.values) - def test_run_with_operator(self): - """test for run with Operator as an observable""" - circuit = self.ansatz.assign_parameters([0, 1, 1, 2, 3, 5]) - matrix = Operator( - [ - [-1.06365335, 0.0, 0.0, 0.1809312], - [0.0, -1.83696799, 0.1809312, 0.0], - [0.0, 0.1809312, -0.24521829, 0.0], - [0.1809312, 0.0, 0.0, -1.06365335], - ] - ) - est = Estimator() - result = est.run([circuit], [matrix]).result() - self.assertIsInstance(result, EstimatorResult) - np.testing.assert_allclose(result.values, [-1.284366511861733]) - def test_run_with_shots_option(self): """test with shots option.""" est = Estimator() @@ -365,19 +349,6 @@ def test_validate_observables(self, obsevables, expected): """Test obsevables standardization.""" self.assertEqual(validation._validate_observables(obsevables), expected) - @data( - (PauliList("IXYZ"), (SparsePauliOp("IXYZ"),)), - ( - [PauliList("IXYZ"), PauliList("ZYXI")], - (SparsePauliOp("IXYZ"), SparsePauliOp("ZYXI")), - ), - ) - @unpack - def test_validate_observables_deprecated(self, obsevables, expected): - """Test obsevables standardization.""" - with self.assertRaises(QiskitError): - self.assertEqual(validation._validate_observables(obsevables), expected) - @data(None, "ERROR") def test_qiskit_error(self, observables): """Test qiskit error if invalid input.""" diff --git a/test/python/primitives/test_result.py b/test/python/primitives/test_result.py index 704b0fd4c2b4..15a9a8d3c781 100644 --- a/test/python/primitives/test_result.py +++ b/test/python/primitives/test_result.py @@ -19,7 +19,7 @@ from typing import Any from ddt import data, ddt, unpack -from qiskit.primitives.base.base_result import BasePrimitiveResult +from qiskit.primitives.base.base_result import _BasePrimitiveResult as BasePrimitiveResult from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -52,33 +52,6 @@ def test_post_init_value_error(self, field_1, field_2): """Tests post init value error.""" self.assertRaises(ValueError, Result, *(field_1, field_2)) - @data(0, 1, 2, 3) - def test_num_experiments(self, num_experiments): - """Tests {num_experiments} num_experiments.""" - result = Result([0] * num_experiments, [1] * num_experiments) - self.assertEqual(num_experiments, result.num_experiments) - - @data(0, 1, 2, 3) - def test_experiments(self, num_experiments): - """Test experiment data.""" - field_1 = list(range(num_experiments)) - field_2 = [i + 1 for i in range(num_experiments)] - experiments = Result(field_1, field_2).experiments - self.assertIsInstance(experiments, tuple) - for i, exp in enumerate(experiments): - self.assertEqual(exp, {"field_1": i, "field_2": i + 1}) - - @data(0, 1, 2, 3) - def test_decompose(self, num_experiments): - """Test decompose.""" - field_1 = list(range(num_experiments)) - field_2 = [i + 1 for i in range(num_experiments)] - result = Result(field_1, field_2) - for i, res in enumerate(result.decompose()): - self.assertIsInstance(res, Result) - f1, f2 = (i,), (i + 1,) - self.assertEqual(res, Result(f1, f2)) - def test_field_names(self): """Tests field names ("field_1", "field_2").""" result = Result([], [])