Skip to content
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

Update code that is pending deprecation #301

Merged
merged 11 commits into from
May 4, 2023
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
now been removed. The `upload_vqe_runner` and `delete_vqe_runner` functions have also been removed.
[(#298)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/298)

### Improvements

* Updated many small things across the plugin to match re-works and deprecations in `qiskit`. The plugin
can still be used in the same way as before. However, we suggest you authenticate with
`qiskit_ibm_provider.IBMProvider` instead of `qiskit.IBMQ` from now on, as the latter is deprecated.
[(#301)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/301)

### Contributors

This release contains contributions from (in alphabetical order):
Expand Down
5 changes: 4 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ in the source folder. Tests restricted to a specific provider can be run by exec
only be run if a ``ibmqx_token`` for the
`IBM Q experience <https://quantum-computing.ibm.com/>`_ is
configured in the `PennyLane configuration file
<https://pennylane.readthedocs.io/en/latest/introduction/configuration.html>`_.
<https://pennylane.readthedocs.io/en/latest/introduction/configuration.html>`_, if the token is
exported in your environment under the name ``IBMQX_TOKEN``, or if you have previously saved your
account credentials using the
`new IBMProvider <https://qiskit.org/ecosystem/ibm-provider/stubs/qiskit_ibm_provider.IBMProvider.html>`_

If this is the case, running ``make test`` also executes tests on the ``ibmq`` device.
By default tests on the ``ibmq`` device run with ``ibmq_qasm_simulator`` backend
Expand Down
6 changes: 3 additions & 3 deletions doc/devices/aer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ or, alternatively,

.. code-block:: python

from qiskit import Aer
from qiskit_aer import Aer
Aer.backends()

.. note::
Expand Down Expand Up @@ -84,7 +84,7 @@ The options are set via additional keyword arguments:
)

For more information on available methods and their options, please visit the `AerSimulator
documentation <https://qiskit.org/documentation/stubs/qiskit.providers.aer.AerSimulator.html>`_.
documentation <https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.AerSimulator.html>`_.

.. warning::

Expand All @@ -103,7 +103,7 @@ which you can instantiate and apply to the device as follows
import pennylane as qml

import qiskit
import qiskit.providers.aer.noise as noise
from qiskit_aer import noise

# Error probabilities
prob_1 = 0.001 # 1-qubit gate
Expand Down
15 changes: 10 additions & 5 deletions doc/devices/ibmq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ IBM Q account. If the device finds no account it will raise an error:

'No active IBM Q account, and no IBM Q token provided.

You can use the ``qiskit.IBMQ.save_account("<my_token>")`` function to permanently store an account,
and the ``qiskit.IBMQ.load_account()`` function to load the stored account in a given session.
You can use the ``qiskit_ibm_provider.IBMProvider.save_account("<my_token>")`` function to permanently
store an account, and the account will be automatically used from then onward.
Alternatively, you can specify the token with PennyLane via the
`PennyLane configuration file <https://pennylane.readthedocs.io/en/latest/introduction/configuration.html>`__ by
adding the section
Expand All @@ -34,6 +34,11 @@ You may also directly pass your IBM Q API token to the device:

dev = qml.device('qiskit.ibmq', wires=2, backend='ibmq_qasm_simulator', ibmqx_token="XXX")

You may also save your token as an environment variable by running the following in a terminal:

.. code::

export IBMQX_TOKEN=<my_token>
timmysilv marked this conversation as resolved.
Show resolved Hide resolved

.. warning:: Never publish code containing your token online.

Expand All @@ -58,8 +63,8 @@ Custom providers can be passed as arguments when a ``qiskit.ibmq`` device is cre

.. code-block:: python

from qiskit import IBMQ
provider = IBMQ.enable_account('XYZ')
from qiskit_ibm_provider import IBMProvider
provider = IBMProvider("XYZ")

import pennylane as qml
dev = qml.device('qiskit.ibmq', wires=2, backend='ibmq_qasm_simulator', provider=provider)
Expand All @@ -76,4 +81,4 @@ Custom provider options can also be passed as keyword arguments when creating a
ibmqx_token='XXX', hub='MYHUB', group='MYGROUP', project='MYPROJECT')

More details on Qiskit providers can be found
in the `IBMQ provider documentation <https://qiskit.org/documentation/apidoc/ibmq-provider.html>`_.
in the `IBMQ provider documentation <https://qiskit.org/ecosystem/ibm-provider/stubs/qiskit_ibm_provider.IBMProvider.html>`_.
3 changes: 1 addition & 2 deletions doc/devices/runtime.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,14 @@ We created a wrapper to use PennyLane objects while solving VQE problems on IBM

from pennylane_qiskit import vqe_runner

IBMQ.enable_account(token)

def vqe_circuit(params):
qml.RX(params[0], wires=0)
qml.RY(params[1], wires=0)

coeffs = [1, 1]
obs = [qml.PauliX(0), qml.PauliZ(0)]
hamiltonian = qml.Hamiltonian(coeffs, obs)
shots = 8000

job = vqe_runner(
backend="ibmq_qasm_simulator",
Expand Down
2 changes: 1 addition & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ follows:

PennyLane chooses the ``qasm_simulator`` as the default backend if no backend is specified.
For more details on the ``qasm_simulator``, including available backend options, see
`Qiskit Qasm Simulator documentation <https://qiskit.org/documentation/stubs/qiskit.providers.aer.QasmSimulator.html>`_.
`Qiskit Qasm Simulator documentation <https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.QasmSimulator.html>`_.

Tutorials
~~~~~~~~~
Expand Down
1 change: 1 addition & 0 deletions doc/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pygments==2.7.4
pygments-github-lexers==0.0.5
qiskit==0.42.1
qiskit-ibm-runtime==0.9.3
timmysilv marked this conversation as resolved.
Show resolved Hide resolved
qiskit-ibm-provider==0.5.2
sphinxcontrib-bibtex==2.5.0
sphinx-automodapi==0.14.1
pennylane-sphinx-theme
12 changes: 6 additions & 6 deletions pennylane_qiskit/aer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
evaluation and differentiation of Qiskit Aer's C++ simulator
using PennyLane.
"""
import qiskit
import qiskit_aer

from .qiskit_device import QiskitDevice

Expand All @@ -31,16 +31,16 @@ class AerDevice(QiskitDevice):
a range of transpile options can be given as kwargs.

For more information on backends, please visit the
`Aer provider documentation <https://qiskit.org/documentation/apidoc/aer_provider.html>`_.
`qiskit_aer documentation <https://qiskit.org/ecosystem/aer/index.html>`_.

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']``).
backend (str): the desired backend
method (str): The desired simulation method. A list of supported simulation
methods can be returned using ``qiskit.Aer.available_methods()``, or by referring
to the ``AerSimulator`` `documentation <https://qiskit.org/documentation/stubs/qiskit.providers.aer.AerSimulator.html>`__.
methods can be returned using ``qiskit_aer.AerSimulator().available_methods()``, or by referring
timmysilv marked this conversation as resolved.
Show resolved Hide resolved
to the ``AerSimulator`` `documentation <https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.AerSimulator.html>`__.
shots (int or None): number of circuit evaluations/random samples used
to estimate expectation values and variances of observables. For statevector backends,
setting to ``None`` results in computing statistics like expectation values and variances analytically.
Expand All @@ -49,7 +49,7 @@ class AerDevice(QiskitDevice):
name (str): The name of the circuit. Default ``'circuit'``.
compile_backend (BaseBackend): The backend used for compilation. If you wish
to simulate a device compliant circuit, you can specify a backend here.
noise_model (NoiseModel): NoiseModel Object from ``qiskit.providers.aer.noise``
noise_model (NoiseModel): NoiseModel Object from ``qiskit_aer.noise``
"""

# pylint: disable=too-many-arguments
Expand All @@ -60,4 +60,4 @@ def __init__(self, wires, shots=1024, backend="aer_simulator", method="automatic
if method != "automatic":
backend += "_" + method

super().__init__(wires, provider=qiskit.Aer, backend=backend, shots=shots, **kwargs)
super().__init__(wires, provider=qiskit_aer.Aer, backend=backend, shots=shots, **kwargs)
67 changes: 27 additions & 40 deletions pennylane_qiskit/ibmq.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
"""
import os

from qiskit import IBMQ
from qiskit.providers.ibmq.exceptions import IBMQAccountError
from qiskit_ibm_provider import IBMProvider
from qiskit_ibm_provider.exceptions import IBMAccountError
from qiskit_ibm_provider.accounts.exceptions import AccountsError

from .qiskit_device import QiskitDevice

Expand All @@ -41,7 +42,7 @@ class IBMQDevice(QiskitDevice):
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 ``IBMQ.get_provider()`` is used.
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
Expand All @@ -51,7 +52,7 @@ class IBMQDevice(QiskitDevice):
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.providers.aer.noise``.
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.
Expand All @@ -67,9 +68,10 @@ def __init__(self, wires, provider=None, backend="ibmq_qasm_simulator", shots=10
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 IBMQ.get_provider(hub=hub, group=group, project=project)
p = provider or IBMProvider(instance=instance)

super().__init__(wires=wires, provider=p, backend=backend, shots=shots, **kwargs)

Expand Down Expand Up @@ -101,41 +103,26 @@ def connect(kwargs):
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")

# TODO: remove "no cover" when #173 is resolved
if token: # pragma: no cover
# token was provided by the user, so attempt to enable an
# IBM Q account manually
def login():
ibmq_kwargs = {"url": url} if url is not None else {}
IBMQ.enable_account(token, **ibmq_kwargs)

active_account = IBMQ.active_account()
if active_account is None:
login()
else:
# There is already an active account:
# If the token is the same, do nothing.
# If the token is different, authenticate with the new account.
if active_account["token"] != token:
IBMQ.disable_account()
rmoyard marked this conversation as resolved.
Show resolved Hide resolved
login()
else:
# check if an IBM Q account is already active.
#
# * IBMQ v2 credentials stored in active_account().
# If no accounts are active, it returns None.

if IBMQ.active_account() is None:
# no active account
try:
# attempt to load a v2 account stored on disk
IBMQ.load_account()
except IBMQAccountError:
# attempt to enable an account manually using
# a provided token
raise IBMQAccountError(
"No active IBM Q account, and no IBM Q token provided."
) from None
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)
8 changes: 7 additions & 1 deletion pennylane_qiskit/qiskit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,13 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs):

self.provider = provider
self.backend_name = backend
self._capabilities["backend"] = [b.name() for b in self.provider.backends()]

def _get_backend_name(name):
return name if isinstance(name, str) else name()
rmoyard marked this conversation as resolved.
Show resolved Hide resolved

self._capabilities["backend"] = [
_get_backend_name(b.name) for b in self.provider.backends()
]
self._capabilities["returns_state"] = backend in self._state_backends

# Check that the backend exists
Expand Down
30 changes: 15 additions & 15 deletions pennylane_qiskit/runtime_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@

import numpy as np

from qiskit.providers.ibmq import RunnerResult
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime.constants import RunnerResult
from pennylane_qiskit.ibmq import IBMQDevice


Expand Down Expand Up @@ -55,6 +56,7 @@ class IBMQCircuitRunnerDevice(IBMQDevice):
def __init__(self, wires, provider=None, backend="ibmq_qasm_simulator", shots=1024, **kwargs):
self.kwargs = kwargs
super().__init__(wires=wires, provider=provider, backend=backend, shots=shots, **kwargs)
self.runtime_service = QiskitRuntimeService(channel="ibm_quantum")
rmoyard marked this conversation as resolved.
Show resolved Hide resolved
rmoyard marked this conversation as resolved.
Show resolved Hide resolved

def batch_execute(self, circuits):
compiled_circuits = self.compile_circuits(circuits)
Expand All @@ -65,10 +67,10 @@ def batch_execute(self, circuits):
program_inputs[kwarg] = self.kwargs.get(kwarg)

# Specify the backend.
options = {"backend_name": self.backend.name()}
options = {"backend": self.backend.name}

# Send circuits to the cloud for execution by the circuit-runner program.
job = self.provider.runtime.run(
job = self.runtime_service.run(
program_id="circuit-runner", options=options, inputs=program_inputs
)
self._current_job = job.result(decoder=RunnerResult)
Expand Down Expand Up @@ -140,20 +142,21 @@ class IBMQSamplerDevice(IBMQDevice):
def __init__(self, wires, provider=None, backend="ibmq_qasm_simulator", shots=1024, **kwargs):
self.kwargs = kwargs
super().__init__(wires=wires, provider=provider, backend=backend, shots=shots, **kwargs)
self.runtime_service = QiskitRuntimeService(channel="ibm_quantum")

def batch_execute(self, circuits):
compiled_circuits = self.compile_circuits(circuits)

program_inputs = {"circuits": compiled_circuits}

if "circuits_indices" not in self.kwargs:
circuit_indices = list(range(0, len(compiled_circuits)))
circuit_indices = list(range(len(compiled_circuits)))
program_inputs["circuit_indices"] = circuit_indices
else:
circuit_indices = self.kwargs.get("circuit_indices")

if "run_options" in self.kwargs:
if not "shots" in self.kwargs["run_options"]:
if "shots" not in self.kwargs["run_options"]:
self.kwargs["run_options"]["shots"] = self.shots
else:
self.kwargs["run_options"] = {"shots": self.shots}
Expand All @@ -162,11 +165,9 @@ def batch_execute(self, circuits):
program_inputs[kwarg] = self.kwargs.get(kwarg)

# Specify the backend.
options = {"backend_name": self.backend.name()}
options = {"backend": self.backend.name}
# Send circuits to the cloud for execution by the sampler program.
job = self.provider.runtime.run(
program_id="sampler", options=options, inputs=program_inputs
)
job = self.runtime_service.run(program_id="sampler", options=options, inputs=program_inputs)
rmoyard marked this conversation as resolved.
Show resolved Hide resolved
self._current_job = job.result()

results = []
Expand Down Expand Up @@ -199,14 +200,13 @@ def generate_samples(self, circuit_id=None):
Returns:
array[complex]: array of samples in the shape ``(dev.shots, dev.num_wires)``
"""
counts = self._current_job.get("quasi_dists")[circuit_id]
counts = self._current_job.quasi_dists[circuit_id]
keys = list(counts.keys())

number_of_states = 2 ** len(keys[0])

# Convert state to int
for i, elem in enumerate(keys):
keys[i] = int(elem, 2)
if isinstance(keys[0], str):
rmoyard marked this conversation as resolved.
Show resolved Hide resolved
for i, elem in enumerate(keys):
keys[i] = int(elem, 2)
number_of_states = len(keys)

values = list(counts.values())
states, probs = zip(*sorted(zip(keys, values)))
Expand Down
2 changes: 1 addition & 1 deletion pennylane_qiskit/vqe_runtime_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def vqe_runner(
project = kwargs.get("project", "main")
instance = "/".join([hub, group, project])

options = {"backend_name": backend, "instance": instance}
options = {"backend": backend, "instance": instance}

service = QiskitRuntimeService(channel="ibm_quantum", token=os.getenv("IBMQX_TOKEN"))
rt_job = RuntimeJobWrapper()
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ pycparser==2.21
python-constraint==1.4.0
python-dateutil==2.8.2
qiskit==0.42.1
qiskit-aer==0.10.1
qiskit-aer==0.12.0
qiskit-ibm-runtime==0.9.3
timmysilv marked this conversation as resolved.
Show resolved Hide resolved
qiskit-ibmq-provider==0.18.3
qiskit-ibm-provider==0.5.2
qiskit-ignis==0.7.1
qiskit-terra==0.23.3
requests==2.27.1
Expand Down
Loading