From bb672a3854fd9d791dfab69bd91af6341d6ce149 Mon Sep 17 00:00:00 2001 From: Pietropaolo Frisoni Date: Fri, 19 Apr 2024 09:17:43 -0400 Subject: [PATCH] Bugfix: Cannot initialize `ParticleConservingU1/2` with default `init_state` (#5535) **Context:** `qml.ParticleConservingU1` and `qml.ParticleConservingU2` cannot be initialized with their default value for the `initial_state` argument (the default value is `None`). **Description of the Change:** If the `initial_state` argument is not specified, it is set to a tuple of zeros, which seems a reasonable choice for an initial state in physics. This modification occurs only if the initial state is not specified and the information is reported in the class's docstring. **Benefits:** The error is no longer raised when the initial state is not specified, and the class works with the default argument. **Possible Drawbacks:** As mentioned above, this modification only occurs if the initial state is not specified and should not cause any issues. **Related GitHub Issues:** #5522 [sc-61431] --- doc/releases/changelog-dev.md | 3 +++ pennylane/templates/layers/particle_conserving_u1.py | 6 ++++-- pennylane/templates/layers/particle_conserving_u2.py | 6 ++++-- tests/templates/test_layers/test_particle_conserving_u1.py | 4 ++-- tests/templates/test_layers/test_particle_conserving_u2.py | 4 ++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 1f4ba35cd86..780c64a2a25 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -380,6 +380,9 @@

Bug fixes 🐛

+* `qml.ParticleConservingU1` and `qml.ParticleConservingU2` no longer raise an error when the initial state is not specified but default to the all-zeros state. + [(#5535)](https://github.com/PennyLaneAI/pennylane/pull/5535) + * `qml.counts` no longer returns negative samples when measuring 8 or more wires. [(#5544)](https://github.com/PennyLaneAI/pennylane/pull/5544) diff --git a/pennylane/templates/layers/particle_conserving_u1.py b/pennylane/templates/layers/particle_conserving_u1.py index 3b6430e3d94..51a825d3b58 100644 --- a/pennylane/templates/layers/particle_conserving_u1.py +++ b/pennylane/templates/layers/particle_conserving_u1.py @@ -183,9 +183,9 @@ class ParticleConservingU1(Operation): weights (tensor_like): Array of weights of shape ``(D, M, 2)``. ``D`` is the number of entangler block layers and :math:`M=N-1` is the number of exchange gates :math:`U_{1,\mathrm{ex}}` per layer. - wires (Iterable): wires that the template acts on + wires (Iterable): wires that the template acts on. init_state (tensor_like): iterable or shape ``(len(wires),)`` tensor representing the Hartree-Fock state - used to initialize the wires + used to initialize the wires. If ``None``, a tuple of zeros is selected as initial state. .. details:: :title: Usage Details @@ -266,6 +266,8 @@ def __init__(self, weights, wires, init_state=None, id=None): f"Weights tensor must have third dimension of length 2; got {shape[2]}" ) + init_state = tuple(0 for _ in wires) if init_state is None else init_state + self._hyperparameters = {"init_state": tuple(init_state)} super().__init__(weights, wires=wires, id=id) diff --git a/pennylane/templates/layers/particle_conserving_u2.py b/pennylane/templates/layers/particle_conserving_u2.py index 70fa3f12cda..47a5ee0ab25 100644 --- a/pennylane/templates/layers/particle_conserving_u2.py +++ b/pennylane/templates/layers/particle_conserving_u2.py @@ -93,9 +93,9 @@ class ParticleConservingU2(Operation): weights (tensor_like): Weight tensor of shape ``(D, M)`` where ``D`` is the number of layers and ``M`` = ``2N-1`` is the total number of rotation ``(N)`` and exchange ``(N-1)`` gates per layer. - wires (Iterable): wires that the template acts on + wires (Iterable): wires that the template acts on. init_state (tensor_like): iterable or shape ``(len(wires),)`` tensor representing the Hartree-Fock state - used to initialize the wires. + used to initialize the wires. If ``None``, a tuple of zeros is selected as initial state. .. details:: :title: Usage Details @@ -171,6 +171,8 @@ def __init__(self, weights, wires, init_state=None, id=None): f"Weights tensor must have a second dimension of length {2 * len(wires) - 1}; got {shape[1]}" ) + init_state = tuple(0 for _ in wires) if init_state is None else init_state + self._hyperparameters = {"init_state": tuple(init_state)} super().__init__(weights, wires=wires, id=id) diff --git a/tests/templates/test_layers/test_particle_conserving_u1.py b/tests/templates/test_layers/test_particle_conserving_u1.py index facc6c24250..443bb2e8bb5 100644 --- a/tests/templates/test_layers/test_particle_conserving_u1.py +++ b/tests/templates/test_layers/test_particle_conserving_u1.py @@ -20,11 +20,11 @@ from pennylane import numpy as pnp -def test_standard_validity(): +@pytest.mark.parametrize("init_state", [np.array([1, 1, 0]), None]) +def test_standard_validity(init_state): """Check the operation using the assert_valid function.""" weights = np.random.random(size=(1, 2, 2)) - init_state = np.array([1, 1, 0]) op = qml.ParticleConservingU1(weights, wires=range(3), init_state=init_state) qml.ops.functions.assert_valid(op) diff --git a/tests/templates/test_layers/test_particle_conserving_u2.py b/tests/templates/test_layers/test_particle_conserving_u2.py index baa40438b77..feef54b4d88 100644 --- a/tests/templates/test_layers/test_particle_conserving_u2.py +++ b/tests/templates/test_layers/test_particle_conserving_u2.py @@ -20,14 +20,14 @@ from pennylane import numpy as pnp -def test_standard_validity(): +@pytest.mark.parametrize("init_state", [np.array([1, 1, 0, 0]), None]) +def test_standard_validity(init_state): """Run standard checks with the assert_valid function.""" layers = 2 qubits = 4 weights = np.random.normal(0, 2 * np.pi, (layers, 2 * qubits - 1)) - init_state = np.array([1, 1, 0, 0]) op = qml.ParticleConservingU2(weights, wires=range(qubits), init_state=init_state) qml.ops.functions.assert_valid(op)