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

limiting matrix-based commutativity check #10495

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
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,9 @@
---
fixes:
- |
The maximum number of qubits to consider for matrix multiplication-based commutativity check
in :class:`~.CommutationChecker` is now limited to 3 by default. 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.
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()
Loading