Reduce number of decomposers used during UnitarySynthesis default plugin (#12151)

* Reduce number of decomposers used during UnitarySynthesis default plugin

This commit reduces the number of decomposers we run in the default
synthesis plugin when we're in known targets. Previously the unitary
synthesis plugin was trying to product of all 1q basis and 2q basis for
every 2q pair that is being synthesized. This would result in duplicated
work for several 1q bases where there were potential subsets available
as two different target euler bases, mainly U321 and U3 or ZSX and ZSXX
if the basis gates for a qubit where U3, U2, U1 or Rz, SX, and X
respectively. This reuses the logic from Optimize1qGatesDecomposition to
make the euler basis selection which does the deduplication. Similarly,
in the presence of known 2q gates we can skip the XXDecomposer checks (or
potentially running the XXDecomposer) which should speed up both the
selection of decomposers and also reduce the number of decomposers we
run.

* Update qiskit/transpiler/passes/synthesis/unitary_synthesis.py

---------

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
This commit is contained in:
Matthew Treinish 2024-04-09 20:03:51 -04:00 committed by GitHub
parent a7cc16624a
commit e48b4c47de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 12 additions and 11 deletions

View File

@ -35,6 +35,7 @@ from qiskit.transpiler.basepasses import TransformationPass
from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.exceptions import TranspilerError
from qiskit.dagcircuit.dagcircuit import DAGCircuit from qiskit.dagcircuit.dagcircuit import DAGCircuit
from qiskit.synthesis.one_qubit import one_qubit_decompose from qiskit.synthesis.one_qubit import one_qubit_decompose
from qiskit.transpiler.passes.optimization.optimize_1q_decomposition import _possible_decomposers
from qiskit.synthesis.two_qubit.xx_decompose import XXDecomposer, XXEmbodiments from qiskit.synthesis.two_qubit.xx_decompose import XXDecomposer, XXEmbodiments
from qiskit.synthesis.two_qubit.two_qubit_decompose import ( from qiskit.synthesis.two_qubit.two_qubit_decompose import (
TwoQubitBasisDecomposer, TwoQubitBasisDecomposer,
@ -84,23 +85,16 @@ def _choose_kak_gate(basis_gates):
def _choose_euler_basis(basis_gates): def _choose_euler_basis(basis_gates):
"""Choose the first available 1q basis to use in the Euler decomposition.""" """Choose the first available 1q basis to use in the Euler decomposition."""
basis_set = set(basis_gates or []) basis_set = set(basis_gates or [])
decomposers = _possible_decomposers(basis_set)
for basis, gates in one_qubit_decompose.ONE_QUBIT_EULER_BASIS_GATES.items(): if decomposers:
return decomposers[0]
if set(gates).issubset(basis_set):
return basis
return "U" return "U"
def _find_matching_euler_bases(target, qubit): def _find_matching_euler_bases(target, qubit):
"""Find matching available 1q basis to use in the Euler decomposition.""" """Find matching available 1q basis to use in the Euler decomposition."""
euler_basis_gates = []
basis_set = target.operation_names_for_qargs((qubit,)) basis_set = target.operation_names_for_qargs((qubit,))
for basis, gates in one_qubit_decompose.ONE_QUBIT_EULER_BASIS_GATES.items(): return _possible_decomposers(basis_set)
if set(gates).issubset(basis_set):
euler_basis_gates.append(basis)
return euler_basis_gates
def _choose_bases(basis_gates, basis_dict=None): def _choose_bases(basis_gates, basis_dict=None):
@ -777,6 +771,13 @@ class DefaultUnitarySynthesis(plugin.UnitarySynthesisPlugin):
) )
decomposers.append(decomposer) decomposers.append(decomposer)
# If our 2q basis gates are a subset of cx, ecr, or cz then we know TwoQubitBasisDecomposer
# is an ideal decomposition and there is no need to bother calculating the XX embodiments
# or try the XX decomposer
if {"cx", "cz", "ecr"}.issuperset(available_2q_basis):
self._decomposer_cache[qubits_tuple] = decomposers
return decomposers
# possible controlled decomposers (i.e. XXDecomposer) # possible controlled decomposers (i.e. XXDecomposer)
controlled_basis = {k: v for k, v in available_2q_basis.items() if is_controlled(v)} controlled_basis = {k: v for k, v in available_2q_basis.items() if is_controlled(v)}
basis_2q_fidelity = {} basis_2q_fidelity = {}