From 86c09575ca9748cb28366821fc9223f2f261ff9d Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 11:38:06 +0100 Subject: [PATCH 01/28] =?UTF-8?q?=E2=9C=A8=20add=20new=20operation=20type?= =?UTF-8?q?=20`R`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- include/mqt-core/ir/operations/OpType.hpp | 1 + include/mqt-core/ir/operations/OpType.inc | 5 +++-- src/ir/operations/OpType.cpp | 2 ++ src/ir/operations/StandardOperation.cpp | 4 ++++ src/ir/operations/SymbolicOperation.cpp | 1 + 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/mqt-core/ir/operations/OpType.hpp b/include/mqt-core/ir/operations/OpType.hpp index 30ff8f98ab..abcb1540a3 100644 --- a/include/mqt-core/ir/operations/OpType.hpp +++ b/include/mqt-core/ir/operations/OpType.hpp @@ -90,6 +90,7 @@ std::string shortName(OpType opType); case RX: case RY: case RZ: + case R: return true; default: return false; diff --git a/include/mqt-core/ir/operations/OpType.inc b/include/mqt-core/ir/operations/OpType.inc index 2ed153d417..b06ed03e4f 100644 --- a/include/mqt-core/ir/operations/OpType.inc +++ b/include/mqt-core/ir/operations/OpType.inc @@ -32,8 +32,9 @@ HANDLE_OP_TYPE(14, SXdg, OpTypeInv, "sxdg") HANDLE_OP_TYPE(15, RX, OpTypeNone, "rx") HANDLE_OP_TYPE(16, RY, OpTypeNone, "ry") HANDLE_OP_TYPE(17, RZ, OpTypeDiag, "rz") +HANDLE_OP_TYPE(41, R, OpTypeNone, "r") HANDLE_OP_TYPE(18, SWAP, OpTypeNone, "swap") -HANDLE_OP_TYPE(19, iSWAP, OpTypeNone, "iswap") +HANDLE_OP_TYPE(19, iSWAP, OpTypeNone, "iswap") HANDLE_OP_TYPE(19, iSWAPdg, OpTypeInv, "iswapdg") HANDLE_OP_TYPE(20, Peres, OpTypeNone, "peres") HANDLE_OP_TYPE(20, Peresdg, OpTypeInv, "peresdg") @@ -68,7 +69,7 @@ HANDLE_OP_TYPE(38, AodActivate, 0, "aod_activate") HANDLE_OP_TYPE(39, AodDeactivate, 0, "aod_deactivate") HANDLE_OP_TYPE(40, AodMove, 0, "aod_move") -LAST_OP_TYPE(41) +LAST_OP_TYPE(42) #undef OpTypeInv diff --git a/src/ir/operations/OpType.cpp b/src/ir/operations/OpType.cpp index 181198454a..cff7da0a33 100644 --- a/src/ir/operations/OpType.cpp +++ b/src/ir/operations/OpType.cpp @@ -114,6 +114,8 @@ OpType opTypeFromString(const std::string& opType) { {"cry", OpType::RY}, {"rz", OpType::RZ}, {"crz", OpType::RZ}, + {"r", OpType::R}, + {"cr", OpType::R}, {"swap", OpType::SWAP}, {"cswap", OpType::SWAP}, {"iswap", OpType::iSWAP}, diff --git a/src/ir/operations/StandardOperation.cpp b/src/ir/operations/StandardOperation.cpp index e9cddf4601..965bedb01a 100644 --- a/src/ir/operations/StandardOperation.cpp +++ b/src/ir/operations/StandardOperation.cpp @@ -421,6 +421,9 @@ void StandardOperation::dumpGateType( case RZ: op << "rz(" << parameter[0] << ")"; break; + case R: + op << "r(" << parameter[0] << "," << parameter[1] << ")"; + break; case DCX: op << "dcx"; break; @@ -597,6 +600,7 @@ void StandardOperation::invert() { case RX: case RY: case RZ: + case R: case RXX: case RYY: case RZZ: diff --git a/src/ir/operations/SymbolicOperation.cpp b/src/ir/operations/SymbolicOperation.cpp index 6a47a47b58..076fb9cf39 100644 --- a/src/ir/operations/SymbolicOperation.cpp +++ b/src/ir/operations/SymbolicOperation.cpp @@ -419,6 +419,7 @@ void SymbolicOperation::invert() { case RX: case RY: case RZ: + case R: case RXX: case RYY: case RZZ: From 261e828873cb2b397c69eba9921b4609b74712ba Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 11:41:18 +0100 Subject: [PATCH 02/28] =?UTF-8?q?=F0=9F=9A=B8=20add=20convenience=20method?= =?UTF-8?q?=20to=20QuantumComputation=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- include/mqt-core/ir/QuantumComputation.hpp | 1 + src/ir/QuantumComputation.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/mqt-core/ir/QuantumComputation.hpp b/include/mqt-core/ir/QuantumComputation.hpp index 34eeccc583..3833beac7e 100644 --- a/include/mqt-core/ir/QuantumComputation.hpp +++ b/include/mqt-core/ir/QuantumComputation.hpp @@ -252,6 +252,7 @@ class QuantumComputation { const Controls& controls, const Qubit target); DECLARE_SINGLE_TARGET_TWO_PARAMETER_OPERATION(u2, phi, lambda) + DECLARE_SINGLE_TARGET_TWO_PARAMETER_OPERATION(r, theta, phi) #undef DECLARE_SINGLE_TARGET_TWO_PARAMETER_OPERATION diff --git a/src/ir/QuantumComputation.cpp b/src/ir/QuantumComputation.cpp index 4d430d7b37..52cf4ba512 100644 --- a/src/ir/QuantumComputation.cpp +++ b/src/ir/QuantumComputation.cpp @@ -1396,6 +1396,7 @@ DEFINE_SINGLE_TARGET_SINGLE_PARAMETER_OPERATION(p, theta) } DEFINE_SINGLE_TARGET_TWO_PARAMETER_OPERATION(u2, phi, lambda) +DEFINE_SINGLE_TARGET_TWO_PARAMETER_OPERATION(r, theta, phi) #undef DEFINE_SINGLE_TARGET_TWO_PARAMETER_OPERATION From ecffe577fc3dbcfe0d35934949ad18ec658b2166 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 11:41:40 +0100 Subject: [PATCH 03/28] =?UTF-8?q?=E2=9C=A8=20add=20support=20to=20QASM=20p?= =?UTF-8?q?arser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- include/mqt-core/qasm3/StdGates.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/mqt-core/qasm3/StdGates.hpp b/include/mqt-core/qasm3/StdGates.hpp index 211f16aeb9..e43fd12a85 100644 --- a/include/mqt-core/qasm3/StdGates.hpp +++ b/include/mqt-core/qasm3/StdGates.hpp @@ -86,6 +86,13 @@ const std::map> STANDARD_GATES = { {"rz", std::make_shared(StandardGate({0, 1, 1, qc::RZ}))}, {"crz", std::make_shared(StandardGate({1, 1, 1, qc::RZ}))}, + {"r", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 2, .type = qc::R}))}, + {"cr", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 2, .type = qc::R}))}, + {"h", std::make_shared(StandardGate({0, 1, 0, qc::H}))}, {"ch", std::make_shared(StandardGate({1, 1, 0, qc::H}))}, From 9fe0b10b3edc916aba08a85e14fb2cf052eccd80 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 11:41:58 +0100 Subject: [PATCH 04/28] =?UTF-8?q?=E2=9C=A8=20add=20support=20to=20DD=20pac?= =?UTF-8?q?kage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/dd/GateMatrixDefinitions.cpp | 14 ++++++++++++++ src/dd/Operations.cpp | 1 + 2 files changed, 15 insertions(+) diff --git a/src/dd/GateMatrixDefinitions.cpp b/src/dd/GateMatrixDefinitions.cpp index 0de5c877a0..8877379df2 100644 --- a/src/dd/GateMatrixDefinitions.cpp +++ b/src/dd/GateMatrixDefinitions.cpp @@ -65,6 +65,18 @@ GateMatrix rzMat(const fp lambda) { {std::cos(lambda / 2.), std::sin(lambda / 2.)}}}; } +GateMatrix rMat(const fp theta, const fp phi) { + const auto cosTheta = std::cos(theta / 2.); + const auto sinTheta = std::sin(theta / 2.); + const auto sinPhi = std::sin(phi); + const auto cosPhi = std::cos(phi); + const std::complex diag = {cosTheta, 0.}; + const std::complex m01 = {-sinTheta * sinPhi, -sinTheta * cosPhi}; + const std::complex m10 = {sinTheta * sinPhi, -sinTheta * cosPhi}; + + return GateMatrix{diag, m01, m10, diag}; +} + TwoQubitGateMatrix rxxMat(const fp theta) { const auto cosTheta = std::cos(theta / 2.); const auto sinTheta = std::sin(theta / 2.); @@ -183,6 +195,8 @@ GateMatrix opToSingleQubitGateMatrix(const qc::OpType t, return ryMat(params.at(0)); case qc::RZ: return rzMat(params.at(0)); + case qc::R: + return rMat(params.at(0), params.at(1)); default: throw std::invalid_argument("Invalid single-qubit gate type"); } diff --git a/src/dd/Operations.cpp b/src/dd/Operations.cpp index 73c211d23e..af440b5091 100644 --- a/src/dd/Operations.cpp +++ b/src/dd/Operations.cpp @@ -109,6 +109,7 @@ MatrixDD getStandardOperationDD(const qc::StandardOperation& op, Package& dd, case qc::RX: case qc::RY: case qc::RZ: + case qc::R: case qc::P: case qc::XXminusYY: case qc::XXplusYY: From f59826fe06c6e347a9b6ccef85b4ec70a792533a Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 11:42:20 +0100 Subject: [PATCH 05/28] =?UTF-8?q?=E2=9C=A8=20expose=20to=20Python?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- bindings/ir/operations/register_optype.cpp | 1 + bindings/ir/register_quantum_computation.cpp | 1 + python/mqt/core/ir/__init__.pyi | 40 ++++++++++++++++++++ python/mqt/core/ir/operations.pyi | 7 ++++ 4 files changed, 49 insertions(+) diff --git a/bindings/ir/operations/register_optype.cpp b/bindings/ir/operations/register_optype.cpp index d721bc95d4..3cc10f3e48 100644 --- a/bindings/ir/operations/register_optype.cpp +++ b/bindings/ir/operations/register_optype.cpp @@ -48,6 +48,7 @@ void registerOptype(const py::module& m) { .value("rx", qc::OpType::RX) .value("ry", qc::OpType::RY) .value("rz", qc::OpType::RZ) + .value("r", qc::OpType::R) .value("swap", qc::OpType::SWAP) .value("iswap", qc::OpType::iSWAP) .value("iswapdg", qc::OpType::iSWAPdg) diff --git a/bindings/ir/register_quantum_computation.cpp b/bindings/ir/register_quantum_computation.cpp index 4f40331e78..45a2c6e30d 100644 --- a/bindings/ir/register_quantum_computation.cpp +++ b/bindings/ir/register_quantum_computation.cpp @@ -345,6 +345,7 @@ void registerQuantumComputation(py::module& m) { py::arg(#param1), "controls"_a, "target"_a); DEFINE_SINGLE_TARGET_TWO_PARAMETER_OPERATION(u2, phi, lambda_) + DEFINE_SINGLE_TARGET_TWO_PARAMETER_OPERATION(r, theta, phi) #define DEFINE_SINGLE_TARGET_THREE_PARAMETER_OPERATION(op, param0, param1, \ param2) \ diff --git a/python/mqt/core/ir/__init__.pyi b/python/mqt/core/ir/__init__.pyi index b23dda45ff..16ace70d08 100644 --- a/python/mqt/core/ir/__init__.pyi +++ b/python/mqt/core/ir/__init__.pyi @@ -1003,6 +1003,46 @@ class QuantumComputation(MutableSequence[Operation]): :meth:`sxdg` """ + def r(self, theta: float, phi: float, q: int) -> None: + r"""Apply an :math:`R(\theta, \phi)` gate. + + .. math:: + R(\theta, \phi) = e^{-i\frac{\theta}{2}(\cos(\phi)X+\sin(\phi)Y)} + = \begin{pmatrix} \cos(\theta/2) & -i e^{-i\phi} \sin(\theta/2) \\ + -i e^{i\phi} \sin(\theta/2) & \cos(\theta/2) \end{pmatrix} + + Args: + theta: The rotation angle :math:`\theta` + phi: The angle specifying the rotation axis given by :math:`\cos(\phi)X+\sin(\phi)Y` + q: The target qubit + """ + + def cr(self, theta: float, phi: float, control: Control | int, target: int) -> None: + r"""Apply a controlled :math:`R(\theta, \phi)` gate. + + Args: + theta: The rotation angle :math:`\theta` + phi: The angle specifying the rotation axis given by :math:`\cos(\phi)X+\sin(\phi)Y` + control: The control qubit + target: The target qubit + + See Also: + :meth:`r` + """ + + def mcr(self, theta: float, phi: float, controls: set[Control | int], target: int) -> None: + r"""Apply a multi-controlled :math:`R(\theta, \phi)` gate. + + Args: + theta: The rotation angle :math:`\theta` + phi: The angle specifying the rotation axis given by :math:`\cos(\phi)X+\sin(\phi)Y` + controls: The control qubits + target: The target qubit + + See Also: + :meth:`r` + """ + def rx(self, theta: float | Expression, q: int) -> None: r"""Apply an :math:`R_x(\theta)` gate. diff --git a/python/mqt/core/ir/operations.pyi b/python/mqt/core/ir/operations.pyi index fd677d6b09..5c23ebf913 100644 --- a/python/mqt/core/ir/operations.pyi +++ b/python/mqt/core/ir/operations.pyi @@ -185,6 +185,13 @@ class OpType(Enum): See Also: :meth:`mqt.core.ir.QuantumComputation.reset` """ + r = ... + r""" + An :math:`R` gate. + + See Also: + :meth:`mqt.core.ir.QuantumComputation.r` + """ rx = ... r""" An :math:`R_x` gate. From 9c51a46656ca824c8c31b0977b25324916990dc2 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 11:53:14 +0100 Subject: [PATCH 06/28] =?UTF-8?q?=E2=9C=A8=20add=20support=20to=20MLIR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- mlir/include/mlir/Dialect/Common/IR/StdOps.td.inc | 10 ++++++++++ mlir/lib/Conversion/MQTOptToMQTRef/MQTOptToMQTRef.cpp | 1 + mlir/lib/Conversion/MQTRefToMQTOpt/MQTRefToMQTOpt.cpp | 1 + mlir/lib/Conversion/MQTRefToQIR/MQTRefToQIR.cpp | 1 + mlir/lib/Conversion/QIRToMQTRef/QIRToMQTRef.cpp | 2 ++ .../MQTRef/Translation/ImportQuantumComputation.cpp | 1 + 6 files changed, 16 insertions(+) diff --git a/mlir/include/mlir/Dialect/Common/IR/StdOps.td.inc b/mlir/include/mlir/Dialect/Common/IR/StdOps.td.inc index 675c4b9929..c1d9f4ac90 100644 --- a/mlir/include/mlir/Dialect/Common/IR/StdOps.td.inc +++ b/mlir/include/mlir/Dialect/Common/IR/StdOps.td.inc @@ -178,6 +178,16 @@ def SXdgOp : UnitaryOp<"sxdg", [OneTarget, NoParameter]> { }]; } +def ROp : UnitaryOp<"r", [OneTarget, TwoParameters]> { + let summary = "R operation"; + + let description = [{ + This class represents a R gate. It takes a qubit and a variadic + list of positive/negative controls as an input. Additionally, it accepts + two parameters indicating the degree of the rotation angles. + }]; +} + def RXOp : UnitaryOp<"rx", [OneTarget, OneParameter]> { let summary = "RX operation"; diff --git a/mlir/lib/Conversion/MQTOptToMQTRef/MQTOptToMQTRef.cpp b/mlir/lib/Conversion/MQTOptToMQTRef/MQTOptToMQTRef.cpp index f0845315c5..28a8ed910f 100644 --- a/mlir/lib/Conversion/MQTOptToMQTRef/MQTOptToMQTRef.cpp +++ b/mlir/lib/Conversion/MQTOptToMQTRef/MQTOptToMQTRef.cpp @@ -322,6 +322,7 @@ struct MQTOptToMQTRef final : impl::MQTOptToMQTRefBase { ADD_CONVERT_PATTERN(POp) ADD_CONVERT_PATTERN(SXOp) ADD_CONVERT_PATTERN(SXdgOp) + ADD_CONVERT_PATTERN(ROp) ADD_CONVERT_PATTERN(RXOp) ADD_CONVERT_PATTERN(RYOp) ADD_CONVERT_PATTERN(RZOp) diff --git a/mlir/lib/Conversion/MQTRefToMQTOpt/MQTRefToMQTOpt.cpp b/mlir/lib/Conversion/MQTRefToMQTOpt/MQTRefToMQTOpt.cpp index 4818e16b1f..e7903e7096 100644 --- a/mlir/lib/Conversion/MQTRefToMQTOpt/MQTRefToMQTOpt.cpp +++ b/mlir/lib/Conversion/MQTRefToMQTOpt/MQTRefToMQTOpt.cpp @@ -434,6 +434,7 @@ struct MQTRefToMQTOpt final : impl::MQTRefToMQTOptBase { ADD_CONVERT_PATTERN(POp) ADD_CONVERT_PATTERN(SXOp) ADD_CONVERT_PATTERN(SXdgOp) + ADD_CONVERT_PATTERN(ROp) ADD_CONVERT_PATTERN(RXOp) ADD_CONVERT_PATTERN(RYOp) ADD_CONVERT_PATTERN(RZOp) diff --git a/mlir/lib/Conversion/MQTRefToQIR/MQTRefToQIR.cpp b/mlir/lib/Conversion/MQTRefToQIR/MQTRefToQIR.cpp index 0973760ef8..81b9811e88 100644 --- a/mlir/lib/Conversion/MQTRefToQIR/MQTRefToQIR.cpp +++ b/mlir/lib/Conversion/MQTRefToQIR/MQTRefToQIR.cpp @@ -986,6 +986,7 @@ struct MQTRefToQIR final : impl::MQTRefToQIRBase { ADD_CONVERT_PATTERN(POp) ADD_CONVERT_PATTERN(SXOp) ADD_CONVERT_PATTERN(SXdgOp) + ADD_CONVERT_PATTERN(ROp) ADD_CONVERT_PATTERN(RXOp) ADD_CONVERT_PATTERN(RYOp) ADD_CONVERT_PATTERN(RZOp) diff --git a/mlir/lib/Conversion/QIRToMQTRef/QIRToMQTRef.cpp b/mlir/lib/Conversion/QIRToMQTRef/QIRToMQTRef.cpp index ddd74c28f5..2d224786f3 100644 --- a/mlir/lib/Conversion/QIRToMQTRef/QIRToMQTRef.cpp +++ b/mlir/lib/Conversion/QIRToMQTRef/QIRToMQTRef.cpp @@ -126,6 +126,7 @@ class StatefulOpConversionPattern : public OpConversionPattern { {"rzz", "RZZOp"}, {"rzx", "RZXOp"}, {"u1", "POp"}}; inline static const llvm::StringMap DOUBLE_ROTATION_GATES = { + {"r", "ROp"}, {"u2", "U2Op"}, {"xx_minus_yy", "XXminusYYOp"}, {"xx_plus_yy", "XXplusYYOp"}}; @@ -349,6 +350,7 @@ struct ConvertQIRCall final : StatefulOpConversionPattern { ADD_CONVERT_ROTATION_GATE(POp) ADD_CONVERT_ROTATION_GATE(UOp) ADD_CONVERT_ROTATION_GATE(U2Op) + ADD_CONVERT_ROTATION_GATE(ROp) ADD_CONVERT_ROTATION_GATE(RXOp) ADD_CONVERT_ROTATION_GATE(RYOp) ADD_CONVERT_ROTATION_GATE(RZOp) diff --git a/mlir/lib/Dialect/MQTRef/Translation/ImportQuantumComputation.cpp b/mlir/lib/Dialect/MQTRef/Translation/ImportQuantumComputation.cpp index ff058e4da6..5e6f16a982 100644 --- a/mlir/lib/Dialect/MQTRef/Translation/ImportQuantumComputation.cpp +++ b/mlir/lib/Dialect/MQTRef/Translation/ImportQuantumComputation.cpp @@ -513,6 +513,7 @@ llvm::LogicalResult addOperation(mlir::OpBuilder& builder, ADD_OP_CASE(P) ADD_OP_CASE(SX) ADD_OP_CASE(SXdg) + ADD_OP_CASE(R) ADD_OP_CASE(RX) ADD_OP_CASE(RY) ADD_OP_CASE(RZ) From 5185d0aa37585bcb54f092f9a55fa5f2c6db32b8 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 12:07:56 +0100 Subject: [PATCH 07/28] =?UTF-8?q?=E2=9C=85=20add=20MLIR=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- mlir/test/Conversion/mqtopt-to-mqtref.mlir | 4 +++- mlir/test/Conversion/mqtref-to-mqtopt.mlir | 2 ++ mlir/test/Conversion/mqtref-to-qir.mlir | 4 ++++ mlir/test/Conversion/qir-to-mqtref.mlir | 6 ++++++ mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir | 12 ++++++++++-- mlir/test/Dialect/MQTRef/IR/dialect_features.mlir | 8 ++++++++ mlir/unittests/translation/test_translation.cpp | 6 ++++++ 7 files changed, 39 insertions(+), 3 deletions(-) diff --git a/mlir/test/Conversion/mqtopt-to-mqtref.mlir b/mlir/test/Conversion/mqtopt-to-mqtref.mlir index c35507ad04..37b9b4bc9a 100644 --- a/mlir/test/Conversion/mqtopt-to-mqtref.mlir +++ b/mlir/test/Conversion/mqtopt-to-mqtref.mlir @@ -292,6 +292,7 @@ module { // CHECK: mqtref.rx(%[[c_0]]) %[[q_0]] // CHECK: mqtref.ry(%[[c_0]]) %[[q_0]] // CHECK: mqtref.rz(%[[c_0]]) %[[q_0]] + // CHECK: mqtref.r(%[[c_0]], %[[c_0]]) %[[q_0]] %i0 = arith.constant 0 : index %qreg = memref.alloc() : memref<1x!mqtopt.Qubit> @@ -304,8 +305,9 @@ module { %q4 = mqtopt.rx(%cst) %q3 : !mqtopt.Qubit %q5 = mqtopt.ry(%cst) %q4 : !mqtopt.Qubit %q6 = mqtopt.rz(%cst) %q5 : !mqtopt.Qubit + %q7 = mqtopt.r(%cst, %cst) %q6 : !mqtopt.Qubit - memref.store %q6, %qreg[%i0] : memref<1x!mqtopt.Qubit> + memref.store %q7, %qreg[%i0] : memref<1x!mqtopt.Qubit> memref.dealloc %qreg : memref<1x!mqtopt.Qubit> return diff --git a/mlir/test/Conversion/mqtref-to-mqtopt.mlir b/mlir/test/Conversion/mqtref-to-mqtopt.mlir index 6a08681c16..70007cbe7d 100644 --- a/mlir/test/Conversion/mqtref-to-mqtopt.mlir +++ b/mlir/test/Conversion/mqtref-to-mqtopt.mlir @@ -310,6 +310,7 @@ module { // CHECK: %[[q_3:.*]] = mqtopt.rx(%[[c_0]]) %[[q_2]] : !mqtopt.Qubit // CHECK: %[[q_4:.*]] = mqtopt.ry(%[[c_0]]) %[[q_3]] : !mqtopt.Qubit // CHECK: %[[q_5:.*]] = mqtopt.rz(%[[c_0]]) %[[q_4]] : !mqtopt.Qubit + // CHECK: %[[q_6:.*]] = mqtopt.r(%[[c_0]], %[[c_0]]) %[[q_5]] : !mqtopt.Qubit %cst = arith.constant 3.000000e-01 : f64 @@ -323,6 +324,7 @@ module { mqtref.rx(%cst) %q0 mqtref.ry(%cst) %q0 mqtref.rz(%cst) %q0 + mqtref.r(%cst, %cst) %q0 return } diff --git a/mlir/test/Conversion/mqtref-to-qir.mlir b/mlir/test/Conversion/mqtref-to-qir.mlir index bc095be493..57477e0bbc 100644 --- a/mlir/test/Conversion/mqtref-to-qir.mlir +++ b/mlir/test/Conversion/mqtref-to-qir.mlir @@ -457,6 +457,7 @@ module { // CHECK: llvm.call @__quantum__qis__rx__body(%[[q_0]], %[[c_0]]) : (!llvm.ptr, f64) -> () // CHECK: llvm.call @__quantum__qis__ry__body(%[[q_0]], %[[c_0]]) : (!llvm.ptr, f64) -> () // CHECK: llvm.call @__quantum__qis__rz__body(%[[q_0]], %[[c_0]]) : (!llvm.ptr, f64) -> () + // CHECK: llvm.call @__quantum__qis__r__body(%[[q_0:.*]], %[[c_0]], %[[c_1]]) : (!llvm.ptr, f64, f64) -> () %c0 = arith.constant 3.000000e-01 : f64 %c1 = arith.constant 1.000000e-01 : f64 @@ -468,6 +469,7 @@ module { mqtref.rx(%c0) %q0 mqtref.ry(%c0) %q0 mqtref.rz(%c0) %q0 + mqtref.r(%c0, %c1) %q0 return } } @@ -486,6 +488,7 @@ module { // CHECK: llvm.call @__quantum__qis__rx__body(%[[q_0]], %[[c_0]]) : (!llvm.ptr, f64) -> () // CHECK: llvm.call @__quantum__qis__ry__body(%[[q_0]], %[[c_0]]) : (!llvm.ptr, f64) -> () // CHECK: llvm.call @__quantum__qis__rz__body(%[[q_0]], %[[c_0]]) : (!llvm.ptr, f64) -> () + // CHECK: llvm.call @__quantum__qis__r__body(%[[q_0:.*]], %[[c_0]], %[[c_1]]) : (!llvm.ptr, f64, f64) -> () %c0 = arith.constant 3.000000e-01 : f64 %c1 = arith.constant 1.000000e-01 : f64 @@ -497,6 +500,7 @@ module { mqtref.rx(%c0) %q0 mqtref.ry(%c0) %q0 mqtref.rz(%c0) %q0 + mqtref.r(%c0, %c1) %q0 return } } diff --git a/mlir/test/Conversion/qir-to-mqtref.mlir b/mlir/test/Conversion/qir-to-mqtref.mlir index ba99d5df4c..eac76e4e9e 100644 --- a/mlir/test/Conversion/qir-to-mqtref.mlir +++ b/mlir/test/Conversion/qir-to-mqtref.mlir @@ -572,6 +572,7 @@ module { // CHECK: mqtref.rx(%[[c_0]]) %[[q_0]] // CHECK: mqtref.ry(%[[c_0]]) %[[q_0]] // CHECK: mqtref.rz(%[[c_0]]) %[[q_0]] + // CHECK: mqtref.r(%[[c_0]], %[[c_1]]) %[[q_0]] %0 = llvm.mlir.zero : !llvm.ptr %c2 = llvm.mlir.constant(1.000000e-01 : f64) : f64 @@ -588,6 +589,7 @@ module { llvm.call @__quantum__qis__rx__body(%q0, %c2) : (!llvm.ptr, f64) -> () llvm.call @__quantum__qis__ry__body(%q0, %c2) : (!llvm.ptr, f64) -> () llvm.call @__quantum__qis__rz__body(%q0, %c2) : (!llvm.ptr, f64) -> () + llvm.call @__quantum__qis__r__body(%q0, %c2, %c3) : (!llvm.ptr, f64, f64) -> () llvm.br ^bb2 ^bb2: llvm.call @__quantum__rt__qubit_release(%q0) : (!llvm.ptr) -> () @@ -602,6 +604,7 @@ module { llvm.func @__quantum__qis__rx__body(!llvm.ptr, f64) llvm.func @__quantum__qis__ry__body(!llvm.ptr, f64) llvm.func @__quantum__qis__rz__body(!llvm.ptr, f64) + llvm.func @__quantum__qis__r__body(!llvm.ptr, f64, f64) llvm.func @__quantum__rt__initialize(!llvm.ptr) llvm.func @__quantum__rt__qubit_allocate() -> !llvm.ptr llvm.func @__quantum__rt__qubit_release(!llvm.ptr) -> () @@ -623,6 +626,7 @@ module { // CHECK: mqtref.rx(%[[c_0]]) %[[q_0]] // CHECK: mqtref.ry(%[[c_0]]) %[[q_0]] // CHECK: mqtref.rz(%[[c_0]]) %[[q_0]] + // CHECK: mqtref.r(%[[c_0]], %[[c_1]]) %[[q_0]] %0 = llvm.mlir.zero : !llvm.ptr %c2 = llvm.mlir.constant(1.000000e-01 : f64) : f64 @@ -638,6 +642,7 @@ module { llvm.call @__quantum__qis__rx__body(%0, %c2) : (!llvm.ptr, f64) -> () llvm.call @__quantum__qis__ry__body(%0, %c2) : (!llvm.ptr, f64) -> () llvm.call @__quantum__qis__rz__body(%0, %c2) : (!llvm.ptr, f64) -> () + llvm.call @__quantum__qis__r__body(%0, %c2, %c3) : (!llvm.ptr, f64, f64) -> () llvm.br ^bb2 ^bb2: @@ -652,6 +657,7 @@ module { llvm.func @__quantum__qis__rx__body(!llvm.ptr, f64) llvm.func @__quantum__qis__ry__body(!llvm.ptr, f64) llvm.func @__quantum__qis__rz__body(!llvm.ptr, f64) + llvm.func @__quantum__qis__r__body(!llvm.ptr, f64, f64) llvm.func @__quantum__rt__initialize(!llvm.ptr) } diff --git a/mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir b/mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir index f5900991af..5271b9fabc 100644 --- a/mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir +++ b/mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir @@ -408,6 +408,7 @@ module { // CHECK: %[[Q_4:.*]] = mqtopt.rx(%[[C0_F64]]) %[[Q_3]] : !mqtopt.Qubit // CHECK: %[[Q_5:.*]] = mqtopt.ry(%[[C0_F64]]) %[[Q_4]] : !mqtopt.Qubit // CHECK: %[[Q_6:.*]] = mqtopt.rz(%[[C0_F64]]) %[[Q_5]] : !mqtopt.Qubit + // CHECK: %[[Q_7:.*]] = mqtopt.r(%[[C0_F64]], %[[C0_F64]] static [] mask [false, false]) %[[Q_6]] : !mqtopt.Qubit %i0 = arith.constant 0 : index %qreg = memref.alloc() : memref<1x!mqtopt.Qubit> @@ -420,8 +421,9 @@ module { %q_4 = mqtopt.rx(%c0_f64) %q_3 : !mqtopt.Qubit %q_5 = mqtopt.ry(%c0_f64) %q_4 : !mqtopt.Qubit %q_6 = mqtopt.rz(%c0_f64) %q_5 : !mqtopt.Qubit + %q_7 = mqtopt.r(%c0_f64, %c0_f64 static [] mask [false, false]) %q_6 : !mqtopt.Qubit - memref.store %q_6, %qreg[%i0] : memref<1x!mqtopt.Qubit> + memref.store %q_7, %qreg[%i0] : memref<1x!mqtopt.Qubit> memref.dealloc %qreg : memref<1x!mqtopt.Qubit> return @@ -440,6 +442,7 @@ module { // CHECK: %[[Q_4:.*]] = mqtopt.rx(%[[C0_F64]]) %[[Q_3]] : !mqtopt.Qubit // CHECK: %[[Q_5:.*]] = mqtopt.ry(%[[C0_F64]]) %[[Q_4]] : !mqtopt.Qubit // CHECK: %[[Q_6:.*]] = mqtopt.rz(%[[C0_F64]]) %[[Q_5]] : !mqtopt.Qubit + // CHECK: %[[Q_7:.*]] = mqtopt.r(%[[C0_F64]], %[[C0_F64]] static [] mask [false, false]) %[[Q_6]] : !mqtopt.Qubit %q_0 = mqtopt.qubit 0 @@ -450,6 +453,7 @@ module { %q_4 = mqtopt.rx(%c0_f64) %q_3 : !mqtopt.Qubit %q_5 = mqtopt.ry(%c0_f64) %q_4 : !mqtopt.Qubit %q_6 = mqtopt.rz(%c0_f64) %q_5 : !mqtopt.Qubit + %q_7 = mqtopt.r(%c0_f64, %c0_f64 static [] mask [false, false]) %q_6 : !mqtopt.Qubit return } @@ -468,6 +472,7 @@ module { // CHECK: %[[Q0_4:.*]], %[[Q1_4:.*]] = mqtopt.rx(%[[C0_F64]]) %[[Q0_3]] ctrl %[[Q1_3]] : !mqtopt.Qubit ctrl !mqtopt.Qubit // CHECK: %[[Q0_5:.*]], %[[Q1_5:.*]] = mqtopt.ry(%[[C0_F64]]) %[[Q0_4]] ctrl %[[Q1_4]] : !mqtopt.Qubit ctrl !mqtopt.Qubit // CHECK: %[[Q0_6:.*]], %[[Q1_6:.*]] = mqtopt.rz(%[[C0_F64]]) %[[Q0_5]] ctrl %[[Q1_5]] : !mqtopt.Qubit ctrl !mqtopt.Qubit + // CHECK: %[[Q0_7:.*]], %[[Q1_7:.*]] = mqtopt.r(%[[C0_F64]], %[[C0_F64]]) %[[Q0_6]] ctrl %[[Q1_6]] : !mqtopt.Qubit ctrl !mqtopt.Qubit %i1 = arith.constant 1 : index %i0 = arith.constant 0 : index @@ -482,8 +487,9 @@ module { %q0_4, %q1_4 = mqtopt.rx(%c0_f64) %q0_3 ctrl %q1_3 : !mqtopt.Qubit ctrl !mqtopt.Qubit %q0_5, %q1_5 = mqtopt.ry(%c0_f64) %q0_4 ctrl %q1_4 : !mqtopt.Qubit ctrl !mqtopt.Qubit %q0_6, %q1_6 = mqtopt.rz(%c0_f64) %q0_5 ctrl %q1_5 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %q0_7, %q1_7 = mqtopt.r(%c0_f64, %c0_f64) %q0_6 ctrl %q1_6 : !mqtopt.Qubit ctrl !mqtopt.Qubit - memref.store %q0_6, %qreg[%i0] : memref<2x!mqtopt.Qubit> + memref.store %q0_7, %qreg[%i0] : memref<2x!mqtopt.Qubit> memref.store %q1_0, %qreg[%i1] : memref<2x!mqtopt.Qubit> memref.dealloc %qreg : memref<2x!mqtopt.Qubit> @@ -503,6 +509,7 @@ module { // CHECK: %[[Q0_4:.*]], %[[Q1_4:.*]] = mqtopt.rx(%[[C0_F64]]) %[[Q0_3]] ctrl %[[Q1_3]] : !mqtopt.Qubit ctrl !mqtopt.Qubit // CHECK: %[[Q0_5:.*]], %[[Q1_5:.*]] = mqtopt.ry(%[[C0_F64]]) %[[Q0_4]] ctrl %[[Q1_4]] : !mqtopt.Qubit ctrl !mqtopt.Qubit // CHECK: %[[Q0_6:.*]], %[[Q1_6:.*]] = mqtopt.rz(%[[C0_F64]]) %[[Q0_5]] ctrl %[[Q1_5]] : !mqtopt.Qubit ctrl !mqtopt.Qubit + // CHECK: %[[Q0_7:.*]], %[[Q1_7:.*]] = mqtopt.r(%[[C0_F64]], %[[C0_F64]]) %[[Q0_6]] ctrl %[[Q1_6]] : !mqtopt.Qubit ctrl !mqtopt.Qubit %q0_0 = mqtopt.qubit 0 %q1_0 = mqtopt.qubit 1 @@ -514,6 +521,7 @@ module { %q0_4, %q1_4 = mqtopt.rx(%c0_f64) %q0_3 ctrl %q1_3 : !mqtopt.Qubit ctrl !mqtopt.Qubit %q0_5, %q1_5 = mqtopt.ry(%c0_f64) %q0_4 ctrl %q1_4 : !mqtopt.Qubit ctrl !mqtopt.Qubit %q0_6, %q1_6 = mqtopt.rz(%c0_f64) %q0_5 ctrl %q1_5 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %q0_7, %q1_7 = mqtopt.r(%c0_f64, %c0_f64) %q0_6 ctrl %q1_6 : !mqtopt.Qubit ctrl !mqtopt.Qubit return } diff --git a/mlir/test/Dialect/MQTRef/IR/dialect_features.mlir b/mlir/test/Dialect/MQTRef/IR/dialect_features.mlir index 729b9d57f6..a8e50efc18 100644 --- a/mlir/test/Dialect/MQTRef/IR/dialect_features.mlir +++ b/mlir/test/Dialect/MQTRef/IR/dialect_features.mlir @@ -378,6 +378,7 @@ module { // CHECK: mqtref.u(%[[P0]], %[[P0]], %[[P0]]) %[[Q0:.*]] // CHECK: mqtref.u2(%[[P0]], %[[P0]] static [] mask [false, false]) %[[Q0]] // CHECK: mqtref.p(%[[P0]]) %[[Q0]] + // CHECK: mqtref.r(%[[P0]], %[[P0]] static [] mask [false, false]) %[[Q0]] // CHECK: mqtref.rx(%[[P0]]) %[[Q0]] // CHECK: mqtref.ry(%[[P0]]) %[[Q0]] // CHECK: mqtref.rz(%[[P0]]) %[[Q0]] @@ -390,6 +391,7 @@ module { mqtref.u(%p0, %p0, %p0) %q0 mqtref.u2(%p0, %p0 static [] mask [false, false]) %q0 mqtref.p(%p0) %q0 + mqtref.r(%p0, %p0 static [] mask [false, false]) %q0 mqtref.rx(%p0) %q0 mqtref.ry(%p0) %q0 mqtref.rz(%p0) %q0 @@ -408,6 +410,7 @@ module { // CHECK: mqtref.u(%[[P0]], %[[P0]], %[[P0]]) %[[Q0:.*]] // CHECK: mqtref.u2(%[[P0]], %[[P0]] static [] mask [false, false]) %[[Q0]] // CHECK: mqtref.p(%[[P0]]) %[[Q0]] + // CHECK: mqtref.r(%[[P0]], %[[P0]] static [] mask [false, false]) %[[Q0]] // CHECK: mqtref.rx(%[[P0]]) %[[Q0]] // CHECK: mqtref.ry(%[[P0]]) %[[Q0]] // CHECK: mqtref.rz(%[[P0]]) %[[Q0]] @@ -418,6 +421,7 @@ module { mqtref.u(%p0, %p0, %p0) %q0 mqtref.u2(%p0, %p0 static [] mask [false, false]) %q0 mqtref.p(%p0) %q0 + mqtref.r(%p0, %p0 static [] mask [false, false]) %q0 mqtref.rx(%p0) %q0 mqtref.ry(%p0) %q0 mqtref.rz(%p0) %q0 @@ -435,6 +439,7 @@ module { // CHECK: mqtref.u(%[[P0]], %[[P0]], %[[P0]]) %[[Q0:.*]] ctrl %[[Q1:.*]] // CHECK: mqtref.u2(%[[P0]], %[[P0]]) %[[Q0]] ctrl %[[Q1]] // CHECK: mqtref.p(%[[P0]]) %[[Q0]] ctrl %[[Q1]] + // CHECK: mqtref.r(%[[P0]], %[[P0]]) %[[Q0]] ctrl %[[Q1]] // CHECK: mqtref.rx(%[[P0]]) %[[Q0]] ctrl %[[Q1]] // CHECK: mqtref.ry(%[[P0]]) %[[Q0]] ctrl %[[Q1]] // CHECK: mqtref.rz(%[[P0]]) %[[Q0]] ctrl %[[Q1]] @@ -449,6 +454,7 @@ module { mqtref.u(%p0, %p0, %p0) %q0 ctrl %q1 mqtref.u2(%p0, %p0) %q0 ctrl %q1 mqtref.p(%p0) %q0 ctrl %q1 + mqtref.r(%p0, %p0) %q0 ctrl %q1 mqtref.rx(%p0) %q0 ctrl %q1 mqtref.ry(%p0) %q0 ctrl %q1 mqtref.rz(%p0) %q0 ctrl %q1 @@ -467,6 +473,7 @@ module { // CHECK: mqtref.u(%[[P0]], %[[P0]], %[[P0]]) %[[Q0:.*]] ctrl %[[Q1:.*]] // CHECK: mqtref.u2(%[[P0]], %[[P0]]) %[[Q0]] ctrl %[[Q1]] // CHECK: mqtref.p(%[[P0]]) %[[Q0]] ctrl %[[Q1]] + // CHECK: mqtref.r(%[[P0]], %[[P0]]) %[[Q0]] ctrl %[[Q1]] // CHECK: mqtref.rx(%[[P0]]) %[[Q0]] ctrl %[[Q1]] // CHECK: mqtref.ry(%[[P0]]) %[[Q0]] ctrl %[[Q1]] // CHECK: mqtref.rz(%[[P0]]) %[[Q0]] ctrl %[[Q1]] @@ -478,6 +485,7 @@ module { mqtref.u(%p0, %p0, %p0) %q0 ctrl %q1 mqtref.u2(%p0, %p0) %q0 ctrl %q1 mqtref.p(%p0) %q0 ctrl %q1 + mqtref.r(%p0, %p0) %q0 ctrl %q1 mqtref.rx(%p0) %q0 ctrl %q1 mqtref.ry(%p0) %q0 ctrl %q1 mqtref.rz(%p0) %q0 ctrl %q1 diff --git a/mlir/unittests/translation/test_translation.cpp b/mlir/unittests/translation/test_translation.cpp index 405b6a509f..793476f788 100644 --- a/mlir/unittests/translation/test_translation.cpp +++ b/mlir/unittests/translation/test_translation.cpp @@ -446,6 +446,12 @@ INSTANTIATE_TEST_SUITE_P( .build = [](QuantumComputation& qc) { qc.p(0.1, 0); }, .checkStringOperation = getCheckStringOperationParams("p", {0.1}, {0})}, + TestCaseUnitary{ + .name = "R", + .numQubits = 1, + .build = [](QuantumComputation& qc) { qc.r(0.1, 0.2, 0); }, + .checkStringOperation = + getCheckStringOperationParams("r", {0.1, 0.2}, {0})}, TestCaseUnitary{.name = "RX", .numQubits = 1, .build = [](QuantumComputation& qc) { qc.rx(0.1, 0); }, From b2e907cb848033ee82f4939dd49d312645a7e1a7 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 12:39:52 +0100 Subject: [PATCH 08/28] =?UTF-8?q?=F0=9F=9A=B8=20add=20`prx`=20alias=20for?= =?UTF-8?q?=20R=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- include/mqt-core/qasm3/StdGates.hpp | 3 +++ src/ir/operations/OpType.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/include/mqt-core/qasm3/StdGates.hpp b/include/mqt-core/qasm3/StdGates.hpp index e43fd12a85..6dd7a9f8ca 100644 --- a/include/mqt-core/qasm3/StdGates.hpp +++ b/include/mqt-core/qasm3/StdGates.hpp @@ -89,6 +89,9 @@ const std::map> STANDARD_GATES = { {"r", std::make_shared(StandardGate( {.nControls = 0, .nTargets = 1, .nParameters = 2, .type = qc::R}))}, + {"prx", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 2, .type = qc::R}))}, {"cr", std::make_shared(StandardGate( {.nControls = 1, .nTargets = 1, .nParameters = 2, .type = qc::R}))}, diff --git a/src/ir/operations/OpType.cpp b/src/ir/operations/OpType.cpp index cff7da0a33..939c22f25e 100644 --- a/src/ir/operations/OpType.cpp +++ b/src/ir/operations/OpType.cpp @@ -114,6 +114,7 @@ OpType opTypeFromString(const std::string& opType) { {"cry", OpType::RY}, {"rz", OpType::RZ}, {"crz", OpType::RZ}, + {"prx", OpType::R}, {"r", OpType::R}, {"cr", OpType::R}, {"swap", OpType::SWAP}, From 10fbcb369d1fc4bc42edc9a9a338c3506521ca38 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 12:40:27 +0100 Subject: [PATCH 09/28] =?UTF-8?q?=E2=9C=A8=20add=20support=20to=20QIR=20ru?= =?UTF-8?q?ntime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- include/mqt-core/qir/runtime/QIR.h | 2 ++ src/qir/runner/Runner.cpp | 6 ++++++ src/qir/runtime/QIR.cpp | 12 ++++++++++++ 3 files changed, 20 insertions(+) diff --git a/include/mqt-core/qir/runtime/QIR.h b/include/mqt-core/qir/runtime/QIR.h index f1ae383368..f67818d681 100644 --- a/include/mqt-core/qir/runtime/QIR.h +++ b/include/mqt-core/qir/runtime/QIR.h @@ -116,6 +116,8 @@ void __quantum__qis__sqrtx__body(Qubit*); void __quantum__qis__sqrtxdg__body(Qubit*); void __quantum__qis__t__body(Qubit*); void __quantum__qis__tdg__body(Qubit*); +void __quantum__qis__r__body(Qubit*, double, double); +void __quantum__qis__prx__body(Qubit*, double, double); void __quantum__qis__rx__body(Qubit*, double); void __quantum__qis__ry__body(Qubit*, double); void __quantum__qis__rz__body(Qubit*, double); diff --git a/src/qir/runner/Runner.cpp b/src/qir/runner/Runner.cpp index 523bc4472b..879758d480 100644 --- a/src/qir/runner/Runner.cpp +++ b/src/qir/runner/Runner.cpp @@ -304,6 +304,12 @@ auto main(int argc, char* argv[]) -> int { llvm::sys::DynamicLibrary::AddSymbol( "__quantum__qis__tdg__body", reinterpret_cast(&__quantum__qis__tdg__body)); + llvm::sys::DynamicLibrary::AddSymbol( + "__quantum__qis__r__body", + reinterpret_cast(&__quantum__qis__r__body)); + llvm::sys::DynamicLibrary::AddSymbol( + "__quantum__qis__prx__body", + reinterpret_cast(&__quantum__qis__prx__body)); llvm::sys::DynamicLibrary::AddSymbol( "__quantum__qis__rx__body", reinterpret_cast(&__quantum__qis__rx__body)); diff --git a/src/qir/runtime/QIR.cpp b/src/qir/runtime/QIR.cpp index 13a01d1ea9..eae286eae0 100644 --- a/src/qir/runtime/QIR.cpp +++ b/src/qir/runtime/QIR.cpp @@ -187,6 +187,18 @@ void __quantum__qis__tdg__body(Qubit* qubit) { runtime.apply(qubit); } +void __quantum__qis__r__body(Qubit* qubit, const double theta, + const double phi) { + auto& runtime = qir::Runtime::getInstance(); + runtime.apply(theta, phi, qubit); +} + +void __quantum__qis__prx__body(Qubit* qubit, const double theta, + const double phi) { + auto& runtime = qir::Runtime::getInstance(); + runtime.apply(phi, theta, qubit); +} + void __quantum__qis__rx__body(Qubit* qubit, const double phi) { auto& runtime = qir::Runtime::getInstance(); runtime.apply(phi, qubit); From b83f5ffa0c92f85c9efb75d8afbe0b970d16c1f5 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 12:40:46 +0100 Subject: [PATCH 10/28] =?UTF-8?q?=E2=9C=85=20add=20IR=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- test/ir/test_qfr_functionality.cpp | 6 ++++++ test/ir/test_symbolic.cpp | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/test/ir/test_qfr_functionality.cpp b/test/ir/test_qfr_functionality.cpp index abae0f4c01..2caa97973e 100644 --- a/test/ir/test_qfr_functionality.cpp +++ b/test/ir/test_qfr_functionality.cpp @@ -272,6 +272,9 @@ TEST_F(QFRFunctionality, gateShortCutsAndCloning) { qc.sxdg(0); qc.csxdg(1, 0); qc.mcsxdg({1, 2_nc}, 0); + qc.r(PI, PI, 0); + qc.cr(PI, PI, 1, 0); + qc.mcr(PI, PI, {1, 2_nc}, 0); qc.rx(PI, 0); qc.crx(PI, 1, 0); qc.mcrx(PI, {1, 2_nc}, 0); @@ -856,6 +859,7 @@ TEST_F(QFRFunctionality, invertStandardOpParamChange) { const auto cases = { std::tuple{OpType::GPhase, std::vector{1}, std::vector{-1}}, std::tuple{OpType::P, std::vector{1}, std::vector{-1}}, + std::tuple{OpType::R, std::vector{1, 2}, std::vector{-1, 2}}, std::tuple{OpType::RX, std::vector{1}, std::vector{-1}}, std::tuple{OpType::RY, std::vector{1}, std::vector{-1}}, std::tuple{OpType::RZ, std::vector{1}, std::vector{-1}}, @@ -909,6 +913,8 @@ TEST_F(QFRFunctionality, invertSymbolicOpParamChange) { std::vector{-1.0}}, std::tuple{OpType::U2, std::vector{Symbolic({x}), 1.0}, std::vector{-1.0 + PI, -Symbolic({x}) - PI}}, + std::tuple{OpType::R, std::vector{Symbolic({x}), 2.0}, + std::vector{-Symbolic({x}), 2.0}}, std::tuple{ OpType::U, std::vector{Symbolic({x}), 2.0, Symbolic({y})}, diff --git a/test/ir/test_symbolic.cpp b/test/ir/test_symbolic.cpp index 44313f0896..e9e30afb3e 100644 --- a/test/ir/test_symbolic.cpp +++ b/test/ir/test_symbolic.cpp @@ -54,6 +54,10 @@ TEST_F(SymbolicTest, Gates) { symQc.cp(xMonom, 1, 0); symQc.p(xMonom, 0); + symQc.mcr(xMonom, yMonom, {1, 2_nc}, 0); + symQc.cr(xMonom, yMonom, 1, 0); + symQc.r(xMonom, yMonom, 0); + symQc.mcrx(xMonom, {1, 2_nc}, 0); symQc.crx(xMonom, 1, 0); symQc.rx(xMonom, 0); @@ -108,6 +112,10 @@ TEST_F(SymbolicTest, Gates) { qc.cp(xVal, 1, 0); qc.p(xVal, 0); + qc.mcr(xVal, yVal, {1, 2_nc}, 0); + qc.cr(xVal, yVal, 1, 0); + qc.r(xVal, yVal, 0); + qc.mcrx(xVal, {1, 2_nc}, 0); qc.crx(xVal, 1, 0); qc.rx(xVal, 0); From c6b5d4e18cb911b8d077b3911eed702988fe288b Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 12:41:57 +0100 Subject: [PATCH 11/28] =?UTF-8?q?=E2=9C=85=20add=20QIR=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- test/qir/runtime/test_qir_runtime.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/qir/runtime/test_qir_runtime.cpp b/test/qir/runtime/test_qir_runtime.cpp index 3df115b02e..34153deca3 100644 --- a/test/qir/runtime/test_qir_runtime.cpp +++ b/test/qir/runtime/test_qir_runtime.cpp @@ -109,6 +109,18 @@ TEST_F(QIRRuntimeTest, TdgGate) { __quantum__qis__tdg__body(q0); } +TEST_F(QIRRuntimeTest, RGate) { + auto* q0 = reinterpret_cast(0UL); + __quantum__rt__initialize(nullptr); + __quantum__qis__r__body(q0, qc::PI_2, 0); +} + +TEST_F(QIRRuntimeTest, PRXGate) { + auto* q0 = reinterpret_cast(0UL); + __quantum__rt__initialize(nullptr); + __quantum__qis__prx__body(q0, qc::PI_2, 0); +} + TEST_F(QIRRuntimeTest, RXGate) { auto* q0 = reinterpret_cast(0UL); __quantum__rt__initialize(nullptr); From 6183d09cb64f797363f317ef59e45cf34fa54914 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 12:45:45 +0100 Subject: [PATCH 12/28] =?UTF-8?q?=E2=9C=85=20add=20DD=20package=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- test/dd/test_dd_functionality.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/dd/test_dd_functionality.cpp b/test/dd/test_dd_functionality.cpp index d24dff61f4..2d2ff1222d 100644 --- a/test/dd/test_dd_functionality.cpp +++ b/test/dd/test_dd_functionality.cpp @@ -58,7 +58,7 @@ class DDFunctionality : public testing::TestWithParam { INSTANTIATE_TEST_SUITE_P( Parameters, DDFunctionality, testing::Values(GPhase, I, H, X, Y, Z, S, Sdg, T, Tdg, SX, SXdg, V, Vdg, U, - U2, P, RX, RY, RZ, Peres, Peresdg, SWAP, iSWAP, iSWAPdg, + U2, P, R, RX, RY, RZ, Peres, Peresdg, SWAP, iSWAP, iSWAPdg, DCX, ECR, RXX, RYY, RZZ, RZX, XXminusYY, XXplusYY), [](const testing::TestParamInfo& inf) { const auto gate = inf.param; @@ -82,6 +82,7 @@ TEST_P(DDFunctionality, StandardOpBuildInverseBuild) { op = StandardOperation(0, gate, std::vector{dist(mt), dist(mt), dist(mt)}); break; case U2: + case R: op = StandardOperation(0, gate, std::vector{dist(mt), dist(mt)}); break; case RX: @@ -138,6 +139,7 @@ TEST_P(DDFunctionality, ControlledStandardOpBuildInverseBuild) { std::vector{dist(mt), dist(mt), dist(mt)}); break; case U2: + case R: op = StandardOperation(0, 1, gate, std::vector{dist(mt), dist(mt)}); break; case RX: @@ -195,6 +197,7 @@ TEST_P(DDFunctionality, ControlledStandardNegOpBuildInverseBuild) { std::vector{dist(mt), dist(mt), dist(mt)}); break; case U2: + case R: op = StandardOperation(Controls{0_nc}, 1, gate, std::vector{dist(mt), dist(mt)}); break; @@ -273,8 +276,14 @@ TEST_F(DDFunctionality, BuildCircuit) { qc.cxx_minus_yy(theta, beta, 2, 0, 1); qc.xx_plus_yy(theta, beta, 0, 1); qc.cxx_plus_yy(theta, beta, 2, 0, 1); + qc.r(theta, beta, 0); + qc.cr(theta, beta, 2, 0); + qc.mcr(theta, beta, {2, 3}, 0); // invert the circuit above + qc.mcr(-theta, beta, {2, 3}, 0); + qc.cr(-theta, beta, 2, 0); + qc.r(-theta, beta, 0); qc.cxx_plus_yy(-theta, beta, 2, 0, 1); qc.xx_plus_yy(-theta, beta, 0, 1); qc.cxx_minus_yy(-theta, beta, 2, 0, 1); From 9235d441a0fa813491b26335a282cb616619ad8c Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 14:00:25 +0100 Subject: [PATCH 13/28] =?UTF-8?q?=E2=9C=A8=20add=20support=20to=20ZX=20pac?= =?UTF-8?q?kage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/zx/FunctionalityConstruction.cpp | 12 ++++++++++++ test/zx/test_zx_functionality.cpp | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/zx/FunctionalityConstruction.cpp b/src/zx/FunctionalityConstruction.cpp index f50a956490..e69dbef87a 100644 --- a/src/zx/FunctionalityConstruction.cpp +++ b/src/zx/FunctionalityConstruction.cpp @@ -380,6 +380,17 @@ FunctionalityConstruction::parseOp(ZXDiagram& diag, op_it it, op_it end, addZSpider(diag, target, qubits, parseParam(op.get(), 0) + PiRational(1, 2)); break; + case qc::OpType::R: + addZSpider(diag, target, qubits, + parseParam(op.get(), 1) - PiRational(1, 2)); + addXSpider(diag, target, qubits, PiExpression(PiRational(1, 2))); + addZSpider(diag, target, qubits, + parseParam(op.get(), 0) + PiRational(1, 1)); + addXSpider(diag, target, qubits, PiExpression(PiRational(1, 2))); + addZSpider(diag, target, qubits, + -(parseParam(op.get(), 1) - PiRational(1, 2)) + + PiRational(3, 1)); + break; case qc::OpType::U: addZSpider(diag, target, qubits, parseParam(op.get(), 2)); addXSpider(diag, target, qubits, PiExpression(PiRational(1, 2))); @@ -647,6 +658,7 @@ bool FunctionalityConstruction::transformableToZX(const qc::Operation* op) { if (!op->isControlled()) { switch (op->getType()) { + case qc::OpType::R: case qc::OpType::Z: case qc::OpType::RZ: case qc::OpType::P: diff --git a/test/zx/test_zx_functionality.cpp b/test/zx/test_zx_functionality.cpp index 7728908893..60ecc9132a 100644 --- a/test/zx/test_zx_functionality.cpp +++ b/test/zx/test_zx_functionality.cpp @@ -124,6 +124,8 @@ TEST_F(ZXFunctionalityTest, complexCircuit) { << "rzx(pi/4) q[0], q[1];" << "ecr q[0], q[1];" << "dcx q[0], q[1];" + << "r(pi/8, pi/4) q[2];" + << "r(-pi/8, pi/4) q[2];" << "dcx q[1], q[0];" << "ecr q[0], q[1];" << "rzx(-pi/4) q[0], q[1];" From 49cdd193ebdacd63ea04781f7704694b5429be23 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 15:02:35 +0100 Subject: [PATCH 14/28] =?UTF-8?q?=E2=9C=A8=20add=20support=20to=20Qiskit?= =?UTF-8?q?=20plugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- python/mqt/core/plugins/qiskit/mqt_to_qiskit.py | 2 ++ python/mqt/core/plugins/qiskit/qiskit_to_mqt.py | 4 ++++ test/python/plugins/test_qiskit.py | 1 + 3 files changed, 7 insertions(+) diff --git a/python/mqt/core/plugins/qiskit/mqt_to_qiskit.py b/python/mqt/core/plugins/qiskit/mqt_to_qiskit.py index fae12505fd..08a156dff6 100644 --- a/python/mqt/core/plugins/qiskit/mqt_to_qiskit.py +++ b/python/mqt/core/plugins/qiskit/mqt_to_qiskit.py @@ -26,6 +26,7 @@ HGate, IGate, PhaseGate, + RGate, RXGate, RXXGate, RYGate, @@ -178,6 +179,7 @@ def _add_standard_operation(circ: QuantumCircuit, op: StandardOperation, qubit_m gate_map_two_param: dict[OpType, type] = { OpType.u2: U2Gate, + OpType.r: RGate, OpType.xx_plus_yy: XXPlusYYGate, OpType.xx_minus_yy: XXMinusYYGate, } diff --git a/python/mqt/core/plugins/qiskit/qiskit_to_mqt.py b/python/mqt/core/plugins/qiskit/qiskit_to_mqt.py index ea31cc40e8..fce31f34a7 100644 --- a/python/mqt/core/plugins/qiskit/qiskit_to_mqt.py +++ b/python/mqt/core/plugins/qiskit/qiskit_to_mqt.py @@ -132,6 +132,7 @@ def qiskit_to_mqt(circ: QuantumCircuit) -> QuantumComputation: "tdg", "p", "u1", + "r", "rx", "ry", "rz", @@ -265,6 +266,9 @@ def _emplace_operation( qargs = qargs[: -num_controls + 2] return _add_operation(qc, OpType.x, qargs, params, qubit_map) + if name in {"r", "prx"}: + return _add_operation(qc, OpType.r, qargs, params, qubit_map) + if name in {"rx", "crx", "mcrx"}: return _add_operation(qc, OpType.rx, qargs, params, qubit_map) diff --git a/test/python/plugins/test_qiskit.py b/test/python/plugins/test_qiskit.py index 7735356bde..5984ccd7fe 100644 --- a/test/python/plugins/test_qiskit.py +++ b/test/python/plugins/test_qiskit.py @@ -378,6 +378,7 @@ def test_operations() -> None: qc.sx(0) qc.csx(0, 1) qc.sxdg(0) + qc.r(0.5, 0.5, 0) qc.rx(0.5, 0) qc.crx(0.5, 0, 1) qc.ry(0.5, 0) From a9cde3e353691225267bc83b57a5a604654b50e9 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 15:04:27 +0100 Subject: [PATCH 15/28] =?UTF-8?q?=F0=9F=93=9D=20add=20changelog=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2b5e5bc5d..6dee39ba2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Added +- ✨ Add native support for `R(theta, phi)` gate ([#1283]) ([**@burgholzer**]) - ✨ Add A\*-search-based routing algorithm to MLIR transpilation routines ([#1237], [#1271], [#1279]) ([**@MatthiasReumann**]) ### Fixed @@ -220,6 +221,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool +[#1283]: https://github.com/munich-quantum-toolkit/core/pull/1283 [#1279]: https://github.com/munich-quantum-toolkit/core/pull/1279 [#1276]: https://github.com/munich-quantum-toolkit/core/pull/1276 [#1271]: https://github.com/munich-quantum-toolkit/core/pull/1271 From 94139e18eb7f0cea972b7b76e1b86a107708c5e8 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 15:22:48 +0100 Subject: [PATCH 16/28] =?UTF-8?q?=F0=9F=9A=A8=20use=20designated=20initial?= =?UTF-8?q?izers=20everywhere?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- include/mqt-core/qasm3/StdGates.hpp | 197 +++++++++++++++++++++------- 1 file changed, 148 insertions(+), 49 deletions(-) diff --git a/include/mqt-core/qasm3/StdGates.hpp b/include/mqt-core/qasm3/StdGates.hpp index 6dd7a9f8ca..92fecf0b7b 100644 --- a/include/mqt-core/qasm3/StdGates.hpp +++ b/include/mqt-core/qasm3/StdGates.hpp @@ -49,42 +49,97 @@ const std::string QE1LIB = "gate rccx a, b, c {\n" const std::map> STANDARD_GATES = { // gates from which all other gates can be constructed. {"gphase", - std::make_shared(StandardGate({0, 0, 1, qc::GPhase}))}, - {"U", std::make_shared(StandardGate({0, 1, 3, qc::U}))}, + std::make_shared(StandardGate({.nControls = 0, + .nTargets = 0, + .nParameters = 1, + .type = qc::GPhase}))}, + {"U", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 3, .type = qc::U}))}, // natively supported gates - {"p", std::make_shared(StandardGate({0, 1, 1, qc::P}))}, - {"u1", std::make_shared(StandardGate({0, 1, 1, qc::P}))}, - {"phase", std::make_shared(StandardGate({0, 1, 1, qc::P}))}, - {"cphase", std::make_shared(StandardGate({1, 1, 1, qc::P}))}, - {"cp", std::make_shared(StandardGate({1, 1, 1, qc::P}))}, + {"p", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 1, .type = qc::P}))}, + {"u1", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 1, .type = qc::P}))}, + {"phase", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 1, .type = qc::P}))}, + {"cphase", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 1, .type = qc::P}))}, + {"cp", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 1, .type = qc::P}))}, - {"id", std::make_shared(StandardGate({0, 1, 0, qc::I}))}, - {"u2", std::make_shared(StandardGate({0, 1, 2, qc::U2}))}, - {"u3", std::make_shared(StandardGate({0, 1, 3, qc::U}))}, - {"u", std::make_shared(StandardGate({0, 1, 3, qc::U}))}, + {"id", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::I}))}, + {"u2", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 2, .type = qc::U2}))}, + {"u3", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 3, .type = qc::U}))}, + {"u", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 3, .type = qc::U}))}, - {"x", std::make_shared(StandardGate({0, 1, 0, qc::X}))}, - {"cx", std::make_shared(StandardGate({1, 1, 0, qc::X}))}, - {"CX", std::make_shared(StandardGate({1, 1, 0, qc::X}))}, - {"ccx", std::make_shared(StandardGate({2, 1, 0, qc::X}))}, - {"c3x", std::make_shared(StandardGate({3, 1, 0, qc::X}))}, - {"c4x", std::make_shared(StandardGate({4, 1, 0, qc::X}))}, + {"x", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::X}))}, + {"cx", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 0, .type = qc::X}))}, + {"CX", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 0, .type = qc::X}))}, + {"ccx", + std::make_shared(StandardGate( + {.nControls = 2, .nTargets = 1, .nParameters = 0, .type = qc::X}))}, + {"c3x", + std::make_shared(StandardGate( + {.nControls = 3, .nTargets = 1, .nParameters = 0, .type = qc::X}))}, + {"c4x", + std::make_shared(StandardGate( + {.nControls = 4, .nTargets = 1, .nParameters = 0, .type = qc::X}))}, - {"rx", std::make_shared(StandardGate({0, 1, 1, qc::RX}))}, - {"crx", std::make_shared(StandardGate({1, 1, 1, qc::RX}))}, + {"rx", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 1, .type = qc::RX}))}, + {"crx", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 1, .type = qc::RX}))}, - {"y", std::make_shared(StandardGate({0, 1, 0, qc::Y}))}, - {"cy", std::make_shared(StandardGate({1, 1, 0, qc::Y}))}, + {"y", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::Y}))}, + {"cy", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 0, .type = qc::Y}))}, - {"ry", std::make_shared(StandardGate({0, 1, 1, qc::RY}))}, - {"cry", std::make_shared(StandardGate({1, 1, 1, qc::RY}))}, + {"ry", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 1, .type = qc::RY}))}, + {"cry", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 1, .type = qc::RY}))}, - {"z", std::make_shared(StandardGate({0, 1, 0, qc::Z}))}, - {"cz", std::make_shared(StandardGate({1, 1, 0, qc::Z}))}, + {"z", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::Z}))}, + {"cz", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 0, .type = qc::Z}))}, - {"rz", std::make_shared(StandardGate({0, 1, 1, qc::RZ}))}, - {"crz", std::make_shared(StandardGate({1, 1, 1, qc::RZ}))}, + {"rz", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 1, .type = qc::RZ}))}, + {"crz", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 1, .type = qc::RZ}))}, {"r", std::make_shared(StandardGate( @@ -96,38 +151,82 @@ const std::map> STANDARD_GATES = { std::make_shared(StandardGate( {.nControls = 1, .nTargets = 1, .nParameters = 2, .type = qc::R}))}, - {"h", std::make_shared(StandardGate({0, 1, 0, qc::H}))}, - {"ch", std::make_shared(StandardGate({1, 1, 0, qc::H}))}, + {"h", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::H}))}, + {"ch", + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 1, .nParameters = 0, .type = qc::H}))}, - {"s", std::make_shared(StandardGate({0, 1, 0, qc::S}))}, - {"sdg", std::make_shared(StandardGate({0, 1, 0, qc::Sdg}))}, + {"s", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::S}))}, + {"sdg", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::Sdg}))}, - {"t", std::make_shared(StandardGate({0, 1, 0, qc::T}))}, - {"tdg", std::make_shared(StandardGate({0, 1, 0, qc::Tdg}))}, + {"t", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::T}))}, + {"tdg", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::Tdg}))}, - {"sx", std::make_shared(StandardGate({0, 1, 0, qc::SX}))}, - {"sxdg", std::make_shared(StandardGate({0, 1, 0, qc::SXdg}))}, + {"sx", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::SX}))}, + {"sxdg", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 1, .nParameters = 0, .type = qc::SXdg}))}, {"c3sqrtx", - std::make_shared(StandardGate({3, 1, 0, qc::SXdg}))}, + std::make_shared(StandardGate( + {.nControls = 3, .nTargets = 1, .nParameters = 0, .type = qc::SXdg}))}, - {"swap", std::make_shared(StandardGate({0, 2, 0, qc::SWAP}))}, + {"swap", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 2, .nParameters = 0, .type = qc::SWAP}))}, {"cswap", - std::make_shared(StandardGate({1, 2, 0, qc::SWAP}))}, + std::make_shared(StandardGate( + {.nControls = 1, .nTargets = 2, .nParameters = 0, .type = qc::SWAP}))}, {"iswap", - std::make_shared(StandardGate({0, 2, 0, qc::iSWAP}))}, + std::make_shared(StandardGate({.nControls = 0, + .nTargets = 2, + .nParameters = 0, + .type = qc::iSWAP}))}, {"iswapdg", - std::make_shared(StandardGate({0, 2, 0, qc::iSWAPdg}))}, - - {"rxx", std::make_shared(StandardGate({0, 2, 1, qc::RXX}))}, - {"ryy", std::make_shared(StandardGate({0, 2, 1, qc::RYY}))}, - {"rzz", std::make_shared(StandardGate({0, 2, 1, qc::RZZ}))}, - {"rzx", std::make_shared(StandardGate({0, 2, 1, qc::RZX}))}, - {"dcx", std::make_shared(StandardGate({0, 2, 0, qc::DCX}))}, - {"ecr", std::make_shared(StandardGate({0, 2, 0, qc::ECR}))}, + std::make_shared(StandardGate({.nControls = 0, + .nTargets = 2, + .nParameters = 0, + .type = qc::iSWAPdg}))}, + + {"rxx", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 2, .nParameters = 1, .type = qc::RXX}))}, + {"ryy", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 2, .nParameters = 1, .type = qc::RYY}))}, + {"rzz", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 2, .nParameters = 1, .type = qc::RZZ}))}, + {"rzx", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 2, .nParameters = 1, .type = qc::RZX}))}, + {"dcx", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 2, .nParameters = 0, .type = qc::DCX}))}, + {"ecr", + std::make_shared(StandardGate( + {.nControls = 0, .nTargets = 2, .nParameters = 0, .type = qc::ECR}))}, {"xx_minus_yy", - std::make_shared(StandardGate({0, 2, 2, qc::XXminusYY}))}, + std::make_shared(StandardGate({.nControls = 0, + .nTargets = 2, + .nParameters = 2, + .type = qc::XXminusYY}))}, {"xx_plus_yy", - std::make_shared(StandardGate({0, 2, 2, qc::XXplusYY}))}, + std::make_shared(StandardGate({.nControls = 0, + .nTargets = 2, + .nParameters = 2, + .type = qc::XXplusYY}))}, }; } // namespace qasm3 From 4da7a8f7a8b07078bbd8758b2d35d89b88250cda Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 15:23:34 +0100 Subject: [PATCH 17/28] =?UTF-8?q?=F0=9F=A9=B9=20fix=20qubit=20SSA=20value?= =?UTF-8?q?=20in=20MLIR=20test=20suite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir b/mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir index 5271b9fabc..0010a38822 100644 --- a/mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir +++ b/mlir/test/Dialect/MQTOpt/IR/dialect_features.mlir @@ -490,7 +490,7 @@ module { %q0_7, %q1_7 = mqtopt.r(%c0_f64, %c0_f64) %q0_6 ctrl %q1_6 : !mqtopt.Qubit ctrl !mqtopt.Qubit memref.store %q0_7, %qreg[%i0] : memref<2x!mqtopt.Qubit> - memref.store %q1_0, %qreg[%i1] : memref<2x!mqtopt.Qubit> + memref.store %q1_7, %qreg[%i1] : memref<2x!mqtopt.Qubit> memref.dealloc %qreg : memref<2x!mqtopt.Qubit> return From 57fb6fbb0542a8656bb334a3a4daf09112aed1c5 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 15:25:37 +0100 Subject: [PATCH 18/28] =?UTF-8?q?=F0=9F=A9=B9=20fix=20type=20stubs=20for?= =?UTF-8?q?=20new=20operation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- python/mqt/core/ir/__init__.pyi | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python/mqt/core/ir/__init__.pyi b/python/mqt/core/ir/__init__.pyi index 16ace70d08..a6c979d53c 100644 --- a/python/mqt/core/ir/__init__.pyi +++ b/python/mqt/core/ir/__init__.pyi @@ -1003,7 +1003,7 @@ class QuantumComputation(MutableSequence[Operation]): :meth:`sxdg` """ - def r(self, theta: float, phi: float, q: int) -> None: + def r(self, theta: float | Expression, phi: float | Expression, q: int) -> None: r"""Apply an :math:`R(\theta, \phi)` gate. .. math:: @@ -1017,7 +1017,7 @@ class QuantumComputation(MutableSequence[Operation]): q: The target qubit """ - def cr(self, theta: float, phi: float, control: Control | int, target: int) -> None: + def cr(self, theta: float | Expression, phi: float | Expression, control: Control | int, target: int) -> None: r"""Apply a controlled :math:`R(\theta, \phi)` gate. Args: @@ -1030,7 +1030,9 @@ class QuantumComputation(MutableSequence[Operation]): :meth:`r` """ - def mcr(self, theta: float, phi: float, controls: set[Control | int], target: int) -> None: + def mcr( + self, theta: float | Expression, phi: float | Expression, controls: set[Control | int], target: int + ) -> None: r"""Apply a multi-controlled :math:`R(\theta, \phi)` gate. Args: From c1956aeaf1d96d2ec5ec4ede7ba9847e88e82013 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 15:26:45 +0100 Subject: [PATCH 19/28] =?UTF-8?q?=F0=9F=A9=B9=20fix=20`prx`=20implementati?= =?UTF-8?q?on=20in=20QIR=20runtime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/qir/runtime/QIR.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qir/runtime/QIR.cpp b/src/qir/runtime/QIR.cpp index eae286eae0..e538c3d997 100644 --- a/src/qir/runtime/QIR.cpp +++ b/src/qir/runtime/QIR.cpp @@ -196,7 +196,7 @@ void __quantum__qis__r__body(Qubit* qubit, const double theta, void __quantum__qis__prx__body(Qubit* qubit, const double theta, const double phi) { auto& runtime = qir::Runtime::getInstance(); - runtime.apply(phi, theta, qubit); + runtime.apply(theta, phi, qubit); } void __quantum__qis__rx__body(Qubit* qubit, const double phi) { From 89f91f79fe720a59c23fb83e18b064e536b2cd82 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 15:35:10 +0100 Subject: [PATCH 20/28] =?UTF-8?q?=E2=9C=85=20add=20`r`=20to=20QASM=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- test/circuits/test.qasm | 1 + 1 file changed, 1 insertion(+) diff --git a/test/circuits/test.qasm b/test/circuits/test.qasm index 59e84016b4..0f76e80127 100755 --- a/test/circuits/test.qasm +++ b/test/circuits/test.qasm @@ -14,6 +14,7 @@ x q; x q[0]; y q[0]; z q[0]; +r(1, 2) q[0]; rx(pi/2) q[0]; rx(pi/4) q[0]; ry(pi/4) q[0]; From ec4fe7f4e156de9b89e9516f099e2b6bacdc3f17 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 15:54:44 +0100 Subject: [PATCH 21/28] =?UTF-8?q?=E2=9A=A1=20faster=20`opTypeFromString`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- include/mqt-core/ir/operations/OpType.hpp | 3 +- src/ir/operations/OpType.cpp | 178 ++++++++++++---------- 2 files changed, 97 insertions(+), 84 deletions(-) diff --git a/include/mqt-core/ir/operations/OpType.hpp b/include/mqt-core/ir/operations/OpType.hpp index abcb1540a3..2bdeda0294 100644 --- a/include/mqt-core/ir/operations/OpType.hpp +++ b/include/mqt-core/ir/operations/OpType.hpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace qc { @@ -101,7 +102,7 @@ inline std::ostream& operator<<(std::ostream& out, const OpType opType) { return out << toString(opType); } -[[nodiscard]] OpType opTypeFromString(const std::string& opType); +[[nodiscard]] OpType opTypeFromString(std::string_view opType); inline std::istream& operator>>(std::istream& in, OpType& opType) { std::string opTypeStr; diff --git a/src/ir/operations/OpType.cpp b/src/ir/operations/OpType.cpp index 939c22f25e..9a4edc5cfa 100644 --- a/src/ir/operations/OpType.cpp +++ b/src/ir/operations/OpType.cpp @@ -10,6 +10,9 @@ #include "ir/operations/OpType.hpp" +#include +#include +#include #include #include #include @@ -64,90 +67,99 @@ std::string shortName(const OpType opType) { return toString(opType); } } -OpType opTypeFromString(const std::string& opType) { - static const std::unordered_map OP_NAME_TO_TYPE = { - {"none", OpType::None}, - {"gphase", OpType::GPhase}, - {"i", OpType::I}, - {"id", OpType::I}, - {"h", OpType::H}, - {"ch", OpType::H}, - {"x", OpType::X}, - {"cnot", OpType::X}, - {"cx", OpType::X}, - {"mcx", OpType::X}, - {"y", OpType::Y}, - {"cy", OpType::Y}, - {"z", OpType::Z}, - {"cz", OpType::Z}, - {"s", OpType::S}, - {"cs", OpType::S}, - {"sdg", OpType::Sdg}, - {"csdg", OpType::Sdg}, - {"t", OpType::T}, - {"ct", OpType::T}, - {"tdg", OpType::Tdg}, - {"ctdg", OpType::Tdg}, - {"v", OpType::V}, - {"vdg", OpType::Vdg}, - {"u", OpType::U}, - {"cu", OpType::U}, - {"u3", OpType::U}, - {"cu3", OpType::U}, - {"u2", OpType::U2}, - {"cu2", OpType::U2}, - {"p", OpType::P}, - {"cp", OpType::P}, - {"mcp", OpType::P}, - {"phase", OpType::P}, - {"cphase", OpType::P}, - {"mcphase", OpType::P}, - {"u1", OpType::P}, - {"cu1", OpType::P}, - {"sx", OpType::SX}, - {"csx", OpType::SX}, - {"sxdg", OpType::SXdg}, - {"csxdg", OpType::SXdg}, - {"rx", OpType::RX}, - {"crx", OpType::RX}, - {"ry", OpType::RY}, - {"cry", OpType::RY}, - {"rz", OpType::RZ}, - {"crz", OpType::RZ}, - {"prx", OpType::R}, - {"r", OpType::R}, - {"cr", OpType::R}, - {"swap", OpType::SWAP}, - {"cswap", OpType::SWAP}, - {"iswap", OpType::iSWAP}, - {"iswapdg", OpType::iSWAPdg}, - {"peres", OpType::Peres}, - {"peresdg", OpType::Peresdg}, - {"dcx", OpType::DCX}, - {"ecr", OpType::ECR}, - {"rxx", OpType::RXX}, - {"ryy", OpType::RYY}, - {"rzz", OpType::RZZ}, - {"rzx", OpType::RZX}, - {"xx_minus_yy", OpType::XXminusYY}, - {"xx_plus_yy", OpType::XXplusYY}, - {"measure", OpType::Measure}, - {"reset", OpType::Reset}, - {"barrier", OpType::Barrier}, - {"if_else", OpType::IfElse}, - {"compound", OpType::Compound}, - {"move", OpType::Move}, - {"aod_activate", OpType::AodActivate}, - {"aod_deactivate", OpType::AodDeactivate}, - {"aod_move", OpType::AodMove}, - }; - // try to find the operation type in the map of known operation types and - // return it if found or throw an exception otherwise. - if (const auto it = OP_NAME_TO_TYPE.find(opType); - it != OP_NAME_TO_TYPE.end()) { - return OP_NAME_TO_TYPE.at(opType); +namespace { +// Sorted lexicographically by `name` +constexpr std::array, 74> OP_NAME_TO_TYPE{{ + {"aod_activate", AodActivate}, + {"aod_deactivate", AodDeactivate}, + {"aod_move", AodMove}, + {"barrier", Barrier}, + {"ch", H}, + {"cnot", X}, + {"compound", Compound}, + {"cp", P}, + {"cphase", P}, + {"cr", R}, + {"crx", RX}, + {"cry", RY}, + {"crz", RZ}, + {"cs", S}, + {"csdg", Sdg}, + {"cswap", SWAP}, + {"csx", SX}, + {"csxdg", SXdg}, + {"ct", T}, + {"ctdg", Tdg}, + {"cu", U}, + {"cu1", P}, + {"cu2", U2}, + {"cu3", U}, + {"cx", X}, + {"cy", Y}, + {"cz", Z}, + {"dcx", DCX}, + {"ecr", ECR}, + {"gphase", GPhase}, + {"h", H}, + {"i", I}, + {"id", I}, + {"if_else", IfElse}, + {"iswap", iSWAP}, + {"iswapdg", iSWAPdg}, + {"mcp", P}, + {"mcphase", P}, + {"mcx", X}, + {"measure", Measure}, + {"move", Move}, + {"none", None}, + {"p", P}, + {"peres", Peres}, + {"peresdg", Peresdg}, + {"phase", P}, + {"prx", R}, + {"r", R}, + {"reset", Reset}, + {"rx", RX}, + {"rxx", RXX}, + {"ry", RY}, + {"ryy", RYY}, + {"rz", RZ}, + {"rzx", RZX}, + {"rzz", RZZ}, + {"s", S}, + {"sdg", Sdg}, + {"swap", SWAP}, + {"sx", SX}, + {"sxdg", SXdg}, + {"t", T}, + {"tdg", Tdg}, + {"u", U}, + {"u1", P}, + {"u2", U2}, + {"u3", U}, + {"v", V}, + {"vdg", Vdg}, + {"x", X}, + {"xx_minus_yy", XXminusYY}, + {"xx_plus_yy", XXplusYY}, + {"y", Y}, + {"z", Z}, +}}; +static_assert(std::ranges::is_sorted(OP_NAME_TO_TYPE.cbegin(), + OP_NAME_TO_TYPE.cend(), + [](const auto& lhs, const auto& rhs) { + return lhs.first < rhs.first; + })); +} // namespace + +OpType opTypeFromString(std::string_view opType) { + const auto* const it = std::ranges::lower_bound( + OP_NAME_TO_TYPE, opType, {}, &std::pair::first); + if (it != OP_NAME_TO_TYPE.end() && it->first == opType) { + return it->second; } - throw std::invalid_argument("Unsupported operation type: " + opType); + throw std::invalid_argument("Unsupported operation type: " + + std::string(opType)); } } // namespace qc From c38257231a9d2edfc26cb1ad038a476af29d7abd Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 16:06:55 +0100 Subject: [PATCH 22/28] =?UTF-8?q?=F0=9F=8F=81=20fix=20windows=20build?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/ir/operations/OpType.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ir/operations/OpType.cpp b/src/ir/operations/OpType.cpp index 9a4edc5cfa..96fd7cb87f 100644 --- a/src/ir/operations/OpType.cpp +++ b/src/ir/operations/OpType.cpp @@ -153,8 +153,8 @@ static_assert(std::ranges::is_sorted(OP_NAME_TO_TYPE.cbegin(), })); } // namespace -OpType opTypeFromString(std::string_view opType) { - const auto* const it = std::ranges::lower_bound( +OpType opTypeFromString(const std::string_view opType) { + const auto it = std::ranges::lower_bound( OP_NAME_TO_TYPE, opType, {}, &std::pair::first); if (it != OP_NAME_TO_TYPE.end() && it->first == opType) { return it->second; From 92d2160db2f5a95d1601461a766b39a095f1e10b Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 17:24:22 +0100 Subject: [PATCH 23/28] =?UTF-8?q?=F0=9F=9A=A8=20address=20linter=20warning?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/ir/operations/OpType.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ir/operations/OpType.cpp b/src/ir/operations/OpType.cpp index 96fd7cb87f..2b44e04719 100644 --- a/src/ir/operations/OpType.cpp +++ b/src/ir/operations/OpType.cpp @@ -12,11 +12,11 @@ #include #include -#include #include #include #include #include +#include namespace qc { std::string toString(const OpType opType) { @@ -154,9 +154,9 @@ static_assert(std::ranges::is_sorted(OP_NAME_TO_TYPE.cbegin(), } // namespace OpType opTypeFromString(const std::string_view opType) { - const auto it = std::ranges::lower_bound( + const auto* const it = std::ranges::lower_bound( OP_NAME_TO_TYPE, opType, {}, &std::pair::first); - if (it != OP_NAME_TO_TYPE.end() && it->first == opType) { + if (it != nullptr && it->first == opType) { return it->second; } throw std::invalid_argument("Unsupported operation type: " + From 5d1241cfd5799b1de5ae7ad3e69f27c178e2f0eb Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 17:34:46 +0100 Subject: [PATCH 24/28] =?UTF-8?q?=F0=9F=8F=81=20fix=20Windows=20(again)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/ir/operations/OpType.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ir/operations/OpType.cpp b/src/ir/operations/OpType.cpp index 2b44e04719..3878b2d60d 100644 --- a/src/ir/operations/OpType.cpp +++ b/src/ir/operations/OpType.cpp @@ -154,9 +154,11 @@ static_assert(std::ranges::is_sorted(OP_NAME_TO_TYPE.cbegin(), } // namespace OpType opTypeFromString(const std::string_view opType) { - const auto* const it = std::ranges::lower_bound( + // clang-tidy produces a false-positive that produces a Windows compile error + // when accepted. NOLINTNEXTLINE(*-qualified-auto) + const auto it = std::ranges::lower_bound( OP_NAME_TO_TYPE, opType, {}, &std::pair::first); - if (it != nullptr && it->first == opType) { + if (it != OP_NAME_TO_TYPE.end() && it->first == opType) { return it->second; } throw std::invalid_argument("Unsupported operation type: " + From f1cc80f5b412d8800dbb30c7bfb91ca500ae5239 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 18:23:15 +0100 Subject: [PATCH 25/28] Add documentation for prx as R gate alias in QIR runtime (#1285) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses feedback on PR #1283 requesting documentation for the `__quantum__qis__prx__body` function to clarify that `prx` is an alias for the R gate. ## Changes - Added inline comment to `__quantum__qis__prx__body` in `src/qir/runtime/QIR.cpp` documenting the alias relationship ```cpp // prx is an alias for the R gate void __quantum__qis__prx__body(Qubit* qubit, const double theta, const double phi) { auto& runtime = qir::Runtime::getInstance(); runtime.apply(theta, phi, qubit); } ``` Both `prx` and `r` map to the same underlying `OpType::R` and use identical implementations. --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: burgholzer <6358767+burgholzer@users.noreply.github.com> --- src/qir/runtime/QIR.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qir/runtime/QIR.cpp b/src/qir/runtime/QIR.cpp index e538c3d997..04439c421d 100644 --- a/src/qir/runtime/QIR.cpp +++ b/src/qir/runtime/QIR.cpp @@ -193,6 +193,7 @@ void __quantum__qis__r__body(Qubit* qubit, const double theta, runtime.apply(theta, phi, qubit); } +// prx is an alias for the R gate void __quantum__qis__prx__body(Qubit* qubit, const double theta, const double phi) { auto& runtime = qir::Runtime::getInstance(); From c189c20907338747fb8797f7e71814d00957520a Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 18:23:43 +0100 Subject: [PATCH 26/28] =?UTF-8?q?Add=20Doxygen=20documentation=20for=20R(?= =?UTF-8?q?=CE=B8,=20=CF=86)=20gate=20matrix=20implementation=20(#1284)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses review feedback on PR #1283 requesting documentation for the `rMat` function implementation. ## Changes - Added proper Doxygen-style function docstring with `@brief`, `@param`, `@return`, and `@details` sections - Documented the mathematical formula: `R(θ, φ) = exp(-i*θ/2*(cos(φ)X + sin(φ)Y))` - Documented the explicit matrix representation: `[[cos(θ/2), -i*e^(-iφ)*sin(θ/2)], [-i*e^(iφ)*sin(θ/2), cos(θ/2)]]` - Added parameter descriptions for `theta` (rotation angle) and `phi` (rotation axis angle) The documentation clarifies the relationship between the exponential form and the matrix elements computed in the implementation, following the standard Doxygen format used throughout the codebase. ```cpp /** * @brief Computes the matrix representation of the R(θ, φ) gate. * @param theta The rotation angle θ. * @param phi The rotation axis angle φ. * @return The gate matrix for the R(θ, φ) rotation. * * @details The R(θ, φ) gate is defined as R(θ, φ) = exp(-i*θ/2*(cos(φ)X + sin(φ)Y)), * which results in the matrix: * [[cos(θ/2), -i*e^(-iφ)*sin(θ/2)], * [-i*e^(iφ)*sin(θ/2), cos(θ/2)]] */ GateMatrix rMat(const fp theta, const fp phi) { // ... implementation } ``` --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: burgholzer <6358767+burgholzer@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Lukas Burgholzer --- src/dd/GateMatrixDefinitions.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/dd/GateMatrixDefinitions.cpp b/src/dd/GateMatrixDefinitions.cpp index 8877379df2..c62780e064 100644 --- a/src/dd/GateMatrixDefinitions.cpp +++ b/src/dd/GateMatrixDefinitions.cpp @@ -65,6 +65,17 @@ GateMatrix rzMat(const fp lambda) { {std::cos(lambda / 2.), std::sin(lambda / 2.)}}}; } +/** + * @brief Computes the matrix representation of the R(θ, φ) gate. + * @param theta The rotation angle θ. + * @param phi The rotation axis angle φ. + * @return The gate matrix for the R(θ, φ) rotation. + * + * @details The R(θ, φ) gate is defined as R(θ, φ) = exp(-i*θ/2*(cos(φ)X + + * sin(φ)Y)), which results in the matrix: + * [[cos(θ/2), -i*e^(-iφ)*sin(θ/2)], + * [-i*e^(iφ)*sin(θ/2), cos(θ/2)]] + */ GateMatrix rMat(const fp theta, const fp phi) { const auto cosTheta = std::cos(theta / 2.); const auto sinTheta = std::sin(theta / 2.); From c6811278eb3d925738d15dc15c656439a40dce05 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 18:33:54 +0100 Subject: [PATCH 27/28] =?UTF-8?q?=F0=9F=8E=A8=20use=20CTAD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/ir/operations/OpType.cpp | 167 ++++++++++++++++++----------------- 1 file changed, 86 insertions(+), 81 deletions(-) diff --git a/src/ir/operations/OpType.cpp b/src/ir/operations/OpType.cpp index 3878b2d60d..64de95fb9b 100644 --- a/src/ir/operations/OpType.cpp +++ b/src/ir/operations/OpType.cpp @@ -69,97 +69,102 @@ std::string shortName(const OpType opType) { } namespace { +struct NameToType { + std::string_view name; + OpType type; +}; + // Sorted lexicographically by `name` -constexpr std::array, 74> OP_NAME_TO_TYPE{{ - {"aod_activate", AodActivate}, - {"aod_deactivate", AodDeactivate}, - {"aod_move", AodMove}, - {"barrier", Barrier}, - {"ch", H}, - {"cnot", X}, - {"compound", Compound}, - {"cp", P}, - {"cphase", P}, - {"cr", R}, - {"crx", RX}, - {"cry", RY}, - {"crz", RZ}, - {"cs", S}, - {"csdg", Sdg}, - {"cswap", SWAP}, - {"csx", SX}, - {"csxdg", SXdg}, - {"ct", T}, - {"ctdg", Tdg}, - {"cu", U}, - {"cu1", P}, - {"cu2", U2}, - {"cu3", U}, - {"cx", X}, - {"cy", Y}, - {"cz", Z}, - {"dcx", DCX}, - {"ecr", ECR}, - {"gphase", GPhase}, - {"h", H}, - {"i", I}, - {"id", I}, - {"if_else", IfElse}, - {"iswap", iSWAP}, - {"iswapdg", iSWAPdg}, - {"mcp", P}, - {"mcphase", P}, - {"mcx", X}, - {"measure", Measure}, - {"move", Move}, - {"none", None}, - {"p", P}, - {"peres", Peres}, - {"peresdg", Peresdg}, - {"phase", P}, - {"prx", R}, - {"r", R}, - {"reset", Reset}, - {"rx", RX}, - {"rxx", RXX}, - {"ry", RY}, - {"ryy", RYY}, - {"rz", RZ}, - {"rzx", RZX}, - {"rzz", RZZ}, - {"s", S}, - {"sdg", Sdg}, - {"swap", SWAP}, - {"sx", SX}, - {"sxdg", SXdg}, - {"t", T}, - {"tdg", Tdg}, - {"u", U}, - {"u1", P}, - {"u2", U2}, - {"u3", U}, - {"v", V}, - {"vdg", Vdg}, - {"x", X}, - {"xx_minus_yy", XXminusYY}, - {"xx_plus_yy", XXplusYY}, - {"y", Y}, - {"z", Z}, -}}; +constexpr std::array OP_NAME_TO_TYPE{ + NameToType{.name = "aod_activate", .type = AodActivate}, + NameToType{.name = "aod_deactivate", .type = AodDeactivate}, + NameToType{.name = "aod_move", .type = AodMove}, + NameToType{.name = "barrier", .type = Barrier}, + NameToType{.name = "ch", .type = H}, + NameToType{.name = "cnot", .type = X}, + NameToType{.name = "compound", .type = Compound}, + NameToType{.name = "cp", .type = P}, + NameToType{.name = "cphase", .type = P}, + NameToType{.name = "cr", .type = R}, + NameToType{.name = "crx", .type = RX}, + NameToType{.name = "cry", .type = RY}, + NameToType{.name = "crz", .type = RZ}, + NameToType{.name = "cs", .type = S}, + NameToType{.name = "csdg", .type = Sdg}, + NameToType{.name = "cswap", .type = SWAP}, + NameToType{.name = "csx", .type = SX}, + NameToType{.name = "csxdg", .type = SXdg}, + NameToType{.name = "ct", .type = T}, + NameToType{.name = "ctdg", .type = Tdg}, + NameToType{.name = "cu", .type = U}, + NameToType{.name = "cu1", .type = P}, + NameToType{.name = "cu2", .type = U2}, + NameToType{.name = "cu3", .type = U}, + NameToType{.name = "cx", .type = X}, + NameToType{.name = "cy", .type = Y}, + NameToType{.name = "cz", .type = Z}, + NameToType{.name = "dcx", .type = DCX}, + NameToType{.name = "ecr", .type = ECR}, + NameToType{.name = "gphase", .type = GPhase}, + NameToType{.name = "h", .type = H}, + NameToType{.name = "i", .type = I}, + NameToType{.name = "id", .type = I}, + NameToType{.name = "if_else", .type = IfElse}, + NameToType{.name = "iswap", .type = iSWAP}, + NameToType{.name = "iswapdg", .type = iSWAPdg}, + NameToType{.name = "mcp", .type = P}, + NameToType{.name = "mcphase", .type = P}, + NameToType{.name = "mcx", .type = X}, + NameToType{.name = "measure", .type = Measure}, + NameToType{.name = "move", .type = Move}, + NameToType{.name = "none", .type = None}, + NameToType{.name = "p", .type = P}, + NameToType{.name = "peres", .type = Peres}, + NameToType{.name = "peresdg", .type = Peresdg}, + NameToType{.name = "phase", .type = P}, + NameToType{.name = "prx", .type = R}, + NameToType{.name = "r", .type = R}, + NameToType{.name = "reset", .type = Reset}, + NameToType{.name = "rx", .type = RX}, + NameToType{.name = "rxx", .type = RXX}, + NameToType{.name = "ry", .type = RY}, + NameToType{.name = "ryy", .type = RYY}, + NameToType{.name = "rz", .type = RZ}, + NameToType{.name = "rzx", .type = RZX}, + NameToType{.name = "rzz", .type = RZZ}, + NameToType{.name = "s", .type = S}, + NameToType{.name = "sdg", .type = Sdg}, + NameToType{.name = "swap", .type = SWAP}, + NameToType{.name = "sx", .type = SX}, + NameToType{.name = "sxdg", .type = SXdg}, + NameToType{.name = "t", .type = T}, + NameToType{.name = "tdg", .type = Tdg}, + NameToType{.name = "u", .type = U}, + NameToType{.name = "u1", .type = P}, + NameToType{.name = "u2", .type = U2}, + NameToType{.name = "u3", .type = U}, + NameToType{.name = "v", .type = V}, + NameToType{.name = "vdg", .type = Vdg}, + NameToType{.name = "x", .type = X}, + NameToType{.name = "xx_minus_yy", .type = XXminusYY}, + NameToType{.name = "xx_plus_yy", .type = XXplusYY}, + NameToType{.name = "y", .type = Y}, + NameToType{.name = "z", .type = Z}, +}; static_assert(std::ranges::is_sorted(OP_NAME_TO_TYPE.cbegin(), OP_NAME_TO_TYPE.cend(), [](const auto& lhs, const auto& rhs) { - return lhs.first < rhs.first; + return lhs.name < rhs.name; })); } // namespace OpType opTypeFromString(const std::string_view opType) { // clang-tidy produces a false-positive that produces a Windows compile error // when accepted. NOLINTNEXTLINE(*-qualified-auto) - const auto it = std::ranges::lower_bound( - OP_NAME_TO_TYPE, opType, {}, &std::pair::first); - if (it != OP_NAME_TO_TYPE.end() && it->first == opType) { - return it->second; + const auto it = + std::ranges::lower_bound(OP_NAME_TO_TYPE, opType, {}, &NameToType::name); + if (it != OP_NAME_TO_TYPE.end() && it->name == opType) { + return it->type; } throw std::invalid_argument("Unsupported operation type: " + std::string(opType)); From c4a992250fd4b59728f1d39ab40b72fdfd7fbc62 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Sat, 1 Nov 2025 18:49:13 +0100 Subject: [PATCH 28/28] =?UTF-8?q?=F0=9F=9A=A8=20fix=20linter=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/ir/operations/OpType.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ir/operations/OpType.cpp b/src/ir/operations/OpType.cpp index 64de95fb9b..b936ee3f55 100644 --- a/src/ir/operations/OpType.cpp +++ b/src/ir/operations/OpType.cpp @@ -16,7 +16,6 @@ #include #include #include -#include namespace qc { std::string toString(const OpType opType) {