From 0b34234428ee4cf2eb3042200517ec17441dce61 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Mon, 13 May 2024 15:50:56 +0900 Subject: [PATCH 1/4] Add support for ECR gate --- qiskit_aer/backends/aer_simulator.py | 21 ++++++++++++++++--- qiskit_aer/backends/backend_utils.py | 3 +++ .../add_ecr_to_mps-0eec56596fc486c7.yaml | 8 +++++++ .../extended_stabilizer_state.hpp | 17 ++++++++++++--- src/simulators/extended_stabilizer/gates.hpp | 4 +++- .../matrix_product_state.hpp | 12 +++++++---- .../matrix_product_state_internal.hpp | 3 ++- .../backends/aer_simulator/test_cliffords.py | 8 ++----- 8 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml diff --git a/qiskit_aer/backends/aer_simulator.py b/qiskit_aer/backends/aer_simulator.py index 958a10ba89..d600f62480 100644 --- a/qiskit_aer/backends/aer_simulator.py +++ b/qiskit_aer/backends/aer_simulator.py @@ -744,6 +744,9 @@ def __init__( backend_options=backend_options, ) + if "basis_gates" in backend_options.items(): + self._check_basis_gates(backend_options["basis_gates"]) + @classmethod def _default_options(cls): return Options( @@ -897,11 +900,12 @@ def configuration(self): config = copy.copy(self._configuration) for key, val in self._options_configuration.items(): setattr(config, key, val) + + method = getattr(self.options, "method", "automatic") + # Update basis gates based on custom options, config, method, # and noise model - config.custom_instructions = self._CUSTOM_INSTR[ - getattr(self.options, "method", "automatic") - ] + config.custom_instructions = self._CUSTOM_INSTR[method] config.basis_gates = self._cached_basis_gates + config.custom_instructions return config @@ -932,6 +936,9 @@ def set_option(self, key, value): f" are: {self.available_methods()}" ) self._set_method_config(value) + if key == "basis_gates": + self._check_basis_gates(value) + super().set_option(key, value) if key in ["method", "noise_model", "basis_gates"]: self._cached_basis_gates = self._basis_gates() @@ -1046,3 +1053,11 @@ def _set_method_config(self, method=None): self._set_configuration_option("description", description) self._set_configuration_option("n_qubits", n_qubits) + + def _check_basis_gates(self, basis_gates): + method = getattr(self.options, "method", "automatic") + # check if basis_gates contains non-supported gates + if method is not "automatic": + for gate in basis_gates: + if gate not in self._BASIS_GATES[method]: + raise AerError(f"Invalid gate {gate} for simulation method {method}.") diff --git a/qiskit_aer/backends/backend_utils.py b/qiskit_aer/backends/backend_utils.py index 09a199380b..9ca1888ec7 100644 --- a/qiskit_aer/backends/backend_utils.py +++ b/qiskit_aer/backends/backend_utils.py @@ -193,6 +193,7 @@ "cswap", "diagonal", "initialize", + "ecr", ] ), "stabilizer": sorted( @@ -241,6 +242,7 @@ "ccz", "delay", "pauli", + "ecr", ] ), "unitary": sorted( @@ -405,6 +407,7 @@ "delay", "pauli", "mcx_gray", + "ecr", ] ), } diff --git a/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml b/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml new file mode 100644 index 0000000000..9205d37696 --- /dev/null +++ b/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + `matrix_product_state` and `tensor_network`methods now support ecr gate. +fixes: + - | + Add check if `basis_gates` backend option has unsupported gate for + the `method` diff --git a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp index cc8c91adf1..1e750862a4 100644 --- a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp +++ b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp @@ -44,9 +44,9 @@ const Operations::OpSet StateOpSet( Operations::OpType::save_statevec, }, // Operations::OpType::save_expval, Operations::OpType::save_expval_var}, // Gates - {"CX", "u0", "u1", "p", "cx", "cz", "swap", "id", - "x", "y", "z", "h", "s", "sdg", "sx", "sxdg", - "t", "tdg", "ccx", "ccz", "delay", "pauli"}); + {"CX", "u0", "u1", "p", "cx", "cz", "swap", "id", + "x", "y", "z", "h", "s", "sdg", "sx", "sxdg", + "t", "tdg", "ccx", "ccz", "delay", "pauli", "ecr"}); using chpauli_t = CHSimulator::pauli_t; using chstate_t = CHSimulator::Runner; @@ -220,6 +220,7 @@ const stringmap_t State::gateset_({ {"cx", Gates::cx}, // Controlled-X gate (CNOT) {"cz", Gates::cz}, // Controlled-Z gate {"swap", Gates::swap}, // SWAP gate + {"ecr", Gates::ecr}, // ECR Gate // Three-qubit gates {"ccx", Gates::ccx}, // Controlled-CX gate (Toffoli) {"ccz", Gates::ccz}, // Constrolled-CZ gate (H3 Toff H3) @@ -694,6 +695,16 @@ void State::apply_gate(const Operations::Op &op, RngEngine &rng, uint_t rank) { case Gates::pauli: apply_pauli(op.qubits, op.string_params[0], rank); break; + case Gates::ecr: + BaseState::qreg_.apply_h(op.qubits[1], rank); + BaseState::qreg_.apply_s(op.qubits[0], rank); + BaseState::qreg_.apply_z(op.qubits[1], rank); // sdg(1) + BaseState::qreg_.apply_s(op.qubits[1], rank); // sdg(1) + BaseState::qreg_.apply_h(op.qubits[1], rank); + BaseState::qreg_.apply_cx(op.qubits[0], op.qubits[1], rank); + BaseState::qreg_.apply_x(op.qubits[0], rank); + BaseState::qreg_.apply_x(op.qubits[1], rank); + break; default: // u0 or Identity break; } diff --git a/src/simulators/extended_stabilizer/gates.hpp b/src/simulators/extended_stabilizer/gates.hpp index 3df76b37eb..c4f357824c 100644 --- a/src/simulators/extended_stabilizer/gates.hpp +++ b/src/simulators/extended_stabilizer/gates.hpp @@ -58,7 +58,8 @@ enum class Gates { swap, ccx, ccz, - pauli + pauli, + ecr, }; enum class Gatetypes { pauli, clifford, non_clifford }; @@ -85,6 +86,7 @@ const AER::stringmap_t gate_types_ = { {"cx", Gatetypes::clifford}, // Controlled-X gate (CNOT) {"cz", Gatetypes::clifford}, // Controlled-Z gate {"swap", Gatetypes::clifford}, // SWAP gate + {"ecr", Gatetypes::clifford}, // ECR Gate // Three-qubit gates {"ccx", Gatetypes::non_clifford}, // Controlled-CX gate (Toffoli) {"ccz", Gatetypes::non_clifford}, // Controlled-CZ gate (H3 Toff H3) diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 51df5dd27e..1cfeb9b43d 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -75,10 +75,10 @@ const Operations::OpSet StateOpSet( OpType::jump, OpType::mark}, // Gates - {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "p", - "u1", "u2", "u3", "u", "U", "CX", "cx", "cy", "cz", "cp", - "cu1", "swap", "ccx", "sx", "sxdg", "r", "rx", "ry", "rz", "rxx", - "ryy", "rzz", "rzx", "csx", "delay", "cswap", "pauli"}); + {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "p", + "u1", "u2", "u3", "u", "U", "CX", "cx", "cy", "cz", "cp", + "cu1", "swap", "ccx", "sx", "sxdg", "r", "rx", "ry", "rz", "rxx", + "ryy", "rzz", "rzx", "csx", "delay", "cswap", "pauli", "ecr"}); //========================================================================= // Matrix Product State subclass @@ -296,6 +296,7 @@ const stringmap_t {"ryy", Gates::ryy}, // Pauli-YY rotation gate {"rzz", Gates::rzz}, // Pauli-ZZ rotation gate {"rzx", Gates::rzx}, // Pauli-ZX rotation gate + {"ecr", Gates::ecr}, // ECR Gate /* Three-qubit gates */ {"ccx", Gates::ccx}, // Controlled-CX gate (Toffoli) {"cswap", Gates::cswap}, @@ -673,6 +674,9 @@ void State::apply_gate(const Operations::Op &op) { case Gates::pauli: apply_pauli(op.qubits, op.string_params[0]); break; + case Gates::ecr: + qreg_.apply_matrix(op.qubits, Linalg::Matrix::ECR); + break; default: // We shouldn't reach here unless there is a bug in gateset throw std::invalid_argument( diff --git a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp index e6a82c28cc..1180e6cddf 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -58,7 +58,8 @@ enum Gates { csx, // two qubit ccx, cswap, // three qubit - pauli + pauli, + ecr, }; // enum class Direction {RIGHT, LEFT}; diff --git a/test/terra/backends/aer_simulator/test_cliffords.py b/test/terra/backends/aer_simulator/test_cliffords.py index b6c430ae0e..df0c2994d0 100644 --- a/test/terra/backends/aer_simulator/test_cliffords.py +++ b/test/terra/backends/aer_simulator/test_cliffords.py @@ -28,10 +28,6 @@ "tensor_network", ] -SUPPORTED_ECR_METHODS = [ - "stabilizer", -] - @ddt class TestCliffords(SimulatorTestCase): @@ -249,11 +245,11 @@ def test_pauli_gate_deterministic(self, method, device): # --------------------------------------------------------------------- # Test ecr gate # --------------------------------------------------------------------- - @supported_methods(SUPPORTED_ECR_METHODS) + @supported_methods(SUPPORTED_METHODS) def test_ecr_gate_nondeterministic(self, method, device): """Test ecr gate circuits""" backend = self.backend(method=method, device=device, seed_simulator=self.SEED) - shots = 100 + shots = 1000 circuits = ref_2q_clifford.ecr_gate_circuits_nondeterministic(final_measure=True) targets = ref_2q_clifford.ecr_gate_counts_nondeterministic(shots) result = backend.run(circuits, shots=shots).result() From 332400f702cffa467dc8c889b950118b8caa97bf Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Mon, 13 May 2024 16:02:12 +0900 Subject: [PATCH 2/4] replace is not to != --- qiskit_aer/backends/aer_simulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_aer/backends/aer_simulator.py b/qiskit_aer/backends/aer_simulator.py index d600f62480..2ae1c6d72a 100644 --- a/qiskit_aer/backends/aer_simulator.py +++ b/qiskit_aer/backends/aer_simulator.py @@ -1057,7 +1057,7 @@ def _set_method_config(self, method=None): def _check_basis_gates(self, basis_gates): method = getattr(self.options, "method", "automatic") # check if basis_gates contains non-supported gates - if method is not "automatic": + if method != "automatic": for gate in basis_gates: if gate not in self._BASIS_GATES[method]: raise AerError(f"Invalid gate {gate} for simulation method {method}.") From c49d05d809c0cf6a5f9b8a74fbebbb260f057fc1 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Mon, 13 May 2024 16:16:04 +0900 Subject: [PATCH 3/4] fix release note --- releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml b/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml index 9205d37696..9505b6025e 100644 --- a/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml +++ b/releasenotes/notes/add_ecr_to_mps-0eec56596fc486c7.yaml @@ -1,8 +1,7 @@ --- features: - | - `matrix_product_state` and `tensor_network`methods now support ecr gate. -fixes: - - | + `matrix_product_state`, `extended_stabilizer` and `tensor_network` methods + now support ecr gate. Add check if `basis_gates` backend option has unsupported gate for the `method` From 65bfb37db5baa10388babd43e989f81beaab98e0 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 24 May 2024 11:54:47 +0900 Subject: [PATCH 4/4] Fix ecr implementation for stabilizer/extended-stabilizer --- .../extended_stabilizer/extended_stabilizer_state.hpp | 6 ++---- src/simulators/stabilizer/stabilizer_state.hpp | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp index 1e750862a4..95ef04dd3a 100644 --- a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp +++ b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp @@ -696,14 +696,12 @@ void State::apply_gate(const Operations::Op &op, RngEngine &rng, uint_t rank) { apply_pauli(op.qubits, op.string_params[0], rank); break; case Gates::ecr: - BaseState::qreg_.apply_h(op.qubits[1], rank); BaseState::qreg_.apply_s(op.qubits[0], rank); - BaseState::qreg_.apply_z(op.qubits[1], rank); // sdg(1) - BaseState::qreg_.apply_s(op.qubits[1], rank); // sdg(1) + BaseState::qreg_.apply_sdag(op.qubits[1], rank); BaseState::qreg_.apply_h(op.qubits[1], rank); + BaseState::qreg_.apply_sdag(op.qubits[1], rank); BaseState::qreg_.apply_cx(op.qubits[0], op.qubits[1], rank); BaseState::qreg_.apply_x(op.qubits[0], rank); - BaseState::qreg_.apply_x(op.qubits[1], rank); break; default: // u0 or Identity break; diff --git a/src/simulators/stabilizer/stabilizer_state.hpp b/src/simulators/stabilizer/stabilizer_state.hpp index cd0e18f678..6da68dbfb4 100644 --- a/src/simulators/stabilizer/stabilizer_state.hpp +++ b/src/simulators/stabilizer/stabilizer_state.hpp @@ -387,14 +387,14 @@ void State::apply_gate(const Operations::Op &op) { apply_pauli(op.qubits, op.string_params[0]); break; case Gates::ecr: - BaseState::qreg_.append_h(op.qubits[1]); BaseState::qreg_.append_s(op.qubits[0]); - BaseState::qreg_.append_z(op.qubits[1]); // sdg(1) - BaseState::qreg_.append_s(op.qubits[1]); // sdg(1) + BaseState::qreg_.append_z(op.qubits[1]); + BaseState::qreg_.append_s(op.qubits[1]); BaseState::qreg_.append_h(op.qubits[1]); + BaseState::qreg_.append_z(op.qubits[1]); + BaseState::qreg_.append_s(op.qubits[1]); BaseState::qreg_.append_cx(op.qubits[0], op.qubits[1]); BaseState::qreg_.append_x(op.qubits[0]); - BaseState::qreg_.append_x(op.qubits[1]); break; case Gates::rx: pi2 = (int_t)std::round(std::real(op.params[0]) * 2.0 / M_PI) & 3;