Skip to content

Commit

Permalink
Merge 685dcd7 into 235c7ce
Browse files Browse the repository at this point in the history
  • Loading branch information
ptristan3 committed Jun 18, 2024
2 parents 235c7ce + 685dcd7 commit 2b9472c
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 2 deletions.
65 changes: 64 additions & 1 deletion qiskit_ibm_runtime/fake_provider/fake_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""
Base class for dummy backends.
"""

import logging
import warnings
import collections
import json
Expand All @@ -40,9 +40,13 @@
from qiskit.providers.basic_provider import BasicSimulator

from qiskit_ibm_runtime.utils.backend_converter import convert_to_target
from .. import QiskitRuntimeService
from ..utils.backend_encoder import BackendEncoder

from ..utils.deprecation import issue_deprecation_msg

logger = logging.getLogger(__name__)


class _Credentials:
def __init__(self, token: str = "123456", url: str = "https://") -> None:
Expand Down Expand Up @@ -458,6 +462,65 @@ def _get_noise_model_from_backend_v2( # type: ignore

return noise_model

def refresh(self, service: QiskitRuntimeService) -> None:
"""Update the data files from its real counterpart
This method pulls the latest backend data files from their real counterpart and
overwrites the corresponding files in the local installation:
* ../fake_provider/backends/{backend_name}/conf_{backend_name}.json
* ../fake_provider/backends/{backend_name}/defs_{backend_name}.json
* ../fake_provider/backends/{backend_name}/props_{backend_name}.json
The new data files will persist through sessions so the files will stay updated unless they
are manually reverted locally or when qiskit-ibm-runtime is upgraded/reinstalled.
Args:
service: A :class:`QiskitRuntimeService` instance
Raises:
Exception: If the real target doesn't exist or can't be accessed
"""

version = self.backend_version
prod_name = self.backend_name.replace("fake", "ibm")
try:
backends = service.backends(prod_name)
real_backend = backends[0]

real_props = real_backend.properties()
real_config = real_backend.configuration()
real_defs = real_backend.defaults()

if real_props:
new_version = real_props.backend_version

if new_version > version:
props_path = os.path.join(self.dirname, self.props_filename)
with open(props_path, "w", encoding="utf-8") as fd:
fd.write(json.dumps(real_props.to_dict(), cls=BackendEncoder))

if real_config:
config_path = os.path.join(self.dirname, self.conf_filename)
config_dict = real_config.to_dict()
with open(config_path, "w", encoding="utf-8") as fd:
fd.write(json.dumps(config_dict, cls=BackendEncoder))

if real_defs:
defs_path = os.path.join(self.dirname, self.defs_filename)
with open(defs_path, "w", encoding="utf-8") as fd:
fd.write(json.dumps(real_defs.to_dict(), cls=BackendEncoder))

logger.info(
"The backend %s has been updated from {version} to %s version.",
self.backend_name,
real_props.backend_version,
)
else:
logger.info("There are no available new updates for %s.", self.backend_name)

except Exception as ex:
logger.info("The refreshing of %s has failed: %s", self.backend_name, str(ex))


class FakeBackend(BackendV1):
"""This is a dummy backend just for testing purposes."""
Expand Down
36 changes: 36 additions & 0 deletions qiskit_ibm_runtime/utils/backend_encoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2024.
#
# 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.

"""Utilities for working with IBM Quantum backends."""
import json
from datetime import datetime
from typing import Any

from qiskit.circuit import ParameterExpression


class BackendEncoder(json.JSONEncoder):
"""A json encoder for qobj"""

def default(self, obj: Any) -> Any: # pylint: disable=arguments-differ
"""Default encoding"""
# Convert numpy arrays:
if hasattr(obj, "tolist"):
return obj.tolist()
# Use Qobj complex json format:
if isinstance(obj, complex):
return [obj.real, obj.imag]
if isinstance(obj, ParameterExpression):
return float(obj)
if isinstance(obj, datetime):
return obj.isoformat()
return json.JSONEncoder.default(self, obj)
4 changes: 4 additions & 0 deletions release-notes/unreleased/1740.upgrade.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The instances of :class:`FakeBackend` can now be updated from
their real counterpart using the :meth:`FakeBackendV2.refresh`.
To pull the latest real backend data files, access permission is
required.
19 changes: 18 additions & 1 deletion test/integration/test_fake_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
FakeSherbrooke,
FakePrague,
)
from ..ibm_test_case import IBMTestCase
from ..ibm_test_case import IBMTestCase, IBMIntegrationTestCase

FAKE_PROVIDER_FOR_BACKEND_V2 = FakeProviderForBackendV2()
FAKE_PROVIDER = FakeProvider()
Expand Down Expand Up @@ -171,3 +171,20 @@ def test_non_cx_tests(self):
self.assertIsInstance(backend.target.operation_from_name("cz"), CZGate)
backend = FakeSherbrooke()
self.assertIsInstance(backend.target.operation_from_name("ecr"), ECRGate)


class TestRefreshFakeBackends(IBMIntegrationTestCase):

@classmethod
def setUpClass(cls):
# pylint: disable=arguments-differ
# pylint: disable=no-value-for-parameter
super().setUpClass()

def test_refresh_method(self):
"""Test refresh method"""
old_backend = FakeSherbrooke()
with self.assertLogs("qiskit_ibm_runtime", level="INFO"):
old_backend.refresh(self.service)
new_backend = FakeSherbrooke()
self.assertGreaterEqual(old_backend.backend_version, new_backend.backend_version)

0 comments on commit 2b9472c

Please sign in to comment.