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 all 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
40 changes: 40 additions & 0 deletions qiskit/quantum_info/operators/symplectic/pauli_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
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
Expand Down Expand Up @@ -1062,3 +1065,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 @@ -15,6 +15,7 @@
import unittest
from test import combine

import itertools
import numpy as np
from ddt import ddt
from scipy.sparse import csr_matrix
Expand All @@ -36,6 +37,7 @@
from qiskit.quantum_info.operators import (
Clifford,
Operator,
Pauli,
PauliList,
PauliTable,
StabilizerTable,
Expand Down Expand Up @@ -1999,6 +2001,35 @@ def test_evolve_clifford_qargs(self, phase):
]
self.assertListEqual(value, target)

def test_group_qubit_wise_commuting(self):
"""Test grouping qubit-wise commuting operators"""

def qubitwise_commutes(left: Pauli, right: Pauli) -> bool:
return len(left) == len(right) and all(a.commutes(b) for a, b in zip(left, right))

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
output_labels = [pauli.to_label() for group in groups for pauli in group]
assert sorted(output_labels) == sorted(input_labels)

# Within each group, every operator qubit-wise commutes with every other operator.
for group in groups:
assert all(
qubitwise_commutes(pauli1, pauli2)
for pauli1, pauli2 in itertools.combinations(group, 2)
)
# For every pair of groups, at least one element from one does not qubit-wise commute with
# at least one element of the other.
for group1, group2 in itertools.combinations(groups, 2):
assert not all(
qubitwise_commutes(group1_pauli, group2_pauli)
for group1_pauli, group2_pauli in itertools.product(group1, group2)
)


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