Skip to content

Commit

Permalink
Merge branch 'master' into grover_matrix
Browse files Browse the repository at this point in the history
  • Loading branch information
antalszava committed Aug 19, 2021
2 parents 96af7dc + a0d3606 commit 2d4a608
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 17 deletions.
5 changes: 4 additions & 1 deletion .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@
and requirements-ci.txt (unpinned). This latter would be used by the CI.
[(#1535)](https://github.com/PennyLaneAI/pennylane/pull/1535)

* The `qml.ResetError` is now supported for `default.mixed` device.
[(#1541)](https://github.com/PennyLaneAI/pennylane/pull/1541)

<h3>Breaking changes</h3>

Expand All @@ -158,7 +160,8 @@ and requirements-ci.txt (unpinned). This latter would be used by the CI.

This release contains contributions from (in alphabetical order):

Thomas Bromley, Josh Izaac, Prateek Jain, Johannes Jakob Meyer, Akash Narayanan, Maria Schuld, Ingrid Strandberg.
Thomas Bromley, Josh Izaac, Prateek Jain, Johannes Jakob Meyer, Akash Narayanan, Maria Schuld,
Ingrid Strandberg, Vincent Wong.

# Release 0.17.0 (current release)

Expand Down
1 change: 1 addition & 0 deletions doc/introduction/operations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ Noisy channels
~pennylane.DepolarizingChannel
~pennylane.BitFlip
~pennylane.PhaseFlip
~pennylane.ResetError
~pennylane.QubitChannel

:html:`</div>`
Expand Down
1 change: 1 addition & 0 deletions pennylane/devices/default_mixed.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class DefaultMixed(QubitDevice):
"DepolarizingChannel",
"BitFlip",
"PhaseFlip",
"ResetError",
"QubitChannel",
"QFT",
"SingleExcitation",
Expand Down
79 changes: 63 additions & 16 deletions tests/devices/test_default_mixed.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@
import pennylane as qml
from pennylane import QubitStateVector, BasisState, DeviceError
from pennylane.devices import DefaultMixed
from pennylane.ops import PauliZ, CZ, PauliX, Hadamard, CNOT, AmplitudeDamping, DepolarizingChannel
from pennylane.ops import (
PauliZ,
CZ,
PauliX,
Hadamard,
CNOT,
AmplitudeDamping,
DepolarizingChannel,
ResetError,
)
from pennylane.wires import Wires

import numpy as np
Expand Down Expand Up @@ -99,11 +108,18 @@ def test_state_after_twoqubit(self, nr_wires, op, tol):

assert np.allclose(dev.state, current_state, atol=tol, rtol=0)

@pytest.mark.parametrize("op", [AmplitudeDamping, DepolarizingChannel])
@pytest.mark.parametrize(
"op",
[
AmplitudeDamping(0.5, wires=0),
DepolarizingChannel(0.5, wires=0),
ResetError(0.1, 0.5, wires=0),
],
)
def test_state_after_channel(self, nr_wires, op, tol):
"""Tests that state is correctly retrieved after applying a channel on the first wires"""
dev = qml.device("default.mixed", wires=nr_wires)
dev.apply([op(0.5, wires=0)])
dev.apply([op])
current_state = np.reshape(dev._state, (2 ** nr_wires, 2 ** nr_wires))

assert np.allclose(dev.state, current_state, atol=tol, rtol=0)
Expand Down Expand Up @@ -139,12 +155,19 @@ def test_reset_after_twoqubit(self, nr_wires, op, tol):

assert np.allclose(dev._state, dev._create_basis_state(0), atol=tol, rtol=0)

@pytest.mark.parametrize("op", [AmplitudeDamping, DepolarizingChannel])
@pytest.mark.parametrize(
"op",
[
AmplitudeDamping(0.5, wires=[0]),
DepolarizingChannel(0.5, wires=[0]),
ResetError(0.1, 0.5, wires=[0]),
],
)
def test_reset_after_channel(self, nr_wires, op, tol):
"""Tests that state is correctly reset after applying a channel on the first
wires"""
dev = qml.device("default.mixed", wires=nr_wires)
dev.apply([op(0.5, wires=[0])])
dev.apply([op])
dev.reset()

assert np.allclose(dev._state, dev._create_basis_state(0), atol=tol, rtol=0)
Expand Down Expand Up @@ -242,17 +265,32 @@ def test_diagonal_kraus(self, ops, tol):
assert np.allclose(dev._get_kraus(ops[0]), ops[1], atol=tol, rtol=0)

p = 0.5
K0 = np.sqrt(1 - p) * np.eye(2)
K1 = np.sqrt(p / 3) * np.array([[0, 1], [1, 0]])
K2 = np.sqrt(p / 3) * np.array([[0, -1j], [1j, 0]])
K3 = np.sqrt(p / 3) * np.array([[1, 0], [0, -1]])
p_0, p_1 = 0.1, 0.5

channel_ops = [
(
AmplitudeDamping(p, wires=0),
[np.diag([1, np.sqrt(1 - p)]), np.sqrt(p) * np.array([[0, 1], [0, 0]])],
),
(DepolarizingChannel(p, wires=0), [K0, K1, K2, K3]),
(
DepolarizingChannel(p, wires=0),
[
np.sqrt(1 - p) * np.eye(2),
np.sqrt(p / 3) * np.array([[0, 1], [1, 0]]),
np.sqrt(p / 3) * np.array([[0, -1j], [1j, 0]]),
np.sqrt(p / 3) * np.array([[1, 0], [0, -1]]),
],
),
(
ResetError(p_0, p_1, wires=0),
[
np.sqrt(1 - p_0 - p_1) * np.eye(2),
np.sqrt(p_0) * np.array([[1, 0], [0, 0]]),
np.sqrt(p_0) * np.array([[0, 1], [0, 0]]),
np.sqrt(p_1) * np.array([[0, 0], [1, 0]]),
np.sqrt(p_1) * np.array([[0, 0], [0, 1]]),
],
),
]

@pytest.mark.parametrize("ops", channel_ops)
Expand All @@ -276,6 +314,11 @@ class TestApplyChannel:
DepolarizingChannel(0.5, wires=0),
np.array([[2 / 3 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 1 / 3 + 0.0j]]),
],
[
1,
ResetError(0.1, 0.5, wires=0),
np.array([[0.5 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.5 + 0.0j]]),
],
]

@pytest.mark.parametrize("x", x_apply_channel_init)
Expand All @@ -289,7 +332,6 @@ def test_channel_init(self, x, tol):
if op == CNOT:
dev._apply_channel(kraus, wires=Wires([0, 1]))
else:
kraus = dev._get_kraus(op)
dev._apply_channel(kraus, wires=Wires(0))

assert np.allclose(dev._state, target_state, atol=tol, rtol=0)
Expand All @@ -308,6 +350,11 @@ def test_channel_init(self, x, tol):
DepolarizingChannel(0.5, wires=0),
np.array([[0.5 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.5 + 0.0j]]),
],
[
1,
ResetError(0.1, 0.5, wires=0),
np.array([[0.3 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.7 + 0.0j]]),
],
]

