From c65229368407a57164e86d120b6f658508c28141 Mon Sep 17 00:00:00 2001 From: jessieyu Date: Mon, 29 Nov 2021 17:24:56 -0500 Subject: [PATCH 1/5] rename utils file --- qiskit_ibm_runtime/hub_group_project.py | 2 +- qiskit_ibm_runtime/ibm_backend.py | 2 +- qiskit_ibm_runtime/program/result_decoder.py | 2 +- qiskit_ibm_runtime/program/user_messenger.py | 2 +- qiskit_ibm_runtime/utils/__init__.py | 12 +- qiskit_ibm_runtime/utils/backend.py | 98 +++++++++++++++- .../utils/{runtime.py => json.py} | 0 qiskit_ibm_runtime/utils/json_decoder.py | 111 ------------------ qiskit_ibm_runtime/utils/json_encoder.py | 39 ------ test/ibm/test_serialization.py | 17 +-- 10 files changed, 112 insertions(+), 173 deletions(-) rename qiskit_ibm_runtime/utils/{runtime.py => json.py} (100%) delete mode 100644 qiskit_ibm_runtime/utils/json_decoder.py delete mode 100644 qiskit_ibm_runtime/utils/json_encoder.py diff --git a/qiskit_ibm_runtime/hub_group_project.py b/qiskit_ibm_runtime/hub_group_project.py index 10365ec04a..2227c592a6 100644 --- a/qiskit_ibm_runtime/hub_group_project.py +++ b/qiskit_ibm_runtime/hub_group_project.py @@ -24,7 +24,7 @@ ibm_backend, ) -from .utils.json_decoder import decode_backend_configuration +from .utils.backend import decode_backend_configuration from .api.clients import AccountClient from .credentials import Credentials from .exceptions import IBMInputValueError diff --git a/qiskit_ibm_runtime/ibm_backend.py b/qiskit_ibm_runtime/ibm_backend.py index 134db45599..f74363e23c 100644 --- a/qiskit_ibm_runtime/ibm_backend.py +++ b/qiskit_ibm_runtime/ibm_backend.py @@ -41,7 +41,7 @@ from .credentials import Credentials from .exceptions import IBMBackendApiProtocolError, IBMBackendError from .utils.converters import utc_to_local_all, local_to_utc -from .utils.json_decoder import decode_pulse_defaults, decode_backend_properties +from .utils.backend import decode_pulse_defaults, decode_backend_properties from .utils.backend import convert_reservation_data logger = logging.getLogger(__name__) diff --git a/qiskit_ibm_runtime/program/result_decoder.py b/qiskit_ibm_runtime/program/result_decoder.py index cc4911c1dd..659760f5d7 100644 --- a/qiskit_ibm_runtime/program/result_decoder.py +++ b/qiskit_ibm_runtime/program/result_decoder.py @@ -15,7 +15,7 @@ import json from typing import Any -from qiskit_ibm_runtime.utils.runtime import RuntimeDecoder +from qiskit_ibm_runtime.utils import RuntimeDecoder class ResultDecoder: diff --git a/qiskit_ibm_runtime/program/user_messenger.py b/qiskit_ibm_runtime/program/user_messenger.py index e9255ff7d1..75ab6f6220 100644 --- a/qiskit_ibm_runtime/program/user_messenger.py +++ b/qiskit_ibm_runtime/program/user_messenger.py @@ -15,7 +15,7 @@ import json from typing import Any, Type -from ..utils.runtime import RuntimeEncoder +from ..utils.json import RuntimeEncoder class UserMessenger: diff --git a/qiskit_ibm_runtime/utils/__init__.py b/qiskit_ibm_runtime/utils/__init__.py index 4c10a70027..62bd0737d4 100644 --- a/qiskit_ibm_runtime/utils/__init__.py +++ b/qiskit_ibm_runtime/utils/__init__.py @@ -17,7 +17,7 @@ .. currentmodule:: qiskit_ibm_runtime.utils -Utility functions related to the IBM Quantum Provider. +Utility functions related to the IBM Runtime Services. Conversion ========== @@ -27,6 +27,14 @@ seconds_to_duration utc_to_local +JSON Encoder and Decoder +======================== +.. autosummary:: + :toctree: ../stubs/ + + RuntimeEncoder + RuntimeDecoder + Misc Functions ============== .. autosummary:: @@ -42,4 +50,4 @@ duration_difference, ) from .utils import to_python_identifier -from .runtime import * +from .json import RuntimeEncoder, RuntimeDecoder diff --git a/qiskit_ibm_runtime/utils/backend.py b/qiskit_ibm_runtime/utils/backend.py index 116e45f0db..a16344fbef 100644 --- a/qiskit_ibm_runtime/utils/backend.py +++ b/qiskit_ibm_runtime/utils/backend.py @@ -12,7 +12,9 @@ """Utilities for working with IBM Quantum backends.""" -from typing import List, Optional +from typing import List, Optional, Dict, Union + +import dateutil.parser from ..backendreservation import BackendReservation from ..utils.converters import utc_to_local @@ -49,3 +51,97 @@ def convert_reservation_data( ) ) return reservations + + +def decode_pulse_defaults(defaults: Dict) -> None: + """Decode pulse defaults data. + + Args: + defaults: A ``PulseDefaults`` in dictionary format. + """ + for item in defaults["pulse_library"]: + _decode_pulse_library_item(item) + + for cmd in defaults["cmd_def"]: + if "sequence" in cmd: + for instr in cmd["sequence"]: + _decode_pulse_qobj_instr(instr) + + +def decode_backend_properties(properties: Dict) -> None: + """Decode backend properties. + + Args: + properties: A ``BackendProperties`` in dictionary format. + """ + properties["last_update_date"] = dateutil.parser.isoparse( + properties["last_update_date"] + ) + for qubit in properties["qubits"]: + for nduv in qubit: + nduv["date"] = dateutil.parser.isoparse(nduv["date"]) + for gate in properties["gates"]: + for param in gate["parameters"]: + param["date"] = dateutil.parser.isoparse(param["date"]) + for gen in properties["general"]: + gen["date"] = dateutil.parser.isoparse(gen["date"]) + + +def decode_backend_configuration(config: Dict) -> None: + """Decode backend configuration. + + Args: + config: A ``QasmBackendConfiguration`` or ``PulseBackendConfiguration`` + in dictionary format. + """ + config["online_date"] = dateutil.parser.isoparse(config["online_date"]) + + if "u_channel_lo" in config: + for u_channle_list in config["u_channel_lo"]: + for u_channle_lo in u_channle_list: + u_channle_lo["scale"] = _to_complex(u_channle_lo["scale"]) + + +def _to_complex(value: Union[List[float], complex]) -> complex: + """Convert the input value to type ``complex``. + + Args: + value: Value to be converted. + + Returns: + Input value in ``complex``. + + Raises: + TypeError: If the input value is not in the expected format. + """ + if isinstance(value, list) and len(value) == 2: + return complex(value[0], value[1]) + elif isinstance(value, complex): + return value + + raise TypeError("{} is not in a valid complex number format.".format(value)) + + +def _decode_pulse_library_item(pulse_library_item: Dict) -> None: + """Decode a pulse library item. + + Args: + pulse_library_item: A ``PulseLibraryItem`` in dictionary format. + """ + pulse_library_item["samples"] = [ + _to_complex(sample) for sample in pulse_library_item["samples"] + ] + + +def _decode_pulse_qobj_instr(pulse_qobj_instr: Dict) -> None: + """Decode a pulse Qobj instruction. + + Args: + pulse_qobj_instr: A ``PulseQobjInstruction`` in dictionary format. + """ + if "val" in pulse_qobj_instr: + pulse_qobj_instr["val"] = _to_complex(pulse_qobj_instr["val"]) + if "parameters" in pulse_qobj_instr and "amp" in pulse_qobj_instr["parameters"]: + pulse_qobj_instr["parameters"]["amp"] = _to_complex( + pulse_qobj_instr["parameters"]["amp"] + ) diff --git a/qiskit_ibm_runtime/utils/runtime.py b/qiskit_ibm_runtime/utils/json.py similarity index 100% rename from qiskit_ibm_runtime/utils/runtime.py rename to qiskit_ibm_runtime/utils/json.py diff --git a/qiskit_ibm_runtime/utils/json_decoder.py b/qiskit_ibm_runtime/utils/json_decoder.py deleted file mode 100644 index 6ec3ecb751..0000000000 --- a/qiskit_ibm_runtime/utils/json_decoder.py +++ /dev/null @@ -1,111 +0,0 @@ -# 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. - -"""Custom JSON decoder.""" - -from typing import Dict, Union, List - -import dateutil.parser - - -def decode_pulse_defaults(defaults: Dict) -> None: - """Decode pulse defaults data. - - Args: - defaults: A ``PulseDefaults`` in dictionary format. - """ - for item in defaults["pulse_library"]: - _decode_pulse_library_item(item) - - for cmd in defaults["cmd_def"]: - if "sequence" in cmd: - for instr in cmd["sequence"]: - _decode_pulse_qobj_instr(instr) - - -def decode_backend_properties(properties: Dict) -> None: - """Decode backend properties. - - Args: - properties: A ``BackendProperties`` in dictionary format. - """ - properties["last_update_date"] = dateutil.parser.isoparse( - properties["last_update_date"] - ) - for qubit in properties["qubits"]: - for nduv in qubit: - nduv["date"] = dateutil.parser.isoparse(nduv["date"]) - for gate in properties["gates"]: - for param in gate["parameters"]: - param["date"] = dateutil.parser.isoparse(param["date"]) - for gen in properties["general"]: - gen["date"] = dateutil.parser.isoparse(gen["date"]) - - -def decode_backend_configuration(config: Dict) -> None: - """Decode backend configuration. - - Args: - config: A ``QasmBackendConfiguration`` or ``PulseBackendConfiguration`` - in dictionary format. - """ - config["online_date"] = dateutil.parser.isoparse(config["online_date"]) - - if "u_channel_lo" in config: - for u_channle_list in config["u_channel_lo"]: - for u_channle_lo in u_channle_list: - u_channle_lo["scale"] = _to_complex(u_channle_lo["scale"]) - - -def _to_complex(value: Union[List[float], complex]) -> complex: - """Convert the input value to type ``complex``. - - Args: - value: Value to be converted. - - Returns: - Input value in ``complex``. - - Raises: - TypeError: If the input value is not in the expected format. - """ - if isinstance(value, list) and len(value) == 2: - return complex(value[0], value[1]) - elif isinstance(value, complex): - return value - - raise TypeError("{} is not in a valid complex number format.".format(value)) - - -def _decode_pulse_library_item(pulse_library_item: Dict) -> None: - """Decode a pulse library item. - - Args: - pulse_library_item: A ``PulseLibraryItem`` in dictionary format. - """ - pulse_library_item["samples"] = [ - _to_complex(sample) for sample in pulse_library_item["samples"] - ] - - -def _decode_pulse_qobj_instr(pulse_qobj_instr: Dict) -> None: - """Decode a pulse Qobj instruction. - - Args: - pulse_qobj_instr: A ``PulseQobjInstruction`` in dictionary format. - """ - if "val" in pulse_qobj_instr: - pulse_qobj_instr["val"] = _to_complex(pulse_qobj_instr["val"]) - if "parameters" in pulse_qobj_instr and "amp" in pulse_qobj_instr["parameters"]: - pulse_qobj_instr["parameters"]["amp"] = _to_complex( - pulse_qobj_instr["parameters"]["amp"] - ) diff --git a/qiskit_ibm_runtime/utils/json_encoder.py b/qiskit_ibm_runtime/utils/json_encoder.py deleted file mode 100644 index d2060268ec..0000000000 --- a/qiskit_ibm_runtime/utils/json_encoder.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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. - -# pylint: disable=method-hidden - -"""Custom JSON encoders.""" - -import json -from typing import Any - -from qiskit.circuit.parameterexpression import ParameterExpression - - -class IBMJsonEncoder(json.JSONEncoder): - """A json encoder for qobj""" - - def default(self, o: Any) -> Any: - # Convert numpy arrays: - if hasattr(o, "tolist"): - return o.tolist() - # Use Qobj complex json format: - if isinstance(o, complex): - return (o.real, o.imag) - if isinstance(o, ParameterExpression): - try: - return float(o) - except (TypeError, RuntimeError): - val = complex(o) - return val.real, val.imag - return json.JSONEncoder.default(self, o) diff --git a/test/ibm/test_serialization.py b/test/ibm/test_serialization.py index b0e0361a72..865f7c4a0a 100644 --- a/test/ibm/test_serialization.py +++ b/test/ibm/test_serialization.py @@ -10,16 +10,11 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Test serializing and deserializing data sent to the server.""" +"""Test deserializing server data.""" -from unittest import skipIf from typing import Any, Dict, Optional import dateutil.parser -from qiskit.circuit import Parameter -from qiskit.version import VERSION as terra_version - -from qiskit_ibm_runtime.utils.json_encoder import IBMJsonEncoder from ..decorators import requires_provider from ..ibm_test_case import IBMTestCase @@ -135,16 +130,6 @@ def _verify_data( } self.assertFalse(suspect_keys) - @skipIf(terra_version < "0.17", "Need Terra >= 0.17") - def test_convert_complex(self): - """Verify that real and complex ParameterExpressions are supported.""" - param = Parameter("test") - self.assertEqual(IBMJsonEncoder().default(param.bind({param: 0.2})), 0.2) - - val = IBMJsonEncoder().default(param.bind({param: 0.2 + 0.1j})) - self.assertEqual(val[0], 0.2) - self.assertEqual(val[1], 0.1) - def _find_potential_encoded(data: Any, c_key: str, tally: set) -> None: """Find data that may be in JSON serialized format. From 855cd8d521b843e403414ebb8ef99dea2f8cf6e7 Mon Sep 17 00:00:00 2001 From: jessieyu Date: Mon, 29 Nov 2021 17:45:58 -0500 Subject: [PATCH 2/5] missed import --- qiskit_ibm_runtime/utils/__init__.py | 2 +- qiskit_ibm_runtime/utils/json.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit_ibm_runtime/utils/__init__.py b/qiskit_ibm_runtime/utils/__init__.py index 62bd0737d4..052e7576f7 100644 --- a/qiskit_ibm_runtime/utils/__init__.py +++ b/qiskit_ibm_runtime/utils/__init__.py @@ -50,4 +50,4 @@ duration_difference, ) from .utils import to_python_identifier -from .json import RuntimeEncoder, RuntimeDecoder +from .json import RuntimeEncoder, RuntimeDecoder, to_base64_string diff --git a/qiskit_ibm_runtime/utils/json.py b/qiskit_ibm_runtime/utils/json.py index 80f6c27d27..0cf474acc1 100644 --- a/qiskit_ibm_runtime/utils/json.py +++ b/qiskit_ibm_runtime/utils/json.py @@ -105,7 +105,7 @@ def _decode_and_deserialize( return orig -def deserialize_from_settings(mod_name: str, class_name: str, settings: Dict) -> Any: +def _deserialize_from_settings(mod_name: str, class_name: str, settings: Dict) -> Any: """Deserialize an object from its settings. Args: @@ -259,7 +259,7 @@ def object_hook(self, obj: Any) -> Any: obj_val, qpy_serialization._read_instruction, False ) if obj_type == "settings": - return deserialize_from_settings( + return _deserialize_from_settings( mod_name=obj["__module__"], class_name=obj["__class__"], settings=_cast_strings_keys_to_int(obj_val), From 19c48a30353a28355e914bec08cc8a1e923b08e1 Mon Sep 17 00:00:00 2001 From: jessieyu Date: Tue, 30 Nov 2021 08:14:33 -0500 Subject: [PATCH 3/5] fix import --- qiskit_ibm_runtime/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/__init__.py b/qiskit_ibm_runtime/__init__.py index e21ae5fb84..d1faf98355 100644 --- a/qiskit_ibm_runtime/__init__.py +++ b/qiskit_ibm_runtime/__init__.py @@ -289,7 +289,7 @@ def interim_result_callback(job_id, interim_result): from .program.user_messenger import UserMessenger from .program.program_backend import ProgramBackend from .program.result_decoder import ResultDecoder -from .utils.runtime import RuntimeEncoder, RuntimeDecoder +from .utils.json import RuntimeEncoder, RuntimeDecoder # Setup the logger for the IBM Quantum Provider package. logger = logging.getLogger(__name__) From 824ca5765c6d60a623e3c36dbc59d0190fb55126 Mon Sep 17 00:00:00 2001 From: jessieyu Date: Tue, 30 Nov 2021 08:24:22 -0500 Subject: [PATCH 4/5] trigger build From 73a7fb027bb0cf1d6993afaae376589e452a4a7a Mon Sep 17 00:00:00 2001 From: jessieyu Date: Fri, 3 Dec 2021 15:02:03 -0500 Subject: [PATCH 5/5] remove duplicate doc --- qiskit_ibm_runtime/utils/__init__.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/qiskit_ibm_runtime/utils/__init__.py b/qiskit_ibm_runtime/utils/__init__.py index 052e7576f7..1439f951e2 100644 --- a/qiskit_ibm_runtime/utils/__init__.py +++ b/qiskit_ibm_runtime/utils/__init__.py @@ -27,14 +27,6 @@ seconds_to_duration utc_to_local -JSON Encoder and Decoder -======================== -.. autosummary:: - :toctree: ../stubs/ - - RuntimeEncoder - RuntimeDecoder - Misc Functions ============== .. autosummary::