diff --git a/doc/introduction/operations.rst b/doc/introduction/operations.rst index 6faf8e7644f..8221f085021 100644 --- a/doc/introduction/operations.rst +++ b/doc/introduction/operations.rst @@ -262,7 +262,7 @@ CV Gates ~pennylane.CrossKerr ~pennylane.CubicPhase ~pennylane.Displacement - ~pennylane.Interferometer + ~pennylane.InterferometerUnitary ~pennylane.Kerr ~pennylane.QuadraticPhase ~pennylane.Rotation diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index bf68d480209..73d09b003b1 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -436,6 +436,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) +

Deprecations

* The `qml.fourier.spectrum` function has been renamed to `qml.fourier.circuit_spectrum`, @@ -490,5 +494,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. diff --git a/pennylane/circuit_drawer/representation_resolver.py b/pennylane/circuit_drawer/representation_resolver.py index 6a1a5bae2f7..d766dee1877 100644 --- a/pennylane/circuit_drawer/representation_resolver.py +++ b/pennylane/circuit_drawer/representation_resolver.py @@ -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 diff --git a/pennylane/devices/default_gaussian.py b/pennylane/devices/default_gaussian.py index ea1f4eb5e69..198e176a9ac 100644 --- a/pennylane/devices/default_gaussian.py +++ b/pennylane/devices/default_gaussian.py @@ -305,8 +305,8 @@ def controlled_phase(s): return S -def interferometer(U): - """Interferometer +def interferometer_unitary(U): + """InterferometerUnitary Args: U (array): unitary matrix @@ -668,7 +668,7 @@ class DefaultGaussian(Device): "SqueezedState": squeezed_state, "ThermalState": thermal_state, "GaussianState": gaussian_state, - "Interferometer": interferometer, + "InterferometerUnitary": interferometer_unitary, } _observable_map = { diff --git a/pennylane/ops/cv.py b/pennylane/ops/cv.py index 93f416c67ee..5e71cdc5000 100644 --- a/pennylane/ops/cv.py +++ b/pennylane/ops/cv.py @@ -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 @@ -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`. @@ -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" @@ -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 + ) # ============================================================================= @@ -1170,7 +1161,7 @@ class FockStateProjector(CVObservable): "Squeezing", "TwoModeSqueezing", "CubicPhase", - "Interferometer", + "InterferometerUnitary", "CatState", "CoherentState", "FockDensityMatrix", @@ -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) diff --git a/tests/circuit_drawer/test_representation_resolver.py b/tests/circuit_drawer/test_representation_resolver.py index e22c9d74a7a..daa60f0e7e5 100644 --- a/tests/circuit_drawer/test_representation_resolver.py +++ b/tests/circuit_drawer/test_representation_resolver.py @@ -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)"), ( @@ -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)"), ( diff --git a/tests/devices/test_default_gaussian.py b/tests/devices/test_default_gaussian.py index c3f46cf1873..36abff15552 100644 --- a/tests/devices/test_default_gaussian.py +++ b/tests/devices/test_default_gaussian.py @@ -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) @@ -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""" @@ -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] diff --git a/tests/gradients/test_parameter_shift_cv.py b/tests/gradients/test_parameter_shift_cv.py index c64cf5a6e95..528249ff66c 100644 --- a/tests/gradients/test_parameter_shift_cv.py +++ b/tests/gradients/test_parameter_shift_cv.py @@ -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, @@ -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. """ @@ -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 @@ -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} diff --git a/tests/ops/test_cv_ops.py b/tests/ops/test_cv_ops.py index 6b0f69646b2..ec4c3cdc8ab 100644 --- a/tests/ops/test_cv_ops.py +++ b/tests/ops/test_cv_ops.py @@ -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), ], @@ -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", [ @@ -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) @@ -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) @@ -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) diff --git a/tests/tape/test_cv_param_shift.py b/tests/tape/test_cv_param_shift.py index deee76094c4..8b410d40092 100644 --- a/tests/tape/test_cv_param_shift.py +++ b/tests/tape/test_cv_param_shift.py @@ -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, @@ -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. """ @@ -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)) # @@ -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() diff --git a/tests/test_operation.py b/tests/test_operation.py index 42a93e2e70d..8f70fe5e238 100644 --- a/tests/test_operation.py +++ b/tests/test_operation.py @@ -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(