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

Qiskit version 0.14 #65

Merged
merged 10 commits into from
Dec 20, 2019
44 changes: 16 additions & 28 deletions pennylane_qiskit/ibmq.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,34 +81,22 @@ def __init__(self, wires, provider=None, backend="ibmq_qasm_simulator", shots=10
ibmq_kwargs = {"url": url} if url is not None else {}
IBMQ.enable_account(token, **ibmq_kwargs)
else:
# turn off deprecation warnings
# TODO: remove IBM Q v1 API calls when fully deprecated
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)

# check if an IBM Q account is already active.
#
# * IBMQ v1 credentials stored in active_accounts().
# If no accounts are active, it returns []
#
# * IBMQ v2 credentials stored in active_account().
# If no accounts are active, it returns None.

if IBMQ.active_account() is None and not IBMQ.active_accounts():
# no active account
try:
# attempt to load a v1 account stored on disk
IBMQ.load_accounts()
except IBMQAccountError:
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
# 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

# IBM Q account is now enabled

Expand Down
8 changes: 6 additions & 2 deletions pennylane_qiskit/qiskit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from qiskit.compiler import assemble, transpile
from qiskit.converters import circuit_to_dag, dag_to_circuit

from pennylane import Device
from pennylane import Device, QuantumFunctionError
from pennylane.operation import Sample

from ._version import __version__
Expand Down Expand Up @@ -205,6 +205,9 @@ def apply(self, operation, wires, par):

if operation == "QubitStateVector":

if self.backend_name == "unitary_simulator":
raise QuantumFunctionError("The QubitStateVector operation is not supported on the unitary simulator backend.")

Comment on lines +208 to +210
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lines were added as per this issue: Qiskit/qiskit-aer#497

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

if len(par[0]) != 2 ** len(wires):
raise ValueError("State vector must be of length 2**wires.")

Expand Down Expand Up @@ -315,7 +318,8 @@ def rotate_basis(self, obs, wires, par):
def pre_measure(self):
for e in self.obs_queue:
# Add unitaries if a different expectation value is given
if hasattr(e, "return_type") and e.return_type == Sample:
# Exclude unitary_simulator as it does not support memory=True
if hasattr(e, "return_type") and e.return_type == Sample and self.backend_name != 'unitary_simulator':
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Backend support for memory=True now checked when that kwarg is passed. QiskitError results if not supported." - from the release notes of version 0.14.0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔

self.memory = True # make sure to return samples

if isinstance(e.name, list):
Expand Down
77 changes: 77 additions & 0 deletions tests/test_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ class TestStateApply:
def test_qubit_state_vector(self, init_state, device, tol):
"""Test PauliX application"""
dev = device(1)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! For maintainablity, I would suggest moving this into a fixture (e.g., skip_unitary), and adding it to function arguments where it should be skipped.


state = init_state(1)

dev.apply("QubitStateVector", [0], [state])
Expand All @@ -82,6 +86,10 @@ def test_invalid_qubit_state_vector(self, device):
"""Test that an exception is raised if the state
vector is the wrong size"""
dev = device(2)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = np.array([0, 123.432])

with pytest.raises(ValueError, match=r"State vector must be of length 2\*\*wires"):
Expand All @@ -91,6 +99,10 @@ def test_invalid_qubit_state_vector(self, device):
def test_single_qubit_no_parameters(self, init_state, device, name, mat, tol):
"""Test PauliX application"""
dev = device(1)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(1)

dev.apply("QubitStateVector", [0], [state])
Expand All @@ -102,11 +114,28 @@ def test_single_qubit_no_parameters(self, init_state, device, name, mat, tol):
expected = np.abs(mat @ state) ** 2
assert np.allclose(res, expected, **tol)

@pytest.mark.parametrize("name,mat", single_qubit)
def test_qubit_state_vector_error_for_unitary_simulator(self, init_state, device, name, mat, tol):
"""Test PauliX application"""
dev = device(1)

if dev.backend_name != "unitary_simulator":
pytest.skip("Test only runs for unitary simulator backend.")

state = init_state(1)

with pytest.raises(qml.QuantumFunctionError, match="The QubitStateVector operation is not supported on the unitary simulator backend."):
dev.apply("QubitStateVector", [0], [state])

@pytest.mark.parametrize("theta", [0.5432, -0.232])
@pytest.mark.parametrize("name,func", single_qubit_param)
def test_single_qubit_parameters(self, init_state, device, name, func, theta, tol):
"""Test PauliX application"""
dev = device(1)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(1)

