Skip to content

Commit

Permalink
Add better error messages for typical SamplerV2 and EstimatorV2 error…
Browse files Browse the repository at this point in the history
… 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>
  • Loading branch information
t-imamichi and ElePT committed Mar 19, 2024
1 parent c26e25c commit 194cc8f
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 17 deletions.
13 changes: 10 additions & 3 deletions qiskit/primitives/containers/estimator_pub.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@ def coerce(cls, pub: EstimatorPubLike, precision: float | None = None) -> Estima
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."
Expand Down Expand Up @@ -208,8 +217,6 @@ def validate(self):
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)``
"""
22 changes: 19 additions & 3 deletions qiskit/primitives/containers/sampler_pub.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
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
Expand Down Expand Up @@ -113,6 +114,14 @@ def coerce(cls, pub: SamplerPubLike, shots: int | None = None) -> SamplerPub:
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."
Expand Down Expand Up @@ -147,10 +156,17 @@ def validate(self):
# 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[
Expand All @@ -171,7 +187,7 @@ def validate(self):
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)``
"""
9 changes: 5 additions & 4 deletions test/python/primitives/test_backend_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
[
Expand Down Expand Up @@ -222,7 +223,7 @@ def test_run_numpy_params(self, backend):
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)
Expand Down Expand Up @@ -288,7 +289,7 @@ def max_circuits(self):
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:
Expand All @@ -304,7 +305,7 @@ def test_job_size_limit_v1(self):
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)
Expand All @@ -321,7 +322,7 @@ def test_no_max_circuits(self):
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)
Expand Down
9 changes: 6 additions & 3 deletions test/python/primitives/test_backend_estimator_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def setUp(self):
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(
Expand Down Expand Up @@ -316,6 +317,9 @@ def test_run_errors(self, backend, abelian_grouping):
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):
Expand All @@ -326,7 +330,7 @@ def test_run_numpy_params(self, backend, abelian_grouping):
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)
Expand Down Expand Up @@ -380,8 +384,7 @@ def test_aer(self, abelian_grouping):
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)
Expand Down
3 changes: 2 additions & 1 deletion test/python/primitives/test_backend_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ def test_run_numpy_params(self, backend):
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)
Expand Down
6 changes: 6 additions & 0 deletions test/python/primitives/test_backend_sampler_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,12 @@ def test_run_errors(self, backend):
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):
Expand Down
3 changes: 2 additions & 1 deletion test/python/primitives/test_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ def test_run_numpy_params(self):
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()
Expand Down
3 changes: 2 additions & 1 deletion test/python/primitives/test_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,8 @@ def test_run_numpy_params(self):
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()
Expand Down
6 changes: 5 additions & 1 deletion test/python/primitives/test_statevector_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,17 @@ def test_run_errors(self):
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()
Expand Down
6 changes: 6 additions & 0 deletions test/python/primitives/test_statevector_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,12 @@ def test_run_errors(self):
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"""
Expand Down

0 comments on commit 194cc8f

Please sign in to comment.