Repository: PennyLaneAI/pennylane
Pull request #4928 (2023-12-07 23:52:28)

Added parity transformation for issue #4881
### Before submitting

Please complete the following checklist when submitting a PR:

When all the above are checked, delete everything above the dashed
line and fill in the pull request template.

------------------------------------------------------------------------------------------------------------

**Context:** 
Parity transform is added to map fermionic operators to qubit operators.

**Description of the Change:** 

**Benefits:** 

**Possible Drawbacks:**

**Related GitHub Issues:**


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4928?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`dcd1201`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/dcd120100872f594817268cb62e4af224008bde1?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) 99.66% compared to head [(`1e4e816`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4928?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) 99.66%.


<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff            @@
##           master    #4928    +/-   ##
========================================
  Coverage   99.66%   99.66%            
========================================
  Files         388      388            
  Lines       35285    35065   -220     
========================================
- Hits        35166    34947   -219     
+ Misses        119      118     -1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4928?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).


Patch:
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 4e81fcef0..94167d189 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -17,7 +17,6 @@
   import pennylane as qml
 
   dev = qml.device("default.clifford", tableau=True)
-
   @qml.qnode(dev)
   def circuit():
       qml.CNOT(wires=[0, 1])
@@ -70,6 +69,26 @@
   + 2j * X(0) @ Z(1)
   ```
 
+
+<h4>Parity Mapping</h4>
+
+* `parity_transform` is added for parity mapping of a fermionic Hamiltonian.
+   [(#4928)](https://github.com/PennyLaneAI/pennylane/pull/4928)
+   It is now possible to transform a fermionic Hamiltonian to a qubit Hamiltonian with parity mapping.
+
+   ```python
+   import pennylane as qml
+   fermi_ham = qml.fermi.FermiWord({(0, 0) : '+', (1, 1) : '-'})
+
+   qubit_ham = qml.fermi.parity_transform(fermi_ham, n=6)
+   ```
+
+   ```pycon
+   >>> print(qubit_ham)
+   (-0.25j*(PauliY(wires=[0]))) + ((-0.25+0j)*(PauliX(wires=[0]) @ PauliZ(wires=[1]))) +
+   ((0.25+0j)*(PauliX(wires=[0]))) + (0.25j*(PauliY(wires=[0]) @ PauliZ(wires=[1])))
+   ```
+
 <h3>Improvements 🛠</h3>
 
 * Remove queuing (`AnnotatedQueue`) from `qml.cut_circuit` and `qml.cut_circuit_mc` to improve performance 
@@ -284,6 +303,7 @@ Utkarsh Azad,
 Gabriel Bottrill,
 Astral Cai,
 Isaac De Vlugt,
+Diksha Dhawan,
 Diego Guala,
 Korbinian Kottmann,
 Christina Lee,
@@ -294,5 +314,6 @@ Pablo Antonio Moreno Casares,
 Lee J. O'Riordan,
 Mudit Pandey,
 Alex Preciado,
-Matthew Silverman.
-Jay Soni,
+Matthew Silverman,
+Jay Soni.
+
diff --git a/pennylane/fermi/__init__.py b/pennylane/fermi/__init__.py
index 29db3e711..08e4c07e0 100644
--- a/pennylane/fermi/__init__.py
+++ b/pennylane/fermi/__init__.py
@@ -15,5 +15,5 @@
 fermionic operators. """
 
 
-from .conversion import jordan_wigner
+from .conversion import jordan_wigner, parity_transform
 from .fermionic import FermiWord, FermiC, FermiA, FermiSentence, from_string
diff --git a/pennylane/fermi/conversion.py b/pennylane/fermi/conversion.py
index e0284ccde..297336f0c 100644
--- a/pennylane/fermi/conversion.py
+++ b/pennylane/fermi/conversion.py
@@ -15,6 +15,7 @@
 
 from functools import singledispatch
 from typing import Union
+import warnings
 
 import pennylane as qml
 from pennylane.operation import Operator
@@ -52,7 +53,7 @@ def jordan_wigner(
         fermi_operator(FermiWord, FermiSentence): the fermionic operator
         ps (bool): whether to return the result as a PauliSentence instead of an
             Operator. Defaults to False.
-        wire_map (dict): a dictionary defining how to map the oribitals of
+        wire_map (dict): a dictionary defining how to map the orbitals of
             the Fermi operator to qubit wires. If None, the integers used to
             order the orbitals will be used as wire labels. Defaults to None.
         tol (float): tolerance for discarding the imaginary part of the coefficients
@@ -148,3 +149,144 @@ def _(fermi_operator: FermiSentence, ps=False, wire_map=None, tol=None):
         return qubit_operator.map_wires(wire_map)
 
     return qubit_operator
+
+
+def parity_transform(
+    fermi_operator: (Union[FermiWord, FermiSentence]),
+    n: int,
+    ps: bool = False,
+    wire_map: dict = None,
+    tol: float = None,
+) -> Union[Operator, PauliSentence]:
+    r"""Convert a fermionic operator to a qubit operator using the parity mapping.
+
+    In parity mapping, qubit :math:`j` stores the parity of all :math:`j-1` qubits before it.
+    In comparison, :func:`~.jordan_wigner` simply uses qubit :math:`j` to store the occupation number.
+    In parity mapping, the fermionic creation and annihilation operators are mapped to the Pauli operators as
+
+    .. math::
+        \begin{align*}
+           a^{\dagger}_0 &= \left (\frac{X_0 - iY_0}{2}  \right )\otimes X_1 \otimes X_2 \otimes ... X_n, \\\\
+           a^{\dagger}_n &= \left (\frac{Z_{n-1} \otimes X_n - iY_n}{2} \right ) \otimes X_{n+1} \otimes X_{n+2} \otimes ... \otimes X_n
+        \end{align*}
+
+    and
+
+    .. math::
+        \begin{align*}
+           a_0 &= \left (\frac{X_0 + iY_0}{2}  \right )\otimes X_1 \otimes X_2 \otimes ... X_n,\\\\
+           a_n &= \left (\frac{Z_{n-1} \otimes X_n + iY_n}{2} \right ) \otimes X_{n+1} \otimes X_{n+2} \otimes ... \otimes X_n
+        \end{align*}
+
+    where :math:`X`, :math:`Y`, and :math:`Z` are the Pauli operators and :math:`n` is the number of qubits, i.e., spin orbitals.
+
+    Args:
+        fermi_operator(FermiWord, FermiSentence): the fermionic operator
+        n (int): number of qubits, i.e., spin orbitals in the system
+        ps (bool): whether to return the result as a :class:`~.PauliSentence` instead of an
+            :class:`~.Operator`. Defaults to ``False``.
+        wire_map (dict): a dictionary defining how to map the orbitals of
+            the Fermi operator to qubit wires. If ``None``, the integers used to
+            order the orbitals will be used as wire labels. Defaults to ``None``.
+        tol (float): tolerance for discarding the imaginary part of the coefficients
+
+    Returns:
+        Union[PauliSentence, Operator]: a linear combination of qubit operators
+
+    **Example**
+
+    >>> w = FermiWord({(0, 0) : '+', (1, 1) : '-'})
+    >>> parity_transform(w, n=6)
+    (-0.25j*(PauliY(wires=[0]))) + ((-0.25+0j)*(PauliX(wires=[0]) @ PauliZ(wires=[1]))) +
+    ((0.25+0j)*(PauliX(wires=[0]))) + (0.25j*(PauliY(wires=[0]) @ PauliZ(wires=[1])))
+
+    >>> parity_transform(w, n=6, ps=True)
+    -0.25j * Y(0)
+    + (-0.25+0j) * X(0) @ Z(1)
+    + (0.25+0j) * X(0)
+    + 0.25j * Y(0) @ Z(1)
+
+    >>> parity_transform(w, n=6, ps=True, wire_map={0: 2, 1: 3})
+    -0.25j * Y(2)
+    + (-0.25+0j) * X(2) @ Z(3)
+    + (0.25+0j) * X(2)
+    + 0.25j * Y(2) @ Z(3)
+    """
+    warnings.warn(
+        "This mapping should be used with operators and states in the parity basis.", UserWarning
+    )
+
+    return _parity_transform_dispatch(fermi_operator, n, ps, wire_map, tol)
+
+
+@singledispatch
+def _parity_transform_dispatch(fermi_operator, n, ps, wire_map, tol):
+    """Dispatches to appropriate function if fermi_operator is a FermiWord or FermiSentence."""
+    raise ValueError(f"fermi_operator must be a FermiWord or FermiSentence, got: {fermi_operator}")
+
+
+@_parity_transform_dispatch.register
+def _(fermi_operator: FermiWord, n, ps=False, wire_map=None, tol=None):
+    wires = list(fermi_operator.wires) or [0]
+    identity_wire = wires[0]
+
+    coeffs = {"+": -0.5j, "-": 0.5j}
+    qubit_operator = PauliSentence({PauliWord({}): 1.0})  # Identity PS to multiply PSs with
+
+    for item in fermi_operator.items():
+        (_, wire), sign = item
+        if wire >= n:
+            raise ValueError(
+                f"Can't create or annihilate a particle on qubit number {wire} for a system with only {n} qubits"
+            )
+
+        x_string = dict(zip(range(wire + 1, n), ["X"] * (n - wire)))
+
+        pw1 = (
+            PauliWord({**{wire: "X"}, **x_string})
+            if wire == 0
+            else PauliWord({**{wire - 1: "Z"}, **{wire: "X"}, **x_string})
+        )
+        pw2 = PauliWord({**{wire: "Y"}, **x_string})
+
+        qubit_operator *= PauliSentence({pw1: 0.5, pw2: coeffs[sign]})
+
+    for pw in qubit_operator:
+        if tol is not None and abs(qml.math.imag(qubit_operator[pw])) <= tol:
+            qubit_operator[pw] = qml.math.real(qubit_operator[pw])
+
+    if not ps:
+        # wire_order specifies wires to use for Identity (PauliWord({}))
+        qubit_operator = qubit_operator.operation(wire_order=[identity_wire])
+
+    if wire_map:
+        return qubit_operator.map_wires(wire_map)
+
+    return qubit_operator
+
+
+@_parity_transform_dispatch.register
+def _(fermi_operator: FermiSentence, n, ps=False, wire_map=None, tol=None):
+    wires = list(fermi_operator.wires) or [0]
+    identity_wire = wires[0]
+
+    qubit_operator = PauliSentence()  # Empty PS as 0 operator to add Pws to
+
+    for fw, coeff in fermi_operator.items():
+        fermi_word_as_ps = parity_transform(fw, n, ps=True)
+
+        for pw in fermi_word_as_ps:
+            qubit_operator[pw] += fermi_word_as_ps[pw] * coeff
+
+            if tol is not None and abs(qml.math.imag(qubit_operator[pw])) <= tol:
+                qubit_operator[pw] = qml.math.real(qubit_operator[pw])
+
+    qubit_operator.simplify(tol=1e-16)
+
+    if not ps:
+        qubit_operator = qubit_operator.operation(wire_order=[identity_wire])
+
+    if wire_map:
+        return qubit_operator.map_wires(wire_map)
+
+    return qubit_operator


Test patch:
diff --git a/tests/fermi/test_parity_mapping.py b/tests/fermi/test_parity_mapping.py
new file mode 100644
index 000000000..b4b94d52b
--- /dev/null
+++ b/tests/fermi/test_parity_mapping.py
@@ -0,0 +1,772 @@
+"""Unit testing of conversion functions for parity transform"""
+import pytest
+
+import pennylane as qml
+from pennylane.ops import SProd, Identity
+from pennylane.pauli.conversion import pauli_sentence
+from pennylane.fermi.conversion import parity_transform
+from pennylane.pauli import PauliWord, PauliSentence
+from pennylane.fermi.fermionic import FermiWord, FermiSentence
+
+
+def test_error_is_raised_for_incompatible_type():
+    """Test that an error is raised in the input is not a FermiWord or FermiSentence"""
+    with pytest.raises(ValueError, match="fermi_operator must be a FermiWord or FermiSentence"):
+        parity_transform(qml.PauliX(0), 10)
+
+
+def test_error_is_raised_for_dimension_mismatch():
+    """Test that an error is raised if the number of qubits are not compatible with the FermiWord or FermiSentence"""
+
+    with pytest.raises(
+        ValueError,
+        match="Can't create or annihilate a particle on qubit number 6 for a system with only 6 qubits",
+    ):
+        parity_transform(FermiWord({(0, 1): "-", (1, 0): "+", (2, 6): "-"}), 6)
+
+
+def test_warning_is_raised_with_use():
+    """Test that a UserWarning is raised when this mapping is used"""
+
+    with pytest.warns(
+        UserWarning,
+        match="This mapping should be used with operators and states in the parity basis.",
+    ):
+        parity_transform(FermiWord({(0, 1): "-", (1, 0): "+", (2, 2): "-"}), 4)
+
+
+FERMI_WORDS_AND_OPS = [
+    (
+        FermiWord({(0, 0): "+"}),
+        1,
+        # trivial case of a creation operator with one qubit, 0^ -> (X_0 - iY_0) / 2 : Same as Jordan-Wigner
+        ([0.5, -0.5j], [qml.PauliX(0), qml.PauliY(0)]),
+    ),
+    (
+        FermiWord({(0, 0): "-"}),
+        1,
+        # trivial case of an annihilation operator with one qubit , 0 -> (X_0 + iY_0) / 2 : Same as Jordan-Wigner
+        ([(0.5 + 0j), (0.0 + 0.5j)], [qml.PauliX(0), qml.PauliY(0)]),
+    ),
+    (
+        FermiWord({(0, 0): "+"}),
+        2,
+        # trivial case of a creation operator with two qubits, 0^ -> (X_0 @ X_1 - iY_0 @ X_1) / 2
+        ([0.5, -0.5j], [qml.PauliX(0) @ qml.PauliX(1), qml.PauliY(0) @ qml.PauliX(1)]),
+    ),
+    (
+        FermiWord({(0, 0): "-"}),
+        2,
+        # trivial case of an annihilation operator with two qubits , 0 -> (X_0 @ X_1 + iY_0 @ X_1) / 2
+        (
+            [(0.5 + 0j), (0.0 + 0.5j)],
+            [qml.PauliX(0) @ qml.PauliX(1), qml.PauliY(0) @ qml.PauliX(1)],
+        ),
+    ),
+    (
+        FermiWord({(0, 0): "+", (1, 0): "-"}),
+        4,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('0^ 0'), parity_code(n_qubits)) for n_qubits = 4
+        # reformatted the original openfermion output: (0.5+0j) [] + (-0.5+0j) [Z0]
+        ([(0.5 + 0j), (-0.5 + 0j)], [qml.Identity(0), qml.PauliZ(0)]),
+    ),
+    (
+        FermiWord({(0, 0): "-", (1, 0): "+"}),
+        4,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('0 0^'), parity_code(n_qubits)) for n_qubits = 4
+        # reformatted the original openfermion output: (0.5+0j) [] + (0.5+0j) [Z0]
+        ([(0.5 + 0j), (0.5 + 0j)], [qml.Identity(0), qml.PauliZ(0)]),
+    ),
+    (
+        FermiWord({(0, 0): "-", (1, 1): "+"}),
+        4,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('0 1^'), parity_code(n_qubits)) for n_qubits = 4
+        # reformatted the original openfermion output:
+        # (-0.25+0j) [X0] +
+        # 0.25 [X0 Z1] +
+        # (-0-0.25j) [Y0] +
+        # 0.25j [Y0 Z1]
+        (
+            [(-0.25 + 0j), 0.25, (-0 - 0.25j), (0.25j)],
+            [
+                qml.PauliX(0),
+                qml.PauliX(0) @ qml.PauliZ(1),
+                qml.PauliY(0),
+                qml.PauliY(0) @ qml.PauliZ(1),
+            ],
+        ),
+    ),
+    (
+        FermiWord({(0, 3): "+", (1, 0): "-"}),
+        4,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('3^ 0'), parity_code(n_qubits)) for n_qubits = 4
+        # reformatted the original openfermion output
+        #  -0.25 [X0 X1 X2 Z3] +
+        #  0.25j [X0 X1 Y2] +
+        #  (-0-0.25j) [Y0 X1 X2 Z3] +
+        #   -0.25 [Y0 X1 Y2]
+        (
+            [(-0.25 + 0j), 0.25j, (-0 - 0.25j), -0.25],
+            [
+                qml.PauliX(0) @ qml.PauliX(1) @ qml.PauliX(2) @ qml.PauliZ(3),
+                qml.PauliX(0) @ qml.PauliX(1) @ qml.PauliY(2),
+                qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliX(2) @ qml.PauliZ(3),
+                qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliY(2),
+            ],
+        ),
+    ),
+    (
+        FermiWord({(0, 5): "+", (1, 5): "-", (2, 5): "+", (3, 5): "-"}),
+        6,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('5^ 5 5^ 5'), parity_code(n_qubits)) with 6 qubits
+        (
+            [(0.5 + 0j), (-0.5 + 0j)],
+            [qml.Identity(0), qml.PauliZ(4) @ qml.PauliZ(5)],
+        ),
+    ),
+    (
+        FermiWord({(0, 3): "+", (1, 3): "-", (2, 3): "+", (3, 1): "-"}),
+        6,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('3^ 3 3^ 1'), parity_code(n_qubits)) with 6 qubits
+        # -0.25 [Z0 X1 X2 Z3] +
+        # 0.25j [Z0 X1 Y2] +
+        # (-0-0.25j) [Y1 X2 Z3] +
+        # -0.25 [Y1 Y2]
+        (
+            [-0.25, 0.25j, -0.25j, -0.25],
+            [
+                qml.PauliZ(0) @ qml.PauliX(1) @ qml.PauliX(2) @ qml.PauliZ(3),
+                qml.PauliZ(0) @ qml.PauliX(1) @ qml.PauliY(2),
+                qml.PauliY(1) @ qml.PauliX(2) @ qml.PauliZ(3),
+                qml.PauliY(1) @ qml.PauliY(2),
+            ],
+        ),
+    ),
+    (
+        FermiWord({(0, 1): "+", (1, 0): "-", (2, 1): "+", (3, 1): "-"}),
+        6,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('1^ 0 1^ 1'), parity_code(n_qubits)) with 6 qubits
+        ([0], [qml.Identity(0)]),
+    ),
+]
+
+FERMI_OPS_COMPLEX = [
+    (
+        FermiWord({(0, 2): "-", (1, 0): "+", (2, 3): "+"}),
+        4,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('2 0^ 3^'), parity_code(n_qubits)) for n_qubits = 4
+        # reformatted the original openfermion output
+        # (-0-0.125j) [X0 X1 Z2 Y3] +
+        # 0.125 [X0 X1 X3] +
+        # 0.125j [X0 Y1 Z2 X3] +
+        # 0.125 [X0 Y1 Y3] +
+        # -0.125 [Y0 X1 Z2 Y3] +
+        # (-0-0.125j) [Y0 X1 X3] +
+        # 0.125 [Y0 Y1 Z2 X3] +
+        # (-0-0.125j) [Y0 Y1 Y3]
+        (
+            [(-0 - 0.125j), 0.125, 0.125j, 0.125, -0.125, -0.125j, 0.125, -0.125j],
+            [
+                qml.PauliX(0) @ qml.PauliX(1) @ qml.PauliZ(2) @ qml.PauliY(3),
+                qml.PauliX(0) @ qml.PauliX(1) @ qml.PauliX(3),
+                qml.PauliX(0) @ qml.PauliY(1) @ qml.PauliZ(2) @ qml.PauliX(3),
+                qml.PauliX(0) @ qml.PauliY(1) @ qml.PauliY(3),
+                qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliZ(2) @ qml.PauliY(3),
+                qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliX(3),
+                qml.PauliY(0) @ qml.PauliY(1) @ qml.PauliZ(2) @ qml.PauliX(3),
+                qml.PauliY(0) @ qml.PauliY(1) @ qml.PauliY(3),
+            ],
+        ),
+    ),
+    (
+        FermiWord({(0, 0): "-", (1, 3): "+"}),
+        4,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('0 3^'), parity_code(n_qubits)) for n_qubits = 4
+        # reformatted the original openfermion output
+        # 0.25 [X0 X1 X2 Z3] +
+        # (-0-0.25j) [X0 X1 Y2] +
+        # 0.25j [Y0 X1 X2 Z3] +
+        # 0.25 [Y0 X1 Y2]
+        (
+            [0.25, -0.25j, 0.25j, 0.25],
+            [
+                qml.PauliX(0) @ qml.PauliX(1) @ qml.PauliX(2) @ qml.PauliZ(3),
+                qml.PauliX(0) @ qml.PauliX(1) @ qml.PauliY(2),
+                qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliX(2) @ qml.PauliZ(3),
+                qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliY(2),
+            ],
+        ),
+    ),
+    (
+        FermiWord({(0, 3): "+", (1, 1): "+", (2, 3): "-", (3, 1): "-"}),
+        6,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('3^ 1^ 3 1'), parity_code(n_qubits)) with 6 qubits
+        # -0.25 [] +
+        # 0.25 [Z0 Z1] +
+        # -0.25 [Z0 Z1 Z2 Z3] +
+        # 0.25 [Z2 Z3]
+        # reformatted the original openfermion output
+        (
+            [(-0.25 + 0j), (0.25 + 0j), (-0.25 + 0j), (0.25 + 0j)],
+            [
+                qml.Identity(0),
+                qml.PauliZ(0) @ qml.PauliZ(1),
+                qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliZ(2) @ qml.PauliZ(3),
+                qml.PauliZ(2) @ qml.PauliZ(3),
+            ],
+        ),
+    ),
+    (
+        FermiWord({(0, 1): "+", (1, 4): "-", (2, 3): "-", (3, 4): "+"}),
+        6,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('1^ 4 3 4^'), parity_code(n_qubits)) with 6 qubits
+        # reformatted the original openfermion output
+        # 0.125 [Z0 X1 X2 Z3] +
+        # 0.125 [Z0 X1 X2 Z4] +
+        # 0.125j [Z0 X1 Y2] +
+        # 0.125j [Z0 X1 Y2 Z3 Z4] +
+        # (-0-0.125j) [Y1 X2 Z3] +
+        # (-0-0.125j) [Y1 X2 Z4] +
+        # 0.125 [Y1 Y2] +
+        # 0.125 [Y1 Y2 Z3 Z4]
+        (
+            [0.125, 0.125, 0.125j, 0.125j, -0.125j, -0.125j, 0.125, 0.125],
+            [
+                qml.PauliZ(0) @ qml.PauliX(1) @ qml.PauliX(2) @ qml.PauliZ(3),
+                qml.PauliZ(0) @ qml.PauliX(1) @ qml.PauliX(2) @ qml.PauliZ(4),
+                qml.PauliZ(0) @ qml.PauliX(1) @ qml.PauliY(2),
+                qml.PauliZ(0) @ qml.PauliX(1) @ qml.PauliY(2) @ qml.PauliZ(3) @ qml.PauliZ(4),
+                qml.PauliY(1) @ qml.PauliX(2) @ qml.PauliZ(3),
+                qml.PauliY(1) @ qml.PauliX(2) @ qml.PauliZ(4),
+                qml.PauliY(1) @ qml.PauliY(2),
+                qml.PauliY(1) @ qml.PauliY(2) @ qml.PauliZ(3) @ qml.PauliZ(4),
+            ],
+        ),
+    ),
+    (
+        FermiWord({(0, 3): "+", (1, 1): "-", (2, 3): "+", (3, 1): "-"}),
+        6,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('3^ 1 3^ 1'), parity_code(n_qubits)) with 6 qubits
+        ([0], [qml.Identity(3)]),
+    ),
+    (
+        FermiWord({(0, 1): "+", (1, 0): "+", (2, 4): "-", (3, 5): "-"}),
+        6,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('1^ 0^ 4 5^'), parity_code(n_qubits)) with 6 qubits
+        # 0.0625 [X0 Z1 Z3 X4 Z5] +
+        # 0.0625j [X0 Z1 Z3 Y4] +
+        # 0.0625 [X0 Z1 X4] +
+        # 0.0625j [X0 Z1 Y4 Z5] +
+        # 0.0625 [X0 Z3 X4 Z5] +
+        # 0.0625j [X0 Z3 Y4] +
+        # 0.0625 [X0 X4] +
+        # 0.0625j [X0 Y4 Z5] +
+        # (-0-0.0625j) [Y0 Z1 Z3 X4 Z5] +
+        # 0.0625 [Y0 Z1 Z3 Y4] +
+        # (-0-0.0625j) [Y0 Z1 X4] +
+        # 0.0625 [Y0 Z1 Y4 Z5] +
+        # (-0-0.0625j) [Y0 Z3 X4 Z5] +
+        # 0.0625 [Y0 Z3 Y4] +
+        # (-0-0.0625j) [Y0 X4] +
+        # 0.0625 [Y0 Y4 Z5])
+        (
+            [
+                0.0625,
+                0.0625j,
+                0.0625,
+                0.0625j,
+                0.0625,
+                0.0625j,
+                0.0625,
+                0.0625j,
+                -0.0625j,
+                0.0625,
+                -0.0625j,
+                0.0625,
+                -0.0625j,
+                0.0625,
+                -0.0625j,
+                0.0625,
+            ],
+            [
+                qml.PauliX(0) @ qml.PauliZ(1) @ qml.PauliZ(3) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliX(0) @ qml.PauliZ(1) @ qml.PauliZ(3) @ qml.PauliY(4),
+                qml.PauliX(0) @ qml.PauliZ(1) @ qml.PauliX(4),
+                qml.PauliX(0) @ qml.PauliZ(1) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliX(0) @ qml.PauliZ(3) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliX(0) @ qml.PauliZ(3) @ qml.PauliY(4),
+                qml.PauliX(0) @ qml.PauliX(4),
+                qml.PauliX(0) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliY(0) @ qml.PauliZ(1) @ qml.PauliZ(3) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliY(0) @ qml.PauliZ(1) @ qml.PauliZ(3) @ qml.PauliY(4),
+                qml.PauliY(0) @ qml.PauliZ(1) @ qml.PauliX(4),
+                qml.PauliY(0) @ qml.PauliZ(1) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliY(0) @ qml.PauliZ(3) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliY(0) @ qml.PauliZ(3) @ qml.PauliY(4),
+                qml.PauliY(0) @ qml.PauliX(4),
+                qml.PauliY(0) @ qml.PauliY(4) @ qml.PauliZ(5),
+            ],
+        ),
+    ),
+    (
+        FermiWord({(0, 1): "-", (1, 0): "+"}),
+        4,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('1 0^'), parity_code(n_qubits)) for n_qubits = 4
+        # reformatted the original openfermion output:
+        # -0.25 [X0] +
+        # 0.25 [X0 Z1] +
+        # 0.25j [Y0] +
+        # (-0-0.25j) [Y0 Z1]
+        (
+            [(-0.25 + 0j), 0.25, 0.25j, (-0 - 0.25j)],
+            [
+                qml.PauliX(0),
+                qml.PauliX(0) @ qml.PauliZ(1),
+                qml.PauliY(0),
+                qml.PauliY(0) @ qml.PauliZ(1),
+            ],
+        ),
+    ),
+    (
+        FermiWord({(0, 1): "+", (1, 1): "-", (2, 3): "+", (3, 4): "-", (4, 2): "+", (5, 5): "-"}),
+        6,
+        # obtained with openfermion using: binary_code_transform(FermionOperator('1^ 1 3^ 4 2^ 5'), parity_code(n_qubits)) with 6 qubits
+        # 0.03125 [Z0 Z1 X2 Z3 X4 Z5] +
+        # 0.03125j [Z0 Z1 X2 Z3 Y4] +
+        # 0.03125 [Z0 Z1 X2 X4] +
+        # 0.03125j [Z0 Z1 X2 Y4 Z5] +
+        # (-0-0.03125j) [Z0 Z1 Y2 Z3 X4] +
+        # 0.03125 [Z0 Z1 Y2 Z3 Y4 Z5] +
+        # (-0-0.03125j) [Z0 Z1 Y2 X4 Z5] +
+        # 0.03125 [Z0 Z1 Y2 Y4] +
+        # 0.03125 [Z0 X2 Z3 X4] +
+        # 0.03125j [Z0 X2 Z3 Y4 Z5] +
+        # 0.03125 [Z0 X2 X4 Z5] +
+        # 0.03125j [Z0 X2 Y4] +
+        # (-0-0.03125j) [Z0 Y2 Z3 X4 Z5] +
+        # 0.03125 [Z0 Y2 Z3 Y4] +
+        # (-0-0.03125j) [Z0 Y2 X4] +
+        # 0.03125 [Z0 Y2 Y4 Z5] +
+        # -0.03125 [Z1 X2 Z3 X4] +
+        # (-0-0.03125j) [Z1 X2 Z3 Y4 Z5] +
+        # -0.03125 [Z1 X2 X4 Z5] +
+        # (-0-0.03125j) [Z1 X2 Y4] +
+        # 0.03125j [Z1 Y2 Z3 X4 Z5] +
+        # -0.03125 [Z1 Y2 Z3 Y4] +
+        # 0.03125j [Z1 Y2 X4] +
+        # -0.03125 [Z1 Y2 Y4 Z5] +
+        # -0.03125 [X2 Z3 X4 Z5] +
+        # (-0-0.03125j) [X2 Z3 Y4] +
+        # -0.03125 [X2 X4] +
+        # (-0-0.03125j) [X2 Y4 Z5] +
+        # 0.03125j [Y2 Z3 X4] +
+        # -0.03125 [Y2 Z3 Y4 Z5] +
+        # 0.03125j [Y2 X4 Z5] +
+        # -0.03125 [Y2 Y4]
+        (
+            [
+                0.03125,
+                0.03125j,
+                0.03125,
+                0.03125j,
+                -0.03125j,
+                0.03125,
+                -0.03125j,
+                0.03125,
+                0.03125,
+                0.03125j,
+                0.03125,
+                0.03125j,
+                -0.03125j,
+                0.03125,
+                -0.03125j,
+                0.03125,
+                -0.03125,
+                -0.03125j,
+                -0.03125,
+                -0.03125j,
+                0.03125j,
+                -0.03125,
+                0.03125j,
+                -0.03125,
+                -0.03125,
+                -0.03125j,
+                -0.03125,
+                -0.03125j,
+                0.03125j,
+                -0.03125,
+                0.03125j,
+                -0.03125,
+            ],
+            [
+                qml.PauliZ(0)
+                @ qml.PauliZ(1)
+                @ qml.PauliX(2)
+                @ qml.PauliZ(3)
+                @ qml.PauliX(4)
+                @ qml.PauliZ(5),
+                qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliX(2) @ qml.PauliZ(3) @ qml.PauliY(4),
+                qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliX(2) @ qml.PauliX(4),
+                qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliX(2) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliY(2) @ qml.PauliZ(3) @ qml.PauliX(4),
+                qml.PauliZ(0)
+                @ qml.PauliZ(1)
+                @ qml.PauliY(2)
+                @ qml.PauliZ(3)
+                @ qml.PauliY(4)
+                @ qml.PauliZ(5),
+                qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliY(2) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliY(2) @ qml.PauliY(4),
+                qml.PauliZ(0) @ qml.PauliX(2) @ qml.PauliZ(3) @ qml.PauliX(4),
+                qml.PauliZ(0) @ qml.PauliX(2) @ qml.PauliZ(3) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliZ(0) @ qml.PauliX(2) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliZ(0) @ qml.PauliX(2) @ qml.PauliY(4),
+                qml.PauliZ(0) @ qml.PauliY(2) @ qml.PauliZ(3) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliZ(0) @ qml.PauliY(2) @ qml.PauliZ(3) @ qml.PauliY(4),
+                qml.PauliZ(0) @ qml.PauliY(2) @ qml.PauliX(4),
+                qml.PauliZ(0) @ qml.PauliY(2) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliZ(1) @ qml.PauliX(2) @ qml.PauliZ(3) @ qml.PauliX(4),
+                qml.PauliZ(1) @ qml.PauliX(2) @ qml.PauliZ(3) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliZ(1) @ qml.PauliX(2) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliZ(1) @ qml.PauliX(2) @ qml.PauliY(4),
+                qml.PauliZ(1) @ qml.PauliY(2) @ qml.PauliZ(3) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliZ(1) @ qml.PauliY(2) @ qml.PauliZ(3) @ qml.PauliY(4),
+                qml.PauliZ(1) @ qml.PauliY(2) @ qml.PauliX(4),
+                qml.PauliZ(1) @ qml.PauliY(2) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliX(2) @ qml.PauliZ(3) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliX(2) @ qml.PauliZ(3) @ qml.PauliY(4),
+                qml.PauliX(2) @ qml.PauliX(4),
+                qml.PauliX(2) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliY(2) @ qml.PauliZ(3) @ qml.PauliX(4),
+                qml.PauliY(2) @ qml.PauliZ(3) @ qml.PauliY(4) @ qml.PauliZ(5),
+                qml.PauliY(2) @ qml.PauliX(4) @ qml.PauliZ(5),
+                qml.PauliY(2) @ qml.PauliY(4),
+            ],
+        ),
+    ),
+]
+
+
+@pytest.mark.parametrize("fermionic_op, n_qubits, result", FERMI_WORDS_AND_OPS + FERMI_OPS_COMPLEX)
+def test_parity_transform_fermi_word_ps(fermionic_op, n_qubits, result):
+    """Test that the parity_transform function returns the correct qubit operator."""
+    # convert FermiWord to PauliSentence and simplify
+    qubit_op = parity_transform(fermionic_op, n_qubits, ps=True)
+    qubit_op.simplify()
+
+    # get expected op as PauliSentence and simplify
+    expected_op = pauli_sentence(qml.Hamiltonian(result[0], result[1]))
+    expected_op.simplify()
+
+    assert qubit_op == expected_op
+
+
+@pytest.mark.parametrize("fermionic_op, n_qubits, result", FERMI_WORDS_AND_OPS)
+def test_parity_transform_fermi_word_operation(fermionic_op, n_qubits, result):
+    wires = fermionic_op.wires or [0]
+
+    qubit_op = parity_transform(fermionic_op, n_qubits)
+
+    expected_op = pauli_sentence(qml.Hamiltonian(result[0], result[1]))
+    expected_op = expected_op.operation(wires)
+
+    assert qml.equal(qubit_op.simplify(), expected_op.simplify())
+
+
+def test_parity_transform_for_identity():
+    """Test that the parity_transform function returns the correct qubit operator for Identity."""
+    assert qml.equal(parity_transform(FermiWord({}), 2), qml.Identity(0))
+
+
+def test_parity_transform_for_identity_ps():
+    """Test that the parity_transform function returns the correct PauliSentence for Identity when ps=True."""
+    assert parity_transform(FermiWord({}), 2, ps=True) == PauliSentence(
+        {PauliWord({0: "I"}): 1.0 + 0.0j}
+    )
+
+
+@pytest.mark.parametrize(
+    "operator",
+    (
+        FermiWord({(0, 1): "-", (1, 0): "+", (2, 2): "-", (3, 1): "-"}),  # ('1 0^ 2 1')
+        FermiWord({(0, 1): "-", (1, 0): "+", (2, 2): "+", (3, 1): "-"}),  # ('1 0^ 2^ 1')
+        FermiWord({(0, 3): "-", (1, 0): "+", (2, 2): "+", (3, 3): "-"}),  # ('3 0^ 2^ 3')
+        FermiWord({(0, 3): "-", (1, 2): "+", (2, 2): "+", (3, 3): "-"}),  # ('3 2^ 2^ 3')
+    ),
+)
+def test_parity_transform_for_null_operator_fermi_word_ps(operator):
+    """Test that the parity_tranform function works when the result is 0"""
+    # in PauliSentence return format, returns None
+    assert parity_transform(operator, 4, ps=True).simplify() is None
+
+    # in operation return format, '0 * I'
+    op = parity_transform(operator, 4).simplify()
+
+    assert isinstance(op, SProd)
+    assert isinstance(op.base, Identity)
+    assert op.scalar == 0
+
+
+fw1 = FermiWord({(0, 0): "+", (1, 1): "-"})
+fw2 = FermiWord({(0, 0): "+", (1, 0): "-"})
+fw3 = FermiWord({(0, 0): "+", (1, 3): "-", (2, 0): "+", (3, 4): "-"})
+fw4 = FermiWord({})
+
+
+def test_empty_fermi_sentence():
+    """Test that an empty FermiSentence (fermi null operator) is
+    converted to an empty PauliSentence or the null operator"""
+    op = FermiSentence({})
+
+    ps_op = parity_transform(op, 6, ps=True)
+    ps_op.simplify()
+    assert ps_op == PauliSentence({})
+
+    op = parity_transform(op, 6).simplify()
+    assert isinstance(op, SProd)
+    assert isinstance(op.base, Identity)
+    assert op.scalar == 0
+
+
+def test_fermi_sentence_identity():
+    """Test that a FermiSentence composed of a single Identity operator
+    converts to PauliSentence and operation as expected"""
+    op = FermiSentence({fw4: 1})
+    ps = PauliSentence({PauliWord({}): 1})
+
+    ps_op = parity_transform(op, 6, ps=True)
+    qubit_op = parity_transform(op, 6)
+
+    assert ps_op == ps
+
+    result = ps.operation(wire_order=[0])
+    assert qml.equal(qubit_op.simplify(), result.simplify())
+
+
+FERMI_AND_PAULI_SENTENCES = [
+    (FermiSentence({fw4: 0, fw2: 0}), 4, PauliSentence({})),  # all 0 coeffs FermiSentence to null
+    (
+        FermiSentence({fw2: 2}),
+        4,
+        PauliSentence({PauliWord({}): (1 + 0j), PauliWord({0: "Z"}): (-1 + 0j)}),
+    ),
+    (
+        FermiSentence({fw1: 1, fw2: 1}),
+        4,
+        PauliSentence(
+            {
+                PauliWord({0: "Y"}): -0.25j,
+                PauliWord({0: "X", 1: "Z"}): (-0.25 + 0j),
+                PauliWord({0: "X"}): (0.25 + 0j),
+                PauliWord({0: "Y", 1: "Z"}): 0.25j,
+                PauliWord({}): (0.5 + 0j),
+                PauliWord({0: "Z"}): (-0.5 + 0j),
+            }
+        ),
+    ),
+    (
+        FermiSentence({fw1: 1j, fw2: -2}),
+        4,
+        PauliSentence(
+            {
+                PauliWord({0: "Y"}): (0.25 + 0j),
+                PauliWord({0: "X", 1: "Z"}): -0.25j,
+                PauliWord({0: "X"}): 0.25j,
+                PauliWord({0: "Y", 1: "Z"}): (-0.25 + 0j),
+                PauliWord({}): (-1 + 0j),
+                PauliWord({0: "Z"}): (1 + 0j),
+            }
+        ),
+    ),
+]
+
+
+@pytest.mark.parametrize("fermionic_op, n_qubits, result", FERMI_AND_PAULI_SENTENCES)
+def test_parity_transform_for_fermi_sentence_ps(fermionic_op, n_qubits, result):
+    qubit_op = parity_transform(fermionic_op, n_qubits, ps=True)
+    qubit_op.simplify()
+
+    assert qubit_op == result
+
+
+@pytest.mark.parametrize("fermionic_op, n_qubits, result", FERMI_AND_PAULI_SENTENCES)
+def test_parity_transform_for_fermi_sentence_operation(fermionic_op, n_qubits, result):
+    wires = fermionic_op.wires or [0]
+
+    qubit_op = parity_transform(fermionic_op, n_qubits)
+    result = result.operation(wires)
+
+    assert qml.equal(qubit_op.simplify(), result.simplify())
+
+
+WIRE_MAP_FOR_FERMI_SENTENCE = [
+    (
+        None,
+        [
+            qml.s_prod(-0.25j, qml.PauliY(0)),
+            qml.s_prod((0.25j), qml.prod(qml.PauliY(0), qml.PauliZ(1))),
+            qml.s_prod((-0.25 + 0j), qml.prod(qml.PauliX(0), qml.PauliZ(1))),
+            qml.s_prod(0.25, qml.PauliX(0)),
+            qml.s_prod((0.5 + 0j), qml.Identity(0)),
+            qml.s_prod((-0.5 + 0j), qml.PauliZ(0)),
+        ],
+    ),
+    (
+        {0: 0, 1: 1},
+        [
+            qml.s_prod(-0.25j, qml.PauliY(0)),
+            qml.s_prod((0.25j), qml.prod(qml.PauliY(0), qml.PauliZ(1))),
+            qml.s_prod((-0.25 + 0j), qml.prod(qml.PauliX(0), qml.PauliZ(1))),
+            qml.s_prod(0.25, qml.PauliX(0)),
+            qml.s_prod((0.5 + 0j), qml.Identity(0)),
+            qml.s_prod((-0.5 + 0j), qml.PauliZ(0)),
+        ],
+    ),
+    (
+        {0: 1, 1: 0},
+        [
+            qml.s_prod(-0.25j, qml.PauliY(1)),
+            qml.s_prod((0.25j), qml.prod(qml.PauliY(1), qml.PauliZ(0))),
+            qml.s_prod((-0.25 + 0j), qml.prod(qml.PauliX(1), qml.PauliZ(0))),
+            qml.s_prod(0.25, qml.PauliX(1)),
+            qml.s_prod((0.5 + 0j), qml.Identity(0)),
+            qml.s_prod((-0.5 + 0j), qml.PauliZ(1)),
+        ],
+    ),
+    (
+        {0: 3, 1: 2},
+        [
+            qml.s_prod(-0.25j, qml.PauliY(3)),
+            qml.s_prod((0.25j), qml.prod(qml.PauliY(3), qml.PauliZ(2))),
+            qml.s_prod((-0.25 + 0j), qml.prod(qml.PauliX(3), qml.PauliZ(2))),
+            qml.s_prod(0.25, qml.PauliX(3)),
+            qml.s_prod((0.5 + 0j), qml.Identity(3)),
+            qml.s_prod((-0.5 + 0j), qml.PauliZ(3)),
+        ],
+    ),
+    (
+        {0: "b", 1: "a"},
+        [
+            qml.s_prod(-0.25j, qml.PauliY("b")),
+            qml.s_prod((0.25j), qml.prod(qml.PauliY("b"), qml.PauliZ("a"))),
+            qml.s_prod((-0.25 + 0j), qml.prod(qml.PauliX("b"), qml.PauliZ("a"))),
+            qml.s_prod(0.25, qml.PauliX("b")),
+            qml.s_prod((0.5 + 0j), qml.Identity("b")),
+            qml.s_prod((-0.5 + 0j), qml.PauliZ("b")),
+        ],
+    ),
+]
+
+
+@pytest.mark.parametrize("wire_map, ops", WIRE_MAP_FOR_FERMI_SENTENCE)
+def test_providing_wire_map_fermi_sentence_to_operation(wire_map, ops):
+    fs = FermiSentence(
+        {FermiWord({(0, 0): "+", (1, 1): "-"}): 1, FermiWord({(0, 0): "+", (1, 0): "-"}): 1}
+    )
+    n_qubits = 4
+    op = parity_transform(fs, n_qubits, wire_map=wire_map)
+    result = qml.sum(*ops)
+
+    assert op.wires == result.wires
+
+    # converting to Pauli representation for comparison because
+    # qml.equal isn't playing nicely with term ordering
+    assert pauli_sentence(op) == pauli_sentence(result)
+
+
+@pytest.mark.parametrize("wire_map, ops", WIRE_MAP_FOR_FERMI_SENTENCE)
+def test_providing_wire_map_fermi_sentence_to_ps(wire_map, ops):
+    fs = FermiSentence(
+        {FermiWord({(0, 0): "+", (1, 1): "-"}): 1, FermiWord({(0, 0): "+", (1, 0): "-"}): 1}
+    )
+    n_qubits = 4
+    op = parity_transform(fs, n_qubits, wire_map=wire_map, ps=True)
+    result_op = qml.sum(*ops)
+    ps = pauli_sentence(result_op)
+
+    ps.simplify()
+    op.simplify()
+
+    assert ps == op
+
+
+WIRE_MAP_FOR_FERMI_WORDS = [
+    (
+        None,
+        [
+            qml.s_prod(-0.25j, qml.PauliY(0)),
+            qml.s_prod(0.25 + 0j, qml.prod(qml.PauliX(0), qml.PauliZ(1))),
+            qml.s_prod(0.25 + 0j, qml.PauliX(0)),
+            qml.s_prod(-0.25j, qml.prod(qml.PauliY(0), qml.PauliZ(1))),
+        ],
+    ),
+    (
+        {0: 3, 1: 2},
+        [
+            qml.s_prod(-0.25j, qml.PauliY(3)),
+            qml.s_prod(0.25 + 0j, qml.prod(qml.PauliX(3), qml.PauliZ(2))),
+            qml.s_prod(0.25 + 0j, qml.PauliX(3)),
+            qml.s_prod(-0.25j, qml.prod(qml.PauliY(3), qml.PauliZ(2))),
+        ],
+    ),
+    (
+        {0: "b", 1: "a"},
+        [
+            qml.s_prod(-0.25j, qml.PauliY("b")),
+            qml.s_prod(0.25 + 0j, qml.prod(qml.PauliX("b"), qml.PauliZ("a"))),
+            qml.s_prod(0.25 + 0j, qml.PauliX("b")),
+            qml.s_prod(-0.25j, qml.prod(qml.PauliY("b"), qml.PauliZ("a"))),
+        ],
+    ),
+]
+
+
+@pytest.mark.parametrize("wire_map, ops", WIRE_MAP_FOR_FERMI_WORDS)
+def test_providing_wire_map_fermi_word_to_operation(wire_map, ops):
+    w = FermiWord({(0, 0): "+", (1, 1): "+"})
+    n_qubits = 4
+    op = parity_transform(w, n_qubits, wire_map=wire_map)
+    result = qml.sum(*ops)
+
+    op.simplify()
+
+    # converting to Pauli representation for comparison because
+    # qml.equal isn't playing nicely with term ordering
+    assert pauli_sentence(op) == pauli_sentence(result)
+
+
+@pytest.mark.parametrize("wire_map, ops", WIRE_MAP_FOR_FERMI_WORDS)
+def test_providing_wire_map_fermi_word_to_ps(wire_map, ops):
+    w = FermiWord({(0, 0): "+", (1, 1): "+"})
+    n_qubits = 4
+    op = parity_transform(w, n_qubits, wire_map=wire_map, ps=True)
+    result_op = qml.sum(*ops)
+    ps = pauli_sentence(result_op)
+
+    ps.simplify()
+    op.simplify()
+
+    assert ps == op
+
+
+fs1 = FermiSentence({fw1: 1})
+
+
+@pytest.mark.parametrize(
+    "fermi_op, qubit_op_data, tol",
+    (
+        (fw1, (-0.25j, (0.25 + 0j), (0.25 + 0j), 0.25j), None),
+        (fw1, (-0.25j, 0.25, 0.25, 0.25j), 0.0),
+        (fw1, (-0.25j, 0.25, 0.25, 0.25j), 1.0e-12),
+        (fw1, (0, -0.25, 0.25, 0), 0.3),
+        (fs1, (-0.25j, (0.25 + 0j), (0.25 + 0j), 0.25j), None),
+        (fs1, (-0.25j, 0.25, 0.25, 0.25j), 0.0),
+        (fs1, (-0.25j, 0.25, 0.25, 0.25j), 1.0e-12),
+        (fs1, (0, -0.25, 0.25, 0), 0.3),
+    ),
+)
+def test_parity_transform_tolerance(fermi_op, qubit_op_data, tol):
+    """Test that parity_transform properly removes negligible imaginary components"""
+    n_qubits = 4
+    op = parity_transform(fermi_op, n_qubits, tol=tol)
+    assert isinstance(op.data[1], type(qubit_op_data[1]))