from qiskit_ibm_provider import IBMProvider
from qiskit_aer import AerSimulator
from typing import List
from openqaoa.backends.basedevice import DeviceBase
[docs]class DeviceQiskit(DeviceBase):
"""
Contains the required information and methods needed to access remote
qiskit QPUs.
Attributes
----------
available_qpus: `list`
When connection to a provider is established, this attribute contains a list
of backend names which can be used to access the selected backend by reinitialising
the Access Object with the name of the available backend as input to the
device_name parameter.
n_qubits: `int`
The maximum number of qubits available for the selected backend. Only
available if check_connection method is executed and a connection to the
qpu and provider is established.
"""
def __init__(
self,
device_name: str,
hub: str = None,
group: str = None,
project: str = None,
as_emulator: bool = False,
):
"""The user's IBMQ account has to be authenticated through qiskit in
order to use this backend. This can be done through `IBMQ.save_account`.
See: https://quantum-computing.ibm.com/lab/docs/iql/manage/account/ibmq
Parameters
----------
device_name: `str`
The name of the IBMQ device to be used
hub: `str`
Valid IBMQ hub name.
group: `str`
Valid IBMQ group name.
project: `str`
The name of the project for which the experimental data will be
saved in on IBMQ's end.
"""
self.device_name = device_name
self.device_location = "ibmq"
self.hub = hub
self.group = group
self.project = project
self.as_emulator = as_emulator
self.provider_connected = None
self.qpu_connected = None
[docs] def check_connection(self) -> bool:
"""
This method should allow a user to easily check if the credentials
provided to access the remote QPU is valid.
If no backend was specified in initialisation of object, just runs
a test connection without a specific backend.
If backend was specified, checks if connection to that backend
can be established.
Returns
-------
bool
True if successfully connected to IBMQ or IBMQ and the QPU backend
if it was specified. False if unable to connect to IBMQ or failure
in the attempt to connect to the specified backend.
"""
self.provider_connected = self._check_provider_connection()
if self.provider_connected == False:
return self.provider_connected
self.available_qpus = [backend.name for backend in self.provider.backends()]
if self.device_name == "":
return self.provider_connected
self.qpu_connected = self._check_backend_connection()
if self.provider_connected and self.qpu_connected:
return True
else:
return False
def _check_backend_connection(self) -> bool:
"""Private method for checking connection with backend(s)."""
if self.device_name in self.available_qpus:
self.backend_device = self.provider.get_backend(self.device_name)
self.n_qubits = self.backend_device.configuration().n_qubits
if self.as_emulator is True:
self.backend_device = AerSimulator.from_backend(self.backend_device)
return True
else:
print(f"Please choose from {self.available_qpus} for this provider")
return False
def _check_provider_connection(self) -> bool:
"""
Private method for checking connection with provider.
"""
try:
# Use default
self.provider = IBMProvider()
# Unless exact instance is specified
if all([self.hub, self.group, self.project]):
instance_name = self.hub + "/" + self.group + "/" + self.project
assert instance_name in self.provider.instances()
self.provider = IBMProvider(instance=instance_name)
elif any([self.hub, self.group, self.project]):
# if only partially specified, print warning.
raise Exception(
"You've only partially specified the instance name. Either"
"the hub, group or project is missing. hub: {}, group: {}, project: {}.\n"
"The default instance will be used instead. (This default can "
"be specified when doing `IBMProvider.save_account`)"
)
return True
except Exception as e:
print(
"An Exception has occured when trying to connect with the provider."
"Please note that you are required to set up your IBMQ account locally first."
"See: https://quantum-computing.ibm.com/lab/docs/iql/manage/account/ibmq "
"for how to save your IBMQ account locally. \n {}".format(e)
)
return False
[docs] def connectivity(self) -> List[List[int]]:
return self.backend_device.configuration().coupling_map