Skip to content

WIP Completely remove pulse defaults #2238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions qiskit_ibm_runtime/api/clients/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,3 @@ def backend_properties(
Backend properties.
"""
pass

@abstractmethod
def backend_pulse_defaults(self, backend_name: str) -> Dict:
"""Return the pulse defaults of the backend.

Args:
backend_name: The name of the backend.

Returns:
Backend pulse defaults.
"""
pass
11 changes: 0 additions & 11 deletions qiskit_ibm_runtime/api/clients/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,17 +315,6 @@ def backend_properties(
"""
return self._api.backend(backend_name).properties(datetime=datetime)

def backend_pulse_defaults(self, backend_name: str) -> Dict:
"""Return the pulse defaults of the IBM backend.

Args:
backend_name: The name of the IBM backend.

Returns:
Backend pulse defaults.
"""
return self._api.backend(backend_name).pulse_defaults()

def update_tags(self, job_id: str, tags: list) -> Response:
"""Update the tags of the job.

Expand Down
10 changes: 0 additions & 10 deletions qiskit_ibm_runtime/api/rest/cloud_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class CloudBackend(RestAdapterBase):
URL_MAP = {
"configuration": "/configuration",
"properties": "/properties",
"pulse_defaults": "/defaults",
"status": "/status",
}

Expand Down Expand Up @@ -67,15 +66,6 @@ def properties(self, datetime: Optional[python_datetime] = None) -> Dict[str, An
response["backend_name"] = self.backend_name
return response

def pulse_defaults(self) -> Dict[str, Any]:
"""Return backend pulse defaults.

Returns:
JSON response of pulse defaults.
"""
url = self.get_url("pulse_defaults")
return self.session.get(url, headers=self._HEADER_JSON_ACCEPT).json()

def status(self) -> Dict[str, Any]:
"""Return backend status.

Expand Down
37 changes: 0 additions & 37 deletions qiskit_ibm_runtime/fake_provider/fake_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
from qiskit_ibm_runtime.utils.backend_decoder import (
decode_backend_configuration,
properties_from_server_data,
defaults_from_server_data,
)

from .. import QiskitRuntimeService
Expand All @@ -44,7 +43,6 @@
from ..models import (
BackendProperties,
BackendConfiguration,
PulseDefaults,
BackendStatus,
QasmBackendConfiguration,
)
Expand Down Expand Up @@ -140,12 +138,6 @@ def _set_props_dict_from_json(self) -> None:
properties_from_server_data(props_dict)
self._props_dict = props_dict

def _set_defs_dict_from_json(self) -> None:
if self.defs_filename:
defs_dict = self._load_json(self.defs_filename) # type: ignore
defaults_from_server_data(defs_dict)
self._defs_dict = defs_dict

def _supports_dynamic_circuits(self) -> bool:
supported_features = self._conf_dict.get("supported_features") or []
return "qasm3" in supported_features
Expand Down Expand Up @@ -188,29 +180,6 @@ def properties(self, refresh: bool = False) -> BackendProperties:
self._set_props_dict_from_json()
return BackendProperties.from_dict(self._props_dict)

def defaults(self, refresh: bool = False) -> PulseDefaults:
"""(DEPRECATED)Return the pulse defaults for the backend

Args:
refresh: If ``True``, re-retrieve the backend defaults from the local file.

Returns:
The backend pulse defaults or ``None`` if the backend does not support pulse.
"""

issue_deprecation_msg(
"The defaults method and the PulseDefaults class have been deprecated",
"0.38.0",
"IBM backends no longer support pulse gates and are no longer used to "
"construct the backend target. ",
)

if refresh or self._defs_dict is None:
self._set_defs_dict_from_json()
if self._defs_dict:
return PulseDefaults.from_dict(self._defs_dict) # type: ignore[unreachable]
return None

def configuration(self) -> QasmBackendConfiguration:
"""Return the backend configuration."""
return BackendConfiguration.from_dict(self._conf_dict)
Expand Down Expand Up @@ -478,7 +447,6 @@ def refresh(self, service: QiskitRuntimeService) -> None:
real_config = configuration_from_server_data(
raw_config=service._api_client.backend_configuration(prod_name, refresh=True)
)
real_defs = real_backend.defaults(refresh=True)

updated_config = real_config.to_dict()
updated_config["backend_name"] = self.backend_name
Expand All @@ -493,11 +461,6 @@ def refresh(self, service: QiskitRuntimeService) -> None:
with open(props_path, "w", encoding="utf-8") as fd:
fd.write(json.dumps(real_props.to_dict(), cls=BackendEncoder))

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

