diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 0349e7a757f..4630e22253b 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -54,6 +54,11 @@
Improvements
+* The qchem openfermion-dependent tests are localized and collected in `tests.qchem.of_tests`. The
+ new module `test_structure` is created to collect the tests of the `qchem.structure` module in
+ one place and remove their dependency to openfermion.
+ [(#2593)](https://github.com/PennyLaneAI/pennylane/pull/2593)
+
* The developer-facing `pow` method has been added to `Operator` with concrete implementations
for many classes.
[(#2225)](https://github.com/PennyLaneAI/pennylane/pull/2225)
diff --git a/tests/qchem/hf_tests/conftest.py b/tests/qchem/hf_tests/conftest.py
deleted file mode 100644
index 8d840b15b42..00000000000
--- a/tests/qchem/hf_tests/conftest.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import pennylane as qml
-import pytest
-
-
-@pytest.fixture(scope="session")
-def tol():
- """Numerical tolerance for equality tests."""
- return {"rtol": 0, "atol": 1e-8}
-
-
-@pytest.fixture(
- scope="module",
- params=[
- None,
- qml.wires.Wires(
- list("ab") + [-3, 42] + ["xyz", "23", "wireX"] + [f"w{i}" for i in range(20)]
- ),
- list(range(100, 120)),
- {13 - i: "abcdefghijklmn"[i] for i in range(14)},
- ],
-)
-def custom_wires(request):
- """Custom wire mapping for Pennylane<->OpenFermion conversion"""
- return request.param
diff --git a/tests/qchem/of_tests/test_active_space.py b/tests/qchem/of_tests/test_active_space.py
deleted file mode 100644
index 469a0ad5cd8..00000000000
--- a/tests/qchem/of_tests/test_active_space.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import os
-import sys
-
-import pytest
-
-from pennylane import qchem
-
-# TODO: Bring pytest skip to relevant tests.
-openfermion = pytest.importorskip("openfermion")
-openfermionpyscf = pytest.importorskip("openfermionpyscf")
-
-ref_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_ref_files")
-
-
-@pytest.mark.parametrize(
- ("mol_name", "act_electrons", "act_orbitals", "core_ref", "active_ref"),
- [
- ("lih", None, None, [], list(range(6))),
- ("lih", 4, None, [], list(range(6))),
- ("lih", 2, None, [0], list(range(1, 6))),
- ("lih", None, 4, [], list(range(4))),
- ("lih", 2, 3, [0], list(range(1, 4))),
- ("lih_anion", 3, 4, [0], list(range(1, 5))),
- ("lih_anion", 1, 4, [0, 1], list(range(2, 6))),
- ],
-)
-def test_active_spaces(mol_name, act_electrons, act_orbitals, core_ref, active_ref):
- r"""Test the correctness of the generated active spaces"""
-
- molecule = openfermion.MolecularData(filename=os.path.join(ref_dir, mol_name))
-
- core, active = qchem.active_space(
- molecule.n_electrons,
- molecule.n_orbitals,
- mult=molecule.multiplicity,
- active_electrons=act_electrons,
- active_orbitals=act_orbitals,
- )
-
- assert core == core_ref
- assert active == active_ref
-
-
-@pytest.mark.parametrize(
- ("mol_name", "act_electrons", "act_orbitals", "message_match"),
- [
- ("lih", 6, 5, "greater than the total number of electrons"),
- ("lih", 1, 5, "should be even"),
- ("lih", -1, 5, "has to be greater than 0."),
- ("lih", 2, 6, "greater than the total number of orbitals"),
- ("lih", 2, 1, "there are no virtual orbitals"),
- ("lih_anion", 2, 5, "should be odd"),
- ("lih_anion", 3, -2, "has to be greater than 0."),
- ("lih_anion", 3, 6, "greater than the total number of orbitals"),
- ("lih_anion", 3, 2, "there are no virtual orbitals"),
- ("lih_anion_2", 1, 2, "greater than or equal to"),
- ],
-)
-def test_inconsistent_active_spaces(mol_name, act_electrons, act_orbitals, message_match):
- r"""Test that an error is raised if an inconsistent active space is generated"""
-
- molecule = openfermion.MolecularData(filename=os.path.join(ref_dir, mol_name))
-
- with pytest.raises(ValueError, match=message_match):
- qchem.active_space(
- molecule.n_electrons,
- molecule.n_orbitals,
- mult=molecule.multiplicity,
- active_electrons=act_electrons,
- active_orbitals=act_orbitals,
- )
diff --git a/tests/qchem/of_tests/test_excitations.py b/tests/qchem/of_tests/test_excitations.py
deleted file mode 100644
index 6d171405519..00000000000
--- a/tests/qchem/of_tests/test_excitations.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import pytest
-
-from pennylane import qchem
-
-
-@pytest.mark.parametrize(
- (
- "electrons",
- "orbitals",
- "delta_sz",
- "n_singles",
- "n_doubles",
- "singles_exp",
- "doubles_exp",
- ),
- [
- (1, 5, 0, 2, 0, [[0, 2], [0, 4]], []),
- (1, 5, 1, 0, 0, [], []),
- (1, 5, -1, 2, 0, [[0, 1], [0, 3]], []),
- (2, 5, 0, 3, 2, [[0, 2], [0, 4], [1, 3]], [[0, 1, 2, 3], [0, 1, 3, 4]]),
- (2, 5, 1, 2, 1, [[1, 2], [1, 4]], [[0, 1, 2, 4]]),
- (2, 5, -1, 1, 0, [[0, 3]], []),
- (2, 5, 2, 0, 0, [], []),
- (3, 6, 1, 1, 0, [[1, 4]], []),
- (
- 3,
- 6,
- -1,
- 4,
- 4,
- [[0, 3], [0, 5], [2, 3], [2, 5]],
- [[0, 1, 3, 5], [0, 2, 3, 4], [0, 2, 4, 5], [1, 2, 3, 5]],
- ),
- (3, 6, -2, 0, 1, [], [[0, 2, 3, 5]]),
- (3, 4, 0, 1, 0, [[1, 3]], []),
- (3, 4, 1, 0, 0, [], []),
- (3, 4, -1, 2, 0, [[0, 3], [2, 3]], []),
- (3, 4, 2, 0, 0, [], []),
- ],
-)
-def test_excitations(electrons, orbitals, delta_sz, n_singles, n_doubles, singles_exp, doubles_exp):
- r"""Test the correctness of the generated configurations"""
-
- singles, doubles = qchem.excitations(electrons, orbitals, delta_sz)
-
- assert len(singles) == len(singles_exp)
- assert len(doubles) == len(doubles_exp)
- assert singles == singles_exp
- assert doubles == doubles_exp
-
-
-@pytest.mark.parametrize(
- ("electrons", "orbitals", "delta_sz", "message_match"),
- [
- (0, 4, 0, "number of active electrons has to be greater than 0"),
- (3, 2, 0, "has to be greater than the number of active electrons"),
- (2, 4, 3, "Expected values for 'delta_sz'"),
- (2, 4, 1.5, "Expected values for 'delta_sz'"),
- ],
-)
-def test_inconsistent_excitations(electrons, orbitals, delta_sz, message_match):
- r"""Test that an error is raised if a set of inconsistent arguments is input"""
-
- with pytest.raises(ValueError, match=message_match):
- qchem.excitations(electrons, orbitals, delta_sz)
diff --git a/tests/qchem/of_tests/test_excitations_to_wires.py b/tests/qchem/of_tests/test_excitations_to_wires.py
deleted file mode 100644
index c1fe766fc93..00000000000
--- a/tests/qchem/of_tests/test_excitations_to_wires.py
+++ /dev/null
@@ -1,94 +0,0 @@
-import numpy as np
-import pytest
-
-import pennylane as qml
-from pennylane import qchem
-from pennylane.templates.subroutines import UCCSD
-
-
-@pytest.mark.parametrize(
- ("singles", "doubles", "wires", "singles_wires_exp", "doubles_wires_exp"),
- [
- ([[0, 2]], [], None, [[0, 1, 2]], []),
- ([], [[0, 1, 2, 3]], None, [], [[[0, 1], [2, 3]]]),
- ([[0, 1]], [[0, 1, 2, 4]], None, [[0, 1]], [[[0, 1], [2, 3, 4]]]),
- (
- [[0, 1], [2, 4]],
- [[0, 1, 2, 3], [0, 2, 4, 6]],
- None,
- [[0, 1], [2, 3, 4]],
- [[[0, 1], [2, 3]], [[0, 1, 2], [4, 5, 6]]],
- ),
- (
- [[0, 1], [2, 4]],
- [[0, 1, 2, 3], [0, 2, 4, 6]],
- ["a0", "b1", "c2", "d3", "e4", "f5", "g6"],
- [["a0", "b1"], ["c2", "d3", "e4"]],
- [[["a0", "b1"], ["c2", "d3"]], [["a0", "b1", "c2"], ["e4", "f5", "g6"]]],
- ),
- ],
-)
-def test_mapping_from_excitations_to_wires(
- singles, doubles, wires, singles_wires_exp, doubles_wires_exp
-):
- r"""Test the correctness of the mapping between indices of the single and double
- excitations and the list of wires to be passed to the quantum circuit"""
-
- singles_wires, doubles_wires = qchem.excitations_to_wires(singles, doubles, wires=wires)
-
- assert len(singles_wires) == len(singles_wires_exp)
- assert len(doubles_wires) == len(doubles_wires_exp)
- assert singles_wires == singles_wires_exp
- assert doubles_wires == doubles_wires_exp
-
-
-@pytest.mark.parametrize(
- ("singles", "doubles", "wires", "message_match"),
- [
- ([], [], None, "'singles' and 'doubles' lists can not be both empty"),
- ([[0, 2, 3]], [], None, "Expected entries of 'singles' to be of shape"),
- ([[0, 2], [3]], [], None, "Expected entries of 'singles' to be of shape"),
- ([], [[0, 1, 2, 3], [1, 3]], None, "Expected entries of 'doubles' to be of shape"),
- ([], [[0, 1, 2, 3], [1, 3, 4, 5, 6]], None, "Expected entries of 'doubles' to be of shape"),
- (
- [[0, 2]],
- [[0, 1, 2, 3], [0, 2, 4, 6]],
- ["a0", "b1", "c2", "d3", "e4", "f5"],
- "Expected number of wires is",
- ),
- ],
-)
-def test_excitations_to_wires_exceptions(singles, doubles, wires, message_match):
- r"""Test that the function 'excitations_to_wires()' throws an exception if ``singles``,
- ``doubles`` or ``wires`` parameter has illegal shapes or size"""
-
- with pytest.raises(ValueError, match=message_match):
- qchem.excitations_to_wires(singles, doubles, wires=wires)
-
-
-@pytest.mark.parametrize(
- ("weights", "singles", "doubles", "expected"),
- [
- (
- np.array([3.90575761, -1.89772083, -1.36689032]),
- [[0, 2], [1, 3]],
- [[0, 1, 2, 3]],
- [-0.14619406, -0.06502792, 0.14619406, 0.06502792],
- )
- ],
-)
-def test_integration_with_uccsd(weights, singles, doubles, expected, tol):
- """Test integration with the UCCSD template"""
-
- s_wires, d_wires = qchem.excitations_to_wires(singles, doubles)
- N = 4
- wires = range(N)
- dev = qml.device("default.qubit", wires=N)
-
- @qml.qnode(dev)
- def circuit(weights):
- UCCSD(weights, wires, s_wires=s_wires, d_wires=d_wires, init_state=np.array([1, 1, 0, 0]))
- return [qml.expval(qml.PauliZ(w)) for w in range(N)]
-
- res = circuit(weights)
- assert np.allclose(res, np.array(expected), **tol)
diff --git a/tests/qchem/of_tests/test_hf_state.py b/tests/qchem/of_tests/test_hf_state.py
deleted file mode 100644
index a94e1f45b2b..00000000000
--- a/tests/qchem/of_tests/test_hf_state.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import numpy as np
-import pytest
-
-from pennylane import qchem
-
-
-@pytest.mark.parametrize(
- ("electrons", "orbitals", "exp_state"),
- [
- (2, 5, np.array([1, 1, 0, 0, 0])),
- (1, 5, np.array([1, 0, 0, 0, 0])),
- (5, 5, np.array([1, 1, 1, 1, 1])),
- ],
-)
-def test_hf_state(electrons, orbitals, exp_state):
- r"""Test the correctness of the generated occupation-number vector"""
-
- res_state = qchem.hf_state(electrons, orbitals)
-
- assert len(res_state) == len(exp_state)
- assert np.allclose(res_state, exp_state)
-
-
-@pytest.mark.parametrize(
- ("electrons", "orbitals", "msg_match"),
- [
- (0, 5, "number of active electrons has to be larger than zero"),
- (-1, 5, "number of active electrons has to be larger than zero"),
- (6, 5, "number of active orbitals cannot be smaller than the number of active"),
- ],
-)
-def test_inconsistent_input(electrons, orbitals, msg_match):
- r"""Test that an error is raised if a set of inconsistent arguments is input"""
-
- with pytest.raises(ValueError, match=msg_match):
- qchem.hf_state(electrons, orbitals)
diff --git a/tests/qchem/of_tests/test_molecular_hamiltonian.py b/tests/qchem/of_tests/test_molecular_hamiltonian.py
index 2023c53c5a9..86d6c396f44 100644
--- a/tests/qchem/of_tests/test_molecular_hamiltonian.py
+++ b/tests/qchem/of_tests/test_molecular_hamiltonian.py
@@ -226,7 +226,7 @@ def test_mol_hamiltonian_with_read_structure(tmpdir):
with open(filename, "w") as f:
f.write(file_content)
- symbols, coordinates = qchem.read_structure(str(filename))
+ symbols, coordinates = qchem.read_structure(str(filename), outpath=tmpdir)
H, num_qubits = qchem.molecular_hamiltonian(symbols, coordinates)
assert len(H.terms()) == 2
assert num_qubits == 4
diff --git a/tests/qchem/of_tests/test_read_structure.py b/tests/qchem/of_tests/test_read_structure.py
deleted file mode 100644
index 7ebd7e07f92..00000000000
--- a/tests/qchem/of_tests/test_read_structure.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import os
-
-import numpy as np
-
-from pennylane import qchem
-
-ref_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_ref_files")
-
-
-def test_reading_xyz_file(tmpdir):
- r"""Test reading of the generated file 'structure.xyz'"""
-
- ref_symbols = ["C", "C", "N", "H", "H", "H", "H", "H"]
- ref_coords = np.array(
- [
- 0.68219113,
- -0.85415621,
- -1.04123909,
- -1.34926445,
- 0.23621577,
- 0.61794044,
- 1.29068294,
- 0.25133357,
- 1.40784596,
- 0.83525895,
- -2.88939124,
- -1.16974047,
- 1.26989596,
- 0.19275206,
- -2.69852891,
- -2.57758643,
- -1.05824663,
- 1.61949529,
- -2.17129532,
- 2.04090421,
- 0.11338357,
- 2.06547065,
- 2.00877887,
- 1.20186582,
- ]
- )
- name = os.path.join(ref_dir, "gdb3.mol5.XYZ")
- symbols, coordinates = qchem.read_structure(name, outpath=tmpdir)
-
- assert symbols == ref_symbols
- assert np.allclose(coordinates, ref_coords)
diff --git a/tests/qchem/hf_tests/test_basis_set.py b/tests/qchem/test_basis_set.py
similarity index 100%
rename from tests/qchem/hf_tests/test_basis_set.py
rename to tests/qchem/test_basis_set.py
diff --git a/tests/qchem/hf_tests/test_dipole.py b/tests/qchem/test_dipole.py
similarity index 100%
rename from tests/qchem/hf_tests/test_dipole.py
rename to tests/qchem/test_dipole.py
diff --git a/tests/qchem/hf_tests/test_hamiltonians.py b/tests/qchem/test_hamiltonians.py
similarity index 100%
rename from tests/qchem/hf_tests/test_hamiltonians.py
rename to tests/qchem/test_hamiltonians.py
diff --git a/tests/qchem/hf_tests/test_hartree_fock.py b/tests/qchem/test_hartree_fock.py
similarity index 100%
rename from tests/qchem/hf_tests/test_hartree_fock.py
rename to tests/qchem/test_hartree_fock.py
diff --git a/tests/qchem/hf_tests/test_integrals.py b/tests/qchem/test_integrals.py
similarity index 100%
rename from tests/qchem/hf_tests/test_integrals.py
rename to tests/qchem/test_integrals.py
diff --git a/tests/qchem/hf_tests/test_matrices.py b/tests/qchem/test_matrices.py
similarity index 100%
rename from tests/qchem/hf_tests/test_matrices.py
rename to tests/qchem/test_matrices.py
diff --git a/tests/qchem/hf_tests/test_molecule.py b/tests/qchem/test_molecule.py
similarity index 100%
rename from tests/qchem/hf_tests/test_molecule.py
rename to tests/qchem/test_molecule.py
diff --git a/tests/qchem/hf_tests/test_observable_hf.py b/tests/qchem/test_observable_hf.py
similarity index 100%
rename from tests/qchem/hf_tests/test_observable_hf.py
rename to tests/qchem/test_observable_hf.py
diff --git a/tests/qchem/hf_tests/test_particle_number.py b/tests/qchem/test_particle_number.py
similarity index 100%
rename from tests/qchem/hf_tests/test_particle_number.py
rename to tests/qchem/test_particle_number.py
diff --git a/tests/qchem/of_tests/test_ref_files/gdb3.mol5.XYZ b/tests/qchem/test_ref_files/gdb3.mol5.XYZ
similarity index 100%
rename from tests/qchem/of_tests/test_ref_files/gdb3.mol5.XYZ
rename to tests/qchem/test_ref_files/gdb3.mol5.XYZ
diff --git a/tests/qchem/hf_tests/test_spin.py b/tests/qchem/test_spin.py
similarity index 100%
rename from tests/qchem/hf_tests/test_spin.py
rename to tests/qchem/test_spin.py
diff --git a/tests/qchem/test_structure.py b/tests/qchem/test_structure.py
new file mode 100644
index 00000000000..2460ef554aa
--- /dev/null
+++ b/tests/qchem/test_structure.py
@@ -0,0 +1,313 @@
+# Copyright 2018-2022 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.
+"""
+Unit tests for the functions of the structure module.
+"""
+import os
+import pytest
+import pennylane as qml
+from pennylane import qchem
+from pennylane import numpy as np
+from pennylane.templates.subroutines import UCCSD
+
+
+ref_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_ref_files")
+
+
+def test_reading_xyz_file(tmpdir):
+ r"""Test reading of the generated file 'structure.xyz'"""
+
+ ref_symbols = ["C", "C", "N", "H", "H", "H", "H", "H"]
+ ref_coords = np.array(
+ [
+ 0.68219113,
+ -0.85415621,
+ -1.04123909,
+ -1.34926445,
+ 0.23621577,
+ 0.61794044,
+ 1.29068294,
+ 0.25133357,
+ 1.40784596,
+ 0.83525895,
+ -2.88939124,
+ -1.16974047,
+ 1.26989596,
+ 0.19275206,
+ -2.69852891,
+ -2.57758643,
+ -1.05824663,
+ 1.61949529,
+ -2.17129532,
+ 2.04090421,
+ 0.11338357,
+ 2.06547065,
+ 2.00877887,
+ 1.20186582,
+ ]
+ )
+ name = os.path.join(ref_dir, "gdb3.mol5.XYZ")
+ symbols, coordinates = qchem.read_structure(name, outpath=tmpdir)
+
+ assert symbols == ref_symbols
+ assert np.allclose(coordinates, ref_coords)
+
+
+@pytest.mark.parametrize(
+ (
+ "electrons",
+ "orbitals",
+ "delta_sz",
+ "n_singles",
+ "n_doubles",
+ "singles_exp",
+ "doubles_exp",
+ ),
+ [
+ (1, 5, 0, 2, 0, [[0, 2], [0, 4]], []),
+ (1, 5, 1, 0, 0, [], []),
+ (1, 5, -1, 2, 0, [[0, 1], [0, 3]], []),
+ (2, 5, 0, 3, 2, [[0, 2], [0, 4], [1, 3]], [[0, 1, 2, 3], [0, 1, 3, 4]]),
+ (2, 5, 1, 2, 1, [[1, 2], [1, 4]], [[0, 1, 2, 4]]),
+ (2, 5, -1, 1, 0, [[0, 3]], []),
+ (2, 5, 2, 0, 0, [], []),
+ (3, 6, 1, 1, 0, [[1, 4]], []),
+ (
+ 3,
+ 6,
+ -1,
+ 4,
+ 4,
+ [[0, 3], [0, 5], [2, 3], [2, 5]],
+ [[0, 1, 3, 5], [0, 2, 3, 4], [0, 2, 4, 5], [1, 2, 3, 5]],
+ ),
+ (3, 6, -2, 0, 1, [], [[0, 2, 3, 5]]),
+ (3, 4, 0, 1, 0, [[1, 3]], []),
+ (3, 4, 1, 0, 0, [], []),
+ (3, 4, -1, 2, 0, [[0, 3], [2, 3]], []),
+ (3, 4, 2, 0, 0, [], []),
+ ],
+)
+def test_excitations(electrons, orbitals, delta_sz, n_singles, n_doubles, singles_exp, doubles_exp):
+ r"""Test the correctness of the generated configurations"""
+
+ singles, doubles = qchem.excitations(electrons, orbitals, delta_sz)
+
+ assert len(singles) == len(singles_exp)
+ assert len(doubles) == len(doubles_exp)
+ assert singles == singles_exp
+ assert doubles == doubles_exp
+
+
+@pytest.mark.parametrize(
+ ("electrons", "orbitals", "delta_sz", "message_match"),
+ [
+ (0, 4, 0, "number of active electrons has to be greater than 0"),
+ (3, 2, 0, "has to be greater than the number of active electrons"),
+ (2, 4, 3, "Expected values for 'delta_sz'"),
+ (2, 4, 1.5, "Expected values for 'delta_sz'"),
+ ],
+)
+def test_inconsistent_excitations(electrons, orbitals, delta_sz, message_match):
+ r"""Test that an error is raised if a set of inconsistent arguments is input"""
+
+ with pytest.raises(ValueError, match=message_match):
+ qchem.excitations(electrons, orbitals, delta_sz)
+
+
+@pytest.mark.parametrize(
+ ("singles", "doubles", "wires", "singles_wires_exp", "doubles_wires_exp"),
+ [
+ ([[0, 2]], [], None, [[0, 1, 2]], []),
+ ([], [[0, 1, 2, 3]], None, [], [[[0, 1], [2, 3]]]),
+ ([[0, 1]], [[0, 1, 2, 4]], None, [[0, 1]], [[[0, 1], [2, 3, 4]]]),
+ (
+ [[0, 1], [2, 4]],
+ [[0, 1, 2, 3], [0, 2, 4, 6]],
+ None,
+ [[0, 1], [2, 3, 4]],
+ [[[0, 1], [2, 3]], [[0, 1, 2], [4, 5, 6]]],
+ ),
+ (
+ [[0, 1], [2, 4]],
+ [[0, 1, 2, 3], [0, 2, 4, 6]],
+ ["a0", "b1", "c2", "d3", "e4", "f5", "g6"],
+ [["a0", "b1"], ["c2", "d3", "e4"]],
+ [[["a0", "b1"], ["c2", "d3"]], [["a0", "b1", "c2"], ["e4", "f5", "g6"]]],
+ ),
+ ],
+)
+def test_mapping_from_excitations_to_wires(
+ singles, doubles, wires, singles_wires_exp, doubles_wires_exp
+):
+ r"""Test the correctness of the mapping between indices of the single and double
+ excitations and the list of wires to be passed to the quantum circuit"""
+
+ singles_wires, doubles_wires = qchem.excitations_to_wires(singles, doubles, wires=wires)
+
+ assert len(singles_wires) == len(singles_wires_exp)
+ assert len(doubles_wires) == len(doubles_wires_exp)
+ assert singles_wires == singles_wires_exp
+ assert doubles_wires == doubles_wires_exp
+
+
+@pytest.mark.parametrize(
+ ("singles", "doubles", "wires", "message_match"),
+ [
+ ([], [], None, "'singles' and 'doubles' lists can not be both empty"),
+ ([[0, 2, 3]], [], None, "Expected entries of 'singles' to be of shape"),
+ ([[0, 2], [3]], [], None, "Expected entries of 'singles' to be of shape"),
+ ([], [[0, 1, 2, 3], [1, 3]], None, "Expected entries of 'doubles' to be of shape"),
+ ([], [[0, 1, 2, 3], [1, 3, 4, 5, 6]], None, "Expected entries of 'doubles' to be of shape"),
+ (
+ [[0, 2]],
+ [[0, 1, 2, 3], [0, 2, 4, 6]],
+ ["a0", "b1", "c2", "d3", "e4", "f5"],
+ "Expected number of wires is",
+ ),
+ ],
+)
+def test_excitations_to_wires_exceptions(singles, doubles, wires, message_match):
+ r"""Test that the function 'excitations_to_wires()' throws an exception if ``singles``,
+ ``doubles`` or ``wires`` parameter has illegal shapes or size"""
+
+ with pytest.raises(ValueError, match=message_match):
+ qchem.excitations_to_wires(singles, doubles, wires=wires)
+
+
+@pytest.mark.parametrize(
+ ("weights", "singles", "doubles", "expected"),
+ [
+ (
+ np.array([3.90575761, -1.89772083, -1.36689032]),
+ [[0, 2], [1, 3]],
+ [[0, 1, 2, 3]],
+ [-0.14619406, -0.06502792, 0.14619406, 0.06502792],
+ )
+ ],
+)
+def test_excitation_integration_with_uccsd(weights, singles, doubles, expected):
+ """Test integration with the UCCSD template"""
+
+ s_wires, d_wires = qchem.excitations_to_wires(singles, doubles)
+ N = 4
+ wires = range(N)
+ dev = qml.device("default.qubit", wires=N)
+
+ @qml.qnode(dev)
+ def circuit(weights):
+ UCCSD(weights, wires, s_wires=s_wires, d_wires=d_wires, init_state=np.array([1, 1, 0, 0]))
+ return [qml.expval(qml.PauliZ(w)) for w in range(N)]
+
+ res = circuit(weights)
+ assert np.allclose(res, np.array(expected))
+
+
+@pytest.mark.parametrize(
+ ("electrons", "orbitals", "exp_state"),
+ [
+ (2, 5, np.array([1, 1, 0, 0, 0])),
+ (1, 5, np.array([1, 0, 0, 0, 0])),
+ (5, 5, np.array([1, 1, 1, 1, 1])),
+ ],
+)
+def test_hf_state(electrons, orbitals, exp_state):
+ r"""Test the correctness of the generated occupation-number vector"""
+
+ res_state = qchem.hf_state(electrons, orbitals)
+
+ assert len(res_state) == len(exp_state)
+ assert np.allclose(res_state, exp_state)
+
+
+@pytest.mark.parametrize(
+ ("electrons", "orbitals", "msg_match"),
+ [
+ (0, 5, "number of active electrons has to be larger than zero"),
+ (-1, 5, "number of active electrons has to be larger than zero"),
+ (6, 5, "number of active orbitals cannot be smaller than the number of active"),
+ ],
+)
+def test__hf_state_inconsistent_input(electrons, orbitals, msg_match):
+ r"""Test that an error is raised if a set of inconsistent arguments is input"""
+
+ with pytest.raises(ValueError, match=msg_match):
+ qchem.hf_state(electrons, orbitals)
+
+
+@pytest.mark.parametrize(
+ (
+ "n_electrons",
+ "n_orbitals",
+ "multiplicity",
+ "act_electrons",
+ "act_orbitals",
+ "core_ref",
+ "active_ref",
+ ),
+ [
+ (4, 6, 1, None, None, [], list(range(6))),
+ (4, 6, 1, 4, None, [], list(range(6))),
+ (4, 6, 1, 2, None, [0], list(range(1, 6))),
+ (4, 6, 1, None, 4, [], list(range(4))),
+ (4, 6, 1, 2, 3, [0], list(range(1, 4))),
+ (5, 6, 2, 3, 4, [0], list(range(1, 5))),
+ (5, 6, 2, 1, 4, [0, 1], list(range(2, 6))),
+ ],
+)
+def test_active_spaces(
+ n_electrons, n_orbitals, multiplicity, act_electrons, act_orbitals, core_ref, active_ref
+):
+ r"""Test the correctness of the generated active spaces"""
+
+ core, active = qchem.active_space(
+ n_electrons,
+ n_orbitals,
+ mult=multiplicity,
+ active_electrons=act_electrons,
+ active_orbitals=act_orbitals,
+ )
+
+ assert core == core_ref
+ assert active == active_ref
+
+
+@pytest.mark.parametrize(
+ ("n_electrons", "n_orbitals", "multiplicity", "act_electrons", "act_orbitals", "message_match"),
+ [
+ (4, 6, 1, 6, 5, "greater than the total number of electrons"),
+ (4, 6, 1, 1, 5, "should be even"),
+ (4, 6, 1, -1, 5, "has to be greater than 0."),
+ (4, 6, 1, 2, 6, "greater than the total number of orbitals"),
+ (4, 6, 1, 2, 1, "there are no virtual orbitals"),
+ (5, 6, 2, 2, 5, "should be odd"),
+ (5, 6, 2, 3, -2, "has to be greater than 0."),
+ (5, 6, 2, 3, 6, "greater than the total number of orbitals"),
+ (5, 6, 2, 3, 2, "there are no virtual orbitals"),
+ (6, 6, 3, 1, 2, "greater than or equal to"),
+ ],
+)
+def test_inconsistent_active_spaces(
+ n_electrons, n_orbitals, multiplicity, act_electrons, act_orbitals, message_match
+):
+ r"""Test that an error is raised if an inconsistent active space is generated"""
+
+ with pytest.raises(ValueError, match=message_match):
+ qchem.active_space(
+ n_electrons,
+ n_orbitals,
+ mult=multiplicity,
+ active_electrons=act_electrons,
+ active_orbitals=act_orbitals,
+ )
diff --git a/tests/qchem/hf_tests/test_tapering.py b/tests/qchem/test_tapering.py
similarity index 100%
rename from tests/qchem/hf_tests/test_tapering.py
rename to tests/qchem/test_tapering.py