Skip to content

Commit

Permalink
Add default provider options (#74)
Browse files Browse the repository at this point in the history
* Specifically pass the hub, group and project to IBMQ.get_provider

* Update documentation with provider options

* Update docs with passing a provider explicitly

* Add custom provider and default provider unit tests

* Linting

* Unit test for custom provider options

* Changing to use plugin specific device creation, adding needed mocking of active_account

* Whitespaces

* Update README.rst

Co-Authored-By: Nathan Killoran <[email protected]>

* Update README.rst

Co-Authored-By: Nathan Killoran <[email protected]>

* Update README.rst

Co-Authored-By: Nathan Killoran <[email protected]>

* Update tests/test_ibmq.py

Co-Authored-By: Nathan Killoran <[email protected]>

Co-authored-by: Nathan Killoran <[email protected]>
  • Loading branch information
antalszava and co9olguy authored Mar 15, 2020
1 parent 7a03a41 commit 2b94058
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 2 deletions.
23 changes: 23 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,29 @@ Note that, by default, the ``qiskit.ibmq`` device uses the simulator backend
dev.capabilities()['backend']
When getting a ``qiskit.ibmq`` device a Qiskit provider is used to connect to the IBM Q systems.

Custom providers can be passed as arguments when a ``qiskit.ibmq`` device is created:

.. code-block:: python
from qiskit import IBMQ
provider = IBMQ.enable_account('XYZ')
import pennylane as qml
dev = qml.device('qiskit.ibmq', wires=2, backend='ibmq_qasm_simulator', provider=provider)
If no provider is passed explicitly, then the official provider is used, with options of ``hub='ibm-q'``, ``group='open'`` and ``project='main'``.

Custom provider options can be passed as keyword arguments when creating a device:

.. code-block:: python
import pennylane as qml
dev = qml.device('qiskit.ibmq', wires=2, backend='ibmq_qasm_simulator', ibmqx_token='XXX', hub='MYHUB', group='MYGROUP', project='MYPROJECT')
More details on Qiskit providers can be found at the `IBMQ provider documentation <https://qiskit.org/documentation/apidoc/ibmq-provider.html>`_.

.. gettingstarted-end-inclusion-marker-do-not-remove
Please refer to the `plugin documentation <https://pennylane-qiskit.readthedocs.io/>`_ as
Expand Down
8 changes: 6 additions & 2 deletions pennylane_qiskit/ibmq.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
~~~~~~~~~~~~
"""
import os
import warnings

from qiskit import IBMQ
from qiskit.providers.ibmq.exceptions import IBMQAccountError
Expand Down Expand Up @@ -75,6 +74,11 @@ def __init__(self, wires, provider=None, backend="ibmq_qasm_simulator", shots=10
token = os.getenv("IBMQX_TOKEN") or kwargs.get("ibmqx_token", None)
url = os.getenv("IBMQX_URL") or kwargs.get("ibmqx_url", None)

# Specify a single hub, group and project
hub = kwargs.get("hub", 'ibm-q')
group = kwargs.get("group", 'open')
project = kwargs.get("project", 'main')

if token is not None:
# token was provided by the user, so attempt to enable an
# IBM Q account manually
Expand All @@ -101,6 +105,6 @@ def __init__(self, wires, provider=None, backend="ibmq_qasm_simulator", shots=10
# IBM Q account is now enabled

# get a provider
p = provider or IBMQ.get_provider()
p = provider or IBMQ.get_provider(hub=hub, group=group, project=project)

super().__init__(wires=wires, provider=p, backend=backend, shots=shots, **kwargs)
70 changes: 70 additions & 0 deletions tests/test_ibmq.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from qiskit.providers.ibmq.exceptions import IBMQAccountError

from pennylane_qiskit import IBMQDevice
from pennylane_qiskit import ibmq as ibmq
from pennylane_qiskit import qiskit_device as qiskit_device


@pytest.fixture
Expand Down Expand Up @@ -36,6 +38,74 @@ def test_account_already_loaded(token):
dev = IBMQDevice(wires=1)
assert dev.provider.credentials.is_ibmq()

class MockQiskitDeviceInit:
"""A mocked version of the QiskitDevice __init__ method which
is called on by the IBMQDevice"""

def mocked_init(self, wires, provider, backend, shots, **kwargs):
"""Stores the provider which QiskitDevice.__init__ was
called with."""
self.provider = provider

def test_custom_provider(monkeypatch):
"""Tests that a custom provider can be passed when creating an IBMQ
device."""
mock_provider = "MockProvider"
mock_qiskit_device = MockQiskitDeviceInit()

with monkeypatch.context() as m:
m.setattr(ibmq.QiskitDevice, "__init__",mock_qiskit_device.mocked_init)
m.setattr(ibmq.IBMQ, "enable_account", lambda *args, **kwargs: None)

# Here mocking to a value such that it is not None
m.setattr(ibmq.IBMQ, "active_account", lambda *args, **kwargs: True)
dev = IBMQDevice(wires=2, backend='ibmq_qasm_simulator', provider=mock_provider)

assert mock_qiskit_device.provider == mock_provider

def mock_get_provider(*args, **kwargs):
"""A mock function for the get_provider Qiskit function to record the
arguments which it was called with."""
return (args, kwargs)

def test_default_provider(monkeypatch):
"""Tests that the default provider is used when no custom provider was
specified."""
mock_qiskit_device = MockQiskitDeviceInit()

with monkeypatch.context() as m:
m.setattr(ibmq.QiskitDevice, "__init__", mock_qiskit_device.mocked_init)
m.setattr(ibmq.IBMQ, "get_provider", mock_get_provider)
m.setattr(ibmq.IBMQ, "enable_account", lambda *args, **kwargs: None)

# Here mocking to a value such that it is not None
m.setattr(ibmq.IBMQ, "active_account", lambda *args, **kwargs: True)
dev = IBMQDevice(wires=2, backend='ibmq_qasm_simulator')

assert mock_qiskit_device.provider[0] == ()
assert mock_qiskit_device.provider[1] == {'hub': 'ibm-q', 'group': 'open', 'project': 'main'}

def test_custom_provider_hub_group_project(monkeypatch):
"""Tests that the custom arguments passed during device instantiation are
used when calling get_provider."""
mock_qiskit_device = MockQiskitDeviceInit()

custom_hub = "SomeHub"
custom_group = "SomeGroup"
custom_project = "SomeProject"

with monkeypatch.context() as m:
m.setattr(ibmq.QiskitDevice, "__init__", mock_qiskit_device.mocked_init)
m.setattr(ibmq.IBMQ, "get_provider", mock_get_provider)
m.setattr(ibmq.IBMQ, "enable_account", lambda *args, **kwargs: None)

# Here mocking to a value such that it is not None
m.setattr(ibmq.IBMQ, "active_account", lambda *args, **kwargs: True)
dev = IBMQDevice(wires=2, backend='ibmq_qasm_simulator', hub=custom_hub, group=custom_group, project=custom_project)

assert mock_qiskit_device.provider[0] == ()
assert mock_qiskit_device.provider[1] == {'hub': custom_hub, 'group': custom_group, 'project': custom_project}


def test_load_from_disk(token):
IBMQ.save_account(token)
Expand Down

0 comments on commit 2b94058

Please sign in to comment.