From bbaea5196a5f674b37e4eaa5d30634be06c01ef3 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Mon, 6 Nov 2023 17:04:04 +0900 Subject: [PATCH 1/5] Avoid selecting stabilizer method when noise model contains rotational gates --- .../fix_automethod_stabilizer-90963b34bd5b4439.yaml | 6 ++++++ src/simulators/circuit_executor.hpp | 3 ++- src/simulators/stabilizer/stabilizer_state.hpp | 13 +++++++++++++ src/simulators/state.hpp | 4 ++++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml diff --git a/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml b/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml new file mode 100644 index 0000000000..f026d243c0 --- /dev/null +++ b/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed `stabilizer` was selected with `method="automatic" `when using + noise model with `rx`, `ry` or `rz` gates. + This is side effect of implementing rotational gates in stabilizer PR #1938 diff --git a/src/simulators/circuit_executor.hpp b/src/simulators/circuit_executor.hpp index 02f00224a6..0c2a73e093 100644 --- a/src/simulators/circuit_executor.hpp +++ b/src/simulators/circuit_executor.hpp @@ -1126,7 +1126,8 @@ bool Executor::validate_state(const Config &config, } // Check if a noise model valid for state ops - bool noise_valid = noise.is_ideal() || state.opset().contains(noise.opset()); + bool noise_valid = + noise.is_ideal() || state.validate_noise_ops(noise.opset()); if (throw_except && !noise_valid) { error_msg << "Noise model contains invalid instructions "; error_msg << state.opset().difference(noise.opset()); diff --git a/src/simulators/stabilizer/stabilizer_state.hpp b/src/simulators/stabilizer/stabilizer_state.hpp index 26ab0f418e..7b2dae9b85 100644 --- a/src/simulators/stabilizer/stabilizer_state.hpp +++ b/src/simulators/stabilizer/stabilizer_state.hpp @@ -107,6 +107,8 @@ class State : public QuantumState::State { bool validate_parameters(const std::vector &ops) const override; + bool validate_noise_ops(const Operations::OpSet &ops) const override; + protected: //----------------------------------------------------------------------- // Apply instructions @@ -271,6 +273,17 @@ bool State::validate_parameters(const std::vector &ops) const { return true; } +bool State::validate_noise_ops(const Operations::OpSet &ops) const { + if (BaseState::opset_.contains(ops)) { + // disable rx, ry, rz gates for noise model for stabilizer + if (ops.contains_gates("rx") || ops.contains_gates("ry") || + ops.contains_gates("rz")) { + return false; + } + return true; + } + return false; +} //========================================================================= // Implementation: apply operations //========================================================================= diff --git a/src/simulators/state.hpp b/src/simulators/state.hpp index ee5613328a..eba74990aa 100644 --- a/src/simulators/state.hpp +++ b/src/simulators/state.hpp @@ -120,6 +120,10 @@ class Base { validate_parameters(const std::vector &ops) const { return true; } + // validate noise model for this method + virtual bool validate_noise_ops(const Operations::OpSet &ops) const { + return opset_.contains(ops); + } //----------------------------------------------------------------------- // ClassicalRegister methods From 618b74de57faedc0f52ff7be50c85a788023bfe4 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 8 Nov 2023 16:46:07 +0900 Subject: [PATCH 2/5] remove checking noise opsets, change priority selecting density_matrix --- .../fix_automethod_stabilizer-90963b34bd5b4439.yaml | 7 +++++-- src/controllers/aer_controller.hpp | 10 +++++----- src/simulators/circuit_executor.hpp | 2 +- src/simulators/stabilizer/stabilizer_state.hpp | 13 ------------- src/simulators/state.hpp | 4 ---- 5 files changed, 11 insertions(+), 25 deletions(-) diff --git a/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml b/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml index f026d243c0..92c8c46c03 100644 --- a/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml +++ b/releasenotes/notes/fix_automethod_stabilizer-90963b34bd5b4439.yaml @@ -1,6 +1,9 @@ --- fixes: - | - Fixed `stabilizer` was selected with `method="automatic" `when using - noise model with `rx`, `ry` or `rz` gates. + Fixed `stabilizer` was selected with `method="automatic" ` when simulating + circuits with rotational gates with noise models for small number of qubits + even it is faster to calculate with `density_matrix` method. + This fix checks if `density_matrix` method with noise model is faster or not + at first and then check using `stabilizer` method. This is side effect of implementing rotational gates in stabilizer PR #1938 diff --git a/src/controllers/aer_controller.hpp b/src/controllers/aer_controller.hpp index d216b4ff9e..baa9d5d85d 100755 --- a/src/controllers/aer_controller.hpp +++ b/src/controllers/aer_controller.hpp @@ -833,22 +833,22 @@ Controller::simulation_methods(const Config &config, Method Controller::automatic_simulation_method( const Config &config, const Circuit &circ, const Noise::NoiseModel &noise_model) const { - // If circuit and noise model are Clifford run on Stabilizer simulator - if (validate_method(Method::stabilizer, config, circ, noise_model, false)) { - return Method::stabilizer; - } // For noisy simulations we enable the density matrix method if // shots > 2 ** num_qubits. This is based on a rough estimate that // a single shot of the density matrix simulator is approx 2 ** nq // times slower than a single shot of statevector due the increased // dimension - if (noise_model.has_quantum_errors() && circ.num_qubits < 64 && + if (noise_model.has_quantum_errors() && circ.num_qubits < 30 && circ.shots > (1ULL << circ.num_qubits) && validate_method(Method::density_matrix, config, circ, noise_model, false) && circ.can_sample) { return Method::density_matrix; } + // If circuit and noise model are Clifford run on Stabilizer simulator + if (validate_method(Method::stabilizer, config, circ, noise_model, false)) { + return Method::stabilizer; + } // If the special conditions for stabilizer or density matrix are // not satisfied we choose simulation method based on supported diff --git a/src/simulators/circuit_executor.hpp b/src/simulators/circuit_executor.hpp index 0c2a73e093..8b0920f1ae 100644 --- a/src/simulators/circuit_executor.hpp +++ b/src/simulators/circuit_executor.hpp @@ -1127,7 +1127,7 @@ bool Executor::validate_state(const Config &config, // Check if a noise model valid for state ops bool noise_valid = - noise.is_ideal() || state.validate_noise_ops(noise.opset()); + noise.is_ideal() || state.opset().contains(noise.opset()); if (throw_except && !noise_valid) { error_msg << "Noise model contains invalid instructions "; error_msg << state.opset().difference(noise.opset()); diff --git a/src/simulators/stabilizer/stabilizer_state.hpp b/src/simulators/stabilizer/stabilizer_state.hpp index 7b2dae9b85..26ab0f418e 100644 --- a/src/simulators/stabilizer/stabilizer_state.hpp +++ b/src/simulators/stabilizer/stabilizer_state.hpp @@ -107,8 +107,6 @@ class State : public QuantumState::State { bool validate_parameters(const std::vector &ops) const override; - bool validate_noise_ops(const Operations::OpSet &ops) const override; - protected: //----------------------------------------------------------------------- // Apply instructions @@ -273,17 +271,6 @@ bool State::validate_parameters(const std::vector &ops) const { return true; } -bool State::validate_noise_ops(const Operations::OpSet &ops) const { - if (BaseState::opset_.contains(ops)) { - // disable rx, ry, rz gates for noise model for stabilizer - if (ops.contains_gates("rx") || ops.contains_gates("ry") || - ops.contains_gates("rz")) { - return false; - } - return true; - } - return false; -} //========================================================================= // Implementation: apply operations //========================================================================= diff --git a/src/simulators/state.hpp b/src/simulators/state.hpp index eba74990aa..ee5613328a 100644 --- a/src/simulators/state.hpp +++ b/src/simulators/state.hpp @@ -120,10 +120,6 @@ class Base { validate_parameters(const std::vector &ops) const { return true; } - // validate noise model for this method - virtual bool validate_noise_ops(const Operations::OpSet &ops) const { - return opset_.contains(ops); - } //----------------------------------------------------------------------- // ClassicalRegister methods From 77d5fa874687f02ffd96f02f07314e400d381c8a Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 8 Nov 2023 16:51:40 +0900 Subject: [PATCH 3/5] format --- src/simulators/circuit_executor.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/simulators/circuit_executor.hpp b/src/simulators/circuit_executor.hpp index 8b0920f1ae..02f00224a6 100644 --- a/src/simulators/circuit_executor.hpp +++ b/src/simulators/circuit_executor.hpp @@ -1126,8 +1126,7 @@ bool Executor::validate_state(const Config &config, } // Check if a noise model valid for state ops - bool noise_valid = - noise.is_ideal() || state.opset().contains(noise.opset()); + bool noise_valid = noise.is_ideal() || state.opset().contains(noise.opset()); if (throw_except && !noise_valid) { error_msg << "Noise model contains invalid instructions "; error_msg << state.opset().difference(noise.opset()); From d6d3aec22407fb9301558f81a970f9ec8740189c Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 8 Nov 2023 18:06:16 +0900 Subject: [PATCH 4/5] modify test cases use auto method result may change by this PR --- .../aer_simulator/test_auto_method.py | 30 ++++++++++++++----- .../aer_simulator/test_thread_management.py | 13 ++++++-- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/test/terra/backends/aer_simulator/test_auto_method.py b/test/terra/backends/aer_simulator/test_auto_method.py index 70fcb0d175..53adc9fb66 100644 --- a/test/terra/backends/aer_simulator/test_auto_method.py +++ b/test/terra/backends/aer_simulator/test_auto_method.py @@ -48,7 +48,7 @@ class TestSimulationMethod(SimulatorTestCase): # --------------------------------------------------------------------- def test_auto_method_clifford_circuits(self): - """Test statevector method is used for Clifford circuit""" + """Test stabilizer method is used for Clifford circuit""" # Test circuits backend = self.backend() shots = 100 @@ -59,7 +59,7 @@ def test_auto_method_clifford_circuits(self): self.compare_result_metadata(result, circuits, "method", "stabilizer") def test_auto_method_clifford_circuits_and_reset_noise(self): - """Test statevector method is used for Clifford circuit""" + """Test stabilizer method is used for Clifford circuit""" # Test noise model noise_circs = [Reset(), IGate()] noise_probs = [0.5, 0.5] @@ -69,7 +69,7 @@ def test_auto_method_clifford_circuits_and_reset_noise(self): backend = self.backend(noise_model=noise_model) # Test circuits - shots = 100 + shots = 4 circuits = ref_2q_clifford.cz_gate_circuits_deterministic(final_measure=True) result = backend.run(circuits, shots=shots).result() success = getattr(result, "success", False) @@ -77,7 +77,7 @@ def test_auto_method_clifford_circuits_and_reset_noise(self): self.compare_result_metadata(result, circuits, "method", "stabilizer") def test_auto_method_clifford_circuits_and_pauli_noise(self): - """Test statevector method is used for Clifford circuit""" + """Test stabilizer method is used for Clifford circuit""" # Noise Model error = pauli_error([["XX", 0.5], ["II", 0.5]]) noise_model = NoiseModel() @@ -85,15 +85,31 @@ def test_auto_method_clifford_circuits_and_pauli_noise(self): backend = self.backend(noise_model=noise_model) # Test circuits - shots = 100 + shots = 4 circuits = ref_2q_clifford.cz_gate_circuits_deterministic(final_measure=True) result = backend.run(circuits, shots=shots).result() success = getattr(result, "success", False) self.assertTrue(success) self.compare_result_metadata(result, circuits, "method", "stabilizer") + def test_auto_method_clifford_circuits_and_pauli_noise_with_many_shots(self): + """Test density_matrix method is used for Clifford circuit""" + # Noise Model + error = pauli_error([["XX", 0.5], ["II", 0.5]]) + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(error, ["cz", "cx"]) + backend = self.backend(noise_model=noise_model) + + # Test circuits + shots = 1000 + circuits = ref_2q_clifford.cz_gate_circuits_deterministic(final_measure=True) + result = backend.run(circuits, shots=shots).result() + success = getattr(result, "success", False) + self.assertTrue(success) + self.compare_result_metadata(result, circuits, "method", "density_matrix") + def test_auto_method_clifford_circuits_and_unitary_noise(self): - """Test statevector method is used for Clifford circuit""" + """Test density_matrix method is used for Clifford circuit""" # Noise Model error = mixed_unitary_error( [(Pauli("XX").to_matrix(), 0.5), (Pauli("II").to_matrix(), 0.5)] @@ -110,7 +126,7 @@ def test_auto_method_clifford_circuits_and_unitary_noise(self): self.compare_result_metadata(result, circuits, "method", "density_matrix") def test_auto_method_clifford_circuits_and_kraus_noise(self): - """Test statevector method is used for Clifford circuit""" + """Test density_matrix method is used for Clifford circuit""" # Noise Model error = amplitude_damping_error(0.5) noise_model = NoiseModel() diff --git a/test/terra/backends/aer_simulator/test_thread_management.py b/test/terra/backends/aer_simulator/test_thread_management.py index 003cb92372..60154e8c25 100644 --- a/test/terra/backends/aer_simulator/test_thread_management.py +++ b/test/terra/backends/aer_simulator/test_thread_management.py @@ -147,7 +147,9 @@ def test_parallel_defaults_single_ideal(self): def test_parallel_defaults_single_noise(self): """Test parallel thread assignment defaults""" backend = self.backend( - noise_model=self.dummy_noise_model(), **self.backend_options_parallel() + method="statevector", + noise_model=self.dummy_noise_model(), + **self.backend_options_parallel(), ) max_threads = self.available_threads() @@ -209,7 +211,9 @@ def test_parallel_defaults_multi_ideal(self): def test_parallel_defaults_multi_noise(self): """Test parallel thread assignment defaults""" backend = self.backend( - noise_model=self.dummy_noise_model(), **self.backend_options_parallel() + method="statevector", + noise_model=self.dummy_noise_model(), + **self.backend_options_parallel(), ) max_threads = self.available_threads() @@ -295,7 +299,9 @@ def test_parallel_thread_assignment(self, custom_max_threads): # Test single circuit, with noise # Parallel experiments should always be 1 # parallel shots should be greater than 1 - backend = self.backend(noise_model=self.dummy_noise_model(), **parallel_opts) + backend = self.backend( + method="statevector", noise_model=self.dummy_noise_model(), **parallel_opts + ) circuits = self.dummy_circuit(1) result = backend.run(circuits, shots=shots).result() for threads in self.threads_used(result): @@ -531,6 +537,7 @@ def test_parallel_shot_thread_multi_noise(self): max_threads = self.available_threads() backend = self.backend( + method="statevector", noise_model=self.dummy_noise_model(), **self.backend_options_parallel(shot_threads=max_threads), ) From 91fcc4a24d2d9be9725c59fd114baadb1a76f77b Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 8 Nov 2023 18:36:44 +0900 Subject: [PATCH 5/5] modify one more test case --- test/terra/backends/aer_simulator/test_measure.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/terra/backends/aer_simulator/test_measure.py b/test/terra/backends/aer_simulator/test_measure.py index fd39d68042..aaf40b598e 100644 --- a/test/terra/backends/aer_simulator/test_measure.py +++ b/test/terra/backends/aer_simulator/test_measure.py @@ -142,7 +142,8 @@ def test_measure_sampling_with_quantum_noise(self, method, device): targets = ref_measure.measure_counts_deterministic(shots) result = backend.run(circuits, shots=shots).result() self.assertSuccess(result) - sampling = method == "density_matrix" or method == "tensor_network" + method_used = result.results[0].metadata.get("method") + sampling = method_used == "density_matrix" or method_used == "tensor_network" self.compare_result_metadata(result, circuits, "measure_sampling", sampling) # ---------------------------------------------------------------------