From ef14f9d57f0347277ea758eb74196f0a5f9aa54e Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 30 Nov 2023 11:52:06 -0500 Subject: [PATCH] Don't substitute ideal gates in target with Optimize1qGatesDecomposition This commit fixes an issue in Optimize1qGatesDecomposition where the pass would defer to synthesized gates if the output from synthesis was ideal even if the input gate was also ideal. This typically comes up in simulators where there are no error rates for any gates and everything is listed as ideal. This would cause the transpiler to translate gates unnecessarily which was unexpected. This commit fixes this by adding an additional check to the subsitution condition to ensure we're only substituting a gate if it's not in the target (when they're all ideal). Fixes #10568 --- .../optimization/optimize_1q_decomposition.py | 13 +++++++++++-- .../fix-optimize-1q-sim-407b88e45e6062b6.yaml | 10 ++++++++++ .../transpiler/test_optimize_1q_decomposition.py | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/fix-optimize-1q-sim-407b88e45e6062b6.yaml diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py index f96ed999061d..c538d9ea5e59 100644 --- a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +++ b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py @@ -173,10 +173,19 @@ def _substitution_checks(self, dag, old_run, new_circ, basis, qubit): # if we're outside of the basis set, we're obligated to logically decompose. # if we're outside of the set of gates for which we have physical definitions, # then we _try_ to decompose, using the results if we see improvement. + new_error = 0.0 + old_error = 0.0 + if not uncalibrated_and_not_basis_p: + new_error = self._error(new_circ, qubit) + old_error = self._error(old_run, qubit) + return ( uncalibrated_and_not_basis_p - or (uncalibrated_p and self._error(new_circ, qubit) < self._error(old_run, qubit)) - or math.isclose(self._error(new_circ, qubit)[0], 0) + or (uncalibrated_p and new_error < old_error) + or ( + math.isclose(new_error[0], 0) + and (not uncalibrated_and_not_basis_p and not math.isclose(old_error[0], 0)) + ) ) @control_flow.trivial_recurse diff --git a/releasenotes/notes/fix-optimize-1q-sim-407b88e45e6062b6.yaml b/releasenotes/notes/fix-optimize-1q-sim-407b88e45e6062b6.yaml new file mode 100644 index 000000000000..a0e734aefa4c --- /dev/null +++ b/releasenotes/notes/fix-optimize-1q-sim-407b88e45e6062b6.yaml @@ -0,0 +1,10 @@ +--- +fixes: + - | + Fixed an issue with the :class:`.Optimize1qGatesDecomposition` transpiler + pass where it would potential resynthesize a single ideal (meaning the + error rate is ``0.0``) gate which was present in the :class:`.Target`. This + is now fixed so the pass :class:`.Optimize1qGatesDecomposition` will defer + to the circuit's gate if the error rate (which includes number of gates) + are the same. + Fixed `#10568 `__ diff --git a/test/python/transpiler/test_optimize_1q_decomposition.py b/test/python/transpiler/test_optimize_1q_decomposition.py index 5d3ebb3d7245..72dbae0d3115 100644 --- a/test/python/transpiler/test_optimize_1q_decomposition.py +++ b/test/python/transpiler/test_optimize_1q_decomposition.py @@ -745,6 +745,20 @@ def test_nested_control_flow(self): result = passmanager.run(test) self.assertEqual(result, expected) + def test_prefer_no_substitution_if_all_ideal(self): + """Test that gates are not substituted if all our ideal gates in basis.""" + target = Target(num_qubits=1) + target.add_instruction(HGate(), {(0,): InstructionProperties(error=0)}) + target.add_instruction( + UGate(Parameter("a"), Parameter("b"), Parameter("c")), + {(0,): InstructionProperties(error=0)}, + ) + qc = QuantumCircuit(1) + qc.h(0) + opt_pass = Optimize1qGatesDecomposition(target) + res = opt_pass(qc) + self.assertEqual(res, qc) + if __name__ == "__main__": unittest.main()