Source code for pennylane_qiskit.ibmq
# Copyright 2019 Xanadu Quantum Technologies Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module contains the :class:`~.IBMQDevice` class, a PennyLane device that allows
evaluation and differentiation of IBM Q's Quantum Processing Units (QPUs)
using PennyLane.
"""
import os
from qiskit_ibm_provider import IBMProvider
from qiskit_ibm_provider.exceptions import IBMAccountError
from qiskit_ibm_provider.accounts.exceptions import AccountsError
from qiskit_ibm_provider.job import IBMJobError
from .qiskit_device import QiskitDevice
[docs]
class IBMQDevice(QiskitDevice):
"""A PennyLane device for the IBMQ API (remote) backend.
For more details, see the `Qiskit documentation <https://qiskit.org/documentation/>`_
You need to register at `IBMQ <https://quantum-computing.ibm.com/>`_ in order to
recieve a token that is used for authentication using the API.
As of the writing of this documentation, the API is free of charge, although
there is a credit system to limit access to the quantum devices.
Args:
wires (int or Iterable[Number, str]]): Number of subsystems represented by the device,
or iterable that contains unique labels for the subsystems as numbers (i.e., ``[-1, 0, 2]``)
or strings (``['ancilla', 'q1', 'q2']``). Note that for some backends, the number
of wires has to match the number of qubits accessible.
provider (Provider): The IBM Q provider you wish to use. If not provided,
then the default provider returned by ``IBMProvider()`` is used.
backend (str): the desired provider backend
shots (int): number of circuit evaluations/random samples used
to estimate expectation values and variances of observables
timeout_secs (int): A timeout value in seconds to wait for job results from an IBMQ backend.
The default value of ``None`` means no timeout
Keyword Args:
ibmqx_token (str): The IBM Q API token. If not provided, the environment
variable ``IBMQX_TOKEN`` is used.
ibmqx_url (str): The IBM Q URL. If not provided, the environment
variable ``IBMQX_URL`` is used, followed by the default URL.
noise_model (NoiseModel): NoiseModel Object from ``qiskit_aer.noise``.
Only applicable for simulator backends.
hub (str): Name of the provider hub.
group (str): Name of the provider group.
project (str): Name of the provider project.
"""
short_name = "qiskit.ibmq"
def __init__(
self,
wires,
provider=None,
backend="ibmq_qasm_simulator",
shots=1024,
timeout_secs=None,
**kwargs,
): # pylint:disable=too-many-arguments
# Connection to IBMQ
connect(kwargs)
hub = kwargs.get("hub", "ibm-q")
group = kwargs.get("group", "open")
project = kwargs.get("project", "main")
instance = "/".join([hub, group, project])
# get a provider
p = provider or IBMProvider(instance=instance)
super().__init__(wires=wires, provider=p, backend=backend, shots=shots, **kwargs)
self.timeout_secs = timeout_secs
[docs]
def batch_execute(self, circuits): # pragma: no cover, pylint:disable=arguments-differ
res = super().batch_execute(circuits, timeout=self.timeout_secs)
if self.tracker.active:
self._track_run()
return res
def _track_run(self): # pragma: no cover
"""Provide runtime information."""
expected_keys = {"created", "running", "finished"}
time_per_step = self._current_job.time_per_step()
if not set(time_per_step).issuperset(expected_keys):
# self._current_job.result() should have already run by now
# tests see a race condition, so this is ample time for that case
timeout_secs = self.timeout_secs or 60
self._current_job.wait_for_final_state(timeout=timeout_secs)
self._current_job.refresh()
time_per_step = self._current_job.time_per_step()
if not set(time_per_step).issuperset(expected_keys):
raise IBMJobError(
f"time_per_step had keys {set(time_per_step)}, needs {expected_keys}. If your program takes a long time, you may want to configure the device with a higher `timeout_secs`"
)
job_time = {
"queued": (time_per_step["running"] - time_per_step["created"]).total_seconds(),
"running": (time_per_step["finished"] - time_per_step["running"]).total_seconds(),
}
self.tracker.update(job_time=job_time)
self.tracker.record()
def connect(kwargs):
"""Function that allows connection to IBMQ.
Args:
kwargs(dict): dictionary that contains the token and the url"""
hub = kwargs.get("hub", "ibm-q")
group = kwargs.get("group", "open")
project = kwargs.get("project", "main")
instance = "/".join([hub, group, project])
token = kwargs.get("ibmqx_token", None) or os.getenv("IBMQX_TOKEN")
url = kwargs.get("ibmqx_url", None) or os.getenv("IBMQX_URL")
saved_accounts = IBMProvider.saved_accounts()
if not token:
if not saved_accounts:
raise IBMAccountError("No active IBM Q account, and no IBM Q token provided.")
try:
IBMProvider(url=url, instance=instance)
except AccountsError as e:
raise AccountsError(
f"Accounts were found ({set(saved_accounts)}), but all failed to load."
) from e
return
for account in saved_accounts.values():
if account["token"] == token:
return
IBMProvider.save_account(token=token, url=url, instance=instance)
_modules/pennylane_qiskit/ibmq
Download Python script
Download Notebook
View on GitHub