From 55d0abb28c61d15a25c1241708f05226547745e3 Mon Sep 17 00:00:00 2001 From: Jessie Yu Date: Thu, 18 Jul 2024 12:56:11 -0400 Subject: [PATCH 1/6] scrub RuntimeOptions from docs (#1808) --- qiskit_ibm_runtime/__init__.py | 1 - qiskit_ibm_runtime/estimator.py | 2 -- qiskit_ibm_runtime/fake_provider/local_service.py | 1 - qiskit_ibm_runtime/qiskit_runtime_service.py | 1 - qiskit_ibm_runtime/sampler.py | 2 -- qiskit_ibm_runtime/session.py | 1 - 6 files changed, 8 deletions(-) diff --git a/qiskit_ibm_runtime/__init__.py b/qiskit_ibm_runtime/__init__.py index 6ed0b71d6..e6aa4b512 100644 --- a/qiskit_ibm_runtime/__init__.py +++ b/qiskit_ibm_runtime/__init__.py @@ -196,7 +196,6 @@ IBMBackend RuntimeJob RuntimeJobV2 - RuntimeOptions RuntimeEncoder RuntimeDecoder """ diff --git a/qiskit_ibm_runtime/estimator.py b/qiskit_ibm_runtime/estimator.py index 3afd851de..e1a752db9 100644 --- a/qiskit_ibm_runtime/estimator.py +++ b/qiskit_ibm_runtime/estimator.py @@ -334,7 +334,6 @@ def run( # pylint: disable=arguments-differ parameter_values: Concrete parameters to be bound. **kwargs: Individual options to overwrite the default primitive options. - These include the runtime options in :class:`qiskit_ibm_runtime.RuntimeOptions`. Returns: Submitted job. @@ -370,7 +369,6 @@ def _run( # pylint: disable=arguments-differ parameter_values: An optional list of concrete parameters to be bound. **kwargs: Individual options to overwrite the default primitive options. - These include the runtime options in :class:`~qiskit_ibm_runtime.RuntimeOptions`. Returns: Submitted job diff --git a/qiskit_ibm_runtime/fake_provider/local_service.py b/qiskit_ibm_runtime/fake_provider/local_service.py index 0bc68bf4c..6833d9dc4 100644 --- a/qiskit_ibm_runtime/fake_provider/local_service.py +++ b/qiskit_ibm_runtime/fake_provider/local_service.py @@ -154,7 +154,6 @@ def run( inputs: Program input parameters. These input values are passed to the runtime program. options: Runtime options that control the execution environment. - See :class:`RuntimeOptions` for all available options. Returns: A job representing the execution. diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index f132045ea..14b18d7a8 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -804,7 +804,6 @@ def run( inputs: Program input parameters. These input values are passed to the runtime program. options: Runtime options that control the execution environment. - See :class:`RuntimeOptions` for all available options. callback: Callback function to be invoked for any interim results and final result. The callback function will receive 2 positional parameters: diff --git a/qiskit_ibm_runtime/sampler.py b/qiskit_ibm_runtime/sampler.py index 5c7116b1c..2ef084278 100644 --- a/qiskit_ibm_runtime/sampler.py +++ b/qiskit_ibm_runtime/sampler.py @@ -266,7 +266,6 @@ def run( # pylint: disable=arguments-differ a list of (parameterized) :class:`~qiskit.circuit.QuantumCircuit`. parameter_values: Concrete parameters to be bound. **kwargs: Individual options to overwrite the default primitive options. - These include the runtime options in :class:`qiskit_ibm_runtime.RuntimeOptions`. Returns: Submitted job. @@ -296,7 +295,6 @@ def _run( # pylint: disable=arguments-differ a list of (parameterized) :class:`~qiskit.circuit.QuantumCircuit`. parameter_values: An optional list of concrete parameters to be bound. **kwargs: Individual options to overwrite the default primitive options. - These include the runtime options in :class:`qiskit_ibm_runtime.RuntimeOptions`. Returns: Submitted job. diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index bbcd53a5e..e8b830967 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -178,7 +178,6 @@ def run( inputs: Program input parameters. These input values are passed to the runtime program. options: Runtime options that control the execution environment. - See :class:`qiskit_ibm_runtime.RuntimeOptions` for all available options. callback: Callback function to be invoked for any interim results and final result. Returns: From 7b81be43d0b02cbd484d64acb574893d3461bd94 Mon Sep 17 00:00:00 2001 From: Jessie Yu Date: Fri, 19 Jul 2024 14:45:37 -0400 Subject: [PATCH 2/6] Break up options classes in docs (#1806) * break up options classes * use lower case --- qiskit_ibm_runtime/options/__init__.py | 39 ++++++++++++++++++++++---- qiskit_ibm_runtime/options/options.py | 2 +- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/qiskit_ibm_runtime/options/__init__.py b/qiskit_ibm_runtime/options/__init__.py index c3a540b8f..4b47dd974 100644 --- a/qiskit_ibm_runtime/options/__init__.py +++ b/qiskit_ibm_runtime/options/__init__.py @@ -17,7 +17,7 @@ .. currentmodule:: qiskit_ibm_runtime.options -Options that can be passed to the primitives. +Options that can be passed to the Qiskit Runtime primitives. V2 Primitives ============= @@ -75,11 +75,23 @@ Classes ======= +Base primitive options +---------------------- + .. autosummary:: :toctree: ../stubs/ EstimatorOptions SamplerOptions + Options + + +Suboptions for V2 primitives only +--------------------------------- + +.. autosummary:: + :toctree: ../stubs/ + DynamicalDecouplingOptions ResilienceOptionsV2 LayerNoiseLearningOptions @@ -88,13 +100,28 @@ ZneOptions TwirlingOptions ExecutionOptionsV2 - Options - TranspilationOptions - ResilienceOptions - ExecutionOptions + SamplerExecutionOptionsV2 + + +Suboptions for both V1 and V2 primitives +---------------------------------------- + +.. autosummary:: + :toctree: ../stubs/ + EnvironmentOptions SimulatorOptions - SamplerExecutionOptionsV2 + + +Suboptions for V1 primitives only +--------------------------------- + +.. autosummary:: + :toctree: ../stubs/ + + TranspilationOptions + ExecutionOptions + ResilienceOptions """ diff --git a/qiskit_ibm_runtime/options/options.py b/qiskit_ibm_runtime/options/options.py index e8e681cce..596d54e61 100644 --- a/qiskit_ibm_runtime/options/options.py +++ b/qiskit_ibm_runtime/options/options.py @@ -233,7 +233,7 @@ def _set_if_exists(name: str, _inputs: dict, _options: dict) -> None: @dataclass class Options(BaseOptions): - """Options for the primitives, used by V1 primitives. + """Options for V1 primitives. Args: optimization_level: How much optimization to perform on the circuits. From b3d0f58427fcd25c276995deb759e4224e21b2b8 Mon Sep 17 00:00:00 2001 From: ptristan3 <44805021+ptristan3@users.noreply.github.com> Date: Mon, 22 Jul 2024 08:51:59 -0300 Subject: [PATCH 3/6] Add local channel (#1793) * add local channel type * return QiskitRuntimeLocalService for local channel * style fixes * pylint disable * pylint disable * add test case for QiskitRuntimeLocalService * ignore[no-untyped-def] * fix type * update FakeRuntimeService * updated test * release note * Update release-notes/unreleased/1793.feat.rst Co-authored-by: Kevin Tian * back the import * replace by args and kwargs * updated docstring * add check to the refresh method * Use private _run * update unit tests --------- Co-authored-by: Kevin Tian Co-authored-by: Kevin Tian --- qiskit_ibm_runtime/accounts/account.py | 2 +- qiskit_ibm_runtime/base_primitive.py | 4 ++-- .../fake_provider/fake_backend.py | 7 +++++++ .../fake_provider/local_service.py | 2 +- qiskit_ibm_runtime/qiskit_runtime_service.py | 17 +++++++++++++++-- qiskit_ibm_runtime/session.py | 2 +- release-notes/unreleased/1793.feat.rst | 8 ++++++++ test/integration/test_account.py | 16 ++++++++++++++++ test/unit/mock/fake_runtime_service.py | 3 +++ test/unit/test_ibm_primitives.py | 8 ++++---- test/unit/test_ibm_primitives_v2.py | 8 ++++---- 11 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 release-notes/unreleased/1793.feat.rst diff --git a/qiskit_ibm_runtime/accounts/account.py b/qiskit_ibm_runtime/accounts/account.py index c2e283a34..cb3793365 100644 --- a/qiskit_ibm_runtime/accounts/account.py +++ b/qiskit_ibm_runtime/accounts/account.py @@ -26,7 +26,7 @@ from ..utils import resolve_crn AccountType = Optional[Literal["cloud", "legacy"]] -ChannelType = Optional[Literal["ibm_cloud", "ibm_quantum"]] +ChannelType = Optional[Literal["ibm_cloud", "ibm_quantum", "local"]] IBM_QUANTUM_API_URL = "https://auth.quantum-computing.ibm.com/api" IBM_CLOUD_API_URL = "https://cloud.ibm.com" diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index a9c481b02..4be1c750a 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -163,7 +163,7 @@ def _run(self, pubs: Union[list[EstimatorPub], list[SamplerPub]]) -> RuntimeJobV result_decoder=DEFAULT_DECODERS.get(self._program_id()), ) - return self._service.run( + return self._service._run( program_id=self._program_id(), # type: ignore[arg-type] options=runtime_options, inputs=primitive_inputs, @@ -400,7 +400,7 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo callback=combined.get("environment", {}).get("callback", None), result_decoder=DEFAULT_DECODERS.get(self._program_id()), ) - return self._service.run( # type: ignore[call-arg] + return self._service._run( # type: ignore[call-arg] program_id=self._program_id(), # type: ignore[arg-type] options=runtime_options, inputs=primitive_inputs, diff --git a/qiskit_ibm_runtime/fake_provider/fake_backend.py b/qiskit_ibm_runtime/fake_provider/fake_backend.py index 29b8061fd..b1183afd2 100644 --- a/qiskit_ibm_runtime/fake_provider/fake_backend.py +++ b/qiskit_ibm_runtime/fake_provider/fake_backend.py @@ -575,8 +575,15 @@ def refresh(self, service: QiskitRuntimeService) -> None: service: A :class:`QiskitRuntimeService` instance Raises: + ValueError: if the provided service is a non-QiskitRuntimeService instance. Exception: If the real target doesn't exist or can't be accessed """ + if not isinstance(service, QiskitRuntimeService): + raise ValueError( + "The provided service to update the fake backend is invalid. A QiskitRuntimeService is" + " required to retrieve the real backend's current properties and settings." + ) + version = self.backend_version prod_name = self.backend_name.replace("fake", "ibm") try: diff --git a/qiskit_ibm_runtime/fake_provider/local_service.py b/qiskit_ibm_runtime/fake_provider/local_service.py index 6833d9dc4..bcfa9f265 100644 --- a/qiskit_ibm_runtime/fake_provider/local_service.py +++ b/qiskit_ibm_runtime/fake_provider/local_service.py @@ -141,7 +141,7 @@ def least_busy( """ return self.backends(min_num_qubits=min_num_qubits, filters=filters)[0] - def run( + def _run( self, program_id: Literal["sampler", "estimator"], inputs: Dict, diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 14b18d7a8..bd9c10f36 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -56,6 +56,16 @@ class QiskitRuntimeService: global_service = None + def __new__(cls, *args, **kwargs): # type: ignore[no-untyped-def] + channel = kwargs.get("channel", None) + if channel == "local": + # pylint: disable=import-outside-toplevel + from .fake_provider.local_service import QiskitRuntimeLocalService + + return super().__new__(QiskitRuntimeLocalService) + else: + return super().__new__(cls) + def __init__( self, channel: Optional[ChannelType] = None, @@ -85,7 +95,10 @@ def __init__( values in the loaded account. Args: - channel: Channel type. ``ibm_cloud`` or ``ibm_quantum``. + channel: Channel type. ``ibm_cloud``, ``ibm_quantum`` or ``local``. If ``local`` is selected, + the local testing mode will be used, and primitive queries will run on a local simulator. + For more details, check the `Qiskit Runtime local testing mode + `_ documentation. token: IBM Cloud API key or IBM Quantum API token. url: The API URL. Defaults to https://cloud.ibm.com (ibm_cloud) or @@ -106,7 +119,7 @@ def __init__( private_endpoint: Connect to private API URL. Returns: - An instance of QiskitRuntimeService. + An instance of QiskitRuntimeService or QiskitRuntimeLocalService for local channel. Raises: IBMInputValueError: If an input is invalid. diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index e8b830967..3b94e6aec 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -213,7 +213,7 @@ def run( if self._backend is None: self._backend = job.backend() else: - job = self._service.run( # type: ignore[call-arg] + job = self._service._run( # type: ignore[call-arg] program_id=program_id, # type: ignore[arg-type] options=options, inputs=inputs, diff --git a/release-notes/unreleased/1793.feat.rst b/release-notes/unreleased/1793.feat.rst new file mode 100644 index 000000000..9922ec2b2 --- /dev/null +++ b/release-notes/unreleased/1793.feat.rst @@ -0,0 +1,8 @@ +The :class:`QiskitRuntimeLocalService` was created to support a local +testing mode. To avoid having to initialize a separate class, "local" +has been added to the valid :class:`QiskitRuntimeService` channel. + +.. code:: python + service=QiskitRuntimeService(channel="local") + +a :class:`QiskitRuntimeLocalService` instance will be returned. \ No newline at end of file diff --git a/test/integration/test_account.py b/test/integration/test_account.py index 9b0b86364..829f33f3d 100644 --- a/test/integration/test_account.py +++ b/test/integration/test_account.py @@ -20,6 +20,7 @@ from qiskit_ibm_runtime import QiskitRuntimeService from qiskit_ibm_runtime.accounts import CloudResourceNameResolutionError +from qiskit_ibm_runtime.fake_provider.local_service import QiskitRuntimeLocalService from qiskit_ibm_runtime.utils.utils import ( get_resource_controller_api_url, get_iam_api_url, @@ -74,6 +75,21 @@ def test_channel_strategy(self): ) self.assertTrue(service) + def test_local_channel(self): + """Test local channel mode""" + local_service = QiskitRuntimeService( + channel="local", + ) + local_service1 = QiskitRuntimeService( + channel="local", + url=self.dependencies.url, + token=self.dependencies.token, + instance=self.dependencies.instance, + channel_strategy="default", + ) + self.assertIsInstance(local_service, QiskitRuntimeLocalService) + self.assertIsInstance(local_service1, QiskitRuntimeLocalService) + def test_resolve_crn_for_valid_service_instance_name(self): """Verify if CRN is transparently resolved based for an existing service instance name.""" self._skip_on_ibm_quantum() diff --git a/test/unit/mock/fake_runtime_service.py b/test/unit/mock/fake_runtime_service.py index ec36e2f03..48c5131f2 100644 --- a/test/unit/mock/fake_runtime_service.py +++ b/test/unit/mock/fake_runtime_service.py @@ -36,6 +36,9 @@ class FakeRuntimeService(QiskitRuntimeService): DEFAULT_COMMON_BACKEND = "common_backend" DEFAULT_UNIQUE_BACKEND_PREFIX = "unique_backend_" + def __new__(cls, *args, num_hgps=2, runtime_client=None, backend_specs=None, **kwargs): + return super().__new__(cls, *args, **kwargs) + def __init__(self, *args, num_hgps=2, runtime_client=None, backend_specs=None, **kwargs): self._test_num_hgps = num_hgps self._fake_runtime_client = runtime_client diff --git a/test/unit/test_ibm_primitives.py b/test/unit/test_ibm_primitives.py index 10d96f985..859793ad9 100644 --- a/test/unit/test_ibm_primitives.py +++ b/test/unit/test_ibm_primitives.py @@ -140,8 +140,8 @@ def __new__(cls, *args, **kwargs): # pylint: disable=unused-argument inst = primitive(backend=backend_name) self.assertIsNone(inst.session) inst.run(self.qx, observables=self.obs) - mock_service_inst.run.assert_called_once() - runtime_options = mock_service_inst.run.call_args.kwargs["options"] + mock_service_inst._run.assert_called_once() + runtime_options = mock_service_inst._run.call_args.kwargs["options"] self.assertEqual(runtime_options["backend"], mock_backend) def test_init_with_session_backend_str(self): @@ -240,8 +240,8 @@ def test_no_session(self): inst = cls(backend) inst.run(self.qx, observables=self.obs) self.assertIsNone(inst.session) - service.run.assert_called_once() - kwargs_list = service.run.call_args.kwargs + service._run.assert_called_once() + kwargs_list = service._run.call_args.kwargs self.assertNotIn("session_id", kwargs_list) self.assertNotIn("start_session", kwargs_list) diff --git a/test/unit/test_ibm_primitives_v2.py b/test/unit/test_ibm_primitives_v2.py index 8c73d9e91..2b6cd3a6d 100644 --- a/test/unit/test_ibm_primitives_v2.py +++ b/test/unit/test_ibm_primitives_v2.py @@ -157,16 +157,16 @@ def __new__(cls, *args, **kwargs): # pylint: disable=unused-argument inst = primitive(backend=backend_name) self.assertIsNone(inst.mode) inst.run(**get_primitive_inputs(inst)) - mock_service_inst.run.assert_called_once() - runtime_options = mock_service_inst.run.call_args.kwargs["options"] + mock_service_inst._run.assert_called_once() + runtime_options = mock_service_inst._run.call_args.kwargs["options"] self.assertEqual(runtime_options["backend"], mock_backend) mock_service_inst.reset_mock() str_mode_inst = primitive(mode=backend_name) self.assertIsNone(str_mode_inst.mode) inst.run(**get_primitive_inputs(str_mode_inst)) - mock_service_inst.run.assert_called_once() - runtime_options = mock_service_inst.run.call_args.kwargs["options"] + mock_service_inst._run.assert_called_once() + runtime_options = mock_service_inst._run.call_args.kwargs["options"] self.assertEqual(runtime_options["backend"], mock_backend) @data(EstimatorV2, SamplerV2) From 5e6944c8243528e8f89aec2c93b3829bde5adc96 Mon Sep 17 00:00:00 2001 From: Kevin Tian Date: Mon, 22 Jul 2024 09:01:52 -0400 Subject: [PATCH 4/6] Update sampler & estimator docstrings (#1812) --- qiskit_ibm_runtime/estimator.py | 8 ++++---- qiskit_ibm_runtime/sampler.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/qiskit_ibm_runtime/estimator.py b/qiskit_ibm_runtime/estimator.py index e1a752db9..0849c0fa9 100644 --- a/qiskit_ibm_runtime/estimator.py +++ b/qiskit_ibm_runtime/estimator.py @@ -125,11 +125,11 @@ def __init__( Refer to the `Qiskit Runtime documentation `_. for more information about the ``Execution modes``. - backend: Backend to run the primitive. This can be a backend name or an :class:`IBMBackend` - instance. If a name is specified, the default account (e.g. ``QiskitRuntimeService()``) - is used. + backend: (DEPRECATED) Backend to run the primitive. This can be a backend name + or an :class:`IBMBackend` instance. If a name is specified, the default account + (e.g. ``QiskitRuntimeService()``) is used. - session: Session in which to call the primitive. + session: (DEPRECATED) Session in which to call the primitive. If both ``session`` and ``backend`` are specified, ``session`` takes precedence. If neither is specified, and the primitive is created inside a diff --git a/qiskit_ibm_runtime/sampler.py b/qiskit_ibm_runtime/sampler.py index 2ef084278..9254e6d80 100644 --- a/qiskit_ibm_runtime/sampler.py +++ b/qiskit_ibm_runtime/sampler.py @@ -83,11 +83,11 @@ def __init__( Refer to the `Qiskit Runtime documentation `_. for more information about the ``Execution modes``. - backend: Backend to run the primitive. This can be a backend name or an :class:`IBMBackend` - instance. If a name is specified, the default account (e.g. ``QiskitRuntimeService()``) - is used. + backend: (DEPRECATED) Backend to run the primitive. This can be a backend name or + an :class:`IBMBackend` instance. If a name is specified, the default account + (e.g. ``QiskitRuntimeService()``) is used. - session: Session in which to call the primitive. + session: (DEPRECATED) Session in which to call the primitive. If both ``session`` and ``backend`` are specified, ``session`` takes precedence. If neither is specified, and the primitive is created inside a From 18b571dc746f4b89ccdc8129dd241bf1c3f9787e Mon Sep 17 00:00:00 2001 From: Rebecca Dimock <66339736+beckykd@users.noreply.github.com> Date: Mon, 22 Jul 2024 16:30:56 -0500 Subject: [PATCH 5/6] Update link in resilience_options.py (#1807) * Update resilience_options.py The link in measure_mitgation pointed to measure_noise_learning * Update qiskit_ibm_runtime/options/resilience_options.py * Update qiskit_ibm_runtime/options/resilience_options.py * Update qiskit_ibm_runtime/options/resilience_options.py * remove links for boolean options * fix black * fix lint * update zne/pec wording --------- Co-authored-by: kevin-tian --- qiskit_ibm_runtime/options/resilience_options.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/qiskit_ibm_runtime/options/resilience_options.py b/qiskit_ibm_runtime/options/resilience_options.py index 5955d144d..b585686b5 100644 --- a/qiskit_ibm_runtime/options/resilience_options.py +++ b/qiskit_ibm_runtime/options/resilience_options.py @@ -39,21 +39,25 @@ class ResilienceOptionsV2: Args: measure_mitigation: Whether to enable measurement error mitigation method. - Further suboptions are available in :attr:`~measure_noise_learning`. + If you enable measurement mitigation, you can fine tune its noise learning + by using :attr:`~measure_noise_learning`. See :class:`MeasureNoiseLearningOptions` + for all measurement mitigation noise learning options. Default: True. measure_noise_learning: Additional measurement noise learning options. See :class:`MeasureNoiseLearningOptions` for all options. zne_mitigation: Whether to turn on Zero Noise Extrapolation error mitigation method. - Further suboptions are available in :attr:`~zne`. + If you enable ZNE, you can fine tune its options by using :attr:`~zne`. + See :class:`ZneOptions` for additional ZNE related options. Default: False. zne: Additional zero noise extrapolation mitigation options. See :class:`ZneOptions` for all options. pec_mitigation: Whether to turn on Probabilistic Error Cancellation error mitigation method. - Further suboptions are available in :attr:`~pec`. + If you enable PEC, you can fine tune its options by using :attr:`~pec`. + See :class:`PecOptions` for additional PEC related options. Default: False. pec: Additional probabalistic error cancellation mitigation options. From d5b0b83399eb6223c5fc0b27029d3e101beb8841 Mon Sep 17 00:00:00 2001 From: Kevin Tian Date: Tue, 23 Jul 2024 11:03:07 -0400 Subject: [PATCH 6/6] Update unit tests for Qiskit 1.2 (#1810) * Update unit tests for Qiskit 1.2 * fix dd tests --- .../passes/scheduling/dynamical_decoupling.py | 16 ++++++++-------- .../transpiler/passes/scheduling/scheduler.py | 5 ++++- test/unit/test_local_mode.py | 1 - 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py index 0ef841829..af1958ea5 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py @@ -490,17 +490,17 @@ def _pad( theta, phi, lam, phase = OneQubitEulerDecomposer().angles_and_phase(u_inv) if isinstance(next_node, DAGOpNode) and isinstance(next_node.op, (UGate, U3Gate)): # Absorb the inverse into the successor (from left in circuit) - theta_r, phi_r, lam_r = next_node.op.params - next_node.op.params = Optimize1qGates.compose_u3( - theta_r, phi_r, lam_r, theta, phi, lam - ) + op = next_node.op + theta_r, phi_r, lam_r = op.params + op.params = Optimize1qGates.compose_u3(theta_r, phi_r, lam_r, theta, phi, lam) + next_node.op = op sequence_gphase += phase elif isinstance(prev_node, DAGOpNode) and isinstance(prev_node.op, (UGate, U3Gate)): # Absorb the inverse into the predecessor (from right in circuit) - theta_l, phi_l, lam_l = prev_node.op.params - prev_node.op.params = Optimize1qGates.compose_u3( - theta, phi, lam, theta_l, phi_l, lam_l - ) + op = prev_node.op + theta_l, phi_l, lam_l = op.params + op.params = Optimize1qGates.compose_u3(theta, phi, lam, theta_l, phi_l, lam_l) + prev_node.op = op sequence_gphase += phase else: # Don't do anything if there's no single-qubit gate to absorb the inverse diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py index 20fee4c3b..4032dff37 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py @@ -222,7 +222,10 @@ def _get_duration(self, node: DAGNode, dag: Optional[DAGCircuit] = None) -> int: # If node has calibration, this value should be the highest priority cal_key = tuple(indices), tuple(float(p) for p in node.op.params) duration = dag.calibrations[node.op.name][cal_key].duration - node.op.duration = duration + + op = node.op.to_mutable() + op.duration = duration + node.op = op else: # map to outer dag to get the appropriate durations duration = self._durations.get(node.op, indices, unit="dt") diff --git a/test/unit/test_local_mode.py b/test/unit/test_local_mode.py index d0736eaa5..a0259d4bd 100644 --- a/test/unit/test_local_mode.py +++ b/test/unit/test_local_mode.py @@ -204,7 +204,6 @@ def test_primitive_v2_with_not_accepted_options(self, primitive, backend): with warnings.catch_warnings(record=True) as warns: job = inst.run(**get_primitive_inputs(inst, backend=backend)) _ = job.result() - self.assertEqual(len(warns), 1) self.assertIn("dynamical_decoupling", str(warns[0].message)) @combine(session_cls=[Session, Batch], backend=[FakeManila(), FakeManilaV2(), AerSimulator()])