-
Notifications
You must be signed in to change notification settings - Fork 22
/
device.py
157 lines (119 loc) · 5.02 KB
/
device.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# Copyright (C) 2023 qBraid
#
# This file is part of the qBraid-SDK
#
# The qBraid-SDK is free software released under the GNU General Public License v3
# or later. You can redistribute and/or modify it under the terms of the GPL v3.
# See the LICENSE file in the project root or <https://www.gnu.org/licenses/gpl-3.0.html>.
#
# THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3.
# pylint:disable=invalid-name
"""
Module defining abstract DeviceLikeWrapper Class
"""
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING # pylint: disable=unused-import
from qbraid import circuit_wrapper
from .exceptions import DeviceError
from .ionq import braket_ionq_compilation
if TYPE_CHECKING:
import qbraid
class DeviceLikeWrapper(ABC):
"""Abstract interface for device-like classes."""
def __init__(self, **kwargs):
"""Create a ``DeviceLikeWrapper`` object.
Keyword Args:
qbraid_id (str): The internal device ID (see :func:`~qbraid.get_devices`)
name (str): The name of the device
provider (str): The company to which the device belongs
vendor (str): The company who's software is used to access the device
runPackage (str): The software package used to access the device
objArg (str): The vendor device id/arn to supply as arg to vendor device-like object
type (str): The type of the device, "QPU" or "Simulator"
numberQubits (int): The number of qubits in the device (if applicable)
"""
self._info = kwargs
self._qubits = self._info.get("numberQubits")
self.vendor_device_id = self._info.pop("objArg")
self.vendor_dlo = self._get_device()
def _compat_run_input(self, run_input: "qbraid.QPROGRAM") -> "qbraid.QPROGRAM":
"""Checks if ``run_input`` is compatible with device and calls transpiler if necessary.
Returns:
:data:`~qbraid.QPROGRAM`: The run_input e.g. a circuit object, possibly transpiled
Raises:
DeviceError: If devices is offline or if the number of qubits used in the circuit
exceeds the number of qubits supported by the device.
"""
if self.status.value == 1:
raise DeviceError("Device is currently offline.")
device_run_package = self.info["runPackage"]
input_run_package = run_input.__module__.split(".")[0]
qbraid_circuit = circuit_wrapper(run_input)
if self.num_qubits and qbraid_circuit.num_qubits > self.num_qubits:
raise DeviceError(
f"Number of qubits in circuit ({qbraid_circuit.num_qubits}) exceeds "
f"number of qubits in device ({self.num_qubits})."
)
if self._info["provider"] == "IonQ" and self._info["name"] == "Harmony":
if input_run_package not in ["pytket", "braket"]:
run_input = qbraid_circuit.transpile(device_run_package)
run_input = braket_ionq_compilation(run_input)
else:
if input_run_package != device_run_package:
run_input = qbraid_circuit.transpile(device_run_package)
compat_run_input = self._vendor_compat_run_input(run_input)
return compat_run_input, qbraid_circuit
@abstractmethod
def _vendor_compat_run_input(self, run_input):
"""Applies any software/device specific modifications to run input."""
@property
def info(self) -> dict:
"""Return the device info."""
return self._info
@property
def id(self) -> str:
"""Return the device ID."""
return self.info["qbraid_id"]
@property
def name(self) -> str:
"""Return the device name.
Returns:
The name of the device.
"""
return self.info["name"]
@property
def provider(self) -> str:
"""Return the device provider.
Returns:
The provider responsible for the device.
"""
return self.info["provider"]
@property
def vendor(self) -> str:
"""Return the software vendor name.
Returns:
The name of the software vendor.
"""
return self.info["vendor"]
@property
def num_qubits(self) -> int:
"""The number of qubits supported by the device.
Returns:
Number of qubits supported by QPU. If Simulator returns None.
"""
return self._qubits
@property
@abstractmethod
def status(self) -> "qbraid.devices.DeviceStatus":
"""Return device status."""
def __str__(self):
return f"{self.vendor} {self.provider} {self.name} device wrapper"
def __repr__(self):
"""String representation of a DeviceWrapper object."""
return f"<{self.__class__.__name__}({self.provider}:'{self.name}')>"
@abstractmethod
def _get_device(self):
"""Abstract init device method."""
@abstractmethod
def run(self, run_input: "qbraid.QPROGRAM", *args, **kwargs) -> "qbraid.devices.JobLikeWrapper":
"""Abstract run method."""