Add support for rotation gates (#2147)

* add rotation gates

* add cr* gates to operations.hpp

* fix test for stabilkize/extended-stabilizer

* fix test again
This commit is contained in:
Jun Doi 2024-05-28 13:39:49 +09:00 committed by GitHub
parent 83d679efd5
commit 5e9be0b30c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 135 additions and 91 deletions

View File

@ -820,6 +820,7 @@ def _assemble_op(
"mcu", "mcu1", "mcu2", "mcu3", "mcx", "mcx_gray", "mcy", "mcz", "p", "r",
"rx", "rxx", "ry", "ryy", "rz", "rzx", "rzz", "s", "sdg", "swap", "sx", "sxdg",
"t", "tdg", "u", "x", "y", "z", "u1", "u2", "u3", "cu", "cu1", "cu2", "cu3",
"crx", "cry", "crz",
}:
aer_circ.gate(name, qubits, params, [], conditional_reg, aer_cond_expr,
label if label else name)

View File

@ -91,6 +91,9 @@ BASIS_GATES = {
"rzx",
"ccx",
"ccz",
"crx",
"cry",
"crz",
"cswap",
"mcx",
"mcy",
@ -217,8 +220,6 @@ BASIS_GATES = {
"delay",
"pauli",
"ecr",
"rx",
"ry",
"rz",
]
),
@ -245,6 +246,7 @@ BASIS_GATES = {
"ccz",
"delay",
"pauli",
"rz",
]
),
"unitary": sorted(
@ -286,6 +288,9 @@ BASIS_GATES = {
"ccx",
"ccz",
"cswap",
"crx",
"cry",
"crz",
"mcx",
"mcy",
"mcz",
@ -387,6 +392,9 @@ BASIS_GATES = {
"ccx",
"ccz",
"cswap",
"crx",
"cry",
"crz",
"mcx",
"mcy",
"mcz",

View File

@ -0,0 +1,8 @@
---
features:
- |
Add `rz` gate with n*pi/2 cases to `extended_stabilizer` method
as well as `stabilizer` method.
Add `crx`, `cry` and `crz` gates to `statevector` and `tensor_netowork`
methods.

View File

@ -724,27 +724,29 @@ inline void check_duplicate_qubits(const Op &op) {
}
inline void check_gate_params(const Op &op) {
const stringmap_t<std::tuple<int_t, int_t>> param_tables(
{{"u1", {1, 1}}, {"u2", {1, 2}}, {"u3", {1, 3}},
{"u", {1, 3}}, {"U", {1, 3}}, {"CX", {2, 0}},
{"cx", {2, 0}}, {"cz", {2, 0}}, {"cy", {2, 0}},
{"cp", {2, 1}}, {"cu1", {2, 1}}, {"cu2", {2, 2}},
{"cu3", {2, 3}}, {"swap", {2, 0}}, {"id", {0, 0}},
{"p", {1, 1}}, {"x", {1, 0}}, {"y", {1, 0}},
{"z", {1, 0}}, {"h", {1, 0}}, {"s", {1, 0}},
{"sdg", {1, 0}}, {"t", {1, 0}}, {"tdg", {1, 0}},
{"r", {1, 2}}, {"rx", {1, 1}}, {"ry", {1, 1}},
{"rz", {1, 1}}, {"rxx", {2, 1}}, {"ryy", {2, 1}},
{"rzz", {2, 1}}, {"rzx", {2, 1}}, {"ccx", {3, 0}},
{"ccz", {3, 0}}, {"cswap", {3, 0}}, {"mcx", {1, 0}},
{"mcy", {1, 0}}, {"mcz", {1, 0}}, {"mcu1", {1, 1}},
{"mcu2", {1, 2}}, {"mcu3", {1, 3}}, {"mcswap", {2, 0}},
{"mcphase", {1, 1}}, {"mcr", {1, 1}}, {"mcrx", {1, 1}},
{"mcry", {1, 1}}, {"mcrz", {1, 1}}, {"sx", {1, 0}},
{"sxdg", {1, 0}}, {"csx", {2, 0}}, {"mcsx", {1, 0}},
{"csxdg", {2, 0}}, {"mcsxdg", {1, 0}}, {"delay", {1, 0}},
{"pauli", {1, 0}}, {"mcx_gray", {1, 0}}, {"cu", {2, 4}},
{"mcu", {1, 4}}, {"mcp", {1, 1}}, {"ecr", {2, 0}}});
const stringmap_t<std::tuple<int_t, int_t>> param_tables({
{"u1", {1, 1}}, {"u2", {1, 2}}, {"u3", {1, 3}},
{"u", {1, 3}}, {"U", {1, 3}}, {"CX", {2, 0}},
{"cx", {2, 0}}, {"cz", {2, 0}}, {"cy", {2, 0}},
{"cp", {2, 1}}, {"cu1", {2, 1}}, {"cu2", {2, 2}},
{"cu3", {2, 3}}, {"swap", {2, 0}}, {"id", {0, 0}},
{"p", {1, 1}}, {"x", {1, 0}}, {"y", {1, 0}},
{"z", {1, 0}}, {"h", {1, 0}}, {"s", {1, 0}},
{"sdg", {1, 0}}, {"t", {1, 0}}, {"tdg", {1, 0}},
{"r", {1, 2}}, {"rx", {1, 1}}, {"ry", {1, 1}},
{"rz", {1, 1}}, {"rxx", {2, 1}}, {"ryy", {2, 1}},
{"rzz", {2, 1}}, {"rzx", {2, 1}}, {"ccx", {3, 0}},
{"ccz", {3, 0}}, {"cswap", {3, 0}}, {"mcx", {1, 0}},
{"mcy", {1, 0}}, {"mcz", {1, 0}}, {"mcu1", {1, 1}},
{"mcu2", {1, 2}}, {"mcu3", {1, 3}}, {"mcswap", {2, 0}},
{"mcphase", {1, 1}}, {"mcr", {1, 1}}, {"mcrx", {1, 1}},
{"mcry", {1, 1}}, {"mcrz", {1, 1}}, {"sx", {1, 0}},
{"sxdg", {1, 0}}, {"csx", {2, 0}}, {"mcsx", {1, 0}},
{"csxdg", {2, 0}}, {"mcsxdg", {1, 0}}, {"delay", {1, 0}},
{"pauli", {1, 0}}, {"mcx_gray", {1, 0}}, {"cu", {2, 4}},
{"mcu", {1, 4}}, {"mcp", {1, 1}}, {"ecr", {2, 0}},
{"crx", {1, 1}}, {"cry", {1, 1}}, {"crz", {1, 1}},
});
auto it = param_tables.find(op.name);
if (it == param_tables.end()) {

View File

@ -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", "rz"});
using chpauli_t = CHSimulator::pauli_t;
using chstate_t = CHSimulator::Runner;
@ -89,6 +89,9 @@ public:
std::vector<SampleVector> sample_measure(const reg_t &qubits, uint_t shots,
RngEngine &rng) override;
bool
validate_parameters(const std::vector<Operations::Op> &ops) const override;
protected:
// Alongside the sample measure optimisaiton, we can parallelise
// circuit applicaiton over the states. This reduces the threading overhead
@ -211,6 +214,7 @@ const stringmap_t<Gates> State::gateset_({
{"sxdg", Gates::sxdg}, // Inverse sqrt(X) gate
{"t", Gates::t}, // T-gate (sqrt(S))
{"tdg", Gates::tdg}, // Conjguate-transpose of T gate
{"rz", Gates::rz}, // RZ gate (only support k * pi/2 cases)
// Waltz Gates
{"u0", Gates::u0}, // idle gate in multiples of X90
{"u1", Gates::u1}, // zero-X90 pulse waltz gate
@ -336,6 +340,23 @@ bool State::check_measurement_opt(InputIterator first,
return true;
}
bool State::validate_parameters(const std::vector<Operations::Op> &ops) const {
for (uint_t i = 0; i < ops.size(); i++) {
if (ops[i].type == OpType::gate) {
// check parameter of RZ gates
if (ops[i].name == "rz") {
double pi2 = std::real(ops[i].params[0]) * 2.0 / M_PI;
double pi2_int = (double)std::round(pi2);
if (!AER::Linalg::almost_equal(pi2, pi2_int)) {
return false;
}
}
}
}
return true;
}
//-------------------------------------------------------------------------
// Implementation: Operations
//-------------------------------------------------------------------------
@ -633,6 +654,7 @@ void State::apply_gate(const Operations::Op &op, RngEngine &rng) {
}
void State::apply_gate(const Operations::Op &op, RngEngine &rng, uint_t rank) {
int_t pi2;
auto it = gateset_.find(op.name);
if (it == gateset_.end()) {
throw std::invalid_argument("CH::State: Invalid gate operation \'" +
@ -694,6 +716,19 @@ 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::rz:
pi2 = (int_t)std::round(std::real(op.params[0]) * 2.0 / M_PI) & 3;
if (pi2 == 1) {
// S
BaseState::qreg_.apply_s(op.qubits[0], rank);
} else if (pi2 == 2) {
// Z
BaseState::qreg_.apply_z(op.qubits[0], rank);
} else if (pi2 == 3) {
// Sdg
BaseState::qreg_.apply_sdag(op.qubits[0], rank);
}
break;
default: // u0 or Identity
break;
}

View File

@ -58,7 +58,8 @@ enum class Gates {
swap,
ccx,
ccz,
pauli
pauli,
rz,
};
enum class Gatetypes { pauli, clifford, non_clifford };
@ -80,6 +81,7 @@ const AER::stringmap_t<Gatetypes> gate_types_ = {
{"tdg", Gatetypes::non_clifford}, // Conjguate-transpose of T gate
{"u1", Gatetypes::non_clifford}, // zero-X90 pulse waltz gate
{"p", Gatetypes::non_clifford}, // zero-X90 pulse waltz gate
{"rz", Gatetypes::clifford}, // RZ gate (only support k * pi/2 cases)
// Two-qubit gates
{"CX", Gatetypes::clifford}, // Controlled-X gate (CNOT)
{"cx", Gatetypes::clifford}, // Controlled-X gate (CNOT)

View File

@ -38,8 +38,8 @@ const Operations::OpSet StateOpSet(
OpType::save_amps_sq, OpType::save_stabilizer, OpType::save_clifford,
OpType::save_state, OpType::set_stabilizer, OpType::jump, OpType::mark},
// Gates
{"CX", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h",
"s", "sdg", "sx", "sxdg", "delay", "pauli", "ecr", "rx", "ry", "rz"});
{"CX", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h", "s", "sdg", "sx",
"sxdg", "delay", "pauli", "ecr", "rz"});
enum class Gates {
id,
@ -57,8 +57,6 @@ enum class Gates {
swap,
pauli,
ecr,
rx,
ry,
rz
};
@ -202,6 +200,7 @@ const stringmap_t<Gates> State::gateset_({
{"h", Gates::h}, // Hadamard gate (X + Z / sqrt(2))
{"sx", Gates::sx}, // Sqrt X gate.
{"sxdg", Gates::sxdg}, // Inverse Sqrt X gate.
{"rz", Gates::rz}, // RZ gate (only support k * pi/2 cases)
// Two-qubit gates
{"CX", Gates::cx}, // Controlled-X gate (CNOT)
{"cx", Gates::cx}, // Controlled-X gate (CNOT),
@ -210,9 +209,6 @@ const stringmap_t<Gates> State::gateset_({
{"swap", Gates::swap}, // SWAP gate
{"pauli", Gates::pauli}, // Pauli gate
{"ecr", Gates::ecr}, // ECR gate
{"rx", Gates::rx}, // RX gate (only support k * pi/2 cases)
{"ry", Gates::ry}, // RY gate (only support k * pi/2 cases)
{"rz", Gates::rz} // RZ gate (only support k * pi/2 cases)
});
//============================================================================
@ -257,8 +253,8 @@ void State::set_config(const Config &config) {
bool State::validate_parameters(const std::vector<Operations::Op> &ops) const {
for (uint_t i = 0; i < ops.size(); i++) {
if (ops[i].type == OpType::gate) {
// check parameter of R gates
if (ops[i].name == "rx" || ops[i].name == "ry" || ops[i].name == "rz") {
// check parameter of RZ gates
if (ops[i].name == "rz") {
double pi2 = std::real(ops[i].params[0]) * 2.0 / M_PI;
double pi2_int = (double)std::round(pi2);
@ -396,37 +392,6 @@ void State::apply_gate(const Operations::Op &op) {
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;
if (pi2 == 1) {
// HSH
BaseState::qreg_.append_h(op.qubits[0]);
BaseState::qreg_.append_s(op.qubits[0]);
BaseState::qreg_.append_h(op.qubits[0]);
} else if (pi2 == 2) {
// X
BaseState::qreg_.append_x(op.qubits[0]);
} else if (pi2 == 3) {
// HSdgH
BaseState::qreg_.append_h(op.qubits[0]);
BaseState::qreg_.append_z(op.qubits[0]);
BaseState::qreg_.append_s(op.qubits[0]);
BaseState::qreg_.append_h(op.qubits[0]);
}
break;
case Gates::ry:
pi2 = (int_t)std::round(std::real(op.params[0]) * 2.0 / M_PI) & 3;
if (pi2 == 1) {
BaseState::qreg_.append_h(op.qubits[0]);
BaseState::qreg_.append_x(op.qubits[0]);
} else if (pi2 == 2) {
// Y
BaseState::qreg_.append_y(op.qubits[0]);
} else if (pi2 == 3) {
BaseState::qreg_.append_x(op.qubits[0]);
BaseState::qreg_.append_h(op.qubits[0]);
}
break;
case Gates::rz:
pi2 = (int_t)std::round(std::real(op.params[0]) * 2.0 / M_PI) & 3;
if (pi2 == 1) {

View File

@ -66,14 +66,17 @@ const Operations::OpSet StateOpSet(
OpType::jump,
OpType::mark},
// Gates
{"u1", "u2", "u3", "u", "U", "CX", "cx", "cz",
"cy", "cp", "cu1", "cu2", "cu3", "swap", "id", "p",
"x", "y", "z", "h", "s", "sdg", "t", "tdg",
"r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx",
"ccx", "ccz", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2",
"mcu3", "mcswap", "mcr", "mcrx", "mcry", "mcrz", "sx", "sxdg",
"csx", "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "mcx_gray", "cu",
"mcu", "mcp", "ecr", "mcphase"});
{
"u1", "u2", "u3", "u", "U", "CX", "cx",
"cz", "cy", "cp", "cu1", "cu2", "cu3", "swap",
"id", "p", "x", "y", "z", "h", "s",
"sdg", "t", "tdg", "r", "rx", "ry", "rz",
"rxx", "ryy", "rzz", "rzx", "ccx", "ccz", "cswap",
"mcx", "mcy", "mcz", "mcu1", "mcu2", "mcu3", "mcswap",
"mcr", "mcrx", "mcry", "mcrz", "sx", "sxdg", "csx",
"mcsx", "csxdg", "mcsxdg", "delay", "pauli", "mcx_gray", "cu",
"mcu", "mcp", "ecr", "mcphase", "crx", "cry", "crz",
});
// Allowed gates enum class
enum class Gates {
@ -368,6 +371,9 @@ const stringmap_t<Gates> State<statevec_t>::gateset_(
{"csx", Gates::mcsx}, // Controlled-Sqrt(X) gate
{"csxdg", Gates::mcsxdg}, // Controlled-Sqrt(X)dg gate
{"ecr", Gates::ecr}, // ECR Gate
{"crx", Gates::mcrx}, // Controlled X-rotation gate
{"cry", Gates::mcry}, // Controlled Y-rotation gate
{"crz", Gates::mcrz}, // Controlled Z-rotation gate
/* 3-qubit gates */
{"ccx", Gates::mcx}, // Controlled-CX gate (Toffoli)
{"ccz", Gates::mcz}, // Controlled-CZ gate

View File

@ -72,9 +72,9 @@ const Operations::OpSet StateOpSet(
"sdg", "t", "tdg", "r", "rx", "ry", "rz",
"rxx", "ryy", "rzz", "rzx", "ccx", "ccz", "mcx",
"mcy", "mcz", "mcu1", "mcu2", "mcu3", "mcswap", "mcphase",
"mcr", "mcrx", "mcry", "mcry", "sx", "sxdg", "csx",
"mcr", "mcrx", "mcry", "mcrz", "sx", "sxdg", "csx",
"mcsx", "csxdg", "mcsxdg", "delay", "pauli", "mcx_gray", "cu",
"mcu", "mcp", "ecr", "cswap"});
"mcu", "mcp", "ecr", "cswap", "crx", "cry", "crz"});
// Allowed gates enum class
enum class Gates {
@ -361,6 +361,9 @@ const stringmap_t<Gates> State<tensor_net_t>::gateset_(
{"csx", Gates::mcsx}, // Controlled-Sqrt(X) gate
{"csxdg", Gates::mcsxdg}, // Controlled-Sqrt(X)dg gate
{"ecr", Gates::ecr}, // ECR Gate
{"crx", Gates::mcrx}, // Controlled X-rotation gate
{"cry", Gates::mcry}, // Controlled Y-rotation gate
{"crz", Gates::mcrz}, // Controlled Z-rotation gate
/* 3-qubit gates */
{"ccx", Gates::mcx}, // Controlled-CX gate (Toffoli)
{"ccz", Gates::mcz}, // Controlled-CZ gate

View File

@ -41,14 +41,16 @@ const Operations::OpSet StateOpSet(
Operations::OpType::save_state, Operations::OpType::set_unitary,
Operations::OpType::jump, Operations::OpType::mark},
// Gates
{"u1", "u2", "u3", "u", "U", "CX", "cx", "cz",
"cy", "cp", "cu1", "cu2", "cu3", "swap", "id", "p",
"x", "y", "z", "h", "s", "sdg", "t", "tdg",
"r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx",
"ccx", "ccz", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2",
"mcu3", "mcswap", "mcr", "mcrx", "mcry", "mcry", "sx", "sxdg",
"csx", "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "cu", "mcu",
"mcp", "ecr", "mcphase"});
{
"u1", "u2", "u3", "u", "U", "CX", "cx", "cz",
"cy", "cp", "cu1", "cu2", "cu3", "swap", "id", "p",
"x", "y", "z", "h", "s", "sdg", "t", "tdg",
"r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx",
"ccx", "ccz", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2",
"mcu3", "mcswap", "mcr", "mcrx", "mcry", "mcrz", "sx", "sxdg",
"csx", "mcsx", "csxdg", "mcsxdg", "delay", "pauli", "cu", "mcu",
"mcp", "ecr", "mcphase", "crx", "cry", "crz",
});
// Allowed gates enum class
enum class Gates {
@ -253,6 +255,9 @@ const stringmap_t<Gates> State<unitary_matrix_t>::gateset_({
{"csx", Gates::mcsx}, // Controlled-Sqrt(X) gate
{"csxdg", Gates::mcsxdg}, // Controlled-Sqrt(X)dg gate
{"ecr", Gates::ecr}, // ECR Gate
{"crx", Gates::mcrx}, // Controlled X-rotation gate
{"cry", Gates::mcry}, // Controlled Y-rotation gate
{"crz", Gates::mcrz}, // Controlled Z-rotation gate
// Three-qubit gates
{"ccx", Gates::mcx}, // Controlled-CX gate (Toffoli)
{"ccz", Gates::mcz}, // Controlled-CZ gate

View File

@ -214,7 +214,7 @@ class TestControlFlow(SimulatorTestCase):
self.assertEqual(len(counts), 1)
self.assertIn("0000 0", counts)
@data("statevector", "density_matrix", "matrix_product_state", "stabilizer")
@data("statevector", "density_matrix", "matrix_product_state")
def test_for_loop_builder(self, method):
backend = self.backend(method=method)
@ -266,7 +266,7 @@ class TestControlFlow(SimulatorTestCase):
self.assertEqual(len(counts), 1)
self.assertIn("01010", counts)
@data("statevector", "density_matrix", "matrix_product_state", "stabilizer")
@data("statevector", "density_matrix", "matrix_product_state")
def test_for_loop_break_builder(self, method):
backend = self.backend(method=method)
@ -309,7 +309,7 @@ class TestControlFlow(SimulatorTestCase):
self.assertEqual(len(counts), 1)
self.assertIn("11100 1", counts)
@data("statevector", "density_matrix", "matrix_product_state", "stabilizer")
@data("statevector", "density_matrix", "matrix_product_state")
def test_for_loop_continue_builder(self, method):
backend = self.backend(method=method)
@ -486,7 +486,7 @@ class TestControlFlow(SimulatorTestCase):
self.assertEqual(len(counts), 1)
self.assertIn("0 0", counts)
@data("statevector", "density_matrix", "matrix_product_state", "stabilizer")
@data("statevector", "density_matrix", "matrix_product_state")
def test_nested_loop(self, method):
backend = self.backend(method=method)

View File

@ -18,12 +18,21 @@ from qiskit import transpile
from test.terra.backends.simulator_test_case import SimulatorTestCase, supported_methods
SUPPORTED_METHODS = [
"automatic",
"statevector",
"density_matrix",
"matrix_product_state",
"tensor_network",
]
SUPPORTED_METHODS_RZ = [
"automatic",
"stabilizer",
"statevector",
"density_matrix",
"matrix_product_state",
"tensor_network",
"extended_stabilizer",
]
@ -50,7 +59,7 @@ class TestRotation(SimulatorTestCase):
# ---------------------------------------------------------------------
# Test rz-gate
# ---------------------------------------------------------------------
@supported_methods(SUPPORTED_METHODS)
@supported_methods(SUPPORTED_METHODS_RZ)
def test_rz_gate_deterministic(self, method, device):
"""Test rz-gate circuits"""
backend = self.backend(method=method, device=device, seed_simulator=self.SEED)

View File

@ -461,7 +461,7 @@ class TestParameterizedQobj(common.QiskitAerTestCase):
def test_global_phase_parameters(self):
"""Test parameterized global phase"""
backend = AerSimulator(method="extended_stabilizer")
backend = AerSimulator(method="extended_stabilizer", basis_gates=["h", "x", "u1"])
theta = Parameter("theta")
circ = QuantumCircuit(2)