From 91b3ef949edc12e84f376ace12a3a2ee5b2c64ab Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Mon, 1 Jun 2026 14:22:26 +0200 Subject: [PATCH 01/26] feat(mlir): :sparkles: implement dead gate elimination canonicalization patterns --- .../include/mlir/Dialect/QCO/IR/QCODialect.td | 2 ++ mlir/include/mlir/Dialect/QCO/IR/QCOOps.td | 1 + mlir/include/mlir/Dialect/QCO/QCOUtils.h | 18 +++++++++++++++ .../Dialect/QCO/IR/Operations/MeasureOp.cpp | 22 +++++++++++++++++++ .../lib/Dialect/QCO/IR/Operations/ResetOp.cpp | 14 ++++++++++++ mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 20 +++++++++++++++++ mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp | 14 ++++++++++++ 7 files changed, 91 insertions(+) diff --git a/mlir/include/mlir/Dialect/QCO/IR/QCODialect.td b/mlir/include/mlir/Dialect/QCO/IR/QCODialect.td index 62d1f5bba4..e7d98a0367 100644 --- a/mlir/include/mlir/Dialect/QCO/IR/QCODialect.td +++ b/mlir/include/mlir/Dialect/QCO/IR/QCODialect.td @@ -38,6 +38,8 @@ def QCODialect : Dialect { let cppNamespace = "::mlir::qco"; let useDefaultTypePrinterParser = 1; + + let hasCanonicalizer = 1; } #endif // MLIR_DIALECT_QCO_IR_QCODIALECT_TD diff --git a/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td b/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td index a5bbfb7f51..04cda7df4a 100644 --- a/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td +++ b/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td @@ -136,6 +136,7 @@ def MeasureOp : QCOOp<"measure"> { }]>]; let hasVerifier = 1; + let hasCanonicalizer = 1; } def ResetOp : QCOOp<"reset", [Idempotent, SameOperandsAndResultType]> { diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index 489fceb00e..5a21b5091c 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -237,4 +237,22 @@ mergeTwoTargetOneParameterWithSwappedTargets(OpType op, return success(); } +/** + * @brief Check if given quantum operation is unused (i.e., only used by + * deallocations) and remove it if so. + * + * @param op The operation to check. + * @param rewriter The pattern rewriter. + * @return LogicalResult Success or failure of the removal. + */ +LogicalResult checkAndRemoveDeadGate(Operation* op, PatternRewriter& rewriter) { + if (std::all_of(op->getUsers().begin(), op->getUsers().end(), + [](Operation* user) { return isa(user); })) { + // If the operation is only used by deallocs, we can safely remove it. + rewriter.replaceOp(op, op->getOperands()); + return success(); + } + return failure(); +} + } // namespace mlir::qco diff --git a/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp b/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp index b76a2d0471..a71412a671 100644 --- a/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp @@ -9,12 +9,29 @@ */ #include "mlir/Dialect/QCO/IR/QCOOps.h" +#include "mlir/Dialect/QCO/QCOUtils.h" #include using namespace mlir; using namespace mlir::qco; +namespace { + +/** + * @brief Remove dead measurements. + */ +struct DeadMeasurementRemoval final : OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(MeasureOp op, + PatternRewriter& rewriter) const override { + return checkAndRemoveDeadGate(op, rewriter); + } +}; + +} // namespace + LogicalResult MeasureOp::verify() { const auto registerName = getRegisterName(); const auto registerSize = getRegisterSize(); @@ -37,3 +54,8 @@ LogicalResult MeasureOp::verify() { } return success(); } + +void MeasureOp::getCanonicalizationPatterns(RewritePatternSet& results, + MLIRContext* context) { + results.add(context); +} diff --git a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp index 8832162354..462a28108d 100644 --- a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp @@ -9,6 +9,7 @@ */ #include "mlir/Dialect/QCO/IR/QCOOps.h" +#include "mlir/Dialect/QCO/QCOUtils.h" #include "mlir/Dialect/QTensor/IR/QTensorOps.h" #include "mlir/Dialect/QTensor/IR/QTensorUtils.h" @@ -101,6 +102,18 @@ struct RemoveResetAfterExtract final : OpRewritePattern { } }; +/** + * @brief Remove dead resets. + */ +struct DeadResetRemoval final : OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(ResetOp op, + PatternRewriter& rewriter) const override { + return checkAndRemoveDeadGate(op, rewriter); + } +}; + } // namespace OpFoldResult ResetOp::fold(FoldAdaptor /*adaptor*/) { @@ -114,4 +127,5 @@ OpFoldResult ResetOp::fold(FoldAdaptor /*adaptor*/) { void ResetOp::getCanonicalizationPatterns(RewritePatternSet& results, MLIRContext* context) { results.add(context); + results.add(context); } diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index a3ce816081..b2d75a7cad 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -11,6 +11,7 @@ #include "mlir/Dialect/QCO/IR/QCOOps.h" #include "mlir/Dialect/QCO/IR/QCODialect.h" // IWYU pragma: associated +#include "mlir/Dialect/QCO/QCOUtils.h" #include #include @@ -30,6 +31,21 @@ using namespace mlir; using namespace mlir::qco; +//===----------------------------------------------------------------------===// +// Dialect-Level Canonicalizers +//===----------------------------------------------------------------------===// + +namespace { +struct DeadGateElimination + : public mlir::OpInterfaceRewritePattern { + + LogicalResult matchAndRewrite(UnitaryOpInterface op, + PatternRewriter& rewriter) const override { + return checkAndRemoveDeadGate(op.getOperation(), rewriter); + } +}; +} // namespace + //===----------------------------------------------------------------------===// // Custom Parsers //===----------------------------------------------------------------------===// @@ -258,6 +274,10 @@ void QCODialect::initialize() { >(); } +void QCODialect::getCanonicalizationPatterns(RewritePatternSet& results) const { + results.add(getContext()); +} + //===----------------------------------------------------------------------===// // Types //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp index 4ac2d98faa..bb401dd9f3 100644 --- a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp @@ -9,6 +9,7 @@ */ #include "mlir/Dialect/QCO/IR/QCOOps.h" +#include "mlir/Dialect/QCO/QCOUtils.h" #include #include @@ -234,11 +235,24 @@ struct ConditionPropagation : public OpRewritePattern { return success(changed); } }; + +/** + * @brief Remove dead resets. + */ +struct DeadIfRemoval final : OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(IfOp op, + PatternRewriter& rewriter) const override { + return checkAndRemoveDeadGate(op, rewriter); + } +}; } // namespace void IfOp::getCanonicalizationPatterns(RewritePatternSet& results, MLIRContext* context) { results.add(context); + results.add(context); populateRegionBranchOpInterfaceCanonicalizationPatterns( results, IfOp::getOperationName()); } From ba57aa2f28d4df7a5f873314d2126572f1b22fc1 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Mon, 1 Jun 2026 15:15:54 +0200 Subject: [PATCH 02/26] fix(mlir): :bug: fix tests --- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 15 ++++++++++++--- mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 12 ++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index 5a21b5091c..8a46a7b72c 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -245,12 +245,21 @@ mergeTwoTargetOneParameterWithSwappedTargets(OpType op, * @param rewriter The pattern rewriter. * @return LogicalResult Success or failure of the removal. */ -LogicalResult checkAndRemoveDeadGate(Operation* op, PatternRewriter& rewriter) { +inline LogicalResult checkAndRemoveDeadGate(Operation* op, + PatternRewriter& rewriter) { if (std::all_of(op->getUsers().begin(), op->getUsers().end(), [](Operation* user) { return isa(user); })) { // If the operation is only used by deallocs, we can safely remove it. - rewriter.replaceOp(op, op->getOperands()); - return success(); + if (auto u = dyn_cast(op)) { + // We specifically have to replace the output *qubits* with the input + // *qubits* to ignore parameters. + rewriter.replaceOp(op, u.getInputQubits()); + return success(); + } else { + // This includes the `IfOp` as well as `Reset` and `Measure`. + rewriter.replaceOp(op, op->getOperands()); + return success(); + } } return failure(); } diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index b2d75a7cad..61031d3258 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -36,11 +36,19 @@ using namespace mlir::qco; //===----------------------------------------------------------------------===// namespace { -struct DeadGateElimination - : public mlir::OpInterfaceRewritePattern { +struct DeadGateElimination final + : public OpInterfaceRewritePattern { + + explicit DeadGateElimination(MLIRContext* context) + : OpInterfaceRewritePattern(context) {} LogicalResult matchAndRewrite(UnitaryOpInterface op, PatternRewriter& rewriter) const override { + if (op->use_empty()) { + // This effectively ignores the GPhase operation and variants such as its + // inverse, which should never be considered dead. + return failure(); + } return checkAndRemoveDeadGate(op.getOperation(), rewriter); } }; From b83afab6110f9207b35b3a3cf67d515f9c085628 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Mon, 1 Jun 2026 15:26:59 +0200 Subject: [PATCH 03/26] test(mlir): :white_check_mark: add direct test for dead gate elimination --- mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index 413f29336d..1267ce553d 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -114,6 +114,39 @@ TEST_F(QCOTest, BuilderRejectsMixedStaticAndDynamicQubitAllocationModes) { "Cannot mix dynamic and static qubit allocation modes"); } +TEST_F(QCOTest, CheckDeadGateElimination) { + QCOProgramBuilder builder(context.get()); + builder.initialize(); + auto q0_0 = builder.allocQubit(); + auto q1_0 = builder.allocQubit(); + auto q0_1 = builder.h(q0_0); + auto [q0_2, q1_1] = builder.cx(q0_1, q1_0); + auto q1_2 = builder.h(q1_1); + builder.sink(q0_2); + builder.sink(q1_2); + auto module = builder.finalize(); + + QCOProgramBuilder reference(context.get()); + reference.initialize(); + auto r0 = reference.allocQubit(); + auto r1 = reference.allocQubit(); + reference.sink(r0); + reference.sink(r1); + auto ref = reference.finalize(); + + ASSERT_TRUE(module); + EXPECT_TRUE(verify(*module).succeeded()); + EXPECT_TRUE(runQCOCleanupPipeline(module.get()).succeeded()); + EXPECT_TRUE(verify(*module).succeeded()); + + ASSERT_TRUE(ref); + EXPECT_TRUE(verify(*ref).succeeded()); + EXPECT_TRUE(runQCOCleanupPipeline(ref.get()).succeeded()); + EXPECT_TRUE(verify(*ref).succeeded()); + + EXPECT_TRUE(areModulesEquivalentWithPermutations(module.get(), ref.get())); +} + TEST_F(QCOTest, DirectIfBuilder) { // Test If construction directly QCOProgramBuilder builder(context.get()); From 4243ac0f78ac780cd7446b45f1411e72adc33893 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Mon, 1 Jun 2026 15:35:41 +0200 Subject: [PATCH 04/26] docs(mlir): :memo: update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dad0d3abf3..ed0b4dfbcc 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 Dead Gate Elimination Pattern ([#1755]) ([**DRovara**]) - 🚸 Add [CMake presets] to provide a standardized and reproducible way to configure builds ([#1660]) ([**@denialhaag**]) - ✨ Add a `quantum-loop-unroll` pass for unrolling for-loop operations containing quantum operations ([#1718]) ([**@MatthiasReumann**]) - ✨ Add a `hadamard-lifting` pass for lifting Hadamard gates above Pauli gates ([#1605]) ([**@lirem101**], [**@burgholzer**]) @@ -402,6 +403,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool +[#1755]: https://github.com/munich-quantum-toolkit/core/pull/1755 [#1749]: https://github.com/munich-quantum-toolkit/core/pull/1749 [#1748]: https://github.com/munich-quantum-toolkit/core/pull/1748 [#1737]: https://github.com/munich-quantum-toolkit/core/pull/1737 From a50032b48137f23e43bc378d55afbc8795571540 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Mon, 1 Jun 2026 15:48:49 +0200 Subject: [PATCH 05/26] style(mlir): :rotating_light: fix linter issues --- mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp | 2 ++ mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 3 +++ mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp | 14 +++++++------- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp b/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp index a71412a671..5d0462b6d7 100644 --- a/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp @@ -11,6 +11,8 @@ #include "mlir/Dialect/QCO/IR/QCOOps.h" #include "mlir/Dialect/QCO/QCOUtils.h" +#include +#include #include using namespace mlir; diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index 61031d3258..33474448d7 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -11,13 +11,16 @@ #include "mlir/Dialect/QCO/IR/QCOOps.h" #include "mlir/Dialect/QCO/IR/QCODialect.h" // IWYU pragma: associated +#include "mlir/Dialect/QCO/IR/QCOInterfaces.h" #include "mlir/Dialect/QCO/QCOUtils.h" #include #include +#include #include #include #include +#include #include #include #include diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index 1267ce553d..7c76b2a049 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -117,13 +117,13 @@ TEST_F(QCOTest, BuilderRejectsMixedStaticAndDynamicQubitAllocationModes) { TEST_F(QCOTest, CheckDeadGateElimination) { QCOProgramBuilder builder(context.get()); builder.initialize(); - auto q0_0 = builder.allocQubit(); - auto q1_0 = builder.allocQubit(); - auto q0_1 = builder.h(q0_0); - auto [q0_2, q1_1] = builder.cx(q0_1, q1_0); - auto q1_2 = builder.h(q1_1); - builder.sink(q0_2); - builder.sink(q1_2); + auto q0S0 = builder.allocQubit(); + auto q1S0 = builder.allocQubit(); + auto q0S1 = builder.h(q0S0); + auto [q0S2, q1S1] = builder.cx(q0S1, q1S0); + auto q1S2 = builder.h(q1S1); + builder.sink(q0S2); + builder.sink(q1S2); auto module = builder.finalize(); QCOProgramBuilder reference(context.get()); From d8c9ad5bfb3890caf957b9b4e8de206067435cf7 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Tue, 2 Jun 2026 09:37:45 +0200 Subject: [PATCH 06/26] fix(mlir): :recycle: guard RegionOp removal for child oeprations with memory effects --- mlir/include/mlir/Dialect/QCO/IR/QCOOps.td | 228 +++++++++--------- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 12 +- mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 9 +- mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp | 2 +- mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp | 4 +- 5 files changed, 137 insertions(+), 118 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td b/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td index 04cda7df4a..4b05cd1442 100644 --- a/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td +++ b/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td @@ -96,7 +96,7 @@ def StaticOp : QCOOp<"static", [Pure]> { // Measurement and Reset Operations //===----------------------------------------------------------------------===// -def MeasureOp : QCOOp<"measure"> { +def MeasureOp : QCOOp<"measure", [Pure]> { let summary = "Measure a qubit in the computational basis"; let description = [{ Measures a qubit in the computational (Z) basis, collapsing the state @@ -119,8 +119,7 @@ def MeasureOp : QCOOp<"measure"> { ``` }]; - let arguments = (ins Arg:$qubit_in, + let arguments = (ins Arg:$qubit_in, OptionalAttr:$register_name, OptionalAttr>:$register_size, OptionalAttr>:$register_index); @@ -139,7 +138,7 @@ def MeasureOp : QCOOp<"measure"> { let hasCanonicalizer = 1; } -def ResetOp : QCOOp<"reset", [Idempotent, SameOperandsAndResultType]> { +def ResetOp : QCOOp<"reset", [Idempotent, SameOperandsAndResultType, Pure]> { let summary = "Reset a qubit to |0⟩ state"; let description = [{ Resets a qubit to the |0⟩ state, regardless of its current state, @@ -151,8 +150,7 @@ def ResetOp : QCOOp<"reset", [Idempotent, SameOperandsAndResultType]> { ``` }]; - let arguments = - (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -209,7 +207,8 @@ def GPhaseOp let hasCanonicalizer = 1; } -def IdOp : QCOOp<"id", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def IdOp + : QCOOp<"id", traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply an Id gate to a qubit"; let description = [{ Applies an Id gate to a qubit and returns the transformed qubit. @@ -220,7 +219,7 @@ def IdOp : QCOOp<"id", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -233,7 +232,8 @@ def IdOp : QCOOp<"id", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { let hasCanonicalizer = 1; } -def XOp : QCOOp<"x", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def XOp + : QCOOp<"x", traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply an X gate to a qubit"; let description = [{ Applies an X gate to a qubit and returns the transformed qubit. @@ -244,7 +244,7 @@ def XOp : QCOOp<"x", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -257,7 +257,8 @@ def XOp : QCOOp<"x", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { let hasCanonicalizer = 1; } -def YOp : QCOOp<"y", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def YOp + : QCOOp<"y", traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply a Y gate to a qubit"; let description = [{ Applies a Y gate to a qubit and returns the transformed qubit. @@ -268,7 +269,7 @@ def YOp : QCOOp<"y", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -281,7 +282,8 @@ def YOp : QCOOp<"y", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { let hasCanonicalizer = 1; } -def ZOp : QCOOp<"z", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def ZOp + : QCOOp<"z", traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply a Z gate to a qubit"; let description = [{ Applies a Z gate to a qubit and returns the transformed qubit. @@ -292,7 +294,7 @@ def ZOp : QCOOp<"z", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -305,7 +307,8 @@ def ZOp : QCOOp<"z", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { let hasCanonicalizer = 1; } -def HOp : QCOOp<"h", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def HOp + : QCOOp<"h", traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply a H gate to a qubit"; let description = [{ Applies a H gate to a qubit and returns the transformed qubit. @@ -316,7 +319,7 @@ def HOp : QCOOp<"h", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -329,7 +332,8 @@ def HOp : QCOOp<"h", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { let hasCanonicalizer = 1; } -def SOp : QCOOp<"s", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def SOp + : QCOOp<"s", traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply an S gate to a qubit"; let description = [{ Applies an S gate to a qubit and returns the transformed qubit. @@ -340,7 +344,7 @@ def SOp : QCOOp<"s", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -353,8 +357,8 @@ def SOp : QCOOp<"s", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { let hasCanonicalizer = 1; } -def SdgOp - : QCOOp<"sdg", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def SdgOp : QCOOp<"sdg", + traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply an Sdg gate to a qubit"; let description = [{ Applies an Sdg gate to a qubit and returns the transformed qubit. @@ -365,7 +369,7 @@ def SdgOp ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -378,7 +382,8 @@ def SdgOp let hasCanonicalizer = 1; } -def TOp : QCOOp<"t", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def TOp + : QCOOp<"t", traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply a T gate to a qubit"; let description = [{ Applies a T gate to a qubit and returns the transformed qubit. @@ -389,7 +394,7 @@ def TOp : QCOOp<"t", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -402,8 +407,8 @@ def TOp : QCOOp<"t", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { let hasCanonicalizer = 1; } -def TdgOp - : QCOOp<"tdg", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def TdgOp : QCOOp<"tdg", + traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply a Tdg gate to a qubit"; let description = [{ Applies a Tdg gate to a qubit and returns the transformed qubit. @@ -414,7 +419,7 @@ def TdgOp ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -427,7 +432,8 @@ def TdgOp let hasCanonicalizer = 1; } -def SXOp : QCOOp<"sx", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def SXOp + : QCOOp<"sx", traits = [UnitaryOpInterface, OneTargetZeroParameter, Pure]> { let summary = "Apply an SX gate to a qubit"; let description = [{ Applies an SX gate to a qubit and returns the transformed qubit. @@ -438,7 +444,7 @@ def SXOp : QCOOp<"sx", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -451,8 +457,8 @@ def SXOp : QCOOp<"sx", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { let hasCanonicalizer = 1; } -def SXdgOp - : QCOOp<"sxdg", traits = [UnitaryOpInterface, OneTargetZeroParameter]> { +def SXdgOp : QCOOp<"sxdg", traits = [UnitaryOpInterface, OneTargetZeroParameter, + Pure]> { let summary = "Apply an SXdg gate to a qubit"; let description = [{ Applies an SXdg gate to a qubit and returns the transformed qubit. @@ -463,7 +469,7 @@ def SXdgOp ``` }]; - let arguments = (ins Arg:$qubit_in); + let arguments = (ins Arg:$qubit_in); let results = (outs QubitType:$qubit_out); let assemblyFormat = "$qubit_in attr-dict `:` type($qubit_in) `->` type($qubit_out)"; @@ -476,7 +482,8 @@ def SXdgOp let hasCanonicalizer = 1; } -def RXOp : QCOOp<"rx", traits = [UnitaryOpInterface, OneTargetOneParameter]> { +def RXOp + : QCOOp<"rx", traits = [UnitaryOpInterface, OneTargetOneParameter, Pure]> { let summary = "Apply an RX gate to a qubit"; let description = [{ Applies an RX gate to a qubit and returns the transformed qubit. @@ -487,7 +494,7 @@ def RXOp : QCOOp<"rx", traits = [UnitaryOpInterface, OneTargetOneParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in, + let arguments = (ins Arg:$qubit_in, Arg:$theta); let results = (outs QubitType:$qubit_out); let assemblyFormat = "`(` $theta `)` $qubit_in attr-dict `:` type($qubit_in) " @@ -505,7 +512,8 @@ def RXOp : QCOOp<"rx", traits = [UnitaryOpInterface, OneTargetOneParameter]> { let hasCanonicalizer = 1; } -def RYOp : QCOOp<"ry", traits = [UnitaryOpInterface, OneTargetOneParameter]> { +def RYOp + : QCOOp<"ry", traits = [UnitaryOpInterface, OneTargetOneParameter, Pure]> { let summary = "Apply an RY gate to a qubit"; let description = [{ Applies an RY gate to a qubit and returns the transformed qubit. @@ -516,7 +524,7 @@ def RYOp : QCOOp<"ry", traits = [UnitaryOpInterface, OneTargetOneParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in, + let arguments = (ins Arg:$qubit_in, Arg:$theta); let results = (outs QubitType:$qubit_out); let assemblyFormat = "`(` $theta `)` $qubit_in attr-dict `:` type($qubit_in) " @@ -534,7 +542,8 @@ def RYOp : QCOOp<"ry", traits = [UnitaryOpInterface, OneTargetOneParameter]> { let hasCanonicalizer = 1; } -def RZOp : QCOOp<"rz", traits = [UnitaryOpInterface, OneTargetOneParameter]> { +def RZOp + : QCOOp<"rz", traits = [UnitaryOpInterface, OneTargetOneParameter, Pure]> { let summary = "Apply an RZ gate to a qubit"; let description = [{ Applies an RZ gate to a qubit and returns the transformed qubit. @@ -545,7 +554,7 @@ def RZOp : QCOOp<"rz", traits = [UnitaryOpInterface, OneTargetOneParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in, + let arguments = (ins Arg:$qubit_in, Arg:$theta); let results = (outs QubitType:$qubit_out); let assemblyFormat = "`(` $theta `)` $qubit_in attr-dict `:` type($qubit_in) " @@ -563,7 +572,8 @@ def RZOp : QCOOp<"rz", traits = [UnitaryOpInterface, OneTargetOneParameter]> { let hasCanonicalizer = 1; } -def POp : QCOOp<"p", traits = [UnitaryOpInterface, OneTargetOneParameter]> { +def POp + : QCOOp<"p", traits = [UnitaryOpInterface, OneTargetOneParameter, Pure]> { let summary = "Apply a P gate to a qubit"; let description = [{ Applies a P gate to a qubit and returns the transformed qubit. @@ -574,7 +584,7 @@ def POp : QCOOp<"p", traits = [UnitaryOpInterface, OneTargetOneParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in, + let arguments = (ins Arg:$qubit_in, Arg:$theta); let results = (outs QubitType:$qubit_out); let assemblyFormat = "`(` $theta `)` $qubit_in attr-dict `:` type($qubit_in) " @@ -592,7 +602,8 @@ def POp : QCOOp<"p", traits = [UnitaryOpInterface, OneTargetOneParameter]> { let hasCanonicalizer = 1; } -def ROp : QCOOp<"r", traits = [UnitaryOpInterface, OneTargetTwoParameter]> { +def ROp + : QCOOp<"r", traits = [UnitaryOpInterface, OneTargetTwoParameter, Pure]> { let summary = "Apply an R gate to a qubit"; let description = [{ Applies an R gate to a qubit and returns the transformed qubit. @@ -603,7 +614,7 @@ def ROp : QCOOp<"r", traits = [UnitaryOpInterface, OneTargetTwoParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in, + let arguments = (ins Arg:$qubit_in, Arg:$theta, Arg:$phi); let results = (outs QubitType:$qubit_out); @@ -622,7 +633,8 @@ def ROp : QCOOp<"r", traits = [UnitaryOpInterface, OneTargetTwoParameter]> { let hasCanonicalizer = 1; } -def U2Op : QCOOp<"u2", traits = [UnitaryOpInterface, OneTargetTwoParameter]> { +def U2Op + : QCOOp<"u2", traits = [UnitaryOpInterface, OneTargetTwoParameter, Pure]> { let summary = "Apply a U2 gate to a qubit"; let description = [{ Applies a U2 gate to a qubit and returns the transformed qubit. @@ -633,7 +645,7 @@ def U2Op : QCOOp<"u2", traits = [UnitaryOpInterface, OneTargetTwoParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in, + let arguments = (ins Arg:$qubit_in, Arg:$phi, Arg:$lambda); let results = (outs QubitType:$qubit_out); @@ -652,7 +664,8 @@ def U2Op : QCOOp<"u2", traits = [UnitaryOpInterface, OneTargetTwoParameter]> { let hasCanonicalizer = 1; } -def UOp : QCOOp<"u", traits = [UnitaryOpInterface, OneTargetThreeParameter]> { +def UOp + : QCOOp<"u", traits = [UnitaryOpInterface, OneTargetThreeParameter, Pure]> { let summary = "Apply a U gate to a qubit"; let description = [{ Applies a U gate to a qubit and returns the transformed qubit. @@ -663,7 +676,7 @@ def UOp : QCOOp<"u", traits = [UnitaryOpInterface, OneTargetThreeParameter]> { ``` }]; - let arguments = (ins Arg:$qubit_in, + let arguments = (ins Arg:$qubit_in, Arg:$theta, Arg:$phi, Arg:$lambda); @@ -684,8 +697,8 @@ def UOp : QCOOp<"u", traits = [UnitaryOpInterface, OneTargetThreeParameter]> { let hasCanonicalizer = 1; } -def SWAPOp - : QCOOp<"swap", traits = [UnitaryOpInterface, TwoTargetZeroParameter]> { +def SWAPOp : QCOOp<"swap", traits = [UnitaryOpInterface, TwoTargetZeroParameter, + Pure]> { let summary = "Apply a SWAP gate to two qubits"; let description = [{ Applies a SWAP gate to two qubits and returns the transformed qubits. @@ -696,9 +709,8 @@ def SWAPOp ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "$qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` " @@ -712,8 +724,8 @@ def SWAPOp let hasCanonicalizer = 1; } -def iSWAPOp - : QCOOp<"iswap", traits = [UnitaryOpInterface, TwoTargetZeroParameter]> { +def iSWAPOp : QCOOp<"iswap", traits = [UnitaryOpInterface, + TwoTargetZeroParameter, Pure]> { let summary = "Apply a iSWAP gate to two qubits"; let description = [{ Applies a iSWAP gate to two qubits and returns the transformed qubits. @@ -724,9 +736,8 @@ def iSWAPOp ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "$qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` " @@ -738,8 +749,8 @@ def iSWAPOp }]; } -def DCXOp - : QCOOp<"dcx", traits = [UnitaryOpInterface, TwoTargetZeroParameter]> { +def DCXOp : QCOOp<"dcx", + traits = [UnitaryOpInterface, TwoTargetZeroParameter, Pure]> { let summary = "Apply a DCX gate to two qubits"; let description = [{ Applies a DCX gate to two qubits and returns the transformed qubits. @@ -750,9 +761,8 @@ def DCXOp ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "$qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` " @@ -766,8 +776,8 @@ def DCXOp let hasCanonicalizer = 1; } -def ECROp - : QCOOp<"ecr", traits = [UnitaryOpInterface, TwoTargetZeroParameter]> { +def ECROp : QCOOp<"ecr", + traits = [UnitaryOpInterface, TwoTargetZeroParameter, Pure]> { let summary = "Apply an ECR gate to two qubits"; let description = [{ Applies an ECR gate to two qubits and returns the transformed qubits. @@ -778,9 +788,8 @@ def ECROp ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "$qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) `,` " @@ -794,7 +803,8 @@ def ECROp let hasCanonicalizer = 1; } -def RXXOp : QCOOp<"rxx", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { +def RXXOp + : QCOOp<"rxx", traits = [UnitaryOpInterface, TwoTargetOneParameter, Pure]> { let summary = "Apply an RXX gate to two qubits"; let description = [{ Applies an RXX gate to two qubits and returns the transformed qubits. @@ -805,10 +815,9 @@ def RXXOp : QCOOp<"rxx", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in, - Arg:$theta); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in, + Arg:$theta); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "`(` $theta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) " @@ -826,7 +835,8 @@ def RXXOp : QCOOp<"rxx", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { let hasCanonicalizer = 1; } -def RYYOp : QCOOp<"ryy", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { +def RYYOp + : QCOOp<"ryy", traits = [UnitaryOpInterface, TwoTargetOneParameter, Pure]> { let summary = "Apply an RYY gate to two qubits"; let description = [{ Applies an RYY gate to two qubits and returns the transformed qubits. @@ -837,10 +847,9 @@ def RYYOp : QCOOp<"ryy", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in, - Arg:$theta); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in, + Arg:$theta); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "`(` $theta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) " @@ -858,7 +867,8 @@ def RYYOp : QCOOp<"ryy", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { let hasCanonicalizer = 1; } -def RZXOp : QCOOp<"rzx", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { +def RZXOp + : QCOOp<"rzx", traits = [UnitaryOpInterface, TwoTargetOneParameter, Pure]> { let summary = "Apply an RZX gate to two qubits"; let description = [{ Applies an RZX gate to two qubits and returns the transformed qubits. @@ -869,10 +879,9 @@ def RZXOp : QCOOp<"rzx", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in, - Arg:$theta); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in, + Arg:$theta); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "`(` $theta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) " @@ -890,7 +899,8 @@ def RZXOp : QCOOp<"rzx", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { let hasCanonicalizer = 1; } -def RZZOp : QCOOp<"rzz", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { +def RZZOp + : QCOOp<"rzz", traits = [UnitaryOpInterface, TwoTargetOneParameter, Pure]> { let summary = "Apply an RZZ gate to two qubits"; let description = [{ Applies an RZZ gate to two qubits and returns the transformed qubits. @@ -901,10 +911,9 @@ def RZZOp : QCOOp<"rzz", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in, - Arg:$theta); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in, + Arg:$theta); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "`(` $theta `)` $qubit0_in `,` $qubit1_in attr-dict `:` type($qubit0_in) " @@ -922,8 +931,8 @@ def RZZOp : QCOOp<"rzz", traits = [UnitaryOpInterface, TwoTargetOneParameter]> { let hasCanonicalizer = 1; } -def XXPlusYYOp : QCOOp<"xx_plus_yy", - traits = [UnitaryOpInterface, TwoTargetTwoParameter]> { +def XXPlusYYOp : QCOOp<"xx_plus_yy", traits = [UnitaryOpInterface, + TwoTargetTwoParameter, Pure]> { let summary = "Apply an XX+YY gate to two qubits"; let description = [{ Applies an XX+YY gate to two qubits and returns the transformed qubits. @@ -934,11 +943,10 @@ def XXPlusYYOp : QCOOp<"xx_plus_yy", ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in, - Arg:$theta, - Arg:$beta); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in, + Arg:$theta, + Arg:$beta); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "`(` $theta `,` $beta `)` $qubit0_in `,` $qubit1_in " "attr-dict `:` type($qubit0_in) `,` type($qubit1_in) " @@ -957,8 +965,8 @@ def XXPlusYYOp : QCOOp<"xx_plus_yy", let hasCanonicalizer = 1; } -def XXMinusYYOp : QCOOp<"xx_minus_yy", - traits = [UnitaryOpInterface, TwoTargetTwoParameter]> { +def XXMinusYYOp : QCOOp<"xx_minus_yy", traits = [UnitaryOpInterface, + TwoTargetTwoParameter, Pure]> { let summary = "Apply an XX-YY gate to two qubits"; let description = [{ Applies an XX-YY gate to two qubits and returns the transformed qubits. @@ -969,11 +977,10 @@ def XXMinusYYOp : QCOOp<"xx_minus_yy", ``` }]; - let arguments = - (ins Arg:$qubit0_in, - Arg:$qubit1_in, - Arg:$theta, - Arg:$beta); + let arguments = (ins Arg:$qubit0_in, + Arg:$qubit1_in, + Arg:$theta, + Arg:$beta); let results = (outs QubitType:$qubit0_out, QubitType:$qubit1_out); let assemblyFormat = "`(` $theta `,` $beta `)` $qubit0_in `,` $qubit1_in " "attr-dict `:` type($qubit0_in) `,` type($qubit1_in) " @@ -992,7 +999,7 @@ def XXMinusYYOp : QCOOp<"xx_minus_yy", let hasCanonicalizer = 1; } -def BarrierOp : QCOOp<"barrier", traits = [UnitaryOpInterface]> { +def BarrierOp : QCOOp<"barrier", traits = [UnitaryOpInterface, Pure]> { let summary = "Apply a barrier gate to a set of qubits"; let description = [{ Applies a barrier gate to a set of qubits and returns the transformed qubits. @@ -1004,7 +1011,7 @@ def BarrierOp : QCOOp<"barrier", traits = [UnitaryOpInterface]> { }]; let arguments = - (ins Arg, "the target qubits", [MemRead]>:$qubits_in); + (ins Arg, "the target qubits">:$qubits_in); let results = (outs Variadic:$qubits_out); let assemblyFormat = "$qubits_in attr-dict `:` type($qubits_in) `->` type($qubits_out)"; @@ -1042,7 +1049,7 @@ def BarrierOp : QCOOp<"barrier", traits = [UnitaryOpInterface]> { // Modifiers //===----------------------------------------------------------------------===// -def YieldOp : QCOOp<"yield", traits = [Terminator, ReturnLike]> { +def YieldOp : QCOOp<"yield", traits = [Terminator, ReturnLike, Pure]> { let summary = "Yield from a modifier region"; let description = [{ Terminates a modifier region, yielding the transformed target qubit and qtensor values back to the enclosing modifier operation. @@ -1067,7 +1074,7 @@ def CtrlOp AttrSizedResultSegments, SameOperandsAndResultType, SameOperandsAndResultShape, SingleBlockImplicitTerminator<"::mlir::qco::YieldOp">, - RecursiveMemoryEffects]> { + Pure, RecursiveMemoryEffects]> { let summary = "Add control qubits to a unitary operation"; let description = [{ A modifier operation that adds control qubits to the unitary operation @@ -1086,9 +1093,9 @@ def CtrlOp ``` }]; - let arguments = (ins Arg, - "the control qubits", [MemRead]>:$controls_in, - Arg, "the target qubits", [MemRead]>:$targets_in); + let arguments = + (ins Arg, "the control qubits">:$controls_in, + Arg, "the target qubits">:$targets_in); let results = (outs Variadic:$controls_out, Variadic:$targets_out); let regions = (region SizedRegion<1>:$region); @@ -1144,7 +1151,7 @@ def InvOp : QCOOp<"inv", traits = [UnitaryOpInterface, SingleBlockImplicitTerminator<"::mlir::qco::YieldOp">, - RecursiveMemoryEffects]> { + Pure, RecursiveMemoryEffects]> { let summary = "Invert a unitary operation"; let description = [{ A modifier operation that inverts the unitary operation defined in its body @@ -1160,9 +1167,8 @@ def InvOp ``` }]; - let arguments = - (ins Arg, - "the qubits involved in the operation", [MemRead]>:$qubits_in); + let arguments = (ins Arg, + "the qubits involved in the operation">:$qubits_in); let results = (outs Variadic:$qubits_out); let regions = (region SizedRegion<1>:$region); let assemblyFormat = [{ @@ -1222,7 +1228,7 @@ def IfOp "getRegionInvocationBounds", "getEntrySuccessorRegions"]>, SingleBlock, - SingleBlockImplicitTerminator<"::mlir::qco::YieldOp">, + SingleBlockImplicitTerminator<"::mlir::qco::YieldOp">, Pure, RecursiveMemoryEffects]> { let summary = "If-then-else operation for linear (qubit) types"; diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index 8a46a7b72c..6135c416cd 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -239,7 +239,7 @@ mergeTwoTargetOneParameterWithSwappedTargets(OpType op, /** * @brief Check if given quantum operation is unused (i.e., only used by - * deallocations) and remove it if so. + * sinks) and remove it if so. * * @param op The operation to check. * @param rewriter The pattern rewriter. @@ -249,14 +249,20 @@ inline LogicalResult checkAndRemoveDeadGate(Operation* op, PatternRewriter& rewriter) { if (std::all_of(op->getUsers().begin(), op->getUsers().end(), [](Operation* user) { return isa(user); })) { - // If the operation is only used by deallocs, we can safely remove it. + // If the operation is only used by sinks, we can safely remove it. if (auto u = dyn_cast(op)) { // We specifically have to replace the output *qubits* with the input // *qubits* to ignore parameters. rewriter.replaceOp(op, u.getInputQubits()); return success(); + } else if (auto m = dyn_cast(op)) { + // We specifically have to replace the output *qubits* with the input + // *qubits* to ignore the classical outcome. + rewriter.replaceAllUsesWith(m.getQubitOut(), m.getQubitIn()); + rewriter.eraseOp(op); + return success(); } else { - // This includes the `IfOp` as well as `Reset` and `Measure`. + // This includes the `IfOp` as well as `Reset`. rewriter.replaceOp(op, op->getOperands()); return success(); } diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index 33474448d7..fe11640e0d 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -39,6 +39,10 @@ using namespace mlir::qco; //===----------------------------------------------------------------------===// namespace { + +/** + * @brief Remove dead measurements. + */ struct DeadGateElimination final : public OpInterfaceRewritePattern { @@ -47,9 +51,10 @@ struct DeadGateElimination final LogicalResult matchAndRewrite(UnitaryOpInterface op, PatternRewriter& rewriter) const override { - if (op->use_empty()) { + if (!isMemoryEffectFree(op)) { // This effectively ignores the GPhase operation and variants such as its - // inverse, which should never be considered dead. + // inverse or `if` ops containing it, which should never be considered + // dead. return failure(); } return checkAndRemoveDeadGate(op.getOperation(), rewriter); diff --git a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp index bb401dd9f3..fc10e98157 100644 --- a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp @@ -237,7 +237,7 @@ struct ConditionPropagation : public OpRewritePattern { }; /** - * @brief Remove dead resets. + * @brief Remove dead `IfOp` instructions. */ struct DeadIfRemoval final : OpRewritePattern { using OpRewritePattern::OpRewritePattern; diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index 7c76b2a049..f1d3f02777 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -121,7 +121,7 @@ TEST_F(QCOTest, CheckDeadGateElimination) { auto q1S0 = builder.allocQubit(); auto q0S1 = builder.h(q0S0); auto [q0S2, q1S1] = builder.cx(q0S1, q1S0); - auto q1S2 = builder.h(q1S1); + auto [q1S2, c1] = builder.measure(q1S1); builder.sink(q0S2); builder.sink(q1S2); auto module = builder.finalize(); @@ -144,6 +144,8 @@ TEST_F(QCOTest, CheckDeadGateElimination) { EXPECT_TRUE(runQCOCleanupPipeline(ref.get()).succeeded()); EXPECT_TRUE(verify(*ref).succeeded()); + module.get().dump(); + EXPECT_TRUE(areModulesEquivalentWithPermutations(module.get(), ref.get())); } From 97175472e086cdd46e8bb5393d16cc7024729dd7 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Tue, 2 Jun 2026 09:54:03 +0200 Subject: [PATCH 07/26] fix(mlir): :bug: fix handling for `IfOp` removal and add specialized test --- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 7 +- mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 1 + mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp | 87 +++++++++++++++++-- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index 6135c416cd..deda577eba 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -261,8 +261,13 @@ inline LogicalResult checkAndRemoveDeadGate(Operation* op, rewriter.replaceAllUsesWith(m.getQubitOut(), m.getQubitIn()); rewriter.eraseOp(op); return success(); + } else if (auto i = dyn_cast(op)) { + // We specifically have to replace the output *qubits* with the input + // *qubits* to ignore the condition. + rewriter.replaceOp(op, i.getQubits()); + return success(); } else { - // This includes the `IfOp` as well as `Reset`. + // This currently only includes the `Reset` operation. rewriter.replaceOp(op, op->getOperands()); return success(); } diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index fe11640e0d..dc302e3028 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include // The following headers are needed for some template instantiations. diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index f1d3f02777..3af2feb196 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -132,21 +132,94 @@ TEST_F(QCOTest, CheckDeadGateElimination) { auto r1 = reference.allocQubit(); reference.sink(r0); reference.sink(r1); - auto ref = reference.finalize(); + auto refModule = reference.finalize(); ASSERT_TRUE(module); EXPECT_TRUE(verify(*module).succeeded()); EXPECT_TRUE(runQCOCleanupPipeline(module.get()).succeeded()); EXPECT_TRUE(verify(*module).succeeded()); - ASSERT_TRUE(ref); - EXPECT_TRUE(verify(*ref).succeeded()); - EXPECT_TRUE(runQCOCleanupPipeline(ref.get()).succeeded()); - EXPECT_TRUE(verify(*ref).succeeded()); + ASSERT_TRUE(refModule); + EXPECT_TRUE(verify(*refModule).succeeded()); + EXPECT_TRUE(runQCOCleanupPipeline(refModule.get()).succeeded()); + EXPECT_TRUE(verify(*refModule).succeeded()); - module.get().dump(); + EXPECT_TRUE( + areModulesEquivalentWithPermutations(module.get(), refModule.get())); +} + +TEST_F(QCOTest, CheckIfOpDeadGateElimination) { + QCOProgramBuilder builder(context.get()); + builder.initialize(); + auto q0S0 = builder.allocQubit(); + auto q1S0 = builder.allocQubit(); + auto q0S1 = builder.h(q0S0); + auto [q0S2, c0] = builder.measure(q0S1); + + // This is an `if` with memory effects - it can't be removed. + auto q1S1 = builder.qcoIf( + c0, {q1S0}, + [&](ValueRange qubits) -> SmallVector { + auto q1Then = builder.x(qubits[0]); + builder.gphase(0.5); + return SmallVector{q1Then}; + }, + [&](ValueRange qubits) -> SmallVector { + auto q1Else = builder.h(qubits[0]); + return SmallVector{q1Else}; + })[0]; + + // This is an `if` without memory effects - it can be removed. + auto q1S2 = builder.qcoIf( + c0, {q1S1}, + [&](ValueRange qubits) -> SmallVector { + auto q1Then = builder.x(qubits[0]); + return SmallVector{q1Then}; + }, + [&](ValueRange qubits) -> SmallVector { + auto q1Else = builder.h(qubits[0]); + return SmallVector{q1Else}; + })[0]; + builder.sink(q0S2); + builder.sink(q1S2); + auto module = builder.finalize(); - EXPECT_TRUE(areModulesEquivalentWithPermutations(module.get(), ref.get())); + QCOProgramBuilder reference(context.get()); + reference.initialize(); + auto r0S0 = reference.allocQubit(); + auto r1S0 = reference.allocQubit(); + auto r0S1 = reference.h(r0S0); + auto [r0S2, cr0] = reference.measure(r0S1); + + // This is an `if` with memory effects - it can't be removed. + auto r1S1 = reference.qcoIf( + cr0, {r1S0}, + [&](ValueRange qubits) -> SmallVector { + auto q1Then = reference.x(qubits[0]); + reference.gphase(0.5); + return SmallVector{q1Then}; + }, + [&](ValueRange qubits) -> SmallVector { + auto q1Else = reference.h(qubits[0]); + return SmallVector{q1Else}; + })[0]; + + reference.sink(r0S2); + reference.sink(r1S1); + auto refModule = reference.finalize(); + + ASSERT_TRUE(module); + EXPECT_TRUE(verify(*module).succeeded()); + EXPECT_TRUE(runQCOCleanupPipeline(module.get()).succeeded()); + EXPECT_TRUE(verify(*module).succeeded()); + + ASSERT_TRUE(refModule); + EXPECT_TRUE(verify(*refModule).succeeded()); + EXPECT_TRUE(runQCOCleanupPipeline(refModule.get()).succeeded()); + EXPECT_TRUE(verify(*refModule).succeeded()); + + EXPECT_TRUE( + areModulesEquivalentWithPermutations(module.get(), refModule.get())); } TEST_F(QCOTest, DirectIfBuilder) { From 2d65418e7a1e4b367f747902f5a5479571475873 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Tue, 2 Jun 2026 10:10:45 +0200 Subject: [PATCH 08/26] fix(mlir): :bug: minor bug and code style fixes --- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 4 ++-- mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 5 +++-- mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp | 5 +++++ mlir/lib/Support/IRVerification.cpp | 1 - 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index deda577eba..9c6af7a8f4 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -247,8 +247,8 @@ mergeTwoTargetOneParameterWithSwappedTargets(OpType op, */ inline LogicalResult checkAndRemoveDeadGate(Operation* op, PatternRewriter& rewriter) { - if (std::all_of(op->getUsers().begin(), op->getUsers().end(), - [](Operation* user) { return isa(user); })) { + if (llvm::all_of(op->getUsers(), + [](Operation* user) { return isa(user); })) { // If the operation is only used by sinks, we can safely remove it. if (auto u = dyn_cast(op)) { // We specifically have to replace the output *qubits* with the input diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index dc302e3028..b1407ee0df 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include // The following headers are needed for some template instantiations. @@ -42,7 +43,7 @@ using namespace mlir::qco; namespace { /** - * @brief Remove dead measurements. + * @brief Remove dead gates. */ struct DeadGateElimination final : public OpInterfaceRewritePattern { @@ -54,7 +55,7 @@ struct DeadGateElimination final PatternRewriter& rewriter) const override { if (!isMemoryEffectFree(op)) { // This effectively ignores the GPhase operation and variants such as its - // inverse or `if` ops containing it, which should never be considered + // inverse or `ctrl` ops containing it, which should never be considered // dead. return failure(); } diff --git a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp index fc10e98157..6589fbbad7 100644 --- a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -244,6 +245,10 @@ struct DeadIfRemoval final : OpRewritePattern { LogicalResult matchAndRewrite(IfOp op, PatternRewriter& rewriter) const override { + if (!isMemoryEffectFree(op)) { + // This effectively ignores `IfOp`s with memory effects. + return failure(); + } return checkAndRemoveDeadGate(op, rewriter); } }; diff --git a/mlir/lib/Support/IRVerification.cpp b/mlir/lib/Support/IRVerification.cpp index eaac426f0a..8aa982e976 100644 --- a/mlir/lib/Support/IRVerification.cpp +++ b/mlir/lib/Support/IRVerification.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include From 278a54e356e4417f4b9446a689c8c74835c35d5f Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Tue, 2 Jun 2026 10:19:43 +0200 Subject: [PATCH 09/26] style(mlir): :rotating_light: fix linter issues on includes --- mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 1 - mlir/lib/Support/IRVerification.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index b1407ee0df..e49d00da5a 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/mlir/lib/Support/IRVerification.cpp b/mlir/lib/Support/IRVerification.cpp index 8aa982e976..eaac426f0a 100644 --- a/mlir/lib/Support/IRVerification.cpp +++ b/mlir/lib/Support/IRVerification.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include From 44eaf7e6bdb0274d2057a64d5b4c1690e35bbb6b Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Tue, 2 Jun 2026 10:57:00 +0200 Subject: [PATCH 10/26] fix: :pencil2: fix typo in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed0b4dfbcc..22616216d5 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 Dead Gate Elimination Pattern ([#1755]) ([**DRovara**]) +- ✨ Add Dead Gate Elimination Pattern ([#1755]) ([**@DRovara**]) - 🚸 Add [CMake presets] to provide a standardized and reproducible way to configure builds ([#1660]) ([**@denialhaag**]) - ✨ Add a `quantum-loop-unroll` pass for unrolling for-loop operations containing quantum operations ([#1718]) ([**@MatthiasReumann**]) - ✨ Add a `hadamard-lifting` pass for lifting Hadamard gates above Pauli gates ([#1605]) ([**@lirem101**], [**@burgholzer**]) From 8b3af4390da92f914007b5607e1325769a9444ed Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Tue, 2 Jun 2026 20:25:18 +0200 Subject: [PATCH 11/26] =?UTF-8?q?=F0=9F=8E=A8=20Optimize=20`checkAndRemove?= =?UTF-8?q?DeadGate`=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 56 +++++++++++++----------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index 9c6af7a8f4..e8f9cf9450 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -10,6 +10,7 @@ #pragma once +#include #include #include #include @@ -238,7 +239,7 @@ mergeTwoTargetOneParameterWithSwappedTargets(OpType op, } /** - * @brief Check if given quantum operation is unused (i.e., only used by + * @brief Check if a given quantum operation is unused (i.e., only used by * sinks) and remove it if so. * * @param op The operation to check. @@ -247,32 +248,35 @@ mergeTwoTargetOneParameterWithSwappedTargets(OpType op, */ inline LogicalResult checkAndRemoveDeadGate(Operation* op, PatternRewriter& rewriter) { - if (llvm::all_of(op->getUsers(), - [](Operation* user) { return isa(user); })) { - // If the operation is only used by sinks, we can safely remove it. - if (auto u = dyn_cast(op)) { - // We specifically have to replace the output *qubits* with the input - // *qubits* to ignore parameters. - rewriter.replaceOp(op, u.getInputQubits()); - return success(); - } else if (auto m = dyn_cast(op)) { - // We specifically have to replace the output *qubits* with the input - // *qubits* to ignore the classical outcome. - rewriter.replaceAllUsesWith(m.getQubitOut(), m.getQubitIn()); - rewriter.eraseOp(op); - return success(); - } else if (auto i = dyn_cast(op)) { - // We specifically have to replace the output *qubits* with the input - // *qubits* to ignore the condition. - rewriter.replaceOp(op, i.getQubits()); - return success(); - } else { - // This currently only includes the `Reset` operation. - rewriter.replaceOp(op, op->getOperands()); - return success(); - } + if (!llvm::all_of(op->getUsers(), + [](Operation* user) { return isa(user); })) { + return failure(); } - return failure(); + + // If the operation is only used by sinks, we can safely remove it. + return TypeSwitch(op) + .Case([&](auto u) { + // Replace output *qubits* with input *qubits* to ignore parameters. + rewriter.replaceOp(op, u.getInputQubits()); + return success(); + }) + .Case([&](auto m) { + // Replace output *qubits* with input *qubits* to ignore classical + // outcome. + rewriter.replaceAllUsesWith(m.getQubitOut(), m.getQubitIn()); + rewriter.eraseOp(op); + return success(); + }) + .Case([&](auto i) { + // Replace output *qubits* with input *qubits* to ignore the condition. + rewriter.replaceOp(op, i.getQubits()); + return success(); + }) + .Default([&](auto*) { + // This currently only includes the `Reset` operation. + rewriter.replaceOp(op, op->getOperands()); + return success(); + }); } } // namespace mlir::qco From 69981101dfdf43dd42d44cf78af942258aad9528 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Tue, 2 Jun 2026 20:54:19 +0200 Subject: [PATCH 12/26] =?UTF-8?q?=F0=9F=93=9D=20Add=20to=20generic=20chang?= =?UTF-8?q?elog=20entry=20for=20mqt-cc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukas Burgholzer --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22616216d5..40752e554d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,6 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Added -- ✨ Add Dead Gate Elimination Pattern ([#1755]) ([**@DRovara**]) - 🚸 Add [CMake presets] to provide a standardized and reproducible way to configure builds ([#1660]) ([**@denialhaag**]) - ✨ Add a `quantum-loop-unroll` pass for unrolling for-loop operations containing quantum operations ([#1718]) ([**@MatthiasReumann**]) - ✨ Add a `hadamard-lifting` pass for lifting Hadamard gates above Pauli gates ([#1605]) ([**@lirem101**], [**@burgholzer**]) @@ -19,7 +18,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel - ✨ Add conversions between `jeff` and QCO ([#1479], [#1548], [#1565], [#1637], [#1676], [#1706]) ([**@denialhaag**], [**@burgholzer**]) - ✨ Add a `place-and-route` pass for mapping circuits to architectures with restricted topologies ([#1537], [#1547], [#1568], [#1581], [#1583], [#1588], [#1600], [#1664], [#1709], [#1716], [#1748]) ([**@MatthiasReumann**], [**@burgholzer**]) - ✨ Add initial infrastructure for new QC and QCO MLIR dialects - ([#1264], [#1330], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465], [#1470], [#1471], [#1472], [#1474], [#1475], [#1506], [#1510], [#1513], [#1521], [#1542], [#1548], [#1550], [#1554], [#1567], [#1569], [#1570], [#1572], [#1573], [#1580], [#1602], [#1620], [#1623], [#1624], [#1626], [#1627], [#1635], [#1638], [#1673], [#1675], [#1700], [#1717], [#1728], [#1730], [#1749]) + ([#1264], [#1330], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465], [#1470], [#1471], [#1472], [#1474], [#1475], [#1506], [#1510], [#1513], [#1521], [#1542], [#1548], [#1550], [#1554], [#1567], [#1569], [#1570], [#1572], [#1573], [#1580], [#1602], [#1620], [#1623], [#1624], [#1626], [#1627], [#1635], [#1638], [#1673], [#1675], [#1700], [#1717], [#1728], [#1730], [#1749], [#1755]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**]) ### Changed From d56ccafec0648d9c590a1755ab468bb78acde1dd Mon Sep 17 00:00:00 2001 From: Damian Rovara <93778306+DRovara@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:32:28 +0200 Subject: [PATCH 13/26] Update mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp Co-authored-by: Lukas Burgholzer Signed-off-by: Damian Rovara <93778306+DRovara@users.noreply.github.com> --- mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp index 462a28108d..595761a1a6 100644 --- a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp @@ -126,6 +126,5 @@ OpFoldResult ResetOp::fold(FoldAdaptor /*adaptor*/) { void ResetOp::getCanonicalizationPatterns(RewritePatternSet& results, MLIRContext* context) { - results.add(context); - results.add(context); +results.add(context); } From fb9fffb7a1a8f78083617b00a28eb6e9282fe7a1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 11:33:33 +0000 Subject: [PATCH 14/26] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp index 595761a1a6..8185289762 100644 --- a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp @@ -126,5 +126,5 @@ OpFoldResult ResetOp::fold(FoldAdaptor /*adaptor*/) { void ResetOp::getCanonicalizationPatterns(RewritePatternSet& results, MLIRContext* context) { -results.add(context); + results.add(context); } From 44f295a42fcae57ae7b3c33955d809a2d6cc44d4 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Wed, 3 Jun 2026 13:49:51 +0200 Subject: [PATCH 15/26] test(mlir): :white_check_mark: improve test and add custom return types to QCOProgramBuilder --- .../Dialect/QCO/Builder/QCOProgramBuilder.h | 33 ++++++++++++++++++- .../Dialect/QCO/Builder/QCOProgramBuilder.cpp | 20 +++++++---- mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp | 25 +++++++++----- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h b/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h index 772ea1eba2..1745923964 100644 --- a/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h +++ b/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h @@ -78,7 +78,8 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder { //===--------------------------------------------------------------------===// /** - * @brief Initialize the builder and prepare for program construction + * @brief Initialize the builder and prepare for program construction, with + * a default return type of i64. * * @details * Creates a main function with an entry_point attribute. Must be called @@ -86,6 +87,17 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder { */ void initialize(); + /** + * @brief Initialize the builder and prepare for program construction + * with specified return types. + * @param returnTypes The return types for the main function + * + * @details + * Creates a main function with an entry_point attribute. Must be called + * before adding operations. + */ + void initialize(TypeRange returnTypes); + //===--------------------------------------------------------------------===// // Constants //===--------------------------------------------------------------------===// @@ -1375,6 +1387,25 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder { */ OwningOpRef finalize(); + /** + * @brief Finalize the program with a given exit code and return the + * constructed module + * @param returnValues Values representing the exit code to return + * + * @details + * Automatically deallocates all remaining valid qubits and tensors of qubits, + * adds a return statement with a given exit code, + * and transfers ownership of the module to the caller. The builder should not + * be used after calling this method. + * + * The return values must have the types indicated by the function signature + * of the main function, which returns an `i64` by default and can be + * modified by passing different arguments to the `initialize()` method. + * + * @return OwningOpRef containing the constructed quantum program module + */ + OwningOpRef finalize(ValueRange returnValues); + /** * @brief Convenience method for building quantum programs * @param context The MLIR context to use for building the program diff --git a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp index a07c52aa0f..8627bd9291 100644 --- a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp +++ b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp @@ -52,12 +52,14 @@ QCOProgramBuilder::QCOProgramBuilder(MLIRContext* context) ctx->loadDialect(); } -void QCOProgramBuilder::initialize() { +void QCOProgramBuilder::initialize() { initialize({getI64Type()}); } + +void QCOProgramBuilder::initialize(TypeRange returnTypes) { // Set insertion point to the module body setInsertionPointToStart(mlir::cast(module).getBody()); // Create main function as entry point - auto funcType = getFunctionType({}, {getI64Type()}); + auto funcType = getFunctionType({}, returnTypes); auto mainFunc = func::FuncOp::create(*this, "main", funcType); // Add entry_point attribute to identify the main function @@ -1098,6 +1100,13 @@ void QCOProgramBuilder::ensureAllocationMode( OwningOpRef QCOProgramBuilder::finalize() { checkFinalized(); + auto exitCode = intConstant(0); + return finalize({exitCode}); +} + +OwningOpRef QCOProgramBuilder::finalize(ValueRange returnValues) { + checkFinalized(); + // Ensure that main function exists and insertion point is valid auto* insertionBlock = getInsertionBlock(); func::FuncOp mainFunc = nullptr; @@ -1146,11 +1155,8 @@ OwningOpRef QCOProgramBuilder::finalize() { validQubits.clear(); validTensors.clear(); - // Create constant 0 for successful exit code - auto exitCode = intConstant(0); - - // Add return statement with exit code 0 to the main function - func::ReturnOp::create(*this, exitCode); + // Add return statement with the given return values to the main function + func::ReturnOp::create(*this, returnValues); // Invalidate context to prevent use-after-finalize ctx = nullptr; diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index 3af2feb196..747c88a422 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -116,23 +116,29 @@ TEST_F(QCOTest, BuilderRejectsMixedStaticAndDynamicQubitAllocationModes) { TEST_F(QCOTest, CheckDeadGateElimination) { QCOProgramBuilder builder(context.get()); - builder.initialize(); + builder.initialize({builder.getI1Type(), builder.getI1Type()}); auto q0S0 = builder.allocQubit(); auto q1S0 = builder.allocQubit(); - auto q0S1 = builder.h(q0S0); - auto [q0S2, q1S1] = builder.cx(q0S1, q1S0); + + auto [q0Measured, m0] = builder.measure(q0S0); + auto [q1Measured, m1] = builder.measure(q1S0); + + auto q0S1 = builder.h(q0Measured); + auto [q0S2, q1S1] = builder.cx(q0S1, q1Measured); auto [q1S2, c1] = builder.measure(q1S1); builder.sink(q0S2); builder.sink(q1S2); - auto module = builder.finalize(); + auto module = builder.finalize({m0, m1}); QCOProgramBuilder reference(context.get()); - reference.initialize(); + reference.initialize({reference.getI1Type(), reference.getI1Type()}); auto r0 = reference.allocQubit(); auto r1 = reference.allocQubit(); - reference.sink(r0); - reference.sink(r1); - auto refModule = reference.finalize(); + auto [r0Measured, mr0] = reference.measure(r0); + auto [r1Measured, mr1] = reference.measure(r1); + reference.sink(r0Measured); + reference.sink(r1Measured); + auto refModule = reference.finalize({mr0, mr1}); ASSERT_TRUE(module); EXPECT_TRUE(verify(*module).succeeded()); @@ -144,6 +150,9 @@ TEST_F(QCOTest, CheckDeadGateElimination) { EXPECT_TRUE(runQCOCleanupPipeline(refModule.get()).succeeded()); EXPECT_TRUE(verify(*refModule).succeeded()); + module->dump(); + refModule->dump(); + EXPECT_TRUE( areModulesEquivalentWithPermutations(module.get(), refModule.get())); } From b6cbf8e7508969bd5f62685c3b6064dcf1872fc9 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Wed, 3 Jun 2026 13:51:37 +0200 Subject: [PATCH 16/26] style(mlir): :recycle: remove unneeded dumps --- mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index 747c88a422..a1ef1d8e73 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -150,9 +150,6 @@ TEST_F(QCOTest, CheckDeadGateElimination) { EXPECT_TRUE(runQCOCleanupPipeline(refModule.get()).succeeded()); EXPECT_TRUE(verify(*refModule).succeeded()); - module->dump(); - refModule->dump(); - EXPECT_TRUE( areModulesEquivalentWithPermutations(module.get(), refModule.get())); } From dee0752928dec877c0d33033dbf2ad23c6928d8f Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Wed, 3 Jun 2026 14:01:06 +0200 Subject: [PATCH 17/26] style(mlir): :recycle: move `checkAndRemoveDeadGate` implementation out of helper function --- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 41 ------------------- .../Dialect/QCO/IR/Operations/MeasureOp.cpp | 7 +++- .../lib/Dialect/QCO/IR/Operations/ResetOp.cpp | 7 +++- mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 8 +++- mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp | 9 +++- 5 files changed, 27 insertions(+), 45 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index e8f9cf9450..7cdffc18e7 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -238,45 +238,4 @@ mergeTwoTargetOneParameterWithSwappedTargets(OpType op, return success(); } -/** - * @brief Check if a given quantum operation is unused (i.e., only used by - * sinks) and remove it if so. - * - * @param op The operation to check. - * @param rewriter The pattern rewriter. - * @return LogicalResult Success or failure of the removal. - */ -inline LogicalResult checkAndRemoveDeadGate(Operation* op, - PatternRewriter& rewriter) { - if (!llvm::all_of(op->getUsers(), - [](Operation* user) { return isa(user); })) { - return failure(); - } - - // If the operation is only used by sinks, we can safely remove it. - return TypeSwitch(op) - .Case([&](auto u) { - // Replace output *qubits* with input *qubits* to ignore parameters. - rewriter.replaceOp(op, u.getInputQubits()); - return success(); - }) - .Case([&](auto m) { - // Replace output *qubits* with input *qubits* to ignore classical - // outcome. - rewriter.replaceAllUsesWith(m.getQubitOut(), m.getQubitIn()); - rewriter.eraseOp(op); - return success(); - }) - .Case([&](auto i) { - // Replace output *qubits* with input *qubits* to ignore the condition. - rewriter.replaceOp(op, i.getQubits()); - return success(); - }) - .Default([&](auto*) { - // This currently only includes the `Reset` operation. - rewriter.replaceOp(op, op->getOperands()); - return success(); - }); -} - } // namespace mlir::qco diff --git a/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp b/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp index 5d0462b6d7..83fe25582f 100644 --- a/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp @@ -28,7 +28,12 @@ struct DeadMeasurementRemoval final : OpRewritePattern { LogicalResult matchAndRewrite(MeasureOp op, PatternRewriter& rewriter) const override { - return checkAndRemoveDeadGate(op, rewriter); + if (!llvm::all_of(op->getUsers(), + [](Operation* user) { return isa(user); })) { + return failure(); + } + rewriter.replaceAllUsesWith(op.getQubitOut(), op.getQubitIn()); + rewriter.eraseOp(op); } }; diff --git a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp index 8185289762..245cf415ba 100644 --- a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp @@ -110,7 +110,12 @@ struct DeadResetRemoval final : OpRewritePattern { LogicalResult matchAndRewrite(ResetOp op, PatternRewriter& rewriter) const override { - return checkAndRemoveDeadGate(op, rewriter); + if (!llvm::all_of(op->getUsers(), + [](Operation* user) { return isa(user); })) { + return failure(); + } + rewriter.replaceOp(op, op->getOperands()); + return success(); } }; diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index e49d00da5a..f3ae237f77 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -58,7 +58,13 @@ struct DeadGateElimination final // dead. return failure(); } - return checkAndRemoveDeadGate(op.getOperation(), rewriter); + if (!llvm::all_of(op->getUsers(), + [](Operation* user) { return isa(user); })) { + return failure(); + } + + rewriter.replaceOp(op, op.getInputQubits()); + return success(); } }; } // namespace diff --git a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp index 6589fbbad7..558038dd2b 100644 --- a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp @@ -249,7 +249,14 @@ struct DeadIfRemoval final : OpRewritePattern { // This effectively ignores `IfOp`s with memory effects. return failure(); } - return checkAndRemoveDeadGate(op, rewriter); + + if (!llvm::all_of(op->getUsers(), + [](Operation* user) { return isa(user); })) { + return failure(); + } + + rewriter.replaceOp(op, op.getQubits()); + return success(); } }; } // namespace From 244f8bb2aeb57b82b3d971da57b16c1ecba5aa03 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Wed, 3 Jun 2026 14:23:05 +0200 Subject: [PATCH 18/26] style(mlir): :recycle: implement helper function to check if a gate is dead --- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 17 +++++++++++++++++ .../lib/Dialect/QCO/IR/Operations/MeasureOp.cpp | 5 +++-- mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp | 4 ++-- mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 9 +-------- mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp | 8 +------- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index 7cdffc18e7..1c920403fe 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -238,4 +238,21 @@ mergeTwoTargetOneParameterWithSwappedTargets(OpType op, return success(); } +/** + * @brief Check if given quantum operation is unused (i.e., only used by + * sinks and no memory effects). + * + * @param op The operation to check. + * @return bool True if the operation is unused, false otherwise. + */ +inline bool checkDeadGate(Operation* op) { + if (!isMemoryEffectFree(op)) { + // This ignores operations with and regions that have children with memory + // effects, which should never be considered dead. + return false; + } + return llvm::all_of(op->getUsers(), + [](Operation* user) { return isa(user); }); +} + } // namespace mlir::qco diff --git a/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp b/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp index 83fe25582f..b2107f7836 100644 --- a/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/Operations/MeasureOp.cpp @@ -28,12 +28,13 @@ struct DeadMeasurementRemoval final : OpRewritePattern { LogicalResult matchAndRewrite(MeasureOp op, PatternRewriter& rewriter) const override { - if (!llvm::all_of(op->getUsers(), - [](Operation* user) { return isa(user); })) { + if (!checkDeadGate(op)) { return failure(); } + rewriter.replaceAllUsesWith(op.getQubitOut(), op.getQubitIn()); rewriter.eraseOp(op); + return success(); } }; diff --git a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp index 245cf415ba..0886ba39a6 100644 --- a/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/Operations/ResetOp.cpp @@ -110,10 +110,10 @@ struct DeadResetRemoval final : OpRewritePattern { LogicalResult matchAndRewrite(ResetOp op, PatternRewriter& rewriter) const override { - if (!llvm::all_of(op->getUsers(), - [](Operation* user) { return isa(user); })) { + if (!checkDeadGate(op)) { return failure(); } + rewriter.replaceOp(op, op->getOperands()); return success(); } diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index f3ae237f77..87edb6179f 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -52,14 +52,7 @@ struct DeadGateElimination final LogicalResult matchAndRewrite(UnitaryOpInterface op, PatternRewriter& rewriter) const override { - if (!isMemoryEffectFree(op)) { - // This effectively ignores the GPhase operation and variants such as its - // inverse or `ctrl` ops containing it, which should never be considered - // dead. - return failure(); - } - if (!llvm::all_of(op->getUsers(), - [](Operation* user) { return isa(user); })) { + if (!checkDeadGate(op)) { return failure(); } diff --git a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp index 558038dd2b..43e2154ce4 100644 --- a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp @@ -245,13 +245,7 @@ struct DeadIfRemoval final : OpRewritePattern { LogicalResult matchAndRewrite(IfOp op, PatternRewriter& rewriter) const override { - if (!isMemoryEffectFree(op)) { - // This effectively ignores `IfOp`s with memory effects. - return failure(); - } - - if (!llvm::all_of(op->getUsers(), - [](Operation* user) { return isa(user); })) { + if (!checkDeadGate(op)) { return failure(); } From 6eaac407e914afe440b02efdcbbb8008c7690749 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Wed, 3 Jun 2026 14:29:39 +0200 Subject: [PATCH 19/26] style(mlir): :rotating_light: fix includes --- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 1 + mlir/lib/Dialect/QCO/IR/QCOOps.cpp | 1 - mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index 1c920403fe..4ade5351f7 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace mlir::qco { diff --git a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp index 87edb6179f..a49a833929 100644 --- a/mlir/lib/Dialect/QCO/IR/QCOOps.cpp +++ b/mlir/lib/Dialect/QCO/IR/QCOOps.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include // The following headers are needed for some template instantiations. diff --git a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp index 43e2154ce4..00e17eb0a1 100644 --- a/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/SCF/IfOp.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include From 07a3f4db3997526104a7d43df83073a54ea6123a Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Fri, 5 Jun 2026 10:45:37 +0200 Subject: [PATCH 20/26] docs(mlir): :memo: add comments to document `gphase` operation as memory effect --- mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index a1ef1d8e73..e4c4262572 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -167,7 +167,7 @@ TEST_F(QCOTest, CheckIfOpDeadGateElimination) { c0, {q1S0}, [&](ValueRange qubits) -> SmallVector { auto q1Then = builder.x(qubits[0]); - builder.gphase(0.5); + builder.gphase(0.5); // This adds memory effects to the `IfOp`. return SmallVector{q1Then}; }, [&](ValueRange qubits) -> SmallVector { @@ -202,7 +202,7 @@ TEST_F(QCOTest, CheckIfOpDeadGateElimination) { cr0, {r1S0}, [&](ValueRange qubits) -> SmallVector { auto q1Then = reference.x(qubits[0]); - reference.gphase(0.5); + reference.gphase(0.5); // Due to memory effect, the `IfOp` stays. return SmallVector{q1Then}; }, [&](ValueRange qubits) -> SmallVector { From cab4155315bb1c79561324f0ce39921cfbd0a348 Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Fri, 5 Jun 2026 13:44:22 +0200 Subject: [PATCH 21/26] test(mlir): :white_check_mark: update tests to now use return values --- .../Dialect/QCO/Builder/QCOProgramBuilder.h | 26 +- .../Dialect/QCO/Builder/QCOProgramBuilder.cpp | 26 +- mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp | 114 +- .../Dialect/QCO/IR/test_qco_ir_matrix.cpp | 35 +- mlir/unittests/TestCaseUtils.h | 14 +- mlir/unittests/programs/qco_programs.cpp | 2671 ++++++++++++----- mlir/unittests/programs/qco_programs.h | 922 ++++-- 7 files changed, 2644 insertions(+), 1164 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h b/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h index 1745923964..380750ba8a 100644 --- a/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h +++ b/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h @@ -98,6 +98,12 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder { */ void initialize(TypeRange returnTypes); + /** + * @brief Modify the return types of the main function after initialization. + * @param returnTypes The new return types for the main function + */ + void retype(TypeRange returnTypes); + //===--------------------------------------------------------------------===// // Constants //===--------------------------------------------------------------------===// @@ -384,7 +390,7 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder { * * @param qubit Input qubit (must be valid/unconsumed) * @param bit The classical bit to record the result - * @return Output qubit value + * @return Pair of (output_qubit, measurement_result) * * @par Example: * ```c++ @@ -394,7 +400,7 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder { * %q0_out, %r0 = qco.measure("c", 3, 0) %q0 : !qco.qubit * ``` */ - Value measure(Value qubit, const Bit& bit); + std::pair measure(Value qubit, const Bit& bit); /** * @brief Reset a qubit to |0⟩ state @@ -1419,6 +1425,22 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder { build(MLIRContext* context, const function_ref& buildFunc); + /** + * @brief Convenience method for building quantum programs with returns. + * @param context The MLIR context to use for building the program + * @param returnTypes The types of the values to be returned by the program. + * @param buildFunc A function that takes a reference to a QCOProgramBuilder + * and uses it to build the desired quantum program. The builder will be + * properly initialized before calling this function, and the resulting module + * will be finalized using the returned ValueRange after this function + * completes. + * @return The module containing the quantum program built by buildFunc. + */ + static OwningOpRef buildWithReturn( + MLIRContext* context, + const function_ref, SmallVector>( + QCOProgramBuilder&)>& buildFunc); + private: enum class AllocationMode : uint8_t { Unset, Static, Dynamic }; diff --git a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp index 8627bd9291..1e39c1fabf 100644 --- a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp +++ b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp @@ -71,6 +71,16 @@ void QCOProgramBuilder::initialize(TypeRange returnTypes) { setInsertionPointToStart(&entryBlock); } +void QCOProgramBuilder::retype(TypeRange returnTypes) { + auto mainFunc = dyn_cast(module).lookupSymbol("main"); + if (!mainFunc) { + llvm::reportFatalUsageError("Main function not found for retyping"); + } + auto funcType = + getFunctionType(mainFunc.getFunctionType().getInputs(), returnTypes); + mainFunc.setType(funcType); +} + Value QCOProgramBuilder::intConstant(const int64_t value) { checkFinalized(); return arith::ConstantOp::create(*this, getI64IntegerAttr(value)).getResult(); @@ -397,7 +407,8 @@ std::pair QCOProgramBuilder::measure(Value qubit) { return {qubitOut, result}; } -Value QCOProgramBuilder::measure(Value qubit, const Bit& bit) { +std::pair QCOProgramBuilder::measure(Value qubit, + const Bit& bit) { checkFinalized(); auto nameAttr = getStringAttr(bit.registerName); @@ -410,7 +421,7 @@ Value QCOProgramBuilder::measure(Value qubit, const Bit& bit) { // Update tracking updateQubitTracking(qubit, qubitOut); - return qubitOut; + return {qubitOut, measureOp.getResult()}; } Value QCOProgramBuilder::reset(Value qubit) { @@ -1173,4 +1184,15 @@ OwningOpRef QCOProgramBuilder::build( return builder.finalize(); } +OwningOpRef QCOProgramBuilder::buildWithReturn( + MLIRContext* context, + const function_ref, SmallVector>( + QCOProgramBuilder&)>& buildFunc) { + QCOProgramBuilder builder(context); + builder.initialize(); + auto [result, resultTypes] = buildFunc(builder); + builder.retype(resultTypes); + return builder.finalize(result); +} + } // namespace mlir::qco diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index e4c4262572..13d3adc5e7 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -74,7 +74,8 @@ TEST_P(QCOTest, ProgramEquivalence) { const auto name = " (" + GetParam().name + ")"; mqt::test::DeferredPrinter printer; - auto program = QCOProgramBuilder::build(context.get(), programBuilder.fn); + auto program = + QCOProgramBuilder::buildWithReturn(context.get(), programBuilder.fn); ASSERT_TRUE(program); printer.record(program.get(), "Original QCO IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -83,7 +84,8 @@ TEST_P(QCOTest, ProgramEquivalence) { printer.record(program.get(), "Canonicalized QCO IR" + name); EXPECT_TRUE(verify(*program).succeeded()); - auto reference = QCOProgramBuilder::build(context.get(), referenceBuilder.fn); + auto reference = + QCOProgramBuilder::buildWithReturn(context.get(), referenceBuilder.fn); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QCO IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); @@ -231,7 +233,7 @@ TEST_F(QCOTest, CheckIfOpDeadGateElimination) { TEST_F(QCOTest, DirectIfBuilder) { // Test If construction directly QCOProgramBuilder builder(context.get()); - builder.initialize(); + builder.initialize({builder.getI1Type()}); auto c0 = arith::ConstantIndexOp::create(builder, 0); auto c1 = arith::ConstantIndexOp::create(builder, 1); auto r0 = qtensor::AllocOp::create(builder, c1); @@ -244,18 +246,19 @@ TEST_F(QCOTest, DirectIfBuilder) { auto innerQubit = XOp::create(builder, qubits[0]); return SmallVector{innerQubit}; }); - auto r2 = qtensor::InsertOp::create(builder, ifOp.getResult(0), + auto finalMeasureOp = MeasureOp::create(builder, ifOp.getResult(0)); + auto r2 = qtensor::InsertOp::create(builder, finalMeasureOp.getQubitOut(), extractOp.getOutTensor(), c0); qtensor::DeallocOp::create(builder, r2); - auto directBuilder = builder.finalize(); + auto directBuilder = builder.finalize({finalMeasureOp.getResult()}); ASSERT_TRUE(directBuilder); EXPECT_TRUE(verify(*directBuilder).succeeded()); EXPECT_TRUE(runQCOCleanupPipeline(directBuilder.get()).succeeded()); EXPECT_TRUE(verify(*directBuilder).succeeded()); - auto refBuilder = - QCOProgramBuilder::build(context.get(), MQT_NAMED_BUILDER(simpleIf).fn); + auto refBuilder = QCOProgramBuilder::buildWithReturn( + context.get(), MQT_NAMED_BUILDER(simpleIf).fn); ASSERT_TRUE(refBuilder); EXPECT_TRUE(verify(*refBuilder).succeeded()); EXPECT_TRUE(runQCOCleanupPipeline(refBuilder.get()).succeeded()); @@ -269,10 +272,9 @@ TEST_F(QCOTest, IfOpParser) { // Test IfOp parser const char* mlirCode = R"( module { - func.func @main() -> i64 attributes {passthrough = ["entry_point"]} { + func.func @main() -> i1 attributes {passthrough = ["entry_point"]} { %c0 = arith.constant 0 : index %c1 = arith.constant 1 : index - %c0_i64 = arith.constant 0 : i64 %q0_0 = qco.alloc : !qco.qubit %t0 = qtensor.alloc(%c1) : tensor<1x!qco.qubit> %q0_1 = qco.h %q0_0 : !qco.qubit -> !qco.qubit @@ -286,9 +288,10 @@ TEST_F(QCOTest, IfOpParser) { } else args(%arg0 = %q0_2, %arg1 = %t0) { qco.yield %arg0, %arg1 : !qco.qubit, tensor<1x!qco.qubit> } - qco.sink %q0_4 : !qco.qubit + %q0_5, %c = qco.measure %q0_4 : !qco.qubit + qco.sink %q0_5 : !qco.qubit qtensor.dealloc %t3 : tensor<1x!qco.qubit> - return %c0_i64 : i64 + return %c : i1 } })"; @@ -299,7 +302,7 @@ TEST_F(QCOTest, IfOpParser) { EXPECT_TRUE(runQCOCleanupPipeline(parsedSourceModule.get()).succeeded()); EXPECT_TRUE(verify(*parsedSourceModule).succeeded()); - auto refBuilder = QCOProgramBuilder::build( + auto refBuilder = QCOProgramBuilder::buildWithReturn( context.get(), MQT_NAMED_BUILDER(ifOneQubitOneTensor).fn); ASSERT_TRUE(refBuilder); EXPECT_TRUE(verify(*refBuilder).succeeded()); @@ -413,7 +416,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(twoDcx)}, QCOTestCase{"TwoDCXSwappedTargets", MQT_NAMED_BUILDER(twoDcxSwappedTargets), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc2QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/EcrOp.cpp @@ -440,7 +443,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledEcr), MQT_NAMED_BUILDER(multipleControlledEcr)}, QCOTestCase{"TwoECR", MQT_NAMED_BUILDER(twoEcr), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc2QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/GphaseOp.cpp @@ -484,7 +487,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledH), MQT_NAMED_BUILDER(multipleControlledH)}, QCOTestCase{"TwoH", MQT_NAMED_BUILDER(twoH), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(allocQubit)})); /// @} /// \name QCO/Operations/StandardGates/IdOp.cpp @@ -493,24 +496,24 @@ INSTANTIATE_TEST_SUITE_P( QCOIDOpTest, QCOTest, testing::Values( QCOTestCase{"Identity", MQT_NAMED_BUILDER(identity), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(allocQubit)}, QCOTestCase{"SingleControlledIdentity", MQT_NAMED_BUILDER(singleControlledIdentity), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc2QubitRegister)}, QCOTestCase{"MultipleControlledIdentity", MQT_NAMED_BUILDER(multipleControlledIdentity), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc3QubitRegister)}, QCOTestCase{"NestedControlledIdentity", MQT_NAMED_BUILDER(nestedControlledIdentity), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc3QubitRegister)}, QCOTestCase{"TrivialControlledIdentity", MQT_NAMED_BUILDER(trivialControlledIdentity), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(allocQubit)}, QCOTestCase{"InverseIdentity", MQT_NAMED_BUILDER(inverseIdentity), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(allocQubit)}, QCOTestCase{"InverseMultipleControlledIdentity", MQT_NAMED_BUILDER(inverseMultipleControlledIdentity), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc3QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/IswapOp.cpp @@ -560,7 +563,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledP), MQT_NAMED_BUILDER(multipleControlledP)}, QCOTestCase{"TwoPOppositePhase", MQT_NAMED_BUILDER(twoPOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(allocQubit)})); /// @} /// \name QCO/Operations/StandardGates/ROp.cpp @@ -611,7 +614,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledRx), MQT_NAMED_BUILDER(multipleControlledRx)}, QCOTestCase{"TwoRXOppositePhase", MQT_NAMED_BUILDER(twoRxOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc1QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/RxxOp.cpp @@ -644,10 +647,10 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(rxx)}, QCOTestCase{"TwoRXXOppositePhase", MQT_NAMED_BUILDER(twoRxxOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc2QubitRegister)}, QCOTestCase{"TwoRXXOppositePhaseSwappedTargets", MQT_NAMED_BUILDER(twoRxxOppositePhaseSwappedTargets), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc2QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/RyOp.cpp @@ -672,7 +675,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledRy), MQT_NAMED_BUILDER(multipleControlledRy)}, QCOTestCase{"TwoRYOppositePhase", MQT_NAMED_BUILDER(twoRyOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc1QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/RyyOp.cpp @@ -705,10 +708,10 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(ryy)}, QCOTestCase{"TwoRYYOppositePhaseSwappedTargets", MQT_NAMED_BUILDER(twoRyyOppositePhaseSwappedTargets), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc2QubitRegister)}, QCOTestCase{"TwoRYYOppositePhase", MQT_NAMED_BUILDER(twoRyyOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc2QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/RzOp.cpp @@ -733,7 +736,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledRz), MQT_NAMED_BUILDER(multipleControlledRz)}, QCOTestCase{"TwoRZOppositePhase", MQT_NAMED_BUILDER(twoRzOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc1QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/RzxOp.cpp @@ -761,7 +764,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(multipleControlledRzx)}, QCOTestCase{"TwoRZXOppositePhase", MQT_NAMED_BUILDER(twoRzxOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc2QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/RzzOp.cpp @@ -794,10 +797,10 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(rzz)}, QCOTestCase{"TwoRZZOppositePhaseSwappedTargets", MQT_NAMED_BUILDER(twoRzzOppositePhaseSwappedTargets), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc2QubitRegister)}, QCOTestCase{"TwoRZZOppositePhase", MQT_NAMED_BUILDER(twoRzzOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc2QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/SOp.cpp @@ -821,7 +824,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledS), MQT_NAMED_BUILDER(multipleControlledSdg)}, QCOTestCase{"SThenSdg", MQT_NAMED_BUILDER(sThenSdg), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc1QubitRegister)}, QCOTestCase{"TwoS", MQT_NAMED_BUILDER(twoS), MQT_NAMED_BUILDER(z)})); /// @} @@ -849,7 +852,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledSdg), MQT_NAMED_BUILDER(multipleControlledS)}, QCOTestCase{"SdgThenS", MQT_NAMED_BUILDER(sdgThenS), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc1QubitRegister)}, QCOTestCase{"TwoSdg", MQT_NAMED_BUILDER(twoSdg), MQT_NAMED_BUILDER(z)})); /// @} @@ -878,10 +881,10 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledSwap), MQT_NAMED_BUILDER(multipleControlledSwap)}, QCOTestCase{"TwoSWAP", MQT_NAMED_BUILDER(twoSwap), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc2QubitRegister)}, QCOTestCase{"TwoSWAPSwappedTargets", MQT_NAMED_BUILDER(twoSwapSwappedTargets), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc2QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/SxOp.cpp @@ -906,7 +909,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledSx), MQT_NAMED_BUILDER(multipleControlledSxdg)}, QCOTestCase{"SXThenSXdg", MQT_NAMED_BUILDER(sxThenSxdg), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc1QubitRegister)}, QCOTestCase{"TwoSX", MQT_NAMED_BUILDER(twoSx), MQT_NAMED_BUILDER(x)})); /// @} @@ -934,7 +937,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledSxdg), MQT_NAMED_BUILDER(multipleControlledSx)}, QCOTestCase{"SXdgThenSX", MQT_NAMED_BUILDER(sxdgThenSx), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc1QubitRegister)}, QCOTestCase{"TwoSXdg", MQT_NAMED_BUILDER(twoSxdg), MQT_NAMED_BUILDER(x)})); /// @} @@ -960,7 +963,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledT), MQT_NAMED_BUILDER(multipleControlledTdg)}, QCOTestCase{"TThenTdg", MQT_NAMED_BUILDER(tThenTdg), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc1QubitRegister)}, QCOTestCase{"TwoT", MQT_NAMED_BUILDER(twoT), MQT_NAMED_BUILDER(s)})); /// @} @@ -988,7 +991,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledTdg), MQT_NAMED_BUILDER(multipleControlledT)}, QCOTestCase{"TdgThenS", MQT_NAMED_BUILDER(tdgThenT), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc1QubitRegister)}, QCOTestCase{"TwoTdg", MQT_NAMED_BUILDER(twoTdg), MQT_NAMED_BUILDER(sdg)})); /// @} @@ -1073,7 +1076,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledX), MQT_NAMED_BUILDER(multipleControlledX)}, QCOTestCase{"TwoX", MQT_NAMED_BUILDER(twoX), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc1QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/XxMinusYyOp.cpp @@ -1102,7 +1105,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(multipleControlledXxMinusYY)}, QCOTestCase{"TwoXXMinusYYOppositePhase", MQT_NAMED_BUILDER(twoXxMinusYYOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc2QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/XxPlusYyOp.cpp @@ -1131,7 +1134,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(multipleControlledXxPlusYY)}, QCOTestCase{"TwoXXPlusYYOppositePhase", MQT_NAMED_BUILDER(twoXxPlusYYOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc2QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/YOp.cpp @@ -1155,7 +1158,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledY), MQT_NAMED_BUILDER(multipleControlledY)}, QCOTestCase{"TwoY", MQT_NAMED_BUILDER(twoY), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc1QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/ZOp.cpp @@ -1179,7 +1182,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(inverseMultipleControlledZ), MQT_NAMED_BUILDER(multipleControlledZ)}, QCOTestCase{"TwoZ", MQT_NAMED_BUILDER(twoZ), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc1QubitRegister)})); /// @} /// \name QCO/Operations/MeasureOp.cpp @@ -1208,13 +1211,13 @@ INSTANTIATE_TEST_SUITE_P( QCOResetOpTest, QCOTest, testing::Values(QCOTestCase{"ResetQubitWithoutOp", MQT_NAMED_BUILDER(resetQubitWithoutOp), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(allocQubit)}, QCOTestCase{"ResetMultipleQubitsWithoutOp", MQT_NAMED_BUILDER(resetMultipleQubitsWithoutOp), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc2QubitRegister)}, QCOTestCase{"RepeatedResetWithoutOp", MQT_NAMED_BUILDER(repeatedResetWithoutOp), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(allocQubit)}, QCOTestCase{"ResetQubitAfterSingleOp", MQT_NAMED_BUILDER(resetQubitAfterSingleOp), MQT_NAMED_BUILDER(resetQubitAfterSingleOp)}, @@ -1232,16 +1235,9 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCOQubitManagementTest, QCOTest, testing::Values( - QCOTestCase{"AllocQubit", MQT_NAMED_BUILDER(allocQubit), - MQT_NAMED_BUILDER(emptyQCO)}, - QCOTestCase{"AllocQubitRegister", MQT_NAMED_BUILDER(allocQubitRegister), - MQT_NAMED_BUILDER(emptyQCO)}, - QCOTestCase{"AllocMultipleQubitRegisters", - MQT_NAMED_BUILDER(allocMultipleQubitRegisters), - MQT_NAMED_BUILDER(emptyQCO)}, - QCOTestCase{"AllocLargeRegister", MQT_NAMED_BUILDER(allocLargeRegister), + QCOTestCase{"AllocQubit", MQT_NAMED_BUILDER(allocQubitNoMeasure), MQT_NAMED_BUILDER(emptyQCO)}, - QCOTestCase{"StaticQubits", MQT_NAMED_BUILDER(staticQubits), + QCOTestCase{"StaticQubits", MQT_NAMED_BUILDER(staticQubitsNoMeasure), MQT_NAMED_BUILDER(emptyQCO)}, QCOTestCase{"StaticQubitsWithOps", MQT_NAMED_BUILDER(staticQubitsWithOps), @@ -1259,5 +1255,5 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(staticQubitsWithInv), MQT_NAMED_BUILDER(staticQubitsWithInv)}, QCOTestCase{"AllocSinkPair", MQT_NAMED_BUILDER(allocSinkPair), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(allocQubit)})); /// @} diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir_matrix.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir_matrix.cpp index 24103da18c..af51838e16 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir_matrix.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir_matrix.cpp @@ -59,7 +59,8 @@ class QCOMatrixTest : public testing::TestWithParam { /// \name QCO/Modifiers/CtrlOp.cpp /// @{ TEST_F(QCOMatrixTest, CXOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), singleControlledX); + auto moduleOp = + QCOProgramBuilder::buildWithReturn(context.get(), singleControlledX); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -89,7 +90,8 @@ TEST_F(QCOMatrixTest, CXOpMatrix) { /// \name QCO/Modifiers/InvOp.cpp /// @{ TEST_F(QCOMatrixTest, InverseIswapOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), inverseIswap); + auto moduleOp = + QCOProgramBuilder::buildWithReturn(context.get(), inverseIswap); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -163,7 +165,8 @@ TEST_F(QCOMatrixTest, ECROpMatrix) { /// \name QCO/Operations/StandardGates/GphaseOp.cpp /// @{ TEST_F(QCOMatrixTest, GPhaseOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), globalPhase); + auto moduleOp = + QCOProgramBuilder::buildWithReturn(context.get(), globalPhase); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -244,7 +247,7 @@ TEST_F(QCOMatrixTest, iSWAPOpMatrix) { /// \name QCO/Operations/StandardGates/POp.cpp /// @{ TEST_F(QCOMatrixTest, POpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), p); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), p); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -267,7 +270,7 @@ TEST_F(QCOMatrixTest, POpMatrix) { /// \name QCO/Operations/StandardGates/ROp.cpp /// @{ TEST_F(QCOMatrixTest, ROpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), r); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), r); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -290,7 +293,7 @@ TEST_F(QCOMatrixTest, ROpMatrix) { /// \name QCO/Operations/StandardGates/RxOp.cpp /// @{ TEST_F(QCOMatrixTest, RXOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), rx); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), rx); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -314,7 +317,7 @@ TEST_F(QCOMatrixTest, RXOpMatrix) { /// \name QCO/Operations/StandardGates/RxxOp.cpp /// @{ TEST_F(QCOMatrixTest, RXXOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), rxx); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), rxx); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -341,7 +344,7 @@ TEST_F(QCOMatrixTest, RXXOpMatrix) { /// \name QCO/Operations/StandardGates/RyOp.cpp /// @{ TEST_F(QCOMatrixTest, RYOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), ry); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), ry); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -365,7 +368,7 @@ TEST_F(QCOMatrixTest, RYOpMatrix) { /// \name QCO/Operations/StandardGates/RyyOp.cpp /// @{ TEST_F(QCOMatrixTest, RYYOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), ryy); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), ryy); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -392,7 +395,7 @@ TEST_F(QCOMatrixTest, RYYOpMatrix) { /// \name QCO/Operations/StandardGates/RzOp.cpp /// @{ TEST_F(QCOMatrixTest, RZOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), rz); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), rz); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -416,7 +419,7 @@ TEST_F(QCOMatrixTest, RZOpMatrix) { /// \name QCO/Operations/StandardGates/RzxOp.cpp /// @{ TEST_F(QCOMatrixTest, RZXOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), rzx); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), rzx); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -443,7 +446,7 @@ TEST_F(QCOMatrixTest, RZXOpMatrix) { /// \name QCO/Operations/StandardGates/RzzOp.cpp /// @{ TEST_F(QCOMatrixTest, RZZOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), rzz); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), rzz); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -600,7 +603,7 @@ TEST_F(QCOMatrixTest, TdgOpMatrix) { /// \name QCO/Operations/StandardGates/U2Op.cpp /// @{ TEST_F(QCOMatrixTest, U2OpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), u2); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), u2); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -624,7 +627,7 @@ TEST_F(QCOMatrixTest, U2OpMatrix) { /// \name QCO/Operations/StandardGates/UOp.cpp /// @{ TEST_F(QCOMatrixTest, UOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), u); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), u); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -666,7 +669,7 @@ TEST_F(QCOMatrixTest, XOpMatrix) { /// \name QCO/Operations/StandardGates/XxMinusYyOp.cpp /// @{ TEST_F(QCOMatrixTest, XXMinusYYOpMatrix) { - auto moduleOp = QCOProgramBuilder::build(context.get(), xxMinusYY); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), xxMinusYY); ASSERT_TRUE(moduleOp); // Get the operation from the module @@ -694,7 +697,7 @@ TEST_F(QCOMatrixTest, XXMinusYYOpMatrix) { /// \name QCO/Operations/StandardGates/XxPlusYyOp.cpp /// @{ TEST_F(QCOMatrixTest, XXPlusYYOp) { - auto moduleOp = QCOProgramBuilder::build(context.get(), xxPlusYY); + auto moduleOp = QCOProgramBuilder::buildWithReturn(context.get(), xxPlusYY); ASSERT_TRUE(moduleOp); // Get the operation from the module diff --git a/mlir/unittests/TestCaseUtils.h b/mlir/unittests/TestCaseUtils.h index 570c86c87f..16dbd46fdc 100644 --- a/mlir/unittests/TestCaseUtils.h +++ b/mlir/unittests/TestCaseUtils.h @@ -28,9 +28,13 @@ namespace mqt::test { template struct NamedBuilder { const char* name = nullptr; - void (*fn)(BuilderT&) = nullptr; + std::pair, mlir::SmallVector> ( + *fn)(BuilderT&) = nullptr; - constexpr NamedBuilder(const char* nameIn, void (*fnIn)(BuilderT&)) noexcept + constexpr NamedBuilder( + const char* nameIn, + std::pair, mlir::SmallVector> ( + *fnIn)(BuilderT&)) noexcept : name(nameIn), fn(fnIn) {} // NOLINTNEXTLINE(*-explicit-constructor) @@ -42,8 +46,10 @@ template struct NamedBuilder { }; template -[[nodiscard]] constexpr NamedBuilder -namedBuilder(const char* name, void (*fn)(BuilderT&)) noexcept { +[[nodiscard]] constexpr NamedBuilder namedBuilder( + const char* name, + std::pair, mlir::SmallVector> ( + *fn)(BuilderT&)) noexcept { return NamedBuilder{name, fn}; } diff --git a/mlir/unittests/programs/qco_programs.cpp b/mlir/unittests/programs/qco_programs.cpp index 0ad96fbb10..6c5cb9f68e 100644 --- a/mlir/unittests/programs/qco_programs.cpp +++ b/mlir/unittests/programs/qco_programs.cpp @@ -14,201 +14,321 @@ #include #include +#include #include #include #include +static std::pair, mlir::SmallVector> +measureAndReturn(mlir::qco::QCOProgramBuilder& b, + mlir::SmallVector qubits) { + mlir::SmallVector bits; + mlir::SmallVector bitTypes; + auto i1Type = b.getI1Type(); + for (const auto& q : qubits) { + auto [q2, bit] = b.measure(q); + bits.push_back(bit); + bitTypes.push_back(i1Type); + } + return {bits, bitTypes}; +} + namespace mlir::qco { -void emptyQCO([[maybe_unused]] QCOProgramBuilder& builder) {} +std::pair, SmallVector> +emptyQCO([[maybe_unused]] QCOProgramBuilder& builder) { + return measureAndReturn(builder, {}); +} + +std::pair, SmallVector> +allocQubit(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + return measureAndReturn(b, {q}); +} + +std::pair, SmallVector> +allocQubitNoMeasure(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + return measureAndReturn(b, {}); +} + +std::pair, SmallVector> +alloc1QubitRegister(QCOProgramBuilder& b) { + auto reg = b.allocQubitRegister(1); + return measureAndReturn(b, {reg[0]}); +} -void allocQubit(QCOProgramBuilder& b) { b.allocQubit(); } +std::pair, SmallVector> +alloc2QubitRegister(QCOProgramBuilder& b) { + auto reg = b.allocQubitRegister(2); + return measureAndReturn(b, {reg[0], reg[1]}); +} -void allocQubitRegister(QCOProgramBuilder& b) { b.allocQubitRegister(2); } +std::pair, SmallVector> +alloc3QubitRegister(QCOProgramBuilder& b) { + auto reg = b.allocQubitRegister(3); + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); +} -void allocMultipleQubitRegisters(QCOProgramBuilder& b) { - b.allocQubitRegister(2); - b.allocQubitRegister(3); +std::pair, SmallVector> +allocMultipleQubitRegisters(QCOProgramBuilder& b) { + auto r1 = b.allocQubitRegister(2); + auto r2 = b.allocQubitRegister(3); + return measureAndReturn(b, {r1[0], r1[1], r2[0], r2[1], r2[2]}); } -void allocLargeRegister(QCOProgramBuilder& b) { b.allocQubitRegister(100); } +std::pair, SmallVector> +allocLargeRegister(QCOProgramBuilder& b) { + auto r = b.allocQubitRegister(100); + return measureAndReturn(b, {r[0]}); +} -void staticQubits(QCOProgramBuilder& b) { - b.staticQubit(0); - b.staticQubit(1); +std::pair, SmallVector> +staticQubitsNoMeasure(QCOProgramBuilder& b) { + auto q1 = b.staticQubit(0); + auto q2 = b.staticQubit(1); + return measureAndReturn(b, {}); } -void staticQubitsWithOps(QCOProgramBuilder& b) { +std::pair, SmallVector> +staticQubits(QCOProgramBuilder& b) { + auto q1 = b.staticQubit(0); + auto q2 = b.staticQubit(1); + return measureAndReturn(b, {q1, q2}); +} + +std::pair, SmallVector> +staticQubitsWithOps(QCOProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); q0 = b.h(q0); q1 = b.h(q1); + return measureAndReturn(b, {q0, q1}); } -void staticQubitsWithParametricOps(QCOProgramBuilder& b) { +std::pair, SmallVector> +staticQubitsWithParametricOps(QCOProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); q0 = b.rx(std::numbers::pi / 4., q0); q1 = b.p(std::numbers::pi / 2., q1); + return measureAndReturn(b, {q0, q1}); } -void staticQubitsWithTwoTargetOps(QCOProgramBuilder& b) { +std::pair, SmallVector> +staticQubitsWithTwoTargetOps(QCOProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); std::tie(q0, q1) = b.rzz(0.123, q0, q1); + return measureAndReturn(b, {q0, q1}); } -void staticQubitsWithCtrl(QCOProgramBuilder& b) { +std::pair, SmallVector> +staticQubitsWithCtrl(QCOProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); std::tie(q0, q1) = b.cx(q0, q1); + return measureAndReturn(b, {q0, q1}); } -void staticQubitsWithInv(QCOProgramBuilder& b) { +std::pair, SmallVector> +staticQubitsWithInv(QCOProgramBuilder& b) { auto q0 = b.staticQubit(0); q0 = b.inv({q0}, [&](auto targets) -> SmallVector { return {b.t(targets[0])}; })[0]; + return measureAndReturn(b, {q0}); } -void allocSinkPair(QCOProgramBuilder& b) { +std::pair, SmallVector> +allocSinkPair(QCOProgramBuilder& b) { auto q = b.allocQubit(); - b.sink(q); + auto [q1, c] = b.measure(q); + b.sink(q1); + return {{c}, {b.getI1Type()}}; } -void mixedStaticThenDynamicQubit(QCOProgramBuilder& b) { - b.staticQubit(0); - b.allocQubit(); +std::pair, SmallVector> +mixedStaticThenDynamicQubit(QCOProgramBuilder& b) { + auto q0 = b.staticQubit(0); + auto q1 = b.allocQubit(); + return measureAndReturn(b, {q0, q1}); } -void mixedDynamicRegisterThenStaticQubit(QCOProgramBuilder& b) { +std::pair, SmallVector> +mixedDynamicRegisterThenStaticQubit(QCOProgramBuilder& b) { b.qtensorAlloc(2); - b.staticQubit(0); + auto q1 = b.staticQubit(0); + return measureAndReturn(b, {q1}); } -void singleMeasurementToSingleBit(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleMeasurementToSingleBit(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto& c = b.allocClassicalBitRegister(1); - q[0] = b.measure(q[0], c[0]); + const auto [q1, bit] = b.measure(q[0], c[0]); + return {{bit}, {b.getI1Type()}}; } -void repeatedMeasurementToSameBit(QCOProgramBuilder& b) { +std::pair, SmallVector> +repeatedMeasurementToSameBit(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto& c = b.allocClassicalBitRegister(1); - q[0] = b.measure(q[0], c[0]); - q[0] = b.measure(q[0], c[0]); - q[0] = b.measure(q[0], c[0]); + auto [q1, c1] = b.measure(q[0], c[0]); + auto [q2, c2] = b.measure(q1, c[0]); + auto [q3, c3] = b.measure(q2, c[0]); + return {{c1, c2, c3}, {b.getI1Type(), b.getI1Type(), b.getI1Type()}}; } -void repeatedMeasurementToDifferentBits(QCOProgramBuilder& b) { +std::pair, SmallVector> +repeatedMeasurementToDifferentBits(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto& c = b.allocClassicalBitRegister(3); - q[0] = b.measure(q[0], c[0]); - q[0] = b.measure(q[0], c[1]); - q[0] = b.measure(q[0], c[2]); + auto [q1, c1] = b.measure(q[0], c[0]); + auto [q2, c2] = b.measure(q1, c[1]); + auto [q3, c3] = b.measure(q2, c[2]); + return {{c1, c2, c3}, {b.getI1Type(), b.getI1Type(), b.getI1Type()}}; } -void multipleClassicalRegistersAndMeasurements(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleClassicalRegistersAndMeasurements(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); const auto& c0 = b.allocClassicalBitRegister(1, "c0"); const auto& c1 = b.allocClassicalBitRegister(2, "c1"); - b.measure(q[0], c0[0]); - b.measure(q[1], c1[0]); - b.measure(q[2], c1[1]); + auto [q1, bit1] = b.measure(q[0], c0[0]); + auto [q2, bit2] = b.measure(q1, c1[0]); + auto [q3, bit3] = b.measure(q2, c1[1]); + return {{bit1, bit2, bit3}, {b.getI1Type(), b.getI1Type(), b.getI1Type()}}; } -void measurementWithoutRegisters(QCOProgramBuilder& b) { +std::pair, SmallVector> +measurementWithoutRegisters(QCOProgramBuilder& b) { auto q = b.allocQubit(); - b.measure(q); + auto [q1, c] = b.measure(q); + return {{c}, {b.getI1Type()}}; } -void resetQubitWithoutOp(QCOProgramBuilder& b) { +std::pair, SmallVector> +resetQubitWithoutOp(QCOProgramBuilder& b) { auto q = b.allocQubit(); q = b.reset(q); + return measureAndReturn(b, {q}); } -void resetMultipleQubitsWithoutOp(QCOProgramBuilder& b) { +std::pair, SmallVector> +resetMultipleQubitsWithoutOp(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); q[0] = b.reset(q[0]); q[1] = b.reset(q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void repeatedResetWithoutOp(QCOProgramBuilder& b) { +std::pair, SmallVector> +repeatedResetWithoutOp(QCOProgramBuilder& b) { auto q = b.allocQubit(); q = b.reset(q); q = b.reset(q); q = b.reset(q); + return measureAndReturn(b, {q}); } -void resetQubitAfterSingleOp(QCOProgramBuilder& b) { +std::pair, SmallVector> +resetQubitAfterSingleOp(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.h(q[0]); q[0] = b.reset(q[0]); + return measureAndReturn(b, {q[0]}); } -void resetMultipleQubitsAfterSingleOp(QCOProgramBuilder& b) { +std::pair, SmallVector> +resetMultipleQubitsAfterSingleOp(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); q[0] = b.h(q[0]); q[0] = b.reset(q[0]); q[1] = b.h(q[1]); q[1] = b.reset(q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void repeatedResetAfterSingleOp(QCOProgramBuilder& b) { +std::pair, SmallVector> +repeatedResetAfterSingleOp(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.h(q[0]); q[0] = b.reset(q[0]); q[0] = b.reset(q[0]); q[0] = b.reset(q[0]); + return measureAndReturn(b, {q[0]}); } -void globalPhase(QCOProgramBuilder& b) { b.gphase(0.123); } +std::pair, SmallVector> +globalPhase(QCOProgramBuilder& b) { + b.gphase(0.123); + return measureAndReturn(b, {}); +} -void singleControlledGlobalPhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledGlobalPhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.cgphase(0.123, q[0]); + q[0] = b.cgphase(0.123, q[0]); + return measureAndReturn(b, {q[0]}); } -void multipleControlledGlobalPhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledGlobalPhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcgphase(0.123, {q[0], q[1], q[2]}); + auto qs = b.mcgphase(0.123, {q[0], q[1], q[2]}); + return measureAndReturn(b, {qs[0], qs[1], qs[2]}); } -void inverseGlobalPhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseGlobalPhase(QCOProgramBuilder& b) { b.inv({}, [&](ValueRange /*qubits*/) { b.gphase(-0.123); return SmallVector{}; }); + return measureAndReturn(b, {}); } -void inverseMultipleControlledGlobalPhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledGlobalPhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto qs = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { SmallVector controls{qubits[0], qubits[1], qubits[2]}; auto controlsOut = b.mcgphase(-0.123, controls); return SmallVector(controlsOut.begin(), controlsOut.end()); }); + return measureAndReturn(b, {qs[0], qs[1], qs[2]}); } -void identity(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - b.id(q[0]); +std::pair, SmallVector> +identity(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + q = b.id(q); + return measureAndReturn(b, {q}); } -void singleControlledIdentity(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledIdentity(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cid(q[1], q[0]); + std::tie(q[1], q[0]) = b.cid(q[1], q[0]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledIdentity(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledIdentity(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcid({q[2], q[1]}, q[0]); + auto res = b.mcid({q[2], q[1]}, q[0]); + q[2] = res.first[0]; + q[1] = res.first[1]; + q[0] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledIdentity(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledIdentity(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.id(innerTargets[0])}; @@ -216,47 +336,71 @@ void nestedControlledIdentity(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledIdentity(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - b.mcid({}, q[0]); +std::pair, SmallVector> +trivialControlledIdentity(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + auto res = b.mcid({}, q); + q = res.second; + return measureAndReturn(b, {q}); } -void inverseIdentity(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - b.inv({q[0]}, - [&](ValueRange qubits) { return SmallVector{b.id(qubits[0])}; }); +std::pair, SmallVector> +inverseIdentity(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + auto res = b.inv( + {q}, [&](ValueRange qubits) { return SmallVector{b.id(qubits[0])}; }); + q = res[0]; + return measureAndReturn(b, {q}); } -void inverseMultipleControlledIdentity(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledIdentity(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcid({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void x(QCOProgramBuilder& b) { +std::pair, SmallVector> x(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.x(q[0]); + q[0] = b.x(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledX(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cx(q[0], q[1]); + std::tie(q[0], q[1]) = b.cx(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledX(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcx({q[0], q[1]}, q[2]); + auto res = b.mcx({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledX(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledX(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.x(innerTargets[0])}; @@ -264,61 +408,94 @@ void nestedControlledX(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledX(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcx({}, q[0]); + auto res = b.mcx({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void repeatedControlledX(QCOProgramBuilder& b) { +std::pair, SmallVector> +repeatedControlledX(QCOProgramBuilder& b) { auto q0 = b.allocQubit(); auto control = b.h(q0); + std::vector targets; for (auto i = 0; i < 50; i++) { auto qubit = b.allocQubit(); - control = b.cx(control, qubit).first; + auto res = b.cx(control, qubit); + control = res.first; + targets.push_back(res.second); } + targets.push_back(control); + return measureAndReturn(b, + SmallVector(targets.begin(), targets.end())); } -void inverseX(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.x(qubits[0])}; }); + auto res = b.inv( + {q[0]}, [&](ValueRange qubits) { return SmallVector{b.x(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledX(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcx({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void twoX(QCOProgramBuilder& b) { +std::pair, SmallVector> twoX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.x(q[0]); q[0] = b.x(q[0]); + return measureAndReturn(b, {q[0]}); } -void y(QCOProgramBuilder& b) { +std::pair, SmallVector> y(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.y(q[0]); + q[0] = b.y(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledY(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cy(q[0], q[1]); + std::tie(q[0], q[1]) = b.cy(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledY(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcy({q[0], q[1]}, q[2]); + auto res = b.mcy({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledY(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledY(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.y(innerTargets[0])}; @@ -326,52 +503,78 @@ void nestedControlledY(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledY(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcy({}, q[0]); + auto res = b.mcy({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseY(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.y(qubits[0])}; }); + auto res = b.inv( + {q[0]}, [&](ValueRange qubits) { return SmallVector{b.y(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledY(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcy({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void twoY(QCOProgramBuilder& b) { +std::pair, SmallVector> twoY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.y(q[0]); q[0] = b.y(q[0]); + return measureAndReturn(b, {q[0]}); } -void z(QCOProgramBuilder& b) { +std::pair, SmallVector> z(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.z(q[0]); + q[0] = b.z(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledZ(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledZ(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cz(q[0], q[1]); + std::tie(q[0], q[1]) = b.cz(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledZ(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledZ(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcz({q[0], q[1]}, q[2]); + auto res = b.mcz({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledZ(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledZ(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.z(innerTargets[0])}; @@ -379,52 +582,78 @@ void nestedControlledZ(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledZ(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledZ(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcz({}, q[0]); + auto res = b.mcz({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseZ(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseZ(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.z(qubits[0])}; }); + auto res = b.inv( + {q[0]}, [&](ValueRange qubits) { return SmallVector{b.z(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledZ(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledZ(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcz({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void twoZ(QCOProgramBuilder& b) { +std::pair, SmallVector> twoZ(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.z(q[0]); q[0] = b.z(q[0]); + return measureAndReturn(b, {q[0]}); } -void h(QCOProgramBuilder& b) { +std::pair, SmallVector> h(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.h(q[0]); + q[0] = b.h(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledH(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledH(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ch(q[0], q[1]); + std::tie(q[0], q[1]) = b.ch(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledH(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledH(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mch({q[0], q[1]}, q[2]); + auto res = b.mch({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledH(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledH(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.h(innerTargets[0])}; @@ -432,57 +661,87 @@ void nestedControlledH(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledH(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledH(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mch({}, q[0]); + auto res = b.mch({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseH(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseH(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.h(qubits[0])}; }); + auto res = b.inv( + {q[0]}, [&](ValueRange qubits) { return SmallVector{b.h(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledH(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledH(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mch({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void twoH(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - q[0] = b.h(q[0]); - q[0] = b.h(q[0]); +std::pair, SmallVector> twoH(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + q = b.h(q); + q = b.h(q); + return measureAndReturn(b, {q}); } -void hWithoutRegister(QCOProgramBuilder& b) { +std::pair, SmallVector> +hWithoutRegister(QCOProgramBuilder& b) { auto q = b.allocQubit(); - b.h(q); + q = b.h(q); + return measureAndReturn(b, {q}); } -void s(QCOProgramBuilder& b) { +std::pair, SmallVector> s(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.s(q[0]); + q[0] = b.s(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledS(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cs(q[0], q[1]); + auto res = b.cs(q[0], q[1]); + q[0] = res.first; + q[1] = res.second; + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledS(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcs({q[0], q[1]}, q[2]); + auto res = b.mcs({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledS(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledS(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.s(innerTargets[0])}; @@ -490,58 +749,88 @@ void nestedControlledS(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledS(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcs({}, q[0]); + auto res = b.mcs({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseS(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.s(qubits[0])}; }); + auto res = b.inv( + {q[0]}, [&](ValueRange qubits) { return SmallVector{b.s(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledS(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcs({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void sThenSdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +sThenSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.s(q[0]); q[0] = b.sdg(q[0]); + return measureAndReturn(b, {q[0]}); } -void twoS(QCOProgramBuilder& b) { +std::pair, SmallVector> twoS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.s(q[0]); q[0] = b.s(q[0]); + return measureAndReturn(b, {q[0]}); } -void sdg(QCOProgramBuilder& b) { +std::pair, SmallVector> sdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.sdg(q[0]); + q[0] = b.sdg(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledSdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.csdg(q[0], q[1]); + auto res = b.csdg(q[0], q[1]); + q[0] = res.first; + q[1] = res.second; + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledSdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcsdg({q[0], q[1]}, q[2]); + auto res = b.mcsdg({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledSdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledSdg(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.sdg(innerTargets[0])}; @@ -549,59 +838,88 @@ void nestedControlledSdg(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledSdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcsdg({}, q[0]); + auto res = b.mcsdg({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseSdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, - [&](ValueRange qubits) { return SmallVector{b.sdg(qubits[0])}; }); + auto res = b.inv( + {q[0]}, [&](ValueRange qubits) { return SmallVector{b.sdg(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledSdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcsdg({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void sdgThenS(QCOProgramBuilder& b) { +std::pair, SmallVector> +sdgThenS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sdg(q[0]); q[0] = b.s(q[0]); + return measureAndReturn(b, {q[0]}); } -void twoSdg(QCOProgramBuilder& b) { +std::pair, SmallVector> twoSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sdg(q[0]); q[0] = b.sdg(q[0]); + return measureAndReturn(b, {q[0]}); } -void t_(QCOProgramBuilder& b) { +std::pair, SmallVector> t_(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.t(q[0]); + q[0] = b.t(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledT(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ct(q[0], q[1]); + auto res = b.ct(q[0], q[1]); + q[0] = res.first; + q[1] = res.second; + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledT(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mct({q[0], q[1]}, q[2]); + auto res = b.mct({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledT(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledT(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.t(innerTargets[0])}; @@ -609,58 +927,88 @@ void nestedControlledT(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledT(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mct({}, q[0]); + auto res = b.mct({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseT(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.t(qubits[0])}; }); + auto res = b.inv( + {q[0]}, [&](ValueRange qubits) { return SmallVector{b.t(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledT(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mct({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void tThenTdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +tThenTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.t(q[0]); q[0] = b.tdg(q[0]); + return measureAndReturn(b, {q[0]}); } -void twoT(QCOProgramBuilder& b) { +std::pair, SmallVector> twoT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.t(q[0]); q[0] = b.t(q[0]); + return measureAndReturn(b, {q[0]}); } -void tdg(QCOProgramBuilder& b) { +std::pair, SmallVector> tdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.tdg(q[0]); + q[0] = b.tdg(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledTdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ctdg(q[0], q[1]); + auto res = b.ctdg(q[0], q[1]); + q[0] = res.first; + q[1] = res.second; + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledTdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mctdg({q[0], q[1]}, q[2]); + auto res = b.mctdg({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledTdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledTdg(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.tdg(innerTargets[0])}; @@ -668,59 +1016,88 @@ void nestedControlledTdg(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledTdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mctdg({}, q[0]); + auto res = b.mctdg({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseTdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, - [&](ValueRange qubits) { return SmallVector{b.tdg(qubits[0])}; }); + auto res = b.inv( + {q[0]}, [&](ValueRange qubits) { return SmallVector{b.tdg(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledTdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mctdg({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void tdgThenT(QCOProgramBuilder& b) { +std::pair, SmallVector> +tdgThenT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.tdg(q[0]); q[0] = b.t(q[0]); + return measureAndReturn(b, {q[0]}); } -void twoTdg(QCOProgramBuilder& b) { +std::pair, SmallVector> twoTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.tdg(q[0]); q[0] = b.tdg(q[0]); + return measureAndReturn(b, {q[0]}); } -void sx(QCOProgramBuilder& b) { +std::pair, SmallVector> sx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.sx(q[0]); + q[0] = b.sx(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledSx(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.csx(q[0], q[1]); + auto res = b.csx(q[0], q[1]); + q[0] = res.first; + q[1] = res.second; + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledSx(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcsx({q[0], q[1]}, q[2]); + auto res = b.mcsx({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledSx(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledSx(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.sx(innerTargets[0])}; @@ -728,59 +1105,88 @@ void nestedControlledSx(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledSx(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcsx({}, q[0]); + auto res = b.mcsx({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseSx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, - [&](ValueRange qubits) { return SmallVector{b.sx(qubits[0])}; }); + auto res = b.inv( + {q[0]}, [&](ValueRange qubits) { return SmallVector{b.sx(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledSx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcsx({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void sxThenSxdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +sxThenSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sx(q[0]); q[0] = b.sxdg(q[0]); + return measureAndReturn(b, {q[0]}); } -void twoSx(QCOProgramBuilder& b) { +std::pair, SmallVector> twoSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sx(q[0]); q[0] = b.sx(q[0]); + return measureAndReturn(b, {q[0]}); } -void sxdg(QCOProgramBuilder& b) { +std::pair, SmallVector> sxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.sxdg(q[0]); + q[0] = b.sxdg(q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledSxdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.csxdg(q[0], q[1]); + auto res = b.csxdg(q[0], q[1]); + q[0] = res.first; + q[1] = res.second; + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledSxdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcsxdg({q[0], q[1]}, q[2]); + auto res = b.mcsxdg({q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledSxdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledSxdg(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.sxdg(innerTargets[0])}; @@ -788,59 +1194,89 @@ void nestedControlledSxdg(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledSxdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcsxdg({}, q[0]); + auto res = b.mcsxdg({}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseSxdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, - [&](ValueRange qubits) { return SmallVector{b.sxdg(qubits[0])}; }); + auto res = b.inv({q[0]}, [&](ValueRange qubits) { + return SmallVector{b.sxdg(qubits[0])}; + }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledSxdg(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcsxdg({qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void sxdgThenSx(QCOProgramBuilder& b) { +std::pair, SmallVector> +sxdgThenSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sxdg(q[0]); q[0] = b.sx(q[0]); + return measureAndReturn(b, {q[0]}); } -void twoSxdg(QCOProgramBuilder& b) { +std::pair, SmallVector> twoSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sxdg(q[0]); q[0] = b.sxdg(q[0]); + return measureAndReturn(b, {q[0]}); } -void rx(QCOProgramBuilder& b) { +std::pair, SmallVector> rx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.rx(0.123, q[0]); + q[0] = b.rx(0.123, q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledRx(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.crx(0.123, q[0], q[1]); + auto res = b.crx(0.123, q[0], q[1]); + q[0] = res.first; + q[1] = res.second; + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledRx(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcrx(0.123, {q[0], q[1]}, q[2]); + auto res = b.mcrx(0.123, {q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledRx(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledRx(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.rx(0.123, innerTargets[0])}; @@ -848,59 +1284,87 @@ void nestedControlledRx(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledRx(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcrx(0.123, {}, q[0]); + auto res = b.mcrx(0.123, {}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseRx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { + auto res = b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.rx(-0.123, qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledRx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcrx(-0.123, {qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void twoRxOppositePhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRxOppositePhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.rx(0.123, q[0]); q[0] = b.rx(-0.123, q[0]); + return measureAndReturn(b, {q[0]}); } -void rxPiOver2(QCOProgramBuilder& b) { +std::pair, SmallVector> +rxPiOver2(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.rx(std::numbers::pi / 2, q[0]); + q[0] = b.rx(std::numbers::pi / 2, q[0]); + return measureAndReturn(b, {q[0]}); } -void ry(QCOProgramBuilder& b) { +std::pair, SmallVector> ry(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.ry(0.456, q[0]); + q[0] = b.ry(0.456, q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledRy(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cry(0.456, q[0], q[1]); + std::tie(q[0], q[1]) = b.cry(0.456, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledRy(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcry(0.456, {q[0], q[1]}, q[2]); + auto res = b.mcry(0.456, {q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledRy(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledRy(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.ry(0.456, innerTargets[0])}; @@ -908,58 +1372,87 @@ void nestedControlledRy(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledRy(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcry(0.456, {}, q[0]); + auto res = b.mcry(0.456, {}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseRy(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { + auto res = b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.ry(-0.456, qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledRy(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcry(-0.456, {qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void twoRyOppositePhase(QCOProgramBuilder& b) { + +std::pair, SmallVector> +twoRyOppositePhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.ry(0.456, q[0]); q[0] = b.ry(-0.456, q[0]); + return measureAndReturn(b, {q[0]}); } -void ryPiOver2(QCOProgramBuilder& b) { +std::pair, SmallVector> +ryPiOver2(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.ry(std::numbers::pi / 2, q[0]); + q[0] = b.ry(std::numbers::pi / 2, q[0]); + return measureAndReturn(b, {q[0]}); } -void rz(QCOProgramBuilder& b) { +std::pair, SmallVector> rz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.rz(0.789, q[0]); + q[0] = b.rz(0.789, q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledRz(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledRz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.crz(0.789, q[0], q[1]); + std::tie(q[0], q[1]) = b.crz(0.789, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledRz(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledRz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcrz(0.789, {q[0], q[1]}, q[2]); + auto res = b.mcrz(0.789, {q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledRz(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledRz(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.rz(0.789, innerTargets[0])}; @@ -967,54 +1460,80 @@ void nestedControlledRz(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledRz(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledRz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcrz(0.789, {}, q[0]); + auto res = b.mcrz(0.789, {}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseRz(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseRz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { + auto res = b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.rz(-0.789, qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledRz(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledRz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcrz(-0.789, {qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void twoRzOppositePhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRzOppositePhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.rz(0.789, q[0]); q[0] = b.rz(-0.789, q[0]); + return measureAndReturn(b, {q[0]}); } -void p(QCOProgramBuilder& b) { +std::pair, SmallVector> p(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.p(0.123, q[0]); + q[0] = b.p(0.123, q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledP(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledP(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cp(0.123, q[0], q[1]); + std::tie(q[0], q[1]) = b.cp(0.123, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledP(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledP(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcp(0.123, {q[0], q[1]}, q[2]); + auto res = b.mcp(0.123, {q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledP(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledP(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.p(0.123, innerTargets[0])}; @@ -1022,53 +1541,80 @@ void nestedControlledP(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledP(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledP(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcp(0.123, {}, q[0]); + auto res = b.mcp(0.123, {}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseP(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseP(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, - [&](ValueRange qubits) { return SmallVector{b.p(-0.123, qubits[0])}; }); + auto res = b.inv({q[0]}, [&](ValueRange qubits) { + return SmallVector{b.p(-0.123, qubits[0])}; + }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledP(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledP(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcp(-0.123, {qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void twoPOppositePhase(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - q[0] = b.p(0.123, q[0]); - q[0] = b.p(-0.123, q[0]); +std::pair, SmallVector> +twoPOppositePhase(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + q = b.p(0.123, q); + q = b.p(-0.123, q); + return measureAndReturn(b, {q}); } -void r(QCOProgramBuilder& b) { +std::pair, SmallVector> r(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.r(0.123, 0.456, q[0]); + q[0] = b.r(0.123, 0.456, q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledR(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledR(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cr(0.123, 0.456, q[0], q[1]); + std::tie(q[0], q[1]) = b.cr(0.123, 0.456, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledR(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledR(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcr(0.123, 0.456, {q[0], q[1]}, q[2]); + auto res = b.mcr(0.123, 0.456, {q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledR(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledR(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.r(0.123, 0.456, innerTargets[0])}; @@ -1076,58 +1622,86 @@ void nestedControlledR(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledR(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledR(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcr(0.123, 0.456, {}, q[0]); + auto res = b.mcr(0.123, 0.456, {}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseR(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseR(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { + auto res = b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.r(-0.123, 0.456, qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledR(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledR(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcr(-0.123, 0.456, {qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void canonicalizeRToRx(QCOProgramBuilder& b) { +std::pair, SmallVector> +canonicalizeRToRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.r(0.123, 0., q[0]); + return measureAndReturn(b, {q[0]}); } -void canonicalizeRToRy(QCOProgramBuilder& b) { +std::pair, SmallVector> +canonicalizeRToRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.r(0.456, std::numbers::pi / 2, q[0]); + return measureAndReturn(b, {q[0]}); } -void u2(QCOProgramBuilder& b) { +std::pair, SmallVector> u2(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u2(0.234, 0.567, q[0]); + q[0] = b.u2(0.234, 0.567, q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledU2(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledU2(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cu2(0.234, 0.567, q[0], q[1]); + std::tie(q[0], q[1]) = b.cu2(0.234, 0.567, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledU2(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledU2(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcu2(0.234, 0.567, {q[0], q[1]}, q[2]); + auto res = b.mcu2(0.234, 0.567, {q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledU2(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledU2(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.u2(0.234, 0.567, innerTargets[0])}; @@ -1135,63 +1709,95 @@ void nestedControlledU2(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledU2(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledU2(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcu2(0.234, 0.567, {}, q[0]); + auto res = b.mcu2(0.234, 0.567, {}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseU2(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseU2(QCOProgramBuilder& b) { constexpr double pi = std::numbers::pi; auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { + auto res = b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.u2(-0.567 + pi, -0.234 - pi, qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledU2(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledU2(QCOProgramBuilder& b) { constexpr double pi = std::numbers::pi; auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcu2(-0.567 + pi, -0.234 - pi, {qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void canonicalizeU2ToH(QCOProgramBuilder& b) { + +std::pair, SmallVector> +canonicalizeU2ToH(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u2(0., std::numbers::pi, q[0]); + q[0] = b.u2(0., std::numbers::pi, q[0]); + return measureAndReturn(b, {q[0]}); } -void canonicalizeU2ToRx(QCOProgramBuilder& b) { +std::pair, SmallVector> +canonicalizeU2ToRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u2(-std::numbers::pi / 2, std::numbers::pi / 2, q[0]); + q[0] = b.u2(-std::numbers::pi / 2, std::numbers::pi / 2, q[0]); + return measureAndReturn(b, {q[0]}); } -void canonicalizeU2ToRy(QCOProgramBuilder& b) { + +std::pair, SmallVector> +canonicalizeU2ToRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u2(0., 0., q[0]); + q[0] = b.u2(0., 0., q[0]); + return measureAndReturn(b, {q[0]}); } -void u(QCOProgramBuilder& b) { +std::pair, SmallVector> u(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u(0.1, 0.2, 0.3, q[0]); + q[0] = b.u(0.1, 0.2, 0.3, q[0]); + return measureAndReturn(b, {q[0]}); } -void singleControlledU(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledU(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cu(0.1, 0.2, 0.3, q[0], q[1]); + std::tie(q[0], q[1]) = b.cu(0.1, 0.2, 0.3, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void multipleControlledU(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledU(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcu(0.1, 0.2, 0.3, {q[0], q[1]}, q[2]); + auto res = b.mcu(0.1, 0.2, 0.3, {q[0], q[1]}, q[2]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void nestedControlledU(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledU(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); - b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { + auto res = b.ctrl({reg[0]}, {reg[1], reg[2]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl({targets[0]}, {targets[1]}, [&](ValueRange innerTargets) { return SmallVector{b.u(0.1, 0.2, 0.3, innerTargets[0])}; @@ -1199,746 +1805,1184 @@ void nestedControlledU(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, {reg[0], reg[1], reg[2]}); } -void trivialControlledU(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledU(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcu(0.1, 0.2, 0.3, {}, q[0]); + auto res = b.mcu(0.1, 0.2, 0.3, {}, q[0]); + q[0] = res.second; + return measureAndReturn(b, {q[0]}); } -void inverseU(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseU(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { + auto res = b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.u(-0.1, -0.3, -0.2, qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void inverseMultipleControlledU(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledU(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetOut] = b.mcu(-0.1, -0.3, -0.2, {qubits[0], qubits[1]}, qubits[2]); return llvm::to_vector( llvm::concat(controlsOut, ValueRange{targetOut})); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void canonicalizeUToP(QCOProgramBuilder& b) { +std::pair, SmallVector> +canonicalizeUToP(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u(0., 0., 0.123, q[0]); + q[0] = b.u(0., 0., 0.123, q[0]); + return measureAndReturn(b, {q[0]}); } -void canonicalizeUToRx(QCOProgramBuilder& b) { +std::pair, SmallVector> +canonicalizeUToRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u(0.123, -std::numbers::pi / 2, std::numbers::pi / 2, q[0]); + q[0] = b.u(0.123, -std::numbers::pi / 2, std::numbers::pi / 2, q[0]); + return measureAndReturn(b, {q[0]}); } -void canonicalizeUToRy(QCOProgramBuilder& b) { +std::pair, SmallVector> +canonicalizeUToRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u(0.456, 0., 0., q[0]); + q[0] = b.u(0.456, 0., 0., q[0]); + return measureAndReturn(b, {q[0]}); } -void canonicalizeUToU2(QCOProgramBuilder& b) { +std::pair, SmallVector> +canonicalizeUToU2(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u(std::numbers::pi / 2, 0.234, 0.567, q[0]); + q[0] = b.u(std::numbers::pi / 2, 0.234, 0.567, q[0]); + return measureAndReturn(b, {q[0]}); } -void swap(QCOProgramBuilder& b) { +std::pair, SmallVector> swap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.swap(q[0], q[1]); + std::tie(q[0], q[1]) = b.swap(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledSwap(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledSwap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cswap(q[0], q[1], q[2]); + auto res = b.cswap(q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledSwap(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledSwap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcswap({q[0], q[1]}, q[2], q[3]); + auto res = b.mcswap({q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledSwap(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledSwap(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = b.swap(innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.swap(innerTargets[0], innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledSwap(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledSwap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcswap({}, q[0], q[1]); + auto res = b.mcswap({}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseSwap(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseSwap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto res = b.swap(qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledSwap(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledSwap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mcswap({qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + q[3] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void twoSwap(QCOProgramBuilder& b) { +std::pair, SmallVector> twoSwap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.swap(q[0], q[1]); std::tie(q[0], q[1]) = b.swap(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoSwapSwappedTargets(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoSwapSwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.swap(q[0], q[1]); std::tie(q[1], q[0]) = b.swap(q[1], q[0]); + return measureAndReturn(b, {q[0], q[1]}); } -void iswap(QCOProgramBuilder& b) { +std::pair, SmallVector> iswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.iswap(q[0], q[1]); + std::tie(q[0], q[1]) = b.iswap(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledIswap(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledIswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.ciswap(q[0], q[1], q[2]); + auto res = b.ciswap(q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledIswap(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledIswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mciswap({q[0], q[1]}, q[2], q[3]); + auto res = b.mciswap({q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledIswap(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledIswap(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = b.iswap(innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.iswap(innerTargets[0], innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledIswap(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledIswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mciswap({}, q[0], q[1]); + auto res = b.mciswap({}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseIswap(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseIswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto res = b.iswap(qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledIswap(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledIswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mciswap({qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + q[3] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void dcx(QCOProgramBuilder& b) { +std::pair, SmallVector> dcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.dcx(q[0], q[1]); + std::tie(q[0], q[1]) = b.dcx(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledDcx(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cdcx(q[0], q[1], q[2]); + auto res = b.cdcx(q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledDcx(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcdcx({q[0], q[1]}, q[2], q[3]); + auto res = b.mcdcx({q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledDcx(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledDcx(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = b.dcx(innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.dcx(innerTargets[0], innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledDcx(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcdcx({}, q[0], q[1]); + auto res = b.mcdcx({}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseDcx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[1], q[0]}, [&](ValueRange qubits) { + auto res = b.inv({q[1], q[0]}, [&](ValueRange qubits) { auto res = b.dcx(qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[1] = res[0]; + q[0] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledDcx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[3], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[3], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mcdcx({qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[3] = res[2]; + q[2] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void twoDcx(QCOProgramBuilder& b) { +std::pair, SmallVector> twoDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.dcx(q[0], q[1]); std::tie(q[0], q[1]) = b.dcx(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoDcxSwappedTargets(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoDcxSwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.dcx(q[0], q[1]); std::tie(q[1], q[0]) = b.dcx(q[1], q[0]); + return measureAndReturn(b, {q[0], q[1]}); } -void ecr(QCOProgramBuilder& b) { +std::pair, SmallVector> ecr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ecr(q[0], q[1]); + std::tie(q[0], q[1]) = b.ecr(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledEcr(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cecr(q[0], q[1], q[2]); + auto res = b.cecr(q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledEcr(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcecr({q[0], q[1]}, q[2], q[3]); + auto res = b.mcecr({q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledEcr(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledEcr(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = b.ecr(innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.ecr(innerTargets[0], innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledEcr(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcecr({}, q[0], q[1]); + auto res = b.mcecr({}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseEcr(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto res = b.ecr(qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledEcr(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mcecr({qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + q[3] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void twoEcr(QCOProgramBuilder& b) { +std::pair, SmallVector> twoEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.ecr(q[0], q[1]); std::tie(q[0], q[1]) = b.ecr(q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void rxx(QCOProgramBuilder& b) { +std::pair, SmallVector> rxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.rxx(0.123, q[0], q[1]); + std::tie(q[0], q[1]) = b.rxx(0.123, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledRxx(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.crxx(0.123, q[0], q[1], q[2]); + auto res = b.crxx(0.123, q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledRxx(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcrxx(0.123, {q[0], q[1]}, q[2], q[3]); + auto res = b.mcrxx(0.123, {q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledRxx(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledRxx(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = b.rxx(0.123, innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.rxx(0.123, innerTargets[0], innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledRxx(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcrxx(0.123, {}, q[0], q[1]); + auto res = b.mcrxx(0.123, {}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseRxx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto res = b.rxx(-0.123, qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledRxx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mcrxx(-0.123, {qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + q[3] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void tripleControlledRxx(QCOProgramBuilder& b) { +std::pair, SmallVector> +tripleControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(5); - b.mcrxx(0.123, {q[0], q[1], q[2]}, q[3], q[4]); + auto res = b.mcrxx(0.123, {q[0], q[1], q[2]}, q[3], q[4]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.first[2]; + q[3] = res.second.first; + q[4] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3], q[4]}); } -void fourControlledRxx(QCOProgramBuilder& b) { +std::pair, SmallVector> +fourControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(6); - b.mcrxx(0.123, {q[0], q[1], q[2], q[3]}, q[4], q[5]); + auto res = b.mcrxx(0.123, {q[0], q[1], q[2], q[3]}, q[4], q[5]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.first[2]; + q[3] = res.first[3]; + q[4] = res.second.first; + q[5] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3], q[4], q[5]}); } -void twoRxx(QCOProgramBuilder& b) { +std::pair, SmallVector> twoRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); // 0.045 + 0.078 = 0.123 std::tie(q[0], q[1]) = b.rxx(0.045, q[0], q[1]); std::tie(q[0], q[1]) = b.rxx(0.078, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoRxxSwappedTargets(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRxxSwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); // 0.045 + 0.078 = 0.123 std::tie(q[0], q[1]) = b.rxx(0.045, q[0], q[1]); std::tie(q[1], q[0]) = b.rxx(0.078, q[1], q[0]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoRxxOppositePhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRxxOppositePhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.rxx(0.123, q[0], q[1]); std::tie(q[0], q[1]) = b.rxx(-0.123, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoRxxOppositePhaseSwappedTargets(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRxxOppositePhaseSwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.rxx(0.123, q[0], q[1]); std::tie(q[1], q[0]) = b.rxx(-0.123, q[1], q[0]); + return measureAndReturn(b, {q[0], q[1]}); } -void ryy(QCOProgramBuilder& b) { +std::pair, SmallVector> ryy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ryy(0.123, q[0], q[1]); + std::tie(q[0], q[1]) = b.ryy(0.123, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledRyy(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cryy(0.123, q[0], q[1], q[2]); + auto res = b.cryy(0.123, q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledRyy(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcryy(0.123, {q[0], q[1]}, q[2], q[3]); + auto res = b.mcryy(0.123, {q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledRyy(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledRyy(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = b.ryy(0.123, innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.ryy(0.123, innerTargets[0], innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledRyy(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcryy(0.123, {}, q[0], q[1]); + auto res = b.mcryy(0.123, {}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseRyy(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto res = b.ryy(-0.123, qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledRyy(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mcryy(-0.123, {qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + q[3] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void twoRyy(QCOProgramBuilder& b) { +std::pair, SmallVector> twoRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); // 0.045 + 0.078 = 0.123 std::tie(q[0], q[1]) = b.ryy(0.045, q[0], q[1]); std::tie(q[0], q[1]) = b.ryy(0.078, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoRyyOppositePhaseSwappedTargets(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRyyOppositePhaseSwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.ryy(0.123, q[0], q[1]); std::tie(q[1], q[0]) = b.ryy(-0.123, q[1], q[0]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoRyyOppositePhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRyyOppositePhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.ryy(0.123, q[0], q[1]); std::tie(q[0], q[1]) = b.ryy(-0.123, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoRyySwappedTargets(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRyySwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); // 0.045 + 0.078 = 0.123 std::tie(q[0], q[1]) = b.ryy(0.045, q[0], q[1]); std::tie(q[1], q[0]) = b.ryy(0.078, q[1], q[0]); + return measureAndReturn(b, {q[0], q[1]}); } -void rzx(QCOProgramBuilder& b) { +std::pair, SmallVector> rzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.rzx(0.123, q[0], q[1]); + std::tie(q[0], q[1]) = b.rzx(0.123, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledRzx(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledRzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.crzx(0.123, q[0], q[1], q[2]); + auto res = b.crzx(0.123, q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledRzx(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledRzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcrzx(0.123, {q[0], q[1]}, q[2], q[3]); + auto res = b.mcrzx(0.123, {q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledRzx(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledRzx(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = b.rzx(0.123, innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.rzx(0.123, innerTargets[0], innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledRzx(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledRzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcrzx(0.123, {}, q[0], q[1]); + auto res = b.mcrzx(0.123, {}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseRzx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseRzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto res = b.rzx(-0.123, qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledRzx(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledRzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mcrzx(-0.123, {qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + q[3] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void twoRzxOppositePhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRzxOppositePhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.rzx(0.123, q[0], q[1]); std::tie(q[0], q[1]) = b.rzx(-0.123, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void rzz(QCOProgramBuilder& b) { +std::pair, SmallVector> rzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.rzz(0.123, q[0], q[1]); + std::tie(q[0], q[1]) = b.rzz(0.123, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledRzz(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.crzz(0.123, q[0], q[1], q[2]); + auto res = b.crzz(0.123, q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledRzz(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcrzz(0.123, {q[0], q[1]}, q[2], q[3]); + auto res = b.mcrzz(0.123, {q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledRzz(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledRzz(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = b.rzz(0.123, innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.rzz(0.123, innerTargets[0], innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledRzz(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcrzz(0.123, {}, q[0], q[1]); + auto res = b.mcrzz(0.123, {}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseRzz(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto res = b.rzz(-0.123, qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledRzz(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mcrzz(-0.123, {qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + q[3] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void twoRzz(QCOProgramBuilder& b) { +std::pair, SmallVector> twoRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); // 0.045 + 0.078 = 0.123 std::tie(q[0], q[1]) = b.rzz(0.045, q[0], q[1]); std::tie(q[0], q[1]) = b.rzz(0.078, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoRzzSwappedTargets(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRzzSwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); // 0.045 + 0.078 = 0.123 std::tie(q[0], q[1]) = b.rzz(0.045, q[0], q[1]); std::tie(q[1], q[0]) = b.rzz(0.078, q[1], q[0]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoRzzOppositePhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRzzOppositePhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.rzz(0.123, q[0], q[1]); std::tie(q[0], q[1]) = b.rzz(-0.123, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void twoRzzOppositePhaseSwappedTargets(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoRzzOppositePhaseSwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.rzz(0.123, q[0], q[1]); std::tie(q[1], q[0]) = b.rzz(-0.123, q[1], q[0]); + return measureAndReturn(b, {q[0], q[1]}); } -void xxPlusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +xxPlusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.xx_plus_yy(0.123, 0.456, q[0], q[1]); + std::tie(q[0], q[1]) = b.xx_plus_yy(0.123, 0.456, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledXxPlusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledXxPlusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cxx_plus_yy(0.123, 0.456, q[0], q[1], q[2]); + auto res = b.cxx_plus_yy(0.123, 0.456, q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledXxPlusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledXxPlusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcxx_plus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + auto res = b.mcxx_plus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledXxPlusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledXxPlusYY(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = - b.xx_plus_yy(0.123, 0.456, innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.xx_plus_yy(0.123, 0.456, innerTargets[0], + innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledXxPlusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledXxPlusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcxx_plus_yy(0.123, 0.456, {}, q[0], q[1]); + auto res = b.mcxx_plus_yy(0.123, 0.456, {}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseXxPlusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseXxPlusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto res = b.xx_plus_yy(-0.123, 0.456, qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledXxPlusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledXxPlusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mcxx_plus_yy( -0.123, 0.456, {qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + q[3] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void twoXxPlusYYOppositePhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoXxPlusYYOppositePhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.xx_plus_yy(0.123, 0.456, q[0], q[1]); std::tie(q[0], q[1]) = b.xx_plus_yy(-0.123, 0.456, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void xxMinusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +xxMinusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.xx_minus_yy(0.123, 0.456, q[0], q[1]); + std::tie(q[0], q[1]) = b.xx_minus_yy(0.123, 0.456, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void singleControlledXxMinusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledXxMinusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cxx_minus_yy(0.123, 0.456, q[0], q[1], q[2]); + auto res = b.cxx_minus_yy(0.123, 0.456, q[0], q[1], q[2]); + q[0] = res.first; + q[1] = res.second.first; + q[2] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void multipleControlledXxMinusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +multipleControlledXxMinusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcxx_minus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + auto res = b.mcxx_minus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second.first; + q[3] = res.second.second; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedControlledXxMinusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedControlledXxMinusYY(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); - b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( - {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { - auto res = - b.xx_minus_yy(0.123, 0.456, innerTargets[0], innerTargets[1]); - return SmallVector{res.first, res.second}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({reg[0]}, {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0]}, {targets[1], targets[2]}, + [&](ValueRange innerTargets) { + auto res = b.xx_minus_yy(0.123, 0.456, innerTargets[0], + innerTargets[1]); + return SmallVector{res.first, res.second}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + reg[3] = res.second[2]; + return measureAndReturn(b, {reg[0], reg[1], reg[2], reg[3]}); } -void trivialControlledXxMinusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialControlledXxMinusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcxx_minus_yy(0.123, 0.456, {}, q[0], q[1]); + auto res = b.mcxx_minus_yy(0.123, 0.456, {}, q[0], q[1]); + q[0] = res.second.first; + q[1] = res.second.second; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseXxMinusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseXxMinusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto res = b.xx_minus_yy(-0.123, 0.456, qubits[0], qubits[1]); return SmallVector{res.first, res.second}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void inverseMultipleControlledXxMinusYY(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseMultipleControlledXxMinusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.mcxx_minus_yy( -0.123, 0.456, {qubits[0], qubits[1]}, qubits[2], qubits[3]); SmallVector targets{targetsOut.first, targetsOut.second}; return llvm::to_vector(llvm::concat(controlsOut, targets)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + q[3] = res[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void twoXxMinusYYOppositePhase(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoXxMinusYYOppositePhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.xx_minus_yy(0.123, 0.456, q[0], q[1]); std::tie(q[0], q[1]) = b.xx_minus_yy(-0.123, 0.456, q[0], q[1]); + return measureAndReturn(b, {q[0], q[1]}); } -void barrier(QCOProgramBuilder& b) { +std::pair, SmallVector> barrier(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.barrier(q[0]); + auto q1 = b.barrier(q[0]); + return measureAndReturn(b, {q1}); } -void barrierTwoQubits(QCOProgramBuilder& b) { +std::pair, SmallVector> +barrierTwoQubits(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.barrier({q[0], q[1]}); + auto res = b.barrier({q[0], q[1]}); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void barrierMultipleQubits(QCOProgramBuilder& b) { +std::pair, SmallVector> +barrierMultipleQubits(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.barrier({q[0], q[1], q[2]}); + auto res = b.barrier({q[0], q[1], q[2]}); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void singleControlledBarrier(QCOProgramBuilder& b) { +std::pair, SmallVector> +singleControlledBarrier(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ctrl({q[1]}, {q[0]}, [&](ValueRange targets) { + auto res = b.ctrl({q[1]}, {q[0]}, [&](ValueRange targets) { return SmallVector{b.barrier(targets[0])}; }); + q[1] = res.first[0]; + q[0] = res.second[0]; + return measureAndReturn(b, {q[0]}); } -void inverseBarrier(QCOProgramBuilder& b) { +std::pair, SmallVector> +inverseBarrier(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv({q[0]}, [&](ValueRange qubits) { + auto res = b.inv({q[0]}, [&](ValueRange qubits) { return SmallVector{b.barrier(qubits[0])}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void twoBarrier(QCOProgramBuilder& b) { +std::pair, SmallVector> +twoBarrier(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); auto b1 = b.barrier({q[0], q[1]}); q[0] = b1[0]; q[1] = b1[1]; - b.barrier({q[0], q[1]}); + auto b2 = b.barrier({q[0], q[1]}); + q[0] = b2[0]; + q[1] = b2[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void trivialCtrl(QCOProgramBuilder& b) { +std::pair, SmallVector> +trivialCtrl(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ctrl({}, {q[0], q[1]}, [&](ValueRange targets) { + auto [_, q01] = b.ctrl({}, {q[0], q[1]}, [&](ValueRange targets) { auto [q0, q1] = b.rxx(0.123, targets[0], targets[1]); return SmallVector{q0, q1}; }); + return measureAndReturn(b, {q01[0], q01[1]}); } -void nestedCtrl(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedCtrl(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.ctrl({q[0]}, {q[1], q[2], q[3]}, [&](ValueRange targets) { + auto res = b.ctrl({q[0]}, {q[1], q[2], q[3]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( {targets[0]}, {targets[1], targets[2]}, [&](ValueRange innerTargets) { auto [q0, q1] = b.rxx(0.123, innerTargets[0], innerTargets[1]); @@ -1947,11 +2991,17 @@ void nestedCtrl(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + q[0] = res.first[0]; + q[1] = res.second[0]; + q[2] = res.second[1]; + q[3] = res.second[2]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void tripleNestedCtrl(QCOProgramBuilder& b) { +std::pair, SmallVector> +tripleNestedCtrl(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(5); - b.ctrl({q[0]}, {q[1], q[2], q[3], q[4]}, [&](ValueRange targets) { + auto res = b.ctrl({q[0]}, {q[1], q[2], q[3], q[4]}, [&](ValueRange targets) { const auto& [innerControlsOut, innerTargetsOut] = b.ctrl( {targets[0]}, {targets[1], targets[2], targets[3]}, [&](ValueRange innerTargets) { @@ -1968,25 +3018,42 @@ void tripleNestedCtrl(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); + q[0] = res.first[0]; + q[1] = res.second[0]; + q[2] = res.second[1]; + q[3] = res.second[2]; + q[4] = res.second[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3], q[4]}); } -void doubleNestedCtrlTwoQubits(QCOProgramBuilder& b) { +std::pair, SmallVector> +doubleNestedCtrlTwoQubits(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(6); - b.ctrl({q[0], q[1]}, {q[2], q[3], q[4], q[5]}, [&](ValueRange targets) { - const auto& [innerControlsOut, innerTargetsOut] = - b.ctrl({targets[0], targets[1]}, {targets[2], targets[3]}, - [&](ValueRange innerTargets) { - auto [q0, q1] = b.rxx(0.123, innerTargets[0], innerTargets[1]); - return SmallVector{q0, q1}; - }); - return llvm::to_vector( - llvm::concat(innerControlsOut, innerTargetsOut)); - }); + auto res = + b.ctrl({q[0], q[1]}, {q[2], q[3], q[4], q[5]}, [&](ValueRange targets) { + const auto& [innerControlsOut, innerTargetsOut] = + b.ctrl({targets[0], targets[1]}, {targets[2], targets[3]}, + [&](ValueRange innerTargets) { + auto [q0, q1] = + b.rxx(0.123, innerTargets[0], innerTargets[1]); + return SmallVector{q0, q1}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + q[0] = res.first[0]; + q[1] = res.first[1]; + q[2] = res.second[0]; + q[3] = res.second[1]; + q[4] = res.second[2]; + q[5] = res.second[3]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3], q[4], q[5]}); } -void ctrlInvSandwich(QCOProgramBuilder& b) { +std::pair, SmallVector> +ctrlInvSandwich(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.ctrl({q[0]}, {q[1], q[2], q[3]}, [&](ValueRange targets) { + auto res = b.ctrl({q[0]}, {q[1], q[2], q[3]}, [&](ValueRange targets) { auto inner = b.inv( {targets[0], targets[1], targets[2]}, [&](ValueRange innerTargets) { auto [innerControlsOut, innerTargetsOut] = @@ -1999,24 +3066,34 @@ void ctrlInvSandwich(QCOProgramBuilder& b) { return llvm::to_vector( llvm::concat(innerControlsOut, innerTargetsOut)); }); - return SmallVector{inner}; + return llvm::to_vector(inner); }); + q[0] = res.first[0]; + q[1] = res.second[0]; + q[2] = res.second[1]; + q[3] = res.second[2]; + return measureAndReturn(b, {q[0], q[1], q[2], q[3]}); } -void nestedInv(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedInv(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto inner = b.inv({qubits[0], qubits[1]}, [&](ValueRange innerQubits) { auto [q0, q1] = b.rxx(0.123, innerQubits[0], innerQubits[1]); return SmallVector{q0, q1}; }); - return SmallVector{inner}; + return llvm::to_vector(inner); }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void tripleNestedInv(QCOProgramBuilder& b) { +std::pair, SmallVector> +tripleNestedInv(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { auto inner1 = b.inv({qubits[0], qubits[1]}, [&](ValueRange innerQubits) { auto inner2 = b.inv( {innerQubits[0], innerQubits[1]}, [&](ValueRange innerInnerQubits) { @@ -2024,15 +3101,19 @@ void tripleNestedInv(QCOProgramBuilder& b) { b.rxx(-0.123, innerInnerQubits[0], innerInnerQubits[1]); return SmallVector{q0, q1}; }); - return SmallVector{inner2}; + return llvm::to_vector(inner2); }); - return SmallVector{inner1}; + return llvm::to_vector(inner1); }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void invCtrlSandwich(QCOProgramBuilder& b) { +std::pair, SmallVector> +invCtrlSandwich(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { const auto& [controlsOut, targetsOut] = b.ctrl({qubits[0]}, {qubits[1], qubits[2]}, [&](ValueRange targets) { auto inner = @@ -2040,38 +3121,50 @@ void invCtrlSandwich(QCOProgramBuilder& b) { auto [q0, q1] = b.rxx(0.123, innerQubits[0], innerQubits[1]); return SmallVector{q0, q1}; }); - return SmallVector{inner}; + return llvm::to_vector(inner); }); return llvm::to_vector(llvm::concat(controlsOut, targetsOut)); }); + q[0] = res[0]; + q[1] = res[1]; + q[2] = res[2]; + return measureAndReturn(b, {q[0], q[1], q[2]}); } -void simpleIf(QCOProgramBuilder& b) { +std::pair, SmallVector> +simpleIf(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); auto q0 = b.h(q[0]); auto [measuredQubit, measureResult] = b.measure(q0); - b.qcoIf(measureResult, measuredQubit, [&](ValueRange args) { + auto res = b.qcoIf(measureResult, measuredQubit, [&](ValueRange args) { auto innerQubit = b.x(args[0]); return SmallVector{innerQubit}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void ifTwoQubits(QCOProgramBuilder& b) { +std::pair, SmallVector> +ifTwoQubits(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); auto q0 = b.h(q[0]); auto [measuredQubit, measureResult] = b.measure(q0); - b.qcoIf(measureResult, {measuredQubit, q[1]}, [&](ValueRange args) { - auto innerQubit0 = b.x(args[0]); - auto innerQubit1 = b.x(args[1]); - return SmallVector{innerQubit0, innerQubit1}; - }); + auto res = + b.qcoIf(measureResult, {measuredQubit, q[1]}, [&](ValueRange args) { + auto innerQubit0 = b.x(args[0]); + auto innerQubit1 = b.x(args[1]); + return SmallVector{innerQubit0, innerQubit1}; + }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, {q[0], q[1]}); } -void ifElse(QCOProgramBuilder& b) { +std::pair, SmallVector> ifElse(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); auto q0 = b.h(q[0]); auto [measuredQubit, measureResult] = b.measure(q0); - b.qcoIf( + auto res = b.qcoIf( measureResult, {measuredQubit}, [&](ValueRange args) { auto innerQubit = b.x(args[0]); @@ -2081,25 +3174,31 @@ void ifElse(QCOProgramBuilder& b) { auto innerQubit = b.z(args[0]); return SmallVector{innerQubit}; }); + q[0] = res[0]; + return measureAndReturn(b, {q[0]}); } -void ifOneQubitOneTensor(QCOProgramBuilder& b) { +std::pair, SmallVector> +ifOneQubitOneTensor(QCOProgramBuilder& b) { auto q0 = b.allocQubit(); auto t0 = b.allocQubitRegister(1); auto q1 = b.h(q0); auto [measuredQubit, measureResult] = b.measure(q1); - b.qcoIf(measureResult, {measuredQubit, t0.value}, [&](ValueRange args) { - auto innerQubit0 = b.x(args[0]); - auto [t1, innerQubit1] = b.qtensorExtract(args[1], 0); - auto innerQubit2 = b.x(innerQubit1); - auto t2 = b.qtensorInsert(innerQubit2, t1, 0); - return SmallVector{innerQubit0, t2}; - }); + auto ifRes = + b.qcoIf(measureResult, {measuredQubit, t0.value}, [&](ValueRange args) { + auto innerQubit0 = b.x(args[0]); + auto [t1, innerQubit1] = b.qtensorExtract(args[1], 0); + auto innerQubit2 = b.x(innerQubit1); + auto t2 = b.qtensorInsert(innerQubit2, t1, 0); + return SmallVector{innerQubit0, t2}; + }); + return measureAndReturn(b, {ifRes[0]}); } -void constantTrueIf(QCOProgramBuilder& b) { +std::pair, SmallVector> +constantTrueIf(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.qcoIf( + auto ifRes = b.qcoIf( true, q.qubits, [&](ValueRange args) { auto innerQubit = b.x(args[0]); @@ -2109,11 +3208,13 @@ void constantTrueIf(QCOProgramBuilder& b) { auto innerQubit = b.z(args[0]); return SmallVector{innerQubit}; }); + return measureAndReturn(b, {ifRes[0]}); } -void constantFalseIf(QCOProgramBuilder& b) { +std::pair, SmallVector> +constantFalseIf(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.qcoIf( + auto ifRes = b.qcoIf( false, q.qubits, [&](ValueRange args) { auto innerQubit = b.x(args[0]); @@ -2123,13 +3224,15 @@ void constantFalseIf(QCOProgramBuilder& b) { auto innerQubit = b.z(args[0]); return SmallVector{innerQubit}; }); + return measureAndReturn(b, {ifRes[0]}); } -void nestedTrueIf(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedTrueIf(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); auto q0 = b.h(q[0]); auto [measuredQubit, measureResult] = b.measure(q0); - b.qcoIf(measureResult, measuredQubit, [&](ValueRange outerArgs) { + auto ifRes = b.qcoIf(measureResult, measuredQubit, [&](ValueRange outerArgs) { auto innerResult = b.qcoIf(measureResult, outerArgs, [&](ValueRange innerArgs) { auto innerQubit = b.x(innerArgs[0]); @@ -2137,13 +3240,15 @@ void nestedTrueIf(QCOProgramBuilder& b) { }); return llvm::to_vector(innerResult); }); + return measureAndReturn(b, {ifRes[0]}); } -void nestedFalseIf(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedFalseIf(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); auto q0 = b.h(q[0]); auto [measuredQubit, measureResult] = b.measure(q0); - b.qcoIf( + auto ifRes = b.qcoIf( measureResult, measuredQubit, [&](ValueRange args) { auto innerQubit = b.x(args[0]); @@ -2159,68 +3264,90 @@ void nestedFalseIf(QCOProgramBuilder& b) { }); return llvm::to_vector(innerResult); }); + return measureAndReturn(b, {ifRes[0]}); } -void qtensorAlloc(QCOProgramBuilder& b) { b.qtensorAlloc(3); } +std::pair, SmallVector> +qtensorAlloc(QCOProgramBuilder& b) { + auto qtensor = b.qtensorAlloc(3); + return measureAndReturn(b, {qtensor}); +} -void qtensorDealloc(QCOProgramBuilder& b) { +std::pair, SmallVector> +qtensorDealloc(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); b.qtensorDealloc(qtensor); + return measureAndReturn(b, {}); } -void qtensorFromElements(QCOProgramBuilder& b) { +std::pair, SmallVector> +qtensorFromElements(QCOProgramBuilder& b) { auto q0 = b.allocQubit(); auto q1 = b.allocQubit(); auto q2 = b.allocQubit(); - b.qtensorFromElements({q0, q1, q2}); + auto t = b.qtensorFromElements({q0, q1, q2}); + return measureAndReturn(b, {t}); } -void qtensorExtract(QCOProgramBuilder& b) { +std::pair, SmallVector> +qtensorExtract(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); - b.qtensorExtract(qtensor, 0); + auto [t, q] = b.qtensorExtract(qtensor, 0); + return measureAndReturn(b, {t, q}); } -void qtensorInsert(QCOProgramBuilder& b) { +std::pair, SmallVector> +qtensorInsert(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); auto [extractOutTensor, q0] = b.qtensorExtract(qtensor, 0); auto q1 = b.h(q0); - b.qtensorInsert(q1, extractOutTensor, 0); + auto insertOutTensor = b.qtensorInsert(q1, extractOutTensor, 0); + return measureAndReturn(b, {insertOutTensor}); } -void qtensorExtractInsertIndexMismatch(QCOProgramBuilder& b) { +std::pair, SmallVector> +qtensorExtractInsertIndexMismatch(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); auto [extractOutTensor, q0] = b.qtensorExtract(qtensor, 0); - b.qtensorInsert(q0, extractOutTensor, 1); + auto insertOutTensor = b.qtensorInsert(q0, extractOutTensor, 1); + return measureAndReturn(b, {insertOutTensor}); } -void qtensorExtractInsertSameIndex(QCOProgramBuilder& b) { +std::pair, SmallVector> +qtensorExtractInsertSameIndex(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); auto [extractOutTensor, q0] = b.qtensorExtract(qtensor, 0); - b.qtensorInsert(q0, extractOutTensor, 0); + auto insertOutTensor = b.qtensorInsert(q0, extractOutTensor, 0); + return measureAndReturn(b, {insertOutTensor}); } -void qtensorInsertExtractIndexMismatch(QCOProgramBuilder& b) { +std::pair, SmallVector> +qtensorInsertExtractIndexMismatch(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); auto [extractOutTensor, q0] = b.qtensorExtract(qtensor, 0); auto q1 = b.h(q0); auto insertOutTensor = b.qtensorInsert(q1, extractOutTensor, 0); auto [extractOutTensor1, q2] = b.qtensorExtract(insertOutTensor, 1); - b.qtensorInsert(q2, extractOutTensor1, 0); + auto insertOutTensor1 = b.qtensorInsert(q2, extractOutTensor1, 0); + return measureAndReturn(b, {insertOutTensor1}); } -void qtensorInsertExtractSameIndex(QCOProgramBuilder& b) { +std::pair, SmallVector> +qtensorInsertExtractSameIndex(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); auto [extractOutTensor, q0] = b.qtensorExtract(qtensor, 0); auto q1 = b.h(q0); auto insertOutTensor = b.qtensorInsert(q1, extractOutTensor, 0); auto [extractOutTensor1, q2] = b.qtensorExtract(insertOutTensor, 0); - b.qtensorInsert(q2, extractOutTensor1, 0); + auto insertOutTensor1 = b.qtensorInsert(q2, extractOutTensor1, 0); + return measureAndReturn(b, {insertOutTensor1}); } -void simpleWhileReset(QCOProgramBuilder& b) { +std::pair, SmallVector> +simpleWhileReset(QCOProgramBuilder& b) { auto q0 = b.allocQubit(); auto q1 = b.h(q0); - b.scfWhile( + auto scfWhile = b.scfWhile( ValueRange{q1}, [&](ValueRange iterArgs) { auto [q2, measureResult] = b.measure(iterArgs[0]); @@ -2231,11 +3358,13 @@ void simpleWhileReset(QCOProgramBuilder& b) { auto q3 = b.h(iterArgs[0]); return SmallVector{q3}; }); + return measureAndReturn(b, {scfWhile[0]}); } -void simpleDoWhileReset(QCOProgramBuilder& b) { +std::pair, SmallVector> +simpleDoWhileReset(QCOProgramBuilder& b) { auto q0 = b.allocQubit(); - b.scfWhile( + auto scfWhile = b.scfWhile( ValueRange{q0}, [&](ValueRange iterArgs) { auto q1 = b.h(iterArgs[0]); @@ -2244,35 +3373,43 @@ void simpleDoWhileReset(QCOProgramBuilder& b) { return SmallVector{q2}; }, [&](ValueRange iterArgs) { return llvm::to_vector(iterArgs); }); + return measureAndReturn(b, {scfWhile[0]}); } -void simpleForLoop(QCOProgramBuilder& b) { +std::pair, SmallVector> +simpleForLoop(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(2); - b.scfFor(0, 2, 1, {reg.value}, [&](Value iv, ValueRange iterArgs) { - auto [t0, q0] = b.qtensorExtract(iterArgs[0], iv); - auto q1 = b.h(q0); - auto insert = b.qtensorInsert(q1, t0, iv); - return SmallVector{insert}; - }); + auto scfFor = + b.scfFor(0, 2, 1, {reg.value}, [&](Value iv, ValueRange iterArgs) { + auto [t0, q0] = b.qtensorExtract(iterArgs[0], iv); + auto q1 = b.h(q0); + auto insert = b.qtensorInsert(q1, t0, iv); + return SmallVector{insert}; + }); + return measureAndReturn(b, {scfFor[0]}); }; -void nestedForLoopIfOp(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedForLoopIfOp(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(2); auto q0 = b.allocQubit(); - b.scfFor(0, 2, 1, {reg.value, q0}, [&](Value iv, ValueRange iterArgs) { - auto q1 = b.h(iterArgs[1]); - auto [q2, cond] = b.measure(q1); - auto ifOp = b.qcoIf(cond, iterArgs[0], [&](ValueRange args) { - auto [t0, q3] = b.qtensorExtract(args[0], iv); - auto q4 = b.h(q3); - auto insert = b.qtensorInsert(q4, t0, iv); - return SmallVector{insert}; - }); - return SmallVector{ifOp[0], q2}; - }); + auto scfFor = + b.scfFor(0, 2, 1, {reg.value, q0}, [&](Value iv, ValueRange iterArgs) { + auto q1 = b.h(iterArgs[1]); + auto [q2, cond] = b.measure(q1); + auto ifOp = b.qcoIf(cond, iterArgs[0], [&](ValueRange args) { + auto [t0, q3] = b.qtensorExtract(args[0], iv); + auto q4 = b.h(q3); + auto insert = b.qtensorInsert(q4, t0, iv); + return SmallVector{insert}; + }); + return SmallVector{ifOp[0], q2}; + }); + return measureAndReturn(b, {scfFor[0], scfFor[1]}); } -void nestedForLoopWhileOp(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedForLoopWhileOp(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(2); auto loopResult = b.scfFor(0, 2, 1, {reg.value}, [&](Value iv, ValueRange iterArgs) { @@ -2281,61 +3418,72 @@ void nestedForLoopWhileOp(QCOProgramBuilder& b) { auto insert = b.qtensorInsert(q1, t0, iv); return SmallVector{insert}; }); - b.scfFor(0, 2, 1, loopResult, [&](Value iv, ValueRange iterArgs) { - auto [t0, q0] = b.qtensorExtract(iterArgs[0], iv); - auto whileResult = b.scfWhile( - q0, - [&](ValueRange iterArgs) { - auto [q1, measureResult] = b.measure(iterArgs[0]); - b.scfCondition(measureResult, q1); - return SmallVector{q1}; - }, - [&](ValueRange iterArgs) { - auto q2 = b.h(iterArgs[0]); - return SmallVector{q2}; - }); - auto insert = b.qtensorInsert(whileResult[0], t0, iv); - return SmallVector{insert}; - }); + auto scfFor = + b.scfFor(0, 2, 1, loopResult, [&](Value iv, ValueRange iterArgs) { + auto [t0, q0] = b.qtensorExtract(iterArgs[0], iv); + auto whileResult = b.scfWhile( + q0, + [&](ValueRange iterArgs) { + auto [q1, measureResult] = b.measure(iterArgs[0]); + b.scfCondition(measureResult, q1); + return SmallVector{q1}; + }, + [&](ValueRange iterArgs) { + auto q2 = b.h(iterArgs[0]); + return SmallVector{q2}; + }); + auto insert = b.qtensorInsert(whileResult[0], t0, iv); + return SmallVector{insert}; + }); + return measureAndReturn(b, {scfFor[0]}); } -void nestedForLoopCtrlOpWithSeparateQubit(QCOProgramBuilder& b) { +std::pair, SmallVector> +nestedForLoopCtrlOpWithSeparateQubit(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); auto control0 = b.allocQubit(); auto control1 = b.h(control0); - b.scfFor(0, 3, 1, {reg.value, control1}, [&](Value iv, ValueRange iterArgs) { - auto [t0, q0] = b.qtensorExtract(iterArgs[0], iv); - auto q1 = b.h(q0); - auto [controls, targets] = b.ctrl(iterArgs[1], q1, [&](ValueRange args) { - auto q2 = b.x(args[0]); - return SmallVector{q2}; - }); - auto insert = b.qtensorInsert(targets[0], t0, iv); - return SmallVector{insert, controls[0]}; - }); -} - -void nestedForLoopCtrlOpWithExtractedQubit(QCOProgramBuilder& b) { + auto scfFor = b.scfFor(0, 3, 1, {reg.value, control1}, + [&](Value iv, ValueRange iterArgs) { + auto [t0, q0] = b.qtensorExtract(iterArgs[0], iv); + auto q1 = b.h(q0); + auto [controls, targets] = + b.ctrl(iterArgs[1], q1, [&](ValueRange args) { + auto q2 = b.x(args[0]); + return SmallVector{q2}; + }); + auto insert = b.qtensorInsert(targets[0], t0, iv); + return SmallVector{insert, controls[0]}; + }); + return measureAndReturn(b, {scfFor[0], scfFor[1]}); +} + +std::pair, SmallVector> +nestedForLoopCtrlOpWithExtractedQubit(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(4); auto control = b.h(reg[0]); - b.scfFor(1, 4, 1, {reg.value, control}, [&](Value iv, ValueRange iterArgs) { - auto [t0, q0] = b.qtensorExtract(iterArgs[0], iv); - auto q1 = b.h(q0); - auto [controls, targets] = b.ctrl(iterArgs[1], q1, [&](ValueRange args) { - auto q2 = b.x(args[0]); - return SmallVector{q2}; - }); - auto insert = b.qtensorInsert(targets[0], t0, iv); - return SmallVector{insert, controls[0]}; - }); -} - -void nestedIfOpForLoop(QCOProgramBuilder& b) { + auto scfFor = b.scfFor(1, 4, 1, {reg.value, control}, + [&](Value iv, ValueRange iterArgs) { + auto [t0, q0] = b.qtensorExtract(iterArgs[0], iv); + auto q1 = b.h(q0); + auto [controls, targets] = + b.ctrl(iterArgs[1], q1, [&](ValueRange args) { + auto q2 = b.x(args[0]); + return SmallVector{q2}; + }); + auto insert = b.qtensorInsert(targets[0], t0, iv); + return SmallVector{insert, controls[0]}; + }); + return measureAndReturn(b, {scfFor[0], scfFor[1]}); +} + +std::pair, SmallVector> +nestedIfOpForLoop(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); auto q0 = b.allocQubit(); auto q1 = b.h(q0); auto [q2, cond] = b.measure(q1); - b.qcoIf( + auto ifRes = b.qcoIf( cond, {reg.value, q2}, [&](ValueRange args) { auto q3 = b.h(args[1]); @@ -2351,6 +3499,7 @@ void nestedIfOpForLoop(QCOProgramBuilder& b) { }); return SmallVector{scfFor[0], args[1]}; }); + return measureAndReturn(b, {ifRes[0], ifRes[1]}); } } // namespace mlir::qco diff --git a/mlir/unittests/programs/qco_programs.h b/mlir/unittests/programs/qco_programs.h index b4197c5a7f..c6f8d3b0e4 100644 --- a/mlir/unittests/programs/qco_programs.h +++ b/mlir/unittests/programs/qco_programs.h @@ -10,1072 +10,1354 @@ #pragma once +#include + +#include + namespace mlir::qco { class QCOProgramBuilder; /// Creates an empty QCO program. -void emptyQCO(QCOProgramBuilder& builder); +std::pair, SmallVector> +emptyQCO(QCOProgramBuilder& builder); // --- Qubit Management ----------------------------------------------------- // /// Allocates a single qubit. -void allocQubit(QCOProgramBuilder& b); +std::pair, SmallVector> +allocQubit(QCOProgramBuilder& b); + +/// Allocates a single qubit that is not measured. +std::pair, SmallVector> +allocQubitNoMeasure(QCOProgramBuilder& b); + +/// Allocates a qubit register of size `1`. +std::pair, SmallVector> +alloc1QubitRegister(QCOProgramBuilder& b); /// Allocates a qubit register of size `2`. -void allocQubitRegister(QCOProgramBuilder& b); +std::pair, SmallVector> +alloc2QubitRegister(QCOProgramBuilder& b); + +/// Allocates a qubit register of size `3`. +std::pair, SmallVector> +alloc3QubitRegister(QCOProgramBuilder& b); /// Allocates two qubit registers of size `2` and `3`. -void allocMultipleQubitRegisters(QCOProgramBuilder& b); +std::pair, SmallVector> +allocMultipleQubitRegisters(QCOProgramBuilder& b); /// Allocates a large qubit register. -void allocLargeRegister(QCOProgramBuilder& b); +std::pair, SmallVector> +allocLargeRegister(QCOProgramBuilder& b); /// Allocates two inline qubits. -void staticQubits(QCOProgramBuilder& b); +std::pair, SmallVector> +staticQubits(QCOProgramBuilder& b); + +/// Allocates two inline qubits without measuring them. +std::pair, SmallVector> +staticQubitsNoMeasure(QCOProgramBuilder& b); /// Allocates two static qubits and applies operations. -void staticQubitsWithOps(QCOProgramBuilder& b); +std::pair, SmallVector> +staticQubitsWithOps(QCOProgramBuilder& b); /// Allocates two static qubits and applies parametric gates. -void staticQubitsWithParametricOps(QCOProgramBuilder& b); +std::pair, SmallVector> +staticQubitsWithParametricOps(QCOProgramBuilder& b); /// Allocates two static qubits and applies a two-target gate. -void staticQubitsWithTwoTargetOps(QCOProgramBuilder& b); +std::pair, SmallVector> +staticQubitsWithTwoTargetOps(QCOProgramBuilder& b); /// Allocates two static qubits and applies a controlled gate. -void staticQubitsWithCtrl(QCOProgramBuilder& b); +std::pair, SmallVector> +staticQubitsWithCtrl(QCOProgramBuilder& b); /// Allocates a static qubit and applies an inverse modifier. -void staticQubitsWithInv(QCOProgramBuilder& b); +std::pair, SmallVector> +staticQubitsWithInv(QCOProgramBuilder& b); /// Allocates and explicitly sinks a single qubit. -void allocSinkPair(QCOProgramBuilder& b); +std::pair, SmallVector> +allocSinkPair(QCOProgramBuilder& b); // --- Invalid / mixed addressing (unit tests) -------------------------------- /// @pre `builder.initialize()`. Fatal mixed addressing: static then dynamic /// alloc. -void mixedStaticThenDynamicQubit(QCOProgramBuilder& b); +std::pair, SmallVector> +mixedStaticThenDynamicQubit(QCOProgramBuilder& b); /// @pre `builder.initialize()`. Fatal mixed addressing: `qtensor` alloc then /// static. -void mixedDynamicRegisterThenStaticQubit(QCOProgramBuilder& b); +std::pair, SmallVector> +mixedDynamicRegisterThenStaticQubit(QCOProgramBuilder& b); // --- MeasureOp ------------------------------------------------------------ // /// Measures a single qubit into a single classical bit. -void singleMeasurementToSingleBit(QCOProgramBuilder& b); +std::pair, SmallVector> +singleMeasurementToSingleBit(QCOProgramBuilder& b); /// Repeatedly measures a single qubit into the same classical bit. -void repeatedMeasurementToSameBit(QCOProgramBuilder& b); +std::pair, SmallVector> +repeatedMeasurementToSameBit(QCOProgramBuilder& b); /// Repeatedly measures a single qubit into different classical bits. -void repeatedMeasurementToDifferentBits(QCOProgramBuilder& b); +std::pair, SmallVector> +repeatedMeasurementToDifferentBits(QCOProgramBuilder& b); /// Measures multiple qubits into multiple classical bits. -void multipleClassicalRegistersAndMeasurements(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleClassicalRegistersAndMeasurements(QCOProgramBuilder& b); /// Measures a single qubit into a single classical bit, without explicitly /// allocating a quantum or classical register. -void measurementWithoutRegisters(QCOProgramBuilder& b); +std::pair, SmallVector> +measurementWithoutRegisters(QCOProgramBuilder& b); // --- ResetOp -------------------------------------------------------------- // /// Resets a single qubit without any operations being applied. -void resetQubitWithoutOp(QCOProgramBuilder& b); +std::pair, SmallVector> +resetQubitWithoutOp(QCOProgramBuilder& b); /// Resets multiple qubits without any operations being applied. -void resetMultipleQubitsWithoutOp(QCOProgramBuilder& b); +std::pair, SmallVector> +resetMultipleQubitsWithoutOp(QCOProgramBuilder& b); /// Repeatedly resets a single qubit without any operations being applied. -void repeatedResetWithoutOp(QCOProgramBuilder& b); +std::pair, SmallVector> +repeatedResetWithoutOp(QCOProgramBuilder& b); /// Resets a single qubit after a single operation. -void resetQubitAfterSingleOp(QCOProgramBuilder& b); +std::pair, SmallVector> +resetQubitAfterSingleOp(QCOProgramBuilder& b); /// Resets multiple qubits after a single operation. -void resetMultipleQubitsAfterSingleOp(QCOProgramBuilder& b); +std::pair, SmallVector> +resetMultipleQubitsAfterSingleOp(QCOProgramBuilder& b); /// Repeatedly resets a single qubit after a single operation. -void repeatedResetAfterSingleOp(QCOProgramBuilder& b); +std::pair, SmallVector> +repeatedResetAfterSingleOp(QCOProgramBuilder& b); // --- GPhaseOp ------------------------------------------------------------- // /// Creates a circuit with just a global phase. -void globalPhase(QCOProgramBuilder& b); +std::pair, SmallVector> +globalPhase(QCOProgramBuilder& b); /// Creates a controlled global phase gate with a single control qubit. -void singleControlledGlobalPhase(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledGlobalPhase(QCOProgramBuilder& b); /// Creates a multi-controlled global phase gate with multiple control qubits. -void multipleControlledGlobalPhase(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledGlobalPhase(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a global phase gate. -void inverseGlobalPhase(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseGlobalPhase(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled global /// phase gate. -void inverseMultipleControlledGlobalPhase(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledGlobalPhase(QCOProgramBuilder& b); // --- IdOp ----------------------------------------------------------------- // /// Creates a circuit with just an identity gate. -void identity(QCOProgramBuilder& b); +std::pair, SmallVector> identity(QCOProgramBuilder& b); /// Creates a controlled identity gate with a single control qubit. -void singleControlledIdentity(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledIdentity(QCOProgramBuilder& b); /// Creates a multi-controlled identity gate with multiple control qubits. -void multipleControlledIdentity(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledIdentity(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled identity gate. -void nestedControlledIdentity(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledIdentity(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled identity gate. -void trivialControlledIdentity(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledIdentity(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an identity gate. -void inverseIdentity(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseIdentity(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled identity /// gate. -void inverseMultipleControlledIdentity(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledIdentity(QCOProgramBuilder& b); // --- XOp ------------------------------------------------------------------ // /// Creates a circuit with just an X gate. -void x(QCOProgramBuilder& b); +std::pair, SmallVector> x(QCOProgramBuilder& b); /// Creates a circuit with a single controlled X gate. -void singleControlledX(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledX(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled X gate. -void multipleControlledX(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledX(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled X gate. -void nestedControlledX(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledX(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled X gate. -void trivialControlledX(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledX(QCOProgramBuilder& b); /// Creates a circuit with repeated controlled X gates. -void repeatedControlledX(QCOProgramBuilder& b); +std::pair, SmallVector> +repeatedControlledX(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an X gate. -void inverseX(QCOProgramBuilder& b); +std::pair, SmallVector> inverseX(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled X gate. -void inverseMultipleControlledX(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledX(QCOProgramBuilder& b); /// Creates a circuit with two X gates in a row. -void twoX(QCOProgramBuilder& b); +std::pair, SmallVector> twoX(QCOProgramBuilder& b); // --- YOp ------------------------------------------------------------------ // /// Creates a circuit with just a Y gate. -void y(QCOProgramBuilder& b); +std::pair, SmallVector> y(QCOProgramBuilder& b); /// Creates a circuit with a single controlled Y gate. -void singleControlledY(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledY(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled Y gate. -void multipleControlledY(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledY(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled Y gate. -void nestedControlledY(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledY(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled Y gate. -void trivialControlledY(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a Y gate. -void inverseY(QCOProgramBuilder& b); +std::pair, SmallVector> inverseY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Y gate. -void inverseMultipleControlledY(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledY(QCOProgramBuilder& b); /// Creates a circuit with two Y gates in a row. -void twoY(QCOProgramBuilder& b); +std::pair, SmallVector> twoY(QCOProgramBuilder& b); // --- ZOp ------------------------------------------------------------------ // /// Creates a circuit with just a Z gate. -void z(QCOProgramBuilder& b); +std::pair, SmallVector> z(QCOProgramBuilder& b); /// Creates a circuit with a single controlled Z gate. -void singleControlledZ(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledZ(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled Z gate. -void multipleControlledZ(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledZ(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled Z gate. -void nestedControlledZ(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledZ(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled Z gate. -void trivialControlledZ(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledZ(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a Z gate. -void inverseZ(QCOProgramBuilder& b); +std::pair, SmallVector> inverseZ(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Z gate. -void inverseMultipleControlledZ(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledZ(QCOProgramBuilder& b); /// Creates a circuit with two Z gates in a row. -void twoZ(QCOProgramBuilder& b); +std::pair, SmallVector> twoZ(QCOProgramBuilder& b); // --- HOp ------------------------------------------------------------------ // /// Creates a circuit with just an H gate. -void h(QCOProgramBuilder& b); +std::pair, SmallVector> h(QCOProgramBuilder& b); /// Creates a circuit with a single controlled H gate. -void singleControlledH(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledH(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled H gate. -void multipleControlledH(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledH(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled H gate. -void nestedControlledH(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledH(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled H gate. -void trivialControlledH(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledH(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an H gate. -void inverseH(QCOProgramBuilder& b); +std::pair, SmallVector> inverseH(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled H gate. -void inverseMultipleControlledH(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledH(QCOProgramBuilder& b); /// Creates a circuit with two H gates in a row. -void twoH(QCOProgramBuilder& b); +std::pair, SmallVector> twoH(QCOProgramBuilder& b); /// Creates a circuit with just an H gate and no qubit register. -void hWithoutRegister(QCOProgramBuilder& b); +std::pair, SmallVector> +hWithoutRegister(QCOProgramBuilder& b); // --- SOp ------------------------------------------------------------------ // /// Creates a circuit with just an S gate. -void s(QCOProgramBuilder& b); +std::pair, SmallVector> s(QCOProgramBuilder& b); /// Creates a circuit with a single controlled S gate. -void singleControlledS(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledS(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled S gate. -void multipleControlledS(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledS(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled S gate. -void nestedControlledS(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledS(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled S gate. -void trivialControlledS(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledS(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an S gate. -void inverseS(QCOProgramBuilder& b); +std::pair, SmallVector> inverseS(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled S gate. -void inverseMultipleControlledS(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledS(QCOProgramBuilder& b); /// Creates a circuit with an S gate followed by an Sdg gate. -void sThenSdg(QCOProgramBuilder& b); +std::pair, SmallVector> sThenSdg(QCOProgramBuilder& b); /// Creates a circuit with two S gates in a row. -void twoS(QCOProgramBuilder& b); +std::pair, SmallVector> twoS(QCOProgramBuilder& b); // --- SdgOp ---------------------------------------------------------------- // /// Creates a circuit with just an Sdg gate. -void sdg(QCOProgramBuilder& b); +std::pair, SmallVector> sdg(QCOProgramBuilder& b); /// Creates a circuit with a single controlled Sdg gate. -void singleControlledSdg(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled Sdg gate. -void multipleControlledSdg(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled Sdg gate. -void nestedControlledSdg(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled Sdg gate. -void trivialControlledSdg(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an Sdg gate. -void inverseSdg(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseSdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Sdg gate. -void inverseMultipleControlledSdg(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with an Sdg gate followed an S gate. -void sdgThenS(QCOProgramBuilder& b); +std::pair, SmallVector> sdgThenS(QCOProgramBuilder& b); /// Creates a circuit with two Sdg gates in a row. -void twoSdg(QCOProgramBuilder& b); +std::pair, SmallVector> twoSdg(QCOProgramBuilder& b); // --- TOp ------------------------------------------------------------------ // /// Creates a circuit with just a T gate. -void t_(QCOProgramBuilder& b); // NOLINT(*-identifier-naming) +std::pair, SmallVector> +t_(QCOProgramBuilder& b); // NOLINT(*-identifier-naming) /// Creates a circuit with a single controlled T gate. -void singleControlledT(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledT(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled T gate. -void multipleControlledT(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledT(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled T gate. -void nestedControlledT(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledT(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled T gate. -void trivialControlledT(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledT(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a T gate. -void inverseT(QCOProgramBuilder& b); +std::pair, SmallVector> inverseT(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled T gate. -void inverseMultipleControlledT(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledT(QCOProgramBuilder& b); /// Creates a circuit with a T gate followed by a Tdg gate. -void tThenTdg(QCOProgramBuilder& b); +std::pair, SmallVector> tThenTdg(QCOProgramBuilder& b); /// Creates a circuit with two T gates in a row. -void twoT(QCOProgramBuilder& b); +std::pair, SmallVector> twoT(QCOProgramBuilder& b); // --- TdgOp ---------------------------------------------------------------- // /// Creates a circuit with just a Tdg gate. -void tdg(QCOProgramBuilder& b); +std::pair, SmallVector> tdg(QCOProgramBuilder& b); /// Creates a circuit with a single controlled Tdg gate. -void singleControlledTdg(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled Tdg gate. -void multipleControlledTdg(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled Tdg gate. -void nestedControlledTdg(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled Tdg gate. -void trivialControlledTdg(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a Tdg gate. -void inverseTdg(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseTdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Tdg gate. -void inverseMultipleControlledTdg(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with a Tdg gate followed by a T gate. -void tdgThenT(QCOProgramBuilder& b); +std::pair, SmallVector> tdgThenT(QCOProgramBuilder& b); /// Creates a circuit with two Tdg gates in a row. -void twoTdg(QCOProgramBuilder& b); +std::pair, SmallVector> twoTdg(QCOProgramBuilder& b); // --- SXOp ----------------------------------------------------------------- // /// Creates a circuit with just an SX gate. -void sx(QCOProgramBuilder& b); +std::pair, SmallVector> sx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled SX gate. -void singleControlledSx(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledSx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled SX gate. -void multipleControlledSx(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledSx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled SX gate. -void nestedControlledSx(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledSx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled SX gate. -void trivialControlledSx(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledSx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an SX gate. -void inverseSx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseSx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled SX gate. -void inverseMultipleControlledSx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledSx(QCOProgramBuilder& b); /// Creates a circuit with an SX gate followed by an SXdg gate. -void sxThenSxdg(QCOProgramBuilder& b); +std::pair, SmallVector> +sxThenSxdg(QCOProgramBuilder& b); /// Creates a circuit with two SX gates in a row. -void twoSx(QCOProgramBuilder& b); +std::pair, SmallVector> twoSx(QCOProgramBuilder& b); // --- SXdgOp --------------------------------------------------------------- // /// Creates a circuit with just an SXdg gate. -void sxdg(QCOProgramBuilder& b); +std::pair, SmallVector> sxdg(QCOProgramBuilder& b); /// Creates a circuit with a single controlled SXdg gate. -void singleControlledSxdg(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled SXdg gate. -void multipleControlledSxdg(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled SXdg gate. -void nestedControlledSxdg(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled SXdg gate. -void trivialControlledSxdg(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an SXdg gate. -void inverseSxdg(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseSxdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled SXdg /// gate. -void inverseMultipleControlledSxdg(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with an SXdg gate followed by an SX gate. -void sxdgThenSx(QCOProgramBuilder& b); +std::pair, SmallVector> +sxdgThenSx(QCOProgramBuilder& b); /// Creates a circuit with two SXdg gates in a row. -void twoSxdg(QCOProgramBuilder& b); +std::pair, SmallVector> twoSxdg(QCOProgramBuilder& b); // --- RXOp ----------------------------------------------------------------- // /// Creates a circuit with just an RX gate. -void rx(QCOProgramBuilder& b); +std::pair, SmallVector> rx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RX gate. -void singleControlledRx(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledRx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RX gate. -void multipleControlledRx(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledRx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RX gate. -void nestedControlledRx(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledRx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RX gate. -void trivialControlledRx(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledRx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RX gate. -void inverseRx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseRx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RX gate. -void inverseMultipleControlledRx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledRx(QCOProgramBuilder& b); /// Creates a circuit with two RX gates in a row with opposite phases. -void twoRxOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRxOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with an RX gate with an angle of pi/2. -void rxPiOver2(QCOProgramBuilder& b); +std::pair, SmallVector> +rxPiOver2(QCOProgramBuilder& b); // --- RYOp ----------------------------------------------------------------- // /// Creates a circuit with just an RY gate. -void ry(QCOProgramBuilder& b); +std::pair, SmallVector> ry(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RY gate. -void singleControlledRy(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledRy(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RY gate. -void multipleControlledRy(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledRy(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RY gate. -void nestedControlledRy(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledRy(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RY gate. -void trivialControlledRy(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledRy(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RY gate. -void inverseRy(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseRy(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RY gate. -void inverseMultipleControlledRy(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledRy(QCOProgramBuilder& b); /// Creates a circuit with two RY gates in a row with opposite phases. -void twoRyOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRyOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with an RY gate with an angle of pi/2. -void ryPiOver2(QCOProgramBuilder& b); +std::pair, SmallVector> +ryPiOver2(QCOProgramBuilder& b); // --- RZOp ----------------------------------------------------------------- // /// Creates a circuit with just an RZ gate. -void rz(QCOProgramBuilder& b); +std::pair, SmallVector> rz(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RZ gate. -void singleControlledRz(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledRz(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RZ gate. -void multipleControlledRz(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledRz(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RZ gate. -void nestedControlledRz(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledRz(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RZ gate. -void trivialControlledRz(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledRz(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RZ gate. -void inverseRz(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseRz(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RZ gate. -void inverseMultipleControlledRz(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledRz(QCOProgramBuilder& b); /// Creates a circuit with two RZ gates in a row with opposite phases. -void twoRzOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRzOppositePhase(QCOProgramBuilder& b); // --- POp ------------------------------------------------------------------ // /// Creates a circuit with just a P gate. -void p(QCOProgramBuilder& b); +std::pair, SmallVector> p(QCOProgramBuilder& b); /// Creates a circuit with a single controlled P gate. -void singleControlledP(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledP(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled P gate. -void multipleControlledP(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledP(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled P gate. -void nestedControlledP(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledP(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled P gate. -void trivialControlledP(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledP(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a P gate. -void inverseP(QCOProgramBuilder& b); +std::pair, SmallVector> inverseP(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled P gate. -void inverseMultipleControlledP(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledP(QCOProgramBuilder& b); /// Creates a circuit with two P gates in a row with opposite phases. -void twoPOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoPOppositePhase(QCOProgramBuilder& b); // --- ROp ------------------------------------------------------------------ // /// Creates a circuit with just an R gate. -void r(QCOProgramBuilder& b); +std::pair, SmallVector> r(QCOProgramBuilder& b); /// Creates a circuit with a single controlled R gate. -void singleControlledR(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledR(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled R gate. -void multipleControlledR(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledR(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled R gate. -void nestedControlledR(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledR(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled R gate. -void trivialControlledR(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledR(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an R gate. -void inverseR(QCOProgramBuilder& b); +std::pair, SmallVector> inverseR(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled R gate. -void inverseMultipleControlledR(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledR(QCOProgramBuilder& b); /// Creates a circuit with an R gate that can be canonicalized to an RX gate. -void canonicalizeRToRx(QCOProgramBuilder& b); +std::pair, SmallVector> +canonicalizeRToRx(QCOProgramBuilder& b); /// Creates a circuit with an R gate that can be canonicalized to an RY gate. -void canonicalizeRToRy(QCOProgramBuilder& b); +std::pair, SmallVector> +canonicalizeRToRy(QCOProgramBuilder& b); // --- U2Op ----------------------------------------------------------------- // /// Creates a circuit with just a U2 gate. -void u2(QCOProgramBuilder& b); +std::pair, SmallVector> u2(QCOProgramBuilder& b); /// Creates a circuit with a single controlled U2 gate. -void singleControlledU2(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledU2(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled U2 gate. -void multipleControlledU2(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledU2(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled U2 gate. -void nestedControlledU2(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledU2(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled U2 gate. -void trivialControlledU2(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledU2(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a U2 gate. -void inverseU2(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseU2(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled U2 gate. -void inverseMultipleControlledU2(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledU2(QCOProgramBuilder& b); /// Creates a circuit with a U2 gate that can be canonicalized to an H gate. -void canonicalizeU2ToH(QCOProgramBuilder& b); +std::pair, SmallVector> +canonicalizeU2ToH(QCOProgramBuilder& b); /// Creates a circuit with a U2 gate that can be canonicalized to an RX gate. -void canonicalizeU2ToRx(QCOProgramBuilder& b); +std::pair, SmallVector> +canonicalizeU2ToRx(QCOProgramBuilder& b); /// Creates a circuit with a U2 gate that can be canonicalized to an RY gate. -void canonicalizeU2ToRy(QCOProgramBuilder& b); +std::pair, SmallVector> +canonicalizeU2ToRy(QCOProgramBuilder& b); // --- UOp ------------------------------------------------------------------ // /// Creates a circuit with just a U gate. -void u(QCOProgramBuilder& b); +std::pair, SmallVector> u(QCOProgramBuilder& b); /// Creates a circuit with a single controlled U gate. -void singleControlledU(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledU(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled U gate. -void multipleControlledU(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledU(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled U gate. -void nestedControlledU(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledU(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled U gate. -void trivialControlledU(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledU(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a U gate. -void inverseU(QCOProgramBuilder& b); +std::pair, SmallVector> inverseU(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled U gate. -void inverseMultipleControlledU(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledU(QCOProgramBuilder& b); /// Creates a circuit with a U gate that can be canonicalized to a P gate. -void canonicalizeUToP(QCOProgramBuilder& b); +std::pair, SmallVector> +canonicalizeUToP(QCOProgramBuilder& b); /// Creates a circuit with a U gate that can be canonicalized to an RX gate. -void canonicalizeUToRx(QCOProgramBuilder& b); +std::pair, SmallVector> +canonicalizeUToRx(QCOProgramBuilder& b); /// Creates a circuit with a U gate that can be canonicalized to an RY gate. -void canonicalizeUToRy(QCOProgramBuilder& b); +std::pair, SmallVector> +canonicalizeUToRy(QCOProgramBuilder& b); /// Creates a circuit with a U gate that can be canonicalized to a U2 gate. -void canonicalizeUToU2(QCOProgramBuilder& b); +std::pair, SmallVector> +canonicalizeUToU2(QCOProgramBuilder& b); // --- SWAPOp --------------------------------------------------------------- // /// Creates a circuit with just a SWAP gate. -void swap(QCOProgramBuilder& b); +std::pair, SmallVector> swap(QCOProgramBuilder& b); /// Creates a circuit with a single controlled SWAP gate. -void singleControlledSwap(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled SWAP gate. -void multipleControlledSwap(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled SWAP gate. -void nestedControlledSwap(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled SWAP gate. -void trivialControlledSwap(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a SWAP gate. -void inverseSwap(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseSwap(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled SWAP /// gate. -void inverseMultipleControlledSwap(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with two SWAP gates in a row. -void twoSwap(QCOProgramBuilder& b); +std::pair, SmallVector> twoSwap(QCOProgramBuilder& b); /// Creates a circuit with two SWAP gates in a row with swapped targets. -void twoSwapSwappedTargets(QCOProgramBuilder& b); +std::pair, SmallVector> +twoSwapSwappedTargets(QCOProgramBuilder& b); // --- iSWAPOp -------------------------------------------------------------- // /// Creates a circuit with just an iSWAP gate. -void iswap(QCOProgramBuilder& b); +std::pair, SmallVector> iswap(QCOProgramBuilder& b); /// Creates a circuit with a single controlled iSWAP gate. -void singleControlledIswap(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledIswap(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled iSWAP gate. -void multipleControlledIswap(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledIswap(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled iSWAP gate. -void nestedControlledIswap(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledIswap(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled iSWAP gate. -void trivialControlledIswap(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledIswap(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an iSWAP gate. -void inverseIswap(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseIswap(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled iSWAP /// gate. -void inverseMultipleControlledIswap(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledIswap(QCOProgramBuilder& b); // --- DCXOp ---------------------------------------------------------------- // /// Creates a circuit with just a DCX gate. -void dcx(QCOProgramBuilder& b); +std::pair, SmallVector> dcx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled DCX gate. -void singleControlledDcx(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled DCX gate. -void multipleControlledDcx(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled DCX gate. -void nestedControlledDcx(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled DCX gate. -void trivialControlledDcx(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a DCX gate. -void inverseDcx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseDcx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled DCX gate. -void inverseMultipleControlledDcx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with two DCX gates in a row with identical targets. -void twoDcx(QCOProgramBuilder& b); +std::pair, SmallVector> twoDcx(QCOProgramBuilder& b); /// Creates a circuit with two DCX gates in a row with swapped targets. -void twoDcxSwappedTargets(QCOProgramBuilder& b); +std::pair, SmallVector> +twoDcxSwappedTargets(QCOProgramBuilder& b); // --- ECROp ---------------------------------------------------------------- // /// Creates a circuit with just an ECR gate. -void ecr(QCOProgramBuilder& b); +std::pair, SmallVector> ecr(QCOProgramBuilder& b); /// Creates a circuit with a single controlled ECR gate. -void singleControlledEcr(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled ECR gate. -void multipleControlledEcr(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled ECR gate. -void nestedControlledEcr(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled ECR gate. -void trivialControlledEcr(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an ECR gate. -void inverseEcr(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseEcr(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled ECR gate. -void inverseMultipleControlledEcr(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with two ECR gates in a row. -void twoEcr(QCOProgramBuilder& b); +std::pair, SmallVector> twoEcr(QCOProgramBuilder& b); // --- RXXOp ---------------------------------------------------------------- // /// Creates a circuit with just an RXX gate. -void rxx(QCOProgramBuilder& b); +std::pair, SmallVector> rxx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RXX gate. -void singleControlledRxx(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RXX gate. -void multipleControlledRxx(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RXX gate. -void nestedControlledRxx(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RXX gate. -void trivialControlledRxx(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RXX gate. -void inverseRxx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseRxx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RXX gate. -void inverseMultipleControlledRxx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a triple-controlled RXX gate. -void tripleControlledRxx(QCOProgramBuilder& b); +std::pair, SmallVector> +tripleControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a four-controlled RXX gate. -void fourControlledRxx(QCOProgramBuilder& b); +std::pair, SmallVector> +fourControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with two RXX gates in a row. -void twoRxx(QCOProgramBuilder& b); +std::pair, SmallVector> twoRxx(QCOProgramBuilder& b); /// Creates a circuit with two RXX gates in a row with swapped targets. -void twoRxxSwappedTargets(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRxxSwappedTargets(QCOProgramBuilder& b); /// Creates a circuit with two RXX gates in a row with opposite phases. -void twoRxxOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRxxOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with two RXX gates in a row with opposite phases and /// swapped targets. -void twoRxxOppositePhaseSwappedTargets(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRxxOppositePhaseSwappedTargets(QCOProgramBuilder& b); // --- RYYOp ---------------------------------------------------------------- // /// Creates a circuit with just an RYY gate. -void ryy(QCOProgramBuilder& b); +std::pair, SmallVector> ryy(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RYY gate. -void singleControlledRyy(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RYY gate. -void multipleControlledRyy(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RYY gate. -void nestedControlledRyy(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RYY gate. -void trivialControlledRyy(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RYY gate. -void inverseRyy(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseRyy(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RYY gate. -void inverseMultipleControlledRyy(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with two RYY gates in a row. -void twoRyy(QCOProgramBuilder& b); +std::pair, SmallVector> twoRyy(QCOProgramBuilder& b); /// Creates a circuit with two RYY gates in a row with swapped targets. -void twoRyySwappedTargets(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRyySwappedTargets(QCOProgramBuilder& b); /// Creates a circuit with two RYY gates in a row with opposite phases. -void twoRyyOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRyyOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with two RYY gates in a row with opposite phases and /// swapped targets. -void twoRyyOppositePhaseSwappedTargets(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRyyOppositePhaseSwappedTargets(QCOProgramBuilder& b); // --- RZXOp ---------------------------------------------------------------- // /// Creates a circuit with just an RZX gate. -void rzx(QCOProgramBuilder& b); +std::pair, SmallVector> rzx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RZX gate. -void singleControlledRzx(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RZX gate. -void multipleControlledRzx(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RZX gate. -void nestedControlledRzx(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RZX gate. -void trivialControlledRzx(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RZX gate. -void inverseRzx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseRzx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RZX gate. -void inverseMultipleControlledRzx(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with two RZX gates in a row with opposite phases. -void twoRzxOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRzxOppositePhase(QCOProgramBuilder& b); // --- RZZOp ---------------------------------------------------------------- // /// Creates a circuit with just an RZZ gate. -void rzz(QCOProgramBuilder& b); +std::pair, SmallVector> rzz(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RZZ gate. -void singleControlledRzz(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RZZ gate. -void multipleControlledRzz(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RZZ gate. -void nestedControlledRzz(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RZZ gate. -void trivialControlledRzz(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RZZ gate. -void inverseRzz(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseRzz(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RZZ gate. -void inverseMultipleControlledRzz(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with two RZZ gates in a row. -void twoRzz(QCOProgramBuilder& b); +std::pair, SmallVector> twoRzz(QCOProgramBuilder& b); /// Creates a circuit with two RZZ gates in a row with swapped targets. -void twoRzzSwappedTargets(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRzzSwappedTargets(QCOProgramBuilder& b); /// Creates a circuit with two RZZ gates in a row with opposite phases. -void twoRzzOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRzzOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with two RZZ gates in a row with opposite phases and /// swapped targets. -void twoRzzOppositePhaseSwappedTargets(QCOProgramBuilder& b); +std::pair, SmallVector> +twoRzzOppositePhaseSwappedTargets(QCOProgramBuilder& b); // --- XXPlusYYOp ----------------------------------------------------------- // /// Creates a circuit with just an XXPlusYY gate. -void xxPlusYY(QCOProgramBuilder& b); +std::pair, SmallVector> xxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with a single controlled XXPlusYY gate. -void singleControlledXxPlusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled XXPlusYY gate. -void multipleControlledXxPlusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled XXPlusYY gate. -void nestedControlledXxPlusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled XXPlusYY gate. -void trivialControlledXxPlusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an XXPlusYY gate. -void inverseXxPlusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled XXPlusYY /// gate. -void inverseMultipleControlledXxPlusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with two XXPlusYY gates in a row with opposite phases. -void twoXxPlusYYOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoXxPlusYYOppositePhase(QCOProgramBuilder& b); // --- XXMinusYYOp ---------------------------------------------------------- // /// Creates a circuit with just an XXMinusYY gate. -void xxMinusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +xxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with a single controlled XXMinusYY gate. -void singleControlledXxMinusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled XXMinusYY gate. -void multipleControlledXxMinusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +multipleControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled XXMinusYY gate. -void nestedControlledXxMinusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled XXMinusYY gate. -void trivialControlledXxMinusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an XXMinusYY gate. -void inverseXxMinusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled XXMinusYY /// gate. -void inverseMultipleControlledXxMinusYY(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseMultipleControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with two XXMinusYY gates in a row with opposite phases. -void twoXxMinusYYOppositePhase(QCOProgramBuilder& b); +std::pair, SmallVector> +twoXxMinusYYOppositePhase(QCOProgramBuilder& b); // --- BarrierOp ------------------------------------------------------------ // /// Creates a circuit with a barrier. -void barrier(QCOProgramBuilder& b); +std::pair, SmallVector> barrier(QCOProgramBuilder& b); /// Creates a circuit with a barrier on two qubits. -void barrierTwoQubits(QCOProgramBuilder& b); +std::pair, SmallVector> +barrierTwoQubits(QCOProgramBuilder& b); /// Creates a circuit with a barrier on multiple qubits. -void barrierMultipleQubits(QCOProgramBuilder& b); +std::pair, SmallVector> +barrierMultipleQubits(QCOProgramBuilder& b); /// Creates a circuit with a single controlled barrier. -void singleControlledBarrier(QCOProgramBuilder& b); +std::pair, SmallVector> +singleControlledBarrier(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a barrier. -void inverseBarrier(QCOProgramBuilder& b); +std::pair, SmallVector> +inverseBarrier(QCOProgramBuilder& b); /// Creates a circuit with two barriers in a row with overlapping qubits. -void twoBarrier(QCOProgramBuilder& b); +std::pair, SmallVector> +twoBarrier(QCOProgramBuilder& b); // --- CtrlOp --------------------------------------------------------------- // /// Creates a circuit with a trivial ctrl modifier. -void trivialCtrl(QCOProgramBuilder& b); +std::pair, SmallVector> +trivialCtrl(QCOProgramBuilder& b); /// Creates a circuit with nested ctrl modifiers. -void nestedCtrl(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedCtrl(QCOProgramBuilder& b); /// Creates a circuit with triple nested ctrl modifiers. -void tripleNestedCtrl(QCOProgramBuilder& b); +std::pair, SmallVector> +tripleNestedCtrl(QCOProgramBuilder& b); /// Creates a circuit with double nested ctrl modifiers with two qubits each. -void doubleNestedCtrlTwoQubits(QCOProgramBuilder& b); +std::pair, SmallVector> +doubleNestedCtrlTwoQubits(QCOProgramBuilder& b); /// Creates a circuit with control modifiers interleaved by an inverse modifier. -void ctrlInvSandwich(QCOProgramBuilder& b); +std::pair, SmallVector> +ctrlInvSandwich(QCOProgramBuilder& b); // --- InvOp ---------------------------------------------------------------- // /// Creates a circuit with nested inverse modifiers. -void nestedInv(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedInv(QCOProgramBuilder& b); /// Creates a circuit with triple nested inverse modifiers. -void tripleNestedInv(QCOProgramBuilder& b); +std::pair, SmallVector> +tripleNestedInv(QCOProgramBuilder& b); /// Creates a circuit with inverse modifiers interleaved by a control modifier. -void invCtrlSandwich(QCOProgramBuilder& b); +std::pair, SmallVector> +invCtrlSandwich(QCOProgramBuilder& b); // --- IfOp ---------------------------------------------------------------- // /// Creates a circuit with a simple if operation with one qubit. -void simpleIf(QCOProgramBuilder& b); +std::pair, SmallVector> simpleIf(QCOProgramBuilder& b); /// Creates a circuit with an if operation with two qubits. -void ifTwoQubits(QCOProgramBuilder& b); +std::pair, SmallVector> +ifTwoQubits(QCOProgramBuilder& b); /// Creates a circuit with an if operation with an else branch. -void ifElse(QCOProgramBuilder& b); +std::pair, SmallVector> ifElse(QCOProgramBuilder& b); /// Creates a circuit with an if operation with one qubit and one register. -void ifOneQubitOneTensor(QCOProgramBuilder& b); +std::pair, SmallVector> +ifOneQubitOneTensor(QCOProgramBuilder& b); /// Creates a circuit with an if operation that uses a constant true as /// condition. -void constantTrueIf(QCOProgramBuilder& b); +std::pair, SmallVector> +constantTrueIf(QCOProgramBuilder& b); /// Creates a circuit with an if operation that uses a constant false as /// condition. -void constantFalseIf(QCOProgramBuilder& b); +std::pair, SmallVector> +constantFalseIf(QCOProgramBuilder& b); /// Creates a circuit with a nested if operation in the then branch that uses /// the same condition. -void nestedTrueIf(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedTrueIf(QCOProgramBuilder& b); /// Creates a circuit with a nested if operation in the else branch that uses /// the same condition. -void nestedFalseIf(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedFalseIf(QCOProgramBuilder& b); /// Creates a circuit with an if operation with a nested for operation with /// a register. -void nestedIfOpForLoop(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedIfOpForLoop(QCOProgramBuilder& b); // --- WhileOp -------------------------------------------------------------- // /// Creates a circuit with a while operation using a while loop. -void simpleWhileReset(QCOProgramBuilder& b); +std::pair, SmallVector> +simpleWhileReset(QCOProgramBuilder& b); /// Creates a circuit with a while operation using a do-while loop. -void simpleDoWhileReset(QCOProgramBuilder& b); +std::pair, SmallVector> +simpleDoWhileReset(QCOProgramBuilder& b); // --- ForOp ---------------------------------------------------------------- // /// Creates a circuit with a simple for operation with a register. -void simpleForLoop(QCOProgramBuilder& b); +std::pair, SmallVector> +simpleForLoop(QCOProgramBuilder& b); /// Creates a circuit with a for operation with a register and a qubit and a /// nested if operation. -void nestedForLoopIfOp(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedForLoopIfOp(QCOProgramBuilder& b); /// Creates a circuit with a for operation with a register and a nested while /// operation. -void nestedForLoopWhileOp(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedForLoopWhileOp(QCOProgramBuilder& b); /// Creates a circuit with a for operation with a register and a qubit and a /// nested ctrl operation where the qubit is separately allocated from the /// register. -void nestedForLoopCtrlOpWithSeparateQubit(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedForLoopCtrlOpWithSeparateQubit(QCOProgramBuilder& b); /// Creates a circuit with a for operation with a register and a qubit and a /// nested ctrl operation where the qubit is extracted from the register. -void nestedForLoopCtrlOpWithExtractedQubit(QCOProgramBuilder& b); +std::pair, SmallVector> +nestedForLoopCtrlOpWithExtractedQubit(QCOProgramBuilder& b); // --- QTensor Operations -------------------------------------------------- // /// Allocates a tensor of size `3`. -void qtensorAlloc(QCOProgramBuilder& b); +std::pair, SmallVector> +qtensorAlloc(QCOProgramBuilder& b); /// Allocates and explicitly deallocates a tensor. -void qtensorDealloc(QCOProgramBuilder& b); +std::pair, SmallVector> +qtensorDealloc(QCOProgramBuilder& b); /// Constructs a tensor with from_elements. -void qtensorFromElements(QCOProgramBuilder& b); +std::pair, SmallVector> +qtensorFromElements(QCOProgramBuilder& b); /// Extracts a qubit from a tensor. -void qtensorExtract(QCOProgramBuilder& b); +std::pair, SmallVector> +qtensorExtract(QCOProgramBuilder& b); /// Inserts a qubit into a tensor. -void qtensorInsert(QCOProgramBuilder& b); +std::pair, SmallVector> +qtensorInsert(QCOProgramBuilder& b); /// Extracts a qubit from a tensor and inserts it immediately at a different /// index. -void qtensorExtractInsertIndexMismatch(QCOProgramBuilder& b); +std::pair, SmallVector> +qtensorExtractInsertIndexMismatch(QCOProgramBuilder& b); /// Extracts a qubit from a tensor and inserts it immediately at the same index. -void qtensorExtractInsertSameIndex(QCOProgramBuilder& b); +std::pair, SmallVector> +qtensorExtractInsertSameIndex(QCOProgramBuilder& b); /// Inserts a qubit into a tensor and extracts it immediately at a different /// index. -void qtensorInsertExtractIndexMismatch(QCOProgramBuilder& b); +std::pair, SmallVector> +qtensorInsertExtractIndexMismatch(QCOProgramBuilder& b); /// Inserts a qubit into a tensor and extracts it immediately at the same index. -void qtensorInsertExtractSameIndex(QCOProgramBuilder& b); +std::pair, SmallVector> +qtensorInsertExtractSameIndex(QCOProgramBuilder& b); } // namespace mlir::qco From 6f1c64eee3e6149b081019cff5240cf8a3ecad82 Mon Sep 17 00:00:00 2001 From: Damian Rovara <93778306+DRovara@users.noreply.github.com> Date: Mon, 8 Jun 2026 10:56:54 +0200 Subject: [PATCH 22/26] Update mlir/include/mlir/Dialect/QCO/QCOUtils.h Co-authored-by: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Signed-off-by: Damian Rovara <93778306+DRovara@users.noreply.github.com> --- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index 4ade5351f7..b15c8a3752 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -248,7 +248,7 @@ mergeTwoTargetOneParameterWithSwappedTargets(OpType op, */ inline bool checkDeadGate(Operation* op) { if (!isMemoryEffectFree(op)) { - // This ignores operations with and regions that have children with memory + // This ignores operations and regions that have children with memory // effects, which should never be considered dead. return false; } From 7e63992906c91ac32accf3fd879d43ffe3b0c33a Mon Sep 17 00:00:00 2001 From: Damian Rovara <93778306+DRovara@users.noreply.github.com> Date: Mon, 8 Jun 2026 10:57:29 +0200 Subject: [PATCH 23/26] Update mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp Co-authored-by: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Signed-off-by: Damian Rovara <93778306+DRovara@users.noreply.github.com> --- mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index 13d3adc5e7..cb283eaaf2 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -1237,7 +1237,7 @@ INSTANTIATE_TEST_SUITE_P( testing::Values( QCOTestCase{"AllocQubit", MQT_NAMED_BUILDER(allocQubitNoMeasure), MQT_NAMED_BUILDER(emptyQCO)}, - QCOTestCase{"StaticQubits", MQT_NAMED_BUILDER(staticQubitsNoMeasure), + QCOTestCase{"StaticQubitsNoMeasure", MQT_NAMED_BUILDER(staticQubitsNoMeasure), MQT_NAMED_BUILDER(emptyQCO)}, QCOTestCase{"StaticQubitsWithOps", MQT_NAMED_BUILDER(staticQubitsWithOps), From 2e9f4e67085ecfce32633b75d841561715eb275f Mon Sep 17 00:00:00 2001 From: Damian Rovara <93778306+DRovara@users.noreply.github.com> Date: Mon, 8 Jun 2026 10:57:51 +0200 Subject: [PATCH 24/26] Update mlir/unittests/programs/qco_programs.cpp Co-authored-by: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Signed-off-by: Damian Rovara <93778306+DRovara@users.noreply.github.com> --- mlir/unittests/programs/qco_programs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mlir/unittests/programs/qco_programs.cpp b/mlir/unittests/programs/qco_programs.cpp index 6c5cb9f68e..c120898fc1 100644 --- a/mlir/unittests/programs/qco_programs.cpp +++ b/mlir/unittests/programs/qco_programs.cpp @@ -37,8 +37,8 @@ measureAndReturn(mlir::qco::QCOProgramBuilder& b, namespace mlir::qco { std::pair, SmallVector> -emptyQCO([[maybe_unused]] QCOProgramBuilder& builder) { - return measureAndReturn(builder, {}); +emptyQCO(QCOProgramBuilder& b) { + return measureAndReturn(b, {}); } std::pair, SmallVector> From 29b0cbed1425576c21d0ec0dc985595f3575fec0 Mon Sep 17 00:00:00 2001 From: Damian Rovara <93778306+DRovara@users.noreply.github.com> Date: Mon, 8 Jun 2026 10:58:19 +0200 Subject: [PATCH 25/26] Update mlir/unittests/programs/qco_programs.h Co-authored-by: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Signed-off-by: Damian Rovara <93778306+DRovara@users.noreply.github.com> --- mlir/unittests/programs/qco_programs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/unittests/programs/qco_programs.h b/mlir/unittests/programs/qco_programs.h index c6f8d3b0e4..239d57d799 100644 --- a/mlir/unittests/programs/qco_programs.h +++ b/mlir/unittests/programs/qco_programs.h @@ -10,7 +10,7 @@ #pragma once -#include +#include #include From 225c88f761ce3c3eec9ab82c68ac7663f69a0aed Mon Sep 17 00:00:00 2001 From: Damian Rovara Date: Mon, 8 Jun 2026 11:19:51 +0200 Subject: [PATCH 26/26] style(mlir): :recycle: address some review comments --- mlir/include/mlir/Dialect/QCO/QCOUtils.h | 1 - mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp | 2 +- mlir/unittests/programs/qco_programs.h | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/QCOUtils.h b/mlir/include/mlir/Dialect/QCO/QCOUtils.h index b15c8a3752..9d844805a9 100644 --- a/mlir/include/mlir/Dialect/QCO/QCOUtils.h +++ b/mlir/include/mlir/Dialect/QCO/QCOUtils.h @@ -10,7 +10,6 @@ #pragma once -#include #include #include #include diff --git a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp index 1e39c1fabf..5d3e811b26 100644 --- a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp +++ b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp @@ -72,7 +72,7 @@ void QCOProgramBuilder::initialize(TypeRange returnTypes) { } void QCOProgramBuilder::retype(TypeRange returnTypes) { - auto mainFunc = dyn_cast(module).lookupSymbol("main"); + auto mainFunc = getEntryPoint(mlir::cast(module)); if (!mainFunc) { llvm::reportFatalUsageError("Main function not found for retyping"); } diff --git a/mlir/unittests/programs/qco_programs.h b/mlir/unittests/programs/qco_programs.h index 239d57d799..95b4634633 100644 --- a/mlir/unittests/programs/qco_programs.h +++ b/mlir/unittests/programs/qco_programs.h @@ -10,6 +10,7 @@ #pragma once +#include #include #include