diff --git a/qiskit_ibm_runtime/accounts/account.py b/qiskit_ibm_runtime/accounts/account.py index fa56d92fc6..f589767ad5 100644 --- a/qiskit_ibm_runtime/accounts/account.py +++ b/qiskit_ibm_runtime/accounts/account.py @@ -17,11 +17,12 @@ from urllib.parse import urlparse from requests.auth import AuthBase +from qiskit_ibm_provider.proxies import ProxyConfiguration +from qiskit_ibm_provider.utils.hgp import from_instance_format from .exceptions import InvalidAccountError, CloudResourceNameResolutionError from ..api.auth import QuantumAuth, CloudAuth -from ..proxies import ProxyConfiguration -from ..utils.hgp import from_instance_format + from ..utils import resolve_crn AccountType = Optional[Literal["cloud", "legacy"]] diff --git a/qiskit_ibm_runtime/accounts/management.py b/qiskit_ibm_runtime/accounts/management.py index ab1959d7e5..5c1e376e64 100644 --- a/qiskit_ibm_runtime/accounts/management.py +++ b/qiskit_ibm_runtime/accounts/management.py @@ -15,9 +15,10 @@ import os import ast from typing import Optional, Dict +from qiskit_ibm_provider.proxies import ProxyConfiguration + from .exceptions import AccountNotFoundError from .account import Account, ChannelType -from ..proxies import ProxyConfiguration from .storage import save_config, read_config, delete_config, read_qiskitrc _DEFAULT_ACCOUNT_CONFIG_JSON_FILE = os.path.join( diff --git a/qiskit_ibm_runtime/api/client_parameters.py b/qiskit_ibm_runtime/api/client_parameters.py index 3ff4911faf..3c722b7899 100644 --- a/qiskit_ibm_runtime/api/client_parameters.py +++ b/qiskit_ibm_runtime/api/client_parameters.py @@ -13,10 +13,10 @@ """Represent IBM Quantum account client parameters.""" from typing import Dict, Optional, Any, Union +from qiskit_ibm_provider.proxies import ProxyConfiguration from ..utils import get_runtime_api_base_url from ..api.auth import QuantumAuth, CloudAuth -from ..proxies import ProxyConfiguration TEMPLATE_IBM_HUBS = "{prefix}/Network/{hub}/Groups/{group}/Projects/{project}" """str: Template for creating an IBM Quantum URL with hub/group/project information.""" diff --git a/qiskit_ibm_runtime/api/clients/runtime.py b/qiskit_ibm_runtime/api/clients/runtime.py index a962de1c76..f3a9ac2ea2 100644 --- a/qiskit_ibm_runtime/api/clients/runtime.py +++ b/qiskit_ibm_runtime/api/clients/runtime.py @@ -16,12 +16,13 @@ from typing import Any, Dict, List, Optional from datetime import datetime as python_datetime +from qiskit_ibm_provider.utils.hgp import from_instance_format from qiskit_ibm_runtime.api.session import RetrySession from .backend import BaseBackendClient from ..rest.runtime import Runtime from ..client_parameters import ClientParameters -from ...utils.hgp import from_instance_format + logger = logging.getLogger(__name__) diff --git a/qiskit_ibm_runtime/backendreservation.py b/qiskit_ibm_runtime/backendreservation.py deleted file mode 100644 index f877c20ec4..0000000000 --- a/qiskit_ibm_runtime/backendreservation.py +++ /dev/null @@ -1,110 +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. - -"""Reservation information related to a backend.""" - -from typing import Optional, Any -from datetime import datetime - - -class BackendReservation: - """Reservation information for a backend. - - Represent a reservation for a backend. This instance is returned by - the :meth:`IBMBackend.reservations` method. Some of the attributes are - only available if you're the owner of the reservation. - - Attributes: - backend_name: The name of the backend. - start_datetime: Starting datetime of the reservation, in local timezone. - end_datetime: Ending datetime of the reservation, in local timezone. - duration: Duration of the reservation, in minutes. - mode: Reservation mode. Only available if it's your reservation. - reservation_id: Reservation ID. Only available if it's your reservation. - creation_datetime: Reservation creation datetime. Only available if it's your reservation. - hub: Hub used to make the reservation. - group: Group used to make the reservation. - project: Project used to make the reservation. - """ - - def __init__( - self, - backend_name: str, - start_datetime: datetime, - end_datetime: datetime, - creation_datetime: Optional[datetime] = None, - mode: Optional[str] = None, - reservation_id: Optional[str] = None, - hub_info: Optional[dict] = None, - ) -> None: - """BackendReservation constructor. - - Args: - backend_name: The name of the backend. - start_datetime: Starting datetime of the reservation, in local timezone. - end_datetime: Ending datetime of the reservation, in local timezone. - mode: Reservation mode. - reservation_id: Reservation ID. - creation_datetime: Reservation creation datetime. - hub_info: Hub/group/project used to make the reservation. - """ - self.backend_name = backend_name - self.start_datetime = start_datetime - self.end_datetime = end_datetime - self.duration = int((end_datetime - start_datetime).seconds / 60) - self.mode = mode - self.reservation_id = reservation_id - self.creation_datetime = creation_datetime - if hub_info: - self.hub = hub_info["hub"]["name"] - self.group = hub_info["group"]["name"] - self.project = hub_info["project"]["name"] - else: - self.hub = self.group = self.project = None - - def __repr__(self) -> str: - out_str = "<{}(backend_name={}, start_datetime={}, end_datetime={}".format( - self.__class__.__name__, - self.backend_name, - self.start_datetime.isoformat(), - self.end_datetime.isoformat(), - ) - for attr in [ - "mode", - "duration", - "reservation_id", - "creation_datetime", - "hub", - "group", - "project", - ]: - val = getattr(self, attr) - if isinstance(val, datetime): - val = val.isoformat() - if val is not None: - out_str += ", {}={}".format(attr, val) - out_str += ")>" - return out_str - - def __eq__(self, other: Any) -> bool: - if ( - isinstance(other, BackendReservation) - and self.backend_name == other.backend_name - ): - if self.reservation_id and self.reservation_id == other.reservation_id: - return True - if ( - self.start_datetime == other.start_datetime - and self.end_datetime == other.end_datetime - ): - return True - return False diff --git a/qiskit_ibm_runtime/hub_group_project.py b/qiskit_ibm_runtime/hub_group_project.py index 83b047c15f..1b213eadbc 100644 --- a/qiskit_ibm_runtime/hub_group_project.py +++ b/qiskit_ibm_runtime/hub_group_project.py @@ -15,13 +15,14 @@ import logging from typing import Any, List +from qiskit_ibm_provider.utils.hgp import from_instance_format from qiskit_ibm_runtime import ( # pylint: disable=unused-import ibm_backend, qiskit_runtime_service, ) + from .api.client_parameters import ClientParameters from .api.clients import RuntimeClient -from .utils.hgp import from_instance_format logger = logging.getLogger(__name__) diff --git a/qiskit_ibm_runtime/ibm_backend.py b/qiskit_ibm_runtime/ibm_backend.py index 9b27c4d608..6cad955022 100644 --- a/qiskit_ibm_runtime/ibm_backend.py +++ b/qiskit_ibm_runtime/ibm_backend.py @@ -37,6 +37,10 @@ ) from qiskit.transpiler.target import Target +from qiskit_ibm_provider.utils.backend_decoder import ( + defaults_from_server_data, + properties_from_server_data, +) from qiskit_ibm_runtime import ( # pylint: disable=unused-import,cyclic-import qiskit_runtime_service, ) @@ -48,10 +52,6 @@ convert_to_target, ) from .utils.converters import local_to_utc -from .utils.backend_decoder import ( - defaults_from_server_data, - properties_from_server_data, -) logger = logging.getLogger(__name__) diff --git a/qiskit_ibm_runtime/ibm_qubit_properties.py b/qiskit_ibm_runtime/ibm_qubit_properties.py deleted file mode 100644 index 169abc7e6a..0000000000 --- a/qiskit_ibm_runtime/ibm_qubit_properties.py +++ /dev/null @@ -1,50 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2022. -# -# 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. - -"""Module for Qubit Properties of an IBM Quantum Backend.""" - -from qiskit.providers.backend import QubitProperties - - -class IBMQubitProperties(QubitProperties): - """A representation of the properties of a qubit on an IBM backend.""" - - __slots__ = ( # pylint: disable=redefined-slots-in-subclass - "t1", - "t2", - "frequency", - "anharmonicity", - ) - - def __init__( # type: ignore[no-untyped-def] - self, - t1=None, - t2=None, - frequency=None, - anharmonicity=None, - ): - """Create a new ``IBMQubitProperties`` object - - Args: - t1: The T1 time for a qubit in secs - t2: The T2 time for a qubit in secs - frequency: The frequency of a qubit in Hz - anharmonicity: The anharmonicity of a qubit in Hz - """ - super().__init__(t1=t1, t2=t2, frequency=frequency) - self.anharmonicity = anharmonicity - - def __repr__(self): # type: ignore[no-untyped-def] - return ( - f"IBMQubitProperties(t1={self.t1}, t2={self.t2}, frequency={self.frequency}, " - f"anharmonicity={self.anharmonicity})" - ) diff --git a/qiskit_ibm_runtime/proxies/__init__.py b/qiskit_ibm_runtime/proxies/__init__.py deleted file mode 100644 index c0212bfb0d..0000000000 --- a/qiskit_ibm_runtime/proxies/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2022. -# -# 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. - -""" -Proxy configuration. -""" - -from .configuration import ProxyConfiguration diff --git a/qiskit_ibm_runtime/proxies/configuration.py b/qiskit_ibm_runtime/proxies/configuration.py deleted file mode 100644 index 2e0ea25eb2..0000000000 --- a/qiskit_ibm_runtime/proxies/configuration.py +++ /dev/null @@ -1,132 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2022. -# -# 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. - -"""Proxy related classes and functions.""" - - -from dataclasses import dataclass -from typing import Optional, Dict, Any -from urllib.parse import urlparse - -from requests_ntlm import HttpNtlmAuth - - -@dataclass -class ProxyConfiguration: - """Class for representing a proxy configuration. - - Args - urls: a dictionary mapping protocol or protocol and host to the URL of the proxy. Refer to - https://docs.python-requests.org/en/latest/api/#requests.Session.proxies for details. - username_ntlm: username used to enable NTLM user authentication. - password_ntlm: password used to enable NTLM user authentication. - """ - - urls: Optional[Dict[str, str]] = None - username_ntlm: Optional[str] = None - password_ntlm: Optional[str] = None - - def validate(self) -> None: - """Validate configuration. - - Raises: - ValueError: If configuration is invalid. - """ - if not any( - [ - isinstance(self.username_ntlm, str) - and isinstance(self.password_ntlm, str), - self.username_ntlm is None and self.password_ntlm is None, - ] - ): - raise ValueError( - f"Invalid proxy configuration for NTLM authentication. None or both of username and " - f"password must be provided. Got username_ntlm={self.username_ntlm}, " - f"password_ntlm={self.password_ntlm}." - ) - - if self.urls is not None and not isinstance(self.urls, dict): - raise ValueError( - f"Invalid proxy configuration. Expected `urls` to contain a dictionary mapping protocol " - f"or protocol and host to the URL of the proxy. Got {self.urls}" - ) - - def to_dict(self) -> dict: - """Transform configuration to dictionary.""" - - return {k: v for k, v in self.__dict__.items() if v is not None} - - def to_request_params(self) -> dict: - """Transform configuration to request parameters. - - Returns: - A dictionary with proxy configuration parameters in the format - expected by ``requests``. The following keys can be present: - ``proxies``and ``auth``. - """ - - request_kwargs = {} - if self.urls: - request_kwargs["proxies"] = self.urls - - if self.username_ntlm and self.password_ntlm: - request_kwargs["auth"] = HttpNtlmAuth( - self.username_ntlm, self.password_ntlm - ) - - return request_kwargs - - def to_ws_params(self, ws_url: str) -> dict: - """Extract proxy information for websocket. - - Args: - ws_url: Websocket URL. - - Returns: - A dictionary with proxy configuration parameters in the format expected by websocket. - The following keys can be present: ``http_proxy_host``and ``http_proxy_port``, - ``proxy_type``, ``http_proxy_auth``. - """ - out: Any = {} - - if self.urls: - proxies = self.urls - url_parts = urlparse(ws_url) - proxy_keys = [ - ws_url, - "wss", - "https://" + url_parts.hostname, - "https", - "all://" + url_parts.hostname, - "all", - ] - for key in proxy_keys: - if key in proxies: - proxy_parts = urlparse(proxies[key], scheme="http") - out["http_proxy_host"] = proxy_parts.hostname - out["http_proxy_port"] = proxy_parts.port - out["proxy_type"] = ( - "http" - if proxy_parts.scheme.startswith("http") - else proxy_parts.scheme - ) - if proxy_parts.username and proxy_parts.password: - out["http_proxy_auth"] = ( - proxy_parts.username, - proxy_parts.password, - ) - break - - if self.username_ntlm and self.password_ntlm: - out["http_proxy_auth"] = (self.username_ntlm, self.password_ntlm) - - return out diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 0549a12013..922a3278ba 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -29,9 +29,12 @@ QasmBackendConfiguration, ) +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 .accounts import AccountManager, Account, AccountType, ChannelType -from .proxies import ProxyConfiguration from .api.clients import AuthClient, VersionClient from .api.clients.runtime import RuntimeClient from .api.exceptions import RequestsApiError @@ -48,8 +51,6 @@ from .runtime_job import RuntimeJob from .runtime_program import RuntimeProgram, ParameterNamespace from .utils import RuntimeDecoder, to_base64_string, to_python_identifier -from .utils.backend_decoder import configuration_from_server_data -from .utils.hgp import to_instance_format, from_instance_format from .api.client_parameters import ClientParameters from .runtime_options import RuntimeOptions from .ibm_backend import IBMBackend diff --git a/qiskit_ibm_runtime/qpy/__init__.py b/qiskit_ibm_runtime/qpy/__init__.py deleted file mode 100644 index 14c75d674a..0000000000 --- a/qiskit_ibm_runtime/qpy/__init__.py +++ /dev/null @@ -1,87 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021, 2022. -# -# 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. - -""" -########################################################### -QPY serialization (:mod:`qiskit_ibm_runtime.qpy`) -########################################################### - -.. currentmodule:: qiskit_ibm_runtime.qpy - -********* -Using QPY -********* - -This is downstream fork of the :mod:`qiskit.qpy` module. - -Using QPY is defined to be straightforward and mirror the user API of the -serializers in Python's standard library, ``pickle`` and ``json``. There are -2 user facing functions: :func:`qiskit.circuit.qpy_serialization.dump` and -:func:`qiskit.circuit.qpy_serialization.load` which are used to dump QPY data -to a file object and load circuits from QPY data in a file object respectively. -For example:: - - from qiskit.circuit import QuantumCircuit - from qiskit import qpy - - qc = QuantumCircuit(2, name='Bell', metadata={'test': True}) - qc.h(0) - qc.cx(0, 1) - qc.measure_all() - - with open('bell.qpy', 'wb') as fd: - qpy.dump(qc, fd) - - with open('bell.qpy', 'rb') as fd: - new_qc = qpy.load(fd)[0] - -API documentation -================= - -.. autosummary:: - :toctree: ../stubs/ - - load - dump - -QPY Compatibility -================= - -The QPY format is designed to be backwards compatible moving forward. This means -you should be able to load a QPY with any newer Qiskit version than the one -that generated it. However, loading a QPY file with an older Qiskit version is -not supported and may not work. - -For example, if you generated a QPY file using qiskit-terra 0.18.1 you could -load that QPY file with qiskit-terra 0.19.0 and a hypothetical qiskit-terra -0.29.0. However, loading that QPY file with 0.18.0 is not supported and may not -work. - -********** -QPY Format -********** - -https://qiskit.org/documentation/apidoc/qpy.html#qpy-format -""" - -from .interface import dump, load - -# For backward compatibility. Provide, Runtime, Experiment call these private functions. -from .binary_io import ( - _write_instruction, - _read_instruction, - _write_parameter_expression, - _read_parameter_expression, - _read_parameter_expression_v3, - _write_parameter, - _read_parameter, -) diff --git a/qiskit_ibm_runtime/qpy/binary_io/__init__.py b/qiskit_ibm_runtime/qpy/binary_io/__init__.py deleted file mode 100644 index 566ebbae53..0000000000 --- a/qiskit_ibm_runtime/qpy/binary_io/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021, 2022. -# -# 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. - -"""Read and write QPY-serializable objects.""" - -from .value import ( - dumps_value, - loads_value, - write_value, - read_value, - # for backward compatibility; provider, runtime, experiment call this private methods. - _write_parameter, - _write_parameter_expression, - _read_parameter_expression, - _read_parameter_expression_v3, - _read_parameter, -) - -from .circuits import ( - write_circuit, - read_circuit, - # for backward compatibility; provider calls this private methods. - _write_instruction, - _read_instruction, -) -from .schedules import ( - write_schedule_block, - read_schedule_block, -) diff --git a/qiskit_ibm_runtime/qpy/binary_io/circuits.py b/qiskit_ibm_runtime/qpy/binary_io/circuits.py deleted file mode 100644 index 920435c1be..0000000000 --- a/qiskit_ibm_runtime/qpy/binary_io/circuits.py +++ /dev/null @@ -1,1024 +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=invalid-name - -"""Binary IO for circuit objects.""" - -import io -import json -import struct -import uuid -import warnings - -import numpy as np - -from qiskit import circuit as circuit_mod -from qiskit import extensions -from qiskit.circuit import library, controlflow, CircuitInstruction -from qiskit.circuit.classicalregister import ClassicalRegister, Clbit -from qiskit.circuit.gate import Gate -from qiskit.circuit.controlledgate import ControlledGate -from qiskit.circuit.instruction import Instruction -from qiskit.circuit.quantumcircuit import QuantumCircuit -from qiskit.circuit.quantumregister import QuantumRegister, Qubit -from qiskit.extensions import quantum_initializer -from qiskit.quantum_info.operators import SparsePauliOp -from qiskit.synthesis import evolution as evo_synth -from .. import common, formats, type_keys -from . import value, schedules - - -def _read_header_v2( # type: ignore[no-untyped-def] - file_obj, version, vectors, metadata_deserializer=None -): - data = formats.CIRCUIT_HEADER_V2._make( - struct.unpack( - formats.CIRCUIT_HEADER_V2_PACK, - file_obj.read(formats.CIRCUIT_HEADER_V2_SIZE), - ) - ) - name = file_obj.read(data.name_size).decode(common.ENCODE) - global_phase = value.loads_value( - data.global_phase_type, - file_obj.read(data.global_phase_size), - version=version, - vectors=vectors, - ) - header = { - "global_phase": global_phase, - "num_qubits": data.num_qubits, - "num_clbits": data.num_clbits, - "num_registers": data.num_registers, - "num_instructions": data.num_instructions, - } - metadata_raw = file_obj.read(data.metadata_size) - metadata = json.loads(metadata_raw, cls=metadata_deserializer) - return header, name, metadata - - -def _read_header(file_obj, metadata_deserializer=None): # type: ignore[no-untyped-def] - data = formats.CIRCUIT_HEADER._make( - struct.unpack( - formats.CIRCUIT_HEADER_PACK, file_obj.read(formats.CIRCUIT_HEADER_SIZE) - ) - ) - name = file_obj.read(data.name_size).decode(common.ENCODE) - header = { - "global_phase": data.global_phase, - "num_qubits": data.num_qubits, - "num_clbits": data.num_clbits, - "num_registers": data.num_registers, - "num_instructions": data.num_instructions, - } - metadata_raw = file_obj.read(data.metadata_size) - metadata = json.loads(metadata_raw, cls=metadata_deserializer) - return header, name, metadata - - -def _read_registers_v4(file_obj, num_registers): # type: ignore[no-untyped-def] - registers = {"q": {}, "c": {}} - for _reg in range(num_registers): - data = formats.REGISTER_V4._make( - struct.unpack( - formats.REGISTER_V4_PACK, - file_obj.read(formats.REGISTER_V4_SIZE), - ) - ) - name = file_obj.read(data.name_size).decode("utf8") - REGISTER_ARRAY_PACK = "!%sq" % data.size - bit_indices_raw = file_obj.read(struct.calcsize(REGISTER_ARRAY_PACK)) - bit_indices = list(struct.unpack(REGISTER_ARRAY_PACK, bit_indices_raw)) - if data.type.decode("utf8") == "q": - registers["q"][name] = (data.standalone, bit_indices, data.in_circuit) - else: - registers["c"][name] = (data.standalone, bit_indices, data.in_circuit) - return registers - - -def _read_registers(file_obj, num_registers): # type: ignore[no-untyped-def] - registers = {"q": {}, "c": {}} - for _reg in range(num_registers): - data = formats.REGISTER._make( - struct.unpack( - formats.REGISTER_PACK, - file_obj.read(formats.REGISTER_SIZE), - ) - ) - name = file_obj.read(data.name_size).decode("utf8") - REGISTER_ARRAY_PACK = "!%sI" % data.size - bit_indices_raw = file_obj.read(struct.calcsize(REGISTER_ARRAY_PACK)) - bit_indices = list(struct.unpack(REGISTER_ARRAY_PACK, bit_indices_raw)) - if data.type.decode("utf8") == "q": - registers["q"][name] = (data.standalone, bit_indices, True) - else: - registers["c"][name] = (data.standalone, bit_indices, True) - return registers - - -def _loads_instruction_parameter( # type: ignore[no-untyped-def] - type_key, data_bytes, version, vectors, registers, circuit -): - if type_key == type_keys.Program.CIRCUIT: - param = common.data_from_binary(data_bytes, read_circuit, version=version) - elif type_key == type_keys.Container.RANGE: - data = formats.RANGE._make(struct.unpack(formats.RANGE_PACK, data_bytes)) - param = range(data.start, data.stop, data.step) - elif type_key == type_keys.Container.TUPLE: - param = tuple( - common.sequence_from_binary( - data_bytes, - _loads_instruction_parameter, - version=version, - vectors=vectors, - registers=registers, - circuit=circuit, - ) - ) - elif type_key == type_keys.Value.INTEGER: - # TODO This uses little endian. Should be fixed in the next QPY version. - param = struct.unpack(" 0: - inst_obj.label = label - if circuit is None: - return inst_obj - circuit._append(inst_obj, qargs, cargs) - return None - elif gate_name in custom_operations: - inst_obj = _parse_custom_operation( - custom_operations, gate_name, params, version, vectors, registers - ) - inst_obj.condition = condition_tuple - if instruction.label_size > 0: - inst_obj.label = label - if circuit is None: - return inst_obj - circuit._append(inst_obj, qargs, cargs) - return None - elif hasattr(library, gate_name): - gate_class = getattr(library, gate_name) - elif hasattr(circuit_mod, gate_name): - gate_class = getattr(circuit_mod, gate_name) - elif hasattr(extensions, gate_name): - gate_class = getattr(extensions, gate_name) - elif hasattr(quantum_initializer, gate_name): - gate_class = getattr(quantum_initializer, gate_name) - elif hasattr(controlflow, gate_name): - gate_class = getattr(controlflow, gate_name) - else: - raise AttributeError("Invalid instruction type: %s" % gate_name) - - if gate_name in {"IfElseOp", "WhileLoopOp"}: - gate = gate_class(condition_tuple, *params) - elif version >= 5 and issubclass(gate_class, ControlledGate): - if gate_name in { - "MCPhaseGate", - "MCU1Gate", - "MCXGrayCode", - "MCXGate", - "MCXRecursive", - "MCXVChain", - }: - gate = gate_class(*params, instruction.num_ctrl_qubits) - else: - gate = gate_class(*params) - gate.num_ctrl_qubits = instruction.num_ctrl_qubits - gate.ctrl_state = instruction.ctrl_state - gate.condition = condition_tuple - else: - if gate_name in { - "Initialize", - "StatePreparation", - "UCRXGate", - "UCRYGate", - "UCRZGate", - }: - gate = gate_class(params) - else: - if gate_name == "Barrier": - params = [len(qargs)] - elif gate_name in {"BreakLoopOp", "ContinueLoopOp"}: - params = [len(qargs), len(cargs)] - gate = gate_class(*params) - gate.condition = condition_tuple - if instruction.label_size > 0: - gate.label = label - if circuit is None: - return gate - if not isinstance(gate, Instruction): - circuit.append(gate, qargs, cargs) - else: - circuit._append(CircuitInstruction(gate, qargs, cargs)) - return None - - -def _parse_custom_operation( # type: ignore[no-untyped-def] - custom_operations, gate_name, params, version, vectors, registers -): - if version >= 5: - ( - type_str, - num_qubits, - num_clbits, - definition, - num_ctrl_qubits, - ctrl_state, - base_gate_raw, - ) = custom_operations[gate_name] - else: - type_str, num_qubits, num_clbits, definition = custom_operations[gate_name] - type_key = type_keys.CircuitInstruction(type_str) - - if type_key == type_keys.CircuitInstruction.INSTRUCTION: - inst_obj = Instruction(gate_name, num_qubits, num_clbits, params) - if definition is not None: - inst_obj.definition = definition - return inst_obj - - if type_key == type_keys.CircuitInstruction.GATE: - inst_obj = Gate(gate_name, num_qubits, params) - inst_obj.definition = definition - return inst_obj - - if version >= 5 and type_key == type_keys.CircuitInstruction.CONTROLLED_GATE: - with io.BytesIO(base_gate_raw) as base_gate_obj: - base_gate = _read_instruction( - base_gate_obj, None, registers, custom_operations, version, vectors - ) - if ctrl_state < 2**num_ctrl_qubits - 1: - # If open controls, we need to discard the control suffix when setting the name. - gate_name = gate_name.rsplit("_", 1)[0] - inst_obj = ControlledGate( - gate_name, - num_qubits, - params, - num_ctrl_qubits=num_ctrl_qubits, - ctrl_state=ctrl_state, - base_gate=base_gate, - ) - inst_obj.definition = definition - return inst_obj - - if type_key == type_keys.CircuitInstruction.PAULI_EVOL_GATE: - return definition - - raise ValueError("Invalid custom instruction type '%s'" % type_str) - - -def _read_pauli_evolution_gate(file_obj, version, vectors): # type: ignore[no-untyped-def] - pauli_evolution_def = formats.PAULI_EVOLUTION_DEF._make( - struct.unpack( - formats.PAULI_EVOLUTION_DEF_PACK, - file_obj.read(formats.PAULI_EVOLUTION_DEF_SIZE), - ) - ) - if pauli_evolution_def.operator_size != 1 and pauli_evolution_def.standalone_op: - raise ValueError( - "Can't have a standalone operator with {pauli_evolution_raw[0]} operators in the payload" - ) - - operator_list = [] - for _ in range(pauli_evolution_def.operator_size): - op_elem = formats.SPARSE_PAULI_OP_LIST_ELEM._make( - struct.unpack( - formats.SPARSE_PAULI_OP_LIST_ELEM_PACK, - file_obj.read(formats.SPARSE_PAULI_OP_LIST_ELEM_SIZE), - ) - ) - op_raw_data = common.data_from_binary(file_obj.read(op_elem.size), np.load) - operator_list.append(SparsePauliOp.from_list(op_raw_data)) - - if pauli_evolution_def.standalone_op: - pauli_op = operator_list[0] - else: - pauli_op = operator_list - - time = value.loads_value( - pauli_evolution_def.time_type, - file_obj.read(pauli_evolution_def.time_size), - version=version, - vectors=vectors, - ) - synth_data = json.loads(file_obj.read(pauli_evolution_def.synth_method_size)) - synthesis = getattr(evo_synth, synth_data["class"])(**synth_data["settings"]) - return_gate = library.PauliEvolutionGate(pauli_op, time=time, synthesis=synthesis) - return return_gate - - -def _read_custom_operations(file_obj, version, vectors): # type: ignore[no-untyped-def] - custom_operations = {} - custom_definition_header = formats.CUSTOM_CIRCUIT_DEF_HEADER._make( - struct.unpack( - formats.CUSTOM_CIRCUIT_DEF_HEADER_PACK, - file_obj.read(formats.CUSTOM_CIRCUIT_DEF_HEADER_SIZE), - ) - ) - if custom_definition_header.size > 0: - for _ in range(custom_definition_header.size): - if version < 5: - data = formats.CUSTOM_CIRCUIT_INST_DEF._make( - struct.unpack( - formats.CUSTOM_CIRCUIT_INST_DEF_PACK, - file_obj.read(formats.CUSTOM_CIRCUIT_INST_DEF_SIZE), - ) - ) - else: - data = formats.CUSTOM_CIRCUIT_INST_DEF_V2._make( - struct.unpack( - formats.CUSTOM_CIRCUIT_INST_DEF_V2_PACK, - file_obj.read(formats.CUSTOM_CIRCUIT_INST_DEF_V2_SIZE), - ) - ) - - name = file_obj.read(data.gate_name_size).decode(common.ENCODE) - type_str = data.type - definition_circuit = None - if data.custom_definition: - def_binary = file_obj.read(data.size) - if version < 3 or not name.startswith(r"###PauliEvolutionGate_"): - definition_circuit = common.data_from_binary( - def_binary, read_circuit, version=version - ) - elif name.startswith(r"###PauliEvolutionGate_"): - definition_circuit = common.data_from_binary( - def_binary, - _read_pauli_evolution_gate, - version=version, - vectors=vectors, - ) - if version < 5: - data_payload = ( - type_str, - data.num_qubits, - data.num_clbits, - definition_circuit, - ) - else: - base_gate = file_obj.read(data.base_gate_size) - data_payload = ( - type_str, - data.num_qubits, - data.num_clbits, - definition_circuit, - data.num_ctrl_qubits, - data.ctrl_state, - base_gate, - ) - custom_operations[name] = data_payload - return custom_operations - - -def _read_calibrations( # type: ignore[no-untyped-def] - file_obj, version, vectors, metadata_deserializer -): - calibrations = {} - - header = formats.CALIBRATION._make( - struct.unpack(formats.CALIBRATION_PACK, file_obj.read(formats.CALIBRATION_SIZE)) - ) - for _ in range(header.num_cals): - defheader = formats.CALIBRATION_DEF._make( - struct.unpack( - formats.CALIBRATION_DEF_PACK, - file_obj.read(formats.CALIBRATION_DEF_SIZE), - ) - ) - name = file_obj.read(defheader.name_size).decode(common.ENCODE) - qubits = tuple( - struct.unpack("!q", file_obj.read(struct.calcsize("!q")))[0] - for _ in range(defheader.num_qubits) - ) - params = tuple( - value.read_value(file_obj, version, vectors) - for _ in range(defheader.num_params) - ) - schedule = schedules.read_schedule_block( - file_obj, version, metadata_deserializer - ) - - if name not in calibrations: - calibrations[name] = {(qubits, params): schedule} - else: - calibrations[name][(qubits, params)] = schedule - - return calibrations - - -def _dumps_register(register, index_map): # type: ignore[no-untyped-def] - if isinstance(register, ClassicalRegister): - return register.name.encode(common.ENCODE) - # Clbit. - return b"\x00" + str(index_map["c"][register]).encode(common.ENCODE) - - -def _dumps_instruction_parameter(param, index_map): # type: ignore[no-untyped-def] - if isinstance(param, QuantumCircuit): - type_key = type_keys.Program.CIRCUIT - data_bytes = common.data_to_binary(param, write_circuit) - elif isinstance(param, range): - type_key = type_keys.Container.RANGE - data_bytes = struct.pack( - formats.RANGE_PACK, param.start, param.stop, param.step - ) - elif isinstance(param, tuple): - type_key = type_keys.Container.TUPLE - data_bytes = common.sequence_to_binary( - param, _dumps_instruction_parameter, index_map=index_map - ) - elif isinstance(param, int): - # TODO This uses little endian. This should be fixed in next QPY version. - type_key = type_keys.Value.INTEGER - data_bytes = struct.pack(" 0: - if version < 4: - registers = _read_registers(file_obj, num_registers) - else: - registers = _read_registers_v4(file_obj, num_registers) - - for bit_type_label, bit_type, reg_type in [ - ("q", Qubit, QuantumRegister), - ("c", Clbit, ClassicalRegister), - ]: - # This does two passes through the registers. In the first, we're actually just - # constructing the `Bit` instances: any register that is `standalone` "owns" all its - # bits in the old Qiskit data model, so we have to construct those by creating the - # register and taking the bits from them. That's the case even if that register isn't - # actually in the circuit, which is why we stored them (with `in_circuit=False`) in QPY. - # - # Since there's no guarantees in QPY about the ordering of registers, we have to pass - # through all registers to create the bits first, because we can't reliably know if a - # non-standalone register contains bits from a standalone one until we've seen all - # standalone registers. - typed_bits = out_bits[bit_type_label] - typed_registers = registers[bit_type_label] - for register_name, ( - standalone, - indices, - _incircuit, - ) in typed_registers.items(): - if not standalone: - continue - register = reg_type(len(indices), register_name) - out_registers[bit_type_label][register_name] = register - for owned, index in zip(register, indices): - # Negative indices are for bits that aren't in the circuit. - if index >= 0: - typed_bits[index] = owned - # Any remaining unset bits aren't owned, so we can construct them in the standard way. - typed_bits = [bit if bit is not None else bit_type() for bit in typed_bits] - # Finally _properly_ construct all the registers. Bits can be in more than one - # register, including bits that are old-style "owned" by a register. - for register_name, ( - standalone, - indices, - in_circuit, - ) in typed_registers.items(): - if standalone: - register = out_registers[bit_type_label][register_name] - else: - register = reg_type( - name=register_name, - bits=[typed_bits[x] if x >= 0 else bit_type() for x in indices], - ) - out_registers[bit_type_label][register_name] = register - if in_circuit: - all_registers.append(register) - out_bits[bit_type_label] = typed_bits - else: - out_bits = { - "q": [Qubit() for _ in out_bits["q"]], - "c": [Clbit() for _ in out_bits["c"]], - } - circ = QuantumCircuit( - out_bits["q"], - out_bits["c"], - *all_registers, - name=name, - global_phase=global_phase, - metadata=metadata, - ) - - custom_operations = _read_custom_operations(file_obj, version, vectors) - for _instruction in range(num_instructions): - _read_instruction( - file_obj, circ, out_registers, custom_operations, version, vectors - ) - - # Read calibrations - if version >= 5: - circ.calibrations = _read_calibrations( - file_obj, version, vectors, metadata_deserializer - ) - - for vec_name, (vector, initialized_params) in vectors.items(): - if len(initialized_params) != len(vector): - warnings.warn( - f"The ParameterVector: '{vec_name}' is not fully identical to its " - "pre-serialization state. Elements " - f"{', '.join([str(x) for x in set(range(len(vector))) - initialized_params])} " - "in the ParameterVector will be not equal to the pre-serialized ParameterVector " - f"as they weren't used in the circuit: {circ.name}", - UserWarning, - ) - - return circ diff --git a/qiskit_ibm_runtime/qpy/binary_io/schedules.py b/qiskit_ibm_runtime/qpy/binary_io/schedules.py deleted file mode 100644 index 60948c3789..0000000000 --- a/qiskit_ibm_runtime/qpy/binary_io/schedules.py +++ /dev/null @@ -1,524 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2022. -# -# 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=invalid-name - -"""Read and write schedule and schedule instructions.""" -import json -import struct -import zlib -import warnings - -import numpy as np - -from qiskit.pulse import library, channels, instructions -from qiskit.pulse.schedule import ScheduleBlock -from qiskit.utils import optionals as _optional -from .. import formats, common, type_keys -from ..exceptions import QpyError -from . import value - - -if _optional.HAS_SYMENGINE: - import symengine as sym -else: - import sympy as sym - - -def _read_channel(file_obj, version): # type: ignore[no-untyped-def] - type_key = common.read_type_key(file_obj) - index = value.read_value(file_obj, version, {}) - - channel_cls = type_keys.ScheduleChannel.retrieve(type_key) - - return channel_cls(index) - - -def _read_waveform(file_obj, version): # type: ignore[no-untyped-def] - header = formats.WAVEFORM._make( - struct.unpack( - formats.WAVEFORM_PACK, - file_obj.read(formats.WAVEFORM_SIZE), - ) - ) - samples_raw = file_obj.read(header.data_size) - samples = common.data_from_binary(samples_raw, np.load) - name = value.read_value(file_obj, version, {}) - - return library.Waveform( - samples=samples, - name=name, - epsilon=header.epsilon, - limit_amplitude=header.amp_limited, - ) - - -def _loads_symbolic_expr(expr_bytes): # type: ignore[no-untyped-def] - from sympy import parse_expr # pylint: disable=import-outside-toplevel - - if expr_bytes == b"": - return None - - expr_txt = zlib.decompress(expr_bytes).decode(common.ENCODE) - expr = parse_expr(expr_txt) - - if _optional.HAS_SYMENGINE: - from symengine import sympify # pylint: disable=import-outside-toplevel - - return sympify(expr) - return expr - - -def _read_symbolic_pulse(file_obj, version): # type: ignore[no-untyped-def] - make = formats.SYMBOLIC_PULSE._make - pack = formats.SYMBOLIC_PULSE_PACK - size = formats.SYMBOLIC_PULSE_SIZE - - header = make( - struct.unpack( - pack, - file_obj.read(size), - ) - ) - pulse_type = file_obj.read(header.type_size).decode(common.ENCODE) - envelope = _loads_symbolic_expr(file_obj.read(header.envelope_size)) - constraints = _loads_symbolic_expr(file_obj.read(header.constraints_size)) - valid_amp_conditions = _loads_symbolic_expr( - file_obj.read(header.valid_amp_conditions_size) - ) - parameters = common.read_mapping( - file_obj, - deserializer=value.loads_value, - version=version, - vectors={}, - ) - - # In the transition to Qiskit Terra 0.23 (QPY version 6), the representation of library pulses - # was changed from complex "amp" to float "amp" and "angle". The existing library pulses in - # previous versions are handled here separately to conform with the new representation. To - # avoid role assumption for "amp" for custom pulses, only the library pulses are handled this - # way. - - # List of pulses in the library in QPY version 5 and below: - legacy_library_pulses = ["Gaussian", "GaussianSquare", "Drag", "Constant"] - class_name = "SymbolicPulse" # Default class name, if not in the library - - if pulse_type in legacy_library_pulses: - # Once complex amp support will be deprecated we will need: - # parameters["angle"] = np.angle(parameters["amp"]) - # parameters["amp"] = np.abs(parameters["amp"]) - - # In the meanwhile we simply add: - parameters["angle"] = 0 - _amp, _angle = sym.symbols("amp, angle") - envelope = envelope.subs(_amp, _amp * sym.exp(sym.I * _angle)) - - # And warn that this will change in future releases: - warnings.warn( - "Complex amp support for symbolic library pulses will be deprecated. " - "Once deprecated, library pulses loaded from old QPY files (Terra version < 0.23)," - " will be converted automatically to float (amp,angle) representation.", - PendingDeprecationWarning, - ) - class_name = "ScalableSymbolicPulse" - - duration = value.read_value(file_obj, version, {}) - name = value.read_value(file_obj, version, {}) - - if class_name == "SymbolicPulse": - return library.SymbolicPulse( - pulse_type=pulse_type, - duration=duration, - parameters=parameters, - name=name, - limit_amplitude=header.amp_limited, - envelope=envelope, - constraints=constraints, - valid_amp_conditions=valid_amp_conditions, - ) - elif class_name == "ScalableSymbolicPulse": - return library.ScalableSymbolicPulse( - pulse_type=pulse_type, - duration=duration, - amp=parameters["amp"], - angle=parameters["angle"], - parameters=parameters, - name=name, - limit_amplitude=header.amp_limited, - envelope=envelope, - constraints=constraints, - valid_amp_conditions=valid_amp_conditions, - ) - else: - raise NotImplementedError(f"Unknown class '{class_name}'") - - -def _read_symbolic_pulse_v6(file_obj, version): # type: ignore[no-untyped-def] - make = formats.SYMBOLIC_PULSE_V2._make - pack = formats.SYMBOLIC_PULSE_PACK_V2 - size = formats.SYMBOLIC_PULSE_SIZE_V2 - - header = make( - struct.unpack( - pack, - file_obj.read(size), - ) - ) - class_name = file_obj.read(header.class_name_size).decode(common.ENCODE) - pulse_type = file_obj.read(header.type_size).decode(common.ENCODE) - envelope = _loads_symbolic_expr(file_obj.read(header.envelope_size)) - constraints = _loads_symbolic_expr(file_obj.read(header.constraints_size)) - valid_amp_conditions = _loads_symbolic_expr( - file_obj.read(header.valid_amp_conditions_size) - ) - parameters = common.read_mapping( - file_obj, - deserializer=value.loads_value, - version=version, - vectors={}, - ) - - duration = value.read_value(file_obj, version, {}) - name = value.read_value(file_obj, version, {}) - - if class_name == "SymbolicPulse": - return library.SymbolicPulse( - pulse_type=pulse_type, - duration=duration, - parameters=parameters, - name=name, - limit_amplitude=header.amp_limited, - envelope=envelope, - constraints=constraints, - valid_amp_conditions=valid_amp_conditions, - ) - elif class_name == "ScalableSymbolicPulse": - return library.ScalableSymbolicPulse( - pulse_type=pulse_type, - duration=duration, - amp=parameters["amp"], - angle=parameters["angle"], - parameters=parameters, - name=name, - limit_amplitude=header.amp_limited, - envelope=envelope, - constraints=constraints, - valid_amp_conditions=valid_amp_conditions, - ) - else: - raise NotImplementedError(f"Unknown class '{class_name}'") - - -def _read_alignment_context(file_obj, version): # type: ignore[no-untyped-def] - type_key = common.read_type_key(file_obj) - - context_params = common.read_sequence( - file_obj, - deserializer=value.loads_value, - version=version, - vectors={}, - ) - context_cls = type_keys.ScheduleAlignment.retrieve(type_key) - - instance = object.__new__(context_cls) - instance._context_params = tuple(context_params) - - return instance - - -def _loads_operand(type_key, data_bytes, version): # type: ignore[no-untyped-def] - if type_key == type_keys.ScheduleOperand.WAVEFORM: - return common.data_from_binary(data_bytes, _read_waveform, version=version) - if type_key == type_keys.ScheduleOperand.SYMBOLIC_PULSE: - if version < 6: - return common.data_from_binary( - data_bytes, _read_symbolic_pulse, version=version - ) - else: - return common.data_from_binary( - data_bytes, _read_symbolic_pulse_v6, version=version - ) - if type_key == type_keys.ScheduleOperand.CHANNEL: - return common.data_from_binary(data_bytes, _read_channel, version=version) - if type_key == type_keys.ScheduleOperand.OPERAND_STR: - return data_bytes.decode(common.ENCODE) - - return value.loads_value(type_key, data_bytes, version, {}) - - -def _read_element(file_obj, version, metadata_deserializer): # type: ignore[no-untyped-def] - type_key = common.read_type_key(file_obj) - - if type_key == type_keys.Program.SCHEDULE_BLOCK: - return read_schedule_block(file_obj, version, metadata_deserializer) - - operands = common.read_sequence( - file_obj, deserializer=_loads_operand, version=version - ) - name = value.read_value(file_obj, version, {}) - - instance = object.__new__(type_keys.ScheduleInstruction.retrieve(type_key)) - instance._operands = tuple(operands) - instance._name = name - instance._hash = None - - return instance - - -def _loads_reference_item( # type: ignore[no-untyped-def] - type_key, data_bytes, version, metadata_deserializer -): - if type_key == type_keys.Value.NULL: - return None - if type_key == type_keys.Program.SCHEDULE_BLOCK: - return common.data_from_binary( - data_bytes, - deserializer=read_schedule_block, - version=version, - metadata_deserializer=metadata_deserializer, - ) - - raise QpyError( - f"Loaded schedule reference item is neither None nor ScheduleBlock. " - f"Type key {type_key} is not valid data type for a reference items. " - "This data cannot be loaded. Please check QPY version." - ) - - -def _write_channel(file_obj, data): # type: ignore[no-untyped-def] - type_key = type_keys.ScheduleChannel.assign(data) - common.write_type_key(file_obj, type_key) - value.write_value(file_obj, data.index) - - -def _write_waveform(file_obj, data): # type: ignore[no-untyped-def] - samples_bytes = common.data_to_binary(data.samples, np.save) - - header = struct.pack( - formats.WAVEFORM_PACK, - data.epsilon, - len(samples_bytes), - data._limit_amplitude, - ) - file_obj.write(header) - file_obj.write(samples_bytes) - value.write_value(file_obj, data.name) - - -def _dumps_symbolic_expr(expr): # type: ignore[no-untyped-def] - from sympy import srepr, sympify # pylint: disable=import-outside-toplevel - - if expr is None: - return b"" - - expr_bytes = srepr(sympify(expr)).encode(common.ENCODE) - return zlib.compress(expr_bytes) - - -def _write_symbolic_pulse(file_obj, data): # type: ignore[no-untyped-def] - class_name_bytes = data.__class__.__name__.encode(common.ENCODE) - pulse_type_bytes = data.pulse_type.encode(common.ENCODE) - envelope_bytes = _dumps_symbolic_expr(data.envelope) - constraints_bytes = _dumps_symbolic_expr(data.constraints) - valid_amp_conditions_bytes = _dumps_symbolic_expr(data.valid_amp_conditions) - - header_bytes = struct.pack( - formats.SYMBOLIC_PULSE_PACK_V2, - len(class_name_bytes), - len(pulse_type_bytes), - len(envelope_bytes), - len(constraints_bytes), - len(valid_amp_conditions_bytes), - data._limit_amplitude, - ) - file_obj.write(header_bytes) - file_obj.write(class_name_bytes) - file_obj.write(pulse_type_bytes) - file_obj.write(envelope_bytes) - file_obj.write(constraints_bytes) - file_obj.write(valid_amp_conditions_bytes) - common.write_mapping( - file_obj, - mapping=data._params, - serializer=value.dumps_value, - ) - value.write_value(file_obj, data.duration) - value.write_value(file_obj, data.name) - - -def _write_alignment_context(file_obj, context): # type: ignore[no-untyped-def] - type_key = type_keys.ScheduleAlignment.assign(context) - common.write_type_key(file_obj, type_key) - common.write_sequence( - file_obj, - sequence=context._context_params, - serializer=value.dumps_value, - ) - - -def _dumps_operand(operand): # type: ignore[no-untyped-def] - if isinstance(operand, library.Waveform): - type_key = type_keys.ScheduleOperand.WAVEFORM - data_bytes = common.data_to_binary(operand, _write_waveform) - elif isinstance(operand, library.SymbolicPulse): - type_key = type_keys.ScheduleOperand.SYMBOLIC_PULSE - data_bytes = common.data_to_binary(operand, _write_symbolic_pulse) - elif isinstance(operand, channels.Channel): - type_key = type_keys.ScheduleOperand.CHANNEL - data_bytes = common.data_to_binary(operand, _write_channel) - elif isinstance(operand, str): - type_key = type_keys.ScheduleOperand.OPERAND_STR - data_bytes = operand.encode(common.ENCODE) - else: - type_key, data_bytes = value.dumps_value(operand) - - return type_key, data_bytes - - -def _write_element(file_obj, element, metadata_serializer): # type: ignore[no-untyped-def] - if isinstance(element, ScheduleBlock): - common.write_type_key(file_obj, type_keys.Program.SCHEDULE_BLOCK) - write_schedule_block(file_obj, element, metadata_serializer) - else: - type_key = type_keys.ScheduleInstruction.assign(element) - common.write_type_key(file_obj, type_key) - common.write_sequence( - file_obj, - sequence=element.operands, - serializer=_dumps_operand, - ) - value.write_value(file_obj, element.name) - - -def _dumps_reference_item(schedule, metadata_serializer): # type: ignore[no-untyped-def] - if schedule is None: - type_key = type_keys.Value.NULL - data_bytes = b"" - else: - type_key = type_keys.Program.SCHEDULE_BLOCK - data_bytes = common.data_to_binary( - obj=schedule, - serializer=write_schedule_block, - metadata_serializer=metadata_serializer, - ) - return type_key, data_bytes - - -def read_schedule_block(file_obj, version, metadata_deserializer=None): # type: ignore[no-untyped-def] - """Read a single ScheduleBlock from the file like object. - - Args: - file_obj (File): A file like object that contains the QPY binary data. - version (int): QPY version. - metadata_deserializer (JSONDecoder): An optional JSONDecoder class - that will be used for the ``cls`` kwarg on the internal - ``json.load`` call used to deserialize the JSON payload used for - the :attr:`.ScheduleBlock.metadata` attribute for a schdule block - in the file-like object. If this is not specified the circuit metadata will - be parsed as JSON with the stdlib ``json.load()`` function using - the default ``JSONDecoder`` class. - - Returns: - ScheduleBlock: The schedule block object from the file. - - Raises: - TypeError: If any of the instructions is invalid data format. - QiskitError: QPY version is earlier than block support. - """ - - data = formats.SCHEDULE_BLOCK_HEADER._make( - struct.unpack( - formats.SCHEDULE_BLOCK_HEADER_PACK, - file_obj.read(formats.SCHEDULE_BLOCK_HEADER_SIZE), - ) - ) - name = file_obj.read(data.name_size).decode(common.ENCODE) - metadata_raw = file_obj.read(data.metadata_size) - metadata = json.loads(metadata_raw, cls=metadata_deserializer) - context = _read_alignment_context(file_obj, version) - - block = ScheduleBlock( - name=name, - metadata=metadata, - alignment_context=context, - ) - for _ in range(data.num_elements): - block_elm = _read_element(file_obj, version, metadata_deserializer) - block.append(block_elm, inplace=True) - - # Load references - if version >= 7: - flat_key_refdict = common.read_mapping( - file_obj=file_obj, - deserializer=_loads_reference_item, - version=version, - metadata_deserializer=metadata_deserializer, - ) - ref_dict = {} - for key_str, schedule in flat_key_refdict.items(): - if schedule is not None: - composite_key = tuple( - key_str.split(instructions.Reference.key_delimiter) - ) - ref_dict[composite_key] = schedule - if ref_dict: - block.assign_references(ref_dict, inplace=True) - - return block - - -def write_schedule_block(file_obj, block, metadata_serializer=None): # type: ignore[no-untyped-def] - """Write a single ScheduleBlock object in the file like object. - - Args: - file_obj (File): The file like object to write the circuit data in. - block (ScheduleBlock): A schedule block data to write. - metadata_serializer (JSONEncoder): An optional JSONEncoder class that - will be passed the :attr:`.ScheduleBlock.metadata` dictionary for - ``block`` and will be used as the ``cls`` kwarg - on the ``json.dump()`` call to JSON serialize that dictionary. - - Raises: - TypeError: If any of the instructions is invalid data format. - """ - metadata = json.dumps( - block.metadata, separators=(",", ":"), cls=metadata_serializer - ).encode(common.ENCODE) - block_name = block.name.encode(common.ENCODE) - - # Write schedule block header - header_raw = formats.SCHEDULE_BLOCK_HEADER( - name_size=len(block_name), - metadata_size=len(metadata), - num_elements=len(block), - ) - header = struct.pack(formats.SCHEDULE_BLOCK_HEADER_PACK, *header_raw) - file_obj.write(header) - file_obj.write(block_name) - file_obj.write(metadata) - - _write_alignment_context(file_obj, block.alignment_context) - for block_elm in block._blocks: - _write_element(file_obj, block_elm, metadata_serializer) - - # Write references - flat_key_refdict = {} - for ref_keys, schedule in block._reference_manager.items(): - # Do not call block.reference. This returns the reference of most outer program by design. - key_str = instructions.Reference.key_delimiter.join(ref_keys) - flat_key_refdict[key_str] = schedule - common.write_mapping( - file_obj=file_obj, - mapping=flat_key_refdict, - serializer=_dumps_reference_item, - metadata_serializer=metadata_serializer, - ) diff --git a/qiskit_ibm_runtime/qpy/binary_io/value.py b/qiskit_ibm_runtime/qpy/binary_io/value.py deleted file mode 100644 index 4e71fc4d1b..0000000000 --- a/qiskit_ibm_runtime/qpy/binary_io/value.py +++ /dev/null @@ -1,339 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021, 2022. -# -# 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. - -"""Binary IO for any value objects, such as numbers, string, parameters.""" - -import struct -import uuid - -import numpy as np - -from qiskit.circuit import CASE_DEFAULT -from qiskit.circuit.parameter import Parameter -from qiskit.circuit.parameterexpression import ParameterExpression -from qiskit.circuit.parametervector import ParameterVector, ParameterVectorElement -from qiskit.utils import optionals as _optional - -from .. import common, formats, exceptions, type_keys - - -def _write_parameter(file_obj, obj): # type: ignore[no-untyped-def] - name_bytes = obj._name.encode(common.ENCODE) - file_obj.write( - struct.pack(formats.PARAMETER_PACK, len(name_bytes), obj._uuid.bytes) - ) - file_obj.write(name_bytes) - - -def _write_parameter_vec(file_obj, obj): # type: ignore[no-untyped-def] - name_bytes = obj._vector._name.encode(common.ENCODE) - file_obj.write( - struct.pack( - formats.PARAMETER_VECTOR_ELEMENT_PACK, - len(name_bytes), - obj._vector._size, - obj._uuid.bytes, - obj._index, - ) - ) - file_obj.write(name_bytes) - - -def _write_parameter_expression(file_obj, obj): # type: ignore[no-untyped-def] - from sympy import srepr, sympify # pylint: disable=import-outside-toplevel - - expr_bytes = srepr(sympify(obj._symbol_expr)).encode(common.ENCODE) - param_expr_header_raw = struct.pack( - formats.PARAMETER_EXPR_PACK, len(obj._parameter_symbols), len(expr_bytes) - ) - file_obj.write(param_expr_header_raw) - file_obj.write(expr_bytes) - - for symbol, value in obj._parameter_symbols.items(): - symbol_key = type_keys.Value.assign(symbol) - - # serialize key - if symbol_key == type_keys.Value.PARAMETER_VECTOR: - symbol_data = common.data_to_binary(symbol, _write_parameter_vec) - else: - symbol_data = common.data_to_binary(symbol, _write_parameter) - - # serialize value - if value == symbol._symbol_expr: - value_key = symbol_key - value_data = bytes() - else: - value_key, value_data = dumps_value(value) - - elem_header = struct.pack( - formats.PARAM_EXPR_MAP_ELEM_V3_PACK, - symbol_key, - value_key, - len(value_data), - ) - file_obj.write(elem_header) - file_obj.write(symbol_data) - file_obj.write(value_data) - - -def _read_parameter(file_obj): # type: ignore[no-untyped-def] - data = formats.PARAMETER( - *struct.unpack(formats.PARAMETER_PACK, file_obj.read(formats.PARAMETER_SIZE)) - ) - param_uuid = uuid.UUID(bytes=data.uuid) - name = file_obj.read(data.name_size).decode(common.ENCODE) - param = Parameter.__new__(Parameter, name, uuid=param_uuid) - param.__init__(name) # pylint: disable=unnecessary-dunder-call - return param - - -def _read_parameter_vec(file_obj, vectors): # type: ignore[no-untyped-def] - data = formats.PARAMETER_VECTOR_ELEMENT( - *struct.unpack( - formats.PARAMETER_VECTOR_ELEMENT_PACK, - file_obj.read(formats.PARAMETER_VECTOR_ELEMENT_SIZE), - ), - ) - param_uuid = uuid.UUID(bytes=data.uuid) - name = file_obj.read(data.vector_name_size).decode(common.ENCODE) - if name not in vectors: - vectors[name] = (ParameterVector(name, data.vector_size), set()) - vector = vectors[name][0] - if vector[data.index]._uuid != param_uuid: - vectors[name][1].add(data.index) - vector._params[data.index] = ParameterVectorElement.__new__( - ParameterVectorElement, vector, data.index, uuid=param_uuid - ) - vector._params[data.index].__init__( # pylint: disable=unnecessary-dunder-call - vector, data.index - ) - return vector[data.index] - - -def _read_parameter_expression(file_obj): # type: ignore[no-untyped-def] - data = formats.PARAMETER_EXPR( - *struct.unpack( - formats.PARAMETER_EXPR_PACK, file_obj.read(formats.PARAMETER_EXPR_SIZE) - ) - ) - # pylint: disable=import-outside-toplevel - from sympy.parsing.sympy_parser import parse_expr - - if _optional.HAS_SYMENGINE: - import symengine # pylint: disable=import-outside-toplevel - - expr = symengine.sympify( - parse_expr(file_obj.read(data.expr_size).decode(common.ENCODE)) - ) - else: - expr = parse_expr(file_obj.read(data.expr_size).decode(common.ENCODE)) - symbol_map = {} - for _ in range(data.map_elements): - elem_data = formats.PARAM_EXPR_MAP_ELEM( - *struct.unpack( - formats.PARAM_EXPR_MAP_ELEM_PACK, - file_obj.read(formats.PARAM_EXPR_MAP_ELEM_SIZE), - ) - ) - symbol = _read_parameter(file_obj) - - elem_key = type_keys.Value(elem_data.type) - binary_data = file_obj.read(elem_data.size) - if elem_key == type_keys.Value.INTEGER: - value = struct.unpack("!q", binary_data) - elif elem_key == type_keys.Value.FLOAT: - value = struct.unpack("!d", binary_data) - elif elem_key == type_keys.Value.COMPLEX: - value = complex(*struct.unpack(formats.COMPLEX_PACK, binary_data)) - elif elem_key == type_keys.Value.PARAMETER: - value = symbol._symbol_expr - elif elem_key == type_keys.Value.PARAMETER_EXPRESSION: - value = common.data_from_binary(binary_data, _read_parameter_expression) - else: - raise exceptions.QpyError( - "Invalid parameter expression map type: %s" % elem_key - ) - symbol_map[symbol] = value - - return ParameterExpression(symbol_map, expr) - - -def _read_parameter_expression_v3(file_obj, vectors): # type: ignore[no-untyped-def] - data = formats.PARAMETER_EXPR( - *struct.unpack( - formats.PARAMETER_EXPR_PACK, file_obj.read(formats.PARAMETER_EXPR_SIZE) - ) - ) - # pylint: disable=import-outside-toplevel - from sympy.parsing.sympy_parser import parse_expr - - if _optional.HAS_SYMENGINE: - import symengine # pylint: disable=import-outside-toplevel - - expr = symengine.sympify( - parse_expr(file_obj.read(data.expr_size).decode(common.ENCODE)) - ) - else: - expr = parse_expr(file_obj.read(data.expr_size).decode(common.ENCODE)) - symbol_map = {} - for _ in range(data.map_elements): - elem_data = formats.PARAM_EXPR_MAP_ELEM_V3( - *struct.unpack( - formats.PARAM_EXPR_MAP_ELEM_V3_PACK, - file_obj.read(formats.PARAM_EXPR_MAP_ELEM_V3_SIZE), - ) - ) - symbol_key = type_keys.Value(elem_data.symbol_type) - - if symbol_key == type_keys.Value.PARAMETER: - symbol = _read_parameter(file_obj) - elif symbol_key == type_keys.Value.PARAMETER_VECTOR: - symbol = _read_parameter_vec(file_obj, vectors) - else: - raise exceptions.QpyError( - "Invalid parameter expression map type: %s" % symbol_key - ) - - elem_key = type_keys.Value(elem_data.type) - binary_data = file_obj.read(elem_data.size) - if elem_key == type_keys.Value.INTEGER: - value = struct.unpack("!q", binary_data) - elif elem_key == type_keys.Value.FLOAT: - value = struct.unpack("!d", binary_data) - elif elem_key == type_keys.Value.COMPLEX: - value = complex(*struct.unpack(formats.COMPLEX_PACK, binary_data)) - elif elem_key in (type_keys.Value.PARAMETER, type_keys.Value.PARAMETER_VECTOR): - value = symbol._symbol_expr - elif elem_key == type_keys.Value.PARAMETER_EXPRESSION: - value = common.data_from_binary( - binary_data, _read_parameter_expression_v3, vectors=vectors - ) - else: - raise exceptions.QpyError( - "Invalid parameter expression map type: %s" % elem_key - ) - symbol_map[symbol] = value - - return ParameterExpression(symbol_map, expr) - - -def dumps_value(obj): # type: ignore[no-untyped-def] - """Serialize input value object. - Args: - obj (any): Arbitrary value object to serialize. - Returns: - tuple: TypeKey and binary data. - Raises: - QpyError: Serializer for given format is not ready. - """ - type_key = type_keys.Value.assign(obj) - - if type_key == type_keys.Value.INTEGER: - binary_data = struct.pack("!q", obj) - elif type_key == type_keys.Value.FLOAT: - binary_data = struct.pack("!d", obj) - elif type_key == type_keys.Value.COMPLEX: - binary_data = struct.pack(formats.COMPLEX_PACK, obj.real, obj.imag) - elif type_key == type_keys.Value.NUMPY_OBJ: - binary_data = common.data_to_binary(obj, np.save) - elif type_key == type_keys.Value.STRING: - binary_data = obj.encode(common.ENCODE) - elif type_key in (type_keys.Value.NULL, type_keys.Value.CASE_DEFAULT): - binary_data = b"" - elif type_key == type_keys.Value.PARAMETER_VECTOR: - binary_data = common.data_to_binary(obj, _write_parameter_vec) - elif type_key == type_keys.Value.PARAMETER: - binary_data = common.data_to_binary(obj, _write_parameter) - elif type_key == type_keys.Value.PARAMETER_EXPRESSION: - binary_data = common.data_to_binary( - obj, _write_parameter_expression - ) # type: ignore[no-untyped-call] - else: - raise exceptions.QpyError( - f"Serialization for {type_key} is not implemented in value I/O." - ) - - return type_key, binary_data - - -def write_value(file_obj, obj): # type: ignore[no-untyped-def] - """Write a value to the file like object. - Args: - file_obj (File): A file like object to write data. - obj (any): Value to write. - """ - type_key, data = dumps_value(obj) - common.write_generic_typed_data(file_obj, type_key, data) - - -def loads_value(type_key, binary_data, version, vectors): # type: ignore[no-untyped-def] - """Deserialize input binary data to value object. - Args: - type_key (ValueTypeKey): Type enum information. - binary_data (bytes): Data to deserialize. - version (int): QPY version. - vectors (dict): ParameterVector in current scope. - Returns: - any: Deserialized value object. - Raises: - QpyError: Serializer for given format is not ready. - """ - # pylint: disable=too-many-return-statements - - if isinstance(type_key, bytes): - type_key = type_keys.Value(type_key) - - if type_key == type_keys.Value.INTEGER: - return struct.unpack("!q", binary_data)[0] - if type_key == type_keys.Value.FLOAT: - return struct.unpack("!d", binary_data)[0] - if type_key == type_keys.Value.COMPLEX: - return complex(*struct.unpack(formats.COMPLEX_PACK, binary_data)) - if type_key == type_keys.Value.NUMPY_OBJ: - return common.data_from_binary(binary_data, np.load) - if type_key == type_keys.Value.STRING: - return binary_data.decode(common.ENCODE) - if type_key == type_keys.Value.NULL: - return None - if type_key == type_keys.Value.CASE_DEFAULT: - return CASE_DEFAULT - if type_key == type_keys.Value.PARAMETER_VECTOR: - return common.data_from_binary( - binary_data, _read_parameter_vec, vectors=vectors - ) - if type_key == type_keys.Value.PARAMETER: - return common.data_from_binary(binary_data, _read_parameter) - if type_key == type_keys.Value.PARAMETER_EXPRESSION: - if version < 3: - return common.data_from_binary(binary_data, _read_parameter_expression) - else: - return common.data_from_binary( - binary_data, _read_parameter_expression_v3, vectors=vectors - ) - - raise exceptions.QpyError( - f"Serialization for {type_key} is not implemented in value I/O." - ) - - -def read_value(file_obj, version, vectors): # type: ignore[no-untyped-def] - """Read a value from the file like object. - Args: - file_obj (File): A file like object to write data. - version (int): QPY version. - vectors (dict): ParameterVector in current scope. - Returns: - any: Deserialized value object. - """ - type_key, data = common.read_generic_typed_data(file_obj) - - return loads_value(type_key, data, version, vectors) diff --git a/qiskit_ibm_runtime/qpy/common.py b/qiskit_ibm_runtime/qpy/common.py deleted file mode 100644 index 22a1fa42a5..0000000000 --- a/qiskit_ibm_runtime/qpy/common.py +++ /dev/null @@ -1,313 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2019. -# -# 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=too-many-return-statements - -""" -Common functions across several serialization and deserialization modules. -""" - -import io -import struct - -from . import formats - -QPY_VERSION = 7 -ENCODE = "utf8" - - -def read_generic_typed_data(file_obj): # type: ignore[no-untyped-def] - """Read a single data chunk from the file like object. - - Args: - file_obj (File): A file like object that contains the QPY binary data. - - Returns: - tuple: Tuple of type key binary and the bytes object of the single data. - """ - data = formats.INSTRUCTION_PARAM._make( - struct.unpack( - formats.INSTRUCTION_PARAM_PACK, - file_obj.read(formats.INSTRUCTION_PARAM_SIZE), - ) - ) - - return data.type, file_obj.read(data.size) - - -def read_sequence(file_obj, deserializer, **kwargs): # type: ignore[no-untyped-def] - """Read a sequence of data from the file like object. - - Args: - file_obj (File): A file like object that contains the QPY binary data. - deserializer (Callable): Deserializer callback that can handle input object type. - This must take type key and binary data of the element and return object. - **kwargs: Options set to the deserializer. - - Returns: - list: Deserialized object. - """ - sequence = [] - - data = formats.SEQUENCE._make( - struct.unpack(formats.SEQUENCE_PACK, file_obj.read(formats.SEQUENCE_SIZE)) - ) - for _ in range(data.num_elements): - type_key, datum_bytes = read_generic_typed_data(file_obj) - sequence.append(deserializer(type_key, datum_bytes, **kwargs)) - - return sequence - - -def read_mapping(file_obj, deserializer, **kwargs): # type: ignore[no-untyped-def] - """Read a mapping from the file like object. - - .. note:: - - This function must be used to make a binary data of mapping - which include QPY serialized values. - It's easier to use JSON serializer followed by encoding for standard data formats. - This only supports flat dictionary and key must be string. - - Args: - file_obj (File): A file like object that contains the QPY binary data. - deserializer (Callable): Deserializer callback that can handle mapping item. - This must take type key and binary data of the mapping value and return object. - **kwargs: Options set to the deserializer. - - Returns: - dict: Deserialized object. - """ - mapping = {} - - data = formats.SEQUENCE._make( - struct.unpack(formats.SEQUENCE_PACK, file_obj.read(formats.SEQUENCE_SIZE)) - ) - for _ in range(data.num_elements): - map_header = formats.MAP_ITEM._make( - struct.unpack(formats.MAP_ITEM_PACK, file_obj.read(formats.MAP_ITEM_SIZE)) - ) - key = file_obj.read(map_header.key_size).decode(ENCODE) - datum = deserializer(map_header.type, file_obj.read(map_header.size), **kwargs) - mapping[key] = datum - - return mapping - - -def read_type_key(file_obj): # type: ignore[no-untyped-def] - """Read a type key from the file like object. - - Args: - file_obj (File): A file like object that contains the QPY binary data. - - Returns: - bytes: Type key. - """ - key_size = struct.calcsize("!1c") - return struct.unpack("!1c", file_obj.read(key_size))[0] - - -def write_generic_typed_data(file_obj, type_key, data_binary): # type: ignore[no-untyped-def] - """Write statically typed binary data to the file like object. - - Args: - file_obj (File): A file like object to write data. - type_key (Enum): Object type of the data. - data_binary (bytes): Binary data to write. - """ - data_header = struct.pack( - formats.INSTRUCTION_PARAM_PACK, type_key, len(data_binary) - ) - file_obj.write(data_header) - file_obj.write(data_binary) - - -def write_sequence(file_obj, sequence, serializer, **kwargs): # type: ignore[no-untyped-def] - """Write a sequence of data in the file like object. - - Args: - file_obj (File): A file like object to write data. - sequence (Sequence): Object to serialize. - serializer (Callable): Serializer callback that can handle input object type. - This must return type key and binary data of each element. - **kwargs: Options set to the serializer. - """ - num_elements = len(sequence) - - file_obj.write(struct.pack(formats.SEQUENCE_PACK, num_elements)) - for datum in sequence: - type_key, datum_bytes = serializer(datum, **kwargs) - write_generic_typed_data(file_obj, type_key, datum_bytes) - - -def write_mapping(file_obj, mapping, serializer, **kwargs): # type: ignore[no-untyped-def] - """Write a mapping in the file like object. - - .. note:: - - This function must be used to make a binary data of mapping - which include QPY serialized values. - It's easier to use JSON serializer followed by encoding for standard data formats. - This only supports flat dictionary and key must be string. - - Args: - file_obj (File): A file like object to write data. - mapping (Mapping): Object to serialize. - serializer (Callable): Serializer callback that can handle mapping item. - This must return type key and binary data of the mapping value. - **kwargs: Options set to the serializer. - """ - num_elements = len(mapping) - - file_obj.write(struct.pack(formats.SEQUENCE_PACK, num_elements)) - for key, datum in mapping.items(): - key_bytes = key.encode(ENCODE) - type_key, datum_bytes = serializer(datum, **kwargs) - item_header = struct.pack( - formats.MAP_ITEM_PACK, len(key_bytes), type_key, len(datum_bytes) - ) - file_obj.write(item_header) - file_obj.write(key_bytes) - file_obj.write(datum_bytes) - - -def write_type_key(file_obj, type_key): # type: ignore[no-untyped-def] - """Write a type key in the file like object. - - Args: - file_obj (File): A file like object that contains the QPY binary data. - type_key (bytes): Type key to write. - """ - file_obj.write(struct.pack("!1c", type_key)) - - -def data_to_binary(obj, serializer, **kwargs): # type: ignore[no-untyped-def] - """Convert object into binary data with specified serializer. - - Args: - obj (any): Object to serialize. - serializer (Callable): Serializer callback that can handle input object type. - **kwargs: Options set to the serializer. - - Returns: - bytes: Binary data. - """ - with io.BytesIO() as container: - serializer(container, obj, **kwargs) - binary_data = container.getvalue() - - return binary_data - - -def sequence_to_binary(sequence, serializer, **kwargs): # type: ignore[no-untyped-def] - """Convert sequence into binary data with specified serializer. - - Args: - sequence (Sequence): Object to serialize. - serializer (Callable): Serializer callback that can handle input object type. - This must return type key and binary data of each element. - **kwargs: Options set to the serializer. - - Returns: - bytes: Binary data. - """ - with io.BytesIO() as container: - write_sequence(container, sequence, serializer, **kwargs) - binary_data = container.getvalue() - - return binary_data - - -def mapping_to_binary(mapping, serializer, **kwargs): # type: ignore[no-untyped-def] - """Convert mapping into binary data with specified serializer. - - .. note:: - - This function must be used to make a binary data of mapping - which include QPY serialized values. - It's easier to use JSON serializer followed by encoding for standard data formats. - This only supports flat dictionary and key must be string. - - Args: - mapping (Mapping): Object to serialize. - serializer (Callable): Serializer callback that can handle mapping item. - This must return type key and binary data of the mapping value. - **kwargs: Options set to the serializer. - - Returns: - bytes: Binary data. - """ - with io.BytesIO() as container: - write_mapping(container, mapping, serializer, **kwargs) - binary_data = container.getvalue() - - return binary_data - - -def data_from_binary(binary_data, deserializer, **kwargs): # type: ignore[no-untyped-def] - """Load object from binary data with specified deserializer. - - Args: - binary_data (bytes): Binary data to deserialize. - deserializer (Callable): Deserializer callback that can handle input object type. - **kwargs: Options set to the deserializer. - - Returns: - any: Deserialized object. - """ - with io.BytesIO(binary_data) as container: - container.seek(0) - obj = deserializer(container, **kwargs) - return obj - - -def sequence_from_binary(binary_data, deserializer, **kwargs): # type: ignore[no-untyped-def] - """Load object from binary sequence with specified deserializer. - - Args: - binary_data (bytes): Binary data to deserialize. - deserializer (Callable): Deserializer callback that can handle input object type. - This must take type key and binary data of the element and return object. - **kwargs: Options set to the deserializer. - - Returns: - any: Deserialized sequence. - """ - with io.BytesIO(binary_data) as container: - sequence = read_sequence(container, deserializer, **kwargs) - - return sequence - - -def mapping_from_binary(binary_data, deserializer, **kwargs): # type: ignore[no-untyped-def] - """Load object from binary mapping with specified deserializer. - - .. note:: - - This function must be used to make a binary data of mapping - which include QPY serialized values. - It's easier to use JSON serializer followed by encoding for standard data formats. - This only supports flat dictionary and key must be string. - - Args: - binary_data (bytes): Binary data to deserialize. - deserializer (Callable): Deserializer callback that can handle mapping item. - This must take type key and binary data of the mapping value and return object. - **kwargs: Options set to the deserializer. - - Returns: - dict: Deserialized object. - """ - with io.BytesIO(binary_data) as container: - mapping = read_mapping(container, deserializer, **kwargs) - - return mapping diff --git a/qiskit_ibm_runtime/qpy/exceptions.py b/qiskit_ibm_runtime/qpy/exceptions.py deleted file mode 100644 index 9b23810db3..0000000000 --- a/qiskit_ibm_runtime/qpy/exceptions.py +++ /dev/null @@ -1,28 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2022. -# -# 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. - -"""Exception for errors raised by the pulse module.""" -from typing import Any -from qiskit.exceptions import QiskitError - - -class QpyError(QiskitError): - """Errors raised by the qpy module.""" - - def __init__(self, *message: Any): - """Set the error message.""" - super().__init__(*message) - self.message = " ".join(message) - - def __str__(self) -> str: - """Return the message.""" - return repr(self.message) diff --git a/qiskit_ibm_runtime/qpy/formats.py b/qiskit_ibm_runtime/qpy/formats.py deleted file mode 100644 index c99336980f..0000000000 --- a/qiskit_ibm_runtime/qpy/formats.py +++ /dev/null @@ -1,277 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021, 2022. -# -# 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=invalid-name -# type: ignore[name-match] - -"""Binary format definition.""" - -import struct -from collections import namedtuple - - -# FILE_HEADER -FILE_HEADER = namedtuple( - "FILE_HEADER", - [ - "preface", - "qpy_version", - "major_version", - "minor_version", - "patch_version", - "num_programs", - ], -) -FILE_HEADER_PACK = "!6sBBBBQ" -FILE_HEADER_SIZE = struct.calcsize(FILE_HEADER_PACK) - -# CIRCUIT_HEADER_V2 -CIRCUIT_HEADER_V2 = namedtuple( - "HEADER", - [ - "name_size", - "global_phase_type", - "global_phase_size", - "num_qubits", - "num_clbits", - "metadata_size", - "num_registers", - "num_instructions", - ], -) -CIRCUIT_HEADER_V2_PACK = "!H1cHIIQIQ" -CIRCUIT_HEADER_V2_SIZE = struct.calcsize(CIRCUIT_HEADER_V2_PACK) - -# CIRCUIT_HEADER -CIRCUIT_HEADER = namedtuple( - "HEADER", - [ - "name_size", - "global_phase", - "num_qubits", - "num_clbits", - "metadata_size", - "num_registers", - "num_instructions", - ], -) -CIRCUIT_HEADER_PACK = "!HdIIQIQ" -CIRCUIT_HEADER_SIZE = struct.calcsize(CIRCUIT_HEADER_PACK) - -# REGISTER -REGISTER_V4 = namedtuple( - "REGISTER", ["type", "standalone", "size", "name_size", "in_circuit"] -) -REGISTER_V4_PACK = "!1c?IH?" -REGISTER_V4_SIZE = struct.calcsize(REGISTER_V4_PACK) - -REGISTER = namedtuple("REGISTER", ["type", "standalone", "size", "name_size"]) -REGISTER_PACK = "!1c?IH" -REGISTER_SIZE = struct.calcsize(REGISTER_PACK) - -# CIRCUIT_INSTRUCTION -CIRCUIT_INSTRUCTION = namedtuple( - "CIRCUIT_INSTRUCTION", - [ - "name_size", - "label_size", - "num_parameters", - "num_qargs", - "num_cargs", - "has_condition", - "condition_register_size", - "condition_value", - ], -) -CIRCUIT_INSTRUCTION_PACK = "!HHHII?Hq" -CIRCUIT_INSTRUCTION_SIZE = struct.calcsize(CIRCUIT_INSTRUCTION_PACK) - -# CIRCUIT_INSTRUCTION_V2 -CIRCUIT_INSTRUCTION_V2 = namedtuple( - "CIRCUIT_INSTRUCTION", - [ - "name_size", - "label_size", - "num_parameters", - "num_qargs", - "num_cargs", - "has_condition", - "condition_register_size", - "condition_value", - "num_ctrl_qubits", - "ctrl_state", - ], -) -CIRCUIT_INSTRUCTION_V2_PACK = "!HHHII?HqII" -CIRCUIT_INSTRUCTION_V2_SIZE = struct.calcsize(CIRCUIT_INSTRUCTION_V2_PACK) - - -# CIRCUIT_INSTRUCTION_ARG -CIRCUIT_INSTRUCTION_ARG = namedtuple("CIRCUIT_INSTRUCTION_ARG", ["type", "size"]) -CIRCUIT_INSTRUCTION_ARG_PACK = "!1cI" -CIRCUIT_INSTRUCTION_ARG_SIZE = struct.calcsize(CIRCUIT_INSTRUCTION_ARG_PACK) - -# SparsePauliOp List -SPARSE_PAULI_OP_LIST_ELEM = namedtuple("SPARSE_PAULI_OP_LIST_ELEMENT", ["size"]) -SPARSE_PAULI_OP_LIST_ELEM_PACK = "!Q" -SPARSE_PAULI_OP_LIST_ELEM_SIZE = struct.calcsize(SPARSE_PAULI_OP_LIST_ELEM_PACK) - -# Pauli Evolution Gate -PAULI_EVOLUTION_DEF = namedtuple( - "PAULI_EVOLUTION_DEF", - ["operator_size", "standalone_op", "time_type", "time_size", "synth_method_size"], -) -PAULI_EVOLUTION_DEF_PACK = "!Q?1cQQ" -PAULI_EVOLUTION_DEF_SIZE = struct.calcsize(PAULI_EVOLUTION_DEF_PACK) - -# CUSTOM_CIRCUIT_DEF_HEADER -CUSTOM_CIRCUIT_DEF_HEADER = namedtuple("CUSTOM_CIRCUIT_DEF_HEADER", ["size"]) -CUSTOM_CIRCUIT_DEF_HEADER_PACK = "!Q" -CUSTOM_CIRCUIT_DEF_HEADER_SIZE = struct.calcsize(CUSTOM_CIRCUIT_DEF_HEADER_PACK) - -# CUSTOM_CIRCUIT_INST_DEF_V2 -CUSTOM_CIRCUIT_INST_DEF_V2 = namedtuple( - "CUSTOM_CIRCUIT_INST_DEF", - [ - "gate_name_size", - "type", - "num_qubits", - "num_clbits", - "custom_definition", - "size", - "num_ctrl_qubits", - "ctrl_state", - "base_gate_size", - ], -) -CUSTOM_CIRCUIT_INST_DEF_V2_PACK = "!H1cII?QIIQ" -CUSTOM_CIRCUIT_INST_DEF_V2_SIZE = struct.calcsize(CUSTOM_CIRCUIT_INST_DEF_V2_PACK) - -# CUSTOM_CIRCUIT_INST_DEF -CUSTOM_CIRCUIT_INST_DEF = namedtuple( - "CUSTOM_CIRCUIT_INST_DEF", - ["gate_name_size", "type", "num_qubits", "num_clbits", "custom_definition", "size"], -) -CUSTOM_CIRCUIT_INST_DEF_PACK = "!H1cII?Q" -CUSTOM_CIRCUIT_INST_DEF_SIZE = struct.calcsize(CUSTOM_CIRCUIT_INST_DEF_PACK) - -# CALIBRATION -CALIBRATION = namedtuple("CALIBRATION", ["num_cals"]) -CALIBRATION_PACK = "!H" -CALIBRATION_SIZE = struct.calcsize(CALIBRATION_PACK) - -# CALIBRATION_DEF -CALIBRATION_DEF = namedtuple( - "CALIBRATION_DEF", ["name_size", "num_qubits", "num_params", "type"] -) -CALIBRATION_DEF_PACK = "!HHH1c" -CALIBRATION_DEF_SIZE = struct.calcsize(CALIBRATION_DEF_PACK) - -# SCHEDULE_BLOCK binary format -SCHEDULE_BLOCK_HEADER = namedtuple( - "SCHEDULE_BLOCK", - [ - "name_size", - "metadata_size", - "num_elements", - ], -) -SCHEDULE_BLOCK_HEADER_PACK = "!HQH" -SCHEDULE_BLOCK_HEADER_SIZE = struct.calcsize(SCHEDULE_BLOCK_HEADER_PACK) - -# WAVEFORM binary format -WAVEFORM = namedtuple("WAVEFORM", ["epsilon", "data_size", "amp_limited"]) -WAVEFORM_PACK = "!fI?" -WAVEFORM_SIZE = struct.calcsize(WAVEFORM_PACK) - -# SYMBOLIC_PULSE -SYMBOLIC_PULSE = namedtuple( - "SYMBOLIC_PULSE", - [ - "type_size", - "envelope_size", - "constraints_size", - "valid_amp_conditions_size", - "amp_limited", - ], -) -SYMBOLIC_PULSE_PACK = "!HHHH?" -SYMBOLIC_PULSE_SIZE = struct.calcsize(SYMBOLIC_PULSE_PACK) - -# SYMBOLIC_PULSE_V2 -SYMBOLIC_PULSE_V2 = namedtuple( - "SYMBOLIC_PULSE", - [ - "class_name_size", - "type_size", - "envelope_size", - "constraints_size", - "valid_amp_conditions_size", - "amp_limited", - ], -) -SYMBOLIC_PULSE_PACK_V2 = "!HHHHH?" -SYMBOLIC_PULSE_SIZE_V2 = struct.calcsize(SYMBOLIC_PULSE_PACK_V2) - -# INSTRUCTION_PARAM -INSTRUCTION_PARAM = namedtuple("INSTRUCTION_PARAM", ["type", "size"]) -INSTRUCTION_PARAM_PACK = "!1cQ" -INSTRUCTION_PARAM_SIZE = struct.calcsize(INSTRUCTION_PARAM_PACK) - -# PARAMETER -PARAMETER = namedtuple("PARAMETER", ["name_size", "uuid"]) -PARAMETER_PACK = "!H16s" -PARAMETER_SIZE = struct.calcsize(PARAMETER_PACK) - -# COMPLEX -COMPLEX = namedtuple("COMPLEX", ["real", "imag"]) -COMPLEX_PACK = "!dd" -COMPLEX_SIZE = struct.calcsize(COMPLEX_PACK) - -# PARAMETER_VECTOR_ELEMENT -PARAMETER_VECTOR_ELEMENT = namedtuple( - "PARAMETER_VECTOR_ELEMENT", ["vector_name_size", "vector_size", "uuid", "index"] -) -PARAMETER_VECTOR_ELEMENT_PACK = "!HQ16sQ" -PARAMETER_VECTOR_ELEMENT_SIZE = struct.calcsize(PARAMETER_VECTOR_ELEMENT_PACK) - -# PARAMETER_EXPR -PARAMETER_EXPR = namedtuple("PARAMETER_EXPR", ["map_elements", "expr_size"]) -PARAMETER_EXPR_PACK = "!QQ" -PARAMETER_EXPR_SIZE = struct.calcsize(PARAMETER_EXPR_PACK) - -# PARAMETER_EXPR_MAP_ELEM_V3 -PARAM_EXPR_MAP_ELEM_V3 = namedtuple( - "PARAMETER_EXPR_MAP_ELEM", ["symbol_type", "type", "size"] -) -PARAM_EXPR_MAP_ELEM_V3_PACK = "!ccQ" -PARAM_EXPR_MAP_ELEM_V3_SIZE = struct.calcsize(PARAM_EXPR_MAP_ELEM_V3_PACK) - -# PARAMETER_EXPR_MAP_ELEM -PARAM_EXPR_MAP_ELEM = namedtuple("PARAMETER_EXPR_MAP_ELEM", ["type", "size"]) -PARAM_EXPR_MAP_ELEM_PACK = "!cQ" -PARAM_EXPR_MAP_ELEM_SIZE = struct.calcsize(PARAM_EXPR_MAP_ELEM_PACK) - -# RANGE -RANGE = namedtuple("RANGE", ["start", "stop", "step"]) -RANGE_PACK = "!qqq" -RANGE_SIZE = struct.calcsize(RANGE_PACK) - -# SEQUENCE -SEQUENCE = namedtuple("SEQUENCE", ["num_elements"]) -SEQUENCE_PACK = "!Q" -SEQUENCE_SIZE = struct.calcsize(SEQUENCE_PACK) - -# MAP_ITEM -MAP_ITEM = namedtuple("MAP_ITEM", ["key_size", "type", "size"]) -MAP_ITEM_PACK = "!H1cH" -MAP_ITEM_SIZE = struct.calcsize(MAP_ITEM_PACK) diff --git a/qiskit_ibm_runtime/qpy/interface.py b/qiskit_ibm_runtime/qpy/interface.py deleted file mode 100644 index 904692999f..0000000000 --- a/qiskit_ibm_runtime/qpy/interface.py +++ /dev/null @@ -1,280 +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. - -"""User interface of qpy serializer.""" - -from json import JSONEncoder, JSONDecoder -from typing import Union, List, BinaryIO, Type, Optional -from collections.abc import Iterable -import struct -import warnings -import re - -from qiskit.circuit import QuantumCircuit -from qiskit.pulse import ScheduleBlock -from qiskit.exceptions import QiskitError -from qiskit.version import __version__ -from qiskit.utils.deprecation import deprecate_arg - -from . import formats, common, binary_io, type_keys -from .exceptions import QpyError - - -# pylint: disable=invalid-name -QPY_SUPPORTED_TYPES = Union[QuantumCircuit, ScheduleBlock] - - -# This version pattern is taken from the pypa packaging project: -# https://github.com/pypa/packaging/blob/21.3/packaging/version.py#L223-L254 -# which is dual licensed Apache 2.0 and BSD see the source for the original -# authors and other details -VERSION_PATTERN = ( - "^" - + r""" - v? - (?: - (?:(?P[0-9]+)!)? # epoch - (?P[0-9]+(?:\.[0-9]+)*) # release segment - (?P
                                          # pre-release
-            [-_\.]?
-            (?P(a|b|c|rc|alpha|beta|pre|preview))
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-        (?P                                         # post release
-            (?:-(?P[0-9]+))
-            |
-            (?:
-                [-_\.]?
-                (?Ppost|rev|r)
-                [-_\.]?
-                (?P[0-9]+)?
-            )
-        )?
-        (?P                                          # dev release
-            [-_\.]?
-            (?Pdev)
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-    )
-    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
-"""
-    + "$"
-)
-VERSION_PATTERN_REGEX = re.compile(VERSION_PATTERN, re.VERBOSE | re.IGNORECASE)
-
-
-@deprecate_arg("circuits", new_alias="programs", since="0.21.0")
-def dump(  # type: ignore[no-untyped-def]
-    programs: Union[List[QPY_SUPPORTED_TYPES], QPY_SUPPORTED_TYPES],
-    file_obj: BinaryIO,
-    metadata_serializer: Optional[Type[JSONEncoder]] = None,
-):
-    """Write QPY binary data to a file
-
-    This function is used to save a circuit to a file for later use or transfer
-    between machines. The QPY format is backwards compatible and can be
-    loaded with future versions of Qiskit.
-
-    For example:
-
-    .. code-block:: python
-
-        from qiskit.circuit import QuantumCircuit
-        from qiskit import qpy
-
-        qc = QuantumCircuit(2, name='Bell', metadata={'test': True})
-        qc.h(0)
-        qc.cx(0, 1)
-        qc.measure_all()
-
-    from this you can write the qpy data to a file:
-
-    .. code-block:: python
-
-        with open('bell.qpy', 'wb') as fd:
-            qpy.dump(qc, fd)
-
-    or a gzip compressed file:
-
-    .. code-block:: python
-
-        import gzip
-
-        with gzip.open('bell.qpy.gz', 'wb') as fd:
-            qpy.dump(qc, fd)
-
-    Which will save the qpy serialized circuit to the provided file.
-
-    Args:
-        programs: QPY supported object(s) to store in the specified file like object.
-            QPY supports :class:`.QuantumCircuit` and :class:`.ScheduleBlock`.
-            Different data types must be separately serialized.
-        file_obj: The file like object to write the QPY data too
-        metadata_serializer: An optional JSONEncoder class that
-            will be passed the ``.metadata`` attribute for each program in ``programs`` and will be
-            used as the ``cls`` kwarg on the `json.dump()`` call to JSON serialize that dictionary.
-
-    Raises:
-        QpyError: When multiple data format is mixed in the output.
-        TypeError: When invalid data type is input.
-    """
-    if not isinstance(programs, Iterable):
-        programs = [programs]
-
-    program_types = set()
-    for program in programs:
-        program_types.add(type(program))
-
-    if len(program_types) > 1:
-        raise QpyError(
-            "Input programs contain multiple data types. "
-            "Different data type must be serialized separately."
-        )
-    program_type = next(iter(program_types))
-
-    if issubclass(program_type, QuantumCircuit):
-        type_key = type_keys.Program.CIRCUIT
-        writer = binary_io.write_circuit
-    elif program_type is ScheduleBlock:
-        type_key = type_keys.Program.SCHEDULE_BLOCK
-        writer = binary_io.write_schedule_block
-    else:
-        raise TypeError(f"'{program_type}' is not supported data type.")
-
-    version_match = VERSION_PATTERN_REGEX.search(__version__)
-    version_parts = [int(x) for x in version_match.group("release").split(".")]
-    header = struct.pack(
-        formats.FILE_HEADER_PACK,  # type: ignore[attr-defined]
-        b"QISKIT",
-        common.QPY_VERSION,
-        version_parts[0],
-        version_parts[1],
-        version_parts[2],
-        len(programs),  # type: ignore[arg-type]
-    )
-    file_obj.write(header)
-    common.write_type_key(file_obj, type_key)  # type: ignore[no-untyped-call]
-
-    for program in programs:
-        writer(  # type: ignore[no-untyped-call]
-            file_obj, program, metadata_serializer=metadata_serializer
-        )
-
-
-def load(  # type: ignore[no-untyped-def]
-    file_obj: BinaryIO,
-    metadata_deserializer: Optional[Type[JSONDecoder]] = None,
-) -> List[QPY_SUPPORTED_TYPES]:
-    """Load a QPY binary file
-
-    This function is used to load a serialized QPY Qiskit program file and create
-    :class:`~qiskit.circuit.QuantumCircuit` objects or
-    :class:`~qiskit.pulse.schedule.ScheduleBlock` objects from its contents.
-    For example:
-
-    .. code-block:: python
-
-        from qiskit import qpy
-
-        with open('bell.qpy', 'rb') as fd:
-            circuits = qpy.load(fd)
-
-    or with a gzip compressed file:
-
-    .. code-block:: python
-
-        import gzip
-        from qiskit import qpy
-
-        with gzip.open('bell.qpy.gz', 'rb') as fd:
-            circuits = qpy.load(fd)
-
-    which will read the contents of the qpy and return a list of
-    :class:`~qiskit.circuit.QuantumCircuit` objects or
-    :class:`~qiskit.pulse.schedule.ScheduleBlock` objects from the file.
-
-    Args:
-        file_obj: A file like object that contains the QPY binary
-            data for a circuit or pulse schedule.
-        metadata_deserializer: An optional JSONDecoder class
-            that will be used for the ``cls`` kwarg on the internal
-            ``json.load`` call used to deserialize the JSON payload used for
-            the ``.metadata`` attribute for any programs in the QPY file.
-            If this is not specified the circuit metadata will
-            be parsed as JSON with the stdlib ``json.load()`` function using
-            the default ``JSONDecoder`` class.
-
-    Returns:
-        The list of Qiskit programs contained in the QPY data.
-        A list is always returned, even if there is only 1 program in the QPY data.
-
-    Raises:
-        QiskitError: if ``file_obj`` is not a valid QPY file
-        TypeError: When invalid data type is loaded.
-    """
-    data = formats.FILE_HEADER._make(  # type: ignore[attr-defined]
-        struct.unpack(
-            formats.FILE_HEADER_PACK,  # type: ignore[attr-defined]
-            file_obj.read(formats.FILE_HEADER_SIZE),  # type: ignore[attr-defined]
-        )
-    )
-    if data.preface.decode(common.ENCODE) != "QISKIT":
-        raise QiskitError("Input file is not a valid QPY file")
-    version_match = VERSION_PATTERN_REGEX.search(__version__)
-    env_qiskit_version = [int(x) for x in version_match.group("release").split(".")]
-
-    qiskit_version = (data.major_version, data.minor_version, data.patch_version)
-    # pylint: disable=too-many-boolean-expressions
-    if (
-        env_qiskit_version[0] < qiskit_version[0]
-        or (
-            env_qiskit_version[0] == qiskit_version[0]
-            and qiskit_version[1] > env_qiskit_version[1]
-        )
-        or (
-            env_qiskit_version[0] == qiskit_version[0]
-            and qiskit_version[1] == env_qiskit_version[1]
-            and qiskit_version[2] > env_qiskit_version[2]
-        )
-    ):
-        warnings.warn(
-            "The qiskit version used to generate the provided QPY "
-            "file, %s, is newer than the current qiskit version %s. "
-            "This may result in an error if the QPY file uses "
-            "instructions not present in this current qiskit "
-            "version" % (".".join([str(x) for x in qiskit_version]), __version__)
-        )
-
-    if data.qpy_version < 5:
-        type_key = type_keys.Program.CIRCUIT
-    else:
-        type_key = common.read_type_key(file_obj)  # type: ignore[no-untyped-call]
-
-    if type_key == type_keys.Program.CIRCUIT:
-        loader = binary_io.read_circuit
-    elif type_key == type_keys.Program.SCHEDULE_BLOCK:
-        loader = binary_io.read_schedule_block
-    else:
-        raise TypeError(f"Invalid payload format data kind '{type_key}'.")
-
-    programs = []
-    for _ in range(data.num_programs):
-        programs.append(
-            loader(  # type: ignore[no-untyped-call]
-                file_obj,
-                data.qpy_version,
-                metadata_deserializer=metadata_deserializer,
-            )
-        )
-    return programs
diff --git a/qiskit_ibm_runtime/qpy/type_keys.py b/qiskit_ibm_runtime/qpy/type_keys.py
deleted file mode 100644
index ea63853a52..0000000000
--- a/qiskit_ibm_runtime/qpy/type_keys.py
+++ /dev/null
@@ -1,416 +0,0 @@
-# This code is part of Qiskit.
-#
-# (C) Copyright IBM 2022.
-#
-# 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=too-many-return-statements
-
-"""
-QPY Type keys for several namespace.
-"""
-
-from abc import abstractmethod
-from enum import Enum
-
-import numpy as np
-
-from qiskit.circuit import (
-    Gate,
-    Instruction,
-    QuantumCircuit,
-    ControlledGate,
-    CASE_DEFAULT,
-    Clbit,
-    ClassicalRegister,
-)
-from qiskit.circuit.library import PauliEvolutionGate
-from qiskit.circuit.parameter import Parameter
-from qiskit.circuit.parameterexpression import ParameterExpression
-from qiskit.circuit.parametervector import ParameterVectorElement
-from qiskit.pulse.channels import (
-    Channel,
-    DriveChannel,
-    MeasureChannel,
-    ControlChannel,
-    AcquireChannel,
-    MemorySlot,
-    RegisterSlot,
-)
-from qiskit.pulse.instructions import (
-    Acquire,
-    Play,
-    Delay,
-    SetFrequency,
-    ShiftFrequency,
-    SetPhase,
-    ShiftPhase,
-    RelativeBarrier,
-    TimeBlockade,
-    Reference,
-)
-from qiskit.pulse.library import Waveform, SymbolicPulse
-from qiskit.pulse.schedule import ScheduleBlock
-from qiskit.pulse.transforms.alignments import (
-    AlignLeft,
-    AlignRight,
-    AlignSequential,
-    AlignEquispaced,
-)
-from . import exceptions
-
-
-class TypeKeyBase(bytes, Enum):
-    """Abstract baseclass for type key Enums."""
-
-    @classmethod
-    @abstractmethod
-    def assign(cls, obj):  # type: ignore[no-untyped-def]
-        """Assign type key to given object.
-        Args:
-            obj (any): Arbitrary object to evaluate.
-        Returns:
-            TypeKey: Corresponding key object.
-        """
-        pass
-
-    @classmethod
-    @abstractmethod
-    def retrieve(cls, type_key):  # type: ignore[no-untyped-def]
-        """Get a class from given type key.
-        Args:
-            type_key (bytes): Object type key.
-        Returns:
-            any: Corresponding class.
-        """
-        pass
-
-
-class Value(TypeKeyBase):
-    """Type key enum for value object."""
-
-    INTEGER = b"i"
-    FLOAT = b"f"
-    COMPLEX = b"c"
-    NUMPY_OBJ = b"n"
-    PARAMETER = b"p"
-    PARAMETER_VECTOR = b"v"
-    PARAMETER_EXPRESSION = b"e"
-    STRING = b"s"
-    NULL = b"z"
-    CASE_DEFAULT = b"d"
-    REGISTER = b"R"
-
-    @classmethod
-    def assign(cls, obj):  # type: ignore[no-untyped-def]
-        if isinstance(obj, int):
-            return cls.INTEGER
-        if isinstance(obj, float):
-            return cls.FLOAT
-        if isinstance(obj, complex):
-            return cls.COMPLEX
-        if isinstance(obj, (np.integer, np.floating, np.complexfloating, np.ndarray)):
-            return cls.NUMPY_OBJ
-        if isinstance(obj, ParameterVectorElement):
-            return cls.PARAMETER_VECTOR
-        if isinstance(obj, Parameter):
-            return cls.PARAMETER
-        if isinstance(obj, ParameterExpression):
-            return cls.PARAMETER_EXPRESSION
-        if isinstance(obj, str):
-            return cls.STRING
-        if isinstance(obj, (Clbit, ClassicalRegister)):
-            return cls.REGISTER
-        if obj is None:
-            return cls.NULL
-        if obj is CASE_DEFAULT:
-            return cls.CASE_DEFAULT
-
-        raise exceptions.QpyError(
-            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
-        )
-
-    @classmethod
-    def retrieve(cls, type_key):  # type: ignore[no-untyped-def]
-        raise NotImplementedError
-
-
-class Container(TypeKeyBase):
-    """Typle key enum for container-like object."""
-
-    RANGE = b"r"
-    TUPLE = b"t"
-
-    @classmethod
-    def assign(cls, obj):  # type: ignore[no-untyped-def]
-        if isinstance(obj, range):
-            return cls.RANGE
-        if isinstance(obj, tuple):
-            return cls.TUPLE
-
-        raise exceptions.QpyError(
-            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
-        )
-
-    @classmethod
-    def retrieve(cls, type_key):  # type: ignore[no-untyped-def]
-        raise NotImplementedError
-
-
-class CircuitInstruction(TypeKeyBase):
-    """Type key enum for circuit instruction object."""
-
-    INSTRUCTION = b"i"
-    GATE = b"g"
-    PAULI_EVOL_GATE = b"p"
-    CONTROLLED_GATE = b"c"
-
-    @classmethod
-    def assign(cls, obj):  # type: ignore[no-untyped-def]
-        if isinstance(obj, PauliEvolutionGate):
-            return cls.PAULI_EVOL_GATE
-        if isinstance(obj, ControlledGate):
-            return cls.CONTROLLED_GATE
-        if isinstance(obj, Gate):
-            return cls.GATE
-        if isinstance(obj, Instruction):
-            return cls.INSTRUCTION
-
-        raise exceptions.QpyError(
-            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
-        )
-
-    @classmethod
-    def retrieve(cls, type_key):  # type: ignore[no-untyped-def]
-        raise NotImplementedError
-
-
-class ScheduleAlignment(TypeKeyBase):
-    """Type key enum for schedule block alignment context object."""
-
-    LEFT = b"l"
-    RIGHT = b"r"
-    SEQUENTIAL = b"s"
-    EQUISPACED = b"e"
-
-    # AlignFunc is not serializable due to the callable in context parameter
-
-    @classmethod
-    def assign(cls, obj):  # type: ignore[no-untyped-def]
-        if isinstance(obj, AlignLeft):
-            return cls.LEFT
-        if isinstance(obj, AlignRight):
-            return cls.RIGHT
-        if isinstance(obj, AlignSequential):
-            return cls.SEQUENTIAL
-        if isinstance(obj, AlignEquispaced):
-            return cls.EQUISPACED
-
-        raise exceptions.QpyError(
-            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
-        )
-
-    @classmethod
-    def retrieve(cls, type_key):  # type: ignore[no-untyped-def]
-        if type_key == cls.LEFT:
-            return AlignLeft
-        if type_key == cls.RIGHT:
-            return AlignRight
-        if type_key == cls.SEQUENTIAL:
-            return AlignSequential
-        if type_key == cls.EQUISPACED:
-            return AlignEquispaced
-
-        raise exceptions.QpyError(
-            f"A class corresponding to type key '{type_key}' is not found in {cls.__name__} namespace."
-        )
-
-
-class ScheduleInstruction(TypeKeyBase):
-    """Type key enum for schedule instruction object."""
-
-    ACQUIRE = b"a"
-    PLAY = b"p"
-    DELAY = b"d"
-    SET_FREQUENCY = b"f"
-    SHIFT_FREQUENCY = b"g"
-    SET_PHASE = b"q"
-    SHIFT_PHASE = b"r"
-    BARRIER = b"b"
-    TIME_BLOCKADE = b"t"
-    REFERENCE = b"y"
-
-    # 's' is reserved by ScheduleBlock, i.e. block can be nested as an element.
-    # Call instructon is not supported by QPY.
-    # This instruction has been excluded from ScheduleBlock instructions with
-    # qiskit-terra/#8005 and new instruction Reference will be added instead.
-    # Call is only applied to Schedule which is not supported by QPY.
-    # Also snapshot is not suppored because of its limited usecase.
-
-    @classmethod
-    def assign(cls, obj):  # type: ignore[no-untyped-def]
-        if isinstance(obj, Acquire):
-            return cls.ACQUIRE
-        if isinstance(obj, Play):
-            return cls.PLAY
-        if isinstance(obj, Delay):
-            return cls.DELAY
-        if isinstance(obj, SetFrequency):
-            return cls.SET_FREQUENCY
-        if isinstance(obj, ShiftFrequency):
-            return cls.SHIFT_FREQUENCY
-        if isinstance(obj, SetPhase):
-            return cls.SET_PHASE
-        if isinstance(obj, ShiftPhase):
-            return cls.SHIFT_PHASE
-        if isinstance(obj, RelativeBarrier):
-            return cls.BARRIER
-        if isinstance(obj, TimeBlockade):
-            return cls.TIME_BLOCKADE
-        if isinstance(obj, Reference):
-            return cls.REFERENCE
-
-        raise exceptions.QpyError(
-            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
-        )
-
-    @classmethod
-    def retrieve(cls, type_key):  # type: ignore[no-untyped-def]
-        if type_key == cls.ACQUIRE:
-            return Acquire
-        if type_key == cls.PLAY:
-            return Play
-        if type_key == cls.DELAY:
-            return Delay
-        if type_key == cls.SET_FREQUENCY:
-            return SetFrequency
-        if type_key == cls.SHIFT_FREQUENCY:
-            return ShiftFrequency
-        if type_key == cls.SET_PHASE:
-            return SetPhase
-        if type_key == cls.SHIFT_PHASE:
-            return ShiftPhase
-        if type_key == cls.BARRIER:
-            return RelativeBarrier
-        if type_key == cls.TIME_BLOCKADE:
-            return TimeBlockade
-        if type_key == cls.REFERENCE:
-            return Reference
-
-        raise exceptions.QpyError(
-            f"A class corresponding to type key '{type_key}' is not found in {cls.__name__} namespace."
-        )
-
-
-class ScheduleOperand(TypeKeyBase):
-    """Type key enum for schedule instruction operand object."""
-
-    WAVEFORM = b"w"
-    SYMBOLIC_PULSE = b"s"
-    CHANNEL = b"c"
-
-    # Discriminator and Acquire instance are not serialzied.
-    # Data format of these object is somewhat opaque and not defiend well.
-    # It's rarely used in the Qiskit experiements. Of course these can be added later.
-
-    # We need to have own string type definition for operands of schedule instruction.
-    # Note that string type is already defined in the Value namespace,
-    # but its key "s" conflicts with the SYMBOLIC_PULSE in the ScheduleOperand namespace.
-    # New in QPY version 7.
-    OPERAND_STR = b"o"
-
-    @classmethod
-    def assign(cls, obj):  # type: ignore[no-untyped-def]
-        if isinstance(obj, Waveform):
-            return cls.WAVEFORM
-        if isinstance(obj, SymbolicPulse):
-            return cls.SYMBOLIC_PULSE
-        if isinstance(obj, Channel):
-            return cls.CHANNEL
-
-        raise exceptions.QpyError(
-            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
-        )
-
-    @classmethod
-    def retrieve(cls, type_key):  # type: ignore[no-untyped-def]
-        raise NotImplementedError
-
-
-class ScheduleChannel(TypeKeyBase):
-    """Type key enum for schedule channel object."""
-
-    DRIVE = b"d"
-    CONTROL = b"c"
-    MEASURE = b"m"
-    ACQURE = b"a"
-    MEM_SLOT = b"e"
-    REG_SLOT = b"r"
-
-    # SnapShot channel is not defined because of its limited usecase.
-
-    @classmethod
-    def assign(cls, obj):  # type: ignore[no-untyped-def]
-        if isinstance(obj, DriveChannel):
-            return cls.DRIVE
-        if isinstance(obj, ControlChannel):
-            return cls.CONTROL
-        if isinstance(obj, MeasureChannel):
-            return cls.MEASURE
-        if isinstance(obj, AcquireChannel):
-            return cls.ACQURE
-        if isinstance(obj, MemorySlot):
-            return cls.MEM_SLOT
-        if isinstance(obj, RegisterSlot):
-            return cls.REG_SLOT
-
-        raise exceptions.QpyError(
-            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
-        )
-
-    @classmethod
-    def retrieve(cls, type_key):  # type: ignore[no-untyped-def]
-        if type_key == cls.DRIVE:
-            return DriveChannel
-        if type_key == cls.CONTROL:
-            return ControlChannel
-        if type_key == cls.MEASURE:
-            return MeasureChannel
-        if type_key == cls.ACQURE:
-            return AcquireChannel
-        if type_key == cls.MEM_SLOT:
-            return MemorySlot
-        if type_key == cls.REG_SLOT:
-            return RegisterSlot
-
-        raise exceptions.QpyError(
-            f"A class corresponding to type key '{type_key}' is not found in {cls.__name__} namespace."
-        )
-
-
-class Program(TypeKeyBase):
-    """Typle key enum for program that QPY supports."""
-
-    CIRCUIT = b"q"
-    SCHEDULE_BLOCK = b"s"
-
-    @classmethod
-    def assign(cls, obj):  # type: ignore[no-untyped-def]
-        if isinstance(obj, QuantumCircuit):
-            return cls.CIRCUIT
-        if isinstance(obj, ScheduleBlock):
-            return cls.SCHEDULE_BLOCK
-
-        raise exceptions.QpyError(
-            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
-        )
-
-    @classmethod
-    def retrieve(cls, type_key):  # type: ignore[no-untyped-def]
-        raise NotImplementedError
diff --git a/qiskit_ibm_runtime/utils/backend_converter.py b/qiskit_ibm_runtime/utils/backend_converter.py
index b46d48a233..35b312dc53 100644
--- a/qiskit_ibm_runtime/utils/backend_converter.py
+++ b/qiskit_ibm_runtime/utils/backend_converter.py
@@ -36,7 +36,7 @@
     PulseDefaults,
 )
 
-from ..ibm_qubit_properties import IBMQubitProperties
+from qiskit_ibm_provider.ibm_qubit_properties import IBMQubitProperties
 
 
 def convert_to_target(
diff --git a/qiskit_ibm_runtime/utils/backend_decoder.py b/qiskit_ibm_runtime/utils/backend_decoder.py
deleted file mode 100644
index 5cc38e3b5d..0000000000
--- a/qiskit_ibm_runtime/utils/backend_decoder.py
+++ /dev/null
@@ -1,171 +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.
-
-"""Utilities for working with IBM Quantum backends."""
-
-from typing import List, Dict, Union, Optional
-import logging
-import traceback
-
-import dateutil.parser
-from qiskit.providers.models import (
-    BackendProperties,
-    PulseDefaults,
-    PulseBackendConfiguration,
-    QasmBackendConfiguration,
-)
-
-from .converters import utc_to_local_all
-
-logger = logging.getLogger(__name__)
-
-
-def configuration_from_server_data(
-    raw_config: Dict,
-    instance: str = "",
-) -> Optional[Union[QasmBackendConfiguration, PulseBackendConfiguration]]:
-    """Create an IBMBackend instance from raw server data.
-
-    Args:
-        raw_config: Raw configuration.
-        instance: Service instance.
-
-    Returns:
-        Backend configuration.
-    """
-    # Make sure the raw_config is of proper type
-    if not isinstance(raw_config, dict):
-        logger.warning(  # type: ignore[unreachable]
-            "An error occurred when retrieving backend "
-            "information. Some backends might not be available."
-        )
-        return None
-    try:
-        _decode_backend_configuration(raw_config)
-        try:
-            return PulseBackendConfiguration.from_dict(raw_config)
-        except (KeyError, TypeError):
-            return QasmBackendConfiguration.from_dict(raw_config)
-    except Exception:  # pylint: disable=broad-except
-        logger.warning(
-            'Remote backend "%s" for service instance %s could not be instantiated due to an '
-            "invalid config: %s",
-            raw_config.get("backend_name", raw_config.get("name", "unknown")),
-            repr(instance),
-            traceback.format_exc(),
-        )
-    return None
-
-
-def defaults_from_server_data(defaults: Dict) -> PulseDefaults:
-    """Decode pulse defaults data.
-
-    Args:
-        defaults: Raw pulse defaults data.
-
-    Returns:
-        A ``PulseDefaults`` instance.
-    """
-    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)
-
-    return PulseDefaults.from_dict(defaults)
-
-
-def properties_from_server_data(properties: Dict) -> BackendProperties:
-    """Decode backend properties.
-
-    Args:
-        properties: Raw properties data.
-
-    Returns:
-        A ``BackendProperties`` instance.
-    """
-    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"])
-
-    properties = utc_to_local_all(properties)
-    return BackendProperties.from_dict(properties)
-
-
-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/hgp.py b/qiskit_ibm_runtime/utils/hgp.py
deleted file mode 100644
index 46d11928e4..0000000000
--- a/qiskit_ibm_runtime/utils/hgp.py
+++ /dev/null
@@ -1,43 +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.
-
-"""Hub/group/project utility functions."""
-
-from typing import Tuple
-from ..exceptions import IBMInputValueError
-
-
-def from_instance_format(instance: str) -> Tuple[str, str, str]:
-    """Convert the input instance to [hub, group, project].
-
-    Args:
-        instance: Service instance in hub/group/project format.
-
-    Returns:
-        Hub, group, and project.
-
-    Raises:
-        IBMInputValueError: If input is not in the correct format.
-    """
-    try:
-        hub, group, project = instance.split("/")
-        return hub, group, project
-    except (ValueError, AttributeError):
-        raise IBMInputValueError(
-            f"Input instance value {instance} is not in the"
-            f"correct hub/group/project format."
-        )
-
-
-def to_instance_format(hub: str, group: str, project: str) -> str:
-    """Convert input to hub/group/project format."""
-    return f"{hub}/{group}/{project}"
diff --git a/qiskit_ibm_runtime/utils/json.py b/qiskit_ibm_runtime/utils/json.py
index c9262c1b4e..7f900352e1 100644
--- a/qiskit_ibm_runtime/utils/json.py
+++ b/qiskit_ibm_runtime/utils/json.py
@@ -56,7 +56,7 @@
 from qiskit.result import Result
 from qiskit.version import __version__ as _terra_version_string
 
-from ..qpy import (
+from qiskit_ibm_provider.qpy import (
     _write_parameter,
     _write_parameter_expression,
     _read_parameter_expression,
@@ -66,7 +66,6 @@
     load,
 )
 
-
 _TERRA_VERSION = tuple(
     int(x)
     for x in re.match(r"\d+\.\d+\.\d", _terra_version_string).group(0).split(".")[:3]
diff --git a/requirements.txt b/requirements.txt
index 4df08837ba..350aa469f3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,3 +7,4 @@ python-dateutil>=2.8.0
 websocket-client>=1.5.1
 typing-extensions>=4.0.0
 ibm-platform-services>=0.22.6
+qiskit-ibm-provider>=0.5.3
diff --git a/setup.py b/setup.py
index ddc268905c..b3e692cd44 100644
--- a/setup.py
+++ b/setup.py
@@ -27,6 +27,7 @@
     "python-dateutil>=2.8.0",
     "websocket-client>=1.5.1",
     "ibm-platform-services>=0.22.6",
+    "qiskit-ibm-provider>=0.5.3",
 ]
 
 # Handle version.
diff --git a/test/integration/test_proxies.py b/test/integration/test_proxies.py
index ad9eff0f74..cd81c5a6bf 100644
--- a/test/integration/test_proxies.py
+++ b/test/integration/test_proxies.py
@@ -17,12 +17,13 @@
 
 from requests.exceptions import ProxyError
 
+from qiskit_ibm_provider.proxies import ProxyConfiguration
 from qiskit_ibm_runtime import QiskitRuntimeService
 from qiskit_ibm_runtime.api.client_parameters import ClientParameters
 from qiskit_ibm_runtime.api.clients import AuthClient, VersionClient
 from qiskit_ibm_runtime.api.clients.runtime import RuntimeClient
 from qiskit_ibm_runtime.api.exceptions import RequestsApiError
-from qiskit_ibm_runtime.proxies import ProxyConfiguration
+
 from ..ibm_test_case import IBMTestCase
 from ..decorators import IntegrationTestDependencies, integration_test_setup
 
diff --git a/test/unit/mock/fake_runtime_client.py b/test/unit/mock/fake_runtime_client.py
index ec372c5dd9..09bcf40b2d 100644
--- a/test/unit/mock/fake_runtime_client.py
+++ b/test/unit/mock/fake_runtime_client.py
@@ -20,9 +20,9 @@
 from concurrent.futures import ThreadPoolExecutor
 from typing import Optional, Dict, Any, List
 
+from qiskit_ibm_provider.utils.hgp import from_instance_format
 from qiskit_ibm_runtime.api.exceptions import RequestsApiError
 from qiskit_ibm_runtime.utils import RuntimeEncoder
-from qiskit_ibm_runtime.utils.hgp import from_instance_format
 
 from .fake_api_backend import FakeApiBackend, FakeApiBackendSpecs
 
diff --git a/test/unit/mock/proxy_server.py b/test/unit/mock/proxy_server.py
index a50b8141b5..16f95c680a 100644
--- a/test/unit/mock/proxy_server.py
+++ b/test/unit/mock/proxy_server.py
@@ -15,7 +15,7 @@
 import subprocess
 from contextlib import contextmanager
 
-from qiskit_ibm_runtime.proxies import ProxyConfiguration
+from qiskit_ibm_provider.proxies import ProxyConfiguration
 
 
 class MockProxyServer:
diff --git a/test/unit/test_account.py b/test/unit/test_account.py
index eb2c5071dc..a2567a9e7f 100644
--- a/test/unit/test_account.py
+++ b/test/unit/test_account.py
@@ -19,6 +19,7 @@
 from typing import Any
 from unittest import skipIf
 
+from qiskit_ibm_provider.proxies import ProxyConfiguration
 from qiskit_ibm_runtime.accounts import (
     AccountManager,
     Account,
@@ -33,7 +34,6 @@
     _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM,
     _DEFAULT_ACCOUNT_NAME_IBM_CLOUD,
 )
-from qiskit_ibm_runtime.proxies import ProxyConfiguration
 from .mock.fake_runtime_service import FakeRuntimeService
 from ..ibm_test_case import IBMTestCase
 from ..account import (
diff --git a/test/unit/test_client_parameters.py b/test/unit/test_client_parameters.py
index cb522a1428..5cf5d2b596 100644
--- a/test/unit/test_client_parameters.py
+++ b/test/unit/test_client_parameters.py
@@ -16,7 +16,7 @@
 
 from requests_ntlm import HttpNtlmAuth
 
-from qiskit_ibm_runtime.proxies import ProxyConfiguration
+from qiskit_ibm_provider.proxies import ProxyConfiguration
 from qiskit_ibm_runtime.api.client_parameters import ClientParameters
 from qiskit_ibm_runtime.api.auth import CloudAuth, QuantumAuth
 
diff --git a/test/unit/test_job_retrieval.py b/test/unit/test_job_retrieval.py
index b1829a58f7..aa2ab38608 100644
--- a/test/unit/test_job_retrieval.py
+++ b/test/unit/test_job_retrieval.py
@@ -13,7 +13,6 @@
 """Tests for runtime job retrieval."""
 
 from datetime import datetime, timedelta, timezone
-from qiskit_ibm_runtime.exceptions import IBMInputValueError
 from .mock.fake_runtime_service import FakeRuntimeService
 from ..ibm_test_case import IBMTestCase
 from ..decorators import run_quantum_and_cloud_fake
@@ -282,7 +281,7 @@ def test_jobs_sort_by_date(self):
     def test_jobs_bad_instance(self):
         """Test retrieving jobs with bad instance values."""
         service = self._ibm_quantum_service
-        with self.assertRaises(IBMInputValueError):
+        with self.assertRaises(Exception):
             _ = service.jobs(instance="foo")
 
     def test_different_hgps(self):
diff --git a/test/unit/test_jobs.py b/test/unit/test_jobs.py
index 2e695d286f..c6317969b6 100644
--- a/test/unit/test_jobs.py
+++ b/test/unit/test_jobs.py
@@ -137,7 +137,7 @@ def test_run_program_by_phantom_hgp(self):
     def test_run_program_by_bad_hgp(self):
         """Test running a program with a bad hgp."""
         service = FakeRuntimeService(channel="ibm_quantum", token="my_token")
-        with self.assertRaises(IBMInputValueError):
+        with self.assertRaises(Exception):
             _ = run_program(service=service, instance="foo")
 
     @run_quantum_and_cloud_fake