diff --git a/qiskit_ibm_runtime/estimator.py b/qiskit_ibm_runtime/estimator.py index f149ddfa1..ab4665631 100644 --- a/qiskit_ibm_runtime/estimator.py +++ b/qiskit_ibm_runtime/estimator.py @@ -153,7 +153,6 @@ def _validate_options(self, options: dict) -> None: """Validate that primitive inputs (options) are valid Raises: - ValidationError: if validation fails. ValueError: if validation fails. """ @@ -168,6 +167,13 @@ def _validate_options(self, options: dict) -> None: "a coupling map is required." ) + if isinstance(rep_delay := options.get("execution", {}).get("rep_delay"), (int, float)): + rep_delay_range = self._backend.configuration().rep_delay_range + if rep_delay < rep_delay_range[0] or rep_delay > rep_delay_range[1]: + raise ValueError( + f"rep_delay {rep_delay} is not in the backend rep_delay_range {rep_delay_range}" + ) + @classmethod def _program_id(cls) -> str: """Return the program ID.""" diff --git a/qiskit_ibm_runtime/sampler.py b/qiskit_ibm_runtime/sampler.py index 7963f558c..7928126da 100644 --- a/qiskit_ibm_runtime/sampler.py +++ b/qiskit_ibm_runtime/sampler.py @@ -114,10 +114,14 @@ def _validate_options(self, options: dict) -> None: """Validate that primitive inputs (options) are valid Raises: - ValidationError: if validation fails. + ValueError: if validation fails. """ - - pass + if isinstance(rep_delay := options.get("execution", {}).get("rep_delay"), (int, float)): + rep_delay_range = self._backend.configuration().rep_delay_range + if rep_delay < rep_delay_range[0] or rep_delay > rep_delay_range[1]: + raise ValueError( + f"rep_delay {rep_delay} is not in the backend rep_delay_range {rep_delay_range}" + ) @classmethod def _program_id(cls) -> str: diff --git a/release-notes/unreleased/2389.feat.rst b/release-notes/unreleased/2389.feat.rst new file mode 100644 index 000000000..b81a4c77f --- /dev/null +++ b/release-notes/unreleased/2389.feat.rst @@ -0,0 +1,2 @@ +Added client side validation to check if a given ``rep_delay`` is within the backend's +``rep_delay_range``. \ No newline at end of file diff --git a/test/unit/test_sampler.py b/test/unit/test_sampler.py index 50a7c83ca..eaeb0708f 100644 --- a/test/unit/test_sampler.py +++ b/test/unit/test_sampler.py @@ -105,7 +105,8 @@ def test_unsupported_dynamical_decoupling_with_dynamic_circuits(self): def test_run_default_options(self): """Test run using default options.""" - session = MagicMock(spec=MockSession, _backend="common_backend") + backend = get_mocked_backend() + session = MagicMock(spec=MockSession, _backend=backend) options_vars = [ ( SamplerOptions( # pylint: disable=unexpected-keyword-arg @@ -119,10 +120,10 @@ def test_run_default_options(self): ), ( { - "execution": {"init_qubits": True, "rep_delay": 0.01}, + "execution": {"init_qubits": True, "rep_delay": 0.0001}, }, { - "execution": {"init_qubits": True, "rep_delay": 0.01}, + "execution": {"init_qubits": True, "rep_delay": 0.0001}, }, ), ] @@ -136,6 +137,15 @@ def test_run_default_options(self): f"{inputs} and {expected} not partially equal.", ) + def test_rep_delay_validation(self): + """Test rep_delay_validation.""" + backend = get_mocked_backend() + session = MagicMock(spec=MockSession, _backend=backend) + options = {"execution": {"init_qubits": True, "rep_delay": 0.1}} + inst = SamplerV2(mode=session, options=options) + with self.assertRaises(ValueError): + inst.run((self.circuit,)) + def test_sampler_validations(self): """Test exceptions when failing client-side validations.""" backend = get_mocked_backend()