@pytest.mark.parametrize("x", x_apply_channel_mixed)
Expand All @@ -323,7 +370,6 @@ def test_channel_mixed(self, x, tol):
if op == CNOT:
dev._apply_channel(kraus, wires=Wires([0, 1]))
else:
kraus = dev._get_kraus(op)
dev._apply_channel(kraus, wires=Wires(0))

assert np.allclose(dev._state, target_state, atol=tol, rtol=0)
Expand Down Expand Up @@ -353,6 +399,11 @@ def test_channel_mixed(self, x, tol):
DepolarizingChannel(0.5, wires=0),
np.array([[0.5 + 0.0j, -1 / 6 + 0.0j], [-1 / 6 + 0.0j, 0.5 + 0.0j]]),
],
[
1,
ResetError(0.1, 0.5, wires=0),
np.array([[0.3 + 0.0j, -0.2 + 0.0j], [-0.2 + 0.0j, 0.7 + 0.0j]]),
],
]

@pytest.mark.parametrize("x", x_apply_channel_root)
Expand All @@ -368,7 +419,6 @@ def test_channel_root(self, x, tol):
if op == CNOT:
dev._apply_channel(kraus, wires=Wires([0, 1]))
else:
kraus = dev._get_kraus(op)
dev._apply_channel(kraus, wires=Wires(0))

assert np.allclose(dev._state, target_state, atol=tol, rtol=0)
Expand All @@ -390,7 +440,6 @@ def test_diag_init(self, x, tol):
if op == CZ:
dev._apply_channel(kraus, wires=Wires([0, 1]))
else:
kraus = dev._get_kraus(op)
dev._apply_channel(kraus, wires=Wires(0))

assert np.allclose(dev._state, target_state, atol=tol, rtol=0)
Expand All @@ -410,7 +459,6 @@ def test_diag_mixed(self, x, tol):
if op == CZ:
dev._apply_channel(kraus, wires=Wires([0, 1]))
else:
kraus = dev._get_kraus(op)
dev._apply_channel(kraus, wires=Wires(0))

assert np.allclose(dev._state, target_state, atol=tol, rtol=0)
Expand Down Expand Up @@ -444,7 +492,6 @@ def test_diag_root(self, x, tol):
if op == CZ:
dev._apply_channel(kraus, wires=Wires([0, 1]))
else:
kraus = dev._get_kraus(op)
dev._apply_channel(kraus, wires=Wires(0))

assert np.allclose(dev._state, target_state, atol=tol, rtol=0)
Expand Down
34 changes: 34 additions & 0 deletions tests/ops/test_channel_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,40 @@ def test_p0_p1_sum_not_normalized(self):
with pytest.raises(ValueError, match="must be between"):
channel.ResetError(1.0, 1.0, wires=0).kraus_matrices

@pytest.mark.parametrize("angle", np.linspace(0, 2 * np.pi, 7))
def test_grad_reset_error(self, angle, tol):
"""Test that gradient is computed correctly for different states. Channel
grad recipes are independent of channel parameter"""

dev = qml.device("default.mixed", wires=1)
p_0, p_1 = 0.0, 0.5

@qml.qnode(dev)
def circuit(p_0, p_1):
qml.RX(angle, wires=0)
qml.ResetError(p_0, p_1, wires=0)
return qml.expval(qml.PauliZ(0))

gradient = np.squeeze(qml.grad(circuit)(p_0, p_1))
assert np.allclose(
gradient,
np.array(
[
(1 / 0.1) * (circuit(0.1, p_1) - circuit(0.0, p_1)),
(1 / 0.1) * (circuit(p_0, 0.1) - circuit(p_0, 0.0)),
]
),
)
assert np.allclose(
gradient,
np.array(
[
(2 * np.sin(angle / 2) * np.sin(angle / 2)),
(-2 * np.cos(angle / 2) * np.cos(angle / 2)),
]
),
)


class TestQubitChannel:
"""Tests for the quantum channel QubitChannel"""
Expand Down

0 comments on commit 2d4a608

Please sign in to comment.