if self._target is not None:
self._conf_dict = self._get_conf_dict_from_json() # type: ignore[unreachable]
self._set_props_dict_from_json()
Expand Down
46 changes: 2 additions & 44 deletions qiskit_ibm_runtime/ibm_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
from .models import (
BackendStatus,
BackendProperties,
PulseDefaults,
GateConfig,
QasmBackendConfiguration,
)
Expand All @@ -42,7 +41,6 @@
from .utils.backend_converter import convert_to_target

from .utils.backend_decoder import (
defaults_from_server_data,
properties_from_server_data,
configuration_from_server_data,
)
Expand Down Expand Up @@ -180,7 +178,6 @@ def __init__(
self._api_client = api_client
self._configuration = configuration
self._properties: Any = None
self._defaults: Any = None
self._target: Any = None
self._max_circuits = configuration.max_experiments
if (
Expand All @@ -205,7 +202,7 @@ def __getattr__(self, name: str) -> Any:
does not yet exist on IBMBackend class.
"""
# Prevent recursion since these properties are accessed within __getattr__
if name in ["_properties", "_defaults", "_target", "_configuration"]:
if name in ["_properties", "_target", "_configuration"]:
raise AttributeError(
"'{}' object has no attribute '{}'".format(self.__class__.__name__, name)
)
Expand All @@ -219,7 +216,6 @@ def __getattr__(self, name: str) -> Any:
)
# Lazy load properties and pulse defaults and construct the target object.
self.properties()
self.defaults()
self._convert_to_target()
# Check if the attribute now is available on IBMBackend class due to above steps
try:
Expand All @@ -236,7 +232,7 @@ def __getattr__(self, name: str) -> Any:
)

def _convert_to_target(self, refresh: bool = False) -> None:
"""Converts backend configuration, properties and defaults to Target object"""
"""Converts backend configuration and properties to Target object"""
if refresh or not self._target:
self._target = convert_to_target(
configuration=self._configuration, # type: ignore[arg-type]
Expand Down Expand Up @@ -317,7 +313,6 @@ def target(self) -> Target:
Target
"""
self.properties()
self.defaults()
self._convert_to_target()
return self._target

Expand All @@ -342,7 +337,6 @@ def refresh(self) -> None:
):
self._configuration = config
self.properties(refresh=True) # pylint: disable=unexpected-keyword-arg
self.defaults(refresh=True)
self._convert_to_target(refresh=True)

def properties(
Expand Down Expand Up @@ -424,37 +418,6 @@ def status(self) -> BackendStatus:
"getting backend status: {}".format(str(ex))
) from ex

def defaults(self, refresh: bool = False) -> Optional[PulseDefaults]:
"""(DEPRECATED) Return the pulse defaults for the backend.

The schema for default pulse configuration can be found in
`Qiskit/ibm-quantum-schemas/default_pulse_configuration
<https://github.com/Qiskit/ibm-quantum-schemas/blob/main/schemas/default_pulse_configuration_schema.json>`_.

Args:
refresh: If ``True``, re-query the server for the backend pulse defaults.
Otherwise, return a cached version.

Returns:
The backend pulse defaults or ``None`` if the backend does not support pulse.
"""

issue_deprecation_msg(
"The defaults method and the PulseDefaults class have been deprecated",
"0.38.0",
"IBM backends no longer support pulse gates and are no longer used to "
"construct the backend target. ",
)

if refresh or self._defaults is None:
api_defaults = self._api_client.backend_pulse_defaults(self.name)
if api_defaults:
self._defaults = defaults_from_server_data(api_defaults)
else:
self._defaults = None

return self._defaults

def configuration(
self,
) -> QasmBackendConfiguration:
Expand Down Expand Up @@ -554,7 +517,6 @@ def __deepcopy__(self, _memo: dict = None) -> "IBMBackend":
cpy.online_date = self.online_date
cpy.backend_version = self.backend_version
cpy._coupling_map = self._coupling_map
cpy._defaults = deepcopy(self._defaults, _memo)
cpy._target = deepcopy(self._target, _memo)
cpy._max_circuits = self._max_circuits
cpy._options = deepcopy(self._options, _memo)
Expand Down Expand Up @@ -613,10 +575,6 @@ def properties(self, refresh: bool = False, datetime: Optional[python_datetime]
"""Return the backend properties."""
return None

def defaults(self, refresh: bool = False) -> None:
"""Return the pulse defaults for the backend."""
return None

def status(self) -> BackendStatus:
"""Return the backend status."""
return self._status
Expand Down
1 change: 0 additions & 1 deletion qiskit_ibm_runtime/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@
)
from .backend_properties import BackendProperties, GateProperties, Nduv
from .backend_status import BackendStatus
from .pulse_defaults import PulseDefaults
113 changes: 1 addition & 112 deletions qiskit_ibm_runtime/models/pulse_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@
# that they have been altered from the originals.

"""Model and schema for pulse defaults."""
from typing import Any, Dict, List, TypeVar, Type
from typing import Any, Dict, TypeVar, Type

MeasurementKernelT = TypeVar("MeasurementKernelT", bound="MeasurementKernel")
DiscriminatorT = TypeVar("DiscriminatorT", bound="Discriminator")
CommandT = TypeVar("CommandT", bound="Command")
PulseDefaultsT = TypeVar("PulseDefaultsT", bound="PulseDefaults")


class MeasurementKernel:
Expand Down Expand Up @@ -155,113 +154,3 @@ def from_dict(cls: Type[CommandT], data: Dict[str, Any]) -> CommandT:
for key, value in data.items():
in_data[key] = value
return cls(**in_data)


class PulseDefaults:
"""(DEPRECATED) Description of default settings for Pulse systems.
These are instructions or settings that may be good starting points for the Pulse user.
The user may modify these defaults for custom scheduling.
"""

_data: Dict[Any, Any] = {}

def __init__(
self,
qubit_freq_est: List[float],
meas_freq_est: List[float],
buffer: int,
cmd_def: List[Command],
meas_kernel: MeasurementKernel = None,
discriminator: Discriminator = None,
**kwargs: Dict[str, Any],
):
"""
Validate and reformat transport layer inputs to initialize.
Args:
qubit_freq_est: Estimated qubit frequencies in GHz.
meas_freq_est: Estimated measurement cavity frequencies in GHz.
buffer: Default buffer time (in units of dt) between pulses.
cmd_def: Operation name and definition in terms of Commands.
meas_kernel: The measurement kernels
discriminator: The discriminators
**kwargs: Other attributes for the super class.
"""
self._data = {}
self.buffer = buffer
self.qubit_freq_est = [freq * 1e9 for freq in qubit_freq_est]
"""Qubit frequencies in Hertz."""
self.meas_freq_est = [freq * 1e9 for freq in meas_freq_est]
"""Measurement frequencies in Hertz."""
self.cmd_def = cmd_def

if meas_kernel is not None:
self.meas_kernel = meas_kernel
if discriminator is not None:
self.discriminator = discriminator

self._data.update(kwargs)

def __getattr__(self, name: str) -> Any:
try:
return self._data[name]
except KeyError as ex:
raise AttributeError(f"Attribute {name} is not defined") from ex

def to_dict(self) -> Dict[str, Any]:
"""Return a dictionary format representation of the PulseDefaults.
Returns:
dict: The dictionary form of the PulseDefaults.
"""
out_dict = {
"qubit_freq_est": self.qubit_freq_est,
"meas_freq_est": self.qubit_freq_est,
"buffer": self.buffer,
"pulse_library": list(self.pulse_library),
"cmd_def": list(self.cmd_def),
}
if hasattr(self, "meas_kernel"):
out_dict["meas_kernel"] = self.meas_kernel
if hasattr(self, "discriminator"):
out_dict["discriminator"] = self.discriminator
for key, value in self.__dict__.items():
if key not in [
"qubit_freq_est",
"meas_freq_est",
"buffer",
"pulse_library",
"cmd_def",
"meas_kernel",
"discriminator",
"converter",
]:
out_dict[key] = value
out_dict.update(self._data)

out_dict["qubit_freq_est"] = [freq * 1e-9 for freq in self.qubit_freq_est]
out_dict["meas_freq_est"] = [freq * 1e-9 for freq in self.meas_freq_est]
return out_dict

@classmethod
def from_dict(cls: Type[PulseDefaultsT], data: Dict[str, Any]) -> PulseDefaultsT:
"""Create a new PulseDefaults object from a dictionary.

Args:
data (dict): A dictionary representing the PulseDefaults
to create. It will be in the same format as output by
:meth:`to_dict`.
Returns:
PulseDefaults: The PulseDefaults from the input dictionary.
"""

in_data: Dict[Any, Any] = {}
for key, value in data.items():
in_data[key] = value

return cls(**in_data)

def __str__(self) -> str:
qubit_freqs = [freq / 1e9 for freq in self.qubit_freq_est]
meas_freqs = [freq / 1e9 for freq in self.meas_freq_est]
qfreq = f"Qubit Frequencies [GHz]\n{qubit_freqs}"
mfreq = f"Measurement Frequencies [GHz]\n{meas_freqs} "
return f"<{self.__class__.__name__}({qfreq}\n{mfreq})>"
Loading
Loading