From ef7956f4804aa5df2d6dafc5cecb0da17e6e5674 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 15 Nov 2023 16:05:34 +0000 Subject: [PATCH 01/42] Recognized fake backends --- qiskit_ibm_runtime/qiskit_runtime_service.py | 32 +++++++++++- qiskit_ibm_runtime/utils/fake_backends.py | 51 ++++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 qiskit_ibm_runtime/utils/fake_backends.py diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 6ef274fad..0387cd974 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -20,6 +20,8 @@ from collections import OrderedDict from typing import Dict, Callable, Optional, Union, List, Any, Type, Sequence +from qiskit_aer import AerSimulator +from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend from qiskit.providers.backend import BackendV1 as Backend from qiskit.providers.provider import ProviderV1 as Provider from qiskit.providers.exceptions import QiskitBackendNotFoundError @@ -34,6 +36,7 @@ from qiskit_ibm_provider.utils.backend_decoder import configuration_from_server_data from qiskit_ibm_runtime import ibm_backend +from .utils.fake_backends import fake_backend_list from .utils.utils import validate_job_tags from .accounts import AccountManager, Account, ChannelType from .api.clients import AuthClient, VersionClient @@ -532,7 +535,7 @@ def backends( instance: Optional[str] = None, filters: Optional[Callable[[List["ibm_backend.IBMBackend"]], bool]] = None, **kwargs: Any, - ) -> List["ibm_backend.IBMBackend"]: + ) -> Union[List["ibm_backend.IBMBackend"], List[FakeBackend]]: """Return all backends accessible via this account, subject to optional filtering. Args: @@ -572,11 +575,18 @@ def backends( QiskitBackendNotFoundError: If the backend is not in any instance. """ # TODO filter out input_allowed not having runtime - backends: List[IBMBackend] = [] + backends: Union[List[IBMBackend], List[FakeBackend]] = [] instance_filter = instance if instance else self._account.instance if self._channel == "ibm_quantum": if name: if name not in self._backends: + fake_backend = self._get_fake_backend(name) + print(fake_backend) + print(isinstance(fake_backend, FakeBackend)) + print("fake_backend name = "+str(fake_backend.backend_name)) + if fake_backend: + backends.append(fake_backend) + return backends raise QiskitBackendNotFoundError("No backend matches the criteria.") if not self._backends[name] or instance != self._backends[name]._instance: self._set_backend_config(name) @@ -802,6 +812,9 @@ def backend( # pylint: disable=arguments-differ, line-too-long backends = self.backends(name, instance=instance) if not backends: + # fake_backend = self._get_fake_backend(name) + # if fake_backend: + # return fake_backend cloud_msg_url = "" if self._channel == "ibm_cloud": cloud_msg_url = ( @@ -809,11 +822,15 @@ def backend( "https://cloud.ibm.com/docs/quantum-computing?topic=quantum-computing-choose-backend " ) raise QiskitBackendNotFoundError("No backend matches the criteria." + cloud_msg_url) + print("backend= " + str(backends[0].backend_name)) return backends[0] def get_backend(self, name: str = None, **kwargs: Any) -> Backend: return self.backend(name, **kwargs) + def _get_fake_backend(self, name: str): + return fake_backend_list[name] + def pprint_programs( self, refresh: bool = False, @@ -1052,6 +1069,17 @@ def run( qrt_options.validate(channel=self.channel) + # if backend is a simulator, run locally + if isinstance(qrt_options.backend, AerSimulator): + from qiskit_aer import Sampler as AerSampler + from qiskit_aer import Estimator as AerEstimator + print("1 backend = "+ str(qrt_options.backend)) + #return FakeRuntimeJob(AerSampler.run(...)) + elif isinstance(qrt_options.backend, FakeBackend): + from qiskit.primitives import BackendSampler, BackendEstimator + print("2 backend = " + str(qrt_options.backend)) + #return FakeRuntimeJob(BackendSampler.run(...)) + hgp_name = None if self._channel == "ibm_quantum": # Find the right hgp diff --git a/qiskit_ibm_runtime/utils/fake_backends.py b/qiskit_ibm_runtime/utils/fake_backends.py new file mode 100644 index 000000000..2d0a801b4 --- /dev/null +++ b/qiskit_ibm_runtime/utils/fake_backends.py @@ -0,0 +1,51 @@ +from qiskit.providers.fake_provider.backends import * + +# BackendV2, Backends +fake_backend_list = { +"almaden": FakeAlmadenV2, +"armonk": FakeArmonkV2, +"athens": FakeAthensV2, +"auckland": FakeAuckland, +"belem": FakeBelemV2, +"boeblingen": FakeBoeblingenV2, +"bogota": FakeBogotaV2, +"brooklyn": FakeBrooklynV2, +"burlington": FakeBurlingtonV2, +"cairo": FakeCairoV2, +"cambridge": FakeCambridgeV2, +"casablanca": FakeCasablancaV2, +"essex": FakeEssexV2, +"geneva": FakeGeneva, +"guadalupe": FakeGuadalupeV2, +"hanoi": FakeHanoiV2, +"jakarta": FakeJakartaV2, +"johannesburg": FakeJohannesburgV2, +"kolkata": FakeKolkataV2, +"lagos": FakeLagosV2, +"lima": FakeLimaV2, +"london": FakeLondonV2, +"manhattan": FakeManhattanV2, +"manila": FakeManilaV2, +"melbourne": FakeMelbourneV2, +"montreal": FakeMontrealV2, +"mumbai": FakeMumbaiV2, +"nairobi": FakeNairobiV2, +"oslo": FakeOslo, +"ourense": FakeOurenseV2, +"paris": FakeParisV2, +"perth": FakePerth, +"prague": FakePrague, +"poughkeepsie": FakePoughkeepsieV2, +"quito": FakeQuitoV2, +"rochester": FakeRochesterV2, +"rome": FakeRomeV2, +"santiago": FakeSantiagoV2, +"sherbrooke": FakeSherbrooke, +"singapore": FakeSingaporeV2, +"sydney": FakeSydneyV2, +"toronto": FakeTorontoV2, +"valencia": FakeValenciaV2, +"vigo": FakeVigoV2, +"washington": FakeWashingtonV2, +"yorktown": FakeYorktownV2, +} From d6ab6342f4799d1727a769f336a36c89aa188160 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Thu, 23 Nov 2023 13:57:31 +0000 Subject: [PATCH 02/42] Continuing support for fake backends in Sampler --- qiskit_ibm_runtime/base_primitive.py | 19 ++++++- qiskit_ibm_runtime/options/utils.py | 10 +++- qiskit_ibm_runtime/qiskit_runtime_service.py | 52 +++++++++++++++----- qiskit_ibm_runtime/utils/fake_backends.py | 2 +- 4 files changed, 68 insertions(+), 15 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 4dd596e2a..b59be168a 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -20,6 +20,7 @@ from dataclasses import asdict from qiskit.providers.options import Options as TerraOptions +from qiskit.providers.fake_provider import fake_backend from .options import Options from .options.utils import set_default_error_levels @@ -96,12 +97,16 @@ def __init__( self._service = backend.service self._backend = backend elif isinstance(backend, str): + print("here") self._service = ( QiskitRuntimeService() if QiskitRuntimeService.global_service is None else QiskitRuntimeService.global_service ) self._backend = self._service.backend(backend) + print("actual backend = " + str(self._backend)) + print(type(self._backend)) + print(isinstance(self._backend, fake_backend.FakeBackendV2)) elif get_cm_session(): self._session = get_cm_session() self._service = self._session.service @@ -156,6 +161,19 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo logger.info("Submitting job using options %s", combined) runtime_options = Options._get_runtime_options(combined) + + if isinstance(self._backend, fake_backend.FakeBackendV2): + print("runnnnning") + runtime_options["backend"] = self._backend #fix this - for cloud, is str, + # for fake is Backend + + return self._service.run( + program_id=self._program_id(), + options=runtime_options, + inputs=primitive_inputs, + callback=combined.get("environment", {}).get("callback", None), + result_decoder=DEFAULT_DECODERS.get(self._program_id()), + ) if self._session: return self._session.run( program_id=self._program_id(), @@ -164,7 +182,6 @@ 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()), ) - if self._backend: runtime_options["backend"] = self._backend.name if "instance" not in runtime_options: diff --git a/qiskit_ibm_runtime/options/utils.py b/qiskit_ibm_runtime/options/utils.py index 3a744f5b5..9ee1e068f 100644 --- a/qiskit_ibm_runtime/options/utils.py +++ b/qiskit_ibm_runtime/options/utils.py @@ -12,6 +12,8 @@ """Utility functions for options.""" +#from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend +from qiskit.providers.fake_provider import fake_backend from ..ibm_backend import IBMBackend @@ -33,8 +35,12 @@ def set_default_error_levels( options with correct error level defaults. """ if options.get("optimization_level") is None: + if isinstance(backend, fake_backend.FakeBackendV2): + print("I am a fake") + else: + print("nononon") if ( - backend.configuration().simulator + (isinstance(backend, fake_backend.FakeBackendV2) or backend.configuration().simulator) and options.get("simulator", {}).get("noise_model") is None ): options["optimization_level"] = 1 @@ -43,7 +49,7 @@ def set_default_error_levels( if options.get("resilience_level") is None: if ( - backend.configuration().simulator + (isinstance(backend, fake_backend.FakeBackendV2) or backend.configuration().simulator) and options.get("simulator", {}).get("noise_model") is None ): options["resilience_level"] = 0 diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 0387cd974..0fb7d771c 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -21,7 +21,8 @@ from typing import Dict, Callable, Optional, Union, List, Any, Type, Sequence from qiskit_aer import AerSimulator -from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend +#from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend +from qiskit.providers.fake_provider import fake_backend from qiskit.providers.backend import BackendV1 as Backend from qiskit.providers.provider import ProviderV1 as Provider from qiskit.providers.exceptions import QiskitBackendNotFoundError @@ -30,6 +31,7 @@ PulseBackendConfiguration, QasmBackendConfiguration, ) +from qiskit.primitives.primitive_job import PrimitiveJob from qiskit_ibm_provider.proxies import ProxyConfiguration from qiskit_ibm_provider.utils.hgp import to_instance_format, from_instance_format @@ -535,7 +537,7 @@ def backends( instance: Optional[str] = None, filters: Optional[Callable[[List["ibm_backend.IBMBackend"]], bool]] = None, **kwargs: Any, - ) -> Union[List["ibm_backend.IBMBackend"], List[FakeBackend]]: + ) -> Union[List["ibm_backend.IBMBackend"], List[fake_backend.FakeBackendV2]]: """Return all backends accessible via this account, subject to optional filtering. Args: @@ -575,14 +577,14 @@ def backends( QiskitBackendNotFoundError: If the backend is not in any instance. """ # TODO filter out input_allowed not having runtime - backends: Union[List[IBMBackend], List[FakeBackend]] = [] + backends: Union[List[IBMBackend], List[fake_backend.FakeBackendV2]] = [] instance_filter = instance if instance else self._account.instance if self._channel == "ibm_quantum": if name: if name not in self._backends: fake_backend = self._get_fake_backend(name) print(fake_backend) - print(isinstance(fake_backend, FakeBackend)) + print(isinstance(fake_backend, fake_backend.FakeBackendV2)) print("fake_backend name = "+str(fake_backend.backend_name)) if fake_backend: backends.append(fake_backend) @@ -793,7 +795,7 @@ def backend( self, name: str = None, instance: Optional[str] = None, - ) -> Backend: + ) -> Union[Backend, fake_backend.FakeBackendV2]: """Return a single backend matching the specified filtering. Args: @@ -810,7 +812,16 @@ def backend( QiskitBackendNotFoundError: if no backend could be found. """ # pylint: disable=arguments-differ, line-too-long + if name and name not in self._backends: + my_fake_backend = self._get_fake_backend(name) + print(my_fake_backend) + print(isinstance(my_fake_backend, fake_backend.FakeBackendV2)) + print("fake_backend name = " + str(my_fake_backend.backend_name)) + if my_fake_backend: + return my_fake_backend + backends = self.backends(name, instance=instance) + print("backends = "+str(backends)) if not backends: # fake_backend = self._get_fake_backend(name) # if fake_backend: @@ -822,14 +833,20 @@ def backend( "https://cloud.ibm.com/docs/quantum-computing?topic=quantum-computing-choose-backend " ) raise QiskitBackendNotFoundError("No backend matches the criteria." + cloud_msg_url) - print("backend= " + str(backends[0].backend_name)) return backends[0] def get_backend(self, name: str = None, **kwargs: Any) -> Backend: return self.backend(name, **kwargs) - def _get_fake_backend(self, name: str): - return fake_backend_list[name] + def _get_fake_backend(self, name: str) -> fake_backend.FakeBackendV2: + from qiskit.providers.fake_provider.backends.manila.fake_manila import FakeManilaV2 + print(issubclass(FakeManilaV2, fake_backend.FakeBackendV2)) + my_fake_backend = fake_backend_list[name] + print(type(my_fake_backend)) + print(my_fake_backend.backend_name) + print(my_fake_backend.defs_filename) + print("in get, my type = " + str(isinstance(my_fake_backend, fake_backend.FakeBackendV2))) + return my_fake_backend def pprint_programs( self, @@ -1061,7 +1078,7 @@ def run( qrt_options = RuntimeOptions() elif isinstance(options, Dict): qrt_options = RuntimeOptions(**options) - + print("qrt_options = " + str(qrt_options)) # If using params object, extract as dictionary. if isinstance(inputs, ParameterNamespace): inputs.validate() @@ -1075,10 +1092,23 @@ def run( from qiskit_aer import Estimator as AerEstimator print("1 backend = "+ str(qrt_options.backend)) #return FakeRuntimeJob(AerSampler.run(...)) - elif isinstance(qrt_options.backend, FakeBackend): + elif isinstance(qrt_options.backend, fake_backend.FakeBackendV2): from qiskit.primitives import BackendSampler, BackendEstimator print("2 backend = " + str(qrt_options.backend)) - #return FakeRuntimeJob(BackendSampler.run(...)) + print("program_id = " + str(program_id)) + if program_id == "sampler": + print("inputs = " + str(inputs)) + print(qrt_options) + sampler = BackendSampler( + backend=qrt_options.backend, skip_transpilation=True + ) + + return sampler._run(circuits=inputs["circuits"], + parameter_values=inputs["parameters"], + run_options=options) + + #primitive_job = BackendSampler.run(...) + #return FakeRuntimeJob(primitive_job) hgp_name = None if self._channel == "ibm_quantum": diff --git a/qiskit_ibm_runtime/utils/fake_backends.py b/qiskit_ibm_runtime/utils/fake_backends.py index 2d0a801b4..c7a28e877 100644 --- a/qiskit_ibm_runtime/utils/fake_backends.py +++ b/qiskit_ibm_runtime/utils/fake_backends.py @@ -25,7 +25,7 @@ "lima": FakeLimaV2, "london": FakeLondonV2, "manhattan": FakeManhattanV2, -"manila": FakeManilaV2, +"manila": FakeManilaV2(), "melbourne": FakeMelbourneV2, "montreal": FakeMontrealV2, "mumbai": FakeMumbaiV2, From d105760cab2eba5347a350c797f84a70c2dc1fa7 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Thu, 23 Nov 2023 19:54:00 +0000 Subject: [PATCH 03/42] Created FakeRuntimeJob --- qiskit_ibm_runtime/base_primitive.py | 5 ----- qiskit_ibm_runtime/options/utils.py | 4 ---- qiskit_ibm_runtime/qiskit_runtime_service.py | 12 +++++++++++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index dceeb0e2d..74870895f 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -100,16 +100,12 @@ def __init__( self._service = backend.service self._backend = backend elif isinstance(backend, str): - print("here") self._service = ( QiskitRuntimeService() if QiskitRuntimeService.global_service is None else QiskitRuntimeService.global_service ) self._backend = self._service.backend(backend) - print("actual backend = " + str(self._backend)) - print(type(self._backend)) - print(isinstance(self._backend, fake_backend.FakeBackendV2)) elif get_cm_session(): self._session = get_cm_session() self._service = self._session.service @@ -171,7 +167,6 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo runtime_options = Options._get_runtime_options(combined) if isinstance(self._backend, fake_backend.FakeBackendV2): - print("runnnnning") runtime_options["backend"] = self._backend #fix this - for cloud, is str, # for fake is Backend diff --git a/qiskit_ibm_runtime/options/utils.py b/qiskit_ibm_runtime/options/utils.py index 9ee1e068f..9464a0448 100644 --- a/qiskit_ibm_runtime/options/utils.py +++ b/qiskit_ibm_runtime/options/utils.py @@ -35,10 +35,6 @@ def set_default_error_levels( options with correct error level defaults. """ if options.get("optimization_level") is None: - if isinstance(backend, fake_backend.FakeBackendV2): - print("I am a fake") - else: - print("nononon") if ( (isinstance(backend, fake_backend.FakeBackendV2) or backend.configuration().simulator) and options.get("simulator", {}).get("noise_model") is None diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 0fb7d771c..7f9970890 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -37,6 +37,7 @@ from qiskit_ibm_provider.utils.hgp import to_instance_format, from_instance_format from qiskit_ibm_provider.utils.backend_decoder import configuration_from_server_data from qiskit_ibm_runtime import ibm_backend +from .fake_runtime_job import FakeRuntimeJob from .utils.fake_backends import fake_backend_list from .utils.utils import validate_job_tags @@ -1103,9 +1104,18 @@ def run( backend=qrt_options.backend, skip_transpilation=True ) - return sampler._run(circuits=inputs["circuits"], + primitive_job = sampler._run(circuits=inputs["circuits"], parameter_values=inputs["parameters"], run_options=options) + fake_runtime_job = FakeRuntimeJob( + primitive_job=primitive_job, + backend=qrt_options.backend, + job_id=primitive_job.job_id(), + program_id=program_id, + service=self, + params=inputs["parameters"], + ) + return fake_runtime_job #primitive_job = BackendSampler.run(...) #return FakeRuntimeJob(primitive_job) From 80ff68f9c4bc32f5535c4633bf49668090665b5b Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Tue, 28 Nov 2023 16:52:09 +0000 Subject: [PATCH 04/42] Added AerSimulator --- qiskit_ibm_runtime/base_primitive.py | 15 ++- qiskit_ibm_runtime/fake_runtime_job.py | 78 ++++++++++++ qiskit_ibm_runtime/qiskit_runtime_service.py | 121 +++++++++++++------ qiskit_ibm_runtime/utils/fake_backends.py | 92 +++++++------- 4 files changed, 221 insertions(+), 85 deletions(-) create mode 100644 qiskit_ibm_runtime/fake_runtime_job.py diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 74870895f..76d1ae746 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -22,6 +22,7 @@ from qiskit.providers.options import Options as TerraOptions from qiskit.providers.fake_provider import fake_backend +from qiskit_aer import AerSimulator from qiskit_ibm_provider.session import get_cm_session as get_cm_provider_session @@ -99,6 +100,13 @@ def __init__( if isinstance(backend, IBMBackend): self._service = backend.service self._backend = backend + elif isinstance(backend, AerSimulator): + self._backend = backend + self._service = ( + QiskitRuntimeService() + if QiskitRuntimeService.global_service is None + else QiskitRuntimeService.global_service + ) elif isinstance(backend, str): self._service = ( QiskitRuntimeService() @@ -138,6 +146,7 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo Returns: Submitted job. """ + run_simulator = isinstance(self._backend, Union[fake_backend.FakeBackendV2, AerSimulator]) combined = Options._merge_options(self._options, user_kwargs) if self._backend: @@ -158,7 +167,7 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo primitive_inputs.update(Options._get_program_inputs(combined)) - if self._backend and combined["transpilation"]["skip_transpilation"]: + if self._backend and combined["transpilation"]["skip_transpilation"] and not run_simulator: for circ in primitive_inputs["circuits"]: self._backend.check_faulty(circ) @@ -166,9 +175,11 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo runtime_options = Options._get_runtime_options(combined) - if isinstance(self._backend, fake_backend.FakeBackendV2): + if run_simulator: runtime_options["backend"] = self._backend #fix this - for cloud, is str, # for fake is Backend + print("runtime options = ", runtime_options) + print("inputs ", primitive_inputs) return self._service.run( program_id=self._program_id(), diff --git a/qiskit_ibm_runtime/fake_runtime_job.py b/qiskit_ibm_runtime/fake_runtime_job.py new file mode 100644 index 000000000..6338ad514 --- /dev/null +++ b/qiskit_ibm_runtime/fake_runtime_job.py @@ -0,0 +1,78 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2023. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Qiskit fake runtime job.""" + +from typing import Optional, Dict, Union, List, Type, Sequence, Any + +from qiskit.primitives.primitive_job import PrimitiveJob +from qiskit.primitives.base.base_primitive import BasePrimitive +from qiskit.providers import JobError, JobStatus, JobV1 +from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend + +from .program.result_decoder import ResultDecoder + +class FakeRuntimeJob(JobV1): + """Representation of a runtime program execution on a simulator.""" + + def __init__( + self, + primitive_job: PrimitiveJob, + backend: FakeBackend, + job_id: str, + program_id: str, + service: "qiskit_runtime_service.QiskitRuntimeService", + params: Optional[Dict] = None, + creation_date: Optional[str] = None, + #user_callback: Optional[Callable] = None, + #result_decoder: Optional[Union[Type[ResultDecoder], Sequence[Type[ResultDecoder]]]] = None, + #tags: Optional[List] = None, + ) -> None: + """FakeRuntimeJob constructor.""" + super().__init__(backend=backend, job_id=job_id) + self._primitive_job = primitive_job + self._job_id = job_id + self._params = params or {} + self._program_id = program_id + + def result(self) -> Any: + """Return the results of the job.""" + return self._primitive_job.result() + + def cancel(self): + self._primitive_job.cancel() + + def status(self)-> JobStatus: + return self._primitive_job.status() + + @property + def inputs(self) -> Dict: + """Job input parameters. + + Returns: + Input parameters used in this job. + """ + return self._params + + def submit(self) -> None: + """Unsupported method. + Note: + This method is not supported, please use + :meth:`~qiskit_ibm_runtime.QiskitRuntimeService.run` + to submit a job. + Raises: + NotImplementedError: Upon invocation. + """ + raise NotImplementedError( + "job.submit() is not supported. Please use " + "QiskitRuntimeService.run() to submit a job." + ) \ No newline at end of file diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 7f9970890..393517f08 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -21,6 +21,9 @@ from typing import Dict, Callable, Optional, Union, List, Any, Type, Sequence from qiskit_aer import AerSimulator +from qiskit_aer.backends.aerbackend import AerBackend +from qiskit_aer.primitives import Sampler as AerSampler +from qiskit_aer.primitives import Estimator as AerEstimator #from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend from qiskit.providers.fake_provider import fake_backend from qiskit.providers.backend import BackendV1 as Backend @@ -32,6 +35,7 @@ QasmBackendConfiguration, ) from qiskit.primitives.primitive_job import PrimitiveJob +from qiskit.primitives import BackendSampler, BackendEstimator from qiskit_ibm_provider.proxies import ProxyConfiguration from qiskit_ibm_provider.utils.hgp import to_instance_format, from_instance_format @@ -584,9 +588,6 @@ def backends( if name: if name not in self._backends: fake_backend = self._get_fake_backend(name) - print(fake_backend) - print(isinstance(fake_backend, fake_backend.FakeBackendV2)) - print("fake_backend name = "+str(fake_backend.backend_name)) if fake_backend: backends.append(fake_backend) return backends @@ -815,14 +816,10 @@ def backend( # pylint: disable=arguments-differ, line-too-long if name and name not in self._backends: my_fake_backend = self._get_fake_backend(name) - print(my_fake_backend) - print(isinstance(my_fake_backend, fake_backend.FakeBackendV2)) - print("fake_backend name = " + str(my_fake_backend.backend_name)) if my_fake_backend: return my_fake_backend backends = self.backends(name, instance=instance) - print("backends = "+str(backends)) if not backends: # fake_backend = self._get_fake_backend(name) # if fake_backend: @@ -841,12 +838,7 @@ def get_backend(self, name: str = None, **kwargs: Any) -> Backend: def _get_fake_backend(self, name: str) -> fake_backend.FakeBackendV2: from qiskit.providers.fake_provider.backends.manila.fake_manila import FakeManilaV2 - print(issubclass(FakeManilaV2, fake_backend.FakeBackendV2)) my_fake_backend = fake_backend_list[name] - print(type(my_fake_backend)) - print(my_fake_backend.backend_name) - print(my_fake_backend.defs_filename) - print("in get, my type = " + str(isinstance(my_fake_backend, fake_backend.FakeBackendV2))) return my_fake_backend def pprint_programs( @@ -1061,6 +1053,7 @@ def run( RuntimeProgramNotFound: If the program cannot be found. IBMRuntimeError: An error occurred running the program. """ + print("inputs = ", inputs) if program_id not in ["sampler", "estimator", "circuit-runner", "qasm3-runner"]: warnings.warn( ( @@ -1079,43 +1072,97 @@ def run( qrt_options = RuntimeOptions() elif isinstance(options, Dict): qrt_options = RuntimeOptions(**options) - print("qrt_options = " + str(qrt_options)) # If using params object, extract as dictionary. if isinstance(inputs, ParameterNamespace): inputs.validate() inputs = vars(inputs) qrt_options.validate(channel=self.channel) + # transpilation_options = inputs["transpilation_settings"] + # print("transpilation_options = ", transpilation_options) + sim_options = inputs["run_options"] + # print("simulator options = ", sim_options) + is_fake_backend = False + is_aer_backend = False # if backend is a simulator, run locally if isinstance(qrt_options.backend, AerSimulator): - from qiskit_aer import Sampler as AerSampler - from qiskit_aer import Estimator as AerEstimator - print("1 backend = "+ str(qrt_options.backend)) - #return FakeRuntimeJob(AerSampler.run(...)) + is_aer_simulator = True + if program_id == "sampler": + prog = AerSampler + else: #program_id == "estimator": + prog = AerEstimator + elif isinstance(qrt_options.backend, fake_backend.FakeBackendV2): - from qiskit.primitives import BackendSampler, BackendEstimator - print("2 backend = " + str(qrt_options.backend)) - print("program_id = " + str(program_id)) + #return FakeRuntimeJob(AerSampler.run(...)) + is_fake_backend= True if program_id == "sampler": - print("inputs = " + str(inputs)) - print(qrt_options) - sampler = BackendSampler( - backend=qrt_options.backend, skip_transpilation=True - ) + prog = BackendSampler + else: #program_id == "estimator": + prog = BackendEstimator - primitive_job = sampler._run(circuits=inputs["circuits"], - parameter_values=inputs["parameters"], - run_options=options) - fake_runtime_job = FakeRuntimeJob( - primitive_job=primitive_job, - backend=qrt_options.backend, - job_id=primitive_job.job_id(), - program_id=program_id, - service=self, - params=inputs["parameters"], - ) - return fake_runtime_job + else: + is_simulation = False + # elif isinstance(qrt_options.backend, fake_backend.FakeBackendV2): + # #from qiskit_ibm_runtime.options import Options + # if program_id == "sampler": + # sampler = BackendSa + # + # else:mpler( + # backend=qrt_options.backend, + # options=sim_options, + # skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"], + # ) + + if is_fake_backend: + my_program = prog(backend=qrt_options.backend, + options=sim_options, + skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"] + ) + observables = inputs.get("observables", None) + + primitive_job = my_program._run(circuits=inputs["circuits"], + parameter_values=inputs["parameters"], + run_options=sim_options, + observables=observables + ) + fake_runtime_job = FakeRuntimeJob( + primitive_job=primitive_job, + backend=qrt_options.backend, + job_id=primitive_job.job_id(), + program_id=program_id, + service=self, + params=inputs["parameters"], + ) + return fake_runtime_job + + if is_aer_simulator: + aer_backend_options = {} + for opt in inputs["run_options"]: + if hasattr(AerSimulator._default_options(), opt): + aer_backend_options[opt] = inputs["run_options"][opt] + print("aer_config", aer_backend_options) + + my_program = prog(backend_options=aer_backend_options, + transpile_options=inputs["transpilation_settings"], + skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"] + ) + observables = inputs.get("observables", None) + + primitive_job = my_program._run(circuits=inputs["circuits"], + parameter_values=inputs["parameters"], + run_options=sim_options, + observables=observables + ) + fake_runtime_job = FakeRuntimeJob( + primitive_job=primitive_job, + backend=qrt_options.backend, + job_id=primitive_job.job_id(), + program_id=program_id, + service=self, + params=inputs["parameters"], + ) + return fake_runtime_job #primitive_job = BackendSampler.run(...) #return FakeRuntimeJob(primitive_job) diff --git a/qiskit_ibm_runtime/utils/fake_backends.py b/qiskit_ibm_runtime/utils/fake_backends.py index c7a28e877..58baa9f39 100644 --- a/qiskit_ibm_runtime/utils/fake_backends.py +++ b/qiskit_ibm_runtime/utils/fake_backends.py @@ -2,50 +2,50 @@ # BackendV2, Backends fake_backend_list = { -"almaden": FakeAlmadenV2, -"armonk": FakeArmonkV2, -"athens": FakeAthensV2, -"auckland": FakeAuckland, -"belem": FakeBelemV2, -"boeblingen": FakeBoeblingenV2, -"bogota": FakeBogotaV2, -"brooklyn": FakeBrooklynV2, -"burlington": FakeBurlingtonV2, -"cairo": FakeCairoV2, -"cambridge": FakeCambridgeV2, -"casablanca": FakeCasablancaV2, -"essex": FakeEssexV2, -"geneva": FakeGeneva, -"guadalupe": FakeGuadalupeV2, -"hanoi": FakeHanoiV2, -"jakarta": FakeJakartaV2, -"johannesburg": FakeJohannesburgV2, -"kolkata": FakeKolkataV2, -"lagos": FakeLagosV2, -"lima": FakeLimaV2, -"london": FakeLondonV2, -"manhattan": FakeManhattanV2, -"manila": FakeManilaV2(), -"melbourne": FakeMelbourneV2, -"montreal": FakeMontrealV2, -"mumbai": FakeMumbaiV2, -"nairobi": FakeNairobiV2, -"oslo": FakeOslo, -"ourense": FakeOurenseV2, -"paris": FakeParisV2, -"perth": FakePerth, -"prague": FakePrague, -"poughkeepsie": FakePoughkeepsieV2, -"quito": FakeQuitoV2, -"rochester": FakeRochesterV2, -"rome": FakeRomeV2, -"santiago": FakeSantiagoV2, -"sherbrooke": FakeSherbrooke, -"singapore": FakeSingaporeV2, -"sydney": FakeSydneyV2, -"toronto": FakeTorontoV2, -"valencia": FakeValenciaV2, -"vigo": FakeVigoV2, -"washington": FakeWashingtonV2, -"yorktown": FakeYorktownV2, + "almaden": FakeAlmadenV2(), + "armonk": FakeArmonkV2(), + "athens": FakeAthensV2(), + "auckland": FakeAuckland(), + "belem": FakeBelemV2(), + "boeblingen": FakeBoeblingenV2(), + "bogota": FakeBogotaV2(), + "brooklyn": FakeBrooklynV2(), + "burlington": FakeBurlingtonV2(), + "cairo": FakeCairoV2(), + "cambridge": FakeCambridgeV2(), + "casablanca": FakeCasablancaV2(), + "essex": FakeEssexV2(), + "geneva": FakeGeneva(), + "guadalupe": FakeGuadalupeV2(), + "hanoi": FakeHanoiV2(), + "jakarta": FakeJakartaV2(), + "johannesburg": FakeJohannesburgV2(), + "kolkata": FakeKolkataV2(), + "lagos": FakeLagosV2(), + "lima": FakeLimaV2(), + "london": FakeLondonV2(), + "manhattan": FakeManhattanV2(), + "manila": FakeManilaV2(), + "melbourne": FakeMelbourneV2(), + "montreal": FakeMontrealV2(), + "mumbai": FakeMumbaiV2(), + "nairobi": FakeNairobiV2(), + "oslo": FakeOslo(), + "ourense": FakeOurenseV2(), + "paris": FakeParisV2(), + "perth": FakePerth(), + "prague": FakePrague(), + "poughkeepsie": FakePoughkeepsieV2(), + "quito": FakeQuitoV2(), + "rochester": FakeRochesterV2(), + "rome": FakeRomeV2(), + "santiago": FakeSantiagoV2(), + "sherbrooke": FakeSherbrooke(), + "singapore": FakeSingaporeV2(), + "sydney": FakeSydneyV2(), + "toronto": FakeTorontoV2(), + "valencia": FakeValenciaV2(), + "vigo": FakeVigoV2(), + "washington": FakeWashingtonV2(), + "yorktown": FakeYorktownV2(), } From e55831bc23f0b9a59fd250ef71e6293049e52d5c Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 29 Nov 2023 11:10:00 +0000 Subject: [PATCH 05/42] Small fixes --- qiskit_ibm_runtime/base_primitive.py | 6 ++++-- qiskit_ibm_runtime/fake_runtime_job.py | 4 ++-- qiskit_ibm_runtime/options/utils.py | 12 +++--------- qiskit_ibm_runtime/qiskit_runtime_service.py | 4 ++++ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 76d1ae746..911ce1eca 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -185,8 +185,9 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo program_id=self._program_id(), options=runtime_options, inputs=primitive_inputs, - callback=combined.get("environment", {}).get("callback", None), - result_decoder=DEFAULT_DECODERS.get(self._program_id()), + # are these relevant for simulators? + # callback=combined.get("environment", {}).get("callback", None), + # result_decoder=DEFAULT_DECODERS.get(self._program_id()), ) if self._session: return self._session.run( @@ -196,6 +197,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()), ) + if self._backend: runtime_options["backend"] = self._backend.name if "instance" not in runtime_options: diff --git a/qiskit_ibm_runtime/fake_runtime_job.py b/qiskit_ibm_runtime/fake_runtime_job.py index 6338ad514..1a35e520f 100644 --- a/qiskit_ibm_runtime/fake_runtime_job.py +++ b/qiskit_ibm_runtime/fake_runtime_job.py @@ -19,7 +19,7 @@ from qiskit.providers import JobError, JobStatus, JobV1 from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend -from .program.result_decoder import ResultDecoder +from .utils.result_decoder import ResultDecoder class FakeRuntimeJob(JobV1): """Representation of a runtime program execution on a simulator.""" @@ -75,4 +75,4 @@ def submit(self) -> None: raise NotImplementedError( "job.submit() is not supported. Please use " "QiskitRuntimeService.run() to submit a job." - ) \ No newline at end of file + ) diff --git a/qiskit_ibm_runtime/options/utils.py b/qiskit_ibm_runtime/options/utils.py index 9464a0448..a76d734d7 100644 --- a/qiskit_ibm_runtime/options/utils.py +++ b/qiskit_ibm_runtime/options/utils.py @@ -12,7 +12,6 @@ """Utility functions for options.""" -#from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend from qiskit.providers.fake_provider import fake_backend from ..ibm_backend import IBMBackend @@ -34,20 +33,15 @@ def set_default_error_levels( Returns: options with correct error level defaults. """ + is_simulator = isinstance(backend, fake_backend.FakeBackendV2) or backend.configuration().simulator if options.get("optimization_level") is None: - if ( - (isinstance(backend, fake_backend.FakeBackendV2) or backend.configuration().simulator) - and options.get("simulator", {}).get("noise_model") is None - ): + if is_simulator and options.get("simulator", {}).get("noise_model") is None: options["optimization_level"] = 1 else: options["optimization_level"] = default_optimization_level if options.get("resilience_level") is None: - if ( - (isinstance(backend, fake_backend.FakeBackendV2) or backend.configuration().simulator) - and options.get("simulator", {}).get("noise_model") is None - ): + if is_simulator and options.get("simulator", {}).get("noise_model") is None: options["resilience_level"] = 0 else: options["resilience_level"] = default_resilience_level diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index c4951f6c9..2031a2461 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -843,6 +843,10 @@ def backend( def get_backend(self, name: str = None, **kwargs: Any) -> Backend: return self.backend(name, **kwargs) + def _get_fake_backend(self, name: str) -> fake_backend.FakeBackendV2: + my_fake_backend = fake_backend_list[name] + return my_fake_backend + def run( self, program_id: str, From 9afe8b3ba2ce2c3374191293782bb3e5fddcf504 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 29 Nov 2023 12:40:30 +0000 Subject: [PATCH 06/42] Cleaning up --- qiskit_ibm_runtime/qiskit_runtime_service.py | 43 +++++--------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 2031a2461..7aa9580c2 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -24,7 +24,6 @@ from qiskit_aer.backends.aerbackend import AerBackend from qiskit_aer.primitives import Sampler as AerSampler from qiskit_aer.primitives import Estimator as AerEstimator -#from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend from qiskit.providers.fake_provider import fake_backend from qiskit.providers.backend import BackendV1 as Backend from qiskit.providers.provider import ProviderV1 as Provider @@ -594,9 +593,9 @@ def backends( if self._channel == "ibm_quantum": if name: if name not in self._backends: - fake_backend = self._get_fake_backend(name) - if fake_backend: - backends.append(fake_backend) + backend = self._get_fake_backend(name) + if backend: + backends.append(backend) return backends raise QiskitBackendNotFoundError("No backend matches the criteria.") if not self._backends[name] or instance != self._backends[name]._instance: @@ -822,15 +821,12 @@ def backend( """ # pylint: disable=arguments-differ, line-too-long if name and name not in self._backends: - my_fake_backend = self._get_fake_backend(name) - if my_fake_backend: - return my_fake_backend + backend = self._get_fake_backend(name) + if backend: + return backend backends = self.backends(name, instance=instance) if not backends: - # fake_backend = self._get_fake_backend(name) - # if fake_backend: - # return fake_backend cloud_msg_url = "" if self._channel == "ibm_cloud": cloud_msg_url = ( @@ -844,8 +840,8 @@ def get_backend(self, name: str = None, **kwargs: Any) -> Backend: return self.backend(name, **kwargs) def _get_fake_backend(self, name: str) -> fake_backend.FakeBackendV2: - my_fake_backend = fake_backend_list[name] - return my_fake_backend + backend = fake_backend_list[name] + return backend def run( self, @@ -905,33 +901,19 @@ def run( is_aer_backend = False # if backend is a simulator, run locally if isinstance(qrt_options.backend, AerSimulator): - is_aer_simulator = True + is_aer_backend = True if program_id == "sampler": prog = AerSampler else: #program_id == "estimator": prog = AerEstimator - elif isinstance(qrt_options.backend, fake_backend.FakeBackendV2): - #return FakeRuntimeJob(AerSampler.run(...)) + if isinstance(qrt_options.backend, fake_backend.FakeBackendV2): is_fake_backend= True if program_id == "sampler": prog = BackendSampler else: #program_id == "estimator": prog = BackendEstimator - else: - is_simulation = False - # elif isinstance(qrt_options.backend, fake_backend.FakeBackendV2): - # #from qiskit_ibm_runtime.options import Options - # if program_id == "sampler": - # sampler = BackendSa - # - # else:mpler( - # backend=qrt_options.backend, - # options=sim_options, - # skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"], - # ) - if is_fake_backend: my_program = prog(backend=qrt_options.backend, options=sim_options, @@ -954,7 +936,7 @@ def run( ) return fake_runtime_job - if is_aer_simulator: + if is_aer_backend: aer_backend_options = {} for opt in inputs["run_options"]: if hasattr(AerSimulator._default_options(), opt): @@ -982,9 +964,6 @@ def run( ) return fake_runtime_job - #primitive_job = BackendSampler.run(...) - #return FakeRuntimeJob(primitive_job) - hgp_name = None if self._channel == "ibm_quantum": # Find the right hgp From 9e0d7ff849e7f2901c178febfd50287dcfe8f0e9 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 29 Nov 2023 13:52:24 +0000 Subject: [PATCH 07/42] Added sample test --- qiskit_ibm_runtime/base_primitive.py | 6 +-- qiskit_ibm_runtime/fake_runtime_job.py | 9 ++-- qiskit_ibm_runtime/options/utils.py | 4 +- qiskit_ibm_runtime/qiskit_runtime_service.py | 50 +++++++++++--------- qiskit_ibm_runtime/utils/fake_backends.py | 49 ++++++++++++++++++- test/unit/test_run_simulation.py | 40 ++++++++++++++++ 6 files changed, 126 insertions(+), 32 deletions(-) create mode 100644 test/unit/test_run_simulation.py diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 911ce1eca..dafb3e7c6 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -176,8 +176,8 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo runtime_options = Options._get_runtime_options(combined) if run_simulator: - runtime_options["backend"] = self._backend #fix this - for cloud, is str, - # for fake is Backend + runtime_options["backend"] = self._backend # fix this - for cloud, is str, + # for fake is Backend print("runtime options = ", runtime_options) print("inputs ", primitive_inputs) @@ -188,7 +188,7 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo # are these relevant for simulators? # callback=combined.get("environment", {}).get("callback", None), # result_decoder=DEFAULT_DECODERS.get(self._program_id()), - ) + ) if self._session: return self._session.run( program_id=self._program_id(), diff --git a/qiskit_ibm_runtime/fake_runtime_job.py b/qiskit_ibm_runtime/fake_runtime_job.py index 1a35e520f..84e689393 100644 --- a/qiskit_ibm_runtime/fake_runtime_job.py +++ b/qiskit_ibm_runtime/fake_runtime_job.py @@ -21,6 +21,7 @@ from .utils.result_decoder import ResultDecoder + class FakeRuntimeJob(JobV1): """Representation of a runtime program execution on a simulator.""" @@ -33,9 +34,9 @@ def __init__( service: "qiskit_runtime_service.QiskitRuntimeService", params: Optional[Dict] = None, creation_date: Optional[str] = None, - #user_callback: Optional[Callable] = None, - #result_decoder: Optional[Union[Type[ResultDecoder], Sequence[Type[ResultDecoder]]]] = None, - #tags: Optional[List] = None, + # user_callback: Optional[Callable] = None, + # result_decoder: Optional[Union[Type[ResultDecoder], Sequence[Type[ResultDecoder]]]] = None, + # tags: Optional[List] = None, ) -> None: """FakeRuntimeJob constructor.""" super().__init__(backend=backend, job_id=job_id) @@ -51,7 +52,7 @@ def result(self) -> Any: def cancel(self): self._primitive_job.cancel() - def status(self)-> JobStatus: + def status(self) -> JobStatus: return self._primitive_job.status() @property diff --git a/qiskit_ibm_runtime/options/utils.py b/qiskit_ibm_runtime/options/utils.py index a76d734d7..842699e4f 100644 --- a/qiskit_ibm_runtime/options/utils.py +++ b/qiskit_ibm_runtime/options/utils.py @@ -33,7 +33,9 @@ def set_default_error_levels( Returns: options with correct error level defaults. """ - is_simulator = isinstance(backend, fake_backend.FakeBackendV2) or backend.configuration().simulator + is_simulator = ( + isinstance(backend, fake_backend.FakeBackendV2) or backend.configuration().simulator + ) if options.get("optimization_level") is None: if is_simulator and options.get("simulator", {}).get("noise_model") is None: options["optimization_level"] = 1 diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 7aa9580c2..78375584b 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -21,7 +21,7 @@ from typing import Dict, Callable, Optional, Union, List, Any, Type, Sequence from qiskit_aer import AerSimulator -from qiskit_aer.backends.aerbackend import AerBackend +#from qiskit_aer.backends.aerbackend import AerBackend from qiskit_aer.primitives import Sampler as AerSampler from qiskit_aer.primitives import Estimator as AerEstimator from qiskit.providers.fake_provider import fake_backend @@ -33,7 +33,7 @@ PulseBackendConfiguration, QasmBackendConfiguration, ) -from qiskit.primitives.primitive_job import PrimitiveJob +#from qiskit.primitives.primitive_job import PrimitiveJob from qiskit.primitives import BackendSampler, BackendEstimator from qiskit_ibm_provider.proxies import ProxyConfiguration @@ -904,28 +904,30 @@ def run( is_aer_backend = True if program_id == "sampler": prog = AerSampler - else: #program_id == "estimator": + else: # program_id == "estimator": prog = AerEstimator if isinstance(qrt_options.backend, fake_backend.FakeBackendV2): - is_fake_backend= True + is_fake_backend = True if program_id == "sampler": prog = BackendSampler - else: #program_id == "estimator": + else: # program_id == "estimator": prog = BackendEstimator if is_fake_backend: - my_program = prog(backend=qrt_options.backend, - options=sim_options, - skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"] - ) + my_program = prog( + backend=qrt_options.backend, + options=sim_options, + skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"], + ) observables = inputs.get("observables", None) - primitive_job = my_program._run(circuits=inputs["circuits"], - parameter_values=inputs["parameters"], - run_options=sim_options, - observables=observables - ) + primitive_job = my_program._run( + circuits=inputs["circuits"], + parameter_values=inputs["parameters"], + run_options=sim_options, + observables=observables, + ) fake_runtime_job = FakeRuntimeJob( primitive_job=primitive_job, backend=qrt_options.backend, @@ -943,17 +945,19 @@ def run( aer_backend_options[opt] = inputs["run_options"][opt] print("aer_config", aer_backend_options) - my_program = prog(backend_options=aer_backend_options, - transpile_options=inputs["transpilation_settings"], - skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"] - ) + my_program = prog( + backend_options=aer_backend_options, + transpile_options=inputs["transpilation_settings"], + skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"], + ) observables = inputs.get("observables", None) - primitive_job = my_program._run(circuits=inputs["circuits"], - parameter_values=inputs["parameters"], - run_options=sim_options, - observables=observables - ) + primitive_job = my_program._run( + circuits=inputs["circuits"], + parameter_values=inputs["parameters"], + run_options=sim_options, + observables=observables, + ) fake_runtime_job = FakeRuntimeJob( primitive_job=primitive_job, backend=qrt_options.backend, diff --git a/qiskit_ibm_runtime/utils/fake_backends.py b/qiskit_ibm_runtime/utils/fake_backends.py index 58baa9f39..2f0421fa2 100644 --- a/qiskit_ibm_runtime/utils/fake_backends.py +++ b/qiskit_ibm_runtime/utils/fake_backends.py @@ -1,4 +1,51 @@ -from qiskit.providers.fake_provider.backends import * +from qiskit.providers.fake_provider.backends import ( + FakeAlmadenV2, + FakeArmonkV2, + FakeAthensV2, + FakeAuckland, + FakeBelemV2, + FakeBoeblingenV2, + FakeBogotaV2, + FakeBrooklynV2, + FakeBurlingtonV2, + FakeCairoV2, + FakeCambridgeV2, + FakeCasablancaV2, + FakeEssexV2, + FakeGeneva, + FakeGuadalupeV2, + FakeHanoiV2, + FakeJakartaV2, + FakeJohannesburgV2, + FakeKolkataV2, + FakeLagosV2, + FakeLimaV2, + FakeLondonV2, + FakeManhattanV2, + FakeManilaV2, + FakeMelbourneV2, + FakeMontrealV2, + FakeMumbaiV2, + FakeNairobiV2, + FakeOslo, + FakeOurenseV2, + FakeParisV2, + FakePerth, + FakePrague, + FakePoughkeepsieV2, + FakeQuitoV2, + FakeRochesterV2, + FakeRomeV2, + FakeSantiagoV2, + FakeSherbrooke, + FakeSingaporeV2, + FakeSydneyV2, + FakeTorontoV2, + FakeValenciaV2, + FakeVigoV2, + FakeWashingtonV2, + FakeYorktownV2, +) # BackendV2, Backends fake_backend_list = { diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py new file mode 100644 index 000000000..2b993a512 --- /dev/null +++ b/test/unit/test_run_simulation.py @@ -0,0 +1,40 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Tests for running locally on a simulator.""" + +from qiskit_aer import AerSimulator + +from qiskit.test.reference_circuits import ReferenceCircuits +from qiskit_ibm_runtime import QiskitRuntimeService, Sampler + +from ..ibm_test_case import IBMTestCase +from .mock.fake_runtime_service import FakeRuntimeService + + +class TestRunSimulation(IBMTestCase): + """Class for testing the Sampler class.""" + + def test_basic_flow(self): + """Test basic flow on simulator.""" + service = QiskitRuntimeService(channel="ibm_quantum") + shots = 1000 + for backend in ["manila", AerSimulator()]: + circuit = ReferenceCircuits.bell() + sampler = Sampler(backend=backend) + job = sampler.run(circuit, skip_transpilation=True, shots=shots) + result = job.result() + self.assertAlmostEqual(result.quasi_dists[0][0], 0.5, delta=0.2) + self.assertAlmostEqual(result.quasi_dists[0][3], 0.5, delta=0.2) + + # currently not working correctly for FakeBackend + # self.assertEqual(result.metadata[0]["shots"], shots) From a56063f8f465c5dda657ae3ed84663588fb3126d Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 29 Nov 2023 16:34:16 +0000 Subject: [PATCH 08/42] Fixed passing options to fake backend --- qiskit_ibm_runtime/base_primitive.py | 2 -- qiskit_ibm_runtime/qiskit_runtime_service.py | 9 +++------ test/unit/test_run_simulation.py | 5 +++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index dafb3e7c6..5e2214099 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -178,8 +178,6 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo if run_simulator: runtime_options["backend"] = self._backend # fix this - for cloud, is str, # for fake is Backend - print("runtime options = ", runtime_options) - print("inputs ", primitive_inputs) return self._service.run( program_id=self._program_id(), diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 78375584b..601d327b6 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -883,7 +883,6 @@ def run( RuntimeProgramNotFound: If the program cannot be found. IBMRuntimeError: An error occurred running the program. """ - print("inputs = ", inputs) qrt_options: RuntimeOptions = options if options is None: @@ -892,10 +891,8 @@ def run( qrt_options = RuntimeOptions(**options) qrt_options.validate(channel=self.channel) - # transpilation_options = inputs["transpilation_settings"] - # print("transpilation_options = ", transpilation_options) + sim_options = inputs["run_options"] - # print("simulator options = ", sim_options) is_fake_backend = False is_aer_backend = False @@ -925,8 +922,9 @@ def run( primitive_job = my_program._run( circuits=inputs["circuits"], parameter_values=inputs["parameters"], - run_options=sim_options, observables=observables, + **sim_options, + ) fake_runtime_job = FakeRuntimeJob( primitive_job=primitive_job, @@ -943,7 +941,6 @@ def run( for opt in inputs["run_options"]: if hasattr(AerSimulator._default_options(), opt): aer_backend_options[opt] = inputs["run_options"][opt] - print("aer_config", aer_backend_options) my_program = prog( backend_options=aer_backend_options, diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 2b993a512..ffa524c0c 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -26,7 +26,8 @@ class TestRunSimulation(IBMTestCase): def test_basic_flow(self): """Test basic flow on simulator.""" - service = QiskitRuntimeService(channel="ibm_quantum") + #service = QiskitRuntimeService(channel="ibm_quantum") + service = FakeRuntimeService() shots = 1000 for backend in ["manila", AerSimulator()]: circuit = ReferenceCircuits.bell() @@ -37,4 +38,4 @@ def test_basic_flow(self): self.assertAlmostEqual(result.quasi_dists[0][3], 0.5, delta=0.2) # currently not working correctly for FakeBackend - # self.assertEqual(result.metadata[0]["shots"], shots) + self.assertEqual(result.metadata[0]["shots"], shots) From 959445be0492d0705ef4acddbe2602f8fff83d5b Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Mon, 4 Dec 2023 12:09:44 +0000 Subject: [PATCH 09/42] Added set_transpile_options --- qiskit_ibm_runtime/options/options.py | 3 +++ qiskit_ibm_runtime/qiskit_runtime_service.py | 9 ++++++++- qiskit_ibm_runtime/utils/fake_backends.py | 2 +- test/unit/test_run_simulation.py | 1 - 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/qiskit_ibm_runtime/options/options.py b/qiskit_ibm_runtime/options/options.py index 063e76e5b..553eff78b 100644 --- a/qiskit_ibm_runtime/options/options.py +++ b/qiskit_ibm_runtime/options/options.py @@ -130,6 +130,9 @@ def _get_program_inputs(options: dict) -> dict: """ sim_options = options.get("simulator", {}) inputs = {} + + #do we need to keep the flat options as well, for passing to terra directly? + inputs["optimization_level"] = options["optimization_level"] inputs["transpilation_settings"] = options.get("transpilation", {}) inputs["transpilation_settings"].update( { diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 601d327b6..d2748a4eb 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -891,8 +891,14 @@ def run( qrt_options = RuntimeOptions(**options) qrt_options.validate(channel=self.channel) - + print() + print("inputs ", inputs) + print() sim_options = inputs["run_options"] + print("sim_options ",sim_options) + + transpile_options = {} + transpile_options["optimization_level"] = inputs["optimization_level"] #do we need additional options is_fake_backend = False is_aer_backend = False @@ -917,6 +923,7 @@ def run( options=sim_options, skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"], ) + my_program.set_transpile_options(**transpile_options) observables = inputs.get("observables", None) primitive_job = my_program._run( diff --git a/qiskit_ibm_runtime/utils/fake_backends.py b/qiskit_ibm_runtime/utils/fake_backends.py index 2f0421fa2..593d5ea1b 100644 --- a/qiskit_ibm_runtime/utils/fake_backends.py +++ b/qiskit_ibm_runtime/utils/fake_backends.py @@ -1,4 +1,4 @@ -from qiskit.providers.fake_provider.backends import ( +from qiskit_ibm_runtime.fake_provider.backends import ( FakeAlmadenV2, FakeArmonkV2, FakeAthensV2, diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index ffa524c0c..96335b544 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -37,5 +37,4 @@ def test_basic_flow(self): self.assertAlmostEqual(result.quasi_dists[0][0], 0.5, delta=0.2) self.assertAlmostEqual(result.quasi_dists[0][3], 0.5, delta=0.2) - # currently not working correctly for FakeBackend self.assertEqual(result.metadata[0]["shots"], shots) From 0bb8f03e98f904a94e99436bb6d0679f515fce77 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Tue, 5 Dec 2023 11:03:31 +0000 Subject: [PATCH 10/42] Fixed options parameters --- qiskit_ibm_runtime/qiskit_runtime_service.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index d2748a4eb..fe77d8548 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -891,14 +891,12 @@ def run( qrt_options = RuntimeOptions(**options) qrt_options.validate(channel=self.channel) - print() - print("inputs ", inputs) - print() - sim_options = inputs["run_options"] + + sim_options = inputs.get("run_options", None) if inputs else None print("sim_options ",sim_options) transpile_options = {} - transpile_options["optimization_level"] = inputs["optimization_level"] #do we need additional options + transpile_options["optimization_level"] = inputs.get("optimization_level", None) if inputs else None #do we need additional options is_fake_backend = False is_aer_backend = False @@ -928,8 +926,8 @@ def run( primitive_job = my_program._run( circuits=inputs["circuits"], - parameter_values=inputs["parameters"], observables=observables, + parameter_values=inputs["parameters"], **sim_options, ) @@ -958,9 +956,9 @@ def run( primitive_job = my_program._run( circuits=inputs["circuits"], - parameter_values=inputs["parameters"], - run_options=sim_options, observables=observables, + parameter_values=inputs["parameters"], + **sim_options ) fake_runtime_job = FakeRuntimeJob( primitive_job=primitive_job, From a83701e36efd344d5a4990ad2b56a505f6246f10 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Tue, 5 Dec 2023 11:19:19 +0000 Subject: [PATCH 11/42] lint and black --- qiskit_ibm_runtime/fake_runtime_job.py | 12 ++++-------- qiskit_ibm_runtime/options/options.py | 2 +- qiskit_ibm_runtime/qiskit_runtime_service.py | 16 ++++++++++------ test/unit/test_run_simulation.py | 8 ++++---- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/qiskit_ibm_runtime/fake_runtime_job.py b/qiskit_ibm_runtime/fake_runtime_job.py index 84e689393..701623b8c 100644 --- a/qiskit_ibm_runtime/fake_runtime_job.py +++ b/qiskit_ibm_runtime/fake_runtime_job.py @@ -12,16 +12,12 @@ """Qiskit fake runtime job.""" -from typing import Optional, Dict, Union, List, Type, Sequence, Any +from typing import Optional, Dict, Any from qiskit.primitives.primitive_job import PrimitiveJob -from qiskit.primitives.base.base_primitive import BasePrimitive -from qiskit.providers import JobError, JobStatus, JobV1 +from qiskit.providers import JobStatus, JobV1 from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend -from .utils.result_decoder import ResultDecoder - - class FakeRuntimeJob(JobV1): """Representation of a runtime program execution on a simulator.""" @@ -31,9 +27,9 @@ def __init__( backend: FakeBackend, job_id: str, program_id: str, - service: "qiskit_runtime_service.QiskitRuntimeService", + #service: "qiskit_runtime_service.QiskitRuntimeService", params: Optional[Dict] = None, - creation_date: Optional[str] = None, + # creation_date: Optional[str] = None, # user_callback: Optional[Callable] = None, # result_decoder: Optional[Union[Type[ResultDecoder], Sequence[Type[ResultDecoder]]]] = None, # tags: Optional[List] = None, diff --git a/qiskit_ibm_runtime/options/options.py b/qiskit_ibm_runtime/options/options.py index 553eff78b..15e343664 100644 --- a/qiskit_ibm_runtime/options/options.py +++ b/qiskit_ibm_runtime/options/options.py @@ -131,7 +131,7 @@ def _get_program_inputs(options: dict) -> dict: sim_options = options.get("simulator", {}) inputs = {} - #do we need to keep the flat options as well, for passing to terra directly? + # do we need to keep the flat options as well, for passing to terra directly? inputs["optimization_level"] = options["optimization_level"] inputs["transpilation_settings"] = options.get("transpilation", {}) inputs["transpilation_settings"].update( diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index fe77d8548..7c1262394 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -21,7 +21,8 @@ from typing import Dict, Callable, Optional, Union, List, Any, Type, Sequence from qiskit_aer import AerSimulator -#from qiskit_aer.backends.aerbackend import AerBackend + +# from qiskit_aer.backends.aerbackend import AerBackend from qiskit_aer.primitives import Sampler as AerSampler from qiskit_aer.primitives import Estimator as AerEstimator from qiskit.providers.fake_provider import fake_backend @@ -33,7 +34,8 @@ PulseBackendConfiguration, QasmBackendConfiguration, ) -#from qiskit.primitives.primitive_job import PrimitiveJob + +# from qiskit.primitives.primitive_job import PrimitiveJob from qiskit.primitives import BackendSampler, BackendEstimator from qiskit_ibm_provider.proxies import ProxyConfiguration @@ -893,10 +895,12 @@ def run( qrt_options.validate(channel=self.channel) sim_options = inputs.get("run_options", None) if inputs else None - print("sim_options ",sim_options) + print("sim_options ", sim_options) transpile_options = {} - transpile_options["optimization_level"] = inputs.get("optimization_level", None) if inputs else None #do we need additional options + transpile_options["optimization_level"] = ( + inputs.get("optimization_level", None) if inputs else None + ) # do we need additional options is_fake_backend = False is_aer_backend = False @@ -915,6 +919,7 @@ def run( else: # program_id == "estimator": prog = BackendEstimator + # pylint: disable=unexpected-keyword-arg if is_fake_backend: my_program = prog( backend=qrt_options.backend, @@ -929,7 +934,6 @@ def run( observables=observables, parameter_values=inputs["parameters"], **sim_options, - ) fake_runtime_job = FakeRuntimeJob( primitive_job=primitive_job, @@ -958,7 +962,7 @@ def run( circuits=inputs["circuits"], observables=observables, parameter_values=inputs["parameters"], - **sim_options + **sim_options, ) fake_runtime_job = FakeRuntimeJob( primitive_job=primitive_job, diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 96335b544..5b17954bc 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -15,6 +15,7 @@ from qiskit_aer import AerSimulator from qiskit.test.reference_circuits import ReferenceCircuits +# pylint: disable=unused-import from qiskit_ibm_runtime import QiskitRuntimeService, Sampler from ..ibm_test_case import IBMTestCase @@ -22,12 +23,12 @@ class TestRunSimulation(IBMTestCase): - """Class for testing the Sampler class.""" def test_basic_flow(self): """Test basic flow on simulator.""" - #service = QiskitRuntimeService(channel="ibm_quantum") - service = FakeRuntimeService() + # service = QiskitRuntimeService(channel="ibm_quantum") + + service = FakeRuntimeService() # pylint: disable=unused-variable shots = 1000 for backend in ["manila", AerSimulator()]: circuit = ReferenceCircuits.bell() @@ -36,5 +37,4 @@ def test_basic_flow(self): result = job.result() self.assertAlmostEqual(result.quasi_dists[0][0], 0.5, delta=0.2) self.assertAlmostEqual(result.quasi_dists[0][3], 0.5, delta=0.2) - self.assertEqual(result.metadata[0]["shots"], shots) From 12fe17ce36e663bf77381ce8bc97e21ba89a2f3f Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Tue, 5 Dec 2023 13:55:42 +0000 Subject: [PATCH 12/42] Use fake_provider.py to get fake backends --- qiskit_ibm_runtime/base_primitive.py | 11 ++- .../fake_provider/fake_provider.py | 11 ++- qiskit_ibm_runtime/fake_runtime_job.py | 4 +- qiskit_ibm_runtime/qiskit_runtime_service.py | 17 ++-- qiskit_ibm_runtime/utils/fake_backends.py | 98 ------------------- test/unit/test_run_simulation.py | 5 +- 6 files changed, 26 insertions(+), 120 deletions(-) delete mode 100644 qiskit_ibm_runtime/utils/fake_backends.py diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 5e2214099..c06cc6573 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -20,12 +20,13 @@ from dataclasses import asdict import warnings -from qiskit.providers.options import Options as TerraOptions -from qiskit.providers.fake_provider import fake_backend from qiskit_aer import AerSimulator +from qiskit.providers.options import Options as TerraOptions + from qiskit_ibm_provider.session import get_cm_session as get_cm_provider_session +from .fake_provider.fake_provider import FakeProviderForBackendV2 from .options import Options from .options.utils import set_default_error_levels from .runtime_job import RuntimeJob @@ -146,7 +147,10 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo Returns: Submitted job. """ - run_simulator = isinstance(self._backend, Union[fake_backend.FakeBackendV2, AerSimulator]) + run_simulator = ( + isinstance(self._backend, AerSimulator) + or FakeProviderForBackendV2().get_backend(self._backend.name) is not None + ) combined = Options._merge_options(self._options, user_kwargs) if self._backend: @@ -164,7 +168,6 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo combined = Options._set_default_resilience_options(combined) combined = Options._remove_none_values(combined) - primitive_inputs.update(Options._get_program_inputs(combined)) if self._backend and combined["transpilation"]["skip_transpilation"] and not run_simulator: diff --git a/qiskit_ibm_runtime/fake_provider/fake_provider.py b/qiskit_ibm_runtime/fake_provider/fake_provider.py index ccd1d704b..0100a4e50 100644 --- a/qiskit_ibm_runtime/fake_provider/fake_provider.py +++ b/qiskit_ibm_runtime/fake_provider/fake_provider.py @@ -70,13 +70,14 @@ class FakeProviderForBackendV2(ProviderV1): """ def get_backend(self, name=None, **kwargs): # type: ignore - backend = self._backends[0] + # backend = self._backends[0] + # when name=None, this will simply return Almaden. Is that what we want? if name: - filtered_backends = [backend for backend in self._backends if backend.name() == name] - if not filtered_backends: - raise QiskitBackendNotFoundError() + filtered_backends = [backend for backend in self.backends() if backend.name == name] + # if not filtered_backends: + # raise QiskitBackendNotFoundError() - backend = filtered_backends[0] + backend = filtered_backends[0] if len(filtered_backends) > 0 else None return backend diff --git a/qiskit_ibm_runtime/fake_runtime_job.py b/qiskit_ibm_runtime/fake_runtime_job.py index 701623b8c..8d30679b0 100644 --- a/qiskit_ibm_runtime/fake_runtime_job.py +++ b/qiskit_ibm_runtime/fake_runtime_job.py @@ -18,6 +18,7 @@ from qiskit.providers import JobStatus, JobV1 from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend + class FakeRuntimeJob(JobV1): """Representation of a runtime program execution on a simulator.""" @@ -27,7 +28,7 @@ def __init__( backend: FakeBackend, job_id: str, program_id: str, - #service: "qiskit_runtime_service.QiskitRuntimeService", + service: "qiskit_runtime_service.QiskitRuntimeService", params: Optional[Dict] = None, # creation_date: Optional[str] = None, # user_callback: Optional[Callable] = None, @@ -36,6 +37,7 @@ def __init__( ) -> None: """FakeRuntimeJob constructor.""" super().__init__(backend=backend, job_id=job_id) + self._service = service # do we need this? self._primitive_job = primitive_job self._job_id = job_id self._params = params or {} diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 7c1262394..d2e2bbe69 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -22,10 +22,8 @@ from qiskit_aer import AerSimulator -# from qiskit_aer.backends.aerbackend import AerBackend from qiskit_aer.primitives import Sampler as AerSampler from qiskit_aer.primitives import Estimator as AerEstimator -from qiskit.providers.fake_provider import fake_backend from qiskit.providers.backend import BackendV1 as Backend from qiskit.providers.provider import ProviderV1 as Provider from qiskit.providers.exceptions import QiskitBackendNotFoundError @@ -35,7 +33,6 @@ QasmBackendConfiguration, ) -# from qiskit.primitives.primitive_job import PrimitiveJob from qiskit.primitives import BackendSampler, BackendEstimator from qiskit_ibm_provider.proxies import ProxyConfiguration @@ -44,7 +41,7 @@ from qiskit_ibm_runtime import ibm_backend from .fake_runtime_job import FakeRuntimeJob -from .utils.fake_backends import fake_backend_list +from .fake_provider.fake_provider import FakeProviderForBackendV2 from .utils.utils import validate_job_tags from .accounts import AccountManager, Account, ChannelType from .api.clients import AuthClient, VersionClient @@ -550,7 +547,7 @@ def backends( instance: Optional[str] = None, filters: Optional[Callable[[List["ibm_backend.IBMBackend"]], bool]] = None, **kwargs: Any, - ) -> Union[List["ibm_backend.IBMBackend"], List[fake_backend.FakeBackendV2]]: + ) -> Union[List["ibm_backend.IBMBackend"], List[FakeProviderForBackendV2]]: """Return all backends accessible via this account, subject to optional filtering. Args: @@ -590,7 +587,7 @@ def backends( QiskitBackendNotFoundError: If the backend is not in any instance. """ # TODO filter out input_allowed not having runtime - backends: Union[List[IBMBackend], List[fake_backend.FakeBackendV2]] = [] + backends: Union[List[IBMBackend], List[FakeProviderForBackendV2]] = [] instance_filter = instance if instance else self._account.instance if self._channel == "ibm_quantum": if name: @@ -805,7 +802,7 @@ def backend( self, name: str = None, instance: Optional[str] = None, - ) -> Union[Backend, fake_backend.FakeBackendV2]: + ) -> Union[Backend, FakeProviderForBackendV2]: """Return a single backend matching the specified filtering. Args: @@ -841,8 +838,8 @@ def backend( def get_backend(self, name: str = None, **kwargs: Any) -> Backend: return self.backend(name, **kwargs) - def _get_fake_backend(self, name: str) -> fake_backend.FakeBackendV2: - backend = fake_backend_list[name] + def _get_fake_backend(self, name: str) -> FakeProviderForBackendV2: + backend = FakeProviderForBackendV2().get_backend(name) return backend def run( @@ -912,7 +909,7 @@ def run( else: # program_id == "estimator": prog = AerEstimator - if isinstance(qrt_options.backend, fake_backend.FakeBackendV2): + if FakeProviderForBackendV2().get_backend(qrt_options.backend.name) is not None: is_fake_backend = True if program_id == "sampler": prog = BackendSampler diff --git a/qiskit_ibm_runtime/utils/fake_backends.py b/qiskit_ibm_runtime/utils/fake_backends.py deleted file mode 100644 index 593d5ea1b..000000000 --- a/qiskit_ibm_runtime/utils/fake_backends.py +++ /dev/null @@ -1,98 +0,0 @@ -from qiskit_ibm_runtime.fake_provider.backends import ( - FakeAlmadenV2, - FakeArmonkV2, - FakeAthensV2, - FakeAuckland, - FakeBelemV2, - FakeBoeblingenV2, - FakeBogotaV2, - FakeBrooklynV2, - FakeBurlingtonV2, - FakeCairoV2, - FakeCambridgeV2, - FakeCasablancaV2, - FakeEssexV2, - FakeGeneva, - FakeGuadalupeV2, - FakeHanoiV2, - FakeJakartaV2, - FakeJohannesburgV2, - FakeKolkataV2, - FakeLagosV2, - FakeLimaV2, - FakeLondonV2, - FakeManhattanV2, - FakeManilaV2, - FakeMelbourneV2, - FakeMontrealV2, - FakeMumbaiV2, - FakeNairobiV2, - FakeOslo, - FakeOurenseV2, - FakeParisV2, - FakePerth, - FakePrague, - FakePoughkeepsieV2, - FakeQuitoV2, - FakeRochesterV2, - FakeRomeV2, - FakeSantiagoV2, - FakeSherbrooke, - FakeSingaporeV2, - FakeSydneyV2, - FakeTorontoV2, - FakeValenciaV2, - FakeVigoV2, - FakeWashingtonV2, - FakeYorktownV2, -) - -# BackendV2, Backends -fake_backend_list = { - "almaden": FakeAlmadenV2(), - "armonk": FakeArmonkV2(), - "athens": FakeAthensV2(), - "auckland": FakeAuckland(), - "belem": FakeBelemV2(), - "boeblingen": FakeBoeblingenV2(), - "bogota": FakeBogotaV2(), - "brooklyn": FakeBrooklynV2(), - "burlington": FakeBurlingtonV2(), - "cairo": FakeCairoV2(), - "cambridge": FakeCambridgeV2(), - "casablanca": FakeCasablancaV2(), - "essex": FakeEssexV2(), - "geneva": FakeGeneva(), - "guadalupe": FakeGuadalupeV2(), - "hanoi": FakeHanoiV2(), - "jakarta": FakeJakartaV2(), - "johannesburg": FakeJohannesburgV2(), - "kolkata": FakeKolkataV2(), - "lagos": FakeLagosV2(), - "lima": FakeLimaV2(), - "london": FakeLondonV2(), - "manhattan": FakeManhattanV2(), - "manila": FakeManilaV2(), - "melbourne": FakeMelbourneV2(), - "montreal": FakeMontrealV2(), - "mumbai": FakeMumbaiV2(), - "nairobi": FakeNairobiV2(), - "oslo": FakeOslo(), - "ourense": FakeOurenseV2(), - "paris": FakeParisV2(), - "perth": FakePerth(), - "prague": FakePrague(), - "poughkeepsie": FakePoughkeepsieV2(), - "quito": FakeQuitoV2(), - "rochester": FakeRochesterV2(), - "rome": FakeRomeV2(), - "santiago": FakeSantiagoV2(), - "sherbrooke": FakeSherbrooke(), - "singapore": FakeSingaporeV2(), - "sydney": FakeSydneyV2(), - "toronto": FakeTorontoV2(), - "valencia": FakeValenciaV2(), - "vigo": FakeVigoV2(), - "washington": FakeWashingtonV2(), - "yorktown": FakeYorktownV2(), -} diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 5b17954bc..c6464e472 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -15,6 +15,7 @@ from qiskit_aer import AerSimulator from qiskit.test.reference_circuits import ReferenceCircuits + # pylint: disable=unused-import from qiskit_ibm_runtime import QiskitRuntimeService, Sampler @@ -23,14 +24,14 @@ class TestRunSimulation(IBMTestCase): - + """ Tests for local execution on simulators""" def test_basic_flow(self): """Test basic flow on simulator.""" # service = QiskitRuntimeService(channel="ibm_quantum") service = FakeRuntimeService() # pylint: disable=unused-variable shots = 1000 - for backend in ["manila", AerSimulator()]: + for backend in ["fake_manila", AerSimulator()]: circuit = ReferenceCircuits.bell() sampler = Sampler(backend=backend) job = sampler.run(circuit, skip_transpilation=True, shots=shots) From b4072affe8c734bab2b11f2729b57af6214f202e Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Tue, 5 Dec 2023 15:37:45 +0000 Subject: [PATCH 13/42] Added estimator to test --- qiskit_ibm_runtime/qiskit_runtime_service.py | 6 +++--- test/unit/test_run_simulation.py | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index d2e2bbe69..07af230fe 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -947,11 +947,11 @@ def run( for opt in inputs["run_options"]: if hasattr(AerSimulator._default_options(), opt): aer_backend_options[opt] = inputs["run_options"][opt] - + print("transpile options = ", inputs["transpilation_settings"]) my_program = prog( backend_options=aer_backend_options, - transpile_options=inputs["transpilation_settings"], - skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"], + transpile_options=transpile_options, + # skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"], ) observables = inputs.get("observables", None) diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index c6464e472..b048160d8 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -13,29 +13,36 @@ """Tests for running locally on a simulator.""" from qiskit_aer import AerSimulator - +from qiskit.quantum_info import SparsePauliOp from qiskit.test.reference_circuits import ReferenceCircuits # pylint: disable=unused-import -from qiskit_ibm_runtime import QiskitRuntimeService, Sampler +from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Estimator from ..ibm_test_case import IBMTestCase from .mock.fake_runtime_service import FakeRuntimeService class TestRunSimulation(IBMTestCase): - """ Tests for local execution on simulators""" + """Tests for local execution on simulators""" + def test_basic_flow(self): """Test basic flow on simulator.""" # service = QiskitRuntimeService(channel="ibm_quantum") service = FakeRuntimeService() # pylint: disable=unused-variable - shots = 1000 + shots = 100 + circuit = ReferenceCircuits.bell() for backend in ["fake_manila", AerSimulator()]: - circuit = ReferenceCircuits.bell() sampler = Sampler(backend=backend) job = sampler.run(circuit, skip_transpilation=True, shots=shots) result = job.result() self.assertAlmostEqual(result.quasi_dists[0][0], 0.5, delta=0.2) self.assertAlmostEqual(result.quasi_dists[0][3], 0.5, delta=0.2) self.assertEqual(result.metadata[0]["shots"], shots) + + estimator = Estimator(backend=backend) + obs = SparsePauliOp("ZZ") + job = estimator.run([circuit], observables=obs) + result = job.result() + self.assertAlmostEqual(result.values[0], 1.0, delta=0.01) From fb283232582809591c5f4373bf88f7056440bae3 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Tue, 5 Dec 2023 17:01:40 +0000 Subject: [PATCH 14/42] Added check that fake_backend is not IBMBackend, for test suite --- qiskit_ibm_runtime/base_primitive.py | 7 ++++--- qiskit_ibm_runtime/qiskit_runtime_service.py | 7 +++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index c06cc6573..f83abf81d 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -147,10 +147,11 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo Returns: Submitted job. """ - run_simulator = ( - isinstance(self._backend, AerSimulator) - or FakeProviderForBackendV2().get_backend(self._backend.name) is not None + run_simulator = isinstance(self._backend, AerSimulator) or ( + FakeProviderForBackendV2().get_backend(self._backend.name) is not None + and not isinstance(self._backend, IBMBackend) ) + combined = Options._merge_options(self._options, user_kwargs) if self._backend: diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 07af230fe..b363bf07c 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -32,7 +32,6 @@ PulseBackendConfiguration, QasmBackendConfiguration, ) - from qiskit.primitives import BackendSampler, BackendEstimator from qiskit_ibm_provider.proxies import ProxyConfiguration @@ -909,7 +908,11 @@ def run( else: # program_id == "estimator": prog = AerEstimator - if FakeProviderForBackendV2().get_backend(qrt_options.backend.name) is not None: + if ( + not isinstance(qrt_options.backend, str) # for fake backends in test suite + and not isinstance(qrt_options.backend, IBMBackend) + and FakeProviderForBackendV2().get_backend(qrt_options.backend.name) is not None + ): is_fake_backend = True if program_id == "sampler": prog = BackendSampler From 1918431b4e559e7f912f9dfa3fe5f3b46b2a4e28 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Tue, 5 Dec 2023 20:09:35 +0000 Subject: [PATCH 15/42] lint --- test/unit/test_data_serialization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_data_serialization.py b/test/unit/test_data_serialization.py index 8011c6eff..40d7f824b 100644 --- a/test/unit/test_data_serialization.py +++ b/test/unit/test_data_serialization.py @@ -246,7 +246,7 @@ def test_result_decoder(self): decoder=result_decoder, ) with mock_wait_for_final_state(ibm_quantum_service, job): - result = job.result(decoder=decoder) + result = job.result(decoder=decoder) # pylint: disable=unexpected-keyword-arg self.assertIsInstance(result["serializable_class"], SerializableClass) def test_circuit_metadata(self): From a59784bb47f8a60215a3e652ec1fd7f54bbe1aaf Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 13:27:45 +0000 Subject: [PATCH 16/42] Fixes for mypy --- qiskit_ibm_runtime/fake_provider/fake_provider.py | 7 +++++-- qiskit_ibm_runtime/fake_runtime_job.py | 9 ++++++--- qiskit_ibm_runtime/qiskit_runtime_service.py | 13 +++++-------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/qiskit_ibm_runtime/fake_provider/fake_provider.py b/qiskit_ibm_runtime/fake_provider/fake_provider.py index 0100a4e50..9b8d6b81f 100644 --- a/qiskit_ibm_runtime/fake_provider/fake_provider.py +++ b/qiskit_ibm_runtime/fake_provider/fake_provider.py @@ -16,8 +16,11 @@ Fake provider class that provides access to fake backends. """ +from typing import List + from qiskit.providers.provider import ProviderV1 from qiskit.providers.exceptions import QiskitBackendNotFoundError +from qiskit.providers.fake_provider.fake_backend import FakeBackendV2 from .backends import * @@ -69,7 +72,7 @@ class FakeProviderForBackendV2(ProviderV1): available in the :mod:`qiskit_ibm_runtime.fake_provider`. """ - def get_backend(self, name=None, **kwargs): # type: ignore + def get_backend(self, name=None, **kwargs) -> FakeBackendV2: # type: ignore # backend = self._backends[0] # when name=None, this will simply return Almaden. Is that what we want? if name: @@ -81,7 +84,7 @@ def get_backend(self, name=None, **kwargs): # type: ignore return backend - def backends(self, name=None, **kwargs): # type: ignore + def backends(self, name=None, **kwargs) -> List[FakeBackendV2]: # type: ignore return self._backends def __init__(self) -> None: diff --git a/qiskit_ibm_runtime/fake_runtime_job.py b/qiskit_ibm_runtime/fake_runtime_job.py index 8d30679b0..29330b8ab 100644 --- a/qiskit_ibm_runtime/fake_runtime_job.py +++ b/qiskit_ibm_runtime/fake_runtime_job.py @@ -18,6 +18,9 @@ from qiskit.providers import JobStatus, JobV1 from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend +# pylint: disable=cyclic-import +#from .qiskit_runtime_service import QiskitRuntimeService + class FakeRuntimeJob(JobV1): """Representation of a runtime program execution on a simulator.""" @@ -28,7 +31,7 @@ def __init__( backend: FakeBackend, job_id: str, program_id: str, - service: "qiskit_runtime_service.QiskitRuntimeService", + #service: "qiskit_runtime_service.QiskitRuntimeService", params: Optional[Dict] = None, # creation_date: Optional[str] = None, # user_callback: Optional[Callable] = None, @@ -37,7 +40,7 @@ def __init__( ) -> None: """FakeRuntimeJob constructor.""" super().__init__(backend=backend, job_id=job_id) - self._service = service # do we need this? + #self._service = service # do we need this? self._primitive_job = primitive_job self._job_id = job_id self._params = params or {} @@ -47,7 +50,7 @@ def result(self) -> Any: """Return the results of the job.""" return self._primitive_job.result() - def cancel(self): + def cancel(self) -> None: self._primitive_job.cancel() def status(self) -> JobStatus: diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index b363bf07c..a8f783844 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -586,7 +586,7 @@ def backends( QiskitBackendNotFoundError: If the backend is not in any instance. """ # TODO filter out input_allowed not having runtime - backends: Union[List[IBMBackend], List[FakeProviderForBackendV2]] = [] + backends: List[Union[IBMBackend, FakeProviderForBackendV2]] = [] instance_filter = instance if instance else self._account.instance if self._channel == "ibm_quantum": if name: @@ -889,7 +889,6 @@ def run( qrt_options = RuntimeOptions(**options) qrt_options.validate(channel=self.channel) - sim_options = inputs.get("run_options", None) if inputs else None print("sim_options ", sim_options) @@ -909,11 +908,11 @@ def run( prog = AerEstimator if ( - not isinstance(qrt_options.backend, str) # for fake backends in test suite - and not isinstance(qrt_options.backend, IBMBackend) - and FakeProviderForBackendV2().get_backend(qrt_options.backend.name) is not None + not isinstance(qrt_options.backend, IBMBackend) + and not isinstance(qrt_options.backend, str) + and FakeProviderForBackendV2().get_backend(qrt_options.backend.name) is not None # type: ignore ): - is_fake_backend = True + is_fake_backend = True # type: ignore if program_id == "sampler": prog = BackendSampler else: # program_id == "estimator": @@ -940,7 +939,6 @@ def run( backend=qrt_options.backend, job_id=primitive_job.job_id(), program_id=program_id, - service=self, params=inputs["parameters"], ) return fake_runtime_job @@ -969,7 +967,6 @@ def run( backend=qrt_options.backend, job_id=primitive_job.job_id(), program_id=program_id, - service=self, params=inputs["parameters"], ) return fake_runtime_job From ee0ed3e733d076ddcd13ed987a43a90894565c94 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 13:31:16 +0000 Subject: [PATCH 17/42] black --- qiskit_ibm_runtime/fake_runtime_job.py | 6 +++--- qiskit_ibm_runtime/qiskit_runtime_service.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qiskit_ibm_runtime/fake_runtime_job.py b/qiskit_ibm_runtime/fake_runtime_job.py index 29330b8ab..4c24b6705 100644 --- a/qiskit_ibm_runtime/fake_runtime_job.py +++ b/qiskit_ibm_runtime/fake_runtime_job.py @@ -19,7 +19,7 @@ from qiskit.providers.fake_provider import FakeBackendV2 as FakeBackend # pylint: disable=cyclic-import -#from .qiskit_runtime_service import QiskitRuntimeService +# from .qiskit_runtime_service import QiskitRuntimeService class FakeRuntimeJob(JobV1): @@ -31,7 +31,7 @@ def __init__( backend: FakeBackend, job_id: str, program_id: str, - #service: "qiskit_runtime_service.QiskitRuntimeService", + # service: "qiskit_runtime_service.QiskitRuntimeService", params: Optional[Dict] = None, # creation_date: Optional[str] = None, # user_callback: Optional[Callable] = None, @@ -40,7 +40,7 @@ def __init__( ) -> None: """FakeRuntimeJob constructor.""" super().__init__(backend=backend, job_id=job_id) - #self._service = service # do we need this? + # self._service = service # do we need this? self._primitive_job = primitive_job self._job_id = job_id self._params = params or {} diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index a8f783844..4d97d3a12 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -910,7 +910,7 @@ def run( if ( not isinstance(qrt_options.backend, IBMBackend) and not isinstance(qrt_options.backend, str) - and FakeProviderForBackendV2().get_backend(qrt_options.backend.name) is not None # type: ignore + and FakeProviderForBackendV2().get_backend(qrt_options.backend.name) is not None # type: ignore ): is_fake_backend = True # type: ignore if program_id == "sampler": From a6516a38e75b637616aa4db62f3a173e6eb01c1d Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 13:39:16 +0000 Subject: [PATCH 18/42] black --- qiskit_ibm_runtime/qiskit_runtime_service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 4d97d3a12..69ed88efc 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -910,7 +910,8 @@ def run( if ( not isinstance(qrt_options.backend, IBMBackend) and not isinstance(qrt_options.backend, str) - and FakeProviderForBackendV2().get_backend(qrt_options.backend.name) is not None # type: ignore + and FakeProviderForBackendV2().get_backend(qrt_options.backend.name) + is not None # type: ignore ): is_fake_backend = True # type: ignore if program_id == "sampler": From e1166f8e2710ef793b835581c644ccc04d56827b Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 15:46:38 +0000 Subject: [PATCH 19/42] Fixed integration tests --- qiskit_ibm_runtime/base_primitive.py | 2 ++ qiskit_ibm_runtime/options/options.py | 2 -- qiskit_ibm_runtime/qiskit_runtime_service.py | 9 ++------- test/unit/test_run_simulation.py | 5 +++-- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index f83abf81d..cfddea88c 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -180,6 +180,8 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo runtime_options = Options._get_runtime_options(combined) if run_simulator: + # do we need to keep the flat options as well, for passing to terra directly? + primitive_inputs["optimization_level"] = combined["optimization_level"] runtime_options["backend"] = self._backend # fix this - for cloud, is str, # for fake is Backend diff --git a/qiskit_ibm_runtime/options/options.py b/qiskit_ibm_runtime/options/options.py index 15e343664..6df599359 100644 --- a/qiskit_ibm_runtime/options/options.py +++ b/qiskit_ibm_runtime/options/options.py @@ -131,8 +131,6 @@ def _get_program_inputs(options: dict) -> dict: sim_options = options.get("simulator", {}) inputs = {} - # do we need to keep the flat options as well, for passing to terra directly? - inputs["optimization_level"] = options["optimization_level"] inputs["transpilation_settings"] = options.get("transpilation", {}) inputs["transpilation_settings"].update( { diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 2822f264d..55a45433d 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -858,7 +858,7 @@ def run( result_decoder: Optional[Union[Type[ResultDecoder], Sequence[Type[ResultDecoder]]]] = None, session_id: Optional[str] = None, start_session: Optional[bool] = False, - ) -> RuntimeJob: + ) -> Union[RuntimeJob, FakeRuntimeJob]: """Execute the runtime program. Args: @@ -898,7 +898,6 @@ def run( qrt_options.validate(channel=self.channel) sim_options = inputs.get("run_options", None) if inputs else None - print("sim_options ", sim_options) transpile_options = {} transpile_options["optimization_level"] = ( @@ -926,7 +925,7 @@ def run( prog = BackendSampler else: # program_id == "estimator": prog = BackendEstimator - + print("skip =", inputs["transpilation_settings"]["skip_transpilation"]) # pylint: disable=unexpected-keyword-arg if is_fake_backend: my_program = prog( @@ -936,7 +935,6 @@ def run( ) my_program.set_transpile_options(**transpile_options) observables = inputs.get("observables", None) - primitive_job = my_program._run( circuits=inputs["circuits"], observables=observables, @@ -957,14 +955,12 @@ def run( for opt in inputs["run_options"]: if hasattr(AerSimulator._default_options(), opt): aer_backend_options[opt] = inputs["run_options"][opt] - print("transpile options = ", inputs["transpilation_settings"]) my_program = prog( backend_options=aer_backend_options, transpile_options=transpile_options, # skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"], ) observables = inputs.get("observables", None) - primitive_job = my_program._run( circuits=inputs["circuits"], observables=observables, @@ -1026,7 +1022,6 @@ def run( if response["backend"] else qrt_options.backend ) - job = RuntimeJob( backend=backend, api_client=self._api_client, diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index b048160d8..684ceb3ed 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -35,7 +35,7 @@ def test_basic_flow(self): circuit = ReferenceCircuits.bell() for backend in ["fake_manila", AerSimulator()]: sampler = Sampler(backend=backend) - job = sampler.run(circuit, skip_transpilation=True, shots=shots) + job = sampler.run(circuit, shots=shots) result = job.result() self.assertAlmostEqual(result.quasi_dists[0][0], 0.5, delta=0.2) self.assertAlmostEqual(result.quasi_dists[0][3], 0.5, delta=0.2) @@ -43,6 +43,7 @@ def test_basic_flow(self): estimator = Estimator(backend=backend) obs = SparsePauliOp("ZZ") - job = estimator.run([circuit], observables=obs) + job = estimator.run([circuit], observables=obs, shots=shots) result = job.result() self.assertAlmostEqual(result.values[0], 1.0, delta=0.01) + self.assertEqual(result.metadata[0]["shots"], shots) From 3d150f197215ff849dae2fed88002e7591a1865e Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 16:15:30 +0000 Subject: [PATCH 20/42] Added channel to constructor of FakeRuntimeService --- test/unit/test_run_simulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 684ceb3ed..36572eb83 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -30,7 +30,7 @@ def test_basic_flow(self): """Test basic flow on simulator.""" # service = QiskitRuntimeService(channel="ibm_quantum") - service = FakeRuntimeService() # pylint: disable=unused-variable + service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable shots = 100 circuit = ReferenceCircuits.bell() for backend in ["fake_manila", AerSimulator()]: From 8f2f5687251e92a19140f06c2c8986f6ddfb5eda Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 16:41:33 +0000 Subject: [PATCH 21/42] Added transfer of AerSimulator options along with test --- qiskit_ibm_runtime/base_primitive.py | 5 ++--- qiskit_ibm_runtime/qiskit_runtime_service.py | 3 +-- test/unit/test_run_simulation.py | 13 +++++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index cfddea88c..d7c65765e 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -182,14 +182,13 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo if run_simulator: # do we need to keep the flat options as well, for passing to terra directly? primitive_inputs["optimization_level"] = combined["optimization_level"] - runtime_options["backend"] = self._backend # fix this - for cloud, is str, - # for fake is Backend + runtime_options["backend"] = self._backend return self._service.run( program_id=self._program_id(), options=runtime_options, inputs=primitive_inputs, - # are these relevant for simulators? + # are the following relevant for simulators? # callback=combined.get("environment", {}).get("callback", None), # result_decoder=DEFAULT_DECODERS.get(self._program_id()), ) diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 55a45433d..227e2a0f9 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -951,14 +951,13 @@ def run( return fake_runtime_job if is_aer_backend: - aer_backend_options = {} + aer_backend_options = qrt_options.backend._options for opt in inputs["run_options"]: if hasattr(AerSimulator._default_options(), opt): aer_backend_options[opt] = inputs["run_options"][opt] my_program = prog( backend_options=aer_backend_options, transpile_options=transpile_options, - # skip_transpilation=inputs["transpilation_settings"]["skip_transpilation"], ) observables = inputs.get("observables", None) primitive_job = my_program._run( diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 36572eb83..d9f55fe0f 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -47,3 +47,16 @@ def test_basic_flow(self): result = job.result() self.assertAlmostEqual(result.values[0], 1.0, delta=0.01) self.assertEqual(result.metadata[0]["shots"], shots) + + def test_aer_sim_options(self): + service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable + shots = 100 + circuit = ReferenceCircuits.bell() + sim_methods =["statevector", "density_matrix", "stabilizer", "extended_stabilizer", "matrix_product_state"] + for method in sim_methods: + backend = AerSimulator(method=method) + sampler = Sampler(backend=backend) + job = sampler.run(circuit, shots=shots) + result = job.result() + print("***") + self.assertEqual(result.metadata[0]["simulator_metadata"]["method"], method) From 6da6e588fe84e07af91c524613760f2a5bef3727 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 17:49:51 +0000 Subject: [PATCH 22/42] attempt to fix account problem --- test/unit/test_run_simulation.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index d9f55fe0f..c786c1f61 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -11,7 +11,7 @@ # that they have been altered from the originals. """Tests for running locally on a simulator.""" - +from unittest.mock import MagicMock from qiskit_aer import AerSimulator from qiskit.quantum_info import SparsePauliOp from qiskit.test.reference_circuits import ReferenceCircuits @@ -30,7 +30,8 @@ def test_basic_flow(self): """Test basic flow on simulator.""" # service = QiskitRuntimeService(channel="ibm_quantum") - service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable + #service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable + service = MagicMock() # pylint: disable=unused-variable shots = 100 circuit = ReferenceCircuits.bell() for backend in ["fake_manila", AerSimulator()]: @@ -52,7 +53,13 @@ def test_aer_sim_options(self): service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable shots = 100 circuit = ReferenceCircuits.bell() - sim_methods =["statevector", "density_matrix", "stabilizer", "extended_stabilizer", "matrix_product_state"] + sim_methods = [ + "statevector", + "density_matrix", + "stabilizer", + "extended_stabilizer", + "matrix_product_state", + ] for method in sim_methods: backend = AerSimulator(method=method) sampler = Sampler(backend=backend) From 1b075472e389fcdd26267d125b5d24c5859f8c4f Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 17:55:33 +0000 Subject: [PATCH 23/42] Added doc string --- test/unit/test_run_simulation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index c786c1f61..40a3b36ec 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -30,7 +30,7 @@ def test_basic_flow(self): """Test basic flow on simulator.""" # service = QiskitRuntimeService(channel="ibm_quantum") - #service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable + # service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable service = MagicMock() # pylint: disable=unused-variable shots = 100 circuit = ReferenceCircuits.bell() @@ -50,6 +50,7 @@ def test_basic_flow(self): self.assertEqual(result.metadata[0]["shots"], shots) def test_aer_sim_options(self): + """ Test that options to Aer simulator are passed properly""" service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable shots = 100 circuit = ReferenceCircuits.bell() From d8b6b86fb5fa9420df277c5671a3accd48ae41a5 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 20:07:19 +0000 Subject: [PATCH 24/42] black --- test/unit/test_run_simulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 40a3b36ec..95578de44 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -50,7 +50,7 @@ def test_basic_flow(self): self.assertEqual(result.metadata[0]["shots"], shots) def test_aer_sim_options(self): - """ Test that options to Aer simulator are passed properly""" + """Test that options to Aer simulator are passed properly""" service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable shots = 100 circuit = ReferenceCircuits.bell() From 625066b45c6c170850da5c497aa9a1115f59fa4f Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 6 Dec 2023 20:13:05 +0000 Subject: [PATCH 25/42] mypy --- qiskit_ibm_runtime/qiskit_runtime_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 227e2a0f9..e538979cc 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -951,7 +951,7 @@ def run( return fake_runtime_job if is_aer_backend: - aer_backend_options = qrt_options.backend._options + aer_backend_options = qrt_options.backend._options # type:ignore for opt in inputs["run_options"]: if hasattr(AerSimulator._default_options(), opt): aer_backend_options[opt] = inputs["run_options"][opt] From 2157aad323e6d3154c675f1f12553b82211cf4cf Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Thu, 7 Dec 2023 11:52:02 +0000 Subject: [PATCH 26/42] Another attempt at fixing account. Removed print. --- qiskit_ibm_runtime/qiskit_runtime_service.py | 1 - test/unit/test_run_simulation.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index e538979cc..fc75b6052 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -925,7 +925,6 @@ def run( prog = BackendSampler else: # program_id == "estimator": prog = BackendEstimator - print("skip =", inputs["transpilation_settings"]["skip_transpilation"]) # pylint: disable=unexpected-keyword-arg if is_fake_backend: my_program = prog( diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 95578de44..e5cfb0139 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -31,7 +31,7 @@ def test_basic_flow(self): # service = QiskitRuntimeService(channel="ibm_quantum") # service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable - service = MagicMock() # pylint: disable=unused-variable + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") shots = 100 circuit = ReferenceCircuits.bell() for backend in ["fake_manila", AerSimulator()]: @@ -51,7 +51,7 @@ def test_basic_flow(self): def test_aer_sim_options(self): """Test that options to Aer simulator are passed properly""" - service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") shots = 100 circuit = ReferenceCircuits.bell() sim_methods = [ From 1959df6bcd738b254b8a7f65c495cd413409c441 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Thu, 7 Dec 2023 11:54:16 +0000 Subject: [PATCH 27/42] Removed unnecessary import --- test/unit/test_run_simulation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index e5cfb0139..a7796b6ef 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -11,7 +11,6 @@ # that they have been altered from the originals. """Tests for running locally on a simulator.""" -from unittest.mock import MagicMock from qiskit_aer import AerSimulator from qiskit.quantum_info import SparsePauliOp from qiskit.test.reference_circuits import ReferenceCircuits From 35678a3bb62b09cfc302eaece92160a56ed5c348 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Thu, 7 Dec 2023 12:04:53 +0000 Subject: [PATCH 28/42] lint --- test/unit/test_run_simulation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index a7796b6ef..5ebd7f19d 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -27,9 +27,7 @@ class TestRunSimulation(IBMTestCase): def test_basic_flow(self): """Test basic flow on simulator.""" - # service = QiskitRuntimeService(channel="ibm_quantum") - - # service = FakeRuntimeService(channel="ibm_quantum") # pylint: disable=unused-variable + # pylint: disable=unused-variable service = FakeRuntimeService(channel="ibm_quantum", token="my_token") shots = 100 circuit = ReferenceCircuits.bell() @@ -50,7 +48,9 @@ def test_basic_flow(self): def test_aer_sim_options(self): """Test that options to Aer simulator are passed properly""" + # pylint: disable=unused-variable service = FakeRuntimeService(channel="ibm_quantum", token="my_token") + shots = 100 circuit = ReferenceCircuits.bell() sim_methods = [ From a6e9379e6499bed822190b48b4c61f2e9e1ac1f1 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Thu, 7 Dec 2023 14:09:07 +0000 Subject: [PATCH 29/42] cleaning up --- qiskit_ibm_runtime/base_primitive.py | 3 ++- qiskit_ibm_runtime/fake_provider/fake_provider.py | 2 +- qiskit_ibm_runtime/options/options.py | 1 - qiskit_ibm_runtime/qiskit_runtime_service.py | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index d7c65765e..1335aa4fb 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -180,7 +180,8 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo runtime_options = Options._get_runtime_options(combined) if run_simulator: - # do we need to keep the flat options as well, for passing to terra directly? + # do we need to keep the other 'flat' options as well, + # for passing to terra directly? primitive_inputs["optimization_level"] = combined["optimization_level"] runtime_options["backend"] = self._backend diff --git a/qiskit_ibm_runtime/fake_provider/fake_provider.py b/qiskit_ibm_runtime/fake_provider/fake_provider.py index 9b8d6b81f..8f41cde7a 100644 --- a/qiskit_ibm_runtime/fake_provider/fake_provider.py +++ b/qiskit_ibm_runtime/fake_provider/fake_provider.py @@ -79,7 +79,7 @@ def get_backend(self, name=None, **kwargs) -> FakeBackendV2: # type: ignore filtered_backends = [backend for backend in self.backends() if backend.name == name] # if not filtered_backends: # raise QiskitBackendNotFoundError() - + # I prefer returning None rather than throwing an error. Any objection? backend = filtered_backends[0] if len(filtered_backends) > 0 else None return backend diff --git a/qiskit_ibm_runtime/options/options.py b/qiskit_ibm_runtime/options/options.py index 6df599359..063e76e5b 100644 --- a/qiskit_ibm_runtime/options/options.py +++ b/qiskit_ibm_runtime/options/options.py @@ -130,7 +130,6 @@ def _get_program_inputs(options: dict) -> dict: """ sim_options = options.get("simulator", {}) inputs = {} - inputs["transpilation_settings"] = options.get("transpilation", {}) inputs["transpilation_settings"].update( { diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index fc75b6052..bb6f9eb4c 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -37,9 +37,9 @@ from qiskit_ibm_provider.proxies import ProxyConfiguration from qiskit_ibm_provider.utils.hgp import to_instance_format, from_instance_format from qiskit_ibm_provider.utils.backend_decoder import configuration_from_server_data + from qiskit_ibm_runtime import ibm_backend from .fake_runtime_job import FakeRuntimeJob - from .fake_provider.fake_provider import FakeProviderForBackendV2 from .utils.utils import validate_job_tags from .accounts import AccountManager, Account, ChannelType @@ -889,7 +889,6 @@ def run( RuntimeProgramNotFound: If the program cannot be found. IBMRuntimeError: An error occurred running the program. """ - qrt_options: RuntimeOptions = options if options is None: qrt_options = RuntimeOptions() From 09aadbe6517098ea3edf5728c0ea4dbd2bf1ac51 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Thu, 7 Dec 2023 14:13:30 +0000 Subject: [PATCH 30/42] Release note --- releasenotes/notes/local_simulation-0e51bf28311f8591.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 releasenotes/notes/local_simulation-0e51bf28311f8591.yaml diff --git a/releasenotes/notes/local_simulation-0e51bf28311f8591.yaml b/releasenotes/notes/local_simulation-0e51bf28311f8591.yaml new file mode 100644 index 000000000..a89b696d4 --- /dev/null +++ b/releasenotes/notes/local_simulation-0e51bf28311f8591.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + When running on ``AerSimulator`` or on a ``FakeProviderForBackendV2``, the program will now locally + rather than running on the IBM Cloud. From acfeb20021bd766087c9aae2d51bbfb1326ef24c Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 13 Dec 2023 11:06:14 +0000 Subject: [PATCH 31/42] Added creation_date to FakeRuntimeJob --- qiskit_ibm_runtime/base_primitive.py | 3 --- qiskit_ibm_runtime/fake_runtime_job.py | 19 +++++++++++++------ qiskit_ibm_runtime/qiskit_runtime_service.py | 2 ++ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 1335aa4fb..6864a0cd5 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -189,9 +189,6 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo program_id=self._program_id(), options=runtime_options, inputs=primitive_inputs, - # are the following relevant for simulators? - # callback=combined.get("environment", {}).get("callback", None), - # result_decoder=DEFAULT_DECODERS.get(self._program_id()), ) if self._session: return self._session.run( diff --git a/qiskit_ibm_runtime/fake_runtime_job.py b/qiskit_ibm_runtime/fake_runtime_job.py index 4c24b6705..4d181c486 100644 --- a/qiskit_ibm_runtime/fake_runtime_job.py +++ b/qiskit_ibm_runtime/fake_runtime_job.py @@ -13,6 +13,7 @@ """Qiskit fake runtime job.""" from typing import Optional, Dict, Any +from datetime import datetime from qiskit.primitives.primitive_job import PrimitiveJob from qiskit.providers import JobStatus, JobV1 @@ -31,20 +32,16 @@ def __init__( backend: FakeBackend, job_id: str, program_id: str, - # service: "qiskit_runtime_service.QiskitRuntimeService", params: Optional[Dict] = None, - # creation_date: Optional[str] = None, - # user_callback: Optional[Callable] = None, - # result_decoder: Optional[Union[Type[ResultDecoder], Sequence[Type[ResultDecoder]]]] = None, - # tags: Optional[List] = None, + creation_date: Optional[str] = None, ) -> None: """FakeRuntimeJob constructor.""" super().__init__(backend=backend, job_id=job_id) - # self._service = service # do we need this? self._primitive_job = primitive_job self._job_id = job_id self._params = params or {} self._program_id = program_id + self._creation_date = creation_date def result(self) -> Any: """Return the results of the job.""" @@ -65,6 +62,16 @@ def inputs(self) -> Dict: """ return self._params + @property + def creation_date(self) -> Optional[datetime]: + """Job creation date in local time. + + Returns: + The job creation date as a datetime object, in local time, or + ``None`` if creation date is not available. + """ + return self._creation_date + def submit(self) -> None: """Unsupported method. Note: diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index bb6f9eb4c..cc266ffa8 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -945,6 +945,7 @@ def run( job_id=primitive_job.job_id(), program_id=program_id, params=inputs["parameters"], + creation_date=datetime.now() ) return fake_runtime_job @@ -970,6 +971,7 @@ def run( job_id=primitive_job.job_id(), program_id=program_id, params=inputs["parameters"], + creation_date=datetime.now() ) return fake_runtime_job From afa0c1ae0c323af5ac417d40bc67aad6fa134a4a Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 13 Dec 2023 12:36:55 +0000 Subject: [PATCH 32/42] Added creation_date and tags to FakeRuntimeJob --- qiskit_ibm_runtime/fake_runtime_job.py | 13 ++++++++++++- qiskit_ibm_runtime/qiskit_runtime_service.py | 6 ++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/qiskit_ibm_runtime/fake_runtime_job.py b/qiskit_ibm_runtime/fake_runtime_job.py index 4d181c486..492105f34 100644 --- a/qiskit_ibm_runtime/fake_runtime_job.py +++ b/qiskit_ibm_runtime/fake_runtime_job.py @@ -12,7 +12,7 @@ """Qiskit fake runtime job.""" -from typing import Optional, Dict, Any +from typing import Optional, Dict, Any, List from datetime import datetime from qiskit.primitives.primitive_job import PrimitiveJob @@ -34,6 +34,7 @@ def __init__( program_id: str, params: Optional[Dict] = None, creation_date: Optional[str] = None, + tags: Optional[List] = None, ) -> None: """FakeRuntimeJob constructor.""" super().__init__(backend=backend, job_id=job_id) @@ -42,6 +43,7 @@ def __init__( self._params = params or {} self._program_id = program_id self._creation_date = creation_date + self._tags = tags def result(self) -> Any: """Return the results of the job.""" @@ -72,6 +74,15 @@ def creation_date(self) -> Optional[datetime]: """ return self._creation_date + @property + def tags(self) -> List: + """Job tags. + + Returns: + Tags assigned to the job that can be used for filtering. + """ + return self._tags + def submit(self) -> None: """Unsupported method. Note: diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index cc266ffa8..bfe2269c9 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -945,7 +945,8 @@ def run( job_id=primitive_job.job_id(), program_id=program_id, params=inputs["parameters"], - creation_date=datetime.now() + creation_date=datetime.now(), + tags=qrt_options.job_tags ) return fake_runtime_job @@ -971,7 +972,8 @@ def run( job_id=primitive_job.job_id(), program_id=program_id, params=inputs["parameters"], - creation_date=datetime.now() + creation_date=datetime.now(), + tags=qrt_options.job_tags, ) return fake_runtime_job From af5fcef399e9eb1f9859ba628c2adc65708e6e45 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 13 Dec 2023 12:46:37 +0000 Subject: [PATCH 33/42] black --- qiskit_ibm_runtime/qiskit_runtime_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index bfe2269c9..429bcb837 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -946,7 +946,7 @@ def run( program_id=program_id, params=inputs["parameters"], creation_date=datetime.now(), - tags=qrt_options.job_tags + tags=qrt_options.job_tags, ) return fake_runtime_job From ea59600529e07eeed75f2508df0a5b07ec6d7d9f Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 13 Dec 2023 13:52:30 +0000 Subject: [PATCH 34/42] Added docstring. Removed comments that contained questions --- qiskit_ibm_runtime/fake_provider/fake_provider.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/qiskit_ibm_runtime/fake_provider/fake_provider.py b/qiskit_ibm_runtime/fake_provider/fake_provider.py index 8f41cde7a..d9e7e2d7b 100644 --- a/qiskit_ibm_runtime/fake_provider/fake_provider.py +++ b/qiskit_ibm_runtime/fake_provider/fake_provider.py @@ -72,16 +72,12 @@ class FakeProviderForBackendV2(ProviderV1): available in the :mod:`qiskit_ibm_runtime.fake_provider`. """ - def get_backend(self, name=None, **kwargs) -> FakeBackendV2: # type: ignore - # backend = self._backends[0] - # when name=None, this will simply return Almaden. Is that what we want? + def get_backend(self, name: str = None, **kwargs) -> FakeBackendV2: # type: ignore + """Return the backend according to its name. If kwargs are defined, then + additional filters may be applied. If no such backend, return None.""" if name: filtered_backends = [backend for backend in self.backends() if backend.name == name] - # if not filtered_backends: - # raise QiskitBackendNotFoundError() - # I prefer returning None rather than throwing an error. Any objection? backend = filtered_backends[0] if len(filtered_backends) > 0 else None - return backend def backends(self, name=None, **kwargs) -> List[FakeBackendV2]: # type: ignore From 22773c58cab0a1d14213d69941a081570884a12b Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 13 Dec 2023 14:03:21 +0000 Subject: [PATCH 35/42] Added support for FakeBackendV2 also when given as an object, not only name. --- qiskit_ibm_runtime/base_primitive.py | 3 ++- test/unit/test_run_simulation.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 6864a0cd5..72757226a 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -23,6 +23,7 @@ from qiskit_aer import AerSimulator from qiskit.providers.options import Options as TerraOptions +from qiskit.providers.fake_provider.fake_backend import FakeBackendV2 from qiskit_ibm_provider.session import get_cm_session as get_cm_provider_session @@ -101,7 +102,7 @@ def __init__( if isinstance(backend, IBMBackend): self._service = backend.service self._backend = backend - elif isinstance(backend, AerSimulator): + elif isinstance(backend, Union[AerSimulator, FakeBackendV2]): self._backend = backend self._service = ( QiskitRuntimeService() diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 5ebd7f19d..174ca8e4b 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -17,6 +17,7 @@ # pylint: disable=unused-import from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Estimator +from qiskit_ibm_runtime.fake_provider.backends.almaden import FakeAlmadenV2 from ..ibm_test_case import IBMTestCase from .mock.fake_runtime_service import FakeRuntimeService @@ -31,7 +32,7 @@ def test_basic_flow(self): service = FakeRuntimeService(channel="ibm_quantum", token="my_token") shots = 100 circuit = ReferenceCircuits.bell() - for backend in ["fake_manila", AerSimulator()]: + for backend in ["fake_manila", AerSimulator(), FakeAlmadenV2()]: sampler = Sampler(backend=backend) job = sampler.run(circuit, shots=shots) result = job.result() From 97a6868d8fb9e6131201bdcb937821abd9dfe8e7 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 13 Dec 2023 14:32:40 +0000 Subject: [PATCH 36/42] mypy --- qiskit_ibm_runtime/base_primitive.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 72757226a..4e493807f 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -20,6 +20,7 @@ from dataclasses import asdict import warnings + from qiskit_aer import AerSimulator from qiskit.providers.options import Options as TerraOptions @@ -47,7 +48,7 @@ class BasePrimitive(ABC): def __init__( self, - backend: Optional[Union[str, IBMBackend]] = None, + backend: Optional[Union[str, IBMBackend, FakeBackendV2]] = None, session: Optional[Union[Session, str, IBMBackend]] = None, options: Optional[Union[Dict, Options]] = None, ): @@ -78,7 +79,7 @@ def __init__( # a nested dictionary to categorize options. self._session: Optional[Session] = None self._service: QiskitRuntimeService = None - self._backend: Optional[IBMBackend] = None + self._backend: Optional[Union[IBMBackend, FakeBackendV2]] = None if options is None: self._options = asdict(Options()) @@ -102,7 +103,7 @@ def __init__( if isinstance(backend, IBMBackend): self._service = backend.service self._backend = backend - elif isinstance(backend, Union[AerSimulator, FakeBackendV2]): + elif isinstance(backend, (AerSimulator, FakeBackendV2)): self._backend = backend self._service = ( QiskitRuntimeService() From 606c902bcebc93c5c97a670aa1a65510dd9b41e7 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 13 Dec 2023 16:00:19 +0000 Subject: [PATCH 37/42] Added checks on importing Aer --- qiskit_ibm_runtime/base_primitive.py | 10 +++++++++- qiskit_ibm_runtime/qiskit_runtime_service.py | 14 +++++++++++++- test/unit/test_run_simulation.py | 7 ++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 4e493807f..8325d7c22 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -20,11 +20,16 @@ from dataclasses import asdict import warnings +try: + from qiskit_aer import AerSimulator -from qiskit_aer import AerSimulator + HAS_AER_SIMULATOR = True +except ImportError: + HAS_AER_SIMULATOR = False from qiskit.providers.options import Options as TerraOptions from qiskit.providers.fake_provider.fake_backend import FakeBackendV2 +from qiskit.providers.exceptions import QiskitBackendNotFoundError from qiskit_ibm_provider.session import get_cm_session as get_cm_provider_session @@ -81,6 +86,9 @@ def __init__( self._service: QiskitRuntimeService = None self._backend: Optional[Union[IBMBackend, FakeBackendV2]] = None + if isinstance(backend, (AerSimulator, FakeBackendV2)) and not HAS_AER_SIMULATOR: + raise QiskitBackendNotFoundError("To use an Aer Simulator, you must install aer") + if options is None: self._options = asdict(Options()) elif isinstance(options, Options): diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 429bcb837..3e49bc908 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -20,7 +20,12 @@ from collections import OrderedDict from typing import Dict, Callable, Optional, Union, List, Any, Type, Sequence -from qiskit_aer import AerSimulator +try: + from qiskit_aer import AerSimulator + + HAS_AER_SIMULATOR = True +except ImportError: + HAS_AER_SIMULATOR = False from qiskit_aer.primitives import Sampler as AerSampler from qiskit_aer.primitives import Estimator as AerEstimator @@ -33,6 +38,7 @@ QasmBackendConfiguration, ) from qiskit.primitives import BackendSampler, BackendEstimator +from qiskit.providers.fake_provider.fake_backend import FakeBackendV2 from qiskit_ibm_provider.proxies import ProxyConfiguration from qiskit_ibm_provider.utils.hgp import to_instance_format, from_instance_format @@ -888,6 +894,8 @@ def run( IBMInputValueError: If input is invalid. RuntimeProgramNotFound: If the program cannot be found. IBMRuntimeError: An error occurred running the program. + QiskitBackendNotFoundError: If backend is an AerSimulator or FakeBackendV2, + and aer is not installed. """ qrt_options: RuntimeOptions = options if options is None: @@ -905,6 +913,10 @@ def run( is_fake_backend = False is_aer_backend = False + + if isinstance(qrt_options.backend, (AerSimulator, FakeBackendV2)) and not HAS_AER_SIMULATOR: + raise QiskitBackendNotFoundError("To use an Aer Simulator, you must install aer") + # if backend is a simulator, run locally if isinstance(qrt_options.backend, AerSimulator): is_aer_backend = True diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 174ca8e4b..1bc23e161 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -11,8 +11,12 @@ # that they have been altered from the originals. """Tests for running locally on a simulator.""" + +import unittest + from qiskit_aer import AerSimulator from qiskit.quantum_info import SparsePauliOp +from qiskit.utils import optionals from qiskit.test.reference_circuits import ReferenceCircuits # pylint: disable=unused-import @@ -26,6 +30,7 @@ class TestRunSimulation(IBMTestCase): """Tests for local execution on simulators""" + @unittest.skipUnless(optionals.HAS_AER, "qiskit-aer is required to run this test") def test_basic_flow(self): """Test basic flow on simulator.""" # pylint: disable=unused-variable @@ -47,6 +52,7 @@ def test_basic_flow(self): self.assertAlmostEqual(result.values[0], 1.0, delta=0.01) self.assertEqual(result.metadata[0]["shots"], shots) + @unittest.skipUnless(optionals.HAS_AER, "qiskit-aer is required to run this test") def test_aer_sim_options(self): """Test that options to Aer simulator are passed properly""" # pylint: disable=unused-variable @@ -66,5 +72,4 @@ def test_aer_sim_options(self): sampler = Sampler(backend=backend) job = sampler.run(circuit, shots=shots) result = job.result() - print("***") self.assertEqual(result.metadata[0]["simulator_metadata"]["method"], method) From 6b8d07f3f4a5f463c2d3c8a7a4edc81814c1eaf8 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Thu, 14 Dec 2023 10:07:52 +0000 Subject: [PATCH 38/42] When backend is FakeBackendV2, don't modify resilience and optimization levels as for other simulators --- qiskit_ibm_runtime/options/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/options/utils.py b/qiskit_ibm_runtime/options/utils.py index 842699e4f..ff56962eb 100644 --- a/qiskit_ibm_runtime/options/utils.py +++ b/qiskit_ibm_runtime/options/utils.py @@ -33,8 +33,10 @@ def set_default_error_levels( Returns: options with correct error level defaults. """ + # The check that this is not a FakeBackendV2 is needed because FakeBackendV2 + # does not have a configuration is_simulator = ( - isinstance(backend, fake_backend.FakeBackendV2) or backend.configuration().simulator + not isinstance(backend, fake_backend.FakeBackendV2) and backend.configuration().simulator ) if options.get("optimization_level") is None: if is_simulator and options.get("simulator", {}).get("noise_model") is None: From 8830e76f232d2e176d99c698826baef241b8e344 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Thu, 14 Dec 2023 10:47:41 +0000 Subject: [PATCH 39/42] Added test for backend.run() on simulator --- test/unit/test_run_simulation.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/unit/test_run_simulation.py b/test/unit/test_run_simulation.py index 1bc23e161..80cf229c2 100644 --- a/test/unit/test_run_simulation.py +++ b/test/unit/test_run_simulation.py @@ -73,3 +73,18 @@ def test_aer_sim_options(self): job = sampler.run(circuit, shots=shots) result = job.result() self.assertEqual(result.metadata[0]["simulator_metadata"]["method"], method) + + def test_run_backend_on_simulator(self): + """Test backend.run() on a simulator""" + # pylint: disable=unused-variable + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") + shots = 100 + seed_simulator = 123 + circuit = ReferenceCircuits.bell() + for backend in [FakeAlmadenV2(), AerSimulator()]: + result = backend.run( + circuit, seed_simulator=seed_simulator, shots=shots, method="statevector" + ).result() + self.assertEqual(result.results[0].shots, shots) + self.assertEqual(result.results[0].seed_simulator, seed_simulator) + self.assertEqual(result.results[0].metadata["method"], "statevector") From 5171d7e75ccdd6b89398fef5548d4ea7e75a4313 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Mon, 25 Dec 2023 12:53:43 +0000 Subject: [PATCH 40/42] black --- qiskit_ibm_runtime/options/utils.py | 6 ++---- qiskit_ibm_runtime/qiskit_runtime_service.py | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/qiskit_ibm_runtime/options/utils.py b/qiskit_ibm_runtime/options/utils.py index 864be39e0..8c0ddd434 100644 --- a/qiskit_ibm_runtime/options/utils.py +++ b/qiskit_ibm_runtime/options/utils.py @@ -12,7 +12,7 @@ """Utility functions for options.""" -#from qiskit.providers.fake_provider import fake_backend +# from qiskit.providers.fake_provider import fake_backend from qiskit_ibm_runtime.fake_provider.fake_backend import FakeBackendV2 from ..ibm_backend import IBMBackend @@ -41,9 +41,7 @@ def set_default_error_levels( print(isinstance(backend, FakeBackendV2)) print() - is_simulator = ( - not isinstance(backend, FakeBackendV2) and backend.configuration().simulator - ) + is_simulator = not isinstance(backend, FakeBackendV2) and backend.configuration().simulator if options.get("optimization_level") is None: if is_simulator and options.get("simulator", {}).get("noise_model") is None: options["optimization_level"] = 1 diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 55def9b08..12a6c8bbc 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -38,7 +38,8 @@ QasmBackendConfiguration, ) from qiskit.primitives import BackendSampler, BackendEstimator -#from qiskit.providers.fake_provider.fake_backend import FakeBackendV2 + +# from qiskit.providers.fake_provider.fake_backend import FakeBackendV2 from qiskit_ibm_provider.proxies import ProxyConfiguration from qiskit_ibm_provider.utils.hgp import to_instance_format, from_instance_format From 74ed19465856fdc013d97771d1b1119e885197c3 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Mon, 25 Dec 2023 12:57:05 +0000 Subject: [PATCH 41/42] lint --- qiskit_ibm_runtime/options/utils.py | 6 ------ qiskit_ibm_runtime/qiskit_runtime_service.py | 4 +--- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/qiskit_ibm_runtime/options/utils.py b/qiskit_ibm_runtime/options/utils.py index 8c0ddd434..6b6843d5a 100644 --- a/qiskit_ibm_runtime/options/utils.py +++ b/qiskit_ibm_runtime/options/utils.py @@ -12,7 +12,6 @@ """Utility functions for options.""" -# from qiskit.providers.fake_provider import fake_backend from qiskit_ibm_runtime.fake_provider.fake_backend import FakeBackendV2 from ..ibm_backend import IBMBackend @@ -36,11 +35,6 @@ def set_default_error_levels( """ # The check that this is not a FakeBackendV2 is needed because FakeBackendV2 # does not have a configuration - print(backend.name) - print(type(backend)) - print(isinstance(backend, FakeBackendV2)) - print() - is_simulator = not isinstance(backend, FakeBackendV2) and backend.configuration().simulator if options.get("optimization_level") is None: if is_simulator and options.get("simulator", {}).get("noise_model") is None: diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 12a6c8bbc..cb61bdf4a 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -39,15 +39,13 @@ ) from qiskit.primitives import BackendSampler, BackendEstimator -# from qiskit.providers.fake_provider.fake_backend import FakeBackendV2 - from qiskit_ibm_provider.proxies import ProxyConfiguration from qiskit_ibm_provider.utils.hgp import to_instance_format, from_instance_format from qiskit_ibm_provider.utils.backend_decoder import configuration_from_server_data from qiskit_ibm_runtime import ibm_backend -from .fake_runtime_job import FakeRuntimeJob from qiskit_ibm_runtime.fake_provider.fake_backend import FakeBackendV2 +from .fake_runtime_job import FakeRuntimeJob from .fake_provider.fake_provider import FakeProviderForBackendV2 from .utils.utils import validate_job_tags from .accounts import AccountManager, Account, ChannelType From 3a90e02604349fdcf3431cddc52d616dea76f46e Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Mon, 25 Dec 2023 15:32:20 +0000 Subject: [PATCH 42/42] Fixed path in base_primitive --- qiskit_ibm_runtime/base_primitive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index d82bd9d37..adc90adf3 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -28,11 +28,11 @@ HAS_AER_SIMULATOR = False from qiskit.providers.options import Options as TerraOptions -from qiskit.providers.fake_provider.fake_backend import FakeBackendV2 from qiskit.providers.exceptions import QiskitBackendNotFoundError from qiskit_ibm_provider.session import get_cm_session as get_cm_provider_session +from qiskit_ibm_runtime.fake_provider.fake_backend import FakeBackendV2 from .fake_provider.fake_provider import FakeProviderForBackendV2 from .options import Options from .options.utils import set_default_error_levels