Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grouping commuting Pauli strings in quantum_info #6690

Merged
merged 25 commits into from
Aug 11, 2021
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4b205b5
added functions, tested
irajput Jul 6, 2021
a15c8ed
deleted extra nb
irajput Jul 6, 2021
01285cf
changed to module level imports
irajput Jul 6, 2021
f0a0212
deleted accidental addition
irajput Jul 6, 2021
6dd6c46
added qubit_wise option too Pauli commutes
irajput Jul 7, 2021
a5f2972
changed to non commutation graph
irajput Jul 8, 2021
b6aa346
formatted
irajput Jul 8, 2021
0c7dd26
changed wording, added noncommutation
irajput Jul 8, 2021
0ff55b2
changed to numpy implementation from opflow
irajput Jul 8, 2021
798cc9a
Merge branch 'main' of https://github.com/Qiskit/qiskit-terra into fi…
irajput Jul 8, 2021
77aae49
added tests
irajput Jul 13, 2021
cb11b4b
reformat
irajput Jul 13, 2021
38bdc14
added release note
irajput Jul 13, 2021
cec373a
made test more complex
irajput Jul 20, 2021
a221378
format
irajput Jul 21, 2021
d20cae4
updated branch
irajput Jul 21, 2021
707e7e3
Merge branch 'main' of https://github.com/Qiskit/qiskit-terra into fi…
irajput Jul 21, 2021
472ac35
finished adding test
irajput Jul 21, 2021
069f264
Update test/python/quantum_info/operators/symplectic/test_pauli_list.py
irajput Jul 22, 2021
f357b70
changed test
irajput Jul 22, 2021
944c5e2
fixed
irajput Jul 22, 2021
27ebc67
Fix indentation in qubitwise-commutation test
jakelishman Jul 23, 2021
19acaec
Merge branch 'main' into pauli-qubitwise-commute
jakelishman Jul 23, 2021
b0d19d8
Restore missing whitespace
jakelishman Jul 23, 2021
c208438
Merge branch 'main' into fix6624
mergify[bot] Aug 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions qiskit/quantum_info/operators/symplectic/pauli.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,11 +518,9 @@ def inverse(self):

def commutes(self, other, qargs=None):
"""Return True if the Pauli commutes with other.

Args:
other (Pauli or PauliList): another Pauli operator.
qargs (list): qubits to apply dot product on (default: None).

Returns:
bool: True if Pauli's commute, False if they anti-commute.
"""
Expand Down
41 changes: 39 additions & 2 deletions qiskit/quantum_info/operators/symplectic/pauli_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
"""
Optimized list of Pauli operators
"""

from collections import defaultdict
import numpy as np

import retworkx as rx
from qiskit.exceptions import QiskitError
from qiskit.quantum_info.operators.custom_iterator import CustomIterator
from qiskit.quantum_info.operators.mixins import GroupMixin, LinearMixin
Expand Down Expand Up @@ -1062,3 +1062,40 @@ def from_symplectic(cls, z, x, phase=0):
"""
base_z, base_x, base_phase = cls._from_array(z, x, phase)
return cls(BasePauli(base_z, base_x, base_phase))

def _noncommutation_graph(self):
"""Create an edge list representing the qubit-wise non-commutation graph.

An edge (i, j) is present if i and j are not commutable.

Returns:
List[Tuple(int,int)]: A list of pairs of indices of the PauliList that are not commutable.
"""
# convert a Pauli operator into int vector where {I: 0, X: 2, Y: 3, Z: 1}
mat1 = np.array(
[op.z + 2 * op.x for op in self],
dtype=np.int8,
)
mat2 = mat1[:, None]
# mat3[i, j] is True if i and j are qubit-wise commutable
mat3 = (((mat1 * mat2) * (mat1 - mat2)) == 0).all(axis=2)
# convert into list where tuple elements are qubit-wise non-commuting operators
return list(zip(*np.where(np.triu(np.logical_not(mat3), k=1))))

def group_qubit_wise_commuting(self):
"""Partition a PauliList into sets of mutually qubit-wise commuting Pauli strings.

Returns:
List[PauliList]: List of PauliLists where each PauliList contains commutable Pauli operators.
"""
nodes = range(self._num_paulis)
edges = self._noncommutation_graph()
graph = rx.PyGraph()
graph.add_nodes_from(nodes)
graph.add_edges_from_no_data(edges)
# Keys in coloring_dict are nodes, values are colors
coloring_dict = rx.graph_greedy_color(graph)
groups = defaultdict(list)
for idx, color in coloring_dict.items():
groups[color].append(idx)
return [PauliList([self[i] for i in x]) for x in groups.values()]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---

features:
- |
Added a new function, `group_qubit_wise_commuting()`, which partitions a
``PauliList`` into sets of mutually qubit-wise commuting ``Pauli`` strings.
for example::

from qiskit.quantum_info import PauliList,Pauli
pauli_list=PauliList([Pauli("IY"), Pauli("XX"),Pauli("YY"),Pauli("YX")])
pauli_list.group_qubit_wise_commuting()

Original file line number Diff line number Diff line change
Expand Up @@ -1999,6 +1999,32 @@ def test_evolve_clifford_qargs(self, phase):
]
self.assertListEqual(value, target)

def test_group_qubit_wise_commuting(self):
"""Test grouping qubit-wise commuting operators"""
input_labels = ["IY", "ZX", "XZ", "YI", "YX", "YY", "YZ", "ZI", "ZX", "ZY", "iZZ", "II"]
np.random.shuffle(input_labels)
pauli_list = PauliList(input_labels)
groups = pauli_list.group_qubit_wise_commuting()

# checking that every input Pauli in pauli_list is in a group in the ouput
assert all(((pauli in group) for group in groups) for pauli in pauli_list)
irajput marked this conversation as resolved.
Show resolved Hide resolved

# checking that for every pair of groups in the output, there is at least one element of
# one group which does not commute with at least one element of the other group
mat1 = [
np.array(
[op.z + 2 * op.x for op in group],
dtype=np.int8,
)
for group in groups
]
mat2 = [mat[:, None] for mat in mat1]

# value[i][j] will be False if groups i and j have non-commuting elements, True otherwise
value = np.array([[(i * j * (i - j) == 0).all(axis=(2, 1, 0)) for i in mat1] for j in mat2])
target = np.diag([True] * len(mat1))
assert (value == target).all()
irajput marked this conversation as resolved.
Show resolved Hide resolved


if __name__ == "__main__":
unittest.main()