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 21 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 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
1 change: 1 addition & 0 deletions qiskit/transpiler/passes/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@

# Utility functions
from . import control_flow
from .block_to_matrix import _block_to_matrix
70 changes: 70 additions & 0 deletions qiskit/transpiler/passes/utils/block_to_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# 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.
"""
block_index_length = len(block_index_map)
if block_index_length != 2:
raise QiskitError(
"This function can only operate with blocks of 2 qubits."
+ f"This block had {block_index_length}"
)
matrix = identity(2**block_index_length, dtype=complex)
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]
if len(q_list) > 2:
raise QiskitError(
f"The operation {node.op.name} in this block has "
+ f"{len(q_list)} qubits, only 2 max allowed."
)
basis_change = False
if len(q_list) < block_index_length:
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,14 @@
---
features:
- |
Added utility function :func:`qiskit.transpiler.passes.utils._block_to_matrix` that can
generate a matrix based on a block of operations between two qubits. This function can
be used in transpiler passes that work on some decomposed circuits such as :class:`.ConsolidateBlocks`.
fixes:
- |
Reduced overhead of the :class:`.ConsolidateBlocks` pass by performing matrix operations
on all two-qubit blocks using :func:`qiskit.transpiler.passes.utils._block_to_matrix`
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.
Loading