Skip to content

Commit

Permalink
limiting matrix-based commutativity check (#10495)
Browse files Browse the repository at this point in the history
* limiting matrix-based commutativity check

* adding tests with the order of gates fixed

* lint tweaks

* improved released notes
  • Loading branch information
alexanderivrii committed Jul 25, 2023
1 parent 42a0ee8 commit 07b06f9
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 3 deletions.
24 changes: 21 additions & 3 deletions qiskit/circuit/commutation_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,20 @@ def _hashable_parameters(self, params):
return ("fallback", str(params))

def commute(
self, op1: Operation, qargs1: List, cargs1: List, op2: Operation, qargs2: List, cargs2: List
):
self,
op1: Operation,
qargs1: List,
cargs1: List,
op2: Operation,
qargs2: List,
cargs2: List,
max_num_qubits: int = 3,
) -> bool:
"""
Checks if two Operations commute.
Checks if two Operations commute. The return value of `True` means that the operations
truly commute, and the return value of `False` means that either the operations do not
commute or that the commutation check was skipped (for example, when the operations
have conditions or have too many qubits).
Args:
op1: first operation.
Expand All @@ -77,10 +87,14 @@ def commute(
op2: second operation.
qargs2: second operation's qubits.
cargs2: second operation's clbits.
max_num_qubits: the maximum number of qubits to consider, the check may be skipped if
the number of qubits for either operation exceeds this amount.
Returns:
bool: whether two operations commute.
"""
# pylint: disable=too-many-return-statements

# We don't support commutation of conditional gates for now due to bugs in
# CommutativeCancellation. See gh-8553.
if (
Expand All @@ -105,6 +119,10 @@ def commute(
if not (intersection_q or intersection_c):
return True

# Skip the check if the number of qubits for either operation is too large
if len(qargs1) > max_num_qubits or len(qargs2) > max_num_qubits:
return False

# These lines are adapted from commutation_analysis, which is more restrictive than the
# check from dag_dependency when considering nodes with "_directive". It would be nice to
# think which optimizations from dag_dependency can indeed be used.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
features:
- |
Added a new option ``max_num_qubits`` to :meth:`qiskit.circuit.CommutationChecker.commute`
that specifies the maximum number of qubits to consider for the more expensive
matrix multiplication-based commutativity check. This avoids trying to
internally allocate arrays of size :math:`2^N \times 2^N`. Simpler versions of commutativity
check (for instance, two quantum operations commute when they are over disjoint sets of qubits)
continue to work without this limit.
fixes:
- |
The maximum number of qubits to consider for matrix multiplication-based commutativity check
in :class:`~.CommutationChecker` is now limited to 3 by default.
Fixed `#10488 <https://github.com/Qiskit/qiskit-terra/issues/10488>`__
15 changes: 15 additions & 0 deletions test/python/circuit/test_commutation_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
XGate,
CXGate,
CCXGate,
MCXGate,
RZGate,
Measure,
Barrier,
Expand Down Expand Up @@ -362,6 +363,20 @@ def test_c7x_gate(self):
res = CommutationChecker().commute(XGate(), qargs[:1], [], XGate().control(7), qargs, [])
self.assertFalse(res)

def test_wide_gates_over_nondisjoint_qubits(self):
"""Test that checking wide gates does not lead to memory problems."""
res = CommutationChecker().commute(MCXGate(29), list(range(30)), [], XGate(), [0], [])
self.assertFalse(res)
res = CommutationChecker().commute(XGate(), [0], [], MCXGate(29), list(range(30)), [])
self.assertFalse(res)

def test_wide_gates_over_disjoint_qubits(self):
"""Test that wide gates still commute when they are over disjoint sets of qubits."""
res = CommutationChecker().commute(MCXGate(29), list(range(30)), [], XGate(), [30], [])
self.assertTrue(res)
res = CommutationChecker().commute(XGate(), [30], [], MCXGate(29), list(range(30)), [])
self.assertTrue(res)


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

0 comments on commit 07b06f9

Please sign in to comment.