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

Rename qml.Interferometer to qml.InterferometerUnitary #1714

Merged
merged 10 commits into from
Oct 8, 2021
2 changes: 1 addition & 1 deletion doc/introduction/operations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ CV Gates
~pennylane.CrossKerr
~pennylane.CubicPhase
~pennylane.Displacement
~pennylane.Interferometer
~pennylane.InterferometerUnitary
~pennylane.Kerr
~pennylane.QuadraticPhase
~pennylane.Rotation
Expand Down
9 changes: 7 additions & 2 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@
`requires_grad=False` was explicitly set.
[(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638)

- The operation `qml.Interferometer` has been renamed `qml.InterferometerUnitary` in order to
distinguish it from the template `qml.templates.Interferometer`.
[(#1714)](https://github.com/PennyLaneAI/pennylane/pull/1714)

<h3>Deprecations</h3>

* The `qml.fourier.spectrum` function has been renamed to `qml.fourier.circuit_spectrum`,
Expand Down Expand Up @@ -479,5 +483,6 @@

This release contains contributions from (in alphabetical order):

Utkarsh Azad, Olivia Di Matteo, Andrew Gardhouse, Josh Izaac, Christina Lee, Romain Moyard,
Carrie-Anne Rubidge, Maria Schuld, Ingrid Strandberg, Antal Száva, Cody Wang, David Wierichs.
Utkarsh Azad, Akash Narayanan B, Olivia Di Matteo, Andrew Gardhouse, Josh Izaac, Christina Lee,
Romain Moyard, Carrie-Anne Rubidge, Maria Schuld, Ingrid Strandberg, Antal Száva, Cody Wang,
David Wierichs.
2 changes: 1 addition & 1 deletion pennylane/circuit_drawer/representation_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ def operator_representation(self, op, wire):
"FockDensityMatrix",
"FockStateVector",
"QubitStateVector",
"Interferometer",
"InterferometerUnitary",
}:
representation = name + RepresentationResolver._format_matrix_arguments(
op.data, "M", self.matrix_cache
Expand Down
6 changes: 3 additions & 3 deletions pennylane/devices/default_gaussian.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,8 @@ def controlled_phase(s):
return S


def interferometer(U):
"""Interferometer
def interferometer_unitary(U):
"""InterferometerUnitary

Args:
U (array): unitary matrix
Expand Down Expand Up @@ -668,7 +668,7 @@ class DefaultGaussian(Device):
"SqueezedState": squeezed_state,
"ThermalState": thermal_state,
"GaussianState": gaussian_state,
"Interferometer": interferometer,
"InterferometerUnitary": interferometer_unitary,
}

_observable_map = {
Expand Down
31 changes: 7 additions & 24 deletions pennylane/ops/cv.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
# As the qubit based ``decomposition``, ``_matrix``, ``diagonalizing_gates``
# abstract methods are not defined in the CV case, disabling the related check
# pylint: disable=abstract-method
import warnings

import math
import numpy as np
from scipy.linalg import block_diag
Expand Down Expand Up @@ -553,8 +551,8 @@ def adjoint(self, do_queue=False):
return CubicPhase(-self.parameters[0], wires=self.wires, do_queue=do_queue)


class Interferometer(CVOperation):
r"""pennylane.Interferometer(U, wires)
class InterferometerUnitary(CVOperation):
r"""pennylane.InterferometerUnitary(U, wires)
A linear interferometer transforming the bosonic operators according to
the unitary matrix :math:`U`.

Expand Down Expand Up @@ -588,15 +586,6 @@ class Interferometer(CVOperation):
wires (Sequence[int] or int): the wires the operation acts on
"""

def __init__(self, *args, **kwargs):
warnings.warn(
"'Interferometer' is deprecated and will be renamed 'InterferometerUnitary'",
UserWarning,
stacklevel=2,
)

super().__init__(*args, **kwargs)

num_params = 1
num_wires = AnyWires
par_domain = "A"
Expand All @@ -618,7 +607,9 @@ def _heisenberg_rep(p):

def adjoint(self, do_queue=False):
U = self.parameters[0]
return Interferometer(qml_math.T(qml_math.conj(U)), wires=self.wires, do_queue=do_queue)
return InterferometerUnitary(
qml_math.T(qml_math.conj(U)), wires=self.wires, do_queue=do_queue
)


# =============================================================================
Expand Down Expand Up @@ -1170,7 +1161,7 @@ class FockStateProjector(CVObservable):
"Squeezing",
"TwoModeSqueezing",
"CubicPhase",
"Interferometer",
"InterferometerUnitary",
"CatState",
"CoherentState",
"FockDensityMatrix",
Expand All @@ -1183,15 +1174,7 @@ class FockStateProjector(CVObservable):
}


obs = {
"QuadOperator",
"NumberOperator",
"TensorN",
"P",
"X",
"PolyXP",
"FockStateProjector",
}
obs = {"QuadOperator", "NumberOperator", "TensorN", "P", "X", "PolyXP", "FockStateProjector"}


__all__ = list(ops | obs)
8 changes: 4 additions & 4 deletions tests/circuit_drawer/test_representation_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ def test_single_parameter_representation(self, unicode_representation_resolver,
(qml.CrossKerr(3.14, wires=[1, 2]), 1, "CrossKerr(3.14)"),
(qml.CrossKerr(3.14, wires=[1, 2]), 2, "CrossKerr(3.14)"),
(qml.CubicPhase(3.14, wires=[1]), 1, "V(3.14)"),
(qml.Interferometer(np.eye(4), wires=[1, 3]), 1, "Interferometer(M0)"),
(qml.Interferometer(np.eye(4), wires=[1, 3]), 3, "Interferometer(M0)"),
(qml.InterferometerUnitary(np.eye(4), wires=[1, 3]), 1, "InterferometerUnitary(M0)"),
(qml.InterferometerUnitary(np.eye(4), wires=[1, 3]), 3, "InterferometerUnitary(M0)"),
(qml.CatState(3.14, 2.14, 1, wires=[1]), 1, "CatState(3.14, 2.14, 1)"),
(qml.CoherentState(3.14, 2.14, wires=[1]), 1, "CoherentState(3.14, 2.14)"),
(
Expand Down Expand Up @@ -280,8 +280,8 @@ def test_operator_representation_unicode(
(qml.CrossKerr(3.14, wires=[1, 2]), 1, "CrossKerr(3.14)"),
(qml.CrossKerr(3.14, wires=[1, 2]), 2, "CrossKerr(3.14)"),
(qml.CubicPhase(3.14, wires=[1]), 1, "V(3.14)"),
(qml.Interferometer(np.eye(4), wires=[1, 3]), 1, "Interferometer(M0)"),
(qml.Interferometer(np.eye(4), wires=[1, 3]), 3, "Interferometer(M0)"),
(qml.InterferometerUnitary(np.eye(4), wires=[1, 3]), 1, "InterferometerUnitary(M0)"),
(qml.InterferometerUnitary(np.eye(4), wires=[1, 3]), 3, "InterferometerUnitary(M0)"),
(qml.CatState(3.14, 2.14, 1, wires=[1]), 1, "CatState(3.14, 2.14, 1)"),
(qml.CoherentState(3.14, 2.14, wires=[1]), 1, "CoherentState(3.14, 2.14)"),
(
Expand Down
8 changes: 4 additions & 4 deletions tests/devices/test_default_gaussian.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ def test_apply(self, gaussian_dev, tol):
p = [cov, mu]
w = list(range(2))
expected_out = [cov, mu]
elif gate_name == "Interferometer":
elif gate_name == "InterferometerUnitary":
w = list(range(2))
p = [U]
S = fn(*p)
Expand Down Expand Up @@ -464,12 +464,12 @@ def test_apply_errors(self, gaussian_dev):

with pytest.raises(ValueError, match="Incorrect number of subsystems"):
p = U
gaussian_dev.apply("Interferometer", wires=Wires([0]), par=[p])
gaussian_dev.apply("InterferometerUnitary", wires=Wires([0]), par=[p])

with pytest.raises(qml.wires.WireError, match="Did not find some of the wires"):
p = U2
# dev = DefaultGaussian(wires=4, shots=1000, hbar=hbar)
gaussian_dev.apply("Interferometer", wires=Wires([0, 1, 2]), par=[p])
gaussian_dev.apply("InterferometerUnitary", wires=Wires([0, 1, 2]), par=[p])

def test_expectation(self, tol):
"""Test that expectation values are calculated correctly"""
Expand Down Expand Up @@ -819,7 +819,7 @@ def reference(*x):

if g == "GaussianState":
p = [np.diag([0.5234] * 4), np.array([0.432, 0.123, 0.342, 0.123])]
elif g == "Interferometer":
elif g == "InterferometerUnitary":
p = [U]
else:
p = [0.432423, -0.12312, 0.324, 0.763][: op.num_params]
Expand Down
8 changes: 4 additions & 4 deletions tests/gradients/test_parameter_shift_cv.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ def test_gradients_gaussian_circuit(self, op, obs, mocker, tol):
assert np.allclose(grad_A, grad_F, atol=tol, rtol=0)

@pytest.mark.parametrize("t", [0, 1])
def test_interferometer(self, t, tol):
def test_interferometer_unitary(self, t, tol):
"""An integration test for CV gates that support analytic differentiation
if succeeding the gate to be differentiated, but cannot be differentiated
themselves (for example, they may be Gaussian but accept no parameters,
Expand All @@ -670,7 +670,7 @@ def test_interferometer(self, t, tol):
This ensures that, assuming their _heisenberg_rep is defined, the quantum
gradient analytic method can still be used, and returns the correct result.

Currently, the only such operation is qml.Interferometer. In the future,
Currently, the only such operation is qml.InterferometerUnitary. In the future,
we may consider adding a qml.GaussianTransfom operator.
"""

Expand All @@ -690,7 +690,7 @@ def test_interferometer(self, t, tol):
# @qml.qnode(dev)
# def circuit(r, phi):
# qml.Displacement(r, phi, wires=0)
# qml.Interferometer(U, wires=[0, 1])
# qml.InterferometerUnitary(U, wires=[0, 1])
# return qml.expval(qml.X(0))
#
# r = 0.543
Expand All @@ -711,7 +711,7 @@ def test_interferometer(self, t, tol):

with qml.tape.JacobianTape() as tape:
qml.Displacement(0.543, 0, wires=0)
qml.Interferometer(U, wires=[0, 1])
qml.InterferometerUnitary(U, wires=[0, 1])
qml.expval(qml.X(0))

tape.trainable_params = {t}
Expand Down
63 changes: 12 additions & 51 deletions tests/ops/test_cv_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ def test_rotation_heisenberg(self, phi):
(cv.Displacement(2.004, 8.673, wires=0), 3), # phi > 2pi
(cv.Beamsplitter(0.456, -0.789, wires=[0, 2]), 5),
(cv.TwoModeSqueezing(2.532, 1.778, wires=[1, 2]), 5),
(cv.Interferometer(np.array([[1, 1], [1, -1]]) * -1.0j / np.sqrt(2.0), wires=1), 5),
(
cv.InterferometerUnitary(
np.array([[1, 1], [1, -1]]) * -1.0j / np.sqrt(2.0), wires=1
),
5,
),
(cv.ControlledAddition(2.551, wires=[0, 2]), 5),
(cv.ControlledPhase(2.189, wires=[3, 1]), 5),
],
Expand All @@ -70,14 +75,6 @@ def test_adjoint_cv_ops(self, op, size, tol):
np_testing.assert_allclose(res2, np.eye(size), atol=tol)
assert op.wires == op_d.wires

def test_Interferometer_deprecation_warning(self):
"""Tests whether a ``UserWarning`` is raised when ``Interferometer`` gate is used."""
with pytest.warns(
UserWarning,
match="'Interferometer' is deprecated and will be renamed 'InterferometerUnitary'",
):
cv.Interferometer(np.array([[1, 1], [1, -1]]) * -1.0j / np.sqrt(2.0), wires=1)

@pytest.mark.parametrize(
"op",
[
Expand Down Expand Up @@ -129,34 +126,10 @@ def test_beamsplitter_heisenberg(self, phi, theta):
true_matrix = np.array(
[
[1, 0, 0, 0, 0],
[
0,
np.cos(theta),
0,
-np.cos(phi) * np.sin(theta),
-np.sin(phi) * np.sin(theta),
],
[
0,
0,
np.cos(theta),
np.sin(phi) * np.sin(theta),
-np.cos(phi) * np.sin(theta),
],
[
0,
np.cos(phi) * np.sin(theta),
-np.sin(phi) * np.sin(theta),
np.cos(theta),
0,
],
[
0,
np.sin(phi) * np.sin(theta),
np.cos(phi) * np.sin(theta),
0,
np.cos(theta),
],
[0, np.cos(theta), 0, -np.cos(phi) * np.sin(theta), -np.sin(phi) * np.sin(theta)],
[0, 0, np.cos(theta), np.sin(phi) * np.sin(theta), -np.cos(phi) * np.sin(theta)],
[0, np.cos(phi) * np.sin(theta), -np.sin(phi) * np.sin(theta), np.cos(theta), 0],
[0, np.sin(phi) * np.sin(theta), np.cos(phi) * np.sin(theta), 0, np.cos(theta)],
]
)
assert np.allclose(matrix, true_matrix)
Expand Down Expand Up @@ -190,13 +163,7 @@ def test_controlled_addition_heisenberg(self, s):
"""ops: Tests the Heisenberg representation of ControlledAddition gate."""
matrix = cv.ControlledAddition._heisenberg_rep([s])
true_matrix = np.array(
[
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, -s],
[0, s, 0, 1, 0],
[0, 0, 0, 0, 1],
]
[[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, -s], [0, s, 0, 1, 0], [0, 0, 0, 0, 1]]
)
assert np.allclose(matrix, true_matrix)

Expand All @@ -205,13 +172,7 @@ def test_controlled_phase_heisenberg(self, s):
"""Tests the Heisenberg representation of the ControlledPhase gate."""
matrix = cv.ControlledPhase._heisenberg_rep([s])
true_matrix = np.array(
[
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, s, 0],
[0, 0, 0, 1, 0],
[0, s, 0, 0, 1],
]
[[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, s, 0], [0, 0, 0, 1, 0], [0, s, 0, 0, 1]]
)
assert np.allclose(matrix, true_matrix)

Expand Down
8 changes: 4 additions & 4 deletions tests/tape/test_cv_param_shift.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ def test_gradients_gaussian_circuit(self, op, obs, mocker, tol):
assert np.allclose(grad_A, grad_F, atol=tol, rtol=0)

@pytest.mark.parametrize("t", [0, 1])
def test_interferometer(self, t, tol):
def test_interferometer_unitary(self, t, tol):
"""An integration test for CV gates that support analytic differentiation
if succeeding the gate to be differentiated, but cannot be differentiated
themselves (for example, they may be Gaussian but accept no parameters,
Expand All @@ -640,7 +640,7 @@ def test_interferometer(self, t, tol):
This ensures that, assuming their _heisenberg_rep is defined, the quantum
gradient analytic method can still be used, and returns the correct result.

Currently, the only such operation is qml.Interferometer. In the future,
Currently, the only such operation is qml.InterferometerUnitary. In the future,
we may consider adding a qml.GaussianTransfom operator.
"""

Expand All @@ -660,7 +660,7 @@ def test_interferometer(self, t, tol):
# @qml.qnode(dev)
# def circuit(r, phi):
# qml.Displacement(r, phi, wires=0)
# qml.Interferometer(U, wires=[0, 1])
# qml.InterferometerUnitary(U, wires=[0, 1])
# return qml.expval(qml.X(0))

#
Expand All @@ -681,7 +681,7 @@ def test_interferometer(self, t, tol):

with CVParamShiftTape() as tape:
qml.Displacement(0.543, 0, wires=0)
qml.Interferometer(U, wires=[0, 1])
qml.InterferometerUnitary(U, wires=[0, 1])
qml.expval(qml.X(0))

tape._update_gradient_info()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def test_heisenberg(self, test_class, tol):

# fixed parameter values
if test_class.par_domain == "A":
if test_class.__name__ == "Interferometer":
if test_class.__name__ == "InterferometerUnitary":
ww = list(range(2))
par = [
np.array(
Expand Down