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

Optimize ConsolidateBlocks pass #10365

Merged
merged 22 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ccf850c
Initial: Introducing speedup by calculating matrix
raynelfss Jun 30, 2023
6aac6c0
Lint: Reformat using Black
raynelfss Jun 30, 2023
1839808
Fix: Added `basis_count` and `outside_basis`
raynelfss Jul 3, 2023
636144c
Merge branch 'main' into blocks-optimize
raynelfss Jul 3, 2023
653e23c
Fix: Use `Operator` if `to_matrix` is unavailable.
raynelfss Jul 5, 2023
b529786
Merge branch 'main' into blocks-optimize
raynelfss Jul 5, 2023
cfe873f
Fix: Default to Operator when necessary
raynelfss Jul 5, 2023
1c3278a
Lint: Removed Cyclic import
raynelfss Jul 5, 2023
76ac395
Docs: Added release note.
raynelfss Jul 6, 2023
410e0ad
Docs: Added reference to the issue.
raynelfss Jul 6, 2023
a990f75
Fix: Move `block_to_matrix` to ~.passes.utils
raynelfss Jul 18, 2023
b1eab99
Merge branch 'Qiskit:main' into blocks-optimize
raynelfss Jul 19, 2023
881a442
Lint: Fixed cyclical import and order
raynelfss Jul 19, 2023
c3e25d6
Merge branch 'main' into blocks-optimize
raynelfss Jul 19, 2023
6d7387a
CI: Removed type checking
raynelfss Jul 19, 2023
5b93147
Merge branch 'blocks-optimize' of https://github.com/raynelfss/qiskit…
raynelfss Jul 19, 2023
c87d00c
Merge branch 'main' into blocks-optimize
raynelfss Jul 19, 2023
128df96
Add: Exceptions on `_block_to_matrix`
raynelfss Jul 20, 2023
b252d7a
Docs: Fix release note.
raynelfss Jul 20, 2023
f6f2cb0
Fix: Change import path for block_to_matrix
raynelfss Jul 20, 2023
07b3c88
Update qiskit/transpiler/passes/utils/block_to_matrix.py
ewinston Jul 20, 2023
7e0d1ad
Merge branch 'main' into blocks-optimize
raynelfss Jul 20, 2023
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
20 changes: 13 additions & 7 deletions qiskit/transpiler/passes/optimization/consolidate_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from qiskit.circuit.library.standard_gates import CXGate
from qiskit.transpiler.basepasses import TransformationPass
from qiskit.transpiler.passes.synthesis import unitary_synthesis
from qiskit.transpiler.passes.utils.block_to_matrix import _block_to_matrix


class ConsolidateBlocks(TransformationPass):
Expand Down Expand Up @@ -102,19 +103,24 @@ def run(self, dag):
if isinstance(nd, DAGOpNode) and getattr(nd.op, "condition", None):
block_cargs |= set(getattr(nd.op, "condition", None)[0])
all_block_gates.add(nd)
q = QuantumRegister(len(block_qargs))
qc = QuantumCircuit(q)
if block_cargs:
c = ClassicalRegister(len(block_cargs))
qc.add_register(c)
block_index_map = self._block_qargs_to_indices(block_qargs, global_index_map)
for nd in block:
if nd.op.name == basis_gate_name:
basis_count += 1
if self._check_not_in_basis(nd.op.name, nd.qargs, global_index_map):
outside_basis = True
qc.append(nd.op, [q[block_index_map[i]] for i in nd.qargs])
unitary = UnitaryGate(Operator(qc))
if len(block_qargs) > 2:
q = QuantumRegister(len(block_qargs))
qc = QuantumCircuit(q)
if block_cargs:
c = ClassicalRegister(len(block_cargs))
qc.add_register(c)
for nd in block:
qc.append(nd.op, [q[block_index_map[i]] for i in nd.qargs])
unitary = UnitaryGate(Operator(qc))
else:
matrix = _block_to_matrix(block, block_index_map)
unitary = UnitaryGate(matrix)

max_2q_depth = 20 # If depth > 20, there will be 1q gates to consolidate.
if ( # pylint: disable=too-many-boolean-expressions
Expand Down
59 changes: 59 additions & 0 deletions qiskit/transpiler/passes/utils/block_to_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2018.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Converts any block of 2 qubit gates into a matrix."""

from numpy import identity, kron
from qiskit.circuit.library import SwapGate
from qiskit.quantum_info import Operator
from qiskit.exceptions import QiskitError


SWAP_GATE = SwapGate()
SWAP_MATRIX = SWAP_GATE.to_matrix()
IDENTITY = identity(2, dtype=complex)


def _block_to_matrix(block, block_index_map):
"""
The function converts any sequence of operations between two qubits into a matrix
that can be utilized to create a gate or a unitary.

Args:
block (List(DAGOpNode)): A block of operations on two qubits.
block_index_map (dict(Qubit, int)): The mapping of the qubit indices in the main circuit.

Returns:
NDArray: Matrix representation of the block of operations.
"""
matrix = identity(2 ** len(block_index_map), dtype=complex)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An exception should be raised if the dimension of matrix != 4.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this, it would be better to just throw an exception whenever len(block_index_map) != 2 . Since earlier in the code we know that block_index_map comes from the following operation:

https://github.com/Qiskit/qiskit-terra/blob/c87d00c90af0635561c97a8ae54cd7eeccf78fce/qiskit/transpiler/passes/optimization/consolidate_blocks.py#L106

Which takes block_qargs (The set of all qubits in the block) as an argument and returns a mapped dictionary of the same length. Before we call _block_to_matrix we will check that len(block_qargs) <= 2 to call it, otherwise, the old method will be used. As shown here:

https://github.com/Qiskit/qiskit-terra/blob/c87d00c90af0635561c97a8ae54cd7eeccf78fce/qiskit/transpiler/passes/optimization/consolidate_blocks.py#L112-L123

So it would be better to just add an exception at the beginning of block_to_matrix that says if the length of block_index_length exceeds 2 then throw an error. Which would cover for cases in which the matrix has a dimension that exceeds 2x2.

for node in block:
try:
current = node.op.to_matrix()
except QiskitError:
current = Operator(node.op).data
q_list = [block_index_map[qubit] for qubit in node.qargs]
basis_change = False
if len(q_list) < 2:
if q_list[0] == 1:
current = kron(current, IDENTITY)
else:
current = kron(IDENTITY, current)
else:
if q_list[0] > q_list[1]:
if node.op != SWAP_GATE:
basis_change = True
if basis_change:
matrix = (SWAP_MATRIX @ current) @ (SWAP_MATRIX @ matrix)
else:
matrix = current @ matrix
return matrix
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
fixes:
- |
Reduced overhead of the :class:`.ConsolidateBlocks` pass by performing matrix operations
on all two-qubit blocks privately instead of creating an instance of :class:`.QuantumCircuit`
and passing it to an :class:`.Operator`. The speedup will only be applicable when
consolidating two-qubit blocks. Anything higher than that will still be handled by the
:class:`.Operator` class.
Check `#8779 <https://github.com/Qiskit/qiskit-terra/issues/8779>`__ for details.