Add better error messages for typical SamplerV2 and EstimatorV2 error cases (#12031)

* add an early error for a case

* Update qiskit/primitives/containers/sampler_pub.py

Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com>

* add better message for estimator pub

* Update qiskit/primitives/containers/estimator_pub.py

Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com>

* add an additional message

---------

Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com>
This commit is contained in:
Takashi Imamichi 2024-03-19 19:28:45 +04:00 committed by GitHub
parent c26e25cddb
commit 194cc8fb9a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 63 additions and 17 deletions

View File

@ -132,6 +132,15 @@ class EstimatorPub(ShapedMixin):
validate=False, # Assume Pub is already validated
)
return pub
if isinstance(pub, QuantumCircuit):
raise ValueError(
f"An invalid Estimator pub-like was given ({type(pub)}). "
"If you want to run a single pub, you need to wrap it with `[]` like "
"`estimator.run([(circuit, observables, param_values)])` "
"instead of `estimator.run((circuit, observables, param_values))`."
)
if len(pub) not in [2, 3, 4]:
raise ValueError(
f"The length of pub must be 2, 3 or 4, but length {len(pub)} is given."
@ -208,8 +217,6 @@ estimator, if ``precision=None`` the estimator will determine the target precisi
An Estimator Pub can also be initialized in the following formats which
will be converted to the full Pub tuple:
* ``circuit
* ``(circuit,)``
* ``(circuit, observables)``
* ``(circuit, observalbes, parameter_values)``
* ``(circuit, observables, parameter_values)``
"""

View File

@ -18,10 +18,11 @@ Sampler Pub class
from __future__ import annotations
from collections.abc import Mapping
from typing import Tuple, Union
from numbers import Integral
from typing import Tuple, Union
from qiskit import QuantumCircuit
from qiskit.circuit import CircuitInstruction
from .bindings_array import BindingsArray, BindingsArrayLike
from .shape import ShapedMixin
@ -113,6 +114,14 @@ class SamplerPub(ShapedMixin):
if isinstance(pub, QuantumCircuit):
return cls(circuit=pub, shots=shots, validate=True)
if isinstance(pub, CircuitInstruction):
raise ValueError(
f"An invalid Sampler pub-like was given ({type(pub)}). "
"If you want to run a single circuit, "
"you need to wrap it with `[]` like `sampler.run([circuit])` "
"instead of `sampler.run(circuit)`."
)
if len(pub) not in [1, 2, 3]:
raise ValueError(
f"The length of pub must be 1, 2 or 3, but length {len(pub)} is given."
@ -147,10 +156,17 @@ class SamplerPub(ShapedMixin):
# Cross validate circuits and parameter values
num_parameters = self.parameter_values.num_parameters
if num_parameters != self.circuit.num_parameters:
raise ValueError(
message = (
f"The number of values ({num_parameters}) does not match "
f"the number of parameters ({self.circuit.num_parameters}) for the circuit."
)
if num_parameters == 0:
message += (
" Note that if you want to run a single pub, you need to wrap it with `[]` like "
"`sampler.run([(circuit, param_values)])` instead of "
"`sampler.run((circuit, param_values))`."
)
raise ValueError(message)
SamplerPubLike = Union[
@ -171,7 +187,7 @@ if ``shots=None`` the number of run shots is determined by the sampler.
A Sampler Pub can also be initialized in the following formats which
will be converted to the full Pub tuple:
* ``circuit
* ``circuit``
* ``(circuit,)``
* ``(circuit, parameter_values)``
"""

View File

@ -56,6 +56,7 @@ class TestBackendEstimator(QiskitTestCase):
def setUp(self):
super().setUp()
self._rng = np.random.default_rng(12)
self.ansatz = RealAmplitudes(num_qubits=2, reps=2)
self.observable = SparsePauliOp.from_list(
[
@ -222,7 +223,7 @@ class TestBackendEstimator(QiskitTestCase):
qc = RealAmplitudes(num_qubits=2, reps=2)
op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)])
k = 5
params_array = np.random.rand(k, qc.num_parameters)
params_array = self._rng.random((k, qc.num_parameters))
params_list = params_array.tolist()
params_list_array = list(params_array)
estimator = BackendEstimator(backend=backend)
@ -288,7 +289,7 @@ class TestBackendEstimator(QiskitTestCase):
qc = RealAmplitudes(num_qubits=2, reps=2)
op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)])
k = 5
params_array = np.random.rand(k, qc.num_parameters)
params_array = self._rng.random((k, qc.num_parameters))
params_list = params_array.tolist()
estimator = BackendEstimator(backend=backend)
with patch.object(backend, "run") as run_mock:
@ -304,7 +305,7 @@ class TestBackendEstimator(QiskitTestCase):
qc = RealAmplitudes(num_qubits=2, reps=2)
op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)])
k = 5
params_array = np.random.rand(k, qc.num_parameters)
params_array = self._rng.random((k, qc.num_parameters))
params_list = params_array.tolist()
estimator = BackendEstimator(backend=backend)
estimator.set_options(seed_simulator=123)
@ -321,7 +322,7 @@ class TestBackendEstimator(QiskitTestCase):
qc = RealAmplitudes(num_qubits=2, reps=2)
op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)])
k = 5
params_array = np.random.rand(k, qc.num_parameters)
params_array = self._rng.random((k, qc.num_parameters))
params_list = params_array.tolist()
params_list_array = list(params_array)
estimator = BackendEstimator(backend=backend)

