diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md
index a2d10f4488b..e8024f4d17a 100644
--- a/.github/CHANGELOG.md
+++ b/.github/CHANGELOG.md
@@ -2,12 +2,13 @@
New features since last release
-* A new hardware-efficient particle-conserving template has been implemented
- to perform VQE-based quantum chemistry simulations. The new template applies
- several layers of the particle-conserving entangler proposed in Fig. 2a
+* Two new hardware-efficient particle-conserving templates have been implemented
+ to perform VQE-based quantum chemistry simulations. The new templates apply
+ several layers of the particle-conserving entanglers proposed in Figs. 2a and 2b
of the article by Barkoutsos *et al*. in
`arXiv:1805.04340 `_
[(#875)](https://github.com/PennyLaneAI/pennylane/pull/875)
+ [(#876)](https://github.com/PennyLaneAI/pennylane/pull/876)
* The `Device` and `QubitDevice` classes have a new API method, `batch_execute()`.
This method accepts a *list* of tapes, and returns a list of evaluated numerical values.
diff --git a/doc/_static/templates/layers/particle_conserving_u2.png b/doc/_static/templates/layers/particle_conserving_u2.png
new file mode 100644
index 00000000000..e4556d4e3cf
Binary files /dev/null and b/doc/_static/templates/layers/particle_conserving_u2.png differ
diff --git a/doc/_static/templates/layers/u2_decomposition.png b/doc/_static/templates/layers/u2_decomposition.png
new file mode 100644
index 00000000000..65fe4b5a6c5
Binary files /dev/null and b/doc/_static/templates/layers/u2_decomposition.png differ
diff --git a/doc/introduction/templates.rst b/doc/introduction/templates.rst
index 8eaf49edd4c..000647b6c3f 100644
--- a/doc/introduction/templates.rst
+++ b/doc/introduction/templates.rst
@@ -110,6 +110,11 @@ neural network. Note arbitrary templates or operations can also be layered using
:description: BasicEntanglerLayers
:figure: ../_static/templates/layers/basic_entangler.png
+.. customgalleryitem::
+ :link: ../code/api/pennylane.templates.layers.ParticleConservingU2.html
+ :description: ParticleConservingU2
+ :figure: ../_static/templates/layers/particle_conserving_u2.png
+
.. customgalleryitem::
:link: ../code/api/pennylane.templates.layers.ParticleConservingU1.html
:description: ParticleConservingU1
diff --git a/pennylane/init.py b/pennylane/init.py
index afb2cdb7eaf..bc583b43fd8 100644
--- a/pennylane/init.py
+++ b/pennylane/init.py
@@ -20,22 +20,77 @@
from pennylane import numpy as np
+def particle_conserving_u2_uniform(n_layers, n_wires, low=0, high=2 * pi, seed=None):
+ r"""Creates a parameter array for :func:`~.ParticleConservingU2`, drawn from a uniform
+ distribution.
+ Each parameter is drawn uniformly at random from the half-open interval [``low``, ``high``).
+ The parameters define the trainable angles entering the Z rotation
+ :math:`R_\mathrm{z}(\vec{\theta})` and particle-conserving gate :math:`U_{2,\mathrm{ex}}`
+ implemented by the :func:`~.u2_ex_gate()`.
+ Args:
+ n_layers (int): number of layers
+ n_wires (int): number of qubits
+ low (float): lower endpoint of the parameter interval
+ high (float): upper endpoint of the parameter interval
+ seed (int): seed used in sampling the parameters, makes function call deterministic
+ Returns:
+ array: parameter array
+ """
+
+ if seed is not None:
+ np.random.seed(seed)
+
+ if n_wires < 2:
+ raise ValueError(
+ "The number of qubits must be greater than one; got 'n_wires' = {}".format(n_wires)
+ )
+
+ params = np.random.uniform(low=low, high=high, size=(n_layers, 2 * n_wires - 1))
+ return params
+
+
+def particle_conserving_u2_normal(n_layers, n_wires, mean=0, std=0.1, seed=None):
+ r"""Creates a parameter array for :func:`~.ParticleConservingU2`, drawn from a normal
+ distribution.
+ Each parameter is drawn from a normal distribution with ``mean`` and standard deviation ``std``.
+ The parameters define the trainable angles entering the Z rotation
+ :math:`R_\mathrm{z}(\vec{\theta})` and particle-conserving gate :math:`U_{2,\mathrm{ex}}`
+ implemented by the :func:`~.u2_ex_gate()`.
+ Args:
+ n_layers (int): number of layers
+ n_wires (int): number of qubits
+ mean (float): mean of parameters
+ std (float): standard deviation of parameters
+ seed (int): seed used in sampling the parameters, makes function call deterministic
+ Returns:
+ array: parameter array
+ """
+
+ if seed is not None:
+ np.random.seed(seed)
+
+ if n_wires < 2:
+ raise ValueError(
+ "The number of qubits must be greater than one; got 'n_wires' = {}".format(n_wires)
+ )
+
+ params = np.random.normal(loc=mean, scale=std, size=(n_layers, 2 * n_wires - 1))
+ return params
+
+
def particle_conserving_u1_uniform(n_layers, n_wires, low=0, high=2 * pi, seed=None):
r"""Creates a parameter array for :func:`~.ParticleConservingU1`, drawn from a uniform
distribution.
-
Each parameter is drawn uniformly at random from the half-open interval [``low``, ``high``).
The parameters define the trainable angles entering the particle-conserving
exchange gates :math:`U_{1,\mathrm{ex}}(\phi, \theta)` implemented by the
:func:`~.u1_ex_gate()`.
-
Args:
n_layers (int): number of layers
n_wires (int): number of qubits
low (float): lower endpoint of the parameter interval
high (float): upper endpoint of the parameter interval
seed (int): seed used in sampling the parameters, makes function call deterministic
-
Returns:
array: parameter array
"""
@@ -55,19 +110,16 @@ def particle_conserving_u1_uniform(n_layers, n_wires, low=0, high=2 * pi, seed=N
def particle_conserving_u1_normal(n_layers, n_wires, mean=0, std=0.1, seed=None):
r"""Creates a parameter array for :func:`~.ParticleConservingU1`, drawn from a normal
distribution.
-
Each parameter is drawn from a normal distribution with ``mean`` and standard deviation ``std``.
The parameters define the trainable angles entering the particle-conserving
exchange gates :math:`U_{1,\mathrm{ex}}(\phi, \theta)` implemented by the
:func:`~.u1_ex_gate()`.
-
Args:
n_layers (int): number of layers
n_wires (int): number of qubits
mean (float): mean of parameters
std (float): standard deviation of parameters
seed (int): seed used in sampling the parameters, makes function call deterministic
-
Returns:
array: parameter array
"""
diff --git a/pennylane/templates/layers/__init__.py b/pennylane/templates/layers/__init__.py
index 44ca27e9b16..8295205ff4a 100644
--- a/pennylane/templates/layers/__init__.py
+++ b/pennylane/templates/layers/__init__.py
@@ -21,4 +21,5 @@
from .cv_neural_net import CVNeuralNetLayers
from .simplified_two_design import SimplifiedTwoDesign
from .basic_entangler import BasicEntanglerLayers
+from .particle_conserving_u2 import ParticleConservingU2
from .particle_conserving_u1 import ParticleConservingU1
diff --git a/pennylane/templates/layers/particle_conserving_u2.py b/pennylane/templates/layers/particle_conserving_u2.py
new file mode 100644
index 00000000000..eb24bb182d8
--- /dev/null
+++ b/pennylane/templates/layers/particle_conserving_u2.py
@@ -0,0 +1,179 @@
+# Copyright 2018-2020 Xanadu Quantum Technologies Inc.
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+r"""
+Contains the hardware efficient ``ParticleConservingU2`` template.
+"""
+import pennylane as qml
+
+# pylint: disable-msg=too-many-branches,too-many-arguments,protected-access
+from pennylane.templates.decorator import template
+from pennylane.ops import CNOT, CRX, RZ
+from pennylane.templates.utils import (
+ check_shape,
+ get_shape,
+)
+from pennylane.wires import Wires
+
+
+def u2_ex_gate(phi, wires=None):
+ r"""Implements the two-qubit exchange gate :math:`U_{2,\mathrm{ex}}` proposed in
+ `arXiv:1805.04340 `_ to build particle-conserving VQE ansatze
+ for Quantum Chemistry simulations.
+
+ The unitary matrix :math:`U_{2, \mathrm{ex}}` acts on the Hilbert space of two qubits
+
+ .. math::
+
+ U_{2, \mathrm{ex}}(\phi) = \left(\begin{array}{cccc}
+ 1 & 0 & 0 & 0 \\
+ 0 & \mathrm{cos}(\phi) & -i\;\mathrm{sin}(\phi) & 0 \\
+ 0 & -i\;\mathrm{sin}(\phi) & \mathrm{cos}(\phi) & 0 \\
+ 0 & 0 & 0 & 1 \\
+ \end{array}\right).
+
+ Args:
+ phi (float): angle entering the controlled-RX operator :math:`CRX(2\phi)`
+ wires (list[Wires]): the two wires ``n`` and ``m`` the circuit acts on
+ """
+
+ CNOT(wires=wires)
+ CRX(2 * phi, wires=wires[::-1])
+ CNOT(wires=wires)
+
+
+@template
+def ParticleConservingU2(weights, wires, init_state=None):
+ r"""Implements the heuristic VQE ansatz for Quantum Chemistry simulations using the
+ particle-conserving entangler :math:`U_\mathrm{ent}(\vec{\theta}, \vec{\phi})` proposed in
+ `arXiv:1805.04340 `_.
+
+ This template prepares :math:`N`-qubit trial states by applying :math:`D` layers of the entangler
+ block :math:`U_\mathrm{ent}(\vec{\theta}, \vec{\phi})` to the Hartree-Fock state
+
+ .. math::
+
+ \vert \Psi(\vec{\theta}, \vec{\phi}) \rangle = \hat{U}^{(D)}_\mathrm{ent}(\vec{\theta}_D,
+ \vec{\phi}_D) \dots \hat{U}^{(2)}_\mathrm{ent}(\vec{\theta}_2, \vec{\phi}_2)
+ \hat{U}^{(1)}_\mathrm{ent}(\vec{\theta}_1, \vec{\phi}_1) \vert \mathrm{HF}\rangle,
+
+ where :math:`\hat{U}^{(i)}_\mathrm{ent}(\vec{\theta}_i, \vec{\phi}_i) =
+ \hat{R}_\mathrm{z}(\vec{\theta}_i) \hat{U}_\mathrm{2,\mathrm{ex}}(\vec{\phi}_i)`.
+ The circuit implementing the entangler blocks is shown in the figure below:
+
+ |
+
+ .. figure:: ../../_static/templates/layers/particle_conserving_u2.png
+ :align: center
+ :width: 60%
+ :target: javascript:void(0);
+
+ |
+
+ Each layer contains :math:`N` rotation gates :math:`R_\mathrm{z}(\vec{\theta})` and
+ :math:`N-1` particle-conserving exchange gates :math:`U_{2,\mathrm{ex}}(\phi)`
+ that act on pairs of nearest-neighbors qubits. The repeated units across several qubits are
+ shown in dotted boxes. The unitary matrix representing :math:`U_{2,\mathrm{ex}}(\phi)`
+ (`arXiv:1805.04340 `_) is decomposed into its elementary
+ gates and implemented in the :func:`~.u2_ex_gate` function using PennyLane quantum operations.
+
+ |
+
+ .. figure:: ../../_static/templates/layers/u2_decomposition.png
+ :align: center
+ :width: 60%
+ :target: javascript:void(0);
+
+ |
+
+
+ Args:
+ weights (array[float]): Array of weights 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 or Wires): Wires that the template acts on. Accepts an iterable of numbers
+ or strings, or a Wires object.
+ init_state (array[int]): length ``len(wires)`` vector representing the Hartree-Fock state
+ used to initialize the wires.
+
+ Raises:
+ ValueError: if inputs do not have the correct format
+
+ .. UsageDetails::
+
+
+ #. The number of wires has to be equal to the number of spin orbitals included in
+ the active space.
+
+ #. The number of trainable parameters scales with the number of layers :math:`D` as
+ :math:`D(2N-1)`.
+
+ An example of how to use this template is shown below:
+
+ .. code-block:: python
+
+ import pennylane as qml
+ from pennylane.templates import ParticleConservingU2
+
+ from functools import partial
+
+ # Build the electronic Hamiltonian from a local .xyz file
+ h, qubits = qml.qchem.molecular_hamiltonian("h2", "h2.xyz")
+
+ # Define the HF state
+ ref_state = qml.qchem.hf_state(2, qubits)
+
+ # Define the device
+ dev = qml.device('default.qubit', wires=qubits)
+
+ # Define the ansatz
+ ansatz = partial(ParticleConservingU2, init_state=ref_state)
+
+ # Define the cost function
+ cost_fn = qml.VQECost(ansatz, h, dev)
+
+ # Compute the expectation value of 'h' for a given set of parameters
+ layers = 1
+ params = qml.init.particle_conserving_u2_normal(layers, qubits)
+ print(cost_fn(params))
+ """
+
+ wires = Wires(wires)
+
+ layers = weights.shape[0]
+
+ if len(wires) < 2:
+ raise ValueError(
+ "This template requires the number of qubits to be greater than one;"
+ "got a wire sequence with {} elements".format(len(wires))
+ )
+
+ expected_shape = (layers, 2 * len(wires) - 1)
+ check_shape(
+ weights,
+ expected_shape,
+ msg="'weights' must be of shape {}; got {}".format(expected_shape, get_shape(weights)),
+ )
+
+ nm_wires = [wires.subset([l, l + 1]) for l in range(0, len(wires) - 1, 2)]
+ nm_wires += [wires.subset([l, l + 1]) for l in range(1, len(wires) - 1, 2)]
+
+ qml.BasisState(init_state, wires=wires)
+
+ for l in range(layers):
+
+ for j, _ in enumerate(wires):
+ RZ(weights[l, j], wires=wires[j])
+
+ for i, wires_ in enumerate(nm_wires):
+ u2_ex_gate(weights[l, len(wires) + i], wires=wires_)
diff --git a/tests/templates/test_integration.py b/tests/templates/test_integration.py
index cfd11768597..a2868d46a2e 100644
--- a/tests/templates/test_integration.py
+++ b/tests/templates/test_integration.py
@@ -148,6 +148,10 @@
{'wires': [0, 1, 2, 3], 's_wires': [[0, 1, 2], [1, 2, 3]],
'd_wires': [[[0, 1], [2, 3]]], 'init_state':np.array([1, 1, 0, 0])},
4),
+ (qml.templates.ParticleConservingU2,
+ {'weights': np.array([[0.35172862, 0.60808317, 1.44397231]])},
+ {'wires': [0, 1], 'init_state': np.array([1, 0])},
+ 2),
(qml.templates.ParticleConservingU1,
{'weights': np.array([[[ 0.17586701, -0.20382066]]])},
{'wires': [0, 1], 'init_state':np.array([1, 0])},
@@ -188,7 +192,7 @@
# before they are called in a quantum function.
# These templates will be skipped in tests of that nature.
-NO_OP_BEFORE = ["AmplitudeEmbedding", "UCCSD", "ParticleConservingU1"]
+NO_OP_BEFORE = ["AmplitudeEmbedding", "UCCSD", "ParticleConservingU2", "ParticleConservingU1"]
# Each entry to QUBIT_INIT and CV_INIT adds a template with specified inputs to the
# integration tests ``TestIntegrationInitFunctions``
diff --git a/tests/templates/test_layers.py b/tests/templates/test_layers.py
index 3f8bcc59d3d..e915d61c5b4 100644
--- a/tests/templates/test_layers.py
+++ b/tests/templates/test_layers.py
@@ -26,6 +26,7 @@
RandomLayers,
BasicEntanglerLayers,
SimplifiedTwoDesign,
+ ParticleConservingU2,
ParticleConservingU1,
)
from pennylane.templates.layers.random import random_layer
@@ -707,6 +708,145 @@ def circuit(weights):
assert exp == target_exp
+class TestParticleConservingU2:
+ """Tests for the ParticleConservingU2 template from the pennylane.templates.layers module."""
+
+ @pytest.mark.parametrize(
+ "layers, qubits, init_state",
+ [
+ (2, 4, np.array([1, 1, 0, 0])),
+ (1, 6, np.array([1, 1, 0, 0, 0, 0])),
+ (1, 5, np.array([1, 1, 0, 0, 0])),
+ ],
+ )
+ def test_u2_operations(self, layers, qubits, init_state):
+ """Test the correctness of the ParticleConservingU2 template including the gate count
+ and order, the wires each operation acts on and the correct use of parameters
+ in the circuit."""
+ weights = np.random.normal(0, 2 * np.pi, (layers, 2 * qubits - 1))
+
+ n_gates = 1 + (qubits + (qubits - 1) * 3) * layers
+
+ exp_gates = (
+ [qml.RZ] * qubits + ([qml.CNOT] + [qml.CRX] + [qml.CNOT]) * (qubits - 1)
+ ) * layers
+
+ with pennylane._queuing.OperationRecorder() as rec:
+ ParticleConservingU2(weights, wires=range(qubits), init_state=init_state)
+
+ # number of gates
+ assert len(rec.queue) == n_gates
+
+ # initialization
+ assert isinstance(rec.queue[0], qml.BasisState)
+
+ # order of gates
+ for op1, op2 in zip(rec.queue[1:], exp_gates):
+ assert isinstance(op1, op2)
+
+ # gate parameter
+ params = np.array(
+ [
+ rec.queue[i].parameters
+ for i in range(1, n_gates)
+ if rec.queue[i].parameters != []
+ ]
+ )
+ weights[:, qubits:] = weights[:, qubits:] * 2
+ assert np.allclose(params.flatten(), weights.flatten())
+
+ # gate wires
+ wires = Wires(range(qubits))
+ nm_wires = [wires.subset([l, l + 1]) for l in range(0, qubits - 1, 2)]
+ nm_wires += [wires.subset([l, l + 1]) for l in range(1, qubits - 1, 2)]
+
+ exp_wires = []
+ for _ in range(layers):
+ for i in range(qubits):
+ exp_wires.append(wires.subset([i]))
+ for j in nm_wires:
+ exp_wires.append(j)
+ exp_wires.append(j[::-1])
+ exp_wires.append(j)
+
+ res_wires = [rec.queue[i]._wires for i in range(1, n_gates)]
+
+ assert res_wires == exp_wires
+
+ @pytest.mark.parametrize(
+ ("weights", "wires", "msg_match"),
+ [
+ (
+ np.array([[-0.080, 2.629, -0.710, 5.383, 0.646, -2.872, -3.856]]),
+ [0],
+ "This template requires the number of qubits to be greater than one",
+ ),
+ (
+ np.array([[-0.080, 2.629, -0.710, 5.383]]),
+ [0, 1, 2, 3],
+ "'weights' must be of shape",
+ ),
+ (
+ np.array(
+ [
+ [-0.080, 2.629, -0.710, 5.383, 0.646, -2.872],
+ [-0.080, 2.629, -0.710, 5.383, 0.646, -2.872],
+ ]
+ ),
+ [0, 1, 2, 3],
+ "'weights' must be of shape",
+ ),
+ ],
+ )
+ def test_u2_exceptions(self, weights, wires, msg_match):
+ """Test that ParticleConservingU2 throws an exception if the parameters have illegal
+ shapes, types or values."""
+ N = len(wires)
+ init_state = np.array([1, 1, 0, 0])
+
+ dev = qml.device("default.qubit", wires=N)
+
+ @qml.qnode(dev)
+ def circuit():
+ ParticleConservingU2(
+ weights=weights,
+ wires=wires,
+ init_state=init_state,
+ )
+ return qml.expval(qml.PauliZ(0))
+
+ with pytest.raises(ValueError, match=msg_match):
+ circuit()
+
+ @pytest.mark.parametrize(
+ ("weights", "wires", "expected"),
+ [
+ (
+ np.array([[-2.712, -1.958, 1.875, 1.811, 0.296, -0.412, 1.723]]),
+ [0, 1, 2, 3],
+ [-1.0, 0.95402475, -0.95402475, 1.0],
+ )
+ ],
+ )
+ def test_u2_integration(self, weights, wires, expected):
+ """Test integration with PennyLane and gradient calculations"""
+
+ N = len(wires)
+ dev = qml.device("default.qubit", wires=N)
+
+ @qml.qnode(dev)
+ def circuit():
+ ParticleConservingU2(
+ weights,
+ wires,
+ init_state=np.array([1, 1, 0, 0]),
+ )
+ return [qml.expval(qml.PauliZ(w)) for w in range(N)]
+
+ res = circuit()
+ assert np.allclose(res, np.array(expected))
+
+
class TestParticleConservingU1:
"""Tests for the ParticleConservingU1 template from the
pennylane.templates.layers module."""
@@ -868,6 +1008,45 @@ def circuit(weights):
exp = np.array([-0.99993177, -0.9853332, 0.98531251, 0.99995246])
assert np.allclose(res, np.array(exp), atol=tol)
+
+ @pytest.mark.parametrize(
+ ("init_state", "exp_state"),
+ [
+ (np.array([0, 0]), np.array([1.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j])),
+ (
+ np.array([0, 1]),
+ np.array([0.0 + 0.0j, 0.862093 + 0.0j, 0.0 - 0.506749j, 0.0 + 0.0j]),
+ ),
+ (
+ np.array([1, 0]),
+ np.array([0.0 + 0.0j, 0.0 - 0.506749j, 0.862093 + 0.0j, 0.0 + 0.0j]),
+ ),
+ (np.array([1, 1]), np.array([0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 1.0 + 0.0j])),
+ ],
+ )
+ def test_decomposition_u2ex(self, init_state, exp_state, tol):
+ """Test the decomposition of the U_{2, ex}` exchange gate by asserting the prepared
+ state."""
+
+ N = 2
+ wires = range(N)
+ wires = Wires(wires)
+
+ weight = 0.53141
+
+ dev = qml.device("default.qubit", wires=N)
+
+ @qml.qnode(dev)
+ def circuit(weight):
+ qml.BasisState(init_state, wires=wires)
+ qml.templates.layers.particle_conserving_u2.u2_ex_gate(weight, wires)
+ return qml.expval(qml.PauliZ(0))
+
+ circuit(weight)
+
+ assert np.allclose(dev.state, exp_state, atol=tol)
+
+
@pytest.mark.parametrize(
("init_state", "exp_state"),
[
diff --git a/tests/test_init.py b/tests/test_init.py
index 2bdd380067a..935329af6d0 100644
--- a/tests/test_init.py
+++ b/tests/test_init.py
@@ -352,6 +352,54 @@ def test_zero_wires(self, init, sgntr):
assert p.flatten().shape == (0,)
+ def test_particle_conserving_u2_init(self, tol):
+ """Test the functions 'particle_conserving_u2_uniform' and
+ 'particle_conserving_u2_normal'."""
+
+ n_layers = 2
+ n_wires = 4
+
+ # check the shape
+ exp_shape = (n_layers, 2 * n_wires - 1)
+ params = qml.init.particle_conserving_u2_uniform(n_layers, n_wires)
+ assert params.shape == exp_shape
+
+ params = qml.init.particle_conserving_u2_normal(n_layers, n_wires)
+ assert params.shape == exp_shape
+
+ # check deterministic output for a fixed seed
+ seed = 1975
+ p1 = qml.init.particle_conserving_u2_uniform(n_layers, n_wires, seed=seed)
+ p2 = qml.init.particle_conserving_u2_uniform(n_layers, n_wires, seed=seed)
+ assert np.allclose(p1, p2, atol=tol)
+
+ p1 = qml.init.particle_conserving_u2_normal(n_layers, n_wires, seed=seed)
+ p2 = qml.init.particle_conserving_u2_normal(n_layers, n_wires, seed=seed)
+ assert np.allclose(p1, p2, atol=tol)
+
+ # check that the output is different for different seeds
+ p1 = qml.init.particle_conserving_u2_uniform(n_layers, n_wires, seed=seed)
+ p2 = qml.init.particle_conserving_u2_uniform(n_layers, n_wires, seed=seed+1)
+ assert not np.allclose(p1, p2, atol=tol)
+
+ p1 = qml.init.particle_conserving_u2_normal(n_layers, n_wires, seed=seed)
+ p2 = qml.init.particle_conserving_u2_normal(n_layers, n_wires, seed=seed+1)
+ assert not np.allclose(p1, p2, atol=tol)
+
+ def test_particle_conserving_u2_init_exceptions(self):
+ """Test exceptions the functions 'particle_conserving_u2_uniform' and
+ 'particle_conserving_u2_normal'."""
+
+ n_layers = 4
+ n_wires = 1
+
+ msg_match = "The number of qubits must be greater than one"
+
+ with pytest.raises(ValueError, match=msg_match):
+ qml.init.particle_conserving_u2_uniform(n_layers, n_wires)
+
+ with pytest.raises(ValueError, match=msg_match):
+ qml.init.particle_conserving_u2_normal(n_layers, n_wires)
def test_particle_conserving_u1_init(self, tol):
"""Test the functions 'particle_conserving_u1_uniform' and
@@ -380,14 +428,13 @@ def test_particle_conserving_u1_init(self, tol):
# check that the output is different for different seeds
p1 = qml.init.particle_conserving_u1_uniform(n_layers, n_wires, seed=seed)
- p2 = qml.init.particle_conserving_u1_uniform(n_layers, n_wires, seed=seed+1)
+ p2 = qml.init.particle_conserving_u1_uniform(n_layers, n_wires, seed=seed + 1)
assert not np.allclose(p1, p2, atol=tol)
p1 = qml.init.particle_conserving_u1_normal(n_layers, n_wires, seed=seed)
- p2 = qml.init.particle_conserving_u1_normal(n_layers, n_wires, seed=seed+1)
+ p2 = qml.init.particle_conserving_u1_normal(n_layers, n_wires, seed=seed + 1)
assert not np.allclose(p1, p2, atol=tol)
-
def test_particle_conserving_u1_init_exceptions(self):
"""Test exceptions the functions 'particle_conserving_u1_uniform' and
'particle_conserving_u1_normal'."""