diff --git a/docs/conf.py b/docs/conf.py index f2799672974c..42c90ab943f7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -248,6 +248,7 @@ # Custom extensions # --------------------------------------------------------------------------------------- + def add_versions_to_config(_app, config): """Add a list of old documentation versions that should have links generated to them into the context, so the theme can use them to generate a sidebar.""" diff --git a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py index b6cf031f3f3a..28d017e91660 100644 --- a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py +++ b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py @@ -27,7 +27,6 @@ from qiskit.transpiler.passes import NoiseAdaptiveLayout from qiskit.transpiler.passes import CheckMap from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements -from qiskit.transpiler.passes import RemoveResetInZeroState from qiskit.transpiler.passes import OptimizeSwapBeforeMeasure from qiskit.transpiler.passes import RemoveDiagonalGatesBeforeMeasure from qiskit.transpiler.preset_passmanagers import common @@ -81,7 +80,6 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana pass_manager_config.unitary_synthesis_plugin_config, pass_manager_config.hls_config, ) - init.append(RemoveResetInZeroState()) init.append(OptimizeSwapBeforeMeasure()) init.append(RemoveDiagonalGatesBeforeMeasure()) else: diff --git a/qiskit/transpiler/preset_passmanagers/level1.py b/qiskit/transpiler/preset_passmanagers/level1.py index 4e585148c080..0a0b1c2a8e43 100644 --- a/qiskit/transpiler/preset_passmanagers/level1.py +++ b/qiskit/transpiler/preset_passmanagers/level1.py @@ -82,10 +82,10 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa target is not None and target.get_non_global_operation_names(strict_direction=True) ): pre_optimization = common.generate_pre_op_passmanager( - target, coupling_map, remove_reset_in_zero=True + target, coupling_map, remove_reset_in_zero=False ) else: - pre_optimization = common.generate_pre_op_passmanager(remove_reset_in_zero=True) + pre_optimization = common.generate_pre_op_passmanager(remove_reset_in_zero=False) optimization = plugin_manager.get_passmanager_stage( "optimization", optimization_method, pass_manager_config, optimization_level=1 diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index 941bf2fcf2ac..b22743883fbe 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -80,9 +80,11 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa if (coupling_map and not coupling_map.is_symmetric) or ( target is not None and target.get_non_global_operation_names(strict_direction=True) ): - pre_optimization = common.generate_pre_op_passmanager(target, coupling_map, True) + pre_optimization = common.generate_pre_op_passmanager( + target, coupling_map, remove_reset_in_zero=False + ) else: - pre_optimization = common.generate_pre_op_passmanager(remove_reset_in_zero=True) + pre_optimization = common.generate_pre_op_passmanager(remove_reset_in_zero=False) optimization = plugin_manager.get_passmanager_stage( "optimization", optimization_method, pass_manager_config, optimization_level=2 diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py index 90e3872adf64..c1393a0b7c6e 100644 --- a/qiskit/transpiler/preset_passmanagers/level3.py +++ b/qiskit/transpiler/preset_passmanagers/level3.py @@ -97,9 +97,11 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa if (coupling_map and not coupling_map.is_symmetric) or ( target is not None and target.get_non_global_operation_names(strict_direction=True) ): - pre_optimization = common.generate_pre_op_passmanager(target, coupling_map, True) + pre_optimization = common.generate_pre_op_passmanager( + target, coupling_map, remove_reset_in_zero=False + ) else: - pre_optimization = common.generate_pre_op_passmanager(remove_reset_in_zero=True) + pre_optimization = common.generate_pre_op_passmanager(remove_reset_in_zero=False) sched = plugin_manager.get_passmanager_stage( "scheduling", scheduling_method, pass_manager_config, optimization_level=3 diff --git a/releasenotes/notes/keep-initial-resets-a5f75cb16c8edb57.yaml b/releasenotes/notes/keep-initial-resets-a5f75cb16c8edb57.yaml new file mode 100644 index 000000000000..e0c987504dc0 --- /dev/null +++ b/releasenotes/notes/keep-initial-resets-a5f75cb16c8edb57.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + Disables the use of :class:`.RemoveResetInZeroState` in the preset passmanagers. + This better aligns circuits to the notion of arbitrary initial states + unless explicitly set to zeros with resets. diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 307e90d914c4..0be4922cb5b7 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -51,7 +51,6 @@ SXGate, U1Gate, U2Gate, - U3Gate, UGate, XGate, ) @@ -802,20 +801,26 @@ def test_move_measurements(self): ) self.assertTrue(is_last_measure) - def test_initialize_reset_should_be_removed(self): - """The reset in front of initializer should be removed when zero state""" + @data(0, 1, 2, 3) + def test_init_resets_kept_preset_passmanagers(self, optimization_level): + """Test initial resets kept at all preset transpilation levels""" + num_qubits = 5 + qc = QuantumCircuit(num_qubits) + qc.reset(range(num_qubits)) + + num_resets = transpile(qc, optimization_level=optimization_level).count_ops()["reset"] + self.assertEqual(num_resets, num_qubits) + + @data(0, 1, 2, 3) + def test_initialize_reset_is_not_removed(self, optimization_level): + """The reset in front of initializer should NOT be removed at beginning""" qr = QuantumRegister(1, "qr") qc = QuantumCircuit(qr) qc.initialize([1.0 / math.sqrt(2), 1.0 / math.sqrt(2)], [qr[0]]) qc.initialize([1.0 / math.sqrt(2), -1.0 / math.sqrt(2)], [qr[0]]) - expected = QuantumCircuit(qr) - expected.append(U3Gate(np.pi / 2, 0, 0), [qr[0]]) - expected.reset(qr[0]) - expected.append(U3Gate(np.pi / 2, -np.pi, 0), [qr[0]]) - - after = transpile(qc, basis_gates=["reset", "u3"], optimization_level=1) - self.assertEqual(after, expected, msg=f"after:\n{after}\nexpected:\n{expected}") + after = transpile(qc, basis_gates=["reset", "u3"], optimization_level=optimization_level) + self.assertEqual(after.count_ops()["reset"], 2, msg=f"{after}\n does not have 2 resets.") def test_initialize_FakeMelbourne(self): """Test that the zero-state resets are remove in a device not supporting them.""" @@ -828,7 +833,7 @@ def test_initialize_FakeMelbourne(self): out_dag = circuit_to_dag(out) reset_nodes = out_dag.named_nodes("reset") - self.assertEqual(reset_nodes, []) + self.assertEqual(len(reset_nodes), 3) def test_non_standard_basis(self): """Test a transpilation with a non-standard basis"""