View File

@ -45,6 +45,7 @@ class TestBackendEstimatorV2(QiskitTestCase):
self._precision = 5e-3
self._rtol = 3e-1
self._seed = 12
self._rng = np.random.default_rng(self._seed)
self._options = {"default_precision": self._precision, "seed_simulator": self._seed}
self.ansatz = RealAmplitudes(num_qubits=2, reps=2)
self.observable = SparsePauliOp.from_list(
@ -316,6 +317,9 @@ class TestBackendEstimatorV2(QiskitTestCase):
est.run([(qc, op, None, -1)]).result()
with self.assertRaises(ValueError):
est.run([(qc, op)], precision=-1).result()
with self.subTest("missing []"):
with self.assertRaisesRegex(ValueError, "An invalid Estimator pub-like was given"):
_ = est.run((qc, op)).result()
@combine(backend=BACKENDS, abelian_grouping=[True, False])
def test_run_numpy_params(self, backend, abelian_grouping):
@ -326,7 +330,7 @@ class TestBackendEstimatorV2(QiskitTestCase):
op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)])
op = op.apply_layout(qc.layout)
k = 5
params_array = np.random.rand(k, qc.num_parameters)
params_array = self._rng.random((k, qc.num_parameters))
params_list = params_array.tolist()
params_list_array = list(params_array)
statevector_estimator = StatevectorEstimator(seed=123)
@ -380,8 +384,7 @@ class TestBackendEstimatorV2(QiskitTestCase):
qc = pm.run(qc)
op = [SparsePauliOp("IX"), SparsePauliOp("YI")]
shape = (3, 2)
rng = np.random.default_rng(seed)
params_array = rng.random(shape + (qc.num_parameters,))
params_array = self._rng.random(shape + (qc.num_parameters,))
params_list = params_array.tolist()
params_list_array = list(params_array)
statevector_estimator = StatevectorEstimator(seed=seed)

View File

@ -259,7 +259,8 @@ class TestBackendSampler(QiskitTestCase):
qc = RealAmplitudes(num_qubits=2, reps=2)
qc.measure_all()
k = 5
params_array = np.random.rand(k, qc.num_parameters)
rng = np.random.default_rng(12)
params_array = rng.random((k, qc.num_parameters))
params_list = params_array.tolist()
params_list_array = list(params_array)
sampler = BackendSampler(backend=backend)

View File

@ -351,6 +351,12 @@ class TestBackendSamplerV2(QiskitTestCase):
with self.subTest("zero shots, pub"):
with self.assertRaises(ValueError):
_ = sampler.run([SamplerPub(qc1, shots=0)]).result()
with self.subTest("missing []"):
with self.assertRaisesRegex(ValueError, "An invalid Sampler pub-like was given"):
_ = sampler.run(qc1).result()
with self.subTest("missing [] for pqc"):
with self.assertRaisesRegex(ValueError, "Note that if you want to run a single pub,"):
_ = sampler.run((qc2, [0, 1])).result()
@combine(backend=BACKENDS)
def test_run_empty_parameter(self, backend):

View File

@ -237,7 +237,8 @@ class TestEstimator(QiskitTestCase):
qc = RealAmplitudes(num_qubits=2, reps=2)
op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)])
k = 5
params_array = np.random.rand(k, qc.num_parameters)
rng = np.random.default_rng(12)
params_array = rng.random((k, qc.num_parameters))
params_list = params_array.tolist()
params_list_array = list(params_array)
estimator = Estimator()

View File

@ -324,7 +324,8 @@ class TestSampler(QiskitTestCase):
qc = RealAmplitudes(num_qubits=2, reps=2)
qc.measure_all()
k = 5
params_array = np.random.rand(k, qc.num_parameters)
rng = np.random.default_rng(12)
params_array = rng.random((k, qc.num_parameters))
params_list = params_array.tolist()
params_list_array = list(params_array)
sampler = Sampler()

View File

@ -236,13 +236,17 @@ class TestStatevectorEstimator(QiskitTestCase):
est.run([(qc, op)], precision=-1).result()
with self.assertRaises(ValueError):
est.run([(qc, 1j * op)], precision=0.1).result()
with self.subTest("missing []"):
with self.assertRaisesRegex(ValueError, "An invalid Estimator pub-like was given"):
_ = est.run((qc, op)).result()
def test_run_numpy_params(self):
"""Test for numpy array as parameter values"""
qc = RealAmplitudes(num_qubits=2, reps=2)
op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)])
k = 5
params_array = np.random.rand(k, qc.num_parameters)
rng = np.random.default_rng(12)
params_array = rng.random((k, qc.num_parameters))
params_list = params_array.tolist()
params_list_array = list(params_array)
estimator = StatevectorEstimator()

View File

@ -320,6 +320,12 @@ class TestStatevectorSampler(QiskitTestCase):
with self.subTest("zero shots, pub"):
with self.assertRaises(ValueError):
_ = sampler.run([SamplerPub(qc1, shots=0)]).result()
with self.subTest("missing []"):
with self.assertRaisesRegex(ValueError, "An invalid Sampler pub-like was given"):
_ = sampler.run(qc1).result()
with self.subTest("missing [] for pqc"):
with self.assertRaisesRegex(ValueError, "Note that if you want to run a single pub,"):
_ = sampler.run((qc2, [0, 1])).result()
def test_run_empty_parameter(self):
"""Test for empty parameter"""