Skip to content

Commit

Permalink
Revert to main preset passmanager logic
Browse files Browse the repository at this point in the history
As was pointed out by @jakelishman in code review. Prior to Qiskit#6124 the
unitary synthesis pass was checking the basis for the presence of
unitary (and swap gates if pulse_optimize=True) in the basis set and
skipping the gates in the pass directly instead of in the pass manager.
This logic was lost when we added the plugin interface in Qiskit#6124
(probably as part of a rebase as it was a long lived branch). Since we
used to have the logic in the pass itself this commit changes the
approach to not adjust the preset passmanager usage and just make the
pass detect if unitary is in the basis and not synthesize. This
simplifies the logic and makes it less error prone.

At the same time the test coverage is expanded to ensure we preserve
this behavior moving forward (as aer's testing requires it).
  • Loading branch information
mtreinish committed Oct 6, 2021
1 parent 99a52af commit 69b8066
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 54 deletions.
2 changes: 2 additions & 0 deletions qiskit/transpiler/passes/synthesis/unitary_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ def run(self, dag: DAGCircuit) -> DAGCircuit:
plugin_method._approximation_degree = self._approximation_degree

for node in dag.named_nodes(*self._synth_gates):
if self._basis_gates and node.name in self._basis_gates:
continue
if self._min_qubits is not None and len(node.qargs) < self._min_qubits:
continue
if plugin_method.supports_coupling_map:
Expand Down
21 changes: 8 additions & 13 deletions qiskit/transpiler/preset_passmanagers/level0.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,14 @@ def _swap_condition(property_set):
elif translation_method == "translator":
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel

if basis_gates is not None and "unitary" not in basis_gates:
_unroll = [
UnitarySynthesis(
basis_gates,
approximation_degree=approximation_degree,
coupling_map=coupling_map,
backend_props=backend_properties,
method=unitary_synthesis_method,
)
]
else:
_unroll = []
_unroll += [
_unroll = [
UnitarySynthesis(
basis_gates,
approximation_degree=approximation_degree,
coupling_map=coupling_map,
backend_props=backend_properties,
method=unitary_synthesis_method,
),
UnrollCustomDefinitions(sel, basis_gates),
BasisTranslator(sel, basis_gates),
]
Expand Down
21 changes: 8 additions & 13 deletions qiskit/transpiler/preset_passmanagers/level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,21 +177,16 @@ def _swap_condition(property_set):
elif translation_method == "translator":
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel

if basis_gates is not None and "unitary" not in basis_gates:
_unroll = [
# Use unitary synthesis for basis aware decomposition of UnitaryGates before
# custom unrolling
_unroll = [
UnitarySynthesis(
basis_gates,
approximation_degree=approximation_degree,
coupling_map=coupling_map,
backend_props=backend_properties,
method=unitary_synthesis_method,
)
]
else:
_unroll = []
_unroll += [
UnitarySynthesis(
basis_gates,
approximation_degree=approximation_degree,
coupling_map=coupling_map,
method=unitary_synthesis_method,
backend_props=backend_properties,
),
UnrollCustomDefinitions(sel, basis_gates),
BasisTranslator(sel, basis_gates),
]
Expand Down
25 changes: 10 additions & 15 deletions qiskit/transpiler/preset_passmanagers/level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,21 +211,16 @@ def _swap_condition(property_set):
elif translation_method == "translator":
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel

# Use unitary synthesis for basis aware decomposition of UnitaryGates before
# custom unrolling
if basis_gates is not None and "unitary" not in basis_gates:
_unroll = [
UnitarySynthesis(
basis_gates,
approximation_degree=approximation_degree,
coupling_map=coupling_map,
backend_props=backend_properties,
method=unitary_synthesis_method,
)
]
else:
_unroll = []
_unroll += [
_unroll = [
# Use unitary synthesis for basis aware decomposition of UnitaryGates before
# custom unrolling
UnitarySynthesis(
basis_gates,
approximation_degree=approximation_degree,
coupling_map=coupling_map,
backend_props=backend_properties,
method=unitary_synthesis_method,
),
UnrollCustomDefinitions(sel, basis_gates),
BasisTranslator(sel, basis_gates),
]
Expand Down
21 changes: 8 additions & 13 deletions qiskit/transpiler/preset_passmanagers/level3.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,19 +214,14 @@ def _swap_condition(property_set):
elif translation_method == "translator":
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel

if basis_gates is not None and "unitary" not in basis_gates:
_unroll = [
UnitarySynthesis(
basis_gates,
approximation_degree=approximation_degree,
coupling_map=coupling_map,
backend_props=backend_properties,
method=unitary_synthesis_method,
)
]
else:
_unroll = []
_unroll += [
_unroll = [
UnitarySynthesis(
basis_gates,
approximation_degree=approximation_degree,
coupling_map=coupling_map,
backend_props=backend_properties,
method=unitary_synthesis_method,
),
UnrollCustomDefinitions(sel, basis_gates),
BasisTranslator(sel, basis_gates),
]
Expand Down
40 changes: 40 additions & 0 deletions test/python/transpiler/test_preset_passmanagers.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,46 @@ def test_unitary_is_preserved_if_in_basis(self, level):
result = transpile(qc, basis_gates=["cx", "u", "unitary"], optimization_level=level)
self.assertEqual(result, qc)

# Level 3 is skipped because the 2q synthesis optimization pass decomposes
# the unitary
@combine(level=[0, 1, 2], name="level{level}")
def test_unitary_is_preserved_if_basis_is_None(self, level):
"""Test that a unitary is not synthesized if basis is None."""
qc = QuantumCircuit(2)
qc.unitary(random_unitary(4, seed=4242), [0, 1])
qc.measure_all()
result = transpile(qc, basis_gates=None, optimization_level=level)
self.assertEqual(result, qc)

# Level 3 is skipped because the 2q synthesis optimization pass decomposes
# the unitary
@combine(level=[0, 1, 2], name="level{level}")
def test_unitary_is_preserved_if_in_basis_synthesis_translation(self, level):
"""Test that a unitary is not synthesized if in the basis with synthesis translation."""
qc = QuantumCircuit(2)
qc.unitary(random_unitary(4, seed=424242), [0, 1])
qc.measure_all()
result = transpile(
qc,
basis_gates=["cx", "u", "unitary"],
optimization_level=level,
translation_method="synthesis",
)
self.assertEqual(result, qc)

# Level 3 is skipped because the 2q synthesis optimization pass decomposes
# the unitary
@combine(level=[0, 1, 2], name="level{level}")
def test_unitary_is_preserved_if_basis_is_None_synthesis_transltion(self, level):
"""Test that a unitary is not synthesized if basis is None with synthesis translation."""
qc = QuantumCircuit(2)
qc.unitary(random_unitary(4, seed=42424242), [0, 1])
qc.measure_all()
result = transpile(
qc, basis_gates=None, optimization_level=level, translation_method="synthesis"
)
self.assertEqual(result, qc)

@combine(level=[0, 1, 2, 3], name="level{level}")
def test_respect_basis(self, level):
"""Test that all levels respect basis"""
Expand Down

0 comments on commit 69b8066

Please sign in to comment.