diff --git a/CHANGELOG.md b/CHANGELOG.md index 938f4ada3..0b2d12057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Added -- ✨ Add initial infrastructure for new QC and QCO MLIR dialects ([#1264], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1465]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**]) +- ✨ Add initial infrastructure for new QC and QCO MLIR dialects ([#1264], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**]) ### Changed @@ -317,6 +317,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool [#1466]: https://github.com/munich-quantum-toolkit/core/pull/1466 [#1465]: https://github.com/munich-quantum-toolkit/core/pull/1465 +[#1464]: https://github.com/munich-quantum-toolkit/core/pull/1464 [#1458]: https://github.com/munich-quantum-toolkit/core/pull/1458 [#1453]: https://github.com/munich-quantum-toolkit/core/pull/1453 [#1447]: https://github.com/munich-quantum-toolkit/core/pull/1447 diff --git a/mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp b/mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp index 2cfeb1516..725afd6d7 100644 --- a/mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp +++ b/mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp @@ -11,6 +11,7 @@ #include "mlir/Dialect/QC/Builder/QCProgramBuilder.h" #include "mlir/Dialect/QC/IR/QCDialect.h" +#include "mlir/Dialect/Utils/Utils.h" #include #include @@ -30,6 +31,8 @@ #include #include +using namespace mlir::utils; + namespace mlir::qc { QCProgramBuilder::QCProgramBuilder(MLIRContext* context) @@ -167,7 +170,8 @@ QCProgramBuilder& QCProgramBuilder::reset(Value qubit) { QCProgramBuilder& QCProgramBuilder::mc##OP_NAME( \ const std::variant&(PARAM), ValueRange controls) { \ checkFinalized(); \ - CtrlOp::create(*this, controls, [&] { OP_CLASS::create(*this, PARAM); }); \ + auto param = variantToValue(*this, getLoc(), PARAM); \ + CtrlOp::create(*this, controls, [&] { OP_CLASS::create(*this, param); }); \ return *this; \ } @@ -228,8 +232,9 @@ DEFINE_ONE_TARGET_ZERO_PARAMETER(SXdgOp, sxdg) const std::variant&(PARAM), ValueRange controls, \ Value target) { \ checkFinalized(); \ + auto param = variantToValue(*this, getLoc(), PARAM); \ CtrlOp::create(*this, controls, \ - [&] { OP_CLASS::create(*this, target, PARAM); }); \ + [&] { OP_CLASS::create(*this, target, param); }); \ return *this; \ } @@ -262,8 +267,10 @@ DEFINE_ONE_TARGET_ONE_PARAMETER(POp, p, theta) const std::variant&(PARAM2), ValueRange controls, \ Value target) { \ checkFinalized(); \ + auto param1 = variantToValue(*this, getLoc(), PARAM1); \ + auto param2 = variantToValue(*this, getLoc(), PARAM2); \ CtrlOp::create(*this, controls, \ - [&] { OP_CLASS::create(*this, target, PARAM1, PARAM2); }); \ + [&] { OP_CLASS::create(*this, target, param1, param2); }); \ return *this; \ } @@ -298,8 +305,11 @@ DEFINE_ONE_TARGET_TWO_PARAMETER(U2Op, u2, phi, lambda) const std::variant&(PARAM3), ValueRange controls, \ Value target) { \ checkFinalized(); \ + auto param1 = variantToValue(*this, getLoc(), PARAM1); \ + auto param2 = variantToValue(*this, getLoc(), PARAM2); \ + auto param3 = variantToValue(*this, getLoc(), PARAM3); \ CtrlOp::create(*this, controls, [&] { \ - OP_CLASS::create(*this, target, PARAM1, PARAM2, PARAM3); \ + OP_CLASS::create(*this, target, param1, param2, param3); \ }); \ return *this; \ } @@ -355,8 +365,9 @@ DEFINE_TWO_TARGET_ZERO_PARAMETER(ECROp, ecr) const std::variant&(PARAM), ValueRange controls, \ Value qubit0, Value qubit1) { \ checkFinalized(); \ + auto param = variantToValue(*this, getLoc(), PARAM); \ CtrlOp::create(*this, controls, \ - [&] { OP_CLASS::create(*this, qubit0, qubit1, PARAM); }); \ + [&] { OP_CLASS::create(*this, qubit0, qubit1, param); }); \ return *this; \ } @@ -390,8 +401,10 @@ DEFINE_TWO_TARGET_ONE_PARAMETER(RZZOp, rzz, theta) const std::variant&(PARAM2), ValueRange controls, \ Value qubit0, Value qubit1) { \ checkFinalized(); \ + auto param1 = variantToValue(*this, getLoc(), PARAM1); \ + auto param2 = variantToValue(*this, getLoc(), PARAM2); \ CtrlOp::create(*this, controls, [&] { \ - OP_CLASS::create(*this, qubit0, qubit1, PARAM1, PARAM2); \ + OP_CLASS::create(*this, qubit0, qubit1, param1, param2); \ }); \ return *this; \ } diff --git a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp index 65992dbeb..8ea9bc0d9 100644 --- a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp +++ b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp @@ -11,6 +11,7 @@ #include "mlir/Dialect/QCO/Builder/QCOProgramBuilder.h" #include "mlir/Dialect/QCO/IR/QCODialect.h" +#include "mlir/Dialect/Utils/Utils.h" #include #include @@ -32,6 +33,8 @@ #include #include +using namespace mlir::utils; + namespace mlir::qco { QCOProgramBuilder::QCOProgramBuilder(MLIRContext* context) @@ -210,10 +213,11 @@ Value QCOProgramBuilder::reset(Value qubit) { Value QCOProgramBuilder::c##OP_NAME( \ const std::variant&(PARAM), Value control) { \ checkFinalized(); \ + auto param = variantToValue(*this, getLoc(), PARAM); \ const auto controlsOut = \ ctrl(control, {}, \ [&](ValueRange /*targets*/) -> llvm::SmallVector { \ - OP_NAME(PARAM); \ + OP_NAME(param); \ return {}; \ }) \ .first; \ @@ -222,10 +226,11 @@ Value QCOProgramBuilder::reset(Value qubit) { ValueRange QCOProgramBuilder::mc##OP_NAME( \ const std::variant&(PARAM), ValueRange controls) { \ checkFinalized(); \ + auto param = variantToValue(*this, getLoc(), PARAM); \ const auto controlsOut = \ ctrl(controls, {}, \ [&](ValueRange /*targets*/) -> llvm::SmallVector { \ - OP_NAME(PARAM); \ + OP_NAME(param); \ return {}; \ }) \ .first; \ @@ -295,9 +300,10 @@ DEFINE_ONE_TARGET_ZERO_PARAMETER(SXdgOp, sxdg) const std::variant&(PARAM), Value control, \ Value target) { \ checkFinalized(); \ + auto param = variantToValue(*this, getLoc(), PARAM); \ const auto [controlsOut, targetsOut] = ctrl( \ control, target, [&](ValueRange targets) -> llvm::SmallVector { \ - return {OP_NAME(PARAM, targets[0])}; \ + return {OP_NAME(param, targets[0])}; \ }); \ return {controlsOut[0], targetsOut[0]}; \ } \ @@ -305,10 +311,11 @@ DEFINE_ONE_TARGET_ZERO_PARAMETER(SXdgOp, sxdg) const std::variant&(PARAM), ValueRange controls, \ Value target) { \ checkFinalized(); \ + auto param = variantToValue(*this, getLoc(), PARAM); \ const auto [controlsOut, targetsOut] = \ ctrl(controls, target, \ [&](ValueRange targets) -> llvm::SmallVector { \ - return {OP_NAME(PARAM, targets[0])}; \ + return {OP_NAME(param, targets[0])}; \ }); \ return {controlsOut, targetsOut[0]}; \ } @@ -337,9 +344,11 @@ DEFINE_ONE_TARGET_ONE_PARAMETER(POp, p, phi) const std::variant&(PARAM2), Value control, \ Value target) { \ checkFinalized(); \ + auto param1 = variantToValue(*this, getLoc(), PARAM1); \ + auto param2 = variantToValue(*this, getLoc(), PARAM2); \ const auto [controlsOut, targetsOut] = ctrl( \ control, target, [&](ValueRange targets) -> llvm::SmallVector { \ - return {OP_NAME(PARAM1, PARAM2, targets[0])}; \ + return {OP_NAME(param1, param2, targets[0])}; \ }); \ return {controlsOut[0], targetsOut[0]}; \ } \ @@ -348,10 +357,12 @@ DEFINE_ONE_TARGET_ONE_PARAMETER(POp, p, phi) const std::variant&(PARAM2), ValueRange controls, \ Value target) { \ checkFinalized(); \ + auto param1 = variantToValue(*this, getLoc(), PARAM1); \ + auto param2 = variantToValue(*this, getLoc(), PARAM2); \ const auto [controlsOut, targetsOut] = \ ctrl(controls, target, \ [&](ValueRange targets) -> llvm::SmallVector { \ - return {OP_NAME(PARAM1, PARAM2, targets[0])}; \ + return {OP_NAME(param1, param2, targets[0])}; \ }); \ return {controlsOut, targetsOut[0]}; \ } @@ -381,9 +392,12 @@ DEFINE_ONE_TARGET_TWO_PARAMETER(U2Op, u2, phi, lambda) const std::variant&(PARAM3), Value control, \ Value target) { \ checkFinalized(); \ + auto param1 = variantToValue(*this, getLoc(), PARAM1); \ + auto param2 = variantToValue(*this, getLoc(), PARAM2); \ + auto param3 = variantToValue(*this, getLoc(), PARAM3); \ const auto [controlsOut, targetsOut] = ctrl( \ control, target, [&](ValueRange targets) -> llvm::SmallVector { \ - return {OP_NAME(PARAM1, PARAM2, PARAM3, targets[0])}; \ + return {OP_NAME(param1, param2, param3, targets[0])}; \ }); \ return {controlsOut[0], targetsOut[0]}; \ } \ @@ -393,10 +407,13 @@ DEFINE_ONE_TARGET_TWO_PARAMETER(U2Op, u2, phi, lambda) const std::variant&(PARAM3), ValueRange controls, \ Value target) { \ checkFinalized(); \ + auto param1 = variantToValue(*this, getLoc(), PARAM1); \ + auto param2 = variantToValue(*this, getLoc(), PARAM2); \ + auto param3 = variantToValue(*this, getLoc(), PARAM3); \ const auto [controlsOut, targetsOut] = \ ctrl(controls, target, \ [&](ValueRange targets) -> llvm::SmallVector { \ - return {OP_NAME(PARAM1, PARAM2, PARAM3, targets[0])}; \ + return {OP_NAME(param1, param2, param3, targets[0])}; \ }); \ return {controlsOut, targetsOut[0]}; \ } @@ -466,10 +483,11 @@ DEFINE_TWO_TARGET_ZERO_PARAMETER(ECROp, ecr) const std::variant&(PARAM), Value control, Value qubit0, \ Value qubit1) { \ checkFinalized(); \ + auto param = variantToValue(*this, getLoc(), PARAM); \ const auto [controlsOut, targetsOut] = \ ctrl(control, {qubit0, qubit1}, \ [&](ValueRange targets) -> llvm::SmallVector { \ - auto [q0, q1] = OP_NAME(PARAM, targets[0], targets[1]); \ + auto [q0, q1] = OP_NAME(param, targets[0], targets[1]); \ return {q0, q1}; \ }); \ return {controlsOut[0], {targetsOut[0], targetsOut[1]}}; \ @@ -479,10 +497,11 @@ DEFINE_TWO_TARGET_ZERO_PARAMETER(ECROp, ecr) const std::variant&(PARAM), ValueRange controls, \ Value qubit0, Value qubit1) { \ checkFinalized(); \ + auto param = variantToValue(*this, getLoc(), PARAM); \ const auto [controlsOut, targetsOut] = \ ctrl(controls, {qubit0, qubit1}, \ [&](ValueRange targets) -> llvm::SmallVector { \ - auto [q0, q1] = OP_NAME(PARAM, targets[0], targets[1]); \ + auto [q0, q1] = OP_NAME(param, targets[0], targets[1]); \ return {q0, q1}; \ }); \ return {controlsOut, {targetsOut[0], targetsOut[1]}}; \ @@ -515,11 +534,13 @@ DEFINE_TWO_TARGET_ONE_PARAMETER(RZZOp, rzz, theta) const std::variant&(PARAM2), Value control, Value qubit0, \ Value qubit1) { \ checkFinalized(); \ + auto param1 = variantToValue(*this, getLoc(), PARAM1); \ + auto param2 = variantToValue(*this, getLoc(), PARAM2); \ const auto [controlsOut, targetsOut] = \ ctrl(control, {qubit0, qubit1}, \ [&](ValueRange targets) -> llvm::SmallVector { \ auto [q0, q1] = \ - OP_NAME(PARAM1, PARAM2, targets[0], targets[1]); \ + OP_NAME(param1, param2, targets[0], targets[1]); \ return {q0, q1}; \ }); \ return {controlsOut[0], {targetsOut[0], targetsOut[1]}}; \ @@ -530,11 +551,13 @@ DEFINE_TWO_TARGET_ONE_PARAMETER(RZZOp, rzz, theta) const std::variant&(PARAM2), ValueRange controls, \ Value qubit0, Value qubit1) { \ checkFinalized(); \ + auto param1 = variantToValue(*this, getLoc(), PARAM1); \ + auto param2 = variantToValue(*this, getLoc(), PARAM2); \ const auto [controlsOut, targetsOut] = \ ctrl(controls, {qubit0, qubit1}, \ [&](ValueRange targets) -> llvm::SmallVector { \ auto [q0, q1] = \ - OP_NAME(PARAM1, PARAM2, targets[0], targets[1]); \ + OP_NAME(param1, param2, targets[0], targets[1]); \ return {q0, q1}; \ }); \ return {controlsOut, {targetsOut[0], targetsOut[1]}}; \ diff --git a/mlir/unittests/Dialect/QCO/IR/Modifiers/test_qco_ctrl.cpp b/mlir/unittests/Dialect/QCO/IR/Modifiers/test_qco_ctrl.cpp index 91ed0d868..eb401b0e4 100644 --- a/mlir/unittests/Dialect/QCO/IR/Modifiers/test_qco_ctrl.cpp +++ b/mlir/unittests/Dialect/QCO/IR/Modifiers/test_qco_ctrl.cpp @@ -221,3 +221,16 @@ TEST_F(QCOCtrlOpTest, ParserErrors) { .get(), nullptr); } + +TEST_F(QCOCtrlOpTest, bodyUnitaryWithParameter) { + auto reg = builder.allocQubitRegister(2); + builder.crx(1.0, reg[0], reg[1]); + auto ctrlOp = cast(builder.getBlock()->getOperations().back()); + module = builder.finalize(); + + auto bodyUnitary = ctrlOp.getBodyUnitary(); + // Test if a valid unitary operation is returned + ASSERT_TRUE(bodyUnitary); + // Ensure it contains the correct operation type + EXPECT_EQ(bodyUnitary.getBaseSymbol(), "rx"); +}