Skip to content

Commit

Permalink
Remove deprecated paul_mult and pauli_mult_with_phase (#5324)
Browse files Browse the repository at this point in the history
**Context:**
Complete the deprecation cycle for ``qml.pauli.pauli_mult`` and
``qml.pauli.pauli_mult_with_phase``

**Description of the Change:**
``qml.pauli.pauli_mult`` and ``qml.pauli.pauli_mult_with_phase`` are now
removed.

**Related Shortcut Issues:**
[sc-58145]
  • Loading branch information
astralcai authored Mar 11, 2024
1 parent e475db3 commit 0b3ac70
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 189 deletions.
26 changes: 13 additions & 13 deletions doc/development/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,6 @@ Pending deprecations
- Deprecated in v0.35
- Will be removed in v0.36

* ``qml.pauli.pauli_mult`` and ``qml.pauli.pauli_mult_with_phase`` are now deprecated. Instead, you
should use ``qml.simplify(qml.prod(pauli_1, pauli_2))`` to get the reduced operator.

>>> op = qml.simplify(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
>>> op
-1j*(PauliY(wires=[0]))
>>> [phase], [base] = op.terms()
>>> phase, base
(-1j, PauliY(wires=[0]))

- Deprecated in v0.35
- Will be removed in v0.36

* Calling ``qml.matrix`` without providing a ``wire_order`` on objects where the wire order could be
ambiguous now raises a warning. This includes tapes with multiple wires, QNodes with a device that
does not provide wires, or quantum functions.
Expand Down Expand Up @@ -64,6 +51,19 @@ Pending deprecations
Completed deprecation cycles
----------------------------

* ``qml.pauli.pauli_mult`` and ``qml.pauli.pauli_mult_with_phase`` are now removed. Instead, you
should use ``qml.simplify(qml.prod(pauli_1, pauli_2))`` to get the reduced operator.

>>> op = qml.simplify(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
>>> op
-1j*(PauliY(wires=[0]))
>>> [phase], [base] = op.terms()
>>> phase, base
(-1j, PauliY(wires=[0]))

- Deprecated in v0.35
- Removed in v0.36

* ``MeasurementProcess.name`` and ``MeasurementProcess.data`` have been deprecated, as they contain
dummy values that are no longer needed.

Expand Down
12 changes: 12 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@

<h3>Breaking changes 💔</h3>

* ``qml.pauli.pauli_mult`` and ``qml.pauli.pauli_mult_with_phase`` are now removed. Instead, you should use ``qml.simplify(qml.prod(pauli_1, pauli_2))`` to get the reduced operator.
[(#5324)](https://github.com/PennyLaneAI/pennylane/pull/5324)

```pycon
>>> op = qml.simplify(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
>>> op
-1j*(PauliY(wires=[0]))
>>> [phase], [base] = op.terms()
>>> phase, base
(-1j, PauliY(wires=[0]))
```

* ``MeasurementProcess.name`` and ``MeasurementProcess.data`` have been removed. Use ``MeasurementProcess.obs.name`` and ``MeasurementProcess.obs.data`` instead.
[(#5321)](https://github.com/PennyLaneAI/pennylane/pull/5321)

Expand Down
2 changes: 0 additions & 2 deletions pennylane/pauli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
observables_to_binary_matrix,
qwc_complement_adj_matrix,
pauli_group,
pauli_mult,
pauli_mult_with_phase,
partition_pauli_group,
qwc_rotation,
diagonalize_pauli_word,
Expand Down
152 changes: 0 additions & 152 deletions pennylane/pauli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,158 +924,6 @@ def pauli_group(n_qubits, wire_map=None):
return _pauli_group_generator(n_qubits, wire_map=wire_map)


def pauli_mult(pauli_1, pauli_2, wire_map=None):
"""Multiply two Pauli words together and return the product as a Pauli word.
.. warning::
``pauli_mult`` is deprecated. Instead, you can multiply two Pauli words
together with ``qml.simplify(qml.prod(pauli_1, pauli_2))``. Note that if
there is a phase, this will be in ``result.scalar``, and the base will be
available in ``result.base``.
Two Pauli operations can be multiplied together by taking the additive
OR of their binary symplectic representations.
Args:
pauli_1 (.Operation): A Pauli word.
pauli_2 (.Operation): A Pauli word to multiply with the first one.
wire_map (dict[Union[str, int], int]): dictionary containing all wire labels used in the Pauli
word as keys, and unique integer labels as their values. If no wire map is
provided, the map will be constructed from the set of wires acted on
by the input Pauli words.
Returns:
.Operation: The product of pauli_1 and pauli_2 as a Pauli word
(ignoring the global phase).
**Example**
This function enables multiplication of Pauli group elements at the level of
Pauli words, rather than matrices. For example,
>>> from pennylane.pauli import pauli_mult
>>> pauli_1 = qml.X(0) @ qml.Z(1)
>>> pauli_2 = qml.Y(0) @ qml.Z(1)
>>> product = pauli_mult(pauli_1, pauli_2)
>>> print(product)
Z(0)
"""

warn(
"`pauli_mult` is deprecated. Instead, you can multiply two Pauli words "
"together with `qml.simplify(qml.prod(pauli_1, pauli_2))`. Note that if "
"there is a phase, this will be in `result.scalar`, and the base will be "
"available in `result.base`.",
qml.PennyLaneDeprecationWarning,
)

if wire_map is None:
wire_map = _wire_map_from_pauli_pair(pauli_1, pauli_2)

# Check if pauli_1 and pauli_2 are the same; if so, the result is the Identity
if are_identical_pauli_words(pauli_1, pauli_2):
first_wire = list(pauli_1.wires)[0]
return Identity(first_wire)

# Compute binary symplectic representations
pauli_1_binary = pauli_to_binary(pauli_1, wire_map=wire_map)
pauli_2_binary = pauli_to_binary(pauli_2, wire_map=wire_map)

bin_symp_1 = np.array([int(x) for x in pauli_1_binary])
bin_symp_2 = np.array([int(x) for x in pauli_2_binary])

# Shorthand for bitwise XOR of numpy arrays
pauli_product = bin_symp_1 ^ bin_symp_2

return binary_to_pauli(pauli_product, wire_map=wire_map)


def pauli_mult_with_phase(pauli_1, pauli_2, wire_map=None):
r"""Multiply two Pauli words together, and return both their product as a Pauli word
and the global phase.
.. warning::
``pauli_mult_with_phase`` is deprecated. Instead, you can multiply two Pauli
words together with ``qml.simplify(qml.prod(pauli_1, pauli_2))``. Note that if
there is a phase, this will be in ``result.scalar``, and the base will be
available in ``result.base``.
Two Pauli operations can be multiplied together by taking the additive
OR of their binary symplectic representations. The phase is computed by
looking at the number of times we have the products :math:`XY, YZ`, or :math:`ZX` (adds a
phase of :math:`i`), or :math:`YX, ZY, XZ` (adds a phase of :math:`-i`).
Args:
pauli_1 (.Operation): A Pauli word.
pauli_2 (.Operation): A Pauli word to multiply with the first one.
wire_map (dict[Union[str, int], int]): dictionary containing all wire labels used in the Pauli
word as keys, and unique integer labels as their values. If no wire map is
provided, the map will be constructed from the set of wires acted on
by the input Pauli words.
Returns:
tuple[.Operation, complex]: The product of ``pauli_1`` and ``pauli_2``, and the
global phase.
**Example**
This function works the same as :func:`~.pauli_mult` but also returns the global
phase accumulated as a result of the ordering of Paulis in the product (e.g., :math:`XY = iZ`,
and :math:`YX = -iZ`).
>>> from pennylane.pauli import pauli_mult_with_phase
>>> pauli_1 = qml.X(0) @ qml.Z(1)
>>> pauli_2 = qml.Y(0) @ qml.Z(1)
>>> product, phase = pauli_mult_with_phase(pauli_1, pauli_2)
>>> product
Z(0)
>>> phase
1j
"""

warn(
"`pauli_mult_with_phase` is deprecated. Instead, you can multiply two Pauli words "
"together with `qml.simplify(qml.prod(pauli_1, pauli_2))`. Note that if "
"there is a phase, this will be in `result.scalar`, and the base will be "
"available in `result.base`.",
qml.PennyLaneDeprecationWarning,
)

if wire_map is None:
wire_map = _wire_map_from_pauli_pair(pauli_1, pauli_2)

# Get the product; use our earlier function
pauli_product = pauli_mult(pauli_1, pauli_2, wire_map)

# Get the names of the operations; in cases where only one single-qubit Pauli
# is present, the operation name is stored as a string rather than a list, so convert it
pauli_1_string = pauli_word_to_string(pauli_1, wire_map=wire_map)
pauli_2_string = pauli_word_to_string(pauli_2, wire_map=wire_map)

pos_phases = (("X", "Y"), ("Y", "Z"), ("Z", "X"))

phase = 1

for qubit_1_char, qubit_2_char in zip(pauli_1_string, pauli_2_string):
# If we have identities anywhere we don't pick up a phase
if qubit_1_char == "I" or qubit_2_char == "I":
continue

# Likewise, no additional phase if the Paulis are the same
if qubit_1_char == qubit_2_char:
continue

# Use Pauli commutation rules to determine the phase
if (qubit_1_char, qubit_2_char) in pos_phases:
phase *= 1j
else:
phase *= -1j

return pauli_product, phase


@lru_cache()
def partition_pauli_group(n_qubits: int) -> List[List[str]]:
"""Partitions the :math:`n`-qubit Pauli group into qubit-wise commuting terms.
Expand Down
22 changes: 0 additions & 22 deletions tests/pauli/test_pauli_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
observables_to_binary_matrix,
partition_pauli_group,
pauli_group,
pauli_mult,
pauli_mult_with_phase,
pauli_to_binary,
pauli_word_to_matrix,
pauli_word_to_string,
Expand Down Expand Up @@ -722,26 +720,6 @@ def test_pauli_mult_with_phase_using_prod(self, pauli_word_1, pauli_word_2, expe
obtained_phase = prod.scalar if isinstance(prod, qml.ops.SProd) else 1
assert obtained_phase == expected_phase

def test_deprecated_pauli_mult(self):
"""Test that pauli_mult is deprecated."""
with pytest.warns(qml.PennyLaneDeprecationWarning, match="`pauli_mult` is deprecated"):
pauli_mult(PauliX(0), PauliY(1))

@pytest.mark.parametrize(
"pauli_word_1,pauli_word_2,expected_phase",
[
(PauliZ(0), PauliY(0), -1j),
(PauliZ("a") @ PauliY("b"), PauliX("a") @ PauliZ("b"), -1),
(PauliZ(0), PauliZ(0), 1),
(PauliZ(0), PauliZ(1), 1),
],
)
def test_deprecated_pauli_mult_with_phase(self, pauli_word_1, pauli_word_2, expected_phase):
"""Test that pauli_mult_with_phase is deprecated."""
with pytest.warns(qml.PennyLaneDeprecationWarning, match="pauli_mult"):
_, obtained_phase = pauli_mult_with_phase(pauli_word_1, pauli_word_2)
assert obtained_phase == expected_phase


class TestPartitionPauliGroup:
"""Tests for the partition_pauli_group function"""
Expand Down

0 comments on commit 0b3ac70

Please sign in to comment.