Repository: PennyLaneAI/pennylane

Issue:
[BUG] `qml.hf.transform_hf()` fails for some molecules 
### Expected behavior

Running `qml.hf.transform_hf()` should return the tapered Hartree Fock state
```
>>> symbols = ["H", "H", "H", "H"]
>>> geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1], [0.0, 0.0, 2], [0.0, 0.0, 3]])
>>> mol = qml.hf.Molecule(symbols, geometry, charge=0, mult=1)
>>> H = qml.hf.generate_hamiltonian(mol)(geometry)
>>> generators, paulix_ops = qml.hf.generate_symmetries(H, len(H.wires))
>>> opt_sector = qml.hf.optimal_sector(H, generators, mol.n_electrons)
>>> hf_tapered = transform_hf(generators, paulix_ops, opt_sector, n_elec, n_qubits)
>>> hf_tapered
tensor([1, 1, 1, 1, 0], requires_grad=True)
```

### Actual behavior

Running `qml.hf.transform_hf()` leads to `IndexError`.
```
>>> symbols = ["H", "H", "H", "H"]
>>> geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1], [0.0, 0.0, 2], [0.0, 0.0, 3]])
>>> mol = qml.hf.Molecule(symbols, geometry, charge=0, mult=1)
>>> H = qml.hf.generate_hamiltonian(mol)(geometry)
>>> generators, paulix_ops = qml.hf.generate_symmetries(H, len(H.wires))
>>> opt_sector = qml.hf.optimal_sector(H, generators, mol.n_electrons)
>>> hf_tapered = transform_hf(generators, paulix_ops, opt_sector, n_elec, n_qubits)
IndexError: string index out of range
```

### Additional information

Pointed out by a user on the [discussion forum](https://discuss.pennylane.ai/t/problem-with-tapering/1818).

### Source code

_No response_

### Tracebacks

```shell
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
     42         for i in range(len(h.terms()[0])):
     43             s = qml.grouping.pauli_word_to_string(h.terms()[1][i], wire_map=wiremap)
---> 44             if s[w] == "X":
     45                 val[i] *= paulix_sector[idx]
     46
```


### System information

```shell
Name: PennyLane
Version: 0.22.0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/XanaduAI/pennylane
Author: None
Author-email: None
License: Apache License 2.0
Location: /home/whatsis/Xanadu/pl/lib/python3.8/site-packages
Requires: autoray, appdirs, networkx, retworkx, cachetools, autograd, numpy, semantic-version, scipy, toml, pennylane-lightning
Required-by: PennyLane-SF, pennylane-qulacs, PennyLane-qiskit, PennyLane-Qchem, PennyLane-Lightning, PennyLane-Cirq
Platform info:           Linux-5.4.0-107-generic-x86_64-with-glibc2.29
Python version:          3.8.10
Numpy version:           1.21.2
Scipy version:           1.7.1
Installed devices:
- default.gaussian (PennyLane-0.22.0)
- default.mixed (PennyLane-0.22.0)
- default.qubit (PennyLane-0.22.0)
- default.qubit.autograd (PennyLane-0.22.0)
- default.qubit.jax (PennyLane-0.22.0)
- default.qubit.tf (PennyLane-0.22.0)
- default.qubit.torch (PennyLane-0.22.0)
- strawberryfields.fock (PennyLane-SF-0.20.0)
- strawberryfields.gaussian (PennyLane-SF-0.20.0)
- strawberryfields.gbs (PennyLane-SF-0.20.0)
- strawberryfields.remote (PennyLane-SF-0.20.0)
- strawberryfields.tf (PennyLane-SF-0.20.0)
- qulacs.simulator (pennylane-qulacs-0.16.0)
- qiskit.aer (PennyLane-qiskit-0.22.0)
- qiskit.basicaer (PennyLane-qiskit-0.22.0)
- qiskit.ibmq (PennyLane-qiskit-0.22.0)
- qiskit.ibmq.circuit_runner (PennyLane-qiskit-0.22.0)
- qiskit.ibmq.sampler (PennyLane-qiskit-0.22.0)
- lightning.qubit (PennyLane-Lightning-0.22.0)
- cirq.mixedsimulator (PennyLane-Cirq-0.22.0)
- cirq.pasqal (PennyLane-Cirq-0.22.0)
- cirq.qsim (PennyLane-Cirq-0.22.0)
- cirq.qsimh (PennyLane-Cirq-0.22.0)
- cirq.simulator (PennyLane-Cirq-0.22.0)
```


### Existing GitHub issues

- [X] I have searched existing GitHub issues to make sure the issue does not already exist.


Discussion:

Resolving patch:
diff --git a/pennylane/hf/tapering.py b/pennylane/hf/tapering.py
--- a/pennylane/hf/tapering.py
+++ b/pennylane/hf/tapering.py
@@ -23,6 +23,7 @@
 import pennylane as qml
 from pennylane import numpy as np
 from pennylane.hf.hamiltonian import _generate_qubit_operator, simplify
+from pennylane.wires import Wires
 
 
 def _binary_matrix(terms, num_qubits, wire_map=None):
@@ -407,7 +408,8 @@ def transform_hamiltonian(h, generators, paulix_ops, paulix_sector):
 
     val = np.ones(len(h.terms()[0])) * complex(1.0)
 
-    wiremap = dict(zip(h.wires, range(len(h.wires) + 1)))
+    wireset = u.wires + h.wires
+    wiremap = dict(zip(wireset, range(len(wireset) + 1)))
     paulix_wires = [x.wires[0] for x in paulix_ops]
     for idx, w in enumerate(paulix_wires):
         for i in range(len(h.terms()[0])):
@@ -558,6 +560,11 @@ def transform_hf(generators, paulix_ops, paulix_sector, num_electrons, num_wires
     fermop_taper = transform_hamiltonian(ferm_op, generators, paulix_ops, paulix_sector)
     fermop_mat = _binary_matrix(fermop_taper.ops, len(fermop_taper.wires))
 
+    # build a wireset to match wires with that of the tapered Hamiltonian
+    gen_wires = Wires.all_wires([generator.wires for generator in generators])
+    xop_wires = Wires.all_wires([paulix_op.wires for paulix_op in paulix_ops])
+    wireset = Wires.unique_wires([gen_wires, xop_wires])
+
     # iterate over the terms in tapered HF observable and build the tapered HF state
     tapered_hartree_fock = []
     for col in fermop_mat.T[fermop_mat.shape[1] // 2 :]:
@@ -565,5 +572,7 @@ def transform_hf(generators, paulix_ops, paulix_sector, num_electrons, num_wires
             tapered_hartree_fock.append(1)
         else:
             tapered_hartree_fock.append(0)
+    while len(tapered_hartree_fock) < len(wireset):
+        tapered_hartree_fock.append(0)
 
     return np.array(tapered_hartree_fock).astype(int)


Test patch:
diff --git a/tests/hf/test_tapering_hf.py b/tests/hf/test_tapering_hf.py
--- a/tests/hf/test_tapering_hf.py
+++ b/tests/hf/test_tapering_hf.py
@@ -610,6 +610,14 @@ def test_transform_hf(generators, paulix_ops, paulix_sector, num_electrons, num_
             ),
             1,
         ),
+        (
+            ["H", "H", "H", "H"],
+            np.array(
+                [[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], [0.0, 0.0, 2.0], [0.0, 0.0, 3.0]],
+                requires_grad=True,
+            ),
+            0,
+        ),
     ],
 )
 def test_hf_energy(symbols, geometry, charge):