dev.apply("QubitStateVector", [0], [state])
Expand All @@ -122,6 +151,10 @@ def test_single_qubit_parameters(self, init_state, device, name, func, theta, to
def test_two_qubit_no_parameters(self, init_state, device, name, mat, tol):
"""Test PauliX application"""
dev = device(2)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(2)

dev.apply("QubitStateVector", [0, 1], [state])
Expand All @@ -137,6 +170,10 @@ def test_two_qubit_no_parameters(self, init_state, device, name, mat, tol):
def test_qubit_unitary(self, init_state, device, mat, tol):
N = int(np.log2(len(mat)))
dev = device(N)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(N)

dev.apply("QubitStateVector", list(range(N)), [state])
Expand All @@ -160,6 +197,10 @@ def test_invalid_qubit_state_unitary(self, device):
@pytest.mark.parametrize("name, mat", three_qubit)
def test_three_qubit_no_parameters(self, init_state, device, name, mat, tol):
dev = device(3)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(3)

dev.apply("QubitStateVector", [0, 1, 2], [state])
Expand All @@ -176,6 +217,10 @@ def test_three_qubit_no_parameters(self, init_state, device, name, mat, tol):
def test_single_qubit_parameters(self, init_state, device, name, func, theta, tol):
"""Test PauliX application"""
dev = device(2)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(2)

dev.apply("QubitStateVector", [0, 1], [state])
Expand All @@ -196,6 +241,10 @@ class TestHardwareApply:
def test_qubit_state_vector(self, init_state, device, tol):
"""Test PauliX application"""
dev = device(1)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(1)

dev.apply("QubitStateVector", [0], [state])
Expand All @@ -210,6 +259,10 @@ def test_invalid_qubit_state_vector(self, device):
"""Test that an exception is raised if the state
vector is the wrong size"""
dev = device(2)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = np.array([0, 123.432])

with pytest.raises(ValueError, match=r"State vector must be of length 2\*\*wires"):
Expand All @@ -219,6 +272,10 @@ def test_invalid_qubit_state_vector(self, device):
def test_single_qubit_no_parameters(self, init_state, device, name, mat, tol):
"""Test PauliX application"""
dev = device(1)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(1)

dev.apply("QubitStateVector", [0], [state])
Expand All @@ -235,6 +292,10 @@ def test_single_qubit_no_parameters(self, init_state, device, name, mat, tol):
def test_single_qubit_parameters(self, init_state, device, name, func, theta, tol):
"""Test PauliX application"""
dev = device(1)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(1)

dev.apply("QubitStateVector", [0], [state])
Expand All @@ -250,6 +311,10 @@ def test_single_qubit_parameters(self, init_state, device, name, func, theta, to
def test_two_qubit_no_parameters(self, init_state, device, name, mat, tol):
"""Test PauliX application"""
dev = device(2)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(2)

dev.apply("QubitStateVector", [0, 1], [state])
Expand All @@ -265,6 +330,10 @@ def test_two_qubit_no_parameters(self, init_state, device, name, mat, tol):
def test_qubit_unitary(self, init_state, device, mat, tol):
N = int(np.log2(len(mat)))
dev = device(N)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(N)

dev.apply("QubitStateVector", list(range(N)), [state])
Expand All @@ -288,6 +357,10 @@ def test_invalid_qubit_state_unitary(self, device):
@pytest.mark.parametrize("name, mat", three_qubit)
def test_three_qubit_no_parameters(self, init_state, device, name, mat, tol):
dev = device(3)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(3)

dev.apply("QubitStateVector", [0, 1, 2], [state])
Expand All @@ -304,6 +377,10 @@ def test_three_qubit_no_parameters(self, init_state, device, name, mat, tol):
def test_single_qubit_parameters(self, init_state, device, name, func, theta, tol):
"""Test PauliX application"""
dev = device(2)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(2)

dev.apply("QubitStateVector", [0, 1], [state])
Expand Down
2 changes: 1 addition & 1 deletion tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ def test_quantum_circuit_error_by_calling_wrong_parameters(self, recorder):

quantum_circuit = load(qc)

with pytest.raises(TypeError, match="can't convert expression to float"):
with pytest.raises(ValueError, match="could not convert string to float: '{}'".format(angle)):
with recorder:
quantum_circuit()

Expand Down
4 changes: 4 additions & 0 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ def test_rotation(self, init_state, state_vector_device, shots, analytic, tol):
Qiskit device with statevector backend"""

dev = state_vector_device(1)

if dev.backend_name == "unitary_simulator":
pytest.skip("Test only runs for backends that are not the unitary simulator.")

state = init_state(1)

a = 0.542
Expand Down
2 changes: 1 addition & 1 deletion tests/test_inverses.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,6 @@ def mean_photon_gaussian(phi):
qml.Rotation(phi, wires=0).inv()
return qml.expval(qml.NumberOperator(0))

with pytest.raises(qml.DeviceError, match="Gate Rotation.inv not supported on device {}"
with pytest.raises(qml.QuantumFunctionError, match="Device {} is a qubit device; CV operations are not allowed."
.format(dev.short_name)):
mean_photon_gaussian(0.015)