diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a37ea0ab0..3a9780e81c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,9 +48,9 @@ releases may include breaking changes. [#1513], [#1521], [#1542], [#1548], [#1550], [#1554], [#1567], [#1569], [#1570], [#1572], [#1573], [#1580], [#1602], [#1620], [#1623], [#1624], [#1626], [#1627], [#1635], [#1638], [#1673], [#1675], [#1700], [#1710], - [#1717], [#1728], [#1730], [#1749], [#1751], [#1762], [#1765], [#1780], - [#1781], [#1782], [#1787], [#1806], [#1807], [#1808], [#1823], [#1824], - [#1830], [#1869], [#1872]) ([**@burgholzer**], [**@denialhaag**], + [#1717], [#1728], [#1730], [#1749], [#1751], [#1755], [#1762], [#1765], + [#1780], [#1781], [#1782], [#1787], [#1806], [#1807], [#1808], [#1823], + [#1824], [#1830], [#1869], [#1872]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**]) @@ -662,6 +662,7 @@ changelogs._ [#1766]: https://github.com/munich-quantum-toolkit/core/pull/1766 [#1765]: https://github.com/munich-quantum-toolkit/core/pull/1765 [#1762]: https://github.com/munich-quantum-toolkit/core/pull/1762 +[#1755]: https://github.com/munich-quantum-toolkit/core/pull/1755 [#1751]: https://github.com/munich-quantum-toolkit/core/pull/1751 [#1749]: https://github.com/munich-quantum-toolkit/core/pull/1749 [#1748]: https://github.com/munich-quantum-toolkit/core/pull/1748 diff --git a/bindings/ir/register_quantum_computation.cpp b/bindings/ir/register_quantum_computation.cpp index 618d52e7e4..3dc239b511 100644 --- a/bindings/ir/register_quantum_computation.cpp +++ b/bindings/ir/register_quantum_computation.cpp @@ -2003,15 +2003,17 @@ This method is equivalent to calling :meth:`measure` multiple times. qubits: The qubits to measure cbits: The classical bits to store the results)pb"); qc.def("measure_all", &qc::QuantumComputation::measureAll, nb::kw_only(), - "add_bits"_a = true, + "add_bits"_a = true, "add_barrier"_a = true, R"pb(Measure all qubits and store the results in classical bits. Details: If `add_bits` is `True`, a new classical register (named "`meas`") with the same size as the number of qubits will be added to the circuit and the results will be stored in it. If `add_bits` is `False`, the classical register must already exist and have a sufficient number of bits to store the results. + If `add_barrier` is `True`, a barrier is added before the measurements. Args: - add_bits: Whether to explicitly add a classical register)pb"); + add_bits: Whether to explicitly add a classical register + add_barrier: Whether to add a barrier before the measurements)pb"); qc.def("reset", nb::overload_cast(&qc::QuantumComputation::reset), "q"_a, R"pb(Add a reset operation to the circuit. diff --git a/include/mqt-core/ir/QuantumComputation.hpp b/include/mqt-core/ir/QuantumComputation.hpp index 68f2e295b1..92e426f982 100644 --- a/include/mqt-core/ir/QuantumComputation.hpp +++ b/include/mqt-core/ir/QuantumComputation.hpp @@ -322,11 +322,12 @@ class QuantumComputation { /** * @brief Add measurements to all qubits * @param addBits Whether to add new classical bits to the circuit + * @param addBarrier Whether to add a barrier before the measurements * @details This function adds measurements to all qubits in the circuit and * appends a new classical register (named "meas") to the circuit if addBits * is true. Otherwise, qubit q is measured into classical bit q. */ - void measureAll(bool addBits = true); + void measureAll(bool addBits = true, bool addBarrier = true); void bridge(const Targets& targets); diff --git a/include/mqt-core/qasm3/Parser.hpp b/include/mqt-core/qasm3/Parser.hpp index b93f679945..72831862da 100644 --- a/include/mqt-core/qasm3/Parser.hpp +++ b/include/mqt-core/qasm3/Parser.hpp @@ -114,7 +114,7 @@ class Parser final { std::shared_ptr parseBarrierStatement(); - std::shared_ptr parseDeclaration(bool isConst); + std::shared_ptr parseDeclaration(bool isConst, bool isOutput); std::shared_ptr parseGateDefinition(); diff --git a/include/mqt-core/qasm3/Statement.hpp b/include/mqt-core/qasm3/Statement.hpp index 258c7a7900..31f09b5ccb 100644 --- a/include/mqt-core/qasm3/Statement.hpp +++ b/include/mqt-core/qasm3/Statement.hpp @@ -347,15 +347,18 @@ class DeclarationStatement final public std::enable_shared_from_this { public: bool isConst; + bool isOutput; std::variant, std::shared_ptr> type; std::string identifier; std::shared_ptr expression; DeclarationStatement(std::shared_ptr debug, const bool declIsConst, - std::shared_ptr ty, std::string id, + bool declIsOutput, std::shared_ptr ty, + std::string id, std::shared_ptr expr) - : Statement(std::move(debug)), isConst(declIsConst), type(ty), - identifier(std::move(id)), expression(std::move(expr)) {} + : Statement(std::move(debug)), isConst(declIsConst), + isOutput(declIsOutput), type(ty), identifier(std::move(id)), + expression(std::move(expr)) {} void accept(InstVisitor* visitor) override; }; diff --git a/mlir/include/mlir/Conversion/QCToQIR/QIRCommon/QIRCommon.h b/mlir/include/mlir/Conversion/QCToQIR/QIRCommon/QIRCommon.h index 2434359f3a..ce1fcde8dc 100644 --- a/mlir/include/mlir/Conversion/QCToQIR/QIRCommon/QIRCommon.h +++ b/mlir/include/mlir/Conversion/QCToQIR/QIRCommon/QIRCommon.h @@ -67,6 +67,15 @@ struct LoweringState { Block* measurementsBlock{}; Block* outputBlock{}; + /// Set of MeasureOps whose results should be recorded in the output. + DenseSet returnedMeasurements; + + /// Set of array register names that should be recorded in the output. + DenseSet recordedArrays; + + /// Set of unnamed result indices that should be recorded in the output. + DenseSet recordedIndices; + /// The qubit allocation mode used in the module AllocationMode allocationMode = AllocationMode::Unset; @@ -152,4 +161,28 @@ void populateQCToQIRPatterns(RewritePatternSet& patterns, void addOutputRecording(LLVM::LLVMFuncOp& main, MLIRContext* ctx, LoweringState& state); +/** + * @brief Strips returned measurement results from function return statements + * + * @details + * Walks all `func::ReturnOp` operations in the module to identify operands + * that are directly defined by a `qc::MeasureOp`. For each such operand: + * - The defining `MeasureOp` is added to `state.returnedMeasurements` so that + * it will be included in the QIR output recording. + * - The operand is removed from the return statement. + * + * Non-measurement return values are preserved. After stripping, the enclosing + * `func::FuncOp` function type is updated to match the new return operands. + * + * This must be called **before** func-to-LLVM conversion, while + * `func::ReturnOp` and `qc::MeasureOp` are still in the IR. + * + * Return values that are indirectly computed from measurement outcomes remain + * unaffected. + * + * @param moduleOp The top-level module operation to walk + * @param state The lowering state; `returnedMeasurements` is populated + */ +void stripReturnedMeasurements(Operation* moduleOp, LoweringState& state); + } // namespace mlir diff --git a/mlir/include/mlir/Dialect/QC/Builder/QCProgramBuilder.h b/mlir/include/mlir/Dialect/QC/Builder/QCProgramBuilder.h index afb1225307..dee7248db0 100644 --- a/mlir/include/mlir/Dialect/QC/Builder/QCProgramBuilder.h +++ b/mlir/include/mlir/Dialect/QC/Builder/QCProgramBuilder.h @@ -70,7 +70,8 @@ class QCProgramBuilder 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 @@ -78,6 +79,23 @@ class QCProgramBuilder 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); + + /** + * @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 //===--------------------------------------------------------------------===// @@ -1145,17 +1163,49 @@ class QCProgramBuilder final : public ImplicitLocOpBuilder { OwningOpRef finalize(); /** - * @brief Convenience method for building quantum programs + * @brief Finalize the program with the given return values and return the + * constructed module + * @param returnValues Values representing the return values of the main + * function. + * + * @details + * Automatically deallocates all remaining valid qubits and tensors of qubits, + * adds a return statement with the given return values, 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 * @param buildFunc A function that takes a reference to a QCProgramBuilder * 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 and returned after this function completes. + * will be finalized using the returned Values after this function completes. + * @return The module containing the quantum program built by buildFunc. + */ + static OwningOpRef + build(MLIRContext* context, + const function_ref(QCProgramBuilder&)>& buildFunc); + + /** + * @brief Convenience method for building quantum programs with one return + * value. + * @param context The MLIR context to use for building the program + * @param buildFunc A function that takes a reference to a QCProgramBuilder + * and returns the single result value of the desired quantum program. * @return The module containing the quantum program built by buildFunc. */ static OwningOpRef build(MLIRContext* context, - const function_ref& buildFunc); + const function_ref& buildFunc); private: enum class AllocationMode : uint8_t { Unset, Static, Dynamic }; diff --git a/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h b/mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h index 425cccc9ae..d88e12dfa7 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,23 @@ 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); + + /** + * @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 //===--------------------------------------------------------------------===// @@ -387,7 +405,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++ @@ -397,7 +415,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 @@ -1453,17 +1471,49 @@ class QCOProgramBuilder final : public ImplicitLocOpBuilder { OwningOpRef finalize(); /** - * @brief Convenience method for building quantum programs + * @brief Finalize the program with the given return values and return the + * constructed module + * @param returnValues Values representing the return values of the main + * function. + * + * @details + * Automatically deallocates all remaining valid qubits and tensors of qubits, + * adds a return statement with the given return values, 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 * @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 and returned after this function completes. + * will be finalized using the returned Values after this function completes. + * @return The module containing the quantum program built by buildFunc. + */ + static OwningOpRef + build(MLIRContext* context, + const function_ref(QCOProgramBuilder&)>& buildFunc); + + /** + * @brief Convenience method for building quantum programs with one return + * value. + * @param context The MLIR context to use for building the program + * @param buildFunc A function that takes a reference to a QCOProgramBuilder + * and returns the single result value of the desired quantum program. * @return The module containing the quantum program built by buildFunc. */ static OwningOpRef build(MLIRContext* context, - const function_ref& buildFunc); + const function_ref& buildFunc); private: enum class AllocationMode : uint8_t { Unset, Static, Dynamic }; diff --git a/mlir/include/mlir/Dialect/QCO/IR/QCODialect.h b/mlir/include/mlir/Dialect/QCO/IR/QCODialect.h index 1b08a1715a..7c0ea4fab2 100644 --- a/mlir/include/mlir/Dialect/QCO/IR/QCODialect.h +++ b/mlir/include/mlir/Dialect/QCO/IR/QCODialect.h @@ -13,9 +13,6 @@ #include "mlir/Dialect/Utils/Utils.h" #include -#include -#include -#include #include #include #include @@ -142,35 +139,4 @@ template class TargetAndParameterArityTrait { }; }; -/** - * @brief Find the entry point function with entry_point attribute - * - * @details - * Searches for the function marked with the "entry_point" attribute in - * the passthrough attributes. If multiple functions are marked, returns the - * first one encountered. - * - * @param op The module operation to search in. - * @returns the entry point function, or nullptr if not found. - */ -inline func::FuncOp getEntryPoint(ModuleOp op) { - static constexpr StringRef PASSTHROUGH_LABEL = "passthrough"; - static constexpr StringRef ENTRY_POINT_LABEL = "entry_point"; - - const auto isEntry = [](Attribute attr) { - const auto strAttr = dyn_cast(attr); - return strAttr && strAttr.getValue() == ENTRY_POINT_LABEL; - }; - - for (auto func : op.getOps()) { - if (const auto passthrough = - func->getAttrOfType(PASSTHROUGH_LABEL); - passthrough && llvm::any_of(passthrough, isEntry)) { - return func; - } - } - - return nullptr; -} - } // namespace mlir::qco diff --git a/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td b/mlir/include/mlir/Dialect/QCO/IR/QCOOps.td index e1b86d79d0..a3ee7b405c 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); @@ -138,7 +137,7 @@ def MeasureOp : QCOOp<"measure"> { let hasVerifier = 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, @@ -150,8 +149,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) " @@ -506,7 +513,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. @@ -517,7 +525,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) " @@ -536,7 +544,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. @@ -547,7 +556,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) " @@ -566,7 +575,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. @@ -577,7 +587,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) " @@ -596,7 +606,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. @@ -607,7 +618,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); @@ -627,7 +638,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. @@ -638,7 +650,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); @@ -658,7 +670,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. @@ -669,7 +682,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); @@ -692,8 +705,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. @@ -704,9 +717,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) `,` " @@ -720,8 +732,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. @@ -732,9 +744,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) `,` " @@ -746,8 +757,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. @@ -758,9 +769,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) `,` " @@ -774,8 +784,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. @@ -786,9 +796,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) `,` " @@ -802,7 +811,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. @@ -813,10 +823,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) " @@ -835,7 +844,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. @@ -846,10 +856,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) " @@ -868,7 +877,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. @@ -879,10 +889,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) " @@ -901,7 +910,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. @@ -912,10 +922,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) " @@ -934,8 +943,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. @@ -946,11 +955,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) " @@ -970,8 +978,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. @@ -982,11 +990,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) " @@ -1006,7 +1013,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. @@ -1018,7 +1025,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)"; @@ -1058,7 +1065,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. @@ -1081,7 +1088,7 @@ def CtrlOp : QCOOp<"ctrl", traits = [UnitaryOpInterface, AttrSizedOperandSegments, AttrSizedResultSegments, SameOperandsAndResultType, SameOperandsAndResultShape, - SingleBlockImplicitTerminator<"YieldOp">, + SingleBlockImplicitTerminator<"YieldOp">, Pure, RecursiveMemoryEffects]> { let summary = "Add control qubits to a unitary operation"; let description = [{ @@ -1103,9 +1110,9 @@ def CtrlOp : QCOOp<"ctrl", ``` }]; - 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); @@ -1165,7 +1172,7 @@ def CtrlOp : QCOOp<"ctrl", def InvOp : QCOOp<"inv", traits = [UnitaryOpInterface, SingleBlockImplicitTerminator<"YieldOp">, - RecursiveMemoryEffects]> { + Pure, RecursiveMemoryEffects]> { let summary = "Invert a unitary operation"; let description = [{ A modifier operation that inverts the unitary operation defined in its body region. @@ -1184,9 +1191,8 @@ def InvOp : QCOOp<"inv", traits = [UnitaryOpInterface, ``` }]; - 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 = [{ @@ -1249,7 +1255,7 @@ def IfOp RegionBranchOpInterface, ["getNumRegionInvocations", "getRegionInvocationBounds", "getEntrySuccessorRegions"]>, - SingleBlock, SingleBlockImplicitTerminator<"YieldOp">, + SingleBlock, SingleBlockImplicitTerminator<"YieldOp">, Pure, RecursiveMemoryEffects]> { let summary = "If-then-else operation for linear (qubit) types"; diff --git a/mlir/include/mlir/Dialect/QIR/Builder/QIRProgramBuilder.h b/mlir/include/mlir/Dialect/QIR/Builder/QIRProgramBuilder.h index 65a4bf7dcf..3b0d025e82 100644 --- a/mlir/include/mlir/Dialect/QIR/Builder/QIRProgramBuilder.h +++ b/mlir/include/mlir/Dialect/QIR/Builder/QIRProgramBuilder.h @@ -100,6 +100,23 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder { */ void initialize(); + /** + * @brief Initialize the builder and prepare for program construction + * with specified return types. + * @param returnType The return type for the main function + * + * @details + * Creates a main function with an entry_point attribute. Must be called + * before adding operations. + */ + void initialize(Type returnType); + + /** + * @brief Modify the return type of the main function after initialization. + * @param returnType The new return type for the main function + */ + void retype(Type returnType); + //===--------------------------------------------------------------------===// // Constants //===--------------------------------------------------------------------===// @@ -304,6 +321,7 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder { * * @param qubit The qubit to measure * @param resultIndex The classical bit index for result pointer + * @param record Whether the measurement should be recorded in the output * @return An LLVM pointer to the measurement result * * @par Example: @@ -324,7 +342,7 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder { * !llvm.ptr) -> () * ``` */ - Value measure(Value qubit, int64_t resultIndex); + Value measure(Value qubit, int64_t resultIndex, bool record = true); /** * @brief Measure a qubit into a classical register @@ -337,6 +355,7 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder { * * @param qubit The qubit to measure * @param bit The classical bit to store the result + * @param record Whether the measurement should be recorded in the output * @return An LLVM pointer to the measurement result * * @par Example: @@ -360,7 +379,7 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder { * : (i64, !llvm.ptr, !llvm.ptr) -> () * ``` */ - Value measure(Value qubit, const Bit& bit); + Value measure(Value qubit, const Bit& bit, bool record = true); /** * @brief Reset a qubit to |0⟩ state @@ -1078,6 +1097,25 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder { */ OwningOpRef finalize(); + /** + * @brief Finalize the program with the given return value and return the + * constructed module + * @param returnValue The return value of the main function + * + * @details + * Automatically deallocates all remaining valid qubits and tensors of qubits, + * adds a return statement with the given return value, and + * transfers ownership of the module to the caller. The builder should not + * be used after calling this method. + * + * The return value must have the type 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(Value returnValue); + /** * @brief Convenience method for building quantum programs * @param context The MLIR context to use for building the program @@ -1085,11 +1123,12 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder { * 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 and returned after this function completes. + * @param profile The profile to use for the program. Defaults to Adaptive. * @return The module containing the quantum program built by buildFunc. */ static OwningOpRef build(MLIRContext* context, - const function_ref& buildFunc, + const function_ref& buildFunc, Profile profile = Profile::Adaptive); private: @@ -1135,6 +1174,12 @@ class QIRProgramBuilder final : public ImplicitLocOpBuilder { /// Map from result index to result pointer for non-register results DenseMap resultPtrs; + /// Set of array register names that should be recorded in the output. + DenseSet recordedArrays; + + /// Set of unnamed result indices that should be recorded in the output. + DenseSet recordedIndices; + /// Map from register to their loaded indices DenseMap> loadedQubits; diff --git a/mlir/include/mlir/Dialect/Utils/Utils.h b/mlir/include/mlir/Dialect/Utils/Utils.h index 4135ca1769..970ec6d90c 100644 --- a/mlir/include/mlir/Dialect/Utils/Utils.h +++ b/mlir/include/mlir/Dialect/Utils/Utils.h @@ -13,8 +13,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -268,4 +271,35 @@ inline void inlineModifierBody(Operation* op, Block& body, rewriter.replaceOp(op, results); } +/** + * @brief Find the entry point function with the entry_point attribute + * + * @details + * Searches for the function marked with the "entry_point" attribute in + * the passthrough attributes. If multiple functions are marked, returns the + * first one encountered. + * + * @param op The module operation to search in. + * @returns the entry point function, or nullptr if not found. + */ +inline func::FuncOp getEntryPoint(ModuleOp op) { + static constexpr StringRef PASSTHROUGH_LABEL = "passthrough"; + static constexpr StringRef ENTRY_POINT_LABEL = "entry_point"; + + const auto isEntry = [](Attribute attr) { + const auto strAttr = dyn_cast(attr); + return strAttr && strAttr.getValue() == ENTRY_POINT_LABEL; + }; + + for (auto func : op.getOps()) { + if (const auto passthrough = + func->getAttrOfType(PASSTHROUGH_LABEL); + passthrough && llvm::any_of(passthrough, isEntry)) { + return func; + } + } + + return nullptr; +} + } // namespace mlir::utils diff --git a/mlir/lib/Conversion/QCOToJeff/QCOToJeff.cpp b/mlir/lib/Conversion/QCOToJeff/QCOToJeff.cpp index e18452a780..0bb434e9e3 100644 --- a/mlir/lib/Conversion/QCOToJeff/QCOToJeff.cpp +++ b/mlir/lib/Conversion/QCOToJeff/QCOToJeff.cpp @@ -1194,16 +1194,11 @@ struct ConvertSCFForOpToJeff final : StatefulOpConversionPattern { * * @par Example: * ```mlir - * func.func @main() -> i64 attributes {passthrough = ["entry_point"]} { - * %0 = arith.constant 0 : i64 - * return %0 - * } + * func.func @main() -> i64 attributes {passthrough = ["entry_point"]} { ... } * ``` * is converted to * ```mlir - * func.func @main() -> () { - * return - * } + * func.func @main() -> i64 { ... } * ``` */ struct ConvertQCOMainToJeff final : StatefulOpConversionPattern { @@ -1236,17 +1231,11 @@ struct ConvertQCOMainToJeff final : StatefulOpConversionPattern { getState().entryPointName = op.getSymName(); - // Update function signature and remove passthrough attribute + // Remove passthrough attribute from function signature rewriter.startOpModification(op); - op.setType(FunctionType::get(rewriter.getContext(), {}, {})); op->removeAttr("passthrough"); rewriter.finalizeOpModification(op); - // Replace return operation - rewriter.setInsertionPointToEnd(block); - func::ReturnOp::create(rewriter, returnOp->getLoc()); - rewriter.eraseOp(returnOp); - return success(); } }; diff --git a/mlir/lib/Conversion/QCToQIR/QIRAdaptive/QCToQIRAdaptive.cpp b/mlir/lib/Conversion/QCToQIR/QIRAdaptive/QCToQIRAdaptive.cpp index 9b03e4d722..80a30c19bd 100644 --- a/mlir/lib/Conversion/QCToQIR/QIRAdaptive/QCToQIRAdaptive.cpp +++ b/mlir/lib/Conversion/QCToQIR/QIRAdaptive/QCToQIRAdaptive.cpp @@ -373,6 +373,9 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern { // Get result pointer Value result; + const bool shouldRecord = + state.returnedMeasurements.contains(op.getOperation()); + if (op.getRegisterName() && op.getRegisterSize() && op.getRegisterIndex()) { const auto registerName = op.getRegisterName().value(); const auto registerSize = @@ -380,6 +383,10 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern { const auto registerIndex = static_cast(op.getRegisterIndex().value()); + if (shouldRecord) { + state.recordedArrays.insert(state.stringSaver.save(registerName)); + } + // Create result register if it does not exist yet if (!resultArrays.contains(registerName)) { auto fnSig = LLVM::LLVMFunctionType::get( @@ -415,8 +422,12 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern { result = loadedResults.at({registerName, registerIndex}); } else { rewriter.setInsertionPoint(state.entryBlock->getTerminator()); - result = createPointerFromIndex(rewriter, op.getLoc(), resultPtrs.size()); - resultPtrs.try_emplace(resultPtrs.size(), result); + auto index = resultPtrs.size(); + if (shouldRecord) { + state.recordedIndices.insert(index); + } + result = createPointerFromIndex(rewriter, op.getLoc(), index); + resultPtrs.try_emplace(index, result); } rewriter.restoreInsertionPoint(savedInsertionPoint); @@ -620,7 +631,10 @@ struct QCToQIRAdaptive final : impl::QCToQIRAdaptiveBase { } } - // Stage 2: Convert func dialect to LLVM + // Stage 2.0: Strip returned measurements from func::ReturnOp + stripReturnedMeasurements(moduleOp, state); + + // Stage 2.1: Convert func dialect to LLVM { RewritePatternSet funcPatterns(ctx); target.addIllegalDialect(); diff --git a/mlir/lib/Conversion/QCToQIR/QIRBase/QCToQIRBase.cpp b/mlir/lib/Conversion/QCToQIR/QIRBase/QCToQIRBase.cpp index c7043422f1..1e5a392a92 100644 --- a/mlir/lib/Conversion/QCToQIR/QIRBase/QCToQIRBase.cpp +++ b/mlir/lib/Conversion/QCToQIR/QIRBase/QCToQIRBase.cpp @@ -220,6 +220,8 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern { // Get result pointer Value result; int64_t resultIndex = 0; + const bool shouldRecord = + state.returnedMeasurements.contains(op.getOperation()); const auto nresults = resultPtrs.size(); if (op.getRegisterIndex() && op.getRegisterName() && op.getRegisterSize()) { @@ -234,6 +236,10 @@ struct ConvertQCMeasureOp final : StatefulOpConversionPattern { resultIndex = static_cast(nresults); } + if (shouldRecord) { + state.recordedIndices.insert(resultIndex); + } + if (resultPtrs.contains(resultIndex)) { result = resultPtrs.at(resultIndex); } else { @@ -406,7 +412,12 @@ struct QCToQIRBase final : impl::QCToQIRBaseBase { target.addLegalDialect(); - // Stage 1: Convert func dialect to LLVM + LoweringState state; + + // Stage 1.0: Strip returned measurements from func::ReturnOp + stripReturnedMeasurements(moduleOp, state); + + // Stage 1.1: Convert func dialect to LLVM { RewritePatternSet funcPatterns(ctx); target.addIllegalDialect(); @@ -426,8 +437,6 @@ struct QCToQIRBase final : impl::QCToQIRBaseBase { return; } - LoweringState state; - // Stage 2: Create block structure ensureBlocks(main, state); diff --git a/mlir/lib/Conversion/QCToQIR/QIRCommon/QIRCommon.cpp b/mlir/lib/Conversion/QCToQIR/QIRCommon/QIRCommon.cpp index aea4ae0a02..1c5c70005c 100644 --- a/mlir/lib/Conversion/QCToQIR/QIRCommon/QIRCommon.cpp +++ b/mlir/lib/Conversion/QCToQIR/QIRCommon/QIRCommon.cpp @@ -15,6 +15,7 @@ #include "mlir/Dialect/QC/IR/QCOps.h" #include "mlir/Dialect/QIR/Utils/QIRUtils.h" +#include #include #include #include @@ -22,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -426,6 +429,9 @@ void addOutputRecording(LLVM::LLVMFuncOp& main, MLIRContext* ctx, auto fnDec = getOrCreateFunctionDeclaration(builder, main, QIR_RECORD_OUTPUT, fnSig); for (const auto& [index, ptr] : resultPtrs) { + if (!state.recordedIndices.contains(index)) { + continue; + } auto label = createResultLabel(builder, main, "__unnamed__" + std::to_string(index)) .getResult(); @@ -440,6 +446,9 @@ void addOutputRecording(LLVM::LLVMFuncOp& main, MLIRContext* ctx, auto fnDec = getOrCreateFunctionDeclaration(builder, main, QIR_ARRAY_RECORD_OUTPUT, fnSig); for (const auto& [name, results] : resultArrays) { + if (!state.recordedArrays.contains(name)) { + continue; + } auto size = results.getDefiningOp().getArraySize(); auto label = createResultLabel(builder, main, name).getResult(); LLVM::CallOp::create(builder, main->getLoc(), fnDec, @@ -463,4 +472,49 @@ void populateQCToQIRPatterns(RewritePatternSet& patterns, &state); } +void stripReturnedMeasurements(Operation* moduleOp, LoweringState& state) { + moduleOp->walk([&](func::FuncOp funcOp) { + // First, check if the given function is the main entrypoint or not. + auto passthrough = funcOp->getAttrOfType("passthrough"); + bool isEntryPoint = false; + if (passthrough) { + isEntryPoint = llvm::any_of(passthrough, [](Attribute attr) { + auto strAttr = dyn_cast(attr); + return strAttr && strAttr.getValue() == "entry_point"; + }); + } + if (!isEntryPoint) { + return; + } + + funcOp.walk([&](func::ReturnOp returnOp) { + SmallVector keptOperands; + SmallVector keptReturnTypes; + + for (auto operand : returnOp.getOperands()) { + if (auto measureOp = operand.getDefiningOp()) { + state.returnedMeasurements.insert(measureOp.getOperation()); + } else { + keptOperands.push_back(operand); + keptReturnTypes.push_back(operand.getType()); + } + } + + if (keptOperands.empty() && !returnOp.getOperands().empty()) { + OpBuilder builder(returnOp); + auto zero = + arith::ConstantIntOp::create(builder, returnOp.getLoc(), 0, 64); + keptOperands.push_back(zero); + keptReturnTypes.push_back(zero.getType()); + } + + returnOp.getOperandsMutable().assign(keptOperands); + + funcOp.setFunctionType(FunctionType::get( + funcOp.getContext(), funcOp.getFunctionType().getInputs(), + keptReturnTypes)); + }); + }); +} + } // namespace mlir diff --git a/mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp b/mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp index 9a0bba6b58..3a06d4b593 100644 --- a/mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp +++ b/mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -48,12 +47,14 @@ QCProgramBuilder::QCProgramBuilder(MLIRContext* context) ctx->loadDialect(); } -void QCProgramBuilder::initialize() { +void QCProgramBuilder::initialize() { initialize({getI64Type()}); } + +void QCProgramBuilder::initialize(TypeRange returnTypes) { // Set insertion point to the module body setInsertionPointToStart(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 @@ -66,6 +67,16 @@ void QCProgramBuilder::initialize() { regionStack.emplace_back(entryBlock.getParent()); } +void QCProgramBuilder::retype(TypeRange returnTypes) { + auto mainFunc = getEntryPoint(mlir::cast(module)); + if (!mainFunc) { + llvm::reportFatalUsageError("Main function not found for retyping"); + } + auto funcType = + getFunctionType(mainFunc.getFunctionType().getInputs(), returnTypes); + mainFunc.setType(funcType); +} + Value QCProgramBuilder::boolConstant(const bool value) { checkFinalized(); return arith::ConstantOp::create(*this, getBoolAttr(value)).getResult(); @@ -653,6 +664,13 @@ void QCProgramBuilder::ensureAllocationMode( OwningOpRef QCProgramBuilder::finalize() { checkFinalized(); + auto exitCode = intConstant(0); + return finalize({exitCode}); +} + +OwningOpRef QCProgramBuilder::finalize(ValueRange returnValues) { + checkFinalized(); + // Ensure that main function exists and insertion point is valid auto* insertionBlock = getInsertionBlock(); func::FuncOp mainFunc = nullptr; @@ -683,11 +701,8 @@ OwningOpRef QCProgramBuilder::finalize() { } allocatedMemrefs.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; @@ -698,11 +713,22 @@ OwningOpRef QCProgramBuilder::finalize() { OwningOpRef QCProgramBuilder::build( MLIRContext* context, - const function_ref& buildFunc) { + const function_ref(QCProgramBuilder&)>& buildFunc) { + QCProgramBuilder builder(context); + builder.initialize(); + auto result = buildFunc(builder); + builder.retype(ValueRange(result).getTypes()); + return builder.finalize(result); +} + +OwningOpRef QCProgramBuilder::build( + MLIRContext* context, + const function_ref& buildFunc) { QCProgramBuilder builder(context); builder.initialize(); - buildFunc(builder); - return builder.finalize(); + auto result = buildFunc(builder); + builder.retype(result.getType()); + return builder.finalize(result); } } // namespace mlir::qc diff --git a/mlir/lib/Dialect/QC/Translation/TranslateQASM3ToQC.cpp b/mlir/lib/Dialect/QC/Translation/TranslateQASM3ToQC.cpp index bfc7bfe989..eab7843753 100644 --- a/mlir/lib/Dialect/QC/Translation/TranslateQASM3ToQC.cpp +++ b/mlir/lib/Dialect/QC/Translation/TranslateQASM3ToQC.cpp @@ -220,7 +220,44 @@ class MLIRQasmImporter final : public qasm3::InstVisitor { } } - OwningOpRef finalize() { return builder.finalize(); } + OwningOpRef finalize() { + if (outputRegisters.empty()) { + outputRegisters = allBitRegisters; + } + + if (outputRegisters.empty()) { + return builder.finalize(); + } + + // Collect measurement results for all output bit registers + SmallVector returnValues; + for (const auto& regName : outputRegisters) { + auto it = bitValues.find(regName); + if (it == bitValues.end()) { + llvm::errs() << "Output register '" << regName + << "' was never measured.\n"; + return nullptr; + } + + auto expectedSize = classicalRegisters[regName].size; + if (it->second.size() < expectedSize) { + llvm::errs() << "Not all bits of output register '" << regName + << "' have been measured.\n"; + return nullptr; + } + for (auto bit : it->second) { + if (!bit) { + llvm::errs() << "Not all bits of output register '" << regName + << "' have been measured.\n"; + return nullptr; + } + returnValues.push_back(bit); + } + } + + builder.retype(ValueRange(returnValues).getTypes()); + return builder.finalize(returnValues); + } private: QCProgramBuilder builder; @@ -238,6 +275,12 @@ class MLIRQasmImporter final : public qasm3::InstVisitor { /// Map from classical-register name to measurement results. llvm::StringMap> bitValues; + /// Names of all bit registers, in declaration order. + SmallVector allBitRegisters; + + /// Names of classical registers declared as output, in declaration order. + SmallVector outputRegisters; + /// Map from gate identifier to OpenQASM 3 definition. llvm::StringMap> gates; @@ -361,6 +404,13 @@ class MLIRQasmImporter final : public qasm3::InstVisitor { case qasm3::Int: case qasm3::Uint: { classicalRegisters[id] = builder.allocClassicalBitRegister(size, id); + if (sizedType->type == qasm3::Bit) { + allBitRegisters.push_back(id); + if (stmt->isOutput || openQASM2CompatMode) { + // We return `output` bits in QASM3, or all named bits in QASM2. + outputRegisters.push_back(id); + } + } break; } default: diff --git a/mlir/lib/Dialect/QC/Translation/TranslateQuantumComputationToQC.cpp b/mlir/lib/Dialect/QC/Translation/TranslateQuantumComputationToQC.cpp index 7a2cf23651..4b798de54b 100644 --- a/mlir/lib/Dialect/QC/Translation/TranslateQuantumComputationToQC.cpp +++ b/mlir/lib/Dialect/QC/Translation/TranslateQuantumComputationToQC.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -729,7 +730,7 @@ static LogicalResult addIfElseOp(QCProgramBuilder& builder, * @brief Translates an operation from QuantumComputation to QC dialect * * @param builder The QCProgramBuilder used to create operations - * @param quantumComputation The quantum computation to translate + * @param operation The operation to translate * @param state The translation state * @return Success if all supported operations were translated */ @@ -849,7 +850,13 @@ OwningOpRef translateQuantumComputationToQC( MLIRContext* context, const ::qc::QuantumComputation& quantumComputation) { // Create and initialize the builder (creates module and main function) QCProgramBuilder builder(context); - builder.initialize(); + SmallVector resultTypes(quantumComputation.getNcbits(), + builder.getI1Type()); + if (quantumComputation.getNcbits() == 0) { + // Without classical bits, we instead return an exit code 0. + resultTypes.push_back(builder.getI64Type()); + } + builder.initialize(resultTypes); // Allocate quantum registers using the builder const auto qregs = allocateQregs(builder, quantumComputation); @@ -876,6 +883,13 @@ OwningOpRef translateQuantumComputationToQC( // Finalize and return the module (adds return statement and transfers // ownership) + if (quantumComputation.getNcbits() > 0) { + if (llvm::any_of(state.results, [](Value v) { return !v; })) { + llvm::errs() << "Not all classical bits were measured.\n"; + return nullptr; + } + return builder.finalize(state.results); + } return builder.finalize(); } diff --git a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp index 728f31f2b0..f766602a24 100644 --- a/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp +++ b/mlir/lib/Dialect/QCO/Builder/QCOProgramBuilder.cpp @@ -53,12 +53,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 @@ -70,6 +72,16 @@ void QCOProgramBuilder::initialize() { setInsertionPointToStart(&entryBlock); } +void QCOProgramBuilder::retype(TypeRange returnTypes) { + auto mainFunc = getEntryPoint(mlir::cast(module)); + 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(); @@ -401,7 +413,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); @@ -414,7 +427,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) { @@ -1146,6 +1159,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; @@ -1194,11 +1214,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; @@ -1208,11 +1225,22 @@ OwningOpRef QCOProgramBuilder::finalize() { OwningOpRef QCOProgramBuilder::build( MLIRContext* context, - const function_ref& buildFunc) { + const function_ref(QCOProgramBuilder&)>& buildFunc) { + QCOProgramBuilder builder(context); + builder.initialize(); + auto result = buildFunc(builder); + builder.retype(ValueRange(result).getTypes()); + return builder.finalize(result); +} + +OwningOpRef QCOProgramBuilder::build( + MLIRContext* context, + const function_ref& buildFunc) { QCOProgramBuilder builder(context); builder.initialize(); - buildFunc(builder); - return builder.finalize(); + auto result = buildFunc(builder); + builder.retype(result.getType()); + return builder.finalize(result); } } // namespace mlir::qco diff --git a/mlir/lib/Dialect/QCO/IR/QubitManagement/SinkOp.cpp b/mlir/lib/Dialect/QCO/IR/QubitManagement/SinkOp.cpp index ec8b33b833..c07fa324aa 100644 --- a/mlir/lib/Dialect/QCO/IR/QubitManagement/SinkOp.cpp +++ b/mlir/lib/Dialect/QCO/IR/QubitManagement/SinkOp.cpp @@ -8,15 +8,40 @@ * Licensed under the MIT License */ +#include "mlir/Dialect/QCO/IR/QCOInterfaces.h" #include "mlir/Dialect/QCO/IR/QCOOps.h" +#include +#include +#include #include +#include #include +#include +#include #include +#include using namespace mlir; using namespace mlir::qco; +/** + * @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. + */ +static bool checkDeadGate(Operation* op) { + if (!isMemoryEffectFree(op)) { + // This ignores operations 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 { /** @@ -39,9 +64,65 @@ struct RemoveAllocSinkPair final : OpRewritePattern { } }; +/** + * @brief Remove dead gates. + */ +struct DeadGateElimination final : OpRewritePattern { + + explicit DeadGateElimination(MLIRContext* context) + : OpRewritePattern(context) {} + + LogicalResult matchAndRewrite(SinkOp op, + PatternRewriter& rewriter) const override { + Value currentValue = op.getQubit(); + auto* currentOp = currentValue.getDefiningOp(); + auto success = false; + while (currentOp != nullptr) { + if (!checkDeadGate(currentOp)) { + break; + } + + currentValue = + TypeSwitch(currentOp) + .Case([&](auto measureOp) { + auto newValue = measureOp.getQubitIn(); + rewriter.replaceAllUsesWith(measureOp.getQubitOut(), newValue); + rewriter.eraseOp(measureOp); + return newValue; + }) + .Case([&](auto ifOp) { + auto* tiedQubit = + ifOp.getTiedQubit(cast(currentValue)); + auto newValue = tiedQubit->get(); + rewriter.replaceOp(ifOp, ifOp.getQubits()); + return newValue; + }) + .Case([&](auto resetOp) { + auto newValue = resetOp.getQubitIn(); + rewriter.replaceOp(resetOp, resetOp->getOperands()); + return newValue; + }) + .Case([&](auto unitaryOp) { + auto newValue = unitaryOp.getInputForOutput(currentValue); + rewriter.replaceOp(unitaryOp, unitaryOp.getInputQubits()); + return newValue; + }) + .Default([&](auto) { return nullptr; }); + + if (currentValue == nullptr) { + break; + } + currentOp = currentValue.getDefiningOp(); + success = true; + } + + return llvm::success(success); + } +}; + } // namespace void SinkOp::getCanonicalizationPatterns(RewritePatternSet& results, MLIRContext* context) { - results.add(context); + results.add(context); } diff --git a/mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp b/mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp index e93c14b180..8664675abb 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp @@ -10,7 +10,6 @@ #include "mlir/Dialect/QCO/Transforms/Mapping/Mapping.h" -#include "mlir/Dialect/QCO/IR/QCODialect.h" #include "mlir/Dialect/QCO/IR/QCOInterfaces.h" #include "mlir/Dialect/QCO/IR/QCOOps.h" #include "mlir/Dialect/QCO/Utils/Drivers.h" @@ -19,6 +18,7 @@ #include "mlir/Dialect/QCO/Utils/WireIterator.h" #include "mlir/Dialect/QTensor/IR/QTensorOps.h" #include "mlir/Dialect/QTensor/Utils/TensorIterator.h" +#include "mlir/Dialect/Utils/Utils.h" #include #include @@ -63,6 +63,7 @@ namespace mlir::qco { using namespace mlir::qtensor; +using namespace mlir::utils; #define GEN_PASS_DEF_MAPPINGPASS #include "mlir/Dialect/QCO/Transforms/Passes.h.inc" diff --git a/mlir/lib/Dialect/QIR/Builder/QIRProgramBuilder.cpp b/mlir/lib/Dialect/QIR/Builder/QIRProgramBuilder.cpp index 40b89cde52..0004d0ebfb 100644 --- a/mlir/lib/Dialect/QIR/Builder/QIRProgramBuilder.cpp +++ b/mlir/lib/Dialect/QIR/Builder/QIRProgramBuilder.cpp @@ -51,12 +51,14 @@ QIRProgramBuilder::QIRProgramBuilder(MLIRContext* context) getContext()->loadDialect(); } -void QIRProgramBuilder::initialize() { +void QIRProgramBuilder::initialize() { initialize(getI64Type()); } + +void QIRProgramBuilder::initialize(Type returnType) { // Set insertion point to the module body setInsertionPointToStart(cast(module).getBody()); // Create main function: () -> i64 - auto funcType = LLVM::LLVMFunctionType::get(getI64Type(), {}); + auto funcType = LLVM::LLVMFunctionType::get(returnType, {}); auto mainFuncOp = LLVM::LLVMFuncOp::create(*this, "main", funcType); mainFunc = mainFuncOp.getOperation(); @@ -87,7 +89,6 @@ void QIRProgramBuilder::initialize() { // Create exit code constant in entry block setInsertionPointToStart(entryBlock); - exitCode = intConstant(0); // Add initialize call auto initSig = LLVM::LLVMFunctionType::get(voidType, ptrType); @@ -99,14 +100,19 @@ void QIRProgramBuilder::initialize() { setInsertionPointToEnd(entryBlock); LLVM::BrOp::create(*this, bodyBlock); - // Return the exit code (success) in output block - setInsertionPointToEnd(outputBlock); - LLVM::ReturnOp::create(*this, exitCode); - // Set insertion point to body block for user operations setInsertionPointToStart(bodyBlock); } +void QIRProgramBuilder::retype(Type returnType) { + auto mainFn = dyn_cast(mainFunc); + if (!mainFn) { + llvm::reportFatalUsageError("Main function not found for retyping"); + } + auto funcType = LLVM::LLVMFunctionType::get(returnType, {}); + mainFn.setType(funcType); +} + Value QIRProgramBuilder::resolveIntVariant( const std::variant& variant) { if (std::holds_alternative(variant)) { @@ -349,7 +355,8 @@ QIRProgramBuilder::allocClassicalBitRegister(const int64_t size, return {.name = name, .size = size}; } -Value QIRProgramBuilder::measure(Value qubit, const int64_t resultIndex) { +Value QIRProgramBuilder::measure(Value qubit, const int64_t resultIndex, + bool record) { checkFinalized(); if (resultIndex < 0) { @@ -378,10 +385,14 @@ Value QIRProgramBuilder::measure(Value qubit, const int64_t resultIndex) { getOrCreateFunctionDeclaration(*this, module, QIR_MEASURE, mzSig); LLVM::CallOp::create(*this, mzDec, ValueRange{qubit, result}); + if (record) { + recordedIndices.insert(resultIndex); + } + return result; } -Value QIRProgramBuilder::measure(Value qubit, const Bit& bit) { +Value QIRProgramBuilder::measure(Value qubit, const Bit& bit, bool record) { checkFinalized(); const InsertionGuard guard(*this); @@ -400,6 +411,21 @@ Value QIRProgramBuilder::measure(Value qubit, const Bit& bit) { getOrCreateFunctionDeclaration(*this, module, QIR_MEASURE, fnSig); LLVM::CallOp::create(*this, fnDec, ValueRange{qubit, result}); + if (record) { + if (profile == Profile::Adaptive) { + recordedArrays.insert(stringSaver.save(bit.registerName)); + } else { + // In the base profile we don't have recorded arrays, so we need to + // find the index of the result and record that instead. + for (const auto& [index, ptr] : resultPtrs) { + if (ptr == result) { + recordedIndices.insert(index); + break; + } + } + } + } + return result; } @@ -951,6 +977,9 @@ void QIRProgramBuilder::generateOutputRecording() { getOrCreateFunctionDeclaration(*this, module, QIR_RECORD_OUTPUT, fnSig); // Create output recording for each result pointer for (const auto& [index, ptr] : resultPtrs) { + if (!recordedIndices.contains(index)) { + continue; + } auto label = createResultLabel(*this, module, "__unnamed__" + std::to_string(index)) .getResult(); @@ -965,6 +994,9 @@ void QIRProgramBuilder::generateOutputRecording() { QIR_ARRAY_RECORD_OUTPUT, fnSig); // Create output recording for each register for (const auto& [name, results] : resultArrays) { + if (!recordedArrays.contains(name)) { + continue; + } auto size = results.getDefiningOp().getArraySize(); auto label = createResultLabel(*this, module, name).getResult(); LLVM::CallOp::create(*this, fnDec, ValueRange{size, results, label}); @@ -975,10 +1007,21 @@ void QIRProgramBuilder::generateOutputRecording() { OwningOpRef QIRProgramBuilder::finalize() { checkFinalized(); + auto exitCode = intConstant(0); + return finalize(exitCode); +} + +OwningOpRef QIRProgramBuilder::finalize(Value returnValue) { + checkFinalized(); + // Save current insertion point const InsertionGuard guard(*this); const bool isAdaptive = (profile == Profile::Adaptive); + // Add return statement with the given return values to the main function + setInsertionPointToEnd(outputBlock); + LLVM::ReturnOp::create(*this, returnValue); + // Release resources in output block setInsertionPoint(outputBlock->getTerminator()); @@ -1034,12 +1077,13 @@ OwningOpRef QIRProgramBuilder::finalize() { OwningOpRef QIRProgramBuilder::build( MLIRContext* context, - const function_ref& buildFunc, Profile profile) { + const function_ref& buildFunc, Profile profile) { QIRProgramBuilder builder(context); builder.profile = profile; builder.initialize(); - buildFunc(builder); - return builder.finalize(); + auto result = buildFunc(builder); + builder.retype(result.getType()); + return builder.finalize(result); } } // namespace mlir::qir diff --git a/mlir/unittests/Compiler/test_compiler_pipeline.cpp b/mlir/unittests/Compiler/test_compiler_pipeline.cpp index ddc3e4ce4d..b67f8c7f96 100644 --- a/mlir/unittests/Compiler/test_compiler_pipeline.cpp +++ b/mlir/unittests/Compiler/test_compiler_pipeline.cpp @@ -34,8 +34,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -44,8 +46,13 @@ namespace mqt::test::compiler { -using QCProgramBuilderFn = NamedBuilder; -using QIRProgramBuilderFn = NamedBuilder; +using namespace mlir; +using namespace mlir::qc; +using namespace mlir::qco; +using namespace mlir::qir; + +using QCProgramBuilderFn = NamedMLIRBuilder; +using QIRProgramBuilderFn = NamedMLIRBuilder; using QuantumComputationBuilderFn = NamedBuilder<::qc::QuantumComputation>; namespace { @@ -82,46 +89,44 @@ std::ostream& operator<<(std::ostream& os, class CompilerPipelineTest : public testing::TestWithParam { protected: - std::unique_ptr context; + std::unique_ptr context; void SetUp() override { - mlir::DialectRegistry registry; - registry.insert(); - context = std::make_unique(); + DialectRegistry registry; + registry + .insert(); + context = std::make_unique(); context->appendDialectRegistry(registry); context->loadAllAvailableDialects(); } - [[nodiscard]] mlir::OwningOpRef + [[nodiscard]] OwningOpRef buildQCReference(const QCProgramBuilderFn builder) const { - auto module = mlir::qc::QCProgramBuilder::build(context.get(), builder.fn); + auto module = mqt::test::buildMLIRProgram(context.get(), builder); EXPECT_TRUE(runQCCleanupPipeline(module.get()).succeeded()); return module; } - [[nodiscard]] mlir::OwningOpRef + [[nodiscard]] OwningOpRef buildQIRReference(const QIRProgramBuilderFn builder) const { - auto module = mlir::qir::QIRProgramBuilder::build( - context.get(), builder.fn, - mlir::qir::QIRProgramBuilder::Profile::Adaptive); + auto module = mqt::test::buildMLIRProgram( + context.get(), builder, QIRProgramBuilder::Profile::Adaptive); EXPECT_TRUE(runQIRCleanupPipeline(module.get(), true).succeeded()); return module; } - [[nodiscard]] mlir::OwningOpRef + [[nodiscard]] OwningOpRef parseRecordedModule(const std::string& ir) const { - return mlir::parseSourceString(ir, context.get()); + return parseSourceString(ir, context.get()); } - static void runPipeline(const mlir::ModuleOp module, const bool convertToQIR, + static void runPipeline(const ModuleOp module, const bool convertToQIR, const bool disableMergeSingleQubitRotationGates, const bool enableHadamardLifting, - mlir::CompilationRecord& record) { - mlir::QuantumCompilerConfig config; + CompilationRecord& record) { + QuantumCompilerConfig config; config.convertToQIRAdaptive = convertToQIR; config.disableMergeSingleQubitRotationGates = disableMergeSingleQubitRotationGates; @@ -129,16 +134,16 @@ class CompilerPipelineTest config.recordIntermediates = true; config.printIRAfterAllStages = true; - mlir::QuantumCompilerPipeline pipeline(config); + QuantumCompilerPipeline pipeline(config); ASSERT_TRUE(pipeline.runPipeline(module, &record).succeeded()); } void expectEquivalent(const std::string& stage, const std::string& ir, - const mlir::ModuleOp expected) const { + const ModuleOp expected) const { auto actual = parseRecordedModule(ir); ASSERT_TRUE(actual) << stage << " failed to parse"; - EXPECT_TRUE(mlir::verify(*actual).succeeded()); - EXPECT_TRUE(mlir::verify(expected).succeeded()); + EXPECT_TRUE(verify(*actual).succeeded()); + EXPECT_TRUE(verify(expected).succeeded()); EXPECT_TRUE(areModulesEquivalentWithPermutations(actual.get(), expected)); } }; @@ -150,25 +155,25 @@ TEST_P(CompilerPipelineTest, EndToEndPipeline) { const auto name = " (" + testCase.name + ")"; DeferredPrinter printer; - mlir::OwningOpRef module; + OwningOpRef module; if (testCase.startFromQuantumComputation) { ASSERT_TRUE(testCase.quantumComputationBuilder); ::qc::QuantumComputation comp; testCase.quantumComputationBuilder.fn(comp); - module = mlir::translateQuantumComputationToQC(context.get(), comp); + module = translateQuantumComputationToQC(context.get(), comp); ASSERT_TRUE(module); printer.record(module.get(), "QC Import" + name); } else { ASSERT_TRUE(testCase.qcProgramBuilder); - module = mlir::qc::QCProgramBuilder::build(context.get(), - testCase.qcProgramBuilder.fn); + module = + mqt::test::buildMLIRProgram(context.get(), testCase.qcProgramBuilder); ASSERT_TRUE(module); printer.record(module.get(), "QC Input" + name); } - EXPECT_TRUE(mlir::verify(*module).succeeded()); + EXPECT_TRUE(verify(*module).succeeded()); - mlir::CompilationRecord record; + CompilationRecord record; runPipeline(module.get(), testCase.convertToQIR, false, false, record); ASSERT_TRUE(testCase.qcReferenceBuilder); @@ -207,15 +212,16 @@ TEST_P(CompilerPipelineTest, EndToEndPipeline) { * Correctness of the pass is tested in a dedicated test. */ TEST_F(CompilerPipelineTest, RotationGateMergingPass) { - auto module = mlir::qc::QCProgramBuilder::build( - context.get(), [&](mlir::qc::QCProgramBuilder& b) { + auto module = + QCProgramBuilder::build(context.get(), [&](QCProgramBuilder& b) { auto q = b.allocQubit(); b.rz(1.0, q); b.rx(1.0, q); + return b.measure(q); }); ASSERT_TRUE(module); - mlir::CompilationRecord record; + CompilationRecord record; runPipeline(module.get(), false, false, false, record); // The outputs must differ, proving the pass ran and transformed the IR @@ -230,15 +236,16 @@ TEST_F(CompilerPipelineTest, RotationGateMergingPass) { * Correctness of the pass is tested in a dedicated test. */ TEST_F(CompilerPipelineTest, HadamardLiftingPass) { - auto module = mlir::qc::QCProgramBuilder::build( - context.get(), [&](mlir::qc::QCProgramBuilder& b) { + auto module = + QCProgramBuilder::build(context.get(), [&](QCProgramBuilder& b) { auto q = b.allocQubit(); b.x(q); b.h(q); + return b.measure(q); }); ASSERT_TRUE(module); - mlir::CompilationRecord record; + CompilationRecord record; runPipeline(module.get(), false, true, true, record); // The outputs must differ, proving the pass ran and transformed the IR @@ -277,419 +284,431 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(mlir::qc::staticQubitsWithInv), MQT_NAMED_BUILDER(mlir::qc::staticQubitsWithInv), MQT_NAMED_BUILDER(mlir::qir::staticQubitsWithInv), false}, - CompilerPipelineTestCase{"AllocQubit", - MQT_NAMED_BUILDER(qc::allocQubit), nullptr, - MQT_NAMED_BUILDER(mlir::qc::emptyQC), - MQT_NAMED_BUILDER(mlir::qir::emptyQIR)}, - CompilerPipelineTestCase{"AllocQubitRegister", - MQT_NAMED_BUILDER(qc::allocQubitRegister), - nullptr, MQT_NAMED_BUILDER(mlir::qc::emptyQC), - MQT_NAMED_BUILDER(mlir::qir::emptyQIR)}, + CompilerPipelineTestCase{ + "AllocQubit", MQT_NAMED_BUILDER(::qc::allocQubit), nullptr, + MQT_NAMED_BUILDER(mlir::qc::alloc1QubitRegister), + MQT_NAMED_BUILDER(mlir::qir::alloc1QubitRegister)}, + CompilerPipelineTestCase{ + "AllocQubitRegister", MQT_NAMED_BUILDER(::qc::allocQubitRegister), + nullptr, MQT_NAMED_BUILDER(mlir::qc::allocQubitRegister), + MQT_NAMED_BUILDER(mlir::qir::allocQubitRegister)}, CompilerPipelineTestCase{ "AllocMultipleQubitRegisters", - MQT_NAMED_BUILDER(qc::allocMultipleQubitRegisters), nullptr, - MQT_NAMED_BUILDER(mlir::qc::emptyQC), - MQT_NAMED_BUILDER(mlir::qir::emptyQIR)}, - CompilerPipelineTestCase{"AllocLargeRegister", - MQT_NAMED_BUILDER(qc::allocLargeRegister), - nullptr, MQT_NAMED_BUILDER(mlir::qc::emptyQC), - MQT_NAMED_BUILDER(mlir::qir::emptyQIR)}, + MQT_NAMED_BUILDER(::qc::allocMultipleQubitRegisters), nullptr, + MQT_NAMED_BUILDER(mlir::qc::allocMultipleQubitRegisters), + MQT_NAMED_BUILDER(mlir::qir::allocMultipleQubitRegisters)}, + CompilerPipelineTestCase{ + "AllocLargeRegister", MQT_NAMED_BUILDER(::qc::allocLargeRegister), + nullptr, MQT_NAMED_BUILDER(mlir::qc::allocLargeRegister), + MQT_NAMED_BUILDER(mlir::qir::allocQubitRegister)}, CompilerPipelineTestCase{ "SingleMeasurementToSingleBit", - MQT_NAMED_BUILDER(qc::singleMeasurementToSingleBit), nullptr, + MQT_NAMED_BUILDER(::qc::singleMeasurementToSingleBit), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleMeasurementToSingleBit), - MQT_NAMED_BUILDER(mlir::qir::singleMeasurementToSingleBit)}, + MQT_NAMED_BUILDER(mlir::qir::singleMeasurementToSingleBit)}, CompilerPipelineTestCase{ "RepeatedMeasurementToSameBit", - MQT_NAMED_BUILDER(qc::repeatedMeasurementToSameBit), nullptr, + MQT_NAMED_BUILDER(::qc::repeatedMeasurementToSameBit), nullptr, MQT_NAMED_BUILDER(mlir::qc::repeatedMeasurementToSameBit), - MQT_NAMED_BUILDER(mlir::qir::repeatedMeasurementToSameBit)}, + MQT_NAMED_BUILDER(mlir::qir::repeatedMeasurementToSameBit)}, CompilerPipelineTestCase{ "RepeatedMeasurementToDifferentBits", - MQT_NAMED_BUILDER(qc::repeatedMeasurementToDifferentBits), nullptr, + MQT_NAMED_BUILDER(::qc::repeatedMeasurementToDifferentBits), + nullptr, MQT_NAMED_BUILDER(mlir::qc::repeatedMeasurementToDifferentBits), - MQT_NAMED_BUILDER(mlir::qir::repeatedMeasurementToDifferentBits)}, + MQT_NAMED_BUILDER( + mlir::qir::repeatedMeasurementToDifferentBits)}, CompilerPipelineTestCase{ "MultipleClassicalRegistersAndMeasurements", - MQT_NAMED_BUILDER(qc::multipleClassicalRegistersAndMeasurements), + MQT_NAMED_BUILDER(::qc::multipleClassicalRegistersAndMeasurements), nullptr, MQT_NAMED_BUILDER( mlir::qc::multipleClassicalRegistersAndMeasurements), MQT_NAMED_BUILDER( - mlir::qir::multipleClassicalRegistersAndMeasurements)}, + mlir::qir::multipleClassicalRegistersAndMeasurements)}, CompilerPipelineTestCase{ "MeasurementWithoutRegisters", nullptr, MQT_NAMED_BUILDER(mlir::qc::measurementWithoutRegisters), MQT_NAMED_BUILDER(mlir::qc::measurementWithoutRegisters), - MQT_NAMED_BUILDER(mlir::qir::measurementWithoutRegisters), false}, + MQT_NAMED_BUILDER(mlir::qir::measurementWithoutRegisters), + false}, CompilerPipelineTestCase{ "ResetQubitAfterSingleOp", - MQT_NAMED_BUILDER(qc::resetQubitAfterSingleOp), nullptr, + MQT_NAMED_BUILDER(::qc::resetQubitAfterSingleOp), nullptr, MQT_NAMED_BUILDER(mlir::qc::resetQubitAfterSingleOp), - MQT_NAMED_BUILDER(mlir::qir::resetQubitAfterSingleOp)}, + MQT_NAMED_BUILDER(mlir::qir::resetQubitAfterSingleOp)}, CompilerPipelineTestCase{ "ResetMultipleQubitsAfterSingleOp", - MQT_NAMED_BUILDER(qc::resetMultipleQubitsAfterSingleOp), nullptr, + MQT_NAMED_BUILDER(::qc::resetMultipleQubitsAfterSingleOp), nullptr, MQT_NAMED_BUILDER(mlir::qc::resetMultipleQubitsAfterSingleOp), - MQT_NAMED_BUILDER(mlir::qir::resetMultipleQubitsAfterSingleOp)}, + MQT_NAMED_BUILDER( + mlir::qir::resetMultipleQubitsAfterSingleOp)}, CompilerPipelineTestCase{ "RepeatedResetAfterSingleOp", - MQT_NAMED_BUILDER(qc::repeatedResetAfterSingleOp), nullptr, + MQT_NAMED_BUILDER(::qc::repeatedResetAfterSingleOp), nullptr, MQT_NAMED_BUILDER(mlir::qc::resetQubitAfterSingleOp), - MQT_NAMED_BUILDER(mlir::qir::resetQubitAfterSingleOp)}, - CompilerPipelineTestCase{"GlobalPhase", - MQT_NAMED_BUILDER(qc::globalPhase), nullptr, - MQT_NAMED_BUILDER(mlir::qc::globalPhase), - MQT_NAMED_BUILDER(mlir::qir::globalPhase)}, - CompilerPipelineTestCase{"Identity", MQT_NAMED_BUILDER(qc::identity), - nullptr, MQT_NAMED_BUILDER(mlir::qc::emptyQC), - MQT_NAMED_BUILDER(mlir::qir::emptyQIR)}, + MQT_NAMED_BUILDER(mlir::qir::resetQubitAfterSingleOp)}, + CompilerPipelineTestCase{ + "GlobalPhase", MQT_NAMED_BUILDER(::qc::globalPhase), nullptr, + MQT_NAMED_BUILDER(mlir::qc::globalPhase), + MQT_NAMED_BUILDER(mlir::qir::globalPhase)}, + CompilerPipelineTestCase{ + "Identity", MQT_NAMED_BUILDER(::qc::identity), nullptr, + MQT_NAMED_BUILDER(mlir::qc::alloc1QubitRegister), + MQT_NAMED_BUILDER(mlir::qir::alloc1QubitRegister)}, CompilerPipelineTestCase{ "SingleControlledIdentity", - MQT_NAMED_BUILDER(qc::singleControlledIdentity), nullptr, - MQT_NAMED_BUILDER(mlir::qc::emptyQC), - MQT_NAMED_BUILDER(mlir::qir::emptyQIR)}, + MQT_NAMED_BUILDER(::qc::singleControlledIdentity), nullptr, + MQT_NAMED_BUILDER(mlir::qc::allocQubitRegister), + MQT_NAMED_BUILDER(mlir::qir::allocQubitRegister)}, CompilerPipelineTestCase{ "MultipleControlledIdentity", - MQT_NAMED_BUILDER(qc::multipleControlledIdentity), nullptr, - MQT_NAMED_BUILDER(mlir::qc::emptyQC), - MQT_NAMED_BUILDER(mlir::qir::emptyQIR)}, - CompilerPipelineTestCase{"X", MQT_NAMED_BUILDER(qc::x), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledIdentity), nullptr, + MQT_NAMED_BUILDER(mlir::qc::alloc3QubitRegister), + MQT_NAMED_BUILDER(mlir::qir::alloc3QubitRegister)}, + CompilerPipelineTestCase{"X", MQT_NAMED_BUILDER(::qc::x), nullptr, MQT_NAMED_BUILDER(mlir::qc::x), - MQT_NAMED_BUILDER(mlir::qir::x)}, + MQT_NAMED_BUILDER(mlir::qir::x)}, CompilerPipelineTestCase{ - "SingleControlledX", MQT_NAMED_BUILDER(qc::singleControlledX), + "SingleControlledX", MQT_NAMED_BUILDER(::qc::singleControlledX), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledX), - MQT_NAMED_BUILDER(mlir::qir::singleControlledX)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledX)}, CompilerPipelineTestCase{ - "MultipleControlledX", MQT_NAMED_BUILDER(qc::multipleControlledX), + "MultipleControlledX", MQT_NAMED_BUILDER(::qc::multipleControlledX), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledX), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledX)}, - CompilerPipelineTestCase{"Y", MQT_NAMED_BUILDER(qc::y), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledX)}, + CompilerPipelineTestCase{"Y", MQT_NAMED_BUILDER(::qc::y), nullptr, MQT_NAMED_BUILDER(mlir::qc::y), - MQT_NAMED_BUILDER(mlir::qir::y)}, + MQT_NAMED_BUILDER(mlir::qir::y)}, CompilerPipelineTestCase{ - "SingleControlledY", MQT_NAMED_BUILDER(qc::singleControlledY), + "SingleControlledY", MQT_NAMED_BUILDER(::qc::singleControlledY), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledY), - MQT_NAMED_BUILDER(mlir::qir::singleControlledY)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledY)}, CompilerPipelineTestCase{ - "MultipleControlledY", MQT_NAMED_BUILDER(qc::multipleControlledY), + "MultipleControlledY", MQT_NAMED_BUILDER(::qc::multipleControlledY), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledY), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledY)}, - CompilerPipelineTestCase{"Z", MQT_NAMED_BUILDER(qc::z), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledY)}, + CompilerPipelineTestCase{"Z", MQT_NAMED_BUILDER(::qc::z), nullptr, MQT_NAMED_BUILDER(mlir::qc::z), - MQT_NAMED_BUILDER(mlir::qir::z)}, + MQT_NAMED_BUILDER(mlir::qir::z)}, CompilerPipelineTestCase{ - "SingleControlledZ", MQT_NAMED_BUILDER(qc::singleControlledZ), + "SingleControlledZ", MQT_NAMED_BUILDER(::qc::singleControlledZ), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledZ), - MQT_NAMED_BUILDER(mlir::qir::singleControlledZ)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledZ)}, CompilerPipelineTestCase{ - "MultipleControlledZ", MQT_NAMED_BUILDER(qc::multipleControlledZ), + "MultipleControlledZ", MQT_NAMED_BUILDER(::qc::multipleControlledZ), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledZ), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledZ)}, - CompilerPipelineTestCase{"H", MQT_NAMED_BUILDER(qc::h), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledZ)}, + CompilerPipelineTestCase{"H", MQT_NAMED_BUILDER(::qc::h), nullptr, MQT_NAMED_BUILDER(mlir::qc::h), - MQT_NAMED_BUILDER(mlir::qir::h)}, + MQT_NAMED_BUILDER(mlir::qir::h)}, CompilerPipelineTestCase{ - "SingleControlledH", MQT_NAMED_BUILDER(qc::singleControlledH), + "SingleControlledH", MQT_NAMED_BUILDER(::qc::singleControlledH), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledH), - MQT_NAMED_BUILDER(mlir::qir::singleControlledH)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledH)}, CompilerPipelineTestCase{ - "MultipleControlledH", MQT_NAMED_BUILDER(qc::multipleControlledH), + "MultipleControlledH", MQT_NAMED_BUILDER(::qc::multipleControlledH), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledH), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledH)}, - CompilerPipelineTestCase{"HWithoutRegister", nullptr, - MQT_NAMED_BUILDER(mlir::qc::hWithoutRegister), - MQT_NAMED_BUILDER(mlir::qc::hWithoutRegister), - MQT_NAMED_BUILDER(mlir::qir::hWithoutRegister), - false}, - CompilerPipelineTestCase{"S", MQT_NAMED_BUILDER(qc::s), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledH)}, + CompilerPipelineTestCase{ + "HWithoutRegister", nullptr, + MQT_NAMED_BUILDER(mlir::qc::hWithoutRegister), + MQT_NAMED_BUILDER(mlir::qc::hWithoutRegister), + MQT_NAMED_BUILDER(mlir::qir::hWithoutRegister), false}, + CompilerPipelineTestCase{"S", MQT_NAMED_BUILDER(::qc::s), nullptr, MQT_NAMED_BUILDER(mlir::qc::s), - MQT_NAMED_BUILDER(mlir::qir::s)}, + MQT_NAMED_BUILDER(mlir::qir::s)}, CompilerPipelineTestCase{ - "SingleControlledS", MQT_NAMED_BUILDER(qc::singleControlledS), + "SingleControlledS", MQT_NAMED_BUILDER(::qc::singleControlledS), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledS), - MQT_NAMED_BUILDER(mlir::qir::singleControlledS)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledS)}, CompilerPipelineTestCase{ - "MultipleControlledS", MQT_NAMED_BUILDER(qc::multipleControlledS), + "MultipleControlledS", MQT_NAMED_BUILDER(::qc::multipleControlledS), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledS), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledS)}, - CompilerPipelineTestCase{"Sdg", MQT_NAMED_BUILDER(qc::sdg), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledS)}, + CompilerPipelineTestCase{"Sdg", MQT_NAMED_BUILDER(::qc::sdg), nullptr, MQT_NAMED_BUILDER(mlir::qc::sdg), - MQT_NAMED_BUILDER(mlir::qir::sdg)}, + MQT_NAMED_BUILDER(mlir::qir::sdg)}, CompilerPipelineTestCase{ - "SingleControlledSdg", MQT_NAMED_BUILDER(qc::singleControlledSdg), + "SingleControlledSdg", MQT_NAMED_BUILDER(::qc::singleControlledSdg), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledSdg), - MQT_NAMED_BUILDER(mlir::qir::singleControlledSdg)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledSdg)}, CompilerPipelineTestCase{ "MultipleControlledSdg", - MQT_NAMED_BUILDER(qc::multipleControlledSdg), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledSdg), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledSdg), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledSdg)}, - CompilerPipelineTestCase{"T", MQT_NAMED_BUILDER(qc::t_), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledSdg)}, + CompilerPipelineTestCase{"T", MQT_NAMED_BUILDER(::qc::t_), nullptr, MQT_NAMED_BUILDER(mlir::qc::t_), - MQT_NAMED_BUILDER(mlir::qir::t_)}, + MQT_NAMED_BUILDER(mlir::qir::t_)}, CompilerPipelineTestCase{ - "SingleControlledT", MQT_NAMED_BUILDER(qc::singleControlledT), + "SingleControlledT", MQT_NAMED_BUILDER(::qc::singleControlledT), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledT), - MQT_NAMED_BUILDER(mlir::qir::singleControlledT)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledT)}, CompilerPipelineTestCase{ - "MultipleControlledT", MQT_NAMED_BUILDER(qc::multipleControlledT), + "MultipleControlledT", MQT_NAMED_BUILDER(::qc::multipleControlledT), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledT), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledT)}, - CompilerPipelineTestCase{"Tdg", MQT_NAMED_BUILDER(qc::tdg), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledT)}, + CompilerPipelineTestCase{"Tdg", MQT_NAMED_BUILDER(::qc::tdg), nullptr, MQT_NAMED_BUILDER(mlir::qc::tdg), - MQT_NAMED_BUILDER(mlir::qir::tdg)}, + MQT_NAMED_BUILDER(mlir::qir::tdg)}, CompilerPipelineTestCase{ - "SingleControlledTdg", MQT_NAMED_BUILDER(qc::singleControlledTdg), + "SingleControlledTdg", MQT_NAMED_BUILDER(::qc::singleControlledTdg), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledTdg), - MQT_NAMED_BUILDER(mlir::qir::singleControlledTdg)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledTdg)}, CompilerPipelineTestCase{ "MultipleControlledTdg", - MQT_NAMED_BUILDER(qc::multipleControlledTdg), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledTdg), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledTdg), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledTdg)}, - CompilerPipelineTestCase{"SX", MQT_NAMED_BUILDER(qc::sx), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledTdg)}, + CompilerPipelineTestCase{"SX", MQT_NAMED_BUILDER(::qc::sx), nullptr, MQT_NAMED_BUILDER(mlir::qc::sx), - MQT_NAMED_BUILDER(mlir::qir::sx)}, + MQT_NAMED_BUILDER(mlir::qir::sx)}, CompilerPipelineTestCase{ - "SingleControlledSX", MQT_NAMED_BUILDER(qc::singleControlledSx), + "SingleControlledSX", MQT_NAMED_BUILDER(::qc::singleControlledSx), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledSx), - MQT_NAMED_BUILDER(mlir::qir::singleControlledSx)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledSx)}, CompilerPipelineTestCase{ - "MultipleControlledSX", MQT_NAMED_BUILDER(qc::multipleControlledSx), - nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledSx), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledSx)}, - CompilerPipelineTestCase{"SXdg", MQT_NAMED_BUILDER(qc::sxdg), nullptr, + "MultipleControlledSX", + MQT_NAMED_BUILDER(::qc::multipleControlledSx), nullptr, + MQT_NAMED_BUILDER(mlir::qc::multipleControlledSx), + MQT_NAMED_BUILDER(mlir::qir::multipleControlledSx)}, + CompilerPipelineTestCase{"SXdg", MQT_NAMED_BUILDER(::qc::sxdg), nullptr, MQT_NAMED_BUILDER(mlir::qc::sxdg), - MQT_NAMED_BUILDER(mlir::qir::sxdg)}, + MQT_NAMED_BUILDER(mlir::qir::sxdg)}, CompilerPipelineTestCase{ - "SingleControlledSXdg", MQT_NAMED_BUILDER(qc::singleControlledSxdg), - nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledSxdg), - MQT_NAMED_BUILDER(mlir::qir::singleControlledSxdg)}, + "SingleControlledSXdg", + MQT_NAMED_BUILDER(::qc::singleControlledSxdg), nullptr, + MQT_NAMED_BUILDER(mlir::qc::singleControlledSxdg), + MQT_NAMED_BUILDER(mlir::qir::singleControlledSxdg)}, CompilerPipelineTestCase{ "MultipleControlledSXdg", - MQT_NAMED_BUILDER(qc::multipleControlledSxdg), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledSxdg), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledSxdg), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledSxdg)}, - CompilerPipelineTestCase{"RX", MQT_NAMED_BUILDER(qc::rx), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledSxdg)}, + CompilerPipelineTestCase{"RX", MQT_NAMED_BUILDER(::qc::rx), nullptr, MQT_NAMED_BUILDER(mlir::qc::rx), - MQT_NAMED_BUILDER(mlir::qir::rx)}, + MQT_NAMED_BUILDER(mlir::qir::rx)}, CompilerPipelineTestCase{ - "SingleControlledRX", MQT_NAMED_BUILDER(qc::singleControlledRx), + "SingleControlledRX", MQT_NAMED_BUILDER(::qc::singleControlledRx), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledRx), - MQT_NAMED_BUILDER(mlir::qir::singleControlledRx)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledRx)}, CompilerPipelineTestCase{ - "MultipleControlledRX", MQT_NAMED_BUILDER(qc::multipleControlledRx), - nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledRx), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledRx)}, - CompilerPipelineTestCase{"RY", MQT_NAMED_BUILDER(qc::ry), nullptr, + "MultipleControlledRX", + MQT_NAMED_BUILDER(::qc::multipleControlledRx), nullptr, + MQT_NAMED_BUILDER(mlir::qc::multipleControlledRx), + MQT_NAMED_BUILDER(mlir::qir::multipleControlledRx)}, + CompilerPipelineTestCase{"RY", MQT_NAMED_BUILDER(::qc::ry), nullptr, MQT_NAMED_BUILDER(mlir::qc::ry), - MQT_NAMED_BUILDER(mlir::qir::ry)}, + MQT_NAMED_BUILDER(mlir::qir::ry)}, CompilerPipelineTestCase{ - "SingleControlledRY", MQT_NAMED_BUILDER(qc::singleControlledRy), + "SingleControlledRY", MQT_NAMED_BUILDER(::qc::singleControlledRy), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledRy), - MQT_NAMED_BUILDER(mlir::qir::singleControlledRy)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledRy)}, CompilerPipelineTestCase{ - "MultipleControlledRY", MQT_NAMED_BUILDER(qc::multipleControlledRy), - nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledRy), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledRy)}, - CompilerPipelineTestCase{"RZ", MQT_NAMED_BUILDER(qc::rz), nullptr, + "MultipleControlledRY", + MQT_NAMED_BUILDER(::qc::multipleControlledRy), nullptr, + MQT_NAMED_BUILDER(mlir::qc::multipleControlledRy), + MQT_NAMED_BUILDER(mlir::qir::multipleControlledRy)}, + CompilerPipelineTestCase{"RZ", MQT_NAMED_BUILDER(::qc::rz), nullptr, MQT_NAMED_BUILDER(mlir::qc::rz), - MQT_NAMED_BUILDER(mlir::qir::rz)}, + MQT_NAMED_BUILDER(mlir::qir::rz)}, CompilerPipelineTestCase{ - "SingleControlledRZ", MQT_NAMED_BUILDER(qc::singleControlledRz), + "SingleControlledRZ", MQT_NAMED_BUILDER(::qc::singleControlledRz), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledRz), - MQT_NAMED_BUILDER(mlir::qir::singleControlledRz)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledRz)}, CompilerPipelineTestCase{ - "MultipleControlledRZ", MQT_NAMED_BUILDER(qc::multipleControlledRz), - nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledRz), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledRz)}, - CompilerPipelineTestCase{"P", MQT_NAMED_BUILDER(qc::p), nullptr, + "MultipleControlledRZ", + MQT_NAMED_BUILDER(::qc::multipleControlledRz), nullptr, + MQT_NAMED_BUILDER(mlir::qc::multipleControlledRz), + MQT_NAMED_BUILDER(mlir::qir::multipleControlledRz)}, + CompilerPipelineTestCase{"P", MQT_NAMED_BUILDER(::qc::p), nullptr, MQT_NAMED_BUILDER(mlir::qc::p), - MQT_NAMED_BUILDER(mlir::qir::p)}, + MQT_NAMED_BUILDER(mlir::qir::p)}, CompilerPipelineTestCase{ "SingleControlledP", - MQT_NAMED_BUILDER(qc::singleControlledP), nullptr, + MQT_NAMED_BUILDER(::qc::singleControlledP), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledP), - MQT_NAMED_BUILDER(mlir::qir::singleControlledP)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledP)}, CompilerPipelineTestCase{ - "MultipleControlledP", MQT_NAMED_BUILDER(qc::multipleControlledP), + "MultipleControlledP", MQT_NAMED_BUILDER(::qc::multipleControlledP), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledP), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledP)}, - CompilerPipelineTestCase{"R", MQT_NAMED_BUILDER(qc::r), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledP)}, + CompilerPipelineTestCase{"R", MQT_NAMED_BUILDER(::qc::r), nullptr, MQT_NAMED_BUILDER(mlir::qc::r), - MQT_NAMED_BUILDER(mlir::qir::r)}, + MQT_NAMED_BUILDER(mlir::qir::r)}, CompilerPipelineTestCase{ "SingleControlledR", - MQT_NAMED_BUILDER(qc::singleControlledR), nullptr, + MQT_NAMED_BUILDER(::qc::singleControlledR), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledR), - MQT_NAMED_BUILDER(mlir::qir::singleControlledR)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledR)}, CompilerPipelineTestCase{ - "MultipleControlledR", MQT_NAMED_BUILDER(qc::multipleControlledR), + "MultipleControlledR", MQT_NAMED_BUILDER(::qc::multipleControlledR), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledR), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledR)}, - CompilerPipelineTestCase{"U2", MQT_NAMED_BUILDER(qc::u2), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledR)}, + CompilerPipelineTestCase{"U2", MQT_NAMED_BUILDER(::qc::u2), nullptr, MQT_NAMED_BUILDER(mlir::qc::u2), - MQT_NAMED_BUILDER(mlir::qir::u2)}, + MQT_NAMED_BUILDER(mlir::qir::u2)}, CompilerPipelineTestCase{ - "SingleControlledU2", MQT_NAMED_BUILDER(qc::singleControlledU2), + "SingleControlledU2", MQT_NAMED_BUILDER(::qc::singleControlledU2), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledU2), - MQT_NAMED_BUILDER(mlir::qir::singleControlledU2)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledU2)}, CompilerPipelineTestCase{ - "MultipleControlledU2", MQT_NAMED_BUILDER(qc::multipleControlledU2), - nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledU2), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledU2)}, - CompilerPipelineTestCase{"U", MQT_NAMED_BUILDER(qc::u), nullptr, + "MultipleControlledU2", + MQT_NAMED_BUILDER(::qc::multipleControlledU2), nullptr, + MQT_NAMED_BUILDER(mlir::qc::multipleControlledU2), + MQT_NAMED_BUILDER(mlir::qir::multipleControlledU2)}, + CompilerPipelineTestCase{"U", MQT_NAMED_BUILDER(::qc::u), nullptr, MQT_NAMED_BUILDER(mlir::qc::u), - MQT_NAMED_BUILDER(mlir::qir::u)}, + MQT_NAMED_BUILDER(mlir::qir::u)}, CompilerPipelineTestCase{ "SingleControlledU", - MQT_NAMED_BUILDER(qc::singleControlledU), nullptr, + MQT_NAMED_BUILDER(::qc::singleControlledU), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledU), - MQT_NAMED_BUILDER(mlir::qir::singleControlledU)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledU)}, CompilerPipelineTestCase{ - "MultipleControlledU", MQT_NAMED_BUILDER(qc::multipleControlledU), + "MultipleControlledU", MQT_NAMED_BUILDER(::qc::multipleControlledU), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledU), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledU)}, - CompilerPipelineTestCase{"SWAP", MQT_NAMED_BUILDER(qc::swap), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledU)}, + CompilerPipelineTestCase{"SWAP", MQT_NAMED_BUILDER(::qc::swap), nullptr, MQT_NAMED_BUILDER(mlir::qc::swap), - MQT_NAMED_BUILDER(mlir::qir::swap)}, + MQT_NAMED_BUILDER(mlir::qir::swap)}, CompilerPipelineTestCase{ - "SingleControlledSWAP", MQT_NAMED_BUILDER(qc::singleControlledSwap), - nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledSwap), - MQT_NAMED_BUILDER(mlir::qir::singleControlledSwap)}, + "SingleControlledSWAP", + MQT_NAMED_BUILDER(::qc::singleControlledSwap), nullptr, + MQT_NAMED_BUILDER(mlir::qc::singleControlledSwap), + MQT_NAMED_BUILDER(mlir::qir::singleControlledSwap)}, CompilerPipelineTestCase{ "MultipleControlledSWAP", - MQT_NAMED_BUILDER(qc::multipleControlledSwap), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledSwap), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledSwap), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledSwap)}, - CompilerPipelineTestCase{"iSWAP", MQT_NAMED_BUILDER(qc::iswap), nullptr, - MQT_NAMED_BUILDER(mlir::qc::iswap), - MQT_NAMED_BUILDER(mlir::qir::iswap)}, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledSwap)}, + CompilerPipelineTestCase{"iSWAP", MQT_NAMED_BUILDER(::qc::iswap), + nullptr, MQT_NAMED_BUILDER(mlir::qc::iswap), + MQT_NAMED_BUILDER(mlir::qir::iswap)}, CompilerPipelineTestCase{ "SingleControllediSWAP", - MQT_NAMED_BUILDER(qc::singleControlledIswap), nullptr, + MQT_NAMED_BUILDER(::qc::singleControlledIswap), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledIswap), - MQT_NAMED_BUILDER(mlir::qir::singleControlledIswap)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledIswap)}, CompilerPipelineTestCase{ "MultipleControllediSWAP", - MQT_NAMED_BUILDER(qc::multipleControlledIswap), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledIswap), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledIswap), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledIswap)}, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledIswap)}, CompilerPipelineTestCase{ - "InverseISWAP", MQT_NAMED_BUILDER(qc::inverseIswap), nullptr, + "InverseISWAP", MQT_NAMED_BUILDER(::qc::inverseIswap), nullptr, MQT_NAMED_BUILDER(mlir::qc::inverseIswap), nullptr, true, false}, CompilerPipelineTestCase{ "InverseMultiControlledISWAP", - MQT_NAMED_BUILDER(qc::inverseMultipleControlledIswap), nullptr, + MQT_NAMED_BUILDER(::qc::inverseMultipleControlledIswap), nullptr, MQT_NAMED_BUILDER(mlir::qc::inverseMultipleControlledIswap), nullptr, true, false}, - CompilerPipelineTestCase{"DCX", MQT_NAMED_BUILDER(qc::dcx), nullptr, + CompilerPipelineTestCase{"DCX", MQT_NAMED_BUILDER(::qc::dcx), nullptr, MQT_NAMED_BUILDER(mlir::qc::dcx), - MQT_NAMED_BUILDER(mlir::qir::dcx)}, + MQT_NAMED_BUILDER(mlir::qir::dcx)}, CompilerPipelineTestCase{ - "SingleControlledDCX", MQT_NAMED_BUILDER(qc::singleControlledDcx), + "SingleControlledDCX", MQT_NAMED_BUILDER(::qc::singleControlledDcx), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledDcx), - MQT_NAMED_BUILDER(mlir::qir::singleControlledDcx)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledDcx)}, CompilerPipelineTestCase{ "MultipleControlledDCX", - MQT_NAMED_BUILDER(qc::multipleControlledDcx), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledDcx), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledDcx), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledDcx)}, - CompilerPipelineTestCase{"ECR", MQT_NAMED_BUILDER(qc::ecr), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledDcx)}, + CompilerPipelineTestCase{"ECR", MQT_NAMED_BUILDER(::qc::ecr), nullptr, MQT_NAMED_BUILDER(mlir::qc::ecr), - MQT_NAMED_BUILDER(mlir::qir::ecr)}, + MQT_NAMED_BUILDER(mlir::qir::ecr)}, CompilerPipelineTestCase{ - "SingleControlledECR", MQT_NAMED_BUILDER(qc::singleControlledEcr), + "SingleControlledECR", MQT_NAMED_BUILDER(::qc::singleControlledEcr), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledEcr), - MQT_NAMED_BUILDER(mlir::qir::singleControlledEcr)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledEcr)}, CompilerPipelineTestCase{ "MultipleControlledECR", - MQT_NAMED_BUILDER(qc::multipleControlledEcr), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledEcr), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledEcr), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledEcr)}, - CompilerPipelineTestCase{"RXX", MQT_NAMED_BUILDER(qc::rxx), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledEcr)}, + CompilerPipelineTestCase{"RXX", MQT_NAMED_BUILDER(::qc::rxx), nullptr, MQT_NAMED_BUILDER(mlir::qc::rxx), - MQT_NAMED_BUILDER(mlir::qir::rxx)}, + MQT_NAMED_BUILDER(mlir::qir::rxx)}, CompilerPipelineTestCase{ - "SingleControlledRXX", MQT_NAMED_BUILDER(qc::singleControlledRxx), + "SingleControlledRXX", MQT_NAMED_BUILDER(::qc::singleControlledRxx), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledRxx), - MQT_NAMED_BUILDER(mlir::qir::singleControlledRxx)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledRxx)}, CompilerPipelineTestCase{ "MultipleControlledRXX", - MQT_NAMED_BUILDER(qc::multipleControlledRxx), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledRxx), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledRxx), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledRxx)}, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledRxx)}, CompilerPipelineTestCase{ - "TripleControlledRXX", MQT_NAMED_BUILDER(qc::tripleControlledRxx), + "TripleControlledRXX", MQT_NAMED_BUILDER(::qc::tripleControlledRxx), nullptr, MQT_NAMED_BUILDER(mlir::qc::tripleControlledRxx), - MQT_NAMED_BUILDER(mlir::qir::tripleControlledRxx)}, - CompilerPipelineTestCase{"RYY", MQT_NAMED_BUILDER(qc::ryy), nullptr, + MQT_NAMED_BUILDER(mlir::qir::tripleControlledRxx)}, + CompilerPipelineTestCase{"RYY", MQT_NAMED_BUILDER(::qc::ryy), nullptr, MQT_NAMED_BUILDER(mlir::qc::ryy), - MQT_NAMED_BUILDER(mlir::qir::ryy)}, + MQT_NAMED_BUILDER(mlir::qir::ryy)}, CompilerPipelineTestCase{ - "SingleControlledRYY", MQT_NAMED_BUILDER(qc::singleControlledRyy), + "SingleControlledRYY", MQT_NAMED_BUILDER(::qc::singleControlledRyy), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledRyy), - MQT_NAMED_BUILDER(mlir::qir::singleControlledRyy)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledRyy)}, CompilerPipelineTestCase{ "MultipleControlledRYY", - MQT_NAMED_BUILDER(qc::multipleControlledRyy), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledRyy), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledRyy), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledRyy)}, - CompilerPipelineTestCase{"RZX", MQT_NAMED_BUILDER(qc::rzx), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledRyy)}, + CompilerPipelineTestCase{"RZX", MQT_NAMED_BUILDER(::qc::rzx), nullptr, MQT_NAMED_BUILDER(mlir::qc::rzx), - MQT_NAMED_BUILDER(mlir::qir::rzx)}, + MQT_NAMED_BUILDER(mlir::qir::rzx)}, CompilerPipelineTestCase{ - "SingleControlledRZX", MQT_NAMED_BUILDER(qc::singleControlledRzx), + "SingleControlledRZX", MQT_NAMED_BUILDER(::qc::singleControlledRzx), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledRzx), - MQT_NAMED_BUILDER(mlir::qir::singleControlledRzx)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledRzx)}, CompilerPipelineTestCase{ "MultipleControlledRZX", - MQT_NAMED_BUILDER(qc::multipleControlledRzx), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledRzx), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledRzx), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledRzx)}, - CompilerPipelineTestCase{"RZZ", MQT_NAMED_BUILDER(qc::rzz), nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledRzx)}, + CompilerPipelineTestCase{"RZZ", MQT_NAMED_BUILDER(::qc::rzz), nullptr, MQT_NAMED_BUILDER(mlir::qc::rzz), - MQT_NAMED_BUILDER(mlir::qir::rzz)}, + MQT_NAMED_BUILDER(mlir::qir::rzz)}, CompilerPipelineTestCase{ - "SingleControlledRZZ", MQT_NAMED_BUILDER(qc::singleControlledRzz), + "SingleControlledRZZ", MQT_NAMED_BUILDER(::qc::singleControlledRzz), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledRzz), - MQT_NAMED_BUILDER(mlir::qir::singleControlledRzz)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledRzz)}, CompilerPipelineTestCase{ "MultipleControlledRZZ", - MQT_NAMED_BUILDER(qc::multipleControlledRzz), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledRzz), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledRzz), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledRzz)}, - CompilerPipelineTestCase{"XXPlusYY", MQT_NAMED_BUILDER(qc::xxPlusYY), + MQT_NAMED_BUILDER(mlir::qir::multipleControlledRzz)}, + CompilerPipelineTestCase{"XXPlusYY", MQT_NAMED_BUILDER(::qc::xxPlusYY), nullptr, MQT_NAMED_BUILDER(mlir::qc::xxPlusYY), - MQT_NAMED_BUILDER(mlir::qir::xxPlusYY)}, + MQT_NAMED_BUILDER(mlir::qir::xxPlusYY)}, CompilerPipelineTestCase{ "SingleControlledXXPlusYY", - MQT_NAMED_BUILDER(qc::singleControlledXxPlusYY), nullptr, + MQT_NAMED_BUILDER(::qc::singleControlledXxPlusYY), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledXxPlusYY), - MQT_NAMED_BUILDER(mlir::qir::singleControlledXxPlusYY)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledXxPlusYY)}, CompilerPipelineTestCase{ "MultipleControlledXXPlusYY", - MQT_NAMED_BUILDER(qc::multipleControlledXxPlusYY), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledXxPlusYY), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledXxPlusYY), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledXxPlusYY)}, - CompilerPipelineTestCase{"XXMinusYY", MQT_NAMED_BUILDER(qc::xxMinusYY), - nullptr, + MQT_NAMED_BUILDER(mlir::qir::multipleControlledXxPlusYY)}, + CompilerPipelineTestCase{"XXMinusYY", + MQT_NAMED_BUILDER(::qc::xxMinusYY), nullptr, MQT_NAMED_BUILDER(mlir::qc::xxMinusYY), - MQT_NAMED_BUILDER(mlir::qir::xxMinusYY)}, + MQT_NAMED_BUILDER(mlir::qir::xxMinusYY)}, CompilerPipelineTestCase{ "SingleControlledXXMinusYY", - MQT_NAMED_BUILDER(qc::singleControlledXxMinusYY), nullptr, + MQT_NAMED_BUILDER(::qc::singleControlledXxMinusYY), nullptr, MQT_NAMED_BUILDER(mlir::qc::singleControlledXxMinusYY), - MQT_NAMED_BUILDER(mlir::qir::singleControlledXxMinusYY)}, + MQT_NAMED_BUILDER(mlir::qir::singleControlledXxMinusYY)}, CompilerPipelineTestCase{ "MultipleControlledXXMinusYY", - MQT_NAMED_BUILDER(qc::multipleControlledXxMinusYY), nullptr, + MQT_NAMED_BUILDER(::qc::multipleControlledXxMinusYY), nullptr, MQT_NAMED_BUILDER(mlir::qc::multipleControlledXxMinusYY), - MQT_NAMED_BUILDER(mlir::qir::multipleControlledXxMinusYY)}, - CompilerPipelineTestCase{"CtrlTwo", MQT_NAMED_BUILDER(qc::ctrlTwo), + MQT_NAMED_BUILDER(mlir::qir::multipleControlledXxMinusYY)}, + CompilerPipelineTestCase{"CtrlTwo", MQT_NAMED_BUILDER(::qc::ctrlTwo), nullptr, MQT_NAMED_BUILDER(mlir::qc::ctrlTwo), - MQT_NAMED_BUILDER(mlir::qir::ctrlTwo)})); + MQT_NAMED_BUILDER(mlir::qir::ctrlTwo)})); } // namespace mqt::test::compiler diff --git a/mlir/unittests/Conversion/JeffRoundTrip/test_jeff_round_trip.cpp b/mlir/unittests/Conversion/JeffRoundTrip/test_jeff_round_trip.cpp index 0f09b2b274..cd4856ebac 100644 --- a/mlir/unittests/Conversion/JeffRoundTrip/test_jeff_round_trip.cpp +++ b/mlir/unittests/Conversion/JeffRoundTrip/test_jeff_round_trip.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -42,8 +43,8 @@ namespace { struct JeffRoundTripTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const JeffRoundTripTestCase& info); @@ -91,8 +92,7 @@ TEST_P(JeffRoundTripTest, ProgramEquivalence) { const auto name = " (" + nameStr + ")"; mqt::test::DeferredPrinter printer; - auto program = - qco::QCOProgramBuilder::build(context.get(), programBuilder.fn); + auto program = mqt::test::buildMLIRProgram(context.get(), programBuilder); ASSERT_TRUE(program); printer.record(program.get(), "Original QCO IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -126,8 +126,7 @@ TEST_P(JeffRoundTripTest, ProgramEquivalence) { printer.record(program.get(), "Canonicalized Converted QCO IR" + name); EXPECT_TRUE(verify(*program).succeeded()); - auto reference = - qco::QCOProgramBuilder::build(context.get(), referenceBuilder.fn); + auto reference = mqt::test::buildMLIRProgram(context.get(), referenceBuilder); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QCO IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); diff --git a/mlir/unittests/Conversion/QCOToQC/test_qco_to_qc.cpp b/mlir/unittests/Conversion/QCOToQC/test_qco_to_qc.cpp index f25ce73b6f..3cab63449f 100644 --- a/mlir/unittests/Conversion/QCOToQC/test_qco_to_qc.cpp +++ b/mlir/unittests/Conversion/QCOToQC/test_qco_to_qc.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -41,8 +42,8 @@ namespace { struct QCOToQCTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const QCOToQCTestCase& info); @@ -85,8 +86,7 @@ TEST_P(QCOToQCTest, ProgramEquivalence) { const auto name = " (" + nameStr + ")"; mqt::test::DeferredPrinter printer; - auto program = - qco::QCOProgramBuilder::build(context.get(), programBuilder.fn); + auto program = mqt::test::buildMLIRProgram(context.get(), programBuilder); ASSERT_TRUE(program); printer.record(program.get(), "Original QCO IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -103,8 +103,7 @@ TEST_P(QCOToQCTest, ProgramEquivalence) { printer.record(program.get(), "Canonicalized Converted QC IR" + name); EXPECT_TRUE(verify(*program).succeeded()); - auto reference = - qc::QCProgramBuilder::build(context.get(), referenceBuilder.fn); + auto reference = mqt::test::buildMLIRProgram(context.get(), referenceBuilder); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QC IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); diff --git a/mlir/unittests/Conversion/QCToQCO/test_qc_to_qco.cpp b/mlir/unittests/Conversion/QCToQCO/test_qc_to_qco.cpp index 9e66a0b655..0b78783834 100644 --- a/mlir/unittests/Conversion/QCToQCO/test_qc_to_qco.cpp +++ b/mlir/unittests/Conversion/QCToQCO/test_qc_to_qco.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -41,8 +42,8 @@ namespace { struct QCToQCOTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const QCToQCOTestCase& info); @@ -85,7 +86,7 @@ TEST_P(QCToQCOTest, ProgramEquivalence) { const auto name = " (" + GetParam().name + ")"; mqt::test::DeferredPrinter printer; - auto program = qc::QCProgramBuilder::build(context.get(), programBuilder.fn); + auto program = mqt::test::buildMLIRProgram(context.get(), programBuilder); ASSERT_TRUE(program); printer.record(program.get(), "Original QC IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -102,8 +103,7 @@ TEST_P(QCToQCOTest, ProgramEquivalence) { printer.record(program.get(), "Canonicalized Converted QCO IR" + name); EXPECT_TRUE(verify(*program).succeeded()); - auto reference = - qco::QCOProgramBuilder::build(context.get(), referenceBuilder.fn); + auto reference = mqt::test::buildMLIRProgram(context.get(), referenceBuilder); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QCO IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); @@ -140,7 +140,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(qco::staticQubitsWithInv)}, QCToQCOTestCase{"AllocDeallocPair", MQT_NAMED_BUILDER(qc::allocDeallocPair), - MQT_NAMED_BUILDER(qco::allocSinkPair)})); + MQT_NAMED_BUILDER(qco::emptyQCO)})); /// @} /// \name QCToQCO/Modifiers/CtrlOp.cpp @@ -248,7 +248,7 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(QCIDOpTest, QCToQCOTest, testing::Values(QCToQCOTestCase{ "Identity", MQT_NAMED_BUILDER(qc::identity), - MQT_NAMED_BUILDER(qco::emptyQCO)})); + MQT_NAMED_BUILDER(qco::alloc1QubitRegister)})); /// @} /// \name QCToQCO/Operations/StandardGates/IswapOp.cpp diff --git a/mlir/unittests/Conversion/QCToQIR/QCToQIRAdaptive/test_qc_to_qir_adaptive.cpp b/mlir/unittests/Conversion/QCToQIR/QCToQIRAdaptive/test_qc_to_qir_adaptive.cpp index 509f1ff321..e386a4e579 100644 --- a/mlir/unittests/Conversion/QCToQIR/QCToQIRAdaptive/test_qc_to_qir_adaptive.cpp +++ b/mlir/unittests/Conversion/QCToQIR/QCToQIRAdaptive/test_qc_to_qir_adaptive.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -42,8 +43,8 @@ namespace { struct QCToQIRAdaptiveTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const QCToQIRAdaptiveTestCase& info); @@ -87,7 +88,7 @@ TEST_P(QCToQIRAdaptiveTest, ProgramEquivalence) { const auto name = " (" + GetParam().name + ")"; mqt::test::DeferredPrinter printer; - auto program = qc::QCProgramBuilder::build(context.get(), programBuilder.fn); + auto program = mqt::test::buildMLIRProgram(context.get(), programBuilder); ASSERT_TRUE(program); printer.record(program.get(), "Original QC IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -105,8 +106,8 @@ TEST_P(QCToQIRAdaptiveTest, ProgramEquivalence) { EXPECT_TRUE(verify(*program).succeeded()); auto reference = - qir::QIRProgramBuilder::build(context.get(), referenceBuilder.fn, - qir::QIRProgramBuilder::Profile::Adaptive); + mqt::test::buildMLIRProgram(context.get(), referenceBuilder, + qir::QIRProgramBuilder::Profile::Adaptive); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QIR IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); @@ -125,16 +126,16 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveBarrierOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"Barrier", MQT_NAMED_BUILDER(qc::barrier), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::alloc1QubitRegister<>)}, QCToQIRAdaptiveTestCase{"BarrierTwoQubits", MQT_NAMED_BUILDER(qc::barrierTwoQubits), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::allocQubitRegister<>)}, QCToQIRAdaptiveTestCase{"BarrierMultipleQubits", MQT_NAMED_BUILDER(qc::barrierMultipleQubits), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::alloc3QubitRegister<>)}, QCToQIRAdaptiveTestCase{"SingleControlledBarrier", MQT_NAMED_BUILDER(qc::singleControlledBarrier), - MQT_NAMED_BUILDER(qir::emptyQIR)})); + MQT_NAMED_BUILDER(qir::allocQubitRegister<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/DcxOp.cpp @@ -142,15 +143,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveDCXOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"DCX", MQT_NAMED_BUILDER(qc::dcx), - MQT_NAMED_BUILDER(qir::dcx)}, + MQT_NAMED_BUILDER(qir::dcx<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledDCX", MQT_NAMED_BUILDER(qc::singleControlledDcx), - MQT_NAMED_BUILDER(qir::singleControlledDcx)}, + MQT_NAMED_BUILDER(qir::singleControlledDcx<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledDCX", MQT_NAMED_BUILDER(qc::multipleControlledDcx), - MQT_NAMED_BUILDER(qir::multipleControlledDcx)})); + MQT_NAMED_BUILDER(qir::multipleControlledDcx<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/EcrOp.cpp @@ -158,15 +159,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveECROpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"ECR", MQT_NAMED_BUILDER(qc::ecr), - MQT_NAMED_BUILDER(qir::ecr)}, + MQT_NAMED_BUILDER(qir::ecr<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledECR", MQT_NAMED_BUILDER(qc::singleControlledEcr), - MQT_NAMED_BUILDER(qir::singleControlledEcr)}, + MQT_NAMED_BUILDER(qir::singleControlledEcr<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledECR", MQT_NAMED_BUILDER(qc::multipleControlledEcr), - MQT_NAMED_BUILDER(qir::multipleControlledEcr)})); + MQT_NAMED_BUILDER(qir::multipleControlledEcr<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/GphaseOp.cpp @@ -174,7 +175,7 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(QCToQIRAdaptiveGPhaseOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{ "GlobalPhase", MQT_NAMED_BUILDER(qc::globalPhase), - MQT_NAMED_BUILDER(qir::globalPhase)})); + MQT_NAMED_BUILDER(qir::globalPhase<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/HOp.cpp @@ -183,16 +184,16 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveHOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"H", MQT_NAMED_BUILDER(qc::h), - MQT_NAMED_BUILDER(qir::h)}, + MQT_NAMED_BUILDER(qir::h<>)}, QCToQIRAdaptiveTestCase{"SingleControlledH", MQT_NAMED_BUILDER(qc::singleControlledH), - MQT_NAMED_BUILDER(qir::singleControlledH)}, + MQT_NAMED_BUILDER(qir::singleControlledH<>)}, QCToQIRAdaptiveTestCase{"MultipleControlledH", MQT_NAMED_BUILDER(qc::multipleControlledH), - MQT_NAMED_BUILDER(qir::multipleControlledH)}, + MQT_NAMED_BUILDER(qir::multipleControlledH<>)}, QCToQIRAdaptiveTestCase{"HWithoutRegister", MQT_NAMED_BUILDER(qc::hWithoutRegister), - MQT_NAMED_BUILDER(qir::hWithoutRegister)})); + MQT_NAMED_BUILDER(qir::hWithoutRegister<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/IdOp.cpp @@ -201,30 +202,31 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveIDOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"Identity", MQT_NAMED_BUILDER(qc::identity), - MQT_NAMED_BUILDER(qir::identity)}, + MQT_NAMED_BUILDER(qir::identity<>)}, QCToQIRAdaptiveTestCase{"SingleControlledIdentity", MQT_NAMED_BUILDER(qc::singleControlledIdentity), - MQT_NAMED_BUILDER(qir::identity)}, + MQT_NAMED_BUILDER(qir::twoQubitsOneIdentity<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledIdentity", MQT_NAMED_BUILDER(qc::multipleControlledIdentity), - MQT_NAMED_BUILDER(qir::identity)})); + MQT_NAMED_BUILDER(qir::threeQubitsOneIdentity<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/IswapOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveiSWAPOpTest, QCToQIRAdaptiveTest, - testing::Values( - QCToQIRAdaptiveTestCase{"iSWAP", MQT_NAMED_BUILDER(qc::iswap), - MQT_NAMED_BUILDER(qir::iswap)}, - QCToQIRAdaptiveTestCase{"SingleControllediSWAP", - MQT_NAMED_BUILDER(qc::singleControlledIswap), - MQT_NAMED_BUILDER(qir::singleControlledIswap)}, - QCToQIRAdaptiveTestCase{ - "MultipleControllediSWAP", - MQT_NAMED_BUILDER(qc::multipleControlledIswap), - MQT_NAMED_BUILDER(qir::multipleControlledIswap)})); + testing::Values(QCToQIRAdaptiveTestCase{"iSWAP", + MQT_NAMED_BUILDER(qc::iswap), + MQT_NAMED_BUILDER(qir::iswap<>)}, + QCToQIRAdaptiveTestCase{ + "SingleControllediSWAP", + MQT_NAMED_BUILDER(qc::singleControlledIswap), + MQT_NAMED_BUILDER(qir::singleControlledIswap<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControllediSWAP", + MQT_NAMED_BUILDER(qc::multipleControlledIswap), + MQT_NAMED_BUILDER(qir::multipleControlledIswap<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/POp.cpp @@ -233,13 +235,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptivePOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"P", MQT_NAMED_BUILDER(qc::p), - MQT_NAMED_BUILDER(qir::p)}, + MQT_NAMED_BUILDER(qir::p<>)}, QCToQIRAdaptiveTestCase{"SingleControlledP", MQT_NAMED_BUILDER(qc::singleControlledP), - MQT_NAMED_BUILDER(qir::singleControlledP)}, - QCToQIRAdaptiveTestCase{"MultipleControlledP", - MQT_NAMED_BUILDER(qc::multipleControlledP), - MQT_NAMED_BUILDER(qir::multipleControlledP)})); + MQT_NAMED_BUILDER(qir::singleControlledP<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledP", MQT_NAMED_BUILDER(qc::multipleControlledP), + MQT_NAMED_BUILDER(qir::multipleControlledP<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/ROp.cpp @@ -248,13 +250,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveROpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"R", MQT_NAMED_BUILDER(qc::r), - MQT_NAMED_BUILDER(qir::r)}, + MQT_NAMED_BUILDER(qir::r<>)}, QCToQIRAdaptiveTestCase{"SingleControlledR", MQT_NAMED_BUILDER(qc::singleControlledR), - MQT_NAMED_BUILDER(qir::singleControlledR)}, - QCToQIRAdaptiveTestCase{"MultipleControlledR", - MQT_NAMED_BUILDER(qc::multipleControlledR), - MQT_NAMED_BUILDER(qir::multipleControlledR)})); + MQT_NAMED_BUILDER(qir::singleControlledR<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledR", MQT_NAMED_BUILDER(qc::multipleControlledR), + MQT_NAMED_BUILDER(qir::multipleControlledR<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/RxOp.cpp @@ -263,13 +265,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveRXOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"RX", MQT_NAMED_BUILDER(qc::rx), - MQT_NAMED_BUILDER(qir::rx)}, + MQT_NAMED_BUILDER(qir::rx<>)}, QCToQIRAdaptiveTestCase{"SingleControlledRX", MQT_NAMED_BUILDER(qc::singleControlledRx), - MQT_NAMED_BUILDER(qir::singleControlledRx)}, - QCToQIRAdaptiveTestCase{"MultipleControlledRX", - MQT_NAMED_BUILDER(qc::multipleControlledRx), - MQT_NAMED_BUILDER(qir::multipleControlledRx)})); + MQT_NAMED_BUILDER(qir::singleControlledRx<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledRX", MQT_NAMED_BUILDER(qc::multipleControlledRx), + MQT_NAMED_BUILDER(qir::multipleControlledRx<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/RxxOp.cpp @@ -277,15 +279,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveRXXOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"RXX", MQT_NAMED_BUILDER(qc::rxx), - MQT_NAMED_BUILDER(qir::rxx)}, + MQT_NAMED_BUILDER(qir::rxx<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledRXX", MQT_NAMED_BUILDER(qc::singleControlledRxx), - MQT_NAMED_BUILDER(qir::singleControlledRxx)}, + MQT_NAMED_BUILDER(qir::singleControlledRxx<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledRXX", MQT_NAMED_BUILDER(qc::multipleControlledRxx), - MQT_NAMED_BUILDER(qir::multipleControlledRxx)})); + MQT_NAMED_BUILDER(qir::multipleControlledRxx<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/RyOp.cpp @@ -294,13 +296,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveRYOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"RY", MQT_NAMED_BUILDER(qc::ry), - MQT_NAMED_BUILDER(qir::ry)}, + MQT_NAMED_BUILDER(qir::ry<>)}, QCToQIRAdaptiveTestCase{"SingleControlledRY", MQT_NAMED_BUILDER(qc::singleControlledRy), - MQT_NAMED_BUILDER(qir::singleControlledRy)}, - QCToQIRAdaptiveTestCase{"MultipleControlledRY", - MQT_NAMED_BUILDER(qc::multipleControlledRy), - MQT_NAMED_BUILDER(qir::multipleControlledRy)})); + MQT_NAMED_BUILDER(qir::singleControlledRy<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledRY", MQT_NAMED_BUILDER(qc::multipleControlledRy), + MQT_NAMED_BUILDER(qir::multipleControlledRy<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/RyyOp.cpp @@ -308,15 +310,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveRYYOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"RYY", MQT_NAMED_BUILDER(qc::ryy), - MQT_NAMED_BUILDER(qir::ryy)}, + MQT_NAMED_BUILDER(qir::ryy<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledRYY", MQT_NAMED_BUILDER(qc::singleControlledRyy), - MQT_NAMED_BUILDER(qir::singleControlledRyy)}, + MQT_NAMED_BUILDER(qir::singleControlledRyy<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledRYY", MQT_NAMED_BUILDER(qc::multipleControlledRyy), - MQT_NAMED_BUILDER(qir::multipleControlledRyy)})); + MQT_NAMED_BUILDER(qir::multipleControlledRyy<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/RzOp.cpp @@ -325,13 +327,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveRZOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"RZ", MQT_NAMED_BUILDER(qc::rz), - MQT_NAMED_BUILDER(qir::rz)}, + MQT_NAMED_BUILDER(qir::rz<>)}, QCToQIRAdaptiveTestCase{"SingleControlledRZ", MQT_NAMED_BUILDER(qc::singleControlledRz), - MQT_NAMED_BUILDER(qir::singleControlledRz)}, - QCToQIRAdaptiveTestCase{"MultipleControlledRZ", - MQT_NAMED_BUILDER(qc::multipleControlledRz), - MQT_NAMED_BUILDER(qir::multipleControlledRz)})); + MQT_NAMED_BUILDER(qir::singleControlledRz<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledRZ", MQT_NAMED_BUILDER(qc::multipleControlledRz), + MQT_NAMED_BUILDER(qir::multipleControlledRz<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/RzxOp.cpp @@ -339,15 +341,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveRZXOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"RZX", MQT_NAMED_BUILDER(qc::rzx), - MQT_NAMED_BUILDER(qir::rzx)}, + MQT_NAMED_BUILDER(qir::rzx<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledRZX", MQT_NAMED_BUILDER(qc::singleControlledRzx), - MQT_NAMED_BUILDER(qir::singleControlledRzx)}, + MQT_NAMED_BUILDER(qir::singleControlledRzx<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledRZX", MQT_NAMED_BUILDER(qc::multipleControlledRzx), - MQT_NAMED_BUILDER(qir::multipleControlledRzx)})); + MQT_NAMED_BUILDER(qir::multipleControlledRzx<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/RzzOp.cpp @@ -355,15 +357,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveRZZOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"RZZ", MQT_NAMED_BUILDER(qc::rzz), - MQT_NAMED_BUILDER(qir::rzz)}, + MQT_NAMED_BUILDER(qir::rzz<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledRZZ", MQT_NAMED_BUILDER(qc::singleControlledRzz), - MQT_NAMED_BUILDER(qir::singleControlledRzz)}, + MQT_NAMED_BUILDER(qir::singleControlledRzz<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledRZZ", MQT_NAMED_BUILDER(qc::multipleControlledRzz), - MQT_NAMED_BUILDER(qir::multipleControlledRzz)})); + MQT_NAMED_BUILDER(qir::multipleControlledRzz<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/SOp.cpp @@ -372,13 +374,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveSOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"S", MQT_NAMED_BUILDER(qc::s), - MQT_NAMED_BUILDER(qir::s)}, + MQT_NAMED_BUILDER(qir::s<>)}, QCToQIRAdaptiveTestCase{"SingleControlledS", MQT_NAMED_BUILDER(qc::singleControlledS), - MQT_NAMED_BUILDER(qir::singleControlledS)}, - QCToQIRAdaptiveTestCase{"MultipleControlledS", - MQT_NAMED_BUILDER(qc::multipleControlledS), - MQT_NAMED_BUILDER(qir::multipleControlledS)})); + MQT_NAMED_BUILDER(qir::singleControlledS<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledS", MQT_NAMED_BUILDER(qc::multipleControlledS), + MQT_NAMED_BUILDER(qir::multipleControlledS<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/SdgOp.cpp @@ -386,15 +388,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveSdgOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"Sdg", MQT_NAMED_BUILDER(qc::sdg), - MQT_NAMED_BUILDER(qir::sdg)}, + MQT_NAMED_BUILDER(qir::sdg<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledSdg", MQT_NAMED_BUILDER(qc::singleControlledSdg), - MQT_NAMED_BUILDER(qir::singleControlledSdg)}, + MQT_NAMED_BUILDER(qir::singleControlledSdg<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledSdg", MQT_NAMED_BUILDER(qc::multipleControlledSdg), - MQT_NAMED_BUILDER(qir::multipleControlledSdg)})); + MQT_NAMED_BUILDER(qir::multipleControlledSdg<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/SwapOp.cpp @@ -402,15 +404,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveSWAPOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"SWAP", MQT_NAMED_BUILDER(qc::swap), - MQT_NAMED_BUILDER(qir::swap)}, + MQT_NAMED_BUILDER(qir::swap<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledSWAP", MQT_NAMED_BUILDER(qc::singleControlledSwap), - MQT_NAMED_BUILDER(qir::singleControlledSwap)}, + MQT_NAMED_BUILDER(qir::singleControlledSwap<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledSWAP", MQT_NAMED_BUILDER(qc::multipleControlledSwap), - MQT_NAMED_BUILDER(qir::multipleControlledSwap)})); + MQT_NAMED_BUILDER(qir::multipleControlledSwap<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/SxOp.cpp @@ -419,13 +421,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveSXOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"SX", MQT_NAMED_BUILDER(qc::sx), - MQT_NAMED_BUILDER(qir::sx)}, + MQT_NAMED_BUILDER(qir::sx<>)}, QCToQIRAdaptiveTestCase{"SingleControlledSX", MQT_NAMED_BUILDER(qc::singleControlledSx), - MQT_NAMED_BUILDER(qir::singleControlledSx)}, - QCToQIRAdaptiveTestCase{"MultipleControlledSX", - MQT_NAMED_BUILDER(qc::multipleControlledSx), - MQT_NAMED_BUILDER(qir::multipleControlledSx)})); + MQT_NAMED_BUILDER(qir::singleControlledSx<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledSX", MQT_NAMED_BUILDER(qc::multipleControlledSx), + MQT_NAMED_BUILDER(qir::multipleControlledSx<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/SxdgOp.cpp @@ -433,15 +435,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveSXdgOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"SXdg", MQT_NAMED_BUILDER(qc::sxdg), - MQT_NAMED_BUILDER(qir::sxdg)}, + MQT_NAMED_BUILDER(qir::sxdg<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledSXdg", MQT_NAMED_BUILDER(qc::singleControlledSxdg), - MQT_NAMED_BUILDER(qir::singleControlledSxdg)}, + MQT_NAMED_BUILDER(qir::singleControlledSxdg<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledSXdg", MQT_NAMED_BUILDER(qc::multipleControlledSxdg), - MQT_NAMED_BUILDER(qir::multipleControlledSxdg)})); + MQT_NAMED_BUILDER(qir::multipleControlledSxdg<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/TOp.cpp @@ -450,13 +452,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveTOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"T", MQT_NAMED_BUILDER(qc::t_), - MQT_NAMED_BUILDER(qir::t_)}, + MQT_NAMED_BUILDER(qir::t_<>)}, QCToQIRAdaptiveTestCase{"SingleControlledT", MQT_NAMED_BUILDER(qc::singleControlledT), - MQT_NAMED_BUILDER(qir::singleControlledT)}, - QCToQIRAdaptiveTestCase{"MultipleControlledT", - MQT_NAMED_BUILDER(qc::multipleControlledT), - MQT_NAMED_BUILDER(qir::multipleControlledT)})); + MQT_NAMED_BUILDER(qir::singleControlledT<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledT", MQT_NAMED_BUILDER(qc::multipleControlledT), + MQT_NAMED_BUILDER(qir::multipleControlledT<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/TdgOp.cpp @@ -464,15 +466,15 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveTdgOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"Tdg", MQT_NAMED_BUILDER(qc::tdg), - MQT_NAMED_BUILDER(qir::tdg)}, + MQT_NAMED_BUILDER(qir::tdg<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledTdg", MQT_NAMED_BUILDER(qc::singleControlledTdg), - MQT_NAMED_BUILDER(qir::singleControlledTdg)}, + MQT_NAMED_BUILDER(qir::singleControlledTdg<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledTdg", MQT_NAMED_BUILDER(qc::multipleControlledTdg), - MQT_NAMED_BUILDER(qir::multipleControlledTdg)})); + MQT_NAMED_BUILDER(qir::multipleControlledTdg<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/U2Op.cpp @@ -481,13 +483,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveU2OpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"U2", MQT_NAMED_BUILDER(qc::u2), - MQT_NAMED_BUILDER(qir::u2)}, + MQT_NAMED_BUILDER(qir::u2<>)}, QCToQIRAdaptiveTestCase{"SingleControlledU2", MQT_NAMED_BUILDER(qc::singleControlledU2), - MQT_NAMED_BUILDER(qir::singleControlledU2)}, - QCToQIRAdaptiveTestCase{"MultipleControlledU2", - MQT_NAMED_BUILDER(qc::multipleControlledU2), - MQT_NAMED_BUILDER(qir::multipleControlledU2)})); + MQT_NAMED_BUILDER(qir::singleControlledU2<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledU2", MQT_NAMED_BUILDER(qc::multipleControlledU2), + MQT_NAMED_BUILDER(qir::multipleControlledU2<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/UOp.cpp @@ -496,13 +498,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveUOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"U", MQT_NAMED_BUILDER(qc::u), - MQT_NAMED_BUILDER(qir::u)}, + MQT_NAMED_BUILDER(qir::u<>)}, QCToQIRAdaptiveTestCase{"SingleControlledU", MQT_NAMED_BUILDER(qc::singleControlledU), - MQT_NAMED_BUILDER(qir::singleControlledU)}, - QCToQIRAdaptiveTestCase{"MultipleControlledU", - MQT_NAMED_BUILDER(qc::multipleControlledU), - MQT_NAMED_BUILDER(qir::multipleControlledU)})); + MQT_NAMED_BUILDER(qir::singleControlledU<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledU", MQT_NAMED_BUILDER(qc::multipleControlledU), + MQT_NAMED_BUILDER(qir::multipleControlledU<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/XOp.cpp @@ -511,30 +513,30 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveXOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"X", MQT_NAMED_BUILDER(qc::x), - MQT_NAMED_BUILDER(qir::x)}, + MQT_NAMED_BUILDER(qir::x<>)}, QCToQIRAdaptiveTestCase{"SingleControlledX", MQT_NAMED_BUILDER(qc::singleControlledX), - MQT_NAMED_BUILDER(qir::singleControlledX)}, - QCToQIRAdaptiveTestCase{"MultipleControlledX", - MQT_NAMED_BUILDER(qc::multipleControlledX), - MQT_NAMED_BUILDER(qir::multipleControlledX)})); + MQT_NAMED_BUILDER(qir::singleControlledX<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledX", MQT_NAMED_BUILDER(qc::multipleControlledX), + MQT_NAMED_BUILDER(qir::multipleControlledX<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/XxMinusYyOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveXXMinusYYOpTest, QCToQIRAdaptiveTest, - testing::Values(QCToQIRAdaptiveTestCase{"XXMinusYY", - MQT_NAMED_BUILDER(qc::xxMinusYY), - MQT_NAMED_BUILDER(qir::xxMinusYY)}, - QCToQIRAdaptiveTestCase{ - "SingleControlledXXMinusYY", - MQT_NAMED_BUILDER(qc::singleControlledXxMinusYY), - MQT_NAMED_BUILDER(qir::singleControlledXxMinusYY)}, - QCToQIRAdaptiveTestCase{ - "MultipleControlledXXMinusYY", - MQT_NAMED_BUILDER(qc::multipleControlledXxMinusYY), - MQT_NAMED_BUILDER(qir::multipleControlledXxMinusYY)})); + testing::Values( + QCToQIRAdaptiveTestCase{"XXMinusYY", MQT_NAMED_BUILDER(qc::xxMinusYY), + MQT_NAMED_BUILDER(qir::xxMinusYY<>)}, + QCToQIRAdaptiveTestCase{ + "SingleControlledXXMinusYY", + MQT_NAMED_BUILDER(qc::singleControlledXxMinusYY), + MQT_NAMED_BUILDER(qir::singleControlledXxMinusYY<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledXXMinusYY", + MQT_NAMED_BUILDER(qc::multipleControlledXxMinusYY), + MQT_NAMED_BUILDER(qir::multipleControlledXxMinusYY<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/XxPlusYyOp.cpp @@ -543,15 +545,15 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveXXPlusYYOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{"XXPlusYY", MQT_NAMED_BUILDER(qc::xxPlusYY), - MQT_NAMED_BUILDER(qir::xxPlusYY)}, + MQT_NAMED_BUILDER(qir::xxPlusYY<>)}, QCToQIRAdaptiveTestCase{ "SingleControlledXXPlusYY", MQT_NAMED_BUILDER(qc::singleControlledXxPlusYY), - MQT_NAMED_BUILDER(qir::singleControlledXxPlusYY)}, + MQT_NAMED_BUILDER(qir::singleControlledXxPlusYY<>)}, QCToQIRAdaptiveTestCase{ "MultipleControlledXXPlusYY", MQT_NAMED_BUILDER(qc::multipleControlledXxPlusYY), - MQT_NAMED_BUILDER(qir::multipleControlledXxPlusYY)})); + MQT_NAMED_BUILDER(qir::multipleControlledXxPlusYY<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/YOp.cpp @@ -560,13 +562,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveYOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"Y", MQT_NAMED_BUILDER(qc::y), - MQT_NAMED_BUILDER(qir::y)}, + MQT_NAMED_BUILDER(qir::y<>)}, QCToQIRAdaptiveTestCase{"SingleControlledY", MQT_NAMED_BUILDER(qc::singleControlledY), - MQT_NAMED_BUILDER(qir::singleControlledY)}, - QCToQIRAdaptiveTestCase{"MultipleControlledY", - MQT_NAMED_BUILDER(qc::multipleControlledY), - MQT_NAMED_BUILDER(qir::multipleControlledY)})); + MQT_NAMED_BUILDER(qir::singleControlledY<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledY", MQT_NAMED_BUILDER(qc::multipleControlledY), + MQT_NAMED_BUILDER(qir::multipleControlledY<>)})); /// @} /// \name QCToQIRAdaptive/Operations/StandardGates/ZOp.cpp @@ -575,13 +577,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveZOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"Z", MQT_NAMED_BUILDER(qc::z), - MQT_NAMED_BUILDER(qir::z)}, + MQT_NAMED_BUILDER(qir::z<>)}, QCToQIRAdaptiveTestCase{"SingleControlledZ", MQT_NAMED_BUILDER(qc::singleControlledZ), - MQT_NAMED_BUILDER(qir::singleControlledZ)}, - QCToQIRAdaptiveTestCase{"MultipleControlledZ", - MQT_NAMED_BUILDER(qc::multipleControlledZ), - MQT_NAMED_BUILDER(qir::multipleControlledZ)})); + MQT_NAMED_BUILDER(qir::singleControlledZ<>)}, + QCToQIRAdaptiveTestCase{ + "MultipleControlledZ", MQT_NAMED_BUILDER(qc::multipleControlledZ), + MQT_NAMED_BUILDER(qir::multipleControlledZ<>)})); /// @} /// \name QCToQIRAdaptive/Operations/MeasureOp.cpp @@ -592,23 +594,24 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveTestCase{ "SingleMeasurementToSingleBit", MQT_NAMED_BUILDER(qc::singleMeasurementToSingleBit), - MQT_NAMED_BUILDER(qir::singleMeasurementToSingleBit)}, + MQT_NAMED_BUILDER(qir::singleMeasurementToSingleBit<>)}, QCToQIRAdaptiveTestCase{ "RepeatedMeasurementToSameBit", MQT_NAMED_BUILDER(qc::repeatedMeasurementToSameBit), - MQT_NAMED_BUILDER(qir::repeatedMeasurementToSameBit)}, + MQT_NAMED_BUILDER(qir::repeatedMeasurementToSameBit<>)}, QCToQIRAdaptiveTestCase{ "RepeatedMeasurementToDifferentBits", MQT_NAMED_BUILDER(qc::repeatedMeasurementToDifferentBits), - MQT_NAMED_BUILDER(qir::repeatedMeasurementToDifferentBits)}, + MQT_NAMED_BUILDER(qir::repeatedMeasurementToDifferentBits<>)}, QCToQIRAdaptiveTestCase{ "MultipleClassicalRegistersAndMeasurements", MQT_NAMED_BUILDER(qc::multipleClassicalRegistersAndMeasurements), - MQT_NAMED_BUILDER(qir::multipleClassicalRegistersAndMeasurements)}, + MQT_NAMED_BUILDER( + qir::multipleClassicalRegistersAndMeasurements)}, QCToQIRAdaptiveTestCase{ "MeasurementWithoutRegisters", MQT_NAMED_BUILDER(qc::measurementWithoutRegisters), - MQT_NAMED_BUILDER(qir::measurementWithoutRegisters)})); + MQT_NAMED_BUILDER(qir::measurementWithoutRegisters<>)})); /// @} /// \name QCToQIRAdaptive/Operations/ResetOp.cpp @@ -618,26 +621,27 @@ INSTANTIATE_TEST_SUITE_P( testing::Values( QCToQIRAdaptiveTestCase{"ResetQubitWithoutOp", MQT_NAMED_BUILDER(qc::resetQubitWithoutOp), - MQT_NAMED_BUILDER(qir::resetQubitWithoutOp)}, + MQT_NAMED_BUILDER(qir::resetQubitWithoutOp<>)}, QCToQIRAdaptiveTestCase{ "ResetMultipleQubitsWithoutOp", MQT_NAMED_BUILDER(qc::resetMultipleQubitsWithoutOp), - MQT_NAMED_BUILDER(qir::resetMultipleQubitsWithoutOp)}, - QCToQIRAdaptiveTestCase{"RepeatedResetWithoutOp", - MQT_NAMED_BUILDER(qc::repeatedResetWithoutOp), - MQT_NAMED_BUILDER(qir::repeatedResetWithoutOp)}, + MQT_NAMED_BUILDER(qir::resetMultipleQubitsWithoutOp<>)}, + QCToQIRAdaptiveTestCase{ + "RepeatedResetWithoutOp", + MQT_NAMED_BUILDER(qc::repeatedResetWithoutOp), + MQT_NAMED_BUILDER(qir::repeatedResetWithoutOp<>)}, QCToQIRAdaptiveTestCase{ "ResetQubitAfterSingleOp", MQT_NAMED_BUILDER(qc::resetQubitAfterSingleOp), - MQT_NAMED_BUILDER(qir::resetQubitAfterSingleOp)}, + MQT_NAMED_BUILDER(qir::resetQubitAfterSingleOp<>)}, QCToQIRAdaptiveTestCase{ "ResetMultipleQubitsAfterSingleOp", MQT_NAMED_BUILDER(qc::resetMultipleQubitsAfterSingleOp), - MQT_NAMED_BUILDER(qir::resetMultipleQubitsAfterSingleOp)}, + MQT_NAMED_BUILDER(qir::resetMultipleQubitsAfterSingleOp<>)}, QCToQIRAdaptiveTestCase{ "RepeatedResetAfterSingleOp", MQT_NAMED_BUILDER(qc::repeatedResetAfterSingleOp), - MQT_NAMED_BUILDER(qir::repeatedResetAfterSingleOp)})); + MQT_NAMED_BUILDER(qir::repeatedResetAfterSingleOp<>)})); /// @} /// \name QCToQIRAdaptive/QubitManagement/QubitManagement.cpp @@ -646,24 +650,24 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRAdaptiveQubitManagementTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"AllocQubit", MQT_NAMED_BUILDER(qc::allocQubit), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::allocQubit<>)}, QCToQIRAdaptiveTestCase{"AllocQubitRegister", MQT_NAMED_BUILDER(qc::allocQubitRegister), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::allocQubitRegister<>)}, QCToQIRAdaptiveTestCase{ "AllocMultipleQubitRegisters", MQT_NAMED_BUILDER(qc::allocMultipleQubitRegisters), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::allocMultipleQubitRegisters<>)}, QCToQIRAdaptiveTestCase{ "AllocMultipleQubitRegistersWithOps", MQT_NAMED_BUILDER(qc::allocMultipleQubitRegistersWithOps), - MQT_NAMED_BUILDER(qir::allocMultipleQubitRegistersWithOps)}, + MQT_NAMED_BUILDER(qir::allocMultipleQubitRegistersWithOps<>)}, QCToQIRAdaptiveTestCase{"AllocLargeRegister", MQT_NAMED_BUILDER(qc::allocLargeRegister), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::allocQubitRegister<>)}, QCToQIRAdaptiveTestCase{"StaticQubits", MQT_NAMED_BUILDER(qc::staticQubits), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::staticQubits)}, QCToQIRAdaptiveTestCase{"StaticQubitsWithOps", MQT_NAMED_BUILDER(qc::staticQubitsWithOps), MQT_NAMED_BUILDER(qir::staticQubitsWithOps)}, @@ -683,7 +687,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(qir::staticQubitsWithInv)}, QCToQIRAdaptiveTestCase{"AllocDeallocPair", MQT_NAMED_BUILDER(qc::allocDeallocPair), - MQT_NAMED_BUILDER(qir::emptyQIR)})); + MQT_NAMED_BUILDER(qir::emptyQIR<>)})); /// @} /// \name QCToQIRAdaptive/Operations/IfOp.cpp @@ -692,15 +696,15 @@ INSTANTIATE_TEST_SUITE_P( SCFIfOpTest, QCToQIRAdaptiveTest, testing::Values( QCToQIRAdaptiveTestCase{"SimpleIfOp", MQT_NAMED_BUILDER(qc::simpleIf), - MQT_NAMED_BUILDER(qir::simpleIf)}, + MQT_NAMED_BUILDER(qir::simpleIf<>)}, QCToQIRAdaptiveTestCase{"IfTwoQubits", MQT_NAMED_BUILDER(qc::ifTwoQubits), - MQT_NAMED_BUILDER(qir::ifTwoQubits)}, + MQT_NAMED_BUILDER(qir::ifTwoQubits<>)}, QCToQIRAdaptiveTestCase{"IfElse", MQT_NAMED_BUILDER(qc::ifElse), - MQT_NAMED_BUILDER(qir::ifElse)}, + MQT_NAMED_BUILDER(qir::ifElse<>)}, QCToQIRAdaptiveTestCase{"NestedIfOpForLoop", MQT_NAMED_BUILDER(qc::nestedIfOpForLoop), - MQT_NAMED_BUILDER(qir::nestedIfOpForLoop)})); + MQT_NAMED_BUILDER(qir::nestedIfOpForLoop<>)})); /// @} /// \name QCToQIRAdaptive/Operations/WhileOp.cpp @@ -710,10 +714,10 @@ INSTANTIATE_TEST_SUITE_P( testing::Values( QCToQIRAdaptiveTestCase{"SimpleWhile", MQT_NAMED_BUILDER(qc::simpleWhileReset), - MQT_NAMED_BUILDER(qir::simpleWhileReset)}, + MQT_NAMED_BUILDER(qir::simpleWhileReset<>)}, QCToQIRAdaptiveTestCase{"SimpleDoWhile", MQT_NAMED_BUILDER(qc::simpleDoWhileReset), - MQT_NAMED_BUILDER(qir::simpleDoWhileReset)})); + MQT_NAMED_BUILDER(qir::simpleDoWhileReset<>)})); /// \name QCToQIRAdaptive/Operations/ForOp.cpp /// @{ @@ -722,26 +726,28 @@ INSTANTIATE_TEST_SUITE_P( testing::Values( QCToQIRAdaptiveTestCase{"SimpleForLoop", MQT_NAMED_BUILDER(qc::simpleForLoop), - MQT_NAMED_BUILDER(qir::simpleForLoop)}, + MQT_NAMED_BUILDER(qir::simpleForLoop<>)}, QCToQIRAdaptiveTestCase{"NestedForLoopIfOp", MQT_NAMED_BUILDER(qc::nestedForLoopIfOp), - MQT_NAMED_BUILDER(qir::nestedForLoopIfOp)}, + MQT_NAMED_BUILDER(qir::nestedForLoopIfOp<>)}, QCToQIRAdaptiveTestCase{"NestedForLoopWhileOp", MQT_NAMED_BUILDER(qc::nestedForLoopWhileOp), - MQT_NAMED_BUILDER(qir::nestedForLoopWhileOp)}, + MQT_NAMED_BUILDER(qir::nestedForLoopWhileOp<>)}, QCToQIRAdaptiveTestCase{ "nestedForLoopCtrlOpWithSeparateQubit", MQT_NAMED_BUILDER(qc::nestedForLoopCtrlOpWithSeparateQubit), - MQT_NAMED_BUILDER(qir::nestedForLoopCtrlOpWithSeparateQubit)}, + MQT_NAMED_BUILDER( + qir::nestedForLoopCtrlOpWithSeparateQubit)}, QCToQIRAdaptiveTestCase{ "nestedForLoopCtrlOpWithExtractedQubit", MQT_NAMED_BUILDER(qc::nestedForLoopCtrlOpWithExtractedQubit), - MQT_NAMED_BUILDER(qir::nestedForLoopCtrlOpWithExtractedQubit)})); + MQT_NAMED_BUILDER( + qir::nestedForLoopCtrlOpWithExtractedQubit)})); /// \name QCToQIRAdaptive/Modifiers/CtrlOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P(QCToQIRCtrlOpTest, QCToQIRAdaptiveTest, testing::Values(QCToQIRAdaptiveTestCase{ "NestedCtrlTwo", MQT_NAMED_BUILDER(qc::ctrlTwo), - MQT_NAMED_BUILDER(qir::ctrlTwo)})); + MQT_NAMED_BUILDER(qir::ctrlTwo<>)})); /// @} diff --git a/mlir/unittests/Conversion/QCToQIR/QCToQIRBase/test_qc_to_qir_base.cpp b/mlir/unittests/Conversion/QCToQIR/QCToQIRBase/test_qc_to_qir_base.cpp index b637247132..4319c3b4d3 100644 --- a/mlir/unittests/Conversion/QCToQIR/QCToQIRBase/test_qc_to_qir_base.cpp +++ b/mlir/unittests/Conversion/QCToQIR/QCToQIRBase/test_qc_to_qir_base.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -42,8 +43,8 @@ namespace { struct QCToQIRBaseTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const QCToQIRBaseTestCase& info); @@ -85,7 +86,7 @@ TEST_P(QCToQIRBaseTest, ProgramEquivalence) { const auto name = " (" + GetParam().name + ")"; mqt::test::DeferredPrinter printer; - auto program = qc::QCProgramBuilder::build(context.get(), programBuilder.fn); + auto program = mqt::test::buildMLIRProgram(context.get(), programBuilder); ASSERT_TRUE(program); printer.record(program.get(), "Original QC IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -102,9 +103,8 @@ TEST_P(QCToQIRBaseTest, ProgramEquivalence) { printer.record(program.get(), "Canonicalized Converted QIR IR" + name); EXPECT_TRUE(verify(*program).succeeded()); - auto reference = - qir::QIRProgramBuilder::build(context.get(), referenceBuilder.fn, - qir::QIRProgramBuilder::Profile::Base); + auto reference = mqt::test::buildMLIRProgram( + context.get(), referenceBuilder, qir::QIRProgramBuilder::Profile::Base); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QIR IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); @@ -123,16 +123,16 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseBarrierOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"Barrier", MQT_NAMED_BUILDER(qc::barrier), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::alloc1QubitRegister<>)}, QCToQIRBaseTestCase{"BarrierTwoQubits", MQT_NAMED_BUILDER(qc::barrierTwoQubits), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::allocQubitRegister<>)}, QCToQIRBaseTestCase{"BarrierMultipleQubits", MQT_NAMED_BUILDER(qc::barrierMultipleQubits), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::alloc3QubitRegister<>)}, QCToQIRBaseTestCase{"SingleControlledBarrier", MQT_NAMED_BUILDER(qc::singleControlledBarrier), - MQT_NAMED_BUILDER(qir::emptyQIR)})); + MQT_NAMED_BUILDER(qir::allocQubitRegister<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/DcxOp.cpp @@ -141,13 +141,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseDCXOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"DCX", MQT_NAMED_BUILDER(qc::dcx), - MQT_NAMED_BUILDER(qir::dcx)}, + MQT_NAMED_BUILDER(qir::dcx<>)}, QCToQIRBaseTestCase{"SingleControlledDCX", MQT_NAMED_BUILDER(qc::singleControlledDcx), - MQT_NAMED_BUILDER(qir::singleControlledDcx)}, + MQT_NAMED_BUILDER(qir::singleControlledDcx<>)}, QCToQIRBaseTestCase{"MultipleControlledDCX", MQT_NAMED_BUILDER(qc::multipleControlledDcx), - MQT_NAMED_BUILDER(qir::multipleControlledDcx)})); + MQT_NAMED_BUILDER(qir::multipleControlledDcx<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/EcrOp.cpp @@ -156,13 +156,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseECROpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"ECR", MQT_NAMED_BUILDER(qc::ecr), - MQT_NAMED_BUILDER(qir::ecr)}, + MQT_NAMED_BUILDER(qir::ecr<>)}, QCToQIRBaseTestCase{"SingleControlledECR", MQT_NAMED_BUILDER(qc::singleControlledEcr), - MQT_NAMED_BUILDER(qir::singleControlledEcr)}, + MQT_NAMED_BUILDER(qir::singleControlledEcr<>)}, QCToQIRBaseTestCase{"MultipleControlledECR", MQT_NAMED_BUILDER(qc::multipleControlledEcr), - MQT_NAMED_BUILDER(qir::multipleControlledEcr)})); + MQT_NAMED_BUILDER(qir::multipleControlledEcr<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/GphaseOp.cpp @@ -170,7 +170,7 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(QCToQIRBaseGPhaseOpTest, QCToQIRBaseTest, testing::Values(QCToQIRBaseTestCase{ "GlobalPhase", MQT_NAMED_BUILDER(qc::globalPhase), - MQT_NAMED_BUILDER(qir::globalPhase)})); + MQT_NAMED_BUILDER(qir::globalPhase<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/HOp.cpp @@ -179,16 +179,16 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseHOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"H", MQT_NAMED_BUILDER(qc::h), - MQT_NAMED_BUILDER(qir::h)}, + MQT_NAMED_BUILDER(qir::h<>)}, QCToQIRBaseTestCase{"SingleControlledH", MQT_NAMED_BUILDER(qc::singleControlledH), - MQT_NAMED_BUILDER(qir::singleControlledH)}, + MQT_NAMED_BUILDER(qir::singleControlledH<>)}, QCToQIRBaseTestCase{"MultipleControlledH", MQT_NAMED_BUILDER(qc::multipleControlledH), - MQT_NAMED_BUILDER(qir::multipleControlledH)}, + MQT_NAMED_BUILDER(qir::multipleControlledH<>)}, QCToQIRBaseTestCase{"HWithoutRegister", MQT_NAMED_BUILDER(qc::hWithoutRegister), - MQT_NAMED_BUILDER(qir::hWithoutRegister)})); + MQT_NAMED_BUILDER(qir::hWithoutRegister<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/IdOp.cpp @@ -197,28 +197,29 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseIDOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"Identity", MQT_NAMED_BUILDER(qc::identity), - MQT_NAMED_BUILDER(qir::identity)}, + MQT_NAMED_BUILDER(qir::identity<>)}, QCToQIRBaseTestCase{"SingleControlledIdentity", MQT_NAMED_BUILDER(qc::singleControlledIdentity), - MQT_NAMED_BUILDER(qir::identity)}, + MQT_NAMED_BUILDER(qir::twoQubitsOneIdentity<>)}, QCToQIRBaseTestCase{"MultipleControlledIdentity", MQT_NAMED_BUILDER(qc::multipleControlledIdentity), - MQT_NAMED_BUILDER(qir::identity)})); + MQT_NAMED_BUILDER(qir::threeQubitsOneIdentity<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/IswapOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseiSWAPOpTest, QCToQIRBaseTest, - testing::Values( - QCToQIRBaseTestCase{"iSWAP", MQT_NAMED_BUILDER(qc::iswap), - MQT_NAMED_BUILDER(qir::iswap)}, - QCToQIRBaseTestCase{"SingleControllediSWAP", - MQT_NAMED_BUILDER(qc::singleControlledIswap), - MQT_NAMED_BUILDER(qir::singleControlledIswap)}, - QCToQIRBaseTestCase{"MultipleControllediSWAP", - MQT_NAMED_BUILDER(qc::multipleControlledIswap), - MQT_NAMED_BUILDER(qir::multipleControlledIswap)})); + testing::Values(QCToQIRBaseTestCase{"iSWAP", MQT_NAMED_BUILDER(qc::iswap), + MQT_NAMED_BUILDER(qir::iswap<>)}, + QCToQIRBaseTestCase{ + "SingleControllediSWAP", + MQT_NAMED_BUILDER(qc::singleControlledIswap), + MQT_NAMED_BUILDER(qir::singleControlledIswap<>)}, + QCToQIRBaseTestCase{ + "MultipleControllediSWAP", + MQT_NAMED_BUILDER(qc::multipleControlledIswap), + MQT_NAMED_BUILDER(qir::multipleControlledIswap<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/POp.cpp @@ -227,13 +228,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBasePOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"P", MQT_NAMED_BUILDER(qc::p), - MQT_NAMED_BUILDER(qir::p)}, + MQT_NAMED_BUILDER(qir::p<>)}, QCToQIRBaseTestCase{"SingleControlledP", MQT_NAMED_BUILDER(qc::singleControlledP), - MQT_NAMED_BUILDER(qir::singleControlledP)}, + MQT_NAMED_BUILDER(qir::singleControlledP<>)}, QCToQIRBaseTestCase{"MultipleControlledP", MQT_NAMED_BUILDER(qc::multipleControlledP), - MQT_NAMED_BUILDER(qir::multipleControlledP)})); + MQT_NAMED_BUILDER(qir::multipleControlledP<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/ROp.cpp @@ -242,13 +243,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseROpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"R", MQT_NAMED_BUILDER(qc::r), - MQT_NAMED_BUILDER(qir::r)}, + MQT_NAMED_BUILDER(qir::r<>)}, QCToQIRBaseTestCase{"SingleControlledR", MQT_NAMED_BUILDER(qc::singleControlledR), - MQT_NAMED_BUILDER(qir::singleControlledR)}, + MQT_NAMED_BUILDER(qir::singleControlledR<>)}, QCToQIRBaseTestCase{"MultipleControlledR", MQT_NAMED_BUILDER(qc::multipleControlledR), - MQT_NAMED_BUILDER(qir::multipleControlledR)})); + MQT_NAMED_BUILDER(qir::multipleControlledR<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/RxOp.cpp @@ -257,13 +258,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseRXOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"RX", MQT_NAMED_BUILDER(qc::rx), - MQT_NAMED_BUILDER(qir::rx)}, + MQT_NAMED_BUILDER(qir::rx<>)}, QCToQIRBaseTestCase{"SingleControlledRX", MQT_NAMED_BUILDER(qc::singleControlledRx), - MQT_NAMED_BUILDER(qir::singleControlledRx)}, + MQT_NAMED_BUILDER(qir::singleControlledRx<>)}, QCToQIRBaseTestCase{"MultipleControlledRX", MQT_NAMED_BUILDER(qc::multipleControlledRx), - MQT_NAMED_BUILDER(qir::multipleControlledRx)})); + MQT_NAMED_BUILDER(qir::multipleControlledRx<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/RxxOp.cpp @@ -272,13 +273,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseRXXOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"RXX", MQT_NAMED_BUILDER(qc::rxx), - MQT_NAMED_BUILDER(qir::rxx)}, + MQT_NAMED_BUILDER(qir::rxx<>)}, QCToQIRBaseTestCase{"SingleControlledRXX", MQT_NAMED_BUILDER(qc::singleControlledRxx), - MQT_NAMED_BUILDER(qir::singleControlledRxx)}, + MQT_NAMED_BUILDER(qir::singleControlledRxx<>)}, QCToQIRBaseTestCase{"MultipleControlledRXX", MQT_NAMED_BUILDER(qc::multipleControlledRxx), - MQT_NAMED_BUILDER(qir::multipleControlledRxx)})); + MQT_NAMED_BUILDER(qir::multipleControlledRxx<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/RyOp.cpp @@ -287,13 +288,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseRYOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"RY", MQT_NAMED_BUILDER(qc::ry), - MQT_NAMED_BUILDER(qir::ry)}, + MQT_NAMED_BUILDER(qir::ry<>)}, QCToQIRBaseTestCase{"SingleControlledRY", MQT_NAMED_BUILDER(qc::singleControlledRy), - MQT_NAMED_BUILDER(qir::singleControlledRy)}, + MQT_NAMED_BUILDER(qir::singleControlledRy<>)}, QCToQIRBaseTestCase{"MultipleControlledRY", MQT_NAMED_BUILDER(qc::multipleControlledRy), - MQT_NAMED_BUILDER(qir::multipleControlledRy)})); + MQT_NAMED_BUILDER(qir::multipleControlledRy<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/RyyOp.cpp @@ -302,13 +303,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseRYYOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"RYY", MQT_NAMED_BUILDER(qc::ryy), - MQT_NAMED_BUILDER(qir::ryy)}, + MQT_NAMED_BUILDER(qir::ryy<>)}, QCToQIRBaseTestCase{"SingleControlledRYY", MQT_NAMED_BUILDER(qc::singleControlledRyy), - MQT_NAMED_BUILDER(qir::singleControlledRyy)}, + MQT_NAMED_BUILDER(qir::singleControlledRyy<>)}, QCToQIRBaseTestCase{"MultipleControlledRYY", MQT_NAMED_BUILDER(qc::multipleControlledRyy), - MQT_NAMED_BUILDER(qir::multipleControlledRyy)})); + MQT_NAMED_BUILDER(qir::multipleControlledRyy<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/RzOp.cpp @@ -317,13 +318,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseRZOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"RZ", MQT_NAMED_BUILDER(qc::rz), - MQT_NAMED_BUILDER(qir::rz)}, + MQT_NAMED_BUILDER(qir::rz<>)}, QCToQIRBaseTestCase{"SingleControlledRZ", MQT_NAMED_BUILDER(qc::singleControlledRz), - MQT_NAMED_BUILDER(qir::singleControlledRz)}, + MQT_NAMED_BUILDER(qir::singleControlledRz<>)}, QCToQIRBaseTestCase{"MultipleControlledRZ", MQT_NAMED_BUILDER(qc::multipleControlledRz), - MQT_NAMED_BUILDER(qir::multipleControlledRz)})); + MQT_NAMED_BUILDER(qir::multipleControlledRz<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/RzxOp.cpp @@ -332,13 +333,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseRZXOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"RZX", MQT_NAMED_BUILDER(qc::rzx), - MQT_NAMED_BUILDER(qir::rzx)}, + MQT_NAMED_BUILDER(qir::rzx<>)}, QCToQIRBaseTestCase{"SingleControlledRZX", MQT_NAMED_BUILDER(qc::singleControlledRzx), - MQT_NAMED_BUILDER(qir::singleControlledRzx)}, + MQT_NAMED_BUILDER(qir::singleControlledRzx<>)}, QCToQIRBaseTestCase{"MultipleControlledRZX", MQT_NAMED_BUILDER(qc::multipleControlledRzx), - MQT_NAMED_BUILDER(qir::multipleControlledRzx)})); + MQT_NAMED_BUILDER(qir::multipleControlledRzx<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/RzzOp.cpp @@ -347,13 +348,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseRZZOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"RZZ", MQT_NAMED_BUILDER(qc::rzz), - MQT_NAMED_BUILDER(qir::rzz)}, + MQT_NAMED_BUILDER(qir::rzz<>)}, QCToQIRBaseTestCase{"SingleControlledRZZ", MQT_NAMED_BUILDER(qc::singleControlledRzz), - MQT_NAMED_BUILDER(qir::singleControlledRzz)}, + MQT_NAMED_BUILDER(qir::singleControlledRzz<>)}, QCToQIRBaseTestCase{"MultipleControlledRZZ", MQT_NAMED_BUILDER(qc::multipleControlledRzz), - MQT_NAMED_BUILDER(qir::multipleControlledRzz)})); + MQT_NAMED_BUILDER(qir::multipleControlledRzz<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/SOp.cpp @@ -362,13 +363,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseSOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"S", MQT_NAMED_BUILDER(qc::s), - MQT_NAMED_BUILDER(qir::s)}, + MQT_NAMED_BUILDER(qir::s<>)}, QCToQIRBaseTestCase{"SingleControlledS", MQT_NAMED_BUILDER(qc::singleControlledS), - MQT_NAMED_BUILDER(qir::singleControlledS)}, + MQT_NAMED_BUILDER(qir::singleControlledS<>)}, QCToQIRBaseTestCase{"MultipleControlledS", MQT_NAMED_BUILDER(qc::multipleControlledS), - MQT_NAMED_BUILDER(qir::multipleControlledS)})); + MQT_NAMED_BUILDER(qir::multipleControlledS<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/SdgOp.cpp @@ -377,13 +378,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseSdgOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"Sdg", MQT_NAMED_BUILDER(qc::sdg), - MQT_NAMED_BUILDER(qir::sdg)}, + MQT_NAMED_BUILDER(qir::sdg<>)}, QCToQIRBaseTestCase{"SingleControlledSdg", MQT_NAMED_BUILDER(qc::singleControlledSdg), - MQT_NAMED_BUILDER(qir::singleControlledSdg)}, + MQT_NAMED_BUILDER(qir::singleControlledSdg<>)}, QCToQIRBaseTestCase{"MultipleControlledSdg", MQT_NAMED_BUILDER(qc::multipleControlledSdg), - MQT_NAMED_BUILDER(qir::multipleControlledSdg)})); + MQT_NAMED_BUILDER(qir::multipleControlledSdg<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/SwapOp.cpp @@ -392,13 +393,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseSWAPOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"SWAP", MQT_NAMED_BUILDER(qc::swap), - MQT_NAMED_BUILDER(qir::swap)}, + MQT_NAMED_BUILDER(qir::swap<>)}, QCToQIRBaseTestCase{"SingleControlledSWAP", MQT_NAMED_BUILDER(qc::singleControlledSwap), - MQT_NAMED_BUILDER(qir::singleControlledSwap)}, + MQT_NAMED_BUILDER(qir::singleControlledSwap<>)}, QCToQIRBaseTestCase{"MultipleControlledSWAP", MQT_NAMED_BUILDER(qc::multipleControlledSwap), - MQT_NAMED_BUILDER(qir::multipleControlledSwap)})); + MQT_NAMED_BUILDER(qir::multipleControlledSwap<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/SxOp.cpp @@ -407,13 +408,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseSXOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"SX", MQT_NAMED_BUILDER(qc::sx), - MQT_NAMED_BUILDER(qir::sx)}, + MQT_NAMED_BUILDER(qir::sx<>)}, QCToQIRBaseTestCase{"SingleControlledSX", MQT_NAMED_BUILDER(qc::singleControlledSx), - MQT_NAMED_BUILDER(qir::singleControlledSx)}, + MQT_NAMED_BUILDER(qir::singleControlledSx<>)}, QCToQIRBaseTestCase{"MultipleControlledSX", MQT_NAMED_BUILDER(qc::multipleControlledSx), - MQT_NAMED_BUILDER(qir::multipleControlledSx)})); + MQT_NAMED_BUILDER(qir::multipleControlledSx<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/SxdgOp.cpp @@ -422,13 +423,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseSXdgOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"SXdg", MQT_NAMED_BUILDER(qc::sxdg), - MQT_NAMED_BUILDER(qir::sxdg)}, + MQT_NAMED_BUILDER(qir::sxdg<>)}, QCToQIRBaseTestCase{"SingleControlledSXdg", MQT_NAMED_BUILDER(qc::singleControlledSxdg), - MQT_NAMED_BUILDER(qir::singleControlledSxdg)}, + MQT_NAMED_BUILDER(qir::singleControlledSxdg<>)}, QCToQIRBaseTestCase{"MultipleControlledSXdg", MQT_NAMED_BUILDER(qc::multipleControlledSxdg), - MQT_NAMED_BUILDER(qir::multipleControlledSxdg)})); + MQT_NAMED_BUILDER(qir::multipleControlledSxdg<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/TOp.cpp @@ -437,13 +438,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseTOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"T", MQT_NAMED_BUILDER(qc::t_), - MQT_NAMED_BUILDER(qir::t_)}, + MQT_NAMED_BUILDER(qir::t_<>)}, QCToQIRBaseTestCase{"SingleControlledT", MQT_NAMED_BUILDER(qc::singleControlledT), - MQT_NAMED_BUILDER(qir::singleControlledT)}, + MQT_NAMED_BUILDER(qir::singleControlledT<>)}, QCToQIRBaseTestCase{"MultipleControlledT", MQT_NAMED_BUILDER(qc::multipleControlledT), - MQT_NAMED_BUILDER(qir::multipleControlledT)})); + MQT_NAMED_BUILDER(qir::multipleControlledT<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/TdgOp.cpp @@ -452,13 +453,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseTdgOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"Tdg", MQT_NAMED_BUILDER(qc::tdg), - MQT_NAMED_BUILDER(qir::tdg)}, + MQT_NAMED_BUILDER(qir::tdg<>)}, QCToQIRBaseTestCase{"SingleControlledTdg", MQT_NAMED_BUILDER(qc::singleControlledTdg), - MQT_NAMED_BUILDER(qir::singleControlledTdg)}, + MQT_NAMED_BUILDER(qir::singleControlledTdg<>)}, QCToQIRBaseTestCase{"MultipleControlledTdg", MQT_NAMED_BUILDER(qc::multipleControlledTdg), - MQT_NAMED_BUILDER(qir::multipleControlledTdg)})); + MQT_NAMED_BUILDER(qir::multipleControlledTdg<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/U2Op.cpp @@ -467,13 +468,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseU2OpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"U2", MQT_NAMED_BUILDER(qc::u2), - MQT_NAMED_BUILDER(qir::u2)}, + MQT_NAMED_BUILDER(qir::u2<>)}, QCToQIRBaseTestCase{"SingleControlledU2", MQT_NAMED_BUILDER(qc::singleControlledU2), - MQT_NAMED_BUILDER(qir::singleControlledU2)}, + MQT_NAMED_BUILDER(qir::singleControlledU2<>)}, QCToQIRBaseTestCase{"MultipleControlledU2", MQT_NAMED_BUILDER(qc::multipleControlledU2), - MQT_NAMED_BUILDER(qir::multipleControlledU2)})); + MQT_NAMED_BUILDER(qir::multipleControlledU2<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/UOp.cpp @@ -482,13 +483,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseUOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"U", MQT_NAMED_BUILDER(qc::u), - MQT_NAMED_BUILDER(qir::u)}, + MQT_NAMED_BUILDER(qir::u<>)}, QCToQIRBaseTestCase{"SingleControlledU", MQT_NAMED_BUILDER(qc::singleControlledU), - MQT_NAMED_BUILDER(qir::singleControlledU)}, + MQT_NAMED_BUILDER(qir::singleControlledU<>)}, QCToQIRBaseTestCase{"MultipleControlledU", MQT_NAMED_BUILDER(qc::multipleControlledU), - MQT_NAMED_BUILDER(qir::multipleControlledU)})); + MQT_NAMED_BUILDER(qir::multipleControlledU<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/XOp.cpp @@ -497,13 +498,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseXOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"X", MQT_NAMED_BUILDER(qc::x), - MQT_NAMED_BUILDER(qir::x)}, + MQT_NAMED_BUILDER(qir::x<>)}, QCToQIRBaseTestCase{"SingleControlledX", MQT_NAMED_BUILDER(qc::singleControlledX), - MQT_NAMED_BUILDER(qir::singleControlledX)}, + MQT_NAMED_BUILDER(qir::singleControlledX<>)}, QCToQIRBaseTestCase{"MultipleControlledX", MQT_NAMED_BUILDER(qc::multipleControlledX), - MQT_NAMED_BUILDER(qir::multipleControlledX)})); + MQT_NAMED_BUILDER(qir::multipleControlledX<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/XxMinusYyOp.cpp @@ -512,14 +513,15 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseXXMinusYYOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"XXMinusYY", MQT_NAMED_BUILDER(qc::xxMinusYY), - MQT_NAMED_BUILDER(qir::xxMinusYY)}, - QCToQIRBaseTestCase{"SingleControlledXXMinusYY", - MQT_NAMED_BUILDER(qc::singleControlledXxMinusYY), - MQT_NAMED_BUILDER(qir::singleControlledXxMinusYY)}, + MQT_NAMED_BUILDER(qir::xxMinusYY<>)}, + QCToQIRBaseTestCase{ + "SingleControlledXXMinusYY", + MQT_NAMED_BUILDER(qc::singleControlledXxMinusYY), + MQT_NAMED_BUILDER(qir::singleControlledXxMinusYY<>)}, QCToQIRBaseTestCase{ "MultipleControlledXXMinusYY", MQT_NAMED_BUILDER(qc::multipleControlledXxMinusYY), - MQT_NAMED_BUILDER(qir::multipleControlledXxMinusYY)})); + MQT_NAMED_BUILDER(qir::multipleControlledXxMinusYY<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/XxPlusYyOp.cpp @@ -528,14 +530,14 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseXXPlusYYOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"XXPlusYY", MQT_NAMED_BUILDER(qc::xxPlusYY), - MQT_NAMED_BUILDER(qir::xxPlusYY)}, + MQT_NAMED_BUILDER(qir::xxPlusYY<>)}, QCToQIRBaseTestCase{"SingleControlledXXPlusYY", MQT_NAMED_BUILDER(qc::singleControlledXxPlusYY), - MQT_NAMED_BUILDER(qir::singleControlledXxPlusYY)}, + MQT_NAMED_BUILDER(qir::singleControlledXxPlusYY<>)}, QCToQIRBaseTestCase{ "MultipleControlledXXPlusYY", MQT_NAMED_BUILDER(qc::multipleControlledXxPlusYY), - MQT_NAMED_BUILDER(qir::multipleControlledXxPlusYY)})); + MQT_NAMED_BUILDER(qir::multipleControlledXxPlusYY<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/YOp.cpp @@ -544,13 +546,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseYOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"Y", MQT_NAMED_BUILDER(qc::y), - MQT_NAMED_BUILDER(qir::y)}, + MQT_NAMED_BUILDER(qir::y<>)}, QCToQIRBaseTestCase{"SingleControlledY", MQT_NAMED_BUILDER(qc::singleControlledY), - MQT_NAMED_BUILDER(qir::singleControlledY)}, + MQT_NAMED_BUILDER(qir::singleControlledY<>)}, QCToQIRBaseTestCase{"MultipleControlledY", MQT_NAMED_BUILDER(qc::multipleControlledY), - MQT_NAMED_BUILDER(qir::multipleControlledY)})); + MQT_NAMED_BUILDER(qir::multipleControlledY<>)})); /// @} /// \name QCToQIRBase/Operations/StandardGates/ZOp.cpp @@ -559,13 +561,13 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseZOpTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"Z", MQT_NAMED_BUILDER(qc::z), - MQT_NAMED_BUILDER(qir::z)}, + MQT_NAMED_BUILDER(qir::z<>)}, QCToQIRBaseTestCase{"SingleControlledZ", MQT_NAMED_BUILDER(qc::singleControlledZ), - MQT_NAMED_BUILDER(qir::singleControlledZ)}, + MQT_NAMED_BUILDER(qir::singleControlledZ<>)}, QCToQIRBaseTestCase{"MultipleControlledZ", MQT_NAMED_BUILDER(qc::multipleControlledZ), - MQT_NAMED_BUILDER(qir::multipleControlledZ)})); + MQT_NAMED_BUILDER(qir::multipleControlledZ<>)})); /// @} /// \name QCToQIRBase/Operations/MeasureOp.cpp @@ -576,23 +578,24 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseTestCase{ "SingleMeasurementToSingleBit", MQT_NAMED_BUILDER(qc::singleMeasurementToSingleBit), - MQT_NAMED_BUILDER(qir::singleMeasurementToSingleBit)}, + MQT_NAMED_BUILDER(qir::singleMeasurementToSingleBit<>)}, QCToQIRBaseTestCase{ "RepeatedMeasurementToSameBit", MQT_NAMED_BUILDER(qc::repeatedMeasurementToSameBit), - MQT_NAMED_BUILDER(qir::repeatedMeasurementToSameBit)}, + MQT_NAMED_BUILDER(qir::repeatedMeasurementToSameBit<>)}, QCToQIRBaseTestCase{ "RepeatedMeasurementToDifferentBits", MQT_NAMED_BUILDER(qc::repeatedMeasurementToDifferentBits), - MQT_NAMED_BUILDER(qir::repeatedMeasurementToDifferentBits)}, + MQT_NAMED_BUILDER(qir::repeatedMeasurementToDifferentBits<>)}, QCToQIRBaseTestCase{ "MultipleClassicalRegistersAndMeasurements", MQT_NAMED_BUILDER(qc::multipleClassicalRegistersAndMeasurements), - MQT_NAMED_BUILDER(qir::multipleClassicalRegistersAndMeasurements)}, + MQT_NAMED_BUILDER( + qir::multipleClassicalRegistersAndMeasurements)}, QCToQIRBaseTestCase{ "MeasurementWithoutRegisters", MQT_NAMED_BUILDER(qc::measurementWithoutRegisters), - MQT_NAMED_BUILDER(qir::measurementWithoutRegisters)})); + MQT_NAMED_BUILDER(qir::measurementWithoutRegisters<>)})); /// @} /// \name QCToQIRBase/QubitManagement/QubitManagement.cpp @@ -601,22 +604,23 @@ INSTANTIATE_TEST_SUITE_P( QCToQIRBaseQubitManagementTest, QCToQIRBaseTest, testing::Values( QCToQIRBaseTestCase{"AllocQubit", MQT_NAMED_BUILDER(qc::allocQubit), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::allocQubit<>)}, QCToQIRBaseTestCase{"AllocQubitRegister", MQT_NAMED_BUILDER(qc::allocQubitRegister), - MQT_NAMED_BUILDER(qir::emptyQIR)}, - QCToQIRBaseTestCase{"AllocMultipleQubitRegisters", - MQT_NAMED_BUILDER(qc::allocMultipleQubitRegisters), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::allocQubitRegister<>)}, + QCToQIRBaseTestCase{ + "AllocMultipleQubitRegisters", + MQT_NAMED_BUILDER(qc::allocMultipleQubitRegisters), + MQT_NAMED_BUILDER(qir::allocMultipleQubitRegisters<>)}, QCToQIRBaseTestCase{ "AllocMultipleQubitRegistersWithOps", MQT_NAMED_BUILDER(qc::allocMultipleQubitRegistersWithOps), - MQT_NAMED_BUILDER(qir::allocMultipleQubitRegistersWithOps)}, + MQT_NAMED_BUILDER(qir::allocMultipleQubitRegistersWithOps<>)}, QCToQIRBaseTestCase{"AllocLargeRegister", MQT_NAMED_BUILDER(qc::allocLargeRegister), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::allocQubitRegister<>)}, QCToQIRBaseTestCase{"StaticQubits", MQT_NAMED_BUILDER(qc::staticQubits), - MQT_NAMED_BUILDER(qir::emptyQIR)}, + MQT_NAMED_BUILDER(qir::staticQubits)}, QCToQIRBaseTestCase{"StaticQubitsWithOps", MQT_NAMED_BUILDER(qc::staticQubitsWithOps), MQT_NAMED_BUILDER(qir::staticQubitsWithOps)}, @@ -636,5 +640,5 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(qir::staticQubitsWithInv)}, QCToQIRBaseTestCase{"AllocDeallocPair", MQT_NAMED_BUILDER(qc::allocDeallocPair), - MQT_NAMED_BUILDER(qir::emptyQIR)})); + MQT_NAMED_BUILDER(qir::emptyQIR<>)})); /// @} diff --git a/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp b/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp index f80bf807b6..08d56935ed 100644 --- a/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp +++ b/mlir/unittests/Dialect/QC/IR/test_qc_ir.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -35,8 +36,8 @@ namespace { struct QCTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const QCTestCase& info); }; @@ -73,7 +74,7 @@ TEST_P(QCTest, ProgramEquivalence) { const auto name = " (" + GetParam().name + ")"; mqt::test::DeferredPrinter printer; - auto program = QCProgramBuilder::build(context.get(), programBuilder.fn); + auto program = mqt::test::buildMLIRProgram(context.get(), programBuilder); ASSERT_TRUE(program); printer.record(program.get(), "Original QC IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -82,7 +83,7 @@ TEST_P(QCTest, ProgramEquivalence) { printer.record(program.get(), "Canonicalized QC IR" + name); EXPECT_TRUE(verify(*program).succeeded()); - auto reference = QCProgramBuilder::build(context.get(), referenceBuilder.fn); + auto reference = mqt::test::buildMLIRProgram(context.get(), referenceBuilder); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QC IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); @@ -212,7 +213,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(barrierMultipleQubits)}, QCTestCase{"SingleControlledBarrier", MQT_NAMED_BUILDER(singleControlledBarrier), - MQT_NAMED_BUILDER(barrier)}, + MQT_NAMED_BUILDER(twoQubitsOneBarrier)}, QCTestCase{"InverseBarrier", MQT_NAMED_BUILDER(inverseBarrier), MQT_NAMED_BUILDER(barrier)})); @@ -286,7 +287,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(singleControlledP)}, QCTestCase{"TrivialControlledGlobalPhase", MQT_NAMED_BUILDER(trivialControlledGlobalPhase), - MQT_NAMED_BUILDER(globalPhase)}, + MQT_NAMED_BUILDER(globalPhaseAndMeasure)}, QCTestCase{"InverseGlobalPhase", MQT_NAMED_BUILDER(inverseGlobalPhase), MQT_NAMED_BUILDER(globalPhase)}, QCTestCase{"InverseMultipleControlledGlobalPhase", @@ -325,13 +326,13 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(identity)}, QCTestCase{"SingleControlledIdentity", MQT_NAMED_BUILDER(singleControlledIdentity), - MQT_NAMED_BUILDER(identity)}, + MQT_NAMED_BUILDER(twoQubitsOneIdentity)}, QCTestCase{"MultipleControlledIdentity", MQT_NAMED_BUILDER(multipleControlledIdentity), - MQT_NAMED_BUILDER(identity)}, + MQT_NAMED_BUILDER(threeQubitsOneIdentity)}, QCTestCase{"NestedControlledIdentity", MQT_NAMED_BUILDER(nestedControlledIdentity), - MQT_NAMED_BUILDER(identity)}, + MQT_NAMED_BUILDER(threeQubitsOneIdentity)}, QCTestCase{"TrivialControlledIdentity", MQT_NAMED_BUILDER(trivialControlledIdentity), MQT_NAMED_BUILDER(identity)}, @@ -339,7 +340,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(identity)}, QCTestCase{"InverseMultipleControlledIdentity", MQT_NAMED_BUILDER(inverseMultipleControlledIdentity), - MQT_NAMED_BUILDER(identity)})); + MQT_NAMED_BUILDER(threeQubitsOneIdentity)})); /// @} /// \name QC/Operations/StandardGates/IswapOp.cpp @@ -915,16 +916,11 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QCQubitManagementTest, QCTest, testing::Values( - QCTestCase{"AllocQubit", MQT_NAMED_BUILDER(allocQubit), - MQT_NAMED_BUILDER(emptyQC)}, - QCTestCase{"AllocQubitRegister", MQT_NAMED_BUILDER(allocQubitRegister), - MQT_NAMED_BUILDER(emptyQC)}, - QCTestCase{"AllocMultipleQubitRegisters", - MQT_NAMED_BUILDER(allocMultipleQubitRegisters), + QCTestCase{"AllocQubit", MQT_NAMED_BUILDER(allocQubitNoMeasure), MQT_NAMED_BUILDER(emptyQC)}, QCTestCase{"AllocLargeRegister", MQT_NAMED_BUILDER(allocLargeRegister), - MQT_NAMED_BUILDER(emptyQC)}, - QCTestCase{"StaticQubits", MQT_NAMED_BUILDER(staticQubits), + MQT_NAMED_BUILDER(allocQubitRegister)}, + QCTestCase{"StaticQubits", MQT_NAMED_BUILDER(staticQubitsNoMeasure), MQT_NAMED_BUILDER(emptyQC)}, QCTestCase{"StaticQubitsWithOps", MQT_NAMED_BUILDER(staticQubitsWithOps), diff --git a/mlir/unittests/Dialect/QC/Translation/test_qasm3_translation.cpp b/mlir/unittests/Dialect/QC/Translation/test_qasm3_translation.cpp index b18c858b2d..c99059aa77 100644 --- a/mlir/unittests/Dialect/QC/Translation/test_qasm3_translation.cpp +++ b/mlir/unittests/Dialect/QC/Translation/test_qasm3_translation.cpp @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include #include @@ -37,7 +39,7 @@ namespace { struct QASM3TranslationTestCase { std::string name; std::string source; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const QASM3TranslationTestCase& test); @@ -67,32 +69,47 @@ class QASM3TranslationTest } // namespace -static void twoX(qc::QCProgramBuilder& b) { +static SmallVector twoX(qc::QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.x(q[0]); b.x(q[1]); + auto c0 = b.measure(q[0]); + auto c1 = b.measure(q[1]); + return {c0, c1}; } -static void singleNegControlledX(qc::QCProgramBuilder& b) { +static SmallVector singleNegControlledX(qc::QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.x(q[0]); b.cx(q[0], q[1]); b.x(q[0]); + auto c0 = b.measure(q[0]); + auto c1 = b.measure(q[1]); + return {c0, c1}; } -static void tripleControlledX(qc::QCProgramBuilder& b) { +static SmallVector tripleControlledX(qc::QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcx({q[0], q[1], q[2]}, q[3]); + auto c0 = b.measure(q[0]); + auto c1 = b.measure(q[1]); + auto c2 = b.measure(q[2]); + auto c3 = b.measure(q[3]); + return {c0, c1, c2, c3}; } -static void mixedControlledX(qc::QCProgramBuilder& b) { +static SmallVector mixedControlledX(qc::QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.x(q[1]); b.mcx({q[0], q[1]}, q[2]); b.x(q[1]); + auto c0 = b.measure(q[0]); + auto c1 = b.measure(q[1]); + auto c2 = b.measure(q[2]); + return {c0, c1, c2}; } -static void twoMixedControlledX(qc::QCProgramBuilder& b) { +static SmallVector twoMixedControlledX(qc::QCProgramBuilder& b) { auto q1 = b.allocQubitRegister(2); auto q2 = b.allocQubitRegister(2); auto q3 = b.allocQubitRegister(2); @@ -102,15 +119,24 @@ static void twoMixedControlledX(qc::QCProgramBuilder& b) { b.x(q2[1]); b.mcx({q1[1], q2[1]}, q3[1]); b.x(q2[1]); + auto c0 = b.measure(q1[0]); + auto c1 = b.measure(q1[1]); + auto c2 = b.measure(q2[0]); + auto c3 = b.measure(q2[1]); + auto c4 = b.measure(q3[0]); + auto c5 = b.measure(q3[1]); + return {c0, c1, c2, c3, c4, c5}; } -static void ifNot(qc::QCProgramBuilder& b) { +static Value ifNot(qc::QCProgramBuilder& b) { auto trueValue = b.boolConstant(true); auto q = b.allocQubitRegister(1); b.h(q[0]); auto c = b.measure(q[0]); auto cond = arith::XOrIOp::create(b, c, trueValue).getResult(); b.scfIf(cond, [&] { b.x(q[0]); }); + auto out = b.measure(q[0]); + return out; } TEST_P(QASM3TranslationTest, ProgramEquivalence) { @@ -128,8 +154,7 @@ TEST_P(QASM3TranslationTest, ProgramEquivalence) { printer.record(translated.get(), "Canonicalized Translated QC IR" + name); EXPECT_TRUE(verify(*translated).succeeded()); - auto reference = - qc::QCProgramBuilder::build(context.get(), referenceBuilder.fn); + auto reference = mqt::test::buildMLIRProgram(context.get(), referenceBuilder); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QC IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); @@ -147,7 +172,7 @@ INSTANTIATE_TEST_SUITE_P( testing::Values( QASM3TranslationTestCase{"AllocQubit", qasm::allocQubit, - MQT_NAMED_BUILDER(qc::allocQubit)}, + MQT_NAMED_BUILDER(qc::alloc1QubitRegister)}, QASM3TranslationTestCase{"AllocQubitRegister", qasm::allocQubitRegister, MQT_NAMED_BUILDER(qc::allocQubitRegister)}, QASM3TranslationTestCase{ @@ -185,12 +210,12 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(qc::inverseGlobalPhase)}, QASM3TranslationTestCase{"Identity", qasm::identity, MQT_NAMED_BUILDER(qc::identity)}, - QASM3TranslationTestCase{ - "SingleControlledIdentity", qasm::singleControlledIdentity, - MQT_NAMED_BUILDER(qc::singleControlledIdentity)}, - QASM3TranslationTestCase{ - "MultipleControlledIdentity", qasm::multipleControlledIdentity, - MQT_NAMED_BUILDER(qc::multipleControlledIdentity)}, + QASM3TranslationTestCase{"SingleControlledIdentity", + qasm::singleControlledIdentity, + MQT_NAMED_BUILDER(qc::twoQubitsOneIdentity)}, + QASM3TranslationTestCase{"MultipleControlledIdentity", + qasm::multipleControlledIdentity, + MQT_NAMED_BUILDER(qc::threeQubitsOneIdentity)}, QASM3TranslationTestCase{"X", qasm::x, MQT_NAMED_BUILDER(qc::x)}, QASM3TranslationTestCase{"TwoX", qasm::twoX, MQT_NAMED_BUILDER(twoX)}, QASM3TranslationTestCase{"SingleControlledX", qasm::singleControlledX, diff --git a/mlir/unittests/Dialect/QC/Translation/test_quantum_computation_translation.cpp b/mlir/unittests/Dialect/QC/Translation/test_quantum_computation_translation.cpp index b47c9f97a7..b94e3f082c 100644 --- a/mlir/unittests/Dialect/QC/Translation/test_quantum_computation_translation.cpp +++ b/mlir/unittests/Dialect/QC/Translation/test_quantum_computation_translation.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,7 @@ namespace { struct QuantumComputationTranslationTestCase { std::string name; mqt::test::NamedBuilder<::qc::QuantumComputation> programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, @@ -87,8 +88,7 @@ TEST_P(QuantumComputationTranslationTest, ProgramEquivalence) { printer.record(translated.get(), "Canonicalized Translated QC IR" + name); EXPECT_TRUE(mlir::verify(*translated).succeeded()); - auto reference = - mlir::qc::QCProgramBuilder::build(context.get(), referenceBuilder.fn); + auto reference = mqt::test::buildMLIRProgram(context.get(), referenceBuilder); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QC IR" + name); EXPECT_TRUE(mlir::verify(*reference).succeeded()); @@ -107,7 +107,7 @@ INSTANTIATE_TEST_SUITE_P( testing::Values( QuantumComputationTranslationTestCase{ "AllocQubit", MQT_NAMED_BUILDER(qc::allocQubit), - MQT_NAMED_BUILDER(mlir::qc::allocQubit)}, + MQT_NAMED_BUILDER(mlir::qc::alloc1QubitRegister)}, QuantumComputationTranslationTestCase{ "AllocQubitRegister", MQT_NAMED_BUILDER(qc::allocQubitRegister), MQT_NAMED_BUILDER(mlir::qc::allocQubitRegister)}, @@ -160,7 +160,7 @@ INSTANTIATE_TEST_SUITE_P( QuantumComputationTranslationTestCase{ "MultipleControlledIdentity", MQT_NAMED_BUILDER(qc::multipleControlledIdentity), - MQT_NAMED_BUILDER(mlir::qc::multipleControlledIdentity)}, + MQT_NAMED_BUILDER(mlir::qc::threeQubitsOneIdentity)}, QuantumComputationTranslationTestCase{"X", MQT_NAMED_BUILDER(qc::x), MQT_NAMED_BUILDER(mlir::qc::x)}, QuantumComputationTranslationTestCase{ diff --git a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp index cbf54cf10d..5d829b6284 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -39,8 +40,8 @@ namespace { struct QCOTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const QCOTestCase& info); }; @@ -74,7 +75,7 @@ TEST_P(QCOTest, ProgramEquivalence) { const auto name = " (" + GetParam().name + ")"; mqt::test::DeferredPrinter printer; - auto program = QCOProgramBuilder::build(context.get(), programBuilder.fn); + auto program = mqt::test::buildMLIRProgram(context.get(), programBuilder); ASSERT_TRUE(program); printer.record(program.get(), "Original QCO IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -83,7 +84,7 @@ 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 = mqt::test::buildMLIRProgram(context.get(), referenceBuilder); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QCO IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); @@ -117,7 +118,7 @@ TEST_F(QCOTest, BuilderRejectsMixedStaticAndDynamicQubitAllocationModes) { TEST_F(QCOTest, DirectIfBuilder) { // Test If construction directly QCOProgramBuilder builder(context.get()); - builder.initialize(); + builder.initialize({builder.getI1Type(), builder.getI1Type()}); auto c0 = arith::ConstantIndexOp::create(builder, 0); auto c1 = arith::ConstantIndexOp::create(builder, 1); auto r0 = qtensor::AllocOp::create(builder, c1); @@ -130,18 +131,20 @@ 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({measureOp.getResult(), 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); + mqt::test::buildMLIRProgram(context.get(), MQT_NAMED_BUILDER(simpleIf)); ASSERT_TRUE(refBuilder); EXPECT_TRUE(verify(*refBuilder).succeeded()); EXPECT_TRUE(runQCOCleanupPipeline(refBuilder.get()).succeeded()); @@ -155,10 +158,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 @@ -172,9 +174,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 } })"; @@ -185,8 +188,8 @@ TEST_F(QCOTest, IfOpParser) { EXPECT_TRUE(runQCOCleanupPipeline(parsedSourceModule.get()).succeeded()); EXPECT_TRUE(verify(*parsedSourceModule).succeeded()); - auto refBuilder = QCOProgramBuilder::build( - context.get(), MQT_NAMED_BUILDER(ifOneQubitOneTensor).fn); + auto refBuilder = mqt::test::buildMLIRProgram( + context.get(), MQT_NAMED_BUILDER(ifOneQubitOneTensor)); ASSERT_TRUE(refBuilder); EXPECT_TRUE(verify(*refBuilder).succeeded()); EXPECT_TRUE(runQCOCleanupPipeline(refBuilder.get()).succeeded()); @@ -308,7 +311,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 @@ -335,7 +338,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 @@ -379,7 +382,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 @@ -388,24 +391,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(alloc1QubitRegister)}, QCOTestCase{"InverseMultipleControlledIdentity", MQT_NAMED_BUILDER(inverseMultipleControlledIdentity), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc3QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/IswapOp.cpp @@ -455,7 +458,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 @@ -507,7 +510,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 @@ -540,10 +543,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 @@ -568,7 +571,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 @@ -601,10 +604,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 @@ -629,7 +632,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 @@ -657,7 +660,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 @@ -690,10 +693,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 @@ -717,7 +720,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)})); /// @} @@ -745,7 +748,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)})); /// @} @@ -774,10 +777,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 @@ -802,7 +805,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)})); /// @} @@ -830,7 +833,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)})); /// @} @@ -856,7 +859,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)})); /// @} @@ -884,7 +887,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)})); /// @} @@ -969,11 +972,11 @@ 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)}, QCOTestCase{"ControlledTwoX", MQT_NAMED_BUILDER(controlledTwoX), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc2QubitRegister)}, QCOTestCase{"InverseTwoX", MQT_NAMED_BUILDER(inverseTwoX), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(alloc1QubitRegister)})); /// @} /// \name QCO/Operations/StandardGates/XxMinusYyOp.cpp @@ -1002,7 +1005,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(multipleControlledXxMinusYY)}, QCOTestCase{"TwoXXMinusYYOppositePhase", MQT_NAMED_BUILDER(twoXxMinusYYOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc2QubitRegister)}, QCOTestCase{"TwoXXMinusYYSwappedTargets", MQT_NAMED_BUILDER(twoXxMinusYYSwappedTargets), MQT_NAMED_BUILDER(xxMinusYY)})); @@ -1034,7 +1037,7 @@ INSTANTIATE_TEST_SUITE_P( MQT_NAMED_BUILDER(multipleControlledXxPlusYY)}, QCOTestCase{"TwoXXPlusYYOppositePhase", MQT_NAMED_BUILDER(twoXxPlusYYOppositePhase), - MQT_NAMED_BUILDER(emptyQCO)}, + MQT_NAMED_BUILDER(alloc2QubitRegister)}, QCOTestCase{"TwoXXPlusYYSwappedTargets", MQT_NAMED_BUILDER(twoXxPlusYYSwappedTargets), MQT_NAMED_BUILDER(xxPlusYY)})); @@ -1061,7 +1064,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 @@ -1085,7 +1088,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 @@ -1114,13 +1117,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)}, @@ -1138,16 +1141,10 @@ 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{"StaticQubitsNoMeasure", + MQT_NAMED_BUILDER(staticQubitsNoMeasure), MQT_NAMED_BUILDER(emptyQCO)}, QCOTestCase{"StaticQubitsWithOps", MQT_NAMED_BUILDER(staticQubitsWithOps), @@ -1164,6 +1161,11 @@ INSTANTIATE_TEST_SUITE_P( QCOTestCase{"StaticQubitsWithInv", MQT_NAMED_BUILDER(staticQubitsWithInv), MQT_NAMED_BUILDER(staticQubitsWithInv)}, + QCOTestCase{"DeadGateElimination", MQT_NAMED_BUILDER(deadGatesProgram), + MQT_NAMED_BUILDER(alloc2Qubits)}, + QCOTestCase{"DeadGateEliminationIfOp", + MQT_NAMED_BUILDER(deadGatesWithIfOpProgram), + MQT_NAMED_BUILDER(deadGatesWithIfOpSimplified)}, QCOTestCase{"AllocSinkPair", MQT_NAMED_BUILDER(allocSinkPair), - MQT_NAMED_BUILDER(emptyQCO)})); + MQT_NAMED_BUILDER(allocQubitNoMeasure)})); /// @} 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 af35f2dbcf..49233d5e4e 100644 --- a/mlir/unittests/Dialect/QCO/IR/test_qco_ir_matrix.cpp +++ b/mlir/unittests/Dialect/QCO/IR/test_qco_ir_matrix.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,7 @@ #include #include #include -#include +#include using namespace mlir; using namespace qco; @@ -67,115 +68,6 @@ expectedMatrixFromComputation(const Fn& build, const size_t numQubits = 2) { dd::buildFunctionality(comp, *package).getMatrix(numQubits)); } -static void controlledXH(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(2); - b.ctrl(q[0], q[1], [&](Value target) { - target = b.x(target); - return b.h(target); - }); -} - -static void inverseTwoRxRy(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange targets) { - auto w0 = b.rx(0.2, targets[0]); - auto w1 = b.ry(0.3, targets[1]); - return SmallVector{w0, w1}; - }); -} - -static void inverseCxThenRz(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange targets) { - auto w0 = targets[0]; - auto w1 = targets[1]; - std::tie(w0, w1) = b.cx(w0, w1); - w1 = b.rz(0.4, w1); - return SmallVector{w0, w1}; - }); -} - -static void inverseDcxThenRz(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange targets) { - auto w0 = targets[0]; - auto w1 = targets[1]; - std::tie(w0, w1) = b.dcx(w0, w1); - w1 = b.rz(0.4, w1); - return SmallVector{w0, w1}; - }); -} - -static void controlledInverseHT(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(2); - b.ctrl(q[0], q[1], [&](Value target) { - return b.inv(target, [&](Value qubit) { - qubit = b.h(qubit); - return b.t(qubit); - }); - }); -} - -static void inverseGphaseBarrierX(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value target) { - b.gphase(0.25); - auto wire = b.barrier({target})[0]; - wire = b.x(wire); - return wire; - }); -} - -static void inverseNestedInvHAndT(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value target) { - auto wire = b.inv(target, [&](Value inner) { return b.h(inner); }); - return b.t(wire); - }); -} - -static void inverseNestedInvHAndX(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange targets) { - auto w0 = b.inv(targets[0], [&](Value inner) { return b.h(inner); }); - auto w1 = b.x(targets[1]); - return SmallVector{w0, w1}; - }); -} - -static void inverseThreeWireRxRyRz(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange targets) { - auto w0 = b.rx(0.2, targets[0]); - auto w1 = b.ry(0.3, targets[1]); - auto w2 = b.rz(0.4, targets[2]); - return SmallVector{w0, w1, w2}; - }); -} - -static void inverseThreeWireNestedTwoInv(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange targets) { - auto inner = b.inv({targets[0], targets[1]}, [&](ValueRange innerTargets) { - auto w0 = b.rx(0.2, innerTargets[0]); - auto w1 = b.ry(0.3, innerTargets[1]); - return SmallVector{w0, w1}; - }); - auto w2 = b.rz(0.4, targets[2]); - return SmallVector{inner[0], inner[1], w2}; - }); -} - -static void inverseWithThreeQubitOpInBody(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(3); - b.inv({q[0], q[1], q[2]}, [&](ValueRange targets) { - auto [controls, innerTarget] = - b.ctrl({targets[0], targets[1]}, targets[2], - [&](Value inner) { return b.x(inner); }); - return SmallVector{controls[0], controls[1], innerTarget}; - }); -} - [[nodiscard]] static InvOp firstInvOp(ModuleOp module) { auto funcOp = cast(module.getBody()->front()); return *funcOp.getBody().getOps().begin(); @@ -213,8 +105,8 @@ namespace { struct QCOMatrixTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; }; class QCOMatrixTest : public testing::TestWithParam { diff --git a/mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_euler_decomposition.cpp b/mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_euler_decomposition.cpp index a15fa401f4..f1413aed70 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_euler_decomposition.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_euler_decomposition.cpp @@ -18,6 +18,8 @@ #include "mlir/Dialect/Utils/Utils.h" #include +#include +#include #include #include #include @@ -70,7 +72,7 @@ struct TestFixture { void setUp() { DialectRegistry registry; - registry.insert(); context = std::make_unique(); context->appendDialectRegistry(registry); @@ -101,6 +103,18 @@ class EulerSynthesisExactTest } // namespace +/** + * @brief Measures the given qubits and returns the measurement outcomes. + * @param b The `ProgramBuilder` used to perform the measurements. + * @param qubits The qubits to be measured. + * @return The result values. + */ +static SmallVector measureAndReturn(QCOProgramBuilder& b, + ValueRange qubits) { + return to_vector( + llvm::map_range(qubits, [&](Value q) { return b.measure(q).second; })); +} + //===----------------------------------------------------------------------===// // Euler synthesis support //===----------------------------------------------------------------------===// @@ -134,8 +148,8 @@ template } template static void forEachBasis(Fn fn) { - const std::array bases = {"zyz", "zxz", "xzx", "xyx", - "u", "zsxx", "r"}; + constexpr std::array bases = {"zyz", "zxz", "xzx", "xyx", + "u", "zsxx", "r"}; for (const char* basis : bases) { fn(StringRef{basis}); } @@ -361,7 +375,7 @@ INSTANTIATE_TEST_SUITE_P( ZSXXShortcutCase{"ZYZNearZeroTheta", [](MLIRContext*) -> Matrix2x2 { constexpr double tol = - 0.5 * mlir::utils::TOLERANCE; + 0.5 * utils::TOLERANCE; return RZOp::unitaryMatrix(0.4) * RYOp::unitaryMatrix(tol) * RZOp::unitaryMatrix(0.3); @@ -376,23 +390,21 @@ INSTANTIATE_TEST_SUITE_P( ZSXXShortcutCase{"RYNearHalfPi", [](MLIRContext* ctx) -> Matrix2x2 { return rotationMatrix( - ctx, - (std::numbers::pi / 2.0) + - (0.5 * mlir::utils::TOLERANCE)); + ctx, (std::numbers::pi / 2.0) + + (0.5 * utils::TOLERANCE)); }, 2, 1, 0}, ZSXXShortcutCase{"RYNearZero", [](MLIRContext* ctx) -> Matrix2x2 { return rotationMatrix( - ctx, 0.5 * mlir::utils::TOLERANCE); + ctx, 0.5 * utils::TOLERANCE); }, 0, 0, 0}, ZSXXShortcutCase{"RYNearPi", [](MLIRContext* ctx) -> Matrix2x2 { return rotationMatrix( - ctx, - std::numbers::pi - - (0.5 * mlir::utils::TOLERANCE)); + ctx, std::numbers::pi - + (0.5 * utils::TOLERANCE)); }, 1, 0, 1}), [](const testing::TestParamInfo& info) { @@ -456,7 +468,7 @@ TEST(EulerSynthesisTest, RandomReconstructionAllBases) { TEST(EulerAnglesCoverageTest, ParamsZYZUsesOffDiagonal01When10IsNearZero) { Matrix2x2 matrix = RXOp::unitaryMatrix(0.4); matrix(1, 0) = Complex{0.0, 0.0}; - ASSERT_GT(std::abs(matrix(0, 1)), mlir::utils::TOLERANCE); + ASSERT_GT(std::abs(matrix(0, 1)), utils::TOLERANCE); const EulerAngles angles = anglesFromUnitary(matrix, ZYZ); EXPECT_TRUE(std::isfinite(angles.theta)); EXPECT_TRUE(std::isfinite(angles.phi)); @@ -470,9 +482,9 @@ TEST(EulerAnglesCoverageTest, PhaseOnlyDecompositionSkipsRotationGates) { const Matrix2x2 matrix = Matrix2x2::fromElements(scale, 0, 0, scale); ASSERT_FALSE(matrix.isApprox(Matrix2x2::identity())); const EulerAngles angles = anglesFromUnitary(matrix, ZYZ); - EXPECT_LE(std::abs(angles.theta), mlir::utils::TOLERANCE); - EXPECT_LE(std::abs(angles.phi), mlir::utils::TOLERANCE); - EXPECT_LE(std::abs(angles.lambda), mlir::utils::TOLERANCE); + EXPECT_LE(std::abs(angles.theta), utils::TOLERANCE); + EXPECT_LE(std::abs(angles.phi), utils::TOLERANCE); + EXPECT_LE(std::abs(angles.lambda), utils::TOLERANCE); const auto circuit = synthesizeMatrix(fx.ctx(), matrix, ZYZ); ASSERT_TRUE(succeeded(verify(*circuit.mlirModule))); EXPECT_EQ(countZYZGates(circuit.func), 0U); @@ -494,7 +506,7 @@ TEST(EulerAnglesCoverageTest, UBasisNonzeroThetaEmitsSingleUGate) { fx.setUp(); const Matrix2x2 matrix = RYOp::unitaryMatrix(1.2); const EulerAngles angles = anglesFromUnitary(matrix, U); - ASSERT_GT(std::abs(angles.theta), mlir::utils::TOLERANCE); + ASSERT_GT(std::abs(angles.theta), utils::TOLERANCE); expectSynthesizedMatrix(fx.ctx(), matrix, U, [](func::FuncOp funcOp, const Matrix2x2& /*matrix*/) { EXPECT_EQ(countOps(funcOp), 1U); @@ -507,7 +519,7 @@ TEST(EulerAnglesCoverageTest, RBasisNonzeroThetaEmitsThreeRGates) { fx.setUp(); const Matrix2x2 matrix = HOp::getUnitaryMatrix(); const EulerAngles angles = anglesFromUnitary(matrix, R); - ASSERT_GT(std::abs(angles.theta), mlir::utils::TOLERANCE); + ASSERT_GT(std::abs(angles.theta), utils::TOLERANCE); expectSynthesizedMatrix(fx.ctx(), matrix, R, [](func::FuncOp funcOp, const Matrix2x2& /*matrix*/) { EXPECT_EQ(countOps(funcOp), 3U); @@ -517,7 +529,7 @@ TEST(EulerAnglesCoverageTest, RBasisNonzeroThetaEmitsThreeRGates) { TEST(EulerAnglesCoverageTest, Mod2PiMapsPiBoundaryThroughSynthesis) { TestFixture fx; fx.setUp(); - constexpr double eps = 0.5 * mlir::utils::TOLERANCE; + constexpr double eps = 0.5 * utils::TOLERANCE; const Complex global = std::polar(1.0, std::numbers::pi - eps); const Matrix2x2 matrix = Matrix2x2::fromElements(global, 0, 0, global); expectSynthesizedMatrix(fx.ctx(), matrix, U, @@ -532,7 +544,8 @@ TEST(EulerAnglesCoverageTest, Mod2PiPreservesNonFinitePhase) { fx.setUp(); const Matrix2x2 matrix = Matrix2x2::fromElements( Complex{std::numeric_limits::quiet_NaN(), 0}, 0, 0, 1); - EXPECT_NO_FATAL_FAILURE(synthesizeMatrix(fx.ctx(), matrix, ZYZ)); + EXPECT_NO_FATAL_FAILURE(std::ignore = + synthesizeMatrix(fx.ctx(), matrix, ZYZ)); } //===----------------------------------------------------------------------===// @@ -765,51 +778,58 @@ static void runFuseInParent(MLIRContext* ctx, ProgramT program, // --- Fuse program fixtures --- // -static void singleQubitRunWithSingleQubitGate(QCOProgramBuilder& b) { +static SmallVector +singleQubitRunWithSingleQubitGate(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.h(q[0]); q[0] = b.t(q[0]); q[0] = b.rz(0.123, q[0]); q[0] = b.inv(q[0], [&b](Value qubit) { return b.sx(qubit); }); q[0] = b.ry(-0.456, q[0]); + return measureAndReturn(b, q.qubits); } -static void singleQubitRunsSplitByTwoQGate(QCOProgramBuilder& b) { +static SmallVector singleQubitRunsSplitByTwoQGate(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); q[0] = b.h(q[0]); q[0] = b.t(q[0]); std::tie(q[0], q[1]) = b.swap(q[0], q[1]); q[0] = b.rz(0.321, q[0]); q[0] = b.sx(q[0]); + return measureAndReturn(b, q.qubits); } -static void singleQubitRunsSplitByBarrier(QCOProgramBuilder& b) { +static SmallVector singleQubitRunsSplitByBarrier(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.h(q[0]); q[0] = b.t(q[0]); q[0] = b.barrier({q[0]})[0]; q[0] = b.rz(0.321, q[0]); q[0] = b.sx(q[0]); + return measureAndReturn(b, q.qubits); } -static void singleNonBasisGate(QCOProgramBuilder& b) { +static SmallVector singleNonBasisGate(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.h(q[0]); + return measureAndReturn(b, q.qubits); } -static void singlePauliX(QCOProgramBuilder& b) { +static SmallVector singlePauliX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.x(q[0]); + return measureAndReturn(b, q.qubits); } -static void canonicalZYZRun(QCOProgramBuilder& b) { +static SmallVector canonicalZYZRun(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.rz(0.3, q[0]); q[0] = b.ry(0.5, q[0]); q[0] = b.rz(0.7, q[0]); + return measureAndReturn(b, q.qubits); } -static void overlongZYZRun(QCOProgramBuilder& b) { +static SmallVector overlongZYZRun(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.rz(0.3, q[0]); q[0] = b.ry(0.5, q[0]); @@ -817,27 +837,31 @@ static void overlongZYZRun(QCOProgramBuilder& b) { q[0] = b.ry(0.9, q[0]); q[0] = b.rz(1.1, q[0]); q[0] = b.ry(1.3, q[0]); + return measureAndReturn(b, q.qubits); } -static void overlongZSXXMixedPureZRun(QCOProgramBuilder& b) { +static SmallVector overlongZSXXMixedPureZRun(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sx(q[0]); q[0] = b.rz(std::numbers::pi, q[0]); q[0] = b.sx(q[0]); + return measureAndReturn(b, q.qubits); } -static void singleQubitRunInScfFor(QCOProgramBuilder& b) { +static SmallVector singleQubitRunInScfFor(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.scfFor(0, 1, 1, ValueRange{q[0]}, [&b](Value, ValueRange iterArgs) { - Value wire = iterArgs[0]; - wire = b.h(wire); - wire = b.t(wire); - wire = b.rz(0.123, wire); - return SmallVector{wire}; - }); + auto res = + b.scfFor(0, 1, 1, ValueRange{q[0]}, [&b](Value, ValueRange iterArgs) { + Value wire = iterArgs[0]; + wire = b.h(wire); + wire = b.t(wire); + wire = b.rz(0.123, wire); + return SmallVector{wire}; + }); + return measureAndReturn(b, res); } -static void xInverseTwoX(QCOProgramBuilder& b) { +static SmallVector xInverseTwoX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.x(q[0]); q[0] = b.inv(q[0], [&b](Value qubit) { @@ -845,9 +869,11 @@ static void xInverseTwoX(QCOProgramBuilder& b) { return b.x(qubit); }); q[0] = b.x(q[0]); + return measureAndReturn(b, q.qubits); } -static void inverseMultiQubitBodySingleQubitRun(QCOProgramBuilder& b) { +static SmallVector +inverseMultiQubitBodySingleQubitRun(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); auto outs = b.inv({q[0], q[1]}, [&b](ValueRange targets) -> SmallVector { @@ -857,33 +883,38 @@ static void inverseMultiQubitBodySingleQubitRun(QCOProgramBuilder& b) { }); q[0] = outs[0]; q[1] = outs[1]; + return measureAndReturn(b, q.qubits); } -static void controlledInverseHT(QCOProgramBuilder& b) { +static SmallVector controlledInverseHT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ctrl(q[0], q[1], [&b](Value target) { + auto res = b.ctrl(q[0], q[1], [&b](Value target) { return b.inv(target, [&b](Value qubit) { qubit = b.h(qubit); return b.t(qubit); }); }); + return measureAndReturn(b, {res.second}); } -static void controlledH(QCOProgramBuilder& b) { +static SmallVector controlledH(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ctrl(q[0], q[1], [&b](Value target) { return b.h(target); }); + auto res = b.ctrl(q[0], q[1], [&b](Value target) { return b.h(target); }); + return measureAndReturn(b, {res.second}); } -static void singleQubitRunsSplitByScfFor(QCOProgramBuilder& b) { +static SmallVector singleQubitRunsSplitByScfFor(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.h(q[0]); q[0] = b.t(q[0]); - b.scfFor(0, 1, 1, ValueRange{q[0]}, [&b](Value, ValueRange iterArgs) { - Value wire = iterArgs[0]; - wire = b.rz(0.321, wire); - wire = b.sx(wire); - return SmallVector{wire}; - }); + auto res = + b.scfFor(0, 1, 1, ValueRange{q[0]}, [&b](Value, ValueRange iterArgs) { + Value wire = iterArgs[0]; + wire = b.rz(0.321, wire); + wire = b.sx(wire); + return SmallVector{wire}; + }); + return measureAndReturn(b, res); } //===----------------------------------------------------------------------===// @@ -904,7 +935,7 @@ TEST(FuseSingleQubitUnitaryRunsTest, FusesProgramsAllBases) { fx.setUp(); struct Case { - void (*program)(QCOProgramBuilder&); + SmallVector (*program)(QCOProgramBuilder&); void (*extra)(func::FuncOp, StringRef); }; const std::array cases = {{ @@ -984,7 +1015,7 @@ TEST(FuseSingleQubitUnitaryRunsTest, DoesNotFuseAcrossBoundariesAllBases) { fx.setUp(); struct Case { - void (*program)(QCOProgramBuilder&); + SmallVector (*program)(QCOProgramBuilder&); void (*check)(func::FuncOp, StringRef, MLIRContext*); }; const std::array cases = {{ diff --git a/mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp b/mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp index 7038ef1b0c..3153febf45 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp @@ -14,6 +14,7 @@ #include "mlir/Dialect/QCO/IR/QCOOps.h" #include "mlir/Dialect/QCO/Transforms/Mapping/Mapping.h" #include "mlir/Dialect/QCO/Transforms/Passes.h" +#include "mlir/Dialect/Utils/Utils.h" #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +44,7 @@ using namespace mlir; using namespace mlir::qco; +using namespace mlir::utils; namespace { struct Device { @@ -230,13 +233,16 @@ TEST_P(MappingPassTest, NoQubitAllocations) { const auto& device = GetParam(); QCOProgramBuilder builder(context.get()); - builder.initialize(); + builder.initialize({builder.getI1Type()}); - Value q0 = builder.allocQubit(); + Value q0; + Value c0; + q0 = builder.allocQubit(); q0 = builder.h(q0); + std::tie(q0, c0) = builder.measure(q0); builder.sink(q0); - auto m = builder.finalize(); + auto m = builder.finalize(c0); auto res = runPass(m.get(), device.couplingSet, MappingPassOptions{}); ASSERT_TRUE(res.failed()); @@ -246,22 +252,24 @@ TEST_P(MappingPassTest, NoExtractAfterInsert) { const auto& device = GetParam(); QCOProgramBuilder builder(context.get()); - builder.initialize(); + builder.initialize({builder.getI1Type()}); Value tensor0 = builder.qtensorAlloc(1); Value q0; + Value c0; std::tie(tensor0, q0) = builder.qtensorExtract(tensor0, 0); q0 = builder.h(q0); tensor0 = builder.qtensorInsert(q0, tensor0, 0); std::tie(tensor0, q0) = builder.qtensorExtract(tensor0, 0); q0 = builder.x(q0); + std::tie(q0, c0) = builder.measure(q0); tensor0 = builder.qtensorInsert(q0, tensor0, 0); builder.qtensorDealloc(tensor0); - auto m = builder.finalize(); + auto m = builder.finalize(c0); auto res = runPass(m.get(), device.couplingSet, MappingPassOptions{}); ASSERT_TRUE(res.failed()); @@ -269,27 +277,29 @@ TEST_P(MappingPassTest, NoExtractAfterInsert) { TEST_P(MappingPassTest, TooManyQubitsForArch) { const auto& device = GetParam(); - const auto n = static_cast(device.nqubits) + 1; + const auto size = static_cast(device.nqubits) + 1; + + SmallVector bits(size); + SmallVector qubits(size); QCOProgramBuilder builder(context.get()); - builder.initialize(); - - Value tensor = builder.qtensorAlloc(n); - SmallVector qubits(n); - for (int64_t i = 0; i < n; ++i) { - Value qi; - std::tie(tensor, qi) = builder.qtensorExtract(tensor, i); - qi = builder.h(qi); - qubits[i] = qi; + builder.initialize(SmallVector(size, builder.getI1Type())); + + Value tensor = builder.qtensorAlloc(size); + + for (int64_t i = 0; i < size; ++i) { + std::tie(tensor, qubits[i]) = builder.qtensorExtract(tensor, i); + qubits[i] = builder.h(qubits[i]); + std::tie(qubits[i], bits[i]) = builder.measure(qubits[i]); } - for (int64_t i = 0; i < n; ++i) { + for (int64_t i = 0; i < size; ++i) { tensor = builder.qtensorInsert(qubits[i], tensor, i); } builder.qtensorDealloc(tensor); - auto m = builder.finalize(); + auto m = builder.finalize(bits); auto res = runPass(m.get(), device.couplingSet, MappingPassOptions{}); ASSERT_TRUE(res.failed()); @@ -297,31 +307,34 @@ TEST_P(MappingPassTest, TooManyQubitsForArch) { TEST_P(MappingPassTest, GHZ) { const auto& device = GetParam(); + const int64_t size = 3; + + SmallVector qubits(size); + SmallVector bits(size); QCOProgramBuilder builder(context.get()); - builder.initialize(); + builder.initialize(SmallVector(3, builder.getI1Type())); Value tensor = builder.qtensorAlloc(3); + std::tie(tensor, qubits[0]) = builder.qtensorExtract(tensor, 0); + std::tie(tensor, qubits[1]) = builder.qtensorExtract(tensor, 1); + std::tie(tensor, qubits[2]) = builder.qtensorExtract(tensor, 2); - Value q0; - std::tie(tensor, q0) = builder.qtensorExtract(tensor, 0); - - Value q1; - std::tie(tensor, q1) = builder.qtensorExtract(tensor, 1); + qubits[0] = builder.h(qubits[0]); + std::tie(qubits[0], qubits[1]) = builder.cx(qubits[0], qubits[1]); + std::tie(qubits[0], qubits[2]) = builder.cx(qubits[0], qubits[2]); - Value q2; - std::tie(tensor, q2) = builder.qtensorExtract(tensor, 2); + std::tie(qubits[0], bits[0]) = builder.measure(qubits[0]); + std::tie(qubits[1], bits[1]) = builder.measure(qubits[1]); + std::tie(qubits[2], bits[2]) = builder.measure(qubits[2]); - q0 = builder.h(q0); - std::tie(q0, q1) = builder.cx(q0, q1); - std::tie(q0, q2) = builder.cx(q0, q2); + tensor = builder.qtensorInsert(qubits[0], tensor, 0); + tensor = builder.qtensorInsert(qubits[1], tensor, 1); + tensor = builder.qtensorInsert(qubits[2], tensor, 2); - tensor = builder.qtensorInsert(q0, tensor, 0); - tensor = builder.qtensorInsert(q1, tensor, 1); - tensor = builder.qtensorInsert(q2, tensor, 2); builder.qtensorDealloc(tensor); - auto m = builder.finalize(); + auto m = builder.finalize(bits); auto res = runPass(m.get(), device.couplingSet, MappingPassOptions{}); auto entry = getEntryPoint(m.get()); @@ -331,7 +344,9 @@ TEST_P(MappingPassTest, GHZ) { TEST_P(MappingPassTest, GHZUnrolled) { const auto& device = GetParam(); - const auto n = static_cast(device.nqubits); + const auto size = static_cast(device.nqubits); + + SmallVector bits(size); PassManager pm(context.get()); pm.addNestedPass(createQuantumLoopUnroll()); @@ -340,15 +355,15 @@ TEST_P(MappingPassTest, GHZUnrolled) { pm.addPass(createMappingPass(device.couplingSet, MappingPassOptions{})); QCOProgramBuilder builder(context.get()); - builder.initialize(); + builder.initialize(SmallVector(size, builder.getI1Type())); - Value tensor = builder.qtensorAlloc(n); + Value tensor = builder.qtensorAlloc(size); Value q0; std::tie(tensor, q0) = builder.qtensorExtract(tensor, 0); q0 = builder.h(q0); tensor = builder.qtensorInsert(q0, tensor, 0); tensor = builder.scfFor( - 1, n, 1, {tensor}, [&builder](Value iv, ValueRange iterArgs) { + 1, size, 1, {tensor}, [&builder](Value iv, ValueRange iterArgs) { Value loopTensor = iterArgs[0]; Value ctrl; Value targ; @@ -363,9 +378,17 @@ TEST_P(MappingPassTest, GHZUnrolled) { return SmallVector{loopTensor}; })[0]; + + for (int64_t i = 0; i < size; ++i) { + Value q; + std::tie(tensor, q) = builder.qtensorExtract(tensor, i); + std::tie(q, bits[i]) = builder.measure(q); + tensor = builder.qtensorInsert(q, tensor, i); + } + builder.qtensorDealloc(tensor); - auto m = builder.finalize(); + auto m = builder.finalize(bits); auto res = pm.run(m.get()); auto entry = getEntryPoint(m.get()); @@ -375,35 +398,34 @@ TEST_P(MappingPassTest, GHZUnrolled) { TEST_P(MappingPassTest, GroverLike) { const auto& device = GetParam(); + const int64_t size = 5; + + SmallVector qubits(size); + SmallVector bits(size); PassManager pm(context.get()); pm.addPass(createMappingPass(device.couplingSet, MappingPassOptions{})); QCOProgramBuilder builder(context.get()); - builder.initialize(); + builder.initialize(SmallVector(5, builder.getI1Type())); Value tensor = builder.qtensorAlloc(4); Value flagTensor = builder.qtensorAlloc(1); - Value q0; - Value q1; - Value q2; - Value q3; - Value flag; - std::tie(tensor, q0) = builder.qtensorExtract(tensor, 0); - std::tie(tensor, q1) = builder.qtensorExtract(tensor, 1); - std::tie(tensor, q2) = builder.qtensorExtract(tensor, 2); - std::tie(tensor, q3) = builder.qtensorExtract(tensor, 3); - std::tie(flagTensor, flag) = builder.qtensorExtract(flagTensor, 0); + std::tie(tensor, qubits[0]) = builder.qtensorExtract(tensor, 0); + std::tie(tensor, qubits[1]) = builder.qtensorExtract(tensor, 1); + std::tie(tensor, qubits[2]) = builder.qtensorExtract(tensor, 2); + std::tie(tensor, qubits[3]) = builder.qtensorExtract(tensor, 3); + std::tie(flagTensor, qubits[4]) = builder.qtensorExtract(flagTensor, 0); - q0 = builder.h(q0); - q1 = builder.h(q1); - q2 = builder.h(q2); - q3 = builder.h(q3); - flag = builder.x(flag); + qubits[0] = builder.h(qubits[0]); + qubits[1] = builder.h(qubits[1]); + qubits[2] = builder.h(qubits[2]); + qubits[3] = builder.h(qubits[3]); + qubits[4] = builder.x(qubits[4]); - const auto forResults = builder.scfFor( - 1, 3, 1, {q0, q1, q2, q3, flag}, [&builder](Value, ValueRange iterArgs) { + qubits = + builder.scfFor(1, 3, 1, qubits, [&builder](Value, ValueRange iterArgs) { Value iterQ0 = iterArgs[0]; Value iterQ1 = iterArgs[1]; Value iterQ2 = iterArgs[2]; @@ -417,42 +439,22 @@ TEST_P(MappingPassTest, GroverLike) { return SmallVector{iterQ0, iterQ1, iterQ2, iterQ3, iterFlag}; }); + qubits = builder.barrier(qubits); - q0 = forResults[0]; - q1 = forResults[1]; - q2 = forResults[2]; - q3 = forResults[3]; - flag = forResults[4]; - - const auto barrierResults = builder.barrier({q0, q1, q2, q3, flag}); - q0 = barrierResults[0]; - q1 = barrierResults[1]; - q2 = barrierResults[2]; - q3 = barrierResults[3]; - flag = barrierResults[4]; - - Value c0; - Value c1; - Value c2; - Value c3; - Value c4; - - std::tie(q0, c0) = builder.measure(q0); - std::tie(q1, c1) = builder.measure(q1); - std::tie(q2, c2) = builder.measure(q2); - std::tie(q3, c3) = builder.measure(q3); - std::tie(flag, c4) = builder.measure(flag); + for (int64_t i = 0; i < size; ++i) { + std::tie(qubits[i], bits[i]) = builder.measure(qubits[i]); + } - tensor = builder.qtensorInsert(q0, tensor, 0); - tensor = builder.qtensorInsert(q1, tensor, 1); - tensor = builder.qtensorInsert(q2, tensor, 2); - tensor = builder.qtensorInsert(q3, tensor, 3); - flagTensor = builder.qtensorInsert(flag, flagTensor, 0); + tensor = builder.qtensorInsert(qubits[0], tensor, 0); + tensor = builder.qtensorInsert(qubits[1], tensor, 1); + tensor = builder.qtensorInsert(qubits[2], tensor, 2); + tensor = builder.qtensorInsert(qubits[3], tensor, 3); + flagTensor = builder.qtensorInsert(qubits[4], flagTensor, 0); builder.qtensorDealloc(tensor); builder.qtensorDealloc(flagTensor); - auto m = builder.finalize(); + auto m = builder.finalize(bits); auto res = pm.run(m.get()); auto entry = getEntryPoint(m.get()); @@ -461,26 +463,26 @@ TEST_P(MappingPassTest, GroverLike) { } TEST_P(MappingPassTest, ParallelLoops) { - constexpr int64_t nqubits = 6; const auto& device = GetParam(); + constexpr int64_t size = 6; + + SmallVector qubits(size); + SmallVector bits(size); PassManager pm(context.get()); pm.addPass(createMappingPass(device.couplingSet, MappingPassOptions{})); QCOProgramBuilder builder(context.get()); - builder.initialize(); - - Value tensor = builder.qtensorAlloc(nqubits); - SmallVector creg(nqubits); - SmallVector qreg(nqubits); + builder.initialize(SmallVector(size, builder.getI1Type())); - for (int64_t i = 0; i < nqubits; ++i) { - std::tie(tensor, qreg[i]) = builder.qtensorExtract(tensor, i); - qreg[i] = builder.h(qreg[i]); + Value tensor = builder.qtensorAlloc(size); + for (int64_t i = 0; i < size; ++i) { + std::tie(tensor, qubits[i]) = builder.qtensorExtract(tensor, i); + qubits[i] = builder.h(qubits[i]); } const auto upForResults = - builder.scfFor(1, 3, 1, {qreg[0], qreg[1], qreg[2]}, + builder.scfFor(1, 3, 1, {qubits[0], qubits[1], qubits[2]}, [&builder](Value, ValueRange iterArgs) { Value iterQ0 = iterArgs[0]; Value iterQ1 = iterArgs[1]; @@ -495,12 +497,12 @@ TEST_P(MappingPassTest, ParallelLoops) { return SmallVector{iterQ0, iterQ1, iterQ2}; }); - qreg[0] = upForResults[0]; - qreg[1] = upForResults[1]; - qreg[2] = upForResults[2]; + qubits[0] = upForResults[0]; + qubits[1] = upForResults[1]; + qubits[2] = upForResults[2]; const auto downForResults = - builder.scfFor(1, 3, 1, {qreg[3], qreg[4], qreg[5]}, + builder.scfFor(1, 3, 1, {qubits[3], qubits[4], qubits[5]}, [&builder](Value, ValueRange iterArgs) { Value iterQ0 = iterArgs[0]; Value iterQ1 = iterArgs[1]; @@ -515,24 +517,24 @@ TEST_P(MappingPassTest, ParallelLoops) { return SmallVector{iterQ0, iterQ1, iterQ2}; }); - qreg[3] = downForResults[0]; - qreg[4] = downForResults[1]; - qreg[5] = downForResults[2]; + qubits[3] = downForResults[0]; + qubits[4] = downForResults[1]; + qubits[5] = downForResults[2]; - qreg = builder.barrier(qreg); + qubits = builder.barrier(qubits); - for (int64_t i = 0; i < nqubits; ++i) { - std::tie(qreg[i], creg[i]) = builder.measure(qreg[i]); - qreg[i] = builder.h(qreg[i]); + for (int64_t i = 0; i < size; ++i) { + std::tie(qubits[i], bits[i]) = builder.measure(qubits[i]); + qubits[i] = builder.h(qubits[i]); } - for (int64_t i = 0; i < nqubits; ++i) { - tensor = builder.qtensorInsert(qreg[i], tensor, i); + for (int64_t i = 0; i < size; ++i) { + tensor = builder.qtensorInsert(qubits[i], tensor, i); } builder.qtensorDealloc(tensor); - auto m = builder.finalize(); + auto m = builder.finalize(bits); auto res = pm.run(m.get()); auto entry = getEntryPoint(m.get()); @@ -542,91 +544,68 @@ TEST_P(MappingPassTest, ParallelLoops) { TEST_P(MappingPassTest, Sabre) { const auto& device = GetParam(); + constexpr int64_t size = 6; + + SmallVector qubits(size); + SmallVector bits(size); QCOProgramBuilder builder(context.get()); - builder.initialize(); + builder.initialize(SmallVector(6, builder.getI1Type())); Value tensorUp = builder.qtensorAlloc(4); Value tensorDown = builder.qtensorAlloc(2); - Value q0; - std::tie(tensorUp, q0) = builder.qtensorExtract(tensorUp, 0); - - Value q1; - std::tie(tensorUp, q1) = builder.qtensorExtract(tensorUp, 1); - - Value q2; - std::tie(tensorUp, q2) = builder.qtensorExtract(tensorUp, 2); + std::tie(tensorUp, qubits[0]) = builder.qtensorExtract(tensorUp, 0); + std::tie(tensorUp, qubits[1]) = builder.qtensorExtract(tensorUp, 1); + std::tie(tensorUp, qubits[2]) = builder.qtensorExtract(tensorUp, 2); + std::tie(tensorUp, qubits[3]) = builder.qtensorExtract(tensorUp, 3); + std::tie(tensorDown, qubits[4]) = builder.qtensorExtract(tensorDown, 0); + std::tie(tensorDown, qubits[5]) = builder.qtensorExtract(tensorDown, 1); - Value q3; - std::tie(tensorUp, q3) = builder.qtensorExtract(tensorUp, 3); - - Value q4; - std::tie(tensorDown, q4) = builder.qtensorExtract(tensorDown, 0); - - Value q5; - std::tie(tensorDown, q5) = builder.qtensorExtract(tensorDown, 1); - - q0 = builder.h(q0); - q1 = builder.h(q1); - q4 = builder.h(q4); + qubits[0] = builder.h(qubits[0]); + qubits[1] = builder.h(qubits[1]); + qubits[4] = builder.h(qubits[4]); - q0 = builder.z(q0); - std::tie(q1, q2) = builder.cx(q1, q2); - std::tie(q4, q5) = builder.cx(q4, q5); + qubits[0] = builder.z(qubits[0]); + std::tie(qubits[1], qubits[2]) = builder.cx(qubits[1], qubits[2]); + std::tie(qubits[4], qubits[5]) = builder.cx(qubits[4], qubits[5]); - std::tie(q0, q1) = builder.cx(q0, q1); + std::tie(qubits[0], qubits[1]) = builder.cx(qubits[0], qubits[1]); - q0 = builder.h(q0); - q1 = builder.y(q1); - std::tie(q0, q1) = builder.cx(q0, q1); + qubits[0] = builder.h(qubits[0]); + qubits[1] = builder.y(qubits[1]); + std::tie(qubits[0], qubits[1]) = builder.cx(qubits[0], qubits[1]); - std::tie(q2, q3) = builder.cx(q2, q3); + std::tie(qubits[2], qubits[3]) = builder.cx(qubits[2], qubits[3]); - q2 = builder.h(q2); - q3 = builder.h(q3); + qubits[2] = builder.h(qubits[2]); + qubits[3] = builder.h(qubits[3]); - std::tie(q1, q2) = builder.cx(q1, q2); - std::tie(q3, q5) = builder.cx(q3, q5); + std::tie(qubits[1], qubits[2]) = builder.cx(qubits[1], qubits[2]); + std::tie(qubits[3], qubits[5]) = builder.cx(qubits[3], qubits[5]); - q3 = builder.z(q3); + qubits[3] = builder.z(qubits[3]); - std::tie(q3, q4) = builder.cx(q3, q4); + std::tie(qubits[3], qubits[4]) = builder.cx(qubits[3], qubits[4]); - std::tie(q3, q0) = builder.cx(q3, q0); + std::tie(qubits[3], qubits[0]) = builder.cx(qubits[3], qubits[0]); - ValueRange out = builder.barrier({q0, q1, q2, q3, q4, q5}); - q0 = out[0]; - q1 = out[1]; - q2 = out[2]; - q3 = out[3]; - q4 = out[4]; - q5 = out[5]; + qubits = builder.barrier(qubits); - Value c0; - Value c1; - Value c2; - Value c3; - Value c4; - Value c5; + for (int64_t i = 0; i < size; ++i) { + std::tie(qubits[i], bits[i]) = builder.measure(qubits[i]); + } - std::tie(q0, c0) = builder.measure(q0); - std::tie(q1, c1) = builder.measure(q1); - std::tie(q2, c2) = builder.measure(q2); - std::tie(q3, c3) = builder.measure(q3); - std::tie(q4, c4) = builder.measure(q4); - std::tie(q5, c5) = builder.measure(q5); - - tensorUp = builder.qtensorInsert(q0, tensorUp, 0); - tensorUp = builder.qtensorInsert(q1, tensorUp, 1); - tensorUp = builder.qtensorInsert(q2, tensorUp, 2); - tensorUp = builder.qtensorInsert(q3, tensorUp, 3); - tensorDown = builder.qtensorInsert(q4, tensorDown, 0); - tensorDown = builder.qtensorInsert(q5, tensorDown, 1); + tensorUp = builder.qtensorInsert(qubits[0], tensorUp, 0); + tensorUp = builder.qtensorInsert(qubits[1], tensorUp, 1); + tensorUp = builder.qtensorInsert(qubits[2], tensorUp, 2); + tensorUp = builder.qtensorInsert(qubits[3], tensorUp, 3); + tensorDown = builder.qtensorInsert(qubits[4], tensorDown, 0); + tensorDown = builder.qtensorInsert(qubits[5], tensorDown, 1); builder.qtensorDealloc(tensorUp); builder.qtensorDealloc(tensorDown); - auto m = builder.finalize(); + auto m = builder.finalize(bits); auto res = runPass(m.get(), device.couplingSet, MappingPassOptions{}); auto entry = getEntryPoint(m.get()); @@ -636,35 +615,36 @@ TEST_P(MappingPassTest, Sabre) { TEST_P(MappingPassTest, RandomOrderGHZ) { const auto& device = GetParam(); + constexpr int64_t size = 9; - QCOProgramBuilder builder(context.get()); - builder.initialize(); + SmallVector qubits(size); + SmallVector bits(size); - Value tensor = builder.qtensorAlloc(9); - SmallVector qubits(9); - SmallVector cregs(9); + QCOProgramBuilder builder(context.get()); + builder.initialize(SmallVector(size, builder.getI1Type())); - for (int64_t i = 0; i < 9; ++i) { + Value tensor = builder.qtensorAlloc(size); + for (int64_t i = 0; i < size; ++i) { std::tie(tensor, qubits[i]) = builder.qtensorExtract(tensor, i); } qubits[0] = builder.h(qubits[0]); - std::tie(qubits[0], cregs[0]) = builder.measure(qubits[0]); + std::tie(qubits[0], bits[0]) = builder.measure(qubits[0]); qubits = builder.qcoIf( - cregs[0], qubits, + bits[0], qubits, [&](ValueRange args) { SmallVector values(args); values[0] = builder.h(values[0]); - for (size_t i = 1; i < 9; ++i) { + for (size_t i = 1; i < size; ++i) { std::tie(values[0], values[i]) = builder.cx(values[0], values[i]); } return values; }, [&](ValueRange args) { SmallVector values(args); - values[8] = builder.h(values[8]); - for (size_t i = 8; i > 0; --i) { + values[size - 1] = builder.h(values[size - 1]); + for (size_t i = size - 1; i > 0; --i) { std::tie(values[8], values[i - 1]) = builder.cx(values[8], values[i - 1]); } @@ -673,17 +653,17 @@ TEST_P(MappingPassTest, RandomOrderGHZ) { qubits = builder.barrier(qubits); - for (int64_t i = 0; i < 9; ++i) { - std::tie(qubits[i], cregs[i]) = builder.measure(qubits[i]); + for (int64_t i = 0; i < size; ++i) { + std::tie(qubits[i], bits[i]) = builder.measure(qubits[i]); } - for (int64_t i = 0; i < 9; ++i) { + for (int64_t i = 0; i < size; ++i) { tensor = builder.qtensorInsert(qubits[i], tensor, i); } builder.qtensorDealloc(tensor); - auto m = builder.finalize(); + auto m = builder.finalize(bits); auto res = runPass(m.get(), device.couplingSet, MappingPassOptions{.ntrials = 1}); auto entry = getEntryPoint(m.get()); diff --git a/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp b/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp index 765b249a41..da6b6e25d0 100644 --- a/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp +++ b/mlir/unittests/Dialect/QIR/IR/test_qir_ir.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -32,8 +33,8 @@ namespace { struct QIRTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const QIRTestCase& info); }; @@ -66,8 +67,8 @@ TEST_P(QIRTest, ProgramEquivalence) { const auto name = " (" + GetParam().name + ")"; mqt::test::DeferredPrinter printer; - auto program = QIRProgramBuilder::build(context.get(), programBuilder.fn, - QIRProgramBuilder::Profile::Adaptive); + auto program = mqt::test::buildMLIRProgram( + context.get(), programBuilder, QIRProgramBuilder::Profile::Adaptive); ASSERT_TRUE(program); printer.record(program.get(), "Original QIR IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -76,8 +77,8 @@ TEST_P(QIRTest, ProgramEquivalence) { printer.record(program.get(), "Canonicalized QIR IR" + name); EXPECT_TRUE(verify(*program).succeeded()); - auto reference = QIRProgramBuilder::build( - context.get(), referenceBuilder.fn, QIRProgramBuilder::Profile::Adaptive); + auto reference = mqt::test::buildMLIRProgram( + context.get(), referenceBuilder, QIRProgramBuilder::Profile::Adaptive); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QIR IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); @@ -112,36 +113,36 @@ TEST_F(QIRTest, BuilderRejectsMixedStaticAndDynamicQubitAllocationModes) { /// @{ INSTANTIATE_TEST_SUITE_P( QIRDCXOpTest, QIRTest, - testing::Values(QIRTestCase{"DCX", MQT_NAMED_BUILDER(dcx), - MQT_NAMED_BUILDER(dcx)}, + testing::Values(QIRTestCase{"DCX", MQT_NAMED_BUILDER(dcx<>), + MQT_NAMED_BUILDER(dcx<>)}, QIRTestCase{"SingleControlledDCX", - MQT_NAMED_BUILDER(singleControlledDcx), - MQT_NAMED_BUILDER(singleControlledDcx)}, + MQT_NAMED_BUILDER(singleControlledDcx<>), + MQT_NAMED_BUILDER(singleControlledDcx<>)}, QIRTestCase{"MultipleControlledDCX", - MQT_NAMED_BUILDER(multipleControlledDcx), - MQT_NAMED_BUILDER(multipleControlledDcx)})); + MQT_NAMED_BUILDER(multipleControlledDcx<>), + MQT_NAMED_BUILDER(multipleControlledDcx<>)})); /// @} /// \name QIR/Operations/StandardGates/EcrOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRECROpTest, QIRTest, - testing::Values(QIRTestCase{"ECR", MQT_NAMED_BUILDER(ecr), - MQT_NAMED_BUILDER(ecr)}, + testing::Values(QIRTestCase{"ECR", MQT_NAMED_BUILDER(ecr<>), + MQT_NAMED_BUILDER(ecr<>)}, QIRTestCase{"SingleControlledECR", - MQT_NAMED_BUILDER(singleControlledEcr), - MQT_NAMED_BUILDER(singleControlledEcr)}, + MQT_NAMED_BUILDER(singleControlledEcr<>), + MQT_NAMED_BUILDER(singleControlledEcr<>)}, QIRTestCase{"MultipleControlledECR", - MQT_NAMED_BUILDER(multipleControlledEcr), - MQT_NAMED_BUILDER(multipleControlledEcr)})); + MQT_NAMED_BUILDER(multipleControlledEcr<>), + MQT_NAMED_BUILDER(multipleControlledEcr<>)})); /// @} /// \name QIR/Operations/StandardGates/GphaseOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P(QIRGPhaseOpTest, QIRTest, testing::Values(QIRTestCase{ - "GlobalPhase", MQT_NAMED_BUILDER(globalPhase), - MQT_NAMED_BUILDER(globalPhase)})); + "GlobalPhase", MQT_NAMED_BUILDER(globalPhase<>), + MQT_NAMED_BUILDER(globalPhase<>)})); /// @} /// \name QIR/Operations/StandardGates/HOp.cpp @@ -149,41 +150,41 @@ INSTANTIATE_TEST_SUITE_P(QIRGPhaseOpTest, QIRTest, INSTANTIATE_TEST_SUITE_P( QIRHOpTest, QIRTest, testing::Values( - QIRTestCase{"H", MQT_NAMED_BUILDER(h), MQT_NAMED_BUILDER(h)}, - QIRTestCase{"SingleControlledH", MQT_NAMED_BUILDER(singleControlledH), - MQT_NAMED_BUILDER(singleControlledH)}, + QIRTestCase{"H", MQT_NAMED_BUILDER(h<>), MQT_NAMED_BUILDER(h<>)}, + QIRTestCase{"SingleControlledH", MQT_NAMED_BUILDER(singleControlledH<>), + MQT_NAMED_BUILDER(singleControlledH<>)}, QIRTestCase{"MultipleControlledH", - MQT_NAMED_BUILDER(multipleControlledH), - MQT_NAMED_BUILDER(multipleControlledH)})); + MQT_NAMED_BUILDER(multipleControlledH<>), + MQT_NAMED_BUILDER(multipleControlledH<>)})); /// @} /// \name QIR/Operations/StandardGates/IdOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRIDOpTest, QIRTest, - testing::Values(QIRTestCase{"Identity", MQT_NAMED_BUILDER(identity), - MQT_NAMED_BUILDER(identity)}, + testing::Values(QIRTestCase{"Identity", MQT_NAMED_BUILDER(identity<>), + MQT_NAMED_BUILDER(identity<>)}, QIRTestCase{"SingleControlledIdentity", - MQT_NAMED_BUILDER(singleControlledIdentity), - MQT_NAMED_BUILDER(singleControlledIdentity)}, + MQT_NAMED_BUILDER(singleControlledIdentity<>), + MQT_NAMED_BUILDER(singleControlledIdentity<>)}, QIRTestCase{ "MultipleControlledIdentity", - MQT_NAMED_BUILDER(multipleControlledIdentity), - MQT_NAMED_BUILDER(multipleControlledIdentity)})); + MQT_NAMED_BUILDER(multipleControlledIdentity<>), + MQT_NAMED_BUILDER(multipleControlledIdentity<>)})); /// @} /// \name QIR/Operations/StandardGates/IswapOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRiSWAPOpTest, QIRTest, - testing::Values(QIRTestCase{"iSWAP", MQT_NAMED_BUILDER(iswap), - MQT_NAMED_BUILDER(iswap)}, + testing::Values(QIRTestCase{"iSWAP", MQT_NAMED_BUILDER(iswap<>), + MQT_NAMED_BUILDER(iswap<>)}, QIRTestCase{"SingleControllediSWAP", - MQT_NAMED_BUILDER(singleControlledIswap), - MQT_NAMED_BUILDER(singleControlledIswap)}, + MQT_NAMED_BUILDER(singleControlledIswap<>), + MQT_NAMED_BUILDER(singleControlledIswap<>)}, QIRTestCase{"MultipleControllediSWAP", - MQT_NAMED_BUILDER(multipleControlledIswap), - MQT_NAMED_BUILDER(multipleControlledIswap)})); + MQT_NAMED_BUILDER(multipleControlledIswap<>), + MQT_NAMED_BUILDER(multipleControlledIswap<>)})); /// @} /// \name QIR/Operations/StandardGates/POp.cpp @@ -191,12 +192,12 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QIRPOpTest, QIRTest, testing::Values( - QIRTestCase{"P", MQT_NAMED_BUILDER(p), MQT_NAMED_BUILDER(p)}, - QIRTestCase{"SingleControlledP", MQT_NAMED_BUILDER(singleControlledP), - MQT_NAMED_BUILDER(singleControlledP)}, + QIRTestCase{"P", MQT_NAMED_BUILDER(p<>), MQT_NAMED_BUILDER(p<>)}, + QIRTestCase{"SingleControlledP", MQT_NAMED_BUILDER(singleControlledP<>), + MQT_NAMED_BUILDER(singleControlledP<>)}, QIRTestCase{"MultipleControlledP", - MQT_NAMED_BUILDER(multipleControlledP), - MQT_NAMED_BUILDER(multipleControlledP)})); + MQT_NAMED_BUILDER(multipleControlledP<>), + MQT_NAMED_BUILDER(multipleControlledP<>)})); /// @} /// \name QIR/Operations/StandardGates/ROp.cpp @@ -204,107 +205,110 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QIRROpTest, QIRTest, testing::Values( - QIRTestCase{"R", MQT_NAMED_BUILDER(r), MQT_NAMED_BUILDER(r)}, - QIRTestCase{"SingleControlledR", MQT_NAMED_BUILDER(singleControlledR), - MQT_NAMED_BUILDER(singleControlledR)}, + QIRTestCase{"R", MQT_NAMED_BUILDER(r<>), MQT_NAMED_BUILDER(r<>)}, + QIRTestCase{"SingleControlledR", MQT_NAMED_BUILDER(singleControlledR<>), + MQT_NAMED_BUILDER(singleControlledR<>)}, QIRTestCase{"MultipleControlledR", - MQT_NAMED_BUILDER(multipleControlledR), - MQT_NAMED_BUILDER(multipleControlledR)})); + MQT_NAMED_BUILDER(multipleControlledR<>), + MQT_NAMED_BUILDER(multipleControlledR<>)})); /// @} /// \name QIR/Operations/StandardGates/RxOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRRXOpTest, QIRTest, - testing::Values( - QIRTestCase{"RX", MQT_NAMED_BUILDER(rx), MQT_NAMED_BUILDER(rx)}, - QIRTestCase{"SingleControlledRX", MQT_NAMED_BUILDER(singleControlledRx), - MQT_NAMED_BUILDER(singleControlledRx)}, - QIRTestCase{"MultipleControlledRX", - MQT_NAMED_BUILDER(multipleControlledRx), - MQT_NAMED_BUILDER(multipleControlledRx)})); + testing::Values(QIRTestCase{"RX", MQT_NAMED_BUILDER(rx<>), + MQT_NAMED_BUILDER(rx<>)}, + QIRTestCase{"SingleControlledRX", + MQT_NAMED_BUILDER(singleControlledRx<>), + MQT_NAMED_BUILDER(singleControlledRx<>)}, + QIRTestCase{"MultipleControlledRX", + MQT_NAMED_BUILDER(multipleControlledRx<>), + MQT_NAMED_BUILDER(multipleControlledRx<>)})); /// @} /// \name QIR/Operations/StandardGates/RxxOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRRXXOpTest, QIRTest, - testing::Values(QIRTestCase{"RXX", MQT_NAMED_BUILDER(rxx), - MQT_NAMED_BUILDER(rxx)}, + testing::Values(QIRTestCase{"RXX", MQT_NAMED_BUILDER(rxx<>), + MQT_NAMED_BUILDER(rxx<>)}, QIRTestCase{"SingleControlledRXX", - MQT_NAMED_BUILDER(singleControlledRxx), - MQT_NAMED_BUILDER(singleControlledRxx)}, + MQT_NAMED_BUILDER(singleControlledRxx<>), + MQT_NAMED_BUILDER(singleControlledRxx<>)}, QIRTestCase{"MultipleControlledRXX", - MQT_NAMED_BUILDER(multipleControlledRxx), - MQT_NAMED_BUILDER(multipleControlledRxx)})); + MQT_NAMED_BUILDER(multipleControlledRxx<>), + MQT_NAMED_BUILDER(multipleControlledRxx<>)})); /// @} /// \name QIR/Operations/StandardGates/RyOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRRYOpTest, QIRTest, - testing::Values( - QIRTestCase{"RY", MQT_NAMED_BUILDER(ry), MQT_NAMED_BUILDER(ry)}, - QIRTestCase{"SingleControlledRY", MQT_NAMED_BUILDER(singleControlledRy), - MQT_NAMED_BUILDER(singleControlledRy)}, - QIRTestCase{"MultipleControlledRY", - MQT_NAMED_BUILDER(multipleControlledRy), - MQT_NAMED_BUILDER(multipleControlledRy)})); + testing::Values(QIRTestCase{"RY", MQT_NAMED_BUILDER(ry<>), + MQT_NAMED_BUILDER(ry<>)}, + QIRTestCase{"SingleControlledRY", + MQT_NAMED_BUILDER(singleControlledRy<>), + MQT_NAMED_BUILDER(singleControlledRy<>)}, + QIRTestCase{"MultipleControlledRY", + MQT_NAMED_BUILDER(multipleControlledRy<>), + MQT_NAMED_BUILDER(multipleControlledRy<>)})); /// @} /// \name QIR/Operations/StandardGates/RyyOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRRYYOpTest, QIRTest, - testing::Values(QIRTestCase{"RYY", MQT_NAMED_BUILDER(ryy), - MQT_NAMED_BUILDER(ryy)}, + testing::Values(QIRTestCase{"RYY", MQT_NAMED_BUILDER(ryy<>), + MQT_NAMED_BUILDER(ryy<>)}, QIRTestCase{"SingleControlledRYY", - MQT_NAMED_BUILDER(singleControlledRyy), - MQT_NAMED_BUILDER(singleControlledRyy)}, + MQT_NAMED_BUILDER(singleControlledRyy<>), + MQT_NAMED_BUILDER(singleControlledRyy<>)}, QIRTestCase{"MultipleControlledRYY", - MQT_NAMED_BUILDER(multipleControlledRyy), - MQT_NAMED_BUILDER(multipleControlledRyy)})); + MQT_NAMED_BUILDER(multipleControlledRyy<>), + MQT_NAMED_BUILDER(multipleControlledRyy<>)})); /// @} /// \name QIR/Operations/StandardGates/RzOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRRZOpTest, QIRTest, - testing::Values( - QIRTestCase{"RZ", MQT_NAMED_BUILDER(rz), MQT_NAMED_BUILDER(rz)}, - QIRTestCase{"SingleControlledRZ", MQT_NAMED_BUILDER(singleControlledRz), - MQT_NAMED_BUILDER(singleControlledRz)}, - QIRTestCase{"MultipleControlledRZ", - MQT_NAMED_BUILDER(multipleControlledRz), - MQT_NAMED_BUILDER(multipleControlledRz)})); + testing::Values(QIRTestCase{"RZ", MQT_NAMED_BUILDER(rz<>), + MQT_NAMED_BUILDER(rz<>)}, + QIRTestCase{"SingleControlledRZ", + MQT_NAMED_BUILDER(singleControlledRz<>), + MQT_NAMED_BUILDER(singleControlledRz<>)}, + QIRTestCase{"MultipleControlledRZ", + MQT_NAMED_BUILDER(multipleControlledRz<>), + MQT_NAMED_BUILDER(multipleControlledRz<>)})); /// @} /// \name QIR/Operations/StandardGates/RzxOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRRZXOpTest, QIRTest, - testing::Values(QIRTestCase{"RZX", MQT_NAMED_BUILDER(rzx), - MQT_NAMED_BUILDER(rzx)}, + testing::Values(QIRTestCase{"RZX", MQT_NAMED_BUILDER(rzx<>), + MQT_NAMED_BUILDER(rzx<>)}, QIRTestCase{"SingleControlledRZX", - MQT_NAMED_BUILDER(singleControlledRzx), - MQT_NAMED_BUILDER(singleControlledRzx)}, + MQT_NAMED_BUILDER(singleControlledRzx<>), + MQT_NAMED_BUILDER(singleControlledRzx<>)}, QIRTestCase{"MultipleControlledRZX", - MQT_NAMED_BUILDER(multipleControlledRzx), - MQT_NAMED_BUILDER(multipleControlledRzx)})); + MQT_NAMED_BUILDER(multipleControlledRzx<>), + MQT_NAMED_BUILDER(multipleControlledRzx<>)})); /// @} /// \name QIR/Operations/StandardGates/RzzOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRRZZOpTest, QIRTest, - testing::Values(QIRTestCase{"RZZ", MQT_NAMED_BUILDER(rzz), - MQT_NAMED_BUILDER(rzz)}, + testing::Values(QIRTestCase{"RZZ", MQT_NAMED_BUILDER(rzz<>), + MQT_NAMED_BUILDER(rzz<>)}, QIRTestCase{"SingleControlledRZZ", - MQT_NAMED_BUILDER(singleControlledRzz), - MQT_NAMED_BUILDER(singleControlledRzz)}, + MQT_NAMED_BUILDER(singleControlledRzz<>), + MQT_NAMED_BUILDER(singleControlledRzz<>)}, QIRTestCase{"MultipleControlledRZZ", - MQT_NAMED_BUILDER(multipleControlledRzz), - MQT_NAMED_BUILDER(multipleControlledRzz)})); + MQT_NAMED_BUILDER(multipleControlledRzz<>), + MQT_NAMED_BUILDER(multipleControlledRzz<>)})); /// @} /// \name QIR/Operations/StandardGates/SOp.cpp @@ -312,67 +316,68 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QIRSOpTest, QIRTest, testing::Values( - QIRTestCase{"S", MQT_NAMED_BUILDER(s), MQT_NAMED_BUILDER(s)}, - QIRTestCase{"SingleControlledS", MQT_NAMED_BUILDER(singleControlledS), - MQT_NAMED_BUILDER(singleControlledS)}, + QIRTestCase{"S", MQT_NAMED_BUILDER(s<>), MQT_NAMED_BUILDER(s<>)}, + QIRTestCase{"SingleControlledS", MQT_NAMED_BUILDER(singleControlledS<>), + MQT_NAMED_BUILDER(singleControlledS<>)}, QIRTestCase{"MultipleControlledS", - MQT_NAMED_BUILDER(multipleControlledS), - MQT_NAMED_BUILDER(multipleControlledS)})); + MQT_NAMED_BUILDER(multipleControlledS<>), + MQT_NAMED_BUILDER(multipleControlledS<>)})); /// @} /// \name QIR/Operations/StandardGates/SdgOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRSdgOpTest, QIRTest, - testing::Values(QIRTestCase{"Sdg", MQT_NAMED_BUILDER(sdg), - MQT_NAMED_BUILDER(sdg)}, + testing::Values(QIRTestCase{"Sdg", MQT_NAMED_BUILDER(sdg<>), + MQT_NAMED_BUILDER(sdg<>)}, QIRTestCase{"SingleControlledSdg", - MQT_NAMED_BUILDER(singleControlledSdg), - MQT_NAMED_BUILDER(singleControlledSdg)}, + MQT_NAMED_BUILDER(singleControlledSdg<>), + MQT_NAMED_BUILDER(singleControlledSdg<>)}, QIRTestCase{"MultipleControlledSdg", - MQT_NAMED_BUILDER(multipleControlledSdg), - MQT_NAMED_BUILDER(multipleControlledSdg)})); + MQT_NAMED_BUILDER(multipleControlledSdg<>), + MQT_NAMED_BUILDER(multipleControlledSdg<>)})); /// @} /// \name QIR/Operations/StandardGates/SwapOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRSWAPOpTest, QIRTest, - testing::Values(QIRTestCase{"SWAP", MQT_NAMED_BUILDER(swap), - MQT_NAMED_BUILDER(swap)}, + testing::Values(QIRTestCase{"SWAP", MQT_NAMED_BUILDER(swap<>), + MQT_NAMED_BUILDER(swap<>)}, QIRTestCase{"SingleControlledSWAP", - MQT_NAMED_BUILDER(singleControlledSwap), - MQT_NAMED_BUILDER(singleControlledSwap)}, + MQT_NAMED_BUILDER(singleControlledSwap<>), + MQT_NAMED_BUILDER(singleControlledSwap<>)}, QIRTestCase{"MultipleControlledSWAP", - MQT_NAMED_BUILDER(multipleControlledSwap), - MQT_NAMED_BUILDER(multipleControlledSwap)})); + MQT_NAMED_BUILDER(multipleControlledSwap<>), + MQT_NAMED_BUILDER(multipleControlledSwap<>)})); /// @} /// \name QIR/Operations/StandardGates/SxOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRSXOpTest, QIRTest, - testing::Values( - QIRTestCase{"SX", MQT_NAMED_BUILDER(sx), MQT_NAMED_BUILDER(sx)}, - QIRTestCase{"SingleControlledSX", MQT_NAMED_BUILDER(singleControlledSx), - MQT_NAMED_BUILDER(singleControlledSx)}, - QIRTestCase{"MultipleControlledSX", - MQT_NAMED_BUILDER(multipleControlledSx), - MQT_NAMED_BUILDER(multipleControlledSx)})); + testing::Values(QIRTestCase{"SX", MQT_NAMED_BUILDER(sx<>), + MQT_NAMED_BUILDER(sx<>)}, + QIRTestCase{"SingleControlledSX", + MQT_NAMED_BUILDER(singleControlledSx<>), + MQT_NAMED_BUILDER(singleControlledSx<>)}, + QIRTestCase{"MultipleControlledSX", + MQT_NAMED_BUILDER(multipleControlledSx<>), + MQT_NAMED_BUILDER(multipleControlledSx<>)})); /// @} /// \name QIR/Operations/StandardGates/SxdgOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRSXdgOpTest, QIRTest, - testing::Values(QIRTestCase{"SXdg", MQT_NAMED_BUILDER(sxdg), - MQT_NAMED_BUILDER(sxdg)}, + testing::Values(QIRTestCase{"SXdg", MQT_NAMED_BUILDER(sxdg<>), + MQT_NAMED_BUILDER(sxdg<>)}, QIRTestCase{"SingleControlledSXdg", - MQT_NAMED_BUILDER(singleControlledSxdg), - MQT_NAMED_BUILDER(singleControlledSxdg)}, + MQT_NAMED_BUILDER(singleControlledSxdg<>), + MQT_NAMED_BUILDER(singleControlledSxdg<>)}, QIRTestCase{"MultipleControlledSXdg", - MQT_NAMED_BUILDER(multipleControlledSxdg), - MQT_NAMED_BUILDER(multipleControlledSxdg)})); + MQT_NAMED_BUILDER(multipleControlledSxdg<>), + MQT_NAMED_BUILDER(multipleControlledSxdg<>)})); /// @} /// \name QIR/Operations/StandardGates/TOp.cpp @@ -380,39 +385,40 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QIRTOpTest, QIRTest, testing::Values( - QIRTestCase{"T", MQT_NAMED_BUILDER(t_), MQT_NAMED_BUILDER(t_)}, - QIRTestCase{"SingleControlledT", MQT_NAMED_BUILDER(singleControlledT), - MQT_NAMED_BUILDER(singleControlledT)}, + QIRTestCase{"T", MQT_NAMED_BUILDER(t_<>), MQT_NAMED_BUILDER(t_<>)}, + QIRTestCase{"SingleControlledT", MQT_NAMED_BUILDER(singleControlledT<>), + MQT_NAMED_BUILDER(singleControlledT<>)}, QIRTestCase{"MultipleControlledT", - MQT_NAMED_BUILDER(multipleControlledT), - MQT_NAMED_BUILDER(multipleControlledT)})); + MQT_NAMED_BUILDER(multipleControlledT<>), + MQT_NAMED_BUILDER(multipleControlledT<>)})); /// @} /// \name QIR/Operations/StandardGates/TdgOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRTdgOpTest, QIRTest, - testing::Values(QIRTestCase{"Tdg", MQT_NAMED_BUILDER(tdg), - MQT_NAMED_BUILDER(tdg)}, + testing::Values(QIRTestCase{"Tdg", MQT_NAMED_BUILDER(tdg<>), + MQT_NAMED_BUILDER(tdg<>)}, QIRTestCase{"SingleControlledTdg", - MQT_NAMED_BUILDER(singleControlledTdg), - MQT_NAMED_BUILDER(singleControlledTdg)}, + MQT_NAMED_BUILDER(singleControlledTdg<>), + MQT_NAMED_BUILDER(singleControlledTdg<>)}, QIRTestCase{"MultipleControlledTdg", - MQT_NAMED_BUILDER(multipleControlledTdg), - MQT_NAMED_BUILDER(multipleControlledTdg)})); + MQT_NAMED_BUILDER(multipleControlledTdg<>), + MQT_NAMED_BUILDER(multipleControlledTdg<>)})); /// @} /// \name QIR/Operations/StandardGates/U2Op.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRU2OpTest, QIRTest, - testing::Values( - QIRTestCase{"U2", MQT_NAMED_BUILDER(u2), MQT_NAMED_BUILDER(u2)}, - QIRTestCase{"SingleControlledU2", MQT_NAMED_BUILDER(singleControlledU2), - MQT_NAMED_BUILDER(singleControlledU2)}, - QIRTestCase{"MultipleControlledU2", - MQT_NAMED_BUILDER(multipleControlledU2), - MQT_NAMED_BUILDER(multipleControlledU2)})); + testing::Values(QIRTestCase{"U2", MQT_NAMED_BUILDER(u2<>), + MQT_NAMED_BUILDER(u2<>)}, + QIRTestCase{"SingleControlledU2", + MQT_NAMED_BUILDER(singleControlledU2<>), + MQT_NAMED_BUILDER(singleControlledU2<>)}, + QIRTestCase{"MultipleControlledU2", + MQT_NAMED_BUILDER(multipleControlledU2<>), + MQT_NAMED_BUILDER(multipleControlledU2<>)})); /// @} /// \name QIR/Operations/StandardGates/UOp.cpp @@ -420,12 +426,12 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QIRUOpTest, QIRTest, testing::Values( - QIRTestCase{"U", MQT_NAMED_BUILDER(u), MQT_NAMED_BUILDER(u)}, - QIRTestCase{"SingleControlledU", MQT_NAMED_BUILDER(singleControlledU), - MQT_NAMED_BUILDER(singleControlledU)}, + QIRTestCase{"U", MQT_NAMED_BUILDER(u<>), MQT_NAMED_BUILDER(u<>)}, + QIRTestCase{"SingleControlledU", MQT_NAMED_BUILDER(singleControlledU<>), + MQT_NAMED_BUILDER(singleControlledU<>)}, QIRTestCase{"MultipleControlledU", - MQT_NAMED_BUILDER(multipleControlledU), - MQT_NAMED_BUILDER(multipleControlledU)})); + MQT_NAMED_BUILDER(multipleControlledU<>), + MQT_NAMED_BUILDER(multipleControlledU<>)})); /// @} /// \name QIR/Operations/StandardGates/XOp.cpp @@ -433,42 +439,42 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QIRXOpTest, QIRTest, testing::Values( - QIRTestCase{"X", MQT_NAMED_BUILDER(x), MQT_NAMED_BUILDER(x)}, - QIRTestCase{"SingleControlledX", MQT_NAMED_BUILDER(singleControlledX), - MQT_NAMED_BUILDER(singleControlledX)}, + QIRTestCase{"X", MQT_NAMED_BUILDER(x<>), MQT_NAMED_BUILDER(x<>)}, + QIRTestCase{"SingleControlledX", MQT_NAMED_BUILDER(singleControlledX<>), + MQT_NAMED_BUILDER(singleControlledX<>)}, QIRTestCase{"MultipleControlledX", - MQT_NAMED_BUILDER(multipleControlledX), - MQT_NAMED_BUILDER(multipleControlledX)})); + MQT_NAMED_BUILDER(multipleControlledX<>), + MQT_NAMED_BUILDER(multipleControlledX<>)})); /// @} /// \name QIR/Operations/StandardGates/XxMinusYyOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRXXMinusYYOpTest, QIRTest, - testing::Values(QIRTestCase{"XXMinusYY", MQT_NAMED_BUILDER(xxMinusYY), - MQT_NAMED_BUILDER(xxMinusYY)}, + testing::Values(QIRTestCase{"XXMinusYY", MQT_NAMED_BUILDER(xxMinusYY<>), + MQT_NAMED_BUILDER(xxMinusYY<>)}, QIRTestCase{"SingleControlledXXMinusYY", - MQT_NAMED_BUILDER(singleControlledXxMinusYY), - MQT_NAMED_BUILDER(singleControlledXxMinusYY)}, + MQT_NAMED_BUILDER(singleControlledXxMinusYY<>), + MQT_NAMED_BUILDER(singleControlledXxMinusYY<>)}, QIRTestCase{ "MultipleControlledXXMinusYY", - MQT_NAMED_BUILDER(multipleControlledXxMinusYY), - MQT_NAMED_BUILDER(multipleControlledXxMinusYY)})); + MQT_NAMED_BUILDER(multipleControlledXxMinusYY<>), + MQT_NAMED_BUILDER(multipleControlledXxMinusYY<>)})); /// @} /// \name QIR/Operations/StandardGates/XxPlusYyOp.cpp /// @{ INSTANTIATE_TEST_SUITE_P( QIRXXPlusYYOpTest, QIRTest, - testing::Values(QIRTestCase{"XXPlusYY", MQT_NAMED_BUILDER(xxPlusYY), - MQT_NAMED_BUILDER(xxPlusYY)}, + testing::Values(QIRTestCase{"XXPlusYY", MQT_NAMED_BUILDER(xxPlusYY<>), + MQT_NAMED_BUILDER(xxPlusYY<>)}, QIRTestCase{"SingleControlledXXPlusYY", - MQT_NAMED_BUILDER(singleControlledXxPlusYY), - MQT_NAMED_BUILDER(singleControlledXxPlusYY)}, + MQT_NAMED_BUILDER(singleControlledXxPlusYY<>), + MQT_NAMED_BUILDER(singleControlledXxPlusYY<>)}, QIRTestCase{ "MultipleControlledXXPlusYY", - MQT_NAMED_BUILDER(multipleControlledXxPlusYY), - MQT_NAMED_BUILDER(multipleControlledXxPlusYY)})); + MQT_NAMED_BUILDER(multipleControlledXxPlusYY<>), + MQT_NAMED_BUILDER(multipleControlledXxPlusYY<>)})); /// @} /// \name QIR/Operations/StandardGates/YOp.cpp @@ -476,12 +482,12 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QIRYOpTest, QIRTest, testing::Values( - QIRTestCase{"Y", MQT_NAMED_BUILDER(y), MQT_NAMED_BUILDER(y)}, - QIRTestCase{"SingleControlledY", MQT_NAMED_BUILDER(singleControlledY), - MQT_NAMED_BUILDER(singleControlledY)}, + QIRTestCase{"Y", MQT_NAMED_BUILDER(y<>), MQT_NAMED_BUILDER(y<>)}, + QIRTestCase{"SingleControlledY", MQT_NAMED_BUILDER(singleControlledY<>), + MQT_NAMED_BUILDER(singleControlledY<>)}, QIRTestCase{"MultipleControlledY", - MQT_NAMED_BUILDER(multipleControlledY), - MQT_NAMED_BUILDER(multipleControlledY)})); + MQT_NAMED_BUILDER(multipleControlledY<>), + MQT_NAMED_BUILDER(multipleControlledY<>)})); /// @} /// \name QIR/Operations/StandardGates/ZOp.cpp @@ -489,12 +495,12 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QIRZOpTest, QIRTest, testing::Values( - QIRTestCase{"Z", MQT_NAMED_BUILDER(z), MQT_NAMED_BUILDER(z)}, - QIRTestCase{"SingleControlledZ", MQT_NAMED_BUILDER(singleControlledZ), - MQT_NAMED_BUILDER(singleControlledZ)}, + QIRTestCase{"Z", MQT_NAMED_BUILDER(z<>), MQT_NAMED_BUILDER(z<>)}, + QIRTestCase{"SingleControlledZ", MQT_NAMED_BUILDER(singleControlledZ<>), + MQT_NAMED_BUILDER(singleControlledZ<>)}, QIRTestCase{"MultipleControlledZ", - MQT_NAMED_BUILDER(multipleControlledZ), - MQT_NAMED_BUILDER(multipleControlledZ)})); + MQT_NAMED_BUILDER(multipleControlledZ<>), + MQT_NAMED_BUILDER(multipleControlledZ<>)})); /// @} /// \name QIR/Operations/MeasureOp.cpp @@ -503,14 +509,14 @@ INSTANTIATE_TEST_SUITE_P( QIRMeasureOpTest, QIRTest, testing::Values( QIRTestCase{"SingleMeasurementToSingleBit", - MQT_NAMED_BUILDER(singleMeasurementToSingleBit), - MQT_NAMED_BUILDER(singleMeasurementToSingleBit)}, + MQT_NAMED_BUILDER(singleMeasurementToSingleBit<>), + MQT_NAMED_BUILDER(singleMeasurementToSingleBit<>)}, QIRTestCase{"RepeatedMeasurementToSameBit", - MQT_NAMED_BUILDER(repeatedMeasurementToSameBit), - MQT_NAMED_BUILDER(repeatedMeasurementToSameBit)}, + MQT_NAMED_BUILDER(repeatedMeasurementToSameBit<>), + MQT_NAMED_BUILDER(repeatedMeasurementToSameBit<>)}, QIRTestCase{"RepeatedMeasurementToDifferentBits", - MQT_NAMED_BUILDER(repeatedMeasurementToDifferentBits), - MQT_NAMED_BUILDER(repeatedMeasurementToDifferentBits)})); + MQT_NAMED_BUILDER(repeatedMeasurementToDifferentBits<>), + MQT_NAMED_BUILDER(repeatedMeasurementToDifferentBits<>)})); /// @} /// \name QIR/Operations/ResetOp.cpp @@ -519,23 +525,23 @@ INSTANTIATE_TEST_SUITE_P( QIRResetOpTest, QIRTest, testing::Values( QIRTestCase{"ResetQubitWithoutOp", - MQT_NAMED_BUILDER(resetQubitWithoutOp), - MQT_NAMED_BUILDER(resetQubitWithoutOp)}, + MQT_NAMED_BUILDER(resetQubitWithoutOp<>), + MQT_NAMED_BUILDER(resetQubitWithoutOp<>)}, QIRTestCase{"ResetMultipleQubitsWithoutOp", - MQT_NAMED_BUILDER(resetMultipleQubitsWithoutOp), - MQT_NAMED_BUILDER(resetMultipleQubitsWithoutOp)}, + MQT_NAMED_BUILDER(resetMultipleQubitsWithoutOp<>), + MQT_NAMED_BUILDER(resetMultipleQubitsWithoutOp<>)}, QIRTestCase{"RepeatedResetWithoutOp", - MQT_NAMED_BUILDER(repeatedResetWithoutOp), - MQT_NAMED_BUILDER(repeatedResetWithoutOp)}, + MQT_NAMED_BUILDER(repeatedResetWithoutOp<>), + MQT_NAMED_BUILDER(repeatedResetWithoutOp<>)}, QIRTestCase{"ResetQubitAfterSingleOp", - MQT_NAMED_BUILDER(resetQubitAfterSingleOp), - MQT_NAMED_BUILDER(resetQubitAfterSingleOp)}, + MQT_NAMED_BUILDER(resetQubitAfterSingleOp<>), + MQT_NAMED_BUILDER(resetQubitAfterSingleOp<>)}, QIRTestCase{"ResetMultipleQubitsAfterSingleOp", - MQT_NAMED_BUILDER(resetMultipleQubitsAfterSingleOp), - MQT_NAMED_BUILDER(resetMultipleQubitsAfterSingleOp)}, + MQT_NAMED_BUILDER(resetMultipleQubitsAfterSingleOp<>), + MQT_NAMED_BUILDER(resetMultipleQubitsAfterSingleOp<>)}, QIRTestCase{"RepeatedResetAfterSingleOp", - MQT_NAMED_BUILDER(repeatedResetAfterSingleOp), - MQT_NAMED_BUILDER(repeatedResetAfterSingleOp)})); + MQT_NAMED_BUILDER(repeatedResetAfterSingleOp<>), + MQT_NAMED_BUILDER(repeatedResetAfterSingleOp<>)})); /// @} /// \name QIR/QubitManagement/QubitManagement.cpp @@ -543,15 +549,17 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( QIRQubitManagementTest, QIRTest, testing::Values( - QIRTestCase{"AllocQubit", MQT_NAMED_BUILDER(allocQubit), - MQT_NAMED_BUILDER(allocQubit)}, - QIRTestCase{"AllocQubitRegister", MQT_NAMED_BUILDER(allocQubitRegister), - MQT_NAMED_BUILDER(allocQubitRegister)}, + QIRTestCase{"AllocQubit", MQT_NAMED_BUILDER(allocQubit<>), + MQT_NAMED_BUILDER(allocQubit<>)}, + QIRTestCase{"AllocQubitRegister", + MQT_NAMED_BUILDER(allocQubitRegister<>), + MQT_NAMED_BUILDER(allocQubitRegister<>)}, QIRTestCase{"AllocMultipleQubitRegisters", - MQT_NAMED_BUILDER(allocMultipleQubitRegisters), - MQT_NAMED_BUILDER(allocMultipleQubitRegisters)}, - QIRTestCase{"AllocLargeRegister", MQT_NAMED_BUILDER(allocLargeRegister), - MQT_NAMED_BUILDER(allocLargeRegister)}, + MQT_NAMED_BUILDER(allocMultipleQubitRegisters<>), + MQT_NAMED_BUILDER(allocMultipleQubitRegisters<>)}, + QIRTestCase{"AllocLargeRegister", + MQT_NAMED_BUILDER(allocLargeRegister<>), + MQT_NAMED_BUILDER(allocLargeRegister<>)}, QIRTestCase{"StaticQubits", MQT_NAMED_BUILDER(staticQubits), MQT_NAMED_BUILDER(staticQubits)}, QIRTestCase{"StaticQubitsWithOps", diff --git a/mlir/unittests/Dialect/QTensor/IR/test_qtensor_ir.cpp b/mlir/unittests/Dialect/QTensor/IR/test_qtensor_ir.cpp index a76e20cc1a..a94ad944c0 100644 --- a/mlir/unittests/Dialect/QTensor/IR/test_qtensor_ir.cpp +++ b/mlir/unittests/Dialect/QTensor/IR/test_qtensor_ir.cpp @@ -33,7 +33,10 @@ #include #include #include +#include +#include #include +#include #include #include @@ -41,6 +44,7 @@ #include #include #include +#include using namespace mlir; using namespace mlir::qtensor; @@ -62,9 +66,11 @@ class QTensorTest : public ::testing::Test { } /// Build a module using the QCOProgramBuilder and run the cleanup pipeline. + template [[nodiscard]] OwningOpRef - buildAndCanonicalize(void (*buildFn)(QCOProgramBuilder&)) const { - auto module = QCOProgramBuilder::build(context.get(), buildFn); + buildAndCanonicalize(BuildFn&& buildFn) const { + auto module = + QCOProgramBuilder::build(context.get(), std::forward(buildFn)); if (!module) { return {}; } @@ -189,8 +195,10 @@ TEST_F(QTensorTest, AllocOpStaticTypeWithDynamicSizeOperandFailsVerification) { /// An alloc immediately followed by dealloc should be eliminated entirely. TEST_F(QTensorTest, DeallocOpAllocDeallocPairIsRemoved) { - auto canonicalized = - buildAndCanonicalize([](QCOProgramBuilder& b) { b.qtensorAlloc(3); }); + auto canonicalized = buildAndCanonicalize([](QCOProgramBuilder& b) { + b.qtensorAlloc(3); + return b.intConstant(0); + }); ASSERT_TRUE(canonicalized); EXPECT_TRUE(verify(*canonicalized).succeeded()); // Both AllocOp and DeallocOp should have been erased. @@ -416,8 +424,8 @@ TEST_F(QTensorTest, ResetAfterExtractThroughSameIndexInsertIsNotEliminated) { struct QTensorIntegrationTestCase { std::string name; - mqt::test::NamedBuilder programBuilder; - mqt::test::NamedBuilder referenceBuilder; + mqt::test::NamedMLIRBuilder programBuilder; + mqt::test::NamedMLIRBuilder referenceBuilder; friend std::ostream& operator<<(std::ostream& os, const QTensorIntegrationTestCase& info); @@ -449,7 +457,7 @@ TEST_P(QTensorIntegrationTest, ProgramEquivalence) { const auto name = " (" + GetParam().name + ")"; mqt::test::DeferredPrinter printer; - auto program = QCOProgramBuilder::build(context.get(), programBuilder.fn); + auto program = mqt::test::buildMLIRProgram(context.get(), programBuilder); ASSERT_TRUE(program); printer.record(program.get(), "Original QTensor IR" + name); EXPECT_TRUE(verify(*program).succeeded()); @@ -458,7 +466,7 @@ TEST_P(QTensorIntegrationTest, ProgramEquivalence) { printer.record(program.get(), "Canonicalized QTensor IR" + name); EXPECT_TRUE(verify(*program).succeeded()); - auto reference = QCOProgramBuilder::build(context.get(), referenceBuilder.fn); + auto reference = mqt::test::buildMLIRProgram(context.get(), referenceBuilder); ASSERT_TRUE(reference); printer.record(reference.get(), "Reference QTensor IR" + name); EXPECT_TRUE(verify(*reference).succeeded()); diff --git a/mlir/unittests/TestCaseUtils.h b/mlir/unittests/TestCaseUtils.h index 570c86c87f..2646b3207a 100644 --- a/mlir/unittests/TestCaseUtils.h +++ b/mlir/unittests/TestCaseUtils.h @@ -17,20 +17,25 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include +#include #include namespace mqt::test { -template struct NamedBuilder { +template struct NamedBuilder { const char* name = nullptr; - void (*fn)(BuilderT&) = nullptr; + RetT (*fn)(BuilderT&) = nullptr; - constexpr NamedBuilder(const char* nameIn, void (*fnIn)(BuilderT&)) noexcept + constexpr NamedBuilder(const char* nameIn, RetT (*fnIn)(BuilderT&)) noexcept : name(nameIn), fn(fnIn) {} // NOLINTNEXTLINE(*-explicit-constructor) @@ -41,10 +46,62 @@ template struct NamedBuilder { } }; +template +[[nodiscard]] constexpr NamedBuilder +namedBuilder(const char* name, RetT (*fn)(BuilderT&)) noexcept { + return NamedBuilder{name, fn}; +} + +template struct NamedMLIRBuilder { + using SingleFn = mlir::Value (*)(BuilderT&); + using MultiFn = mlir::SmallVector (*)(BuilderT&); + + const char* name = nullptr; + std::variant fn; + + constexpr NamedMLIRBuilder(const char* nameIn, SingleFn fnIn) noexcept + : name(nameIn), fn(fnIn) {} + + constexpr NamedMLIRBuilder(const char* nameIn, MultiFn fnIn) noexcept + : name(nameIn), fn(fnIn) {} + + // NOLINTNEXTLINE(*-explicit-constructor) + constexpr NamedMLIRBuilder(std::nullptr_t) noexcept : fn(std::monostate{}) {} + + [[nodiscard]] constexpr explicit operator bool() const noexcept { + return !std::holds_alternative(fn); + } +}; + template -[[nodiscard]] constexpr NamedBuilder -namedBuilder(const char* name, void (*fn)(BuilderT&)) noexcept { - return NamedBuilder{name, fn}; +[[nodiscard]] constexpr NamedMLIRBuilder +namedBuilder(const char* name, mlir::Value (*fn)(BuilderT&)) noexcept { + return NamedMLIRBuilder{name, fn}; +} + +template +[[nodiscard]] constexpr NamedMLIRBuilder +namedBuilder(const char* name, + mlir::SmallVector (*fn)(BuilderT&)) noexcept { + return NamedMLIRBuilder{name, fn}; +} + +template +[[nodiscard]] mlir::OwningOpRef +buildMLIRProgram(mlir::MLIRContext* context, + const NamedMLIRBuilder& builder, Args&&... args) { + return std::visit( + [&](T fn) -> mlir::OwningOpRef { + if constexpr (requires { + BuilderT::build(context, fn, + std::forward(args)...); + }) { + return BuilderT::build(context, fn, std::forward(args)...); + } else { + return {}; + } + }, + builder.fn); } [[nodiscard]] constexpr const char* displayName(const char* name) noexcept { diff --git a/mlir/unittests/programs/qasm_programs.cpp b/mlir/unittests/programs/qasm_programs.cpp index 2386d7e8c7..97cf133e2a 100644 --- a/mlir/unittests/programs/qasm_programs.cpp +++ b/mlir/unittests/programs/qasm_programs.cpp @@ -18,29 +18,35 @@ namespace mlir::qasm { const std::string allocQubit = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit q; +bit c = measure q; )qasm"; const std::string allocQubitRegister = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; +bit[2] c = measure q; )qasm"; const std::string allocMultipleQubitRegisters = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q0; qubit[3] q1; +bit[2] c0 = measure q0; +bit[3] c1 = measure q1; )qasm"; const std::string allocLargeRegister = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[100] q; +bit[2] c; +c[0] = measure q[0]; +c[1] = measure q[99]; )qasm"; const std::string singleMeasurementToSingleBit = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; -bit[1] c; -measure q[0] -> c[0]; +bit[1] c = measure q[0]; )qasm"; const std::string repeatedMeasurementToSameBit = R"qasm(OPENQASM 3.0; @@ -77,6 +83,7 @@ include "stdgates.inc"; qubit[1] q; h q[0]; reset q[0]; +bit[1] c = measure q; )qasm"; const std::string resetMultipleQubitsAfterSingleOp = R"qasm(OPENQASM 3.0; @@ -86,6 +93,7 @@ h q[0]; reset q[0]; h q[1]; reset q[1]; +bit[2] c = measure q; )qasm"; const std::string repeatedResetAfterSingleOp = R"qasm(OPENQASM 3.0; @@ -95,6 +103,7 @@ h q[0]; reset q[0]; reset q[0]; reset q[0]; +bit[1] c = measure q; )qasm"; const std::string globalPhase = R"qasm(OPENQASM 3.0; @@ -111,60 +120,70 @@ const std::string identity = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; id q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledIdentity = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ id q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledIdentity = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ id q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string x = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; x q[0]; +bit[1] c = measure q; )qasm"; const std::string twoX = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; x q; +bit[2] c = measure q; )qasm"; const std::string singleControlledX = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ x q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleNegControlledX = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; negctrl @ x q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledX = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ x q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string tripleControlledXOpenQASM2 = R"qasm(OPENQASM 2.0; include "qelib1.inc"; qreg q[4]; cccx q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string mixedControlledX = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ negctrl @ x q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string twoMixedControlledX = R"qasm(OPENQASM 3.0; @@ -173,522 +192,611 @@ qubit[2] q1; qubit[2] q2; qubit[2] q3; ctrl @ negctrl @ x q1, q2, q3; +bit[2] c1 = measure q1; +bit[2] c2 = measure q2; +bit[2] c3 = measure q3; )qasm"; const std::string inverseX = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; inv @ x q[0]; +bit[1] c = measure q; )qasm"; const std::string inverseMultipleControlledX = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; inv @ ctrl(2) @ x q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string y = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; y q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledY = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ y q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledY = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ y q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string z = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; z q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledZ = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ z q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledZ = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ z q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string h = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; h q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledH = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ h q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledH = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ h q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string s = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; s q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledS = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ s q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledS = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ s q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string sdg = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; sdg q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledSdg = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ sdg q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledSdg = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ sdg q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string t_ = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; t q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledT = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ t q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledT = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ t q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string tdg = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; tdg q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledTdg = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ tdg q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledTdg = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ tdg q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string sx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; sx q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledSx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ sx q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledSx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ sx q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string sxdg = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; sxdg q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledSxdg = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ sxdg q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledSxdg = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ sxdg q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string rx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; rx(0.123) q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledRx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ rx(0.123) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledRx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ rx(0.123) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string ry = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; ry(0.456) q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledRy = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ ry(0.456) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledRy = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ ry(0.456) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string rz = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; rz(0.789) q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledRz = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ rz(0.789) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledRz = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ rz(0.789) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string p = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; p(0.123) q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledP = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ p(0.123) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledP = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ p(0.123) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string r = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; r(0.123, 0.456) q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledR = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ r(0.123, 0.456) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledR = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ r(0.123, 0.456) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string u2 = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; u2(0.234, 0.567) q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledU2 = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ u2(0.234, 0.567) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledU2 = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ u2(0.234, 0.567) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string u = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; u(0.1, 0.2, 0.3) q[0]; +bit[1] c = measure q; )qasm"; const std::string singleControlledU = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ctrl @ u(0.1, 0.2, 0.3) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string multipleControlledU = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl(2) @ u(0.1, 0.2, 0.3) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string swap = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; swap q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledSwap = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ swap q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledSwap = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ swap q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string iswap = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; iswap q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledIswap = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ iswap q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledIswap = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ iswap q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string inverseIswap = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; inv @ iswap q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string inverseMultipleControlledIswap = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; inv @ ctrl(2) @ iswap q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string dcx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; dcx q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledDcx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ dcx q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledDcx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ dcx q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string ecr = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ecr q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledEcr = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ ecr q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledEcr = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ ecr q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string rxx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; rxx(0.123) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledRxx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ rxx(0.123) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledRxx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ rxx(0.123) q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string tripleControlledRxx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[5] q; ctrl(3) @ rxx(0.123) q[0], q[1], q[2], q[3], q[4]; +bit[5] c = measure q; )qasm"; const std::string ryy = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; ryy(0.123) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledRyy = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ ryy(0.123) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledRyy = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ ryy(0.123) q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string rzx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; rzx(0.123) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledRzx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ rzx(0.123) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledRzx = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ rzx(0.123) q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string rzz = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; rzz(0.123) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledRzz = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ rzz(0.123) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledRzz = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ rzz(0.123) q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string xxPlusYY = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; xx_plus_yy(0.123, 0.456) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledXxPlusYY = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ xx_plus_yy(0.123, 0.456) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledXxPlusYY = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ xx_plus_yy(0.123, 0.456) q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string xxMinusYY = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; xx_minus_yy(0.123, 0.456) q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string singleControlledXxMinusYY = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; ctrl @ xx_minus_yy(0.123, 0.456) q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string multipleControlledXxMinusYY = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[4] q; ctrl(2) @ xx_minus_yy(0.123, 0.456) q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string barrier = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[1] q; barrier q[0]; +bit[1] c = measure q; )qasm"; const std::string barrierTwoQubits = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[2] q; barrier q[0], q[1]; +bit[2] c = measure q; )qasm"; const std::string barrierMultipleQubits = R"qasm(OPENQASM 3.0; include "stdgates.inc"; qubit[3] q; barrier q[0], q[1], q[2]; +bit[3] c = measure q; )qasm"; const std::string ctrlTwo = R"qasm(OPENQASM 3.0; @@ -699,6 +807,7 @@ gate compound q0, q1 { rxx(0.123) q0, q1; } ctrl(2) @ compound q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string ctrlTwoMixed = R"qasm(OPENQASM 3.0; @@ -709,6 +818,7 @@ gate compound q0, q1 { rxx(0.123) q0, q1; } ctrl(2) @ compound q[0], q[1], q[2], q[3]; +bit[4] c = measure q; )qasm"; const std::string simpleIf = R"qasm(OPENQASM 3.0; @@ -719,6 +829,7 @@ bit c = measure q[0]; if (c) { x q[0]; } +bit[1] out = measure q; )qasm"; const std::string ifNot = R"qasm(OPENQASM 3.0; @@ -729,6 +840,7 @@ bit c = measure q[0]; if (!c) { x q[0]; } +output bit[1] out = measure q; )qasm"; const std::string ifTwoQubits = R"qasm(OPENQASM 3.0; @@ -740,6 +852,7 @@ if (c) { x q[0]; x q[1]; } +bit[2] out = measure q; )qasm"; const std::string ifEmptyThen = R"qasm(OPENQASM 3.0; @@ -751,6 +864,7 @@ if (c) { } else { x q[0]; } +output bit[1] out = measure q; )qasm"; const std::string ifElse = R"qasm(OPENQASM 3.0; @@ -763,6 +877,7 @@ if (c) { } else { z q[0]; } +bit[1] out = measure q; )qasm"; } // namespace mlir::qasm diff --git a/mlir/unittests/programs/qc_programs.cpp b/mlir/unittests/programs/qc_programs.cpp index a56ce38d61..c54cc9c2d9 100644 --- a/mlir/unittests/programs/qc_programs.cpp +++ b/mlir/unittests/programs/qc_programs.cpp @@ -12,22 +12,40 @@ #include "mlir/Dialect/QC/Builder/QCProgramBuilder.h" +#include +#include +#include +#include + #include namespace mlir::qc { -void emptyQC([[maybe_unused]] QCProgramBuilder& builder) {} +/** + * @brief Measures the given qubits and returns the measurement outcomes. + * @param b The `ProgramBuilder` used to perform the measurements. + * @param qubits The qubits to be measured. + * @return The result values. + */ +static SmallVector measureAndReturn(QCProgramBuilder& b, + ValueRange qubits) { + return llvm::to_vector( + llvm::map_range(qubits, [&](Value q) { return b.measure(q); })); +} -void allocQubit(QCProgramBuilder& b) { b.allocQubit(); } +Value emptyQC(QCProgramBuilder& b) { return b.intConstant(0); } -void allocQubitRegister(QCProgramBuilder& b) { b.allocQubitRegister(2); } +Value allocQubit(QCProgramBuilder& b) { + auto q = b.allocQubit(); + return b.measure(q); +} -void allocMultipleQubitRegisters(QCProgramBuilder& b) { - b.allocQubitRegister(2); - b.allocQubitRegister(3); +Value allocQubitNoMeasure(QCProgramBuilder& b) { + b.allocQubit(); + return b.intConstant(0); } -void allocMultipleQubitRegistersWithOps(QCProgramBuilder& b) { +SmallVector allocMultipleQubitRegistersWithOps(QCProgramBuilder& b) { auto q0 = b.allocQubitRegister(2); auto q1 = b.allocQubitRegister(3); b.h(q0[0]); @@ -35,47 +53,84 @@ void allocMultipleQubitRegistersWithOps(QCProgramBuilder& b) { b.h(q1[0]); b.h(q1[1]); b.h(q1[2]); + return measureAndReturn(b, {q0[0], q0[1], q1[0], q1[1], q1[2]}); +} + +Value alloc1QubitRegister(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(1); + return b.measure(q[0]); +} + +SmallVector allocQubitRegister(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + return measureAndReturn(b, q.qubits); +} + +SmallVector alloc3QubitRegister(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(3); + return measureAndReturn(b, q.qubits); +} + +SmallVector allocMultipleQubitRegisters(QCProgramBuilder& b) { + auto q0 = b.allocQubitRegister(2); + auto q1 = b.allocQubitRegister(3); + return measureAndReturn(b, {q0[0], q0[1], q1[0], q1[1], q1[2]}); +} + +SmallVector allocLargeRegister(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(100); + return measureAndReturn(b, {q[0], q[99]}); } -void allocLargeRegister(QCProgramBuilder& b) { b.allocQubitRegister(100); } +SmallVector staticQubits(QCProgramBuilder& b) { + auto q0 = b.staticQubit(0); + auto q1 = b.staticQubit(1); + return measureAndReturn(b, {q0, q1}); +} -void staticQubits(QCProgramBuilder& b) { +Value staticQubitsNoMeasure(QCProgramBuilder& b) { b.staticQubit(0); b.staticQubit(1); + return b.intConstant(0); } -void staticQubitsWithOps(QCProgramBuilder& b) { +SmallVector staticQubitsWithOps(QCProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); b.h(q0); b.h(q1); + return measureAndReturn(b, {q0, q1}); } -void staticQubitsWithParametricOps(QCProgramBuilder& b) { +SmallVector staticQubitsWithParametricOps(QCProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); b.rx(std::numbers::pi / 4., q0); b.p(std::numbers::pi / 2., q1); + return measureAndReturn(b, {q0, q1}); } -void staticQubitsWithTwoTargetOps(QCProgramBuilder& b) { +SmallVector staticQubitsWithTwoTargetOps(QCProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); b.rzz(0.123, q0, q1); + return measureAndReturn(b, {q0, q1}); } -void staticQubitsWithCtrl(QCProgramBuilder& b) { +SmallVector staticQubitsWithCtrl(QCProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); b.cx(q0, q1); + return measureAndReturn(b, {q0, q1}); } -void staticQubitsWithInv(QCProgramBuilder& b) { +Value staticQubitsWithInv(QCProgramBuilder& b) { auto q0 = b.staticQubit(0); b.inv(q0, [&](Value qubit) { b.t(qubit); }); + return b.measure(q0); } -void staticQubitsWithDuplicates(QCProgramBuilder& b) { +SmallVector staticQubitsWithDuplicates(QCProgramBuilder& b) { const auto q0a = b.staticQubit(0); const auto q1a = b.staticQubit(1); const auto q0b = b.staticQubit(0); @@ -86,9 +141,10 @@ void staticQubitsWithDuplicates(QCProgramBuilder& b) { b.rzz(0.123, q0b, q1b); b.cx(q0b, q1b); b.inv(q0a, [&](Value qubit) { b.t(qubit); }); + return measureAndReturn(b, {q0b, q1b}); } -void staticQubitsCanonical(QCProgramBuilder& b) { +SmallVector staticQubitsCanonical(QCProgramBuilder& b) { const auto q0 = b.staticQubit(0); const auto q1 = b.staticQubit(1); @@ -97,1280 +153,1541 @@ void staticQubitsCanonical(QCProgramBuilder& b) { b.rzz(0.123, q0, q1); b.cx(q0, q1); b.inv(q0, [&](Value qubit) { b.t(qubit); }); + return measureAndReturn(b, {q0, q1}); } -void allocDeallocPair(QCProgramBuilder& b) { +Value allocDeallocPair(QCProgramBuilder& b) { auto q = b.allocQubit(); b.dealloc(q); + return b.intConstant(0); } -void mixedStaticThenDynamicQubit(QCProgramBuilder& b) { - b.staticQubit(0); - b.allocQubit(); +SmallVector mixedStaticThenDynamicQubit(QCProgramBuilder& b) { + auto q0 = b.staticQubit(0); + auto q1 = b.allocQubit(); + return measureAndReturn(b, {q0, q1}); } -void mixedDynamicRegisterThenStaticQubit(QCProgramBuilder& b) { - b.allocQubitRegister(2); - b.staticQubit(0); +SmallVector mixedDynamicRegisterThenStaticQubit(QCProgramBuilder& b) { + auto q0 = b.allocQubitRegister(2); + auto q1 = b.staticQubit(0); + return measureAndReturn(b, {q0[0], q0[1], q1}); } -void singleMeasurementToSingleBit(QCProgramBuilder& b) { +Value singleMeasurementToSingleBit(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto& c = b.allocClassicalBitRegister(1); - b.measure(q[0], c[0]); + const auto outcome = b.measure(q[0], c[0]); + return outcome; } -void repeatedMeasurementToSameBit(QCProgramBuilder& b) { +Value repeatedMeasurementToSameBit(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto& c = b.allocClassicalBitRegister(1); b.measure(q[0], c[0]); b.measure(q[0], c[0]); - b.measure(q[0], c[0]); + auto c3 = b.measure(q[0], c[0]); + return c3; } -void repeatedMeasurementToDifferentBits(QCProgramBuilder& b) { +SmallVector repeatedMeasurementToDifferentBits(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto& c = b.allocClassicalBitRegister(3); - b.measure(q[0], c[0]); - b.measure(q[0], c[1]); - b.measure(q[0], c[2]); + auto c1 = b.measure(q[0], c[0]); + auto c2 = b.measure(q[0], c[1]); + auto c3 = b.measure(q[0], c[2]); + return {c1, c2, c3}; } -void multipleClassicalRegistersAndMeasurements(QCProgramBuilder& b) { +SmallVector +multipleClassicalRegistersAndMeasurements(QCProgramBuilder& 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]); + const auto b1 = b.measure(q[0], c0[0]); + const auto b2 = b.measure(q[1], c1[0]); + const auto b3 = b.measure(q[2], c1[1]); + return {b1, b2, b3}; } -void measurementWithoutRegisters(QCProgramBuilder& b) { +Value measurementWithoutRegisters(QCProgramBuilder& b) { auto q = b.allocQubit(); - b.measure(q); + auto c = b.measure(q); + return c; } -void resetQubitWithoutOp(QCProgramBuilder& b) { +Value resetQubitWithoutOp(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.reset(q[0]); + return b.measure(q[0]); } -void resetMultipleQubitsWithoutOp(QCProgramBuilder& b) { +SmallVector resetMultipleQubitsWithoutOp(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.reset(q[0]); b.reset(q[1]); + return measureAndReturn(b, q.qubits); } -void repeatedResetWithoutOp(QCProgramBuilder& b) { +Value repeatedResetWithoutOp(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.reset(q[0]); b.reset(q[0]); b.reset(q[0]); + return b.measure(q[0]); } -void resetQubitAfterSingleOp(QCProgramBuilder& b) { +Value resetQubitAfterSingleOp(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.h(q[0]); b.reset(q[0]); + return b.measure(q[0]); } -void resetMultipleQubitsAfterSingleOp(QCProgramBuilder& b) { +SmallVector resetMultipleQubitsAfterSingleOp(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.h(q[0]); b.reset(q[0]); b.h(q[1]); b.reset(q[1]); + return measureAndReturn(b, q.qubits); } -void repeatedResetAfterSingleOp(QCProgramBuilder& b) { +Value repeatedResetAfterSingleOp(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.h(q[0]); b.reset(q[0]); b.reset(q[0]); b.reset(q[0]); + return b.measure(q[0]); } -void globalPhase(QCProgramBuilder& b) { b.gphase(0.123); } +Value globalPhase(QCProgramBuilder& b) { + b.gphase(0.123); + return b.intConstant(0); +} + +Value globalPhaseAndMeasure(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(1); + b.gphase(0.123); + return b.measure(q[0]); +} -void singleControlledGlobalPhase(QCProgramBuilder& b) { +Value singleControlledGlobalPhase(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.cgphase(0.123, q[0]); + return b.measure(q[0]); } -void multipleControlledGlobalPhase(QCProgramBuilder& b) { +SmallVector multipleControlledGlobalPhase(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcgphase(0.123, {q[0], q[1], q[2]}); + return measureAndReturn(b, q.qubits); } -void nestedControlledGlobalPhase(QCProgramBuilder& b) { - auto q = b.allocQubitRegister(3); +SmallVector nestedControlledGlobalPhase(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(2); b.ctrl(q[0], q[1], [&](Value target) { b.cgphase(0.123, target); }); + return measureAndReturn(b, q.qubits); } -void trivialControlledGlobalPhase(QCProgramBuilder& b) { +Value trivialControlledGlobalPhase(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcgphase(0.123, {}); + return b.measure(q[0]); } -void inverseGlobalPhase(QCProgramBuilder& b) { +Value inverseGlobalPhase(QCProgramBuilder& b) { b.inv(ValueRange{}, [&](ValueRange /*qubits*/) { b.gphase(-0.123); }); + return b.intConstant(0); } -void inverseMultipleControlledGlobalPhase(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledGlobalPhase(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcgphase(-0.123, qubits); }); + return measureAndReturn(b, q.qubits); } -void identity(QCProgramBuilder& b) { +Value identity(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.id(q[0]); + return b.measure(q[0]); +} + +SmallVector singleControlledIdentity(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + b.cid(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledIdentity(QCProgramBuilder& b) { +SmallVector twoQubitsOneIdentity(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.cid(q[1], q[0]); + b.id(q[1]); + return measureAndReturn(b, q.qubits); +} + +SmallVector threeQubitsOneIdentity(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(3); + b.id(q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledIdentity(QCProgramBuilder& b) { +SmallVector multipleControlledIdentity(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.mcid({q[2], q[1]}, q[0]); + b.mcid({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); +} + +SmallVector twoQubitsOneBarrier(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + b.barrier(q[0]); + return measureAndReturn(b, q.qubits); } -void nestedControlledIdentity(QCProgramBuilder& b) { +SmallVector nestedControlledIdentity(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.ctrl(q[2], {q[0], q[1]}, - [&](ValueRange targets) { b.cid(targets[1], targets[0]); }); + b.ctrl(q[0], {q[1], q[2]}, + [&](ValueRange targets) { b.cid(targets[0], targets[1]); }); + return measureAndReturn(b, q.qubits); } -void trivialControlledIdentity(QCProgramBuilder& b) { +Value trivialControlledIdentity(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcid({}, q[0]); + return b.measure(q[0]); } -void inverseIdentity(QCProgramBuilder& b) { +Value inverseIdentity(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.id(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledIdentity(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledIdentity(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcid({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void x(QCProgramBuilder& b) { +Value x(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.x(q[0]); + return b.measure(q[0]); } -void singleControlledX(QCProgramBuilder& b) { +SmallVector singleControlledX(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cx(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledX(QCProgramBuilder& b) { +SmallVector multipleControlledX(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcx({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledX(QCProgramBuilder& b) { +SmallVector nestedControlledX(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.cx(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledX(QCProgramBuilder& b) { +Value trivialControlledX(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcx({}, q[0]); + return b.measure(q[0]); } -void repeatedControlledX(QCProgramBuilder& b) { - auto q = b.allocQubitRegister(64); - b.h(q[0]); - for (auto i = 1; i < 64; i++) { - b.cx(q[0], q[i]); +SmallVector repeatedControlledX(QCProgramBuilder& b) { + auto control = b.allocQubit(); + b.h(control); + SmallVector qubits; + for (auto i = 0; i < 50; i++) { + auto qubit = b.allocQubit(); + b.cx(control, qubit); + qubits.push_back(qubit); } + qubits.push_back(control); + return measureAndReturn(b, qubits); } -void inverseX(QCProgramBuilder& b) { +Value inverseX(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.x(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledX(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledX(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcx({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void y(QCProgramBuilder& b) { +Value y(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.y(q[0]); + return b.measure(q[0]); } -void singleControlledY(QCProgramBuilder& b) { +SmallVector singleControlledY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cy(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledY(QCProgramBuilder& b) { +SmallVector multipleControlledY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcy({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledY(QCProgramBuilder& b) { +SmallVector nestedControlledY(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.cy(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledY(QCProgramBuilder& b) { +Value trivialControlledY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcy({}, q[0]); + return b.measure(q[0]); } -void inverseY(QCProgramBuilder& b) { +Value inverseY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.y(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledY(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcy({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void z(QCProgramBuilder& b) { +Value z(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.z(q[0]); + return b.measure(q[0]); } -void singleControlledZ(QCProgramBuilder& b) { +SmallVector singleControlledZ(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cz(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledZ(QCProgramBuilder& b) { +SmallVector multipleControlledZ(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcz({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledZ(QCProgramBuilder& b) { +SmallVector nestedControlledZ(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.cz(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledZ(QCProgramBuilder& b) { +Value trivialControlledZ(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcz({}, q[0]); + return b.measure(q[0]); } -void inverseZ(QCProgramBuilder& b) { +Value inverseZ(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.z(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledZ(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledZ(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcz({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void h(QCProgramBuilder& b) { +Value h(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.h(q[0]); + return b.measure(q[0]); } -void singleControlledH(QCProgramBuilder& b) { +SmallVector singleControlledH(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ch(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledH(QCProgramBuilder& b) { +SmallVector multipleControlledH(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mch({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledH(QCProgramBuilder& b) { +SmallVector nestedControlledH(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.ch(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledH(QCProgramBuilder& b) { +Value trivialControlledH(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mch({}, q[0]); + return b.measure(q[0]); } -void inverseH(QCProgramBuilder& b) { +Value inverseH(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.h(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledH(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledH(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mch({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void hWithoutRegister(QCProgramBuilder& b) { +Value hWithoutRegister(QCProgramBuilder& b) { auto q = b.allocQubit(); b.h(q); + return b.measure(q); } -void s(QCProgramBuilder& b) { +Value s(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.s(q[0]); + return b.measure(q[0]); } -void singleControlledS(QCProgramBuilder& b) { +SmallVector singleControlledS(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cs(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledS(QCProgramBuilder& b) { +SmallVector multipleControlledS(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcs({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledS(QCProgramBuilder& b) { +SmallVector nestedControlledS(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.cs(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledS(QCProgramBuilder& b) { +Value trivialControlledS(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcs({}, q[0]); + return b.measure(q[0]); } -void inverseS(QCProgramBuilder& b) { +Value inverseS(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.s(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledS(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledS(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcs({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void sdg(QCProgramBuilder& b) { +Value sdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.sdg(q[0]); + return b.measure(q[0]); } -void singleControlledSdg(QCProgramBuilder& b) { +SmallVector singleControlledSdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.csdg(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledSdg(QCProgramBuilder& b) { +SmallVector multipleControlledSdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcsdg({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledSdg(QCProgramBuilder& b) { +SmallVector nestedControlledSdg(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.csdg(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledSdg(QCProgramBuilder& b) { +Value trivialControlledSdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcsdg({}, q[0]); + return b.measure(q[0]); } -void inverseSdg(QCProgramBuilder& b) { +Value inverseSdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.sdg(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledSdg(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledSdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcsdg({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void t_(QCProgramBuilder& b) { +Value t_(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.t(q[0]); + return b.measure(q[0]); } -void singleControlledT(QCProgramBuilder& b) { +SmallVector singleControlledT(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ct(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledT(QCProgramBuilder& b) { +SmallVector multipleControlledT(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mct({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledT(QCProgramBuilder& b) { +SmallVector nestedControlledT(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.ct(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledT(QCProgramBuilder& b) { +Value trivialControlledT(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mct({}, q[0]); + return b.measure(q[0]); } -void inverseT(QCProgramBuilder& b) { +Value inverseT(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.t(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledT(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledT(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mct({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void tdg(QCProgramBuilder& b) { +Value tdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.tdg(q[0]); + return b.measure(q[0]); } -void singleControlledTdg(QCProgramBuilder& b) { +SmallVector singleControlledTdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ctdg(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledTdg(QCProgramBuilder& b) { +SmallVector multipleControlledTdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mctdg({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledTdg(QCProgramBuilder& b) { +SmallVector nestedControlledTdg(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.ctdg(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledTdg(QCProgramBuilder& b) { +Value trivialControlledTdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mctdg({}, q[0]); + return b.measure(q[0]); } -void inverseTdg(QCProgramBuilder& b) { +Value inverseTdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.tdg(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledTdg(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledTdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mctdg({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void sx(QCProgramBuilder& b) { +Value sx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.sx(q[0]); + return b.measure(q[0]); } -void singleControlledSx(QCProgramBuilder& b) { +SmallVector singleControlledSx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.csx(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledSx(QCProgramBuilder& b) { +SmallVector multipleControlledSx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcsx({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledSx(QCProgramBuilder& b) { +SmallVector nestedControlledSx(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.csx(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledSx(QCProgramBuilder& b) { +Value trivialControlledSx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcsx({}, q[0]); + return b.measure(q[0]); } -void inverseSx(QCProgramBuilder& b) { +Value inverseSx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.sx(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledSx(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledSx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcsx({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void sxdg(QCProgramBuilder& b) { +Value sxdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.sxdg(q[0]); + return b.measure(q[0]); } -void singleControlledSxdg(QCProgramBuilder& b) { +SmallVector singleControlledSxdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.csxdg(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledSxdg(QCProgramBuilder& b) { +SmallVector multipleControlledSxdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcsxdg({q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledSxdg(QCProgramBuilder& b) { +SmallVector nestedControlledSxdg(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.csxdg(targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledSxdg(QCProgramBuilder& b) { +Value trivialControlledSxdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcsxdg({}, q[0]); + return b.measure(q[0]); } -void inverseSxdg(QCProgramBuilder& b) { +Value inverseSxdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.sxdg(qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledSxdg(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledSxdg(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcsxdg({qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void rx(QCProgramBuilder& b) { +Value rx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.rx(0.123, q[0]); + return b.measure(q[0]); } -void singleControlledRx(QCProgramBuilder& b) { +SmallVector singleControlledRx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.crx(0.123, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledRx(QCProgramBuilder& b) { +SmallVector multipleControlledRx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcrx(0.123, {q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledRx(QCProgramBuilder& b) { +SmallVector nestedControlledRx(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.crx(0.123, targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledRx(QCProgramBuilder& b) { +Value trivialControlledRx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcrx(0.123, {}, q[0]); + return b.measure(q[0]); } -void inverseRx(QCProgramBuilder& b) { +Value inverseRx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.rx(-0.123, qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledRx(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledRx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcrx(-0.123, {qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void ry(QCProgramBuilder& b) { +Value ry(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.ry(0.456, q[0]); + return b.measure(q[0]); } -void singleControlledRy(QCProgramBuilder& b) { +SmallVector singleControlledRy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cry(0.456, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledRy(QCProgramBuilder& b) { +SmallVector multipleControlledRy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcry(0.456, {q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledRy(QCProgramBuilder& b) { +SmallVector nestedControlledRy(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.cry(0.456, targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledRy(QCProgramBuilder& b) { +Value trivialControlledRy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcry(0.456, {}, q[0]); + return b.measure(q[0]); } -void inverseRy(QCProgramBuilder& b) { +Value inverseRy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.ry(-0.456, qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledRy(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledRy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcry(-0.456, {qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void rz(QCProgramBuilder& b) { +Value rz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.rz(0.789, q[0]); + return b.measure(q[0]); } -void singleControlledRz(QCProgramBuilder& b) { +SmallVector singleControlledRz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.crz(0.789, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledRz(QCProgramBuilder& b) { +SmallVector multipleControlledRz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcrz(0.789, {q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledRz(QCProgramBuilder& b) { +SmallVector nestedControlledRz(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.crz(0.789, targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledRz(QCProgramBuilder& b) { +Value trivialControlledRz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcrz(0.789, {}, q[0]); + return b.measure(q[0]); } -void inverseRz(QCProgramBuilder& b) { +Value inverseRz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.rz(-0.789, qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledRz(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledRz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcrz(-0.789, {qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void p(QCProgramBuilder& b) { +Value p(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.p(0.123, q[0]); + return b.measure(q[0]); } -void singleControlledP(QCProgramBuilder& b) { +SmallVector singleControlledP(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cp(0.123, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledP(QCProgramBuilder& b) { +SmallVector multipleControlledP(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcp(0.123, {q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledP(QCProgramBuilder& b) { +SmallVector nestedControlledP(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.cp(0.123, targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledP(QCProgramBuilder& b) { +Value trivialControlledP(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcp(0.123, {}, q[0]); + return b.measure(q[0]); } -void inverseP(QCProgramBuilder& b) { +Value inverseP(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.p(-0.123, qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledP(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledP(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcp(-0.123, {qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void r(QCProgramBuilder& b) { +Value r(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.r(0.123, 0.456, q[0]); + return b.measure(q[0]); } -void singleControlledR(QCProgramBuilder& b) { +SmallVector singleControlledR(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cr(0.123, 0.456, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledR(QCProgramBuilder& b) { +SmallVector multipleControlledR(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcr(0.123, 0.456, {q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledR(QCProgramBuilder& b) { +SmallVector nestedControlledR(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.cr(0.123, 0.456, targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledR(QCProgramBuilder& b) { +Value trivialControlledR(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcr(0.123, 0.456, {}, q[0]); + return b.measure(q[0]); } -void inverseR(QCProgramBuilder& b) { +Value inverseR(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.r(-0.123, 0.456, qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledR(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledR(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcr(-0.123, 0.456, {qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void u2(QCProgramBuilder& b) { +Value u2(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.u2(0.234, 0.567, q[0]); + return b.measure(q[0]); } -void singleControlledU2(QCProgramBuilder& b) { +SmallVector singleControlledU2(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cu2(0.234, 0.567, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledU2(QCProgramBuilder& b) { +SmallVector multipleControlledU2(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcu2(0.234, 0.567, {q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledU2(QCProgramBuilder& b) { +SmallVector nestedControlledU2(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.cu2(0.234, 0.567, targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledU2(QCProgramBuilder& b) { +Value trivialControlledU2(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcu2(0.234, 0.567, {}, q[0]); + return b.measure(q[0]); } -void inverseU2(QCProgramBuilder& b) { +Value inverseU2(QCProgramBuilder& b) { constexpr double pi = std::numbers::pi; auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.u2(-0.567 + pi, -0.234 - pi, qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledU2(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledU2(QCProgramBuilder& b) { constexpr double pi = std::numbers::pi; auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcu2(-0.567 + pi, -0.234 - pi, {qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void u(QCProgramBuilder& b) { +Value u(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.u(0.1, 0.2, 0.3, q[0]); + return b.measure(q[0]); } -void singleControlledU(QCProgramBuilder& b) { +SmallVector singleControlledU(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cu(0.1, 0.2, 0.3, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void multipleControlledU(QCProgramBuilder& b) { +SmallVector multipleControlledU(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcu(0.1, 0.2, 0.3, {q[0], q[1]}, q[2]); + return measureAndReturn(b, q.qubits); } -void nestedControlledU(QCProgramBuilder& b) { +SmallVector nestedControlledU(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); b.ctrl(reg[0], {reg[1], reg[2]}, [&](ValueRange targets) { b.cu(0.1, 0.2, 0.3, targets[0], targets[1]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledU(QCProgramBuilder& b) { +Value trivialControlledU(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.mcu(0.1, 0.2, 0.3, {}, q[0]); + return b.measure(q[0]); } -void inverseU(QCProgramBuilder& b) { +Value inverseU(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.u(-0.1, -0.3, -0.2, qubit); }); + return b.measure(q[0]); } -void inverseMultipleControlledU(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledU(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.mcu(-0.1, -0.3, -0.2, {qubits[0], qubits[1]}, qubits[2]); }); + return measureAndReturn(b, q.qubits); } -void swap(QCProgramBuilder& b) { +SmallVector swap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.swap(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledSwap(QCProgramBuilder& b) { +SmallVector singleControlledSwap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cswap(q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledSwap(QCProgramBuilder& b) { +SmallVector multipleControlledSwap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcswap({q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledSwap(QCProgramBuilder& b) { +SmallVector nestedControlledSwap(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.cswap(targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledSwap(QCProgramBuilder& b) { +SmallVector trivialControlledSwap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mcswap({}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseSwap(QCProgramBuilder& b) { +SmallVector inverseSwap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.swap(qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledSwap(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledSwap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { b.mcswap({qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void iswap(QCProgramBuilder& b) { +SmallVector iswap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.iswap(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledIswap(QCProgramBuilder& b) { +SmallVector singleControlledIswap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.ciswap(q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledIswap(QCProgramBuilder& b) { +SmallVector multipleControlledIswap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mciswap({q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledIswap(QCProgramBuilder& b) { +SmallVector nestedControlledIswap(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.ciswap(targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledIswap(QCProgramBuilder& b) { +SmallVector trivialControlledIswap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mciswap({}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseIswap(QCProgramBuilder& b) { +SmallVector inverseIswap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.iswap(qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledIswap(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledIswap(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { b.mciswap({qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void dcx(QCProgramBuilder& b) { +SmallVector dcx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.dcx(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledDcx(QCProgramBuilder& b) { +SmallVector singleControlledDcx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cdcx(q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledDcx(QCProgramBuilder& b) { +SmallVector multipleControlledDcx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcdcx({q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledDcx(QCProgramBuilder& b) { +SmallVector nestedControlledDcx(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.cdcx(targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledDcx(QCProgramBuilder& b) { +SmallVector trivialControlledDcx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mcdcx({}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseDcx(QCProgramBuilder& b) { +SmallVector inverseDcx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.dcx(qubits[1], qubits[0]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledDcx(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledDcx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[3], q[2]}, [&](ValueRange qubits) { b.mcdcx({qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void ecr(QCProgramBuilder& b) { +SmallVector ecr(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ecr(q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledEcr(QCProgramBuilder& b) { +SmallVector singleControlledEcr(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cecr(q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledEcr(QCProgramBuilder& b) { +SmallVector multipleControlledEcr(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcecr({q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledEcr(QCProgramBuilder& b) { +SmallVector nestedControlledEcr(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.cecr(targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledEcr(QCProgramBuilder& b) { +SmallVector trivialControlledEcr(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mcecr({}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseEcr(QCProgramBuilder& b) { +SmallVector inverseEcr(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.ecr(qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledEcr(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledEcr(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { b.mcecr({qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void rxx(QCProgramBuilder& b) { +SmallVector rxx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.rxx(0.123, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledRxx(QCProgramBuilder& b) { +SmallVector singleControlledRxx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.crxx(0.123, q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledRxx(QCProgramBuilder& b) { +SmallVector multipleControlledRxx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcrxx(0.123, {q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledRxx(QCProgramBuilder& b) { +SmallVector nestedControlledRxx(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.crxx(0.123, targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledRxx(QCProgramBuilder& b) { +SmallVector trivialControlledRxx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mcrxx(0.123, {}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseRxx(QCProgramBuilder& b) { +SmallVector inverseRxx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.rxx(-0.123, qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledRxx(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledRxx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { b.mcrxx(-0.123, {qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void tripleControlledRxx(QCProgramBuilder& b) { +SmallVector tripleControlledRxx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(5); b.mcrxx(0.123, {q[0], q[1], q[2]}, q[3], q[4]); + return measureAndReturn(b, q.qubits); } -void fourControlledRxx(QCProgramBuilder& b) { +SmallVector fourControlledRxx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(6); b.mcrxx(0.123, {q[0], q[1], q[2], q[3]}, q[4], q[5]); + return measureAndReturn(b, q.qubits); } -void ryy(QCProgramBuilder& b) { +SmallVector ryy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ryy(0.123, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledRyy(QCProgramBuilder& b) { +SmallVector singleControlledRyy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cryy(0.123, q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledRyy(QCProgramBuilder& b) { +SmallVector multipleControlledRyy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcryy(0.123, {q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledRyy(QCProgramBuilder& b) { +SmallVector nestedControlledRyy(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.cryy(0.123, targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledRyy(QCProgramBuilder& b) { +SmallVector trivialControlledRyy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mcryy(0.123, {}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseRyy(QCProgramBuilder& b) { +SmallVector inverseRyy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.ryy(-0.123, qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledRyy(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledRyy(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { b.mcryy(-0.123, {qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void rzx(QCProgramBuilder& b) { +SmallVector rzx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.rzx(0.123, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledRzx(QCProgramBuilder& b) { +SmallVector singleControlledRzx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.crzx(0.123, q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledRzx(QCProgramBuilder& b) { +SmallVector multipleControlledRzx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcrzx(0.123, {q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledRzx(QCProgramBuilder& b) { +SmallVector nestedControlledRzx(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.crzx(0.123, targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledRzx(QCProgramBuilder& b) { +SmallVector trivialControlledRzx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mcrzx(0.123, {}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseRzx(QCProgramBuilder& b) { +SmallVector inverseRzx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.rzx(-0.123, qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledRzx(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledRzx(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { b.mcrzx(-0.123, {qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void rzz(QCProgramBuilder& b) { +SmallVector rzz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.rzz(0.123, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledRzz(QCProgramBuilder& b) { +SmallVector singleControlledRzz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.crzz(0.123, q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledRzz(QCProgramBuilder& b) { +SmallVector multipleControlledRzz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcrzz(0.123, {q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledRzz(QCProgramBuilder& b) { +SmallVector nestedControlledRzz(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.crzz(0.123, targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledRzz(QCProgramBuilder& b) { +SmallVector trivialControlledRzz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mcrzz(0.123, {}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseRzz(QCProgramBuilder& b) { +SmallVector inverseRzz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.rzz(-0.123, qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledRzz(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledRzz(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { b.mcrzz(-0.123, {qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void xxPlusYY(QCProgramBuilder& b) { +SmallVector xxPlusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.xx_plus_yy(0.123, 0.456, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledXxPlusYY(QCProgramBuilder& b) { +SmallVector singleControlledXxPlusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cxx_plus_yy(0.123, 0.456, q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledXxPlusYY(QCProgramBuilder& b) { +SmallVector multipleControlledXxPlusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcxx_plus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledXxPlusYY(QCProgramBuilder& b) { +SmallVector nestedControlledXxPlusYY(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.cxx_plus_yy(0.123, 0.456, targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledXxPlusYY(QCProgramBuilder& b) { +SmallVector trivialControlledXxPlusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mcxx_plus_yy(0.123, 0.456, {}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseXxPlusYY(QCProgramBuilder& b) { +SmallVector inverseXxPlusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.xx_plus_yy(-0.123, 0.456, qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledXxPlusYY(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledXxPlusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { b.mcxx_plus_yy(-0.123, 0.456, {qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void xxMinusYY(QCProgramBuilder& b) { +SmallVector xxMinusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.xx_minus_yy(0.123, 0.456, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void singleControlledXxMinusYY(QCProgramBuilder& b) { +SmallVector singleControlledXxMinusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cxx_minus_yy(0.123, 0.456, q[0], q[1], q[2]); + return measureAndReturn(b, q.qubits); } -void multipleControlledXxMinusYY(QCProgramBuilder& b) { +SmallVector multipleControlledXxMinusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcxx_minus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + return measureAndReturn(b, q.qubits); } -void nestedControlledXxMinusYY(QCProgramBuilder& b) { +SmallVector nestedControlledXxMinusYY(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.ctrl(reg[0], {reg[1], reg[2], reg[3]}, [&](ValueRange targets) { b.cxx_minus_yy(0.123, 0.456, targets[0], targets[1], targets[2]); }); + return measureAndReturn(b, reg.qubits); } -void trivialControlledXxMinusYY(QCProgramBuilder& b) { +SmallVector trivialControlledXxMinusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.mcxx_minus_yy(0.123, 0.456, {}, q[0], q[1]); + return measureAndReturn(b, q.qubits); } -void inverseXxMinusYY(QCProgramBuilder& b) { +SmallVector inverseXxMinusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.xx_minus_yy(-0.123, 0.456, qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledXxMinusYY(QCProgramBuilder& b) { +SmallVector inverseMultipleControlledXxMinusYY(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.inv({q[0], q[1], q[2], q[3]}, [&](ValueRange qubits) { b.mcxx_minus_yy(-0.123, 0.456, {qubits[0], qubits[1]}, qubits[2], qubits[3]); }); + return measureAndReturn(b, q.qubits); } -void barrier(QCProgramBuilder& b) { +Value barrier(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.barrier(q[0]); + return b.measure(q[0]); } -void barrierTwoQubits(QCProgramBuilder& b) { +SmallVector barrierTwoQubits(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.barrier({q[0], q[1]}); + return measureAndReturn(b, q.qubits); } -void barrierMultipleQubits(QCProgramBuilder& b) { +SmallVector barrierMultipleQubits(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.barrier({q[0], q[1], q[2]}); + return measureAndReturn(b, q.qubits); } -void singleControlledBarrier(QCProgramBuilder& b) { +SmallVector singleControlledBarrier(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ctrl(q[1], q[0], [&](Value target) { b.barrier({target}); }); + return measureAndReturn(b, q.qubits); } -void inverseBarrier(QCProgramBuilder& b) { +Value inverseBarrier(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.inv(q[0], [&](Value qubit) { b.barrier(qubit); }); + return b.measure(q[0]); } -void trivialCtrl(QCProgramBuilder& b) { +SmallVector trivialCtrl(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ctrl({}, {q[0], q[1]}, [&](ValueRange targets) { b.rxx(0.123, targets[0], targets[1]); }); + return measureAndReturn(b, q.qubits); } -void emptyCtrl(QCProgramBuilder& b) { +SmallVector emptyCtrl(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.rxx(0.123, q[0], q[1]); b.ctrl(q[0], q[1], [&](Value /*target*/) {}); + return measureAndReturn(b, q.qubits); } -void nestedCtrl(QCProgramBuilder& b) { +SmallVector nestedCtrl(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.ctrl(q[0], {q[1], q[2], q[3]}, [&](ValueRange targets) { b.ctrl(targets[0], {targets[1], targets[2]}, [&](ValueRange innerTargets) { b.rxx(0.123, innerTargets[0], innerTargets[1]); }); }); + return measureAndReturn(b, q.qubits); } -void tripleNestedCtrl(QCProgramBuilder& b) { +SmallVector tripleNestedCtrl(QCProgramBuilder& b) { auto q = b.allocQubitRegister(5); b.ctrl(q[0], {q[1], q[2], q[3], q[4]}, [&](ValueRange targets) { b.ctrl(targets[0], {targets[1], targets[2], targets[3]}, @@ -1381,9 +1698,10 @@ void tripleNestedCtrl(QCProgramBuilder& b) { }); }); }); + return measureAndReturn(b, q.qubits); } -void doubleNestedCtrlTwoQubits(QCProgramBuilder& b) { +SmallVector doubleNestedCtrlTwoQubits(QCProgramBuilder& b) { auto q = b.allocQubitRegister(6); b.ctrl({q[0], q[1]}, {q[2], q[3], q[4], q[5]}, [&](ValueRange targets) { b.ctrl({targets[0], targets[1]}, {targets[2], targets[3]}, @@ -1391,9 +1709,10 @@ void doubleNestedCtrlTwoQubits(QCProgramBuilder& b) { b.rxx(0.123, innerTargets[0], innerTargets[1]); }); }); + return measureAndReturn(b, q.qubits); } -void ctrlInvSandwich(QCProgramBuilder& b) { +SmallVector ctrlInvSandwich(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.ctrl(q[0], {q[1], q[2], q[3]}, [&](ValueRange targets) { b.inv(targets, [&](ValueRange qubits) { @@ -1402,25 +1721,28 @@ void ctrlInvSandwich(QCProgramBuilder& b) { }); }); }); + return measureAndReturn(b, q.qubits); } -void ctrlTwo(QCProgramBuilder& b) { +SmallVector ctrlTwo(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.ctrl({q[0], q[1]}, {q[2], q[3]}, [&](ValueRange targets) { b.x(targets[0]); b.rxx(0.123, targets[0], targets[1]); }); + return measureAndReturn(b, q.qubits); } -void ctrlTwoMixed(QCProgramBuilder& b) { +SmallVector ctrlTwoMixed(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.ctrl({q[0], q[1]}, {q[2], q[3]}, [&](ValueRange targets) { b.cx(targets[0], targets[1]); b.rxx(0.123, targets[0], targets[1]); }); + return measureAndReturn(b, q.qubits); } -void nestedCtrlTwo(QCProgramBuilder& b) { +SmallVector nestedCtrlTwo(QCProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.ctrl(q[0], {q[1], q[2], q[3]}, [&](ValueRange targets) { b.ctrl(targets[0], {targets[1], targets[2]}, [&](ValueRange innerTargets) { @@ -1428,9 +1750,10 @@ void nestedCtrlTwo(QCProgramBuilder& b) { b.rxx(0.123, innerTargets[0], innerTargets[1]); }); }); + return measureAndReturn(b, q.qubits); } -void ctrlInvTwo(QCProgramBuilder& b) { +SmallVector ctrlInvTwo(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.ctrl(q[0], {q[1], q[2]}, [&](ValueRange targets) { b.inv(targets, [&](ValueRange qubits) { @@ -1438,24 +1761,27 @@ void ctrlInvTwo(QCProgramBuilder& b) { b.rxx(0.123, qubits[0], qubits[1]); }); }); + return measureAndReturn(b, q.qubits); } -void emptyInv(QCProgramBuilder& b) { +SmallVector emptyInv(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.rxx(0.123, q[0], q[1]); b.inv({q[0], q[1]}, [&](ValueRange /*targets*/) {}); + return measureAndReturn(b, q.qubits); } -void nestedInv(QCProgramBuilder& b) { +SmallVector nestedInv(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.inv(qubits, [&](ValueRange innerQubits) { b.rxx(0.123, innerQubits[0], innerQubits[1]); }); }); + return measureAndReturn(b, q.qubits); } -void tripleNestedInv(QCProgramBuilder& b) { +SmallVector tripleNestedInv(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.inv(qubits, [&](ValueRange innerQubits) { @@ -1464,9 +1790,10 @@ void tripleNestedInv(QCProgramBuilder& b) { }); }); }); + return measureAndReturn(b, q.qubits); } -void invCtrlSandwich(QCProgramBuilder& b) { +SmallVector invCtrlSandwich(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.ctrl(qubits[0], {qubits[1], qubits[2]}, [&](ValueRange targets) { @@ -1475,17 +1802,19 @@ void invCtrlSandwich(QCProgramBuilder& b) { }); }); }); + return measureAndReturn(b, q.qubits); } -void invTwo(QCProgramBuilder& b) { +SmallVector invTwo(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.inv({q[0], q[1]}, [&](ValueRange qubits) { b.x(qubits[0]); b.rxx(0.123, qubits[0], qubits[1]); }); + return measureAndReturn(b, q.qubits); } -void invCtrlTwo(QCProgramBuilder& b) { +SmallVector invCtrlTwo(QCProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.inv({q[0], q[1], q[2]}, [&](ValueRange qubits) { b.ctrl(qubits[0], {qubits[1], qubits[2]}, [&](ValueRange targets) { @@ -1493,16 +1822,28 @@ void invCtrlTwo(QCProgramBuilder& b) { b.rxx(0.123, targets[0], targets[1]); }); }); + return measureAndReturn(b, q.qubits); } -void simpleIf(QCProgramBuilder& b) { +SmallVector simpleIf(QCProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.h(q[0]); auto cond = b.measure(q[0]); b.scfIf(cond, [&] { b.x(q[0]); }); + auto res = b.measure(q[0]); + return {cond, res}; } -void ifTwoQubits(QCProgramBuilder& b) { +SmallVector ifElse(QCProgramBuilder& b) { + auto q = b.allocQubitRegister(1); + b.h(q[0]); + auto cond = b.measure(q[0]); + b.scfIf(cond, [&] { b.x(q[0]); }, [&] { b.z(q[0]); }); + auto bit = b.measure(q[0]); + return {cond, bit}; +} + +SmallVector ifTwoQubits(QCProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.h(q[0]); auto cond = b.measure(q[0]); @@ -1510,16 +1851,12 @@ void ifTwoQubits(QCProgramBuilder& b) { b.x(q[0]); b.x(q[1]); }); + auto c0 = b.measure(q[0]); + auto c1 = b.measure(q[1]); + return {cond, c0, c1}; } -void ifElse(QCProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - b.h(q[0]); - auto cond = b.measure(q[0]); - b.scfIf(cond, [&] { b.x(q[0]); }, [&] { b.z(q[0]); }); -} - -void nestedIfOpForLoop(QCProgramBuilder& b) { +Value nestedIfOpForLoop(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); auto q0 = b.allocQubit(); b.h(q0); @@ -1532,9 +1869,10 @@ void nestedIfOpForLoop(QCProgramBuilder& b) { b.h(q1); }); }); + return b.measure(q0); } -void simpleWhileReset(QCProgramBuilder& b) { +Value simpleWhileReset(QCProgramBuilder& b) { auto q = b.allocQubit(); b.h(q); b.scfWhile( @@ -1543,9 +1881,10 @@ void simpleWhileReset(QCProgramBuilder& b) { b.scfCondition(measureResult); }, [&] { b.h(q); }); + return b.measure(q); } -void simpleDoWhileReset(QCProgramBuilder& b) { +Value simpleDoWhileReset(QCProgramBuilder& b) { auto q = b.allocQubit(); b.scfWhile( [&] { @@ -1554,17 +1893,19 @@ void simpleDoWhileReset(QCProgramBuilder& b) { b.scfCondition(measureResult); }, [&] {}); + return b.measure(q); } -void simpleForLoop(QCProgramBuilder& b) { +SmallVector simpleForLoop(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(2); b.scfFor(0, 2, 1, [&](Value iv) { auto q = b.memrefLoad(reg.value, iv); b.h(q); }); + return measureAndReturn(b, reg.qubits); }; -void nestedForLoopIfOp(QCProgramBuilder& b) { +Value nestedForLoopIfOp(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(2); auto qCond = b.allocQubit(); b.scfFor(0, 2, 1, [&](Value iv) { @@ -1575,9 +1916,10 @@ void nestedForLoopIfOp(QCProgramBuilder& b) { b.h(q); }); }); + return b.measure(qCond); } -void nestedForLoopWhileOp(QCProgramBuilder& b) { +SmallVector nestedForLoopWhileOp(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(2); b.scfFor(0, 2, 1, [&](Value iv) { auto q = b.memrefLoad(reg.value, iv); @@ -1592,9 +1934,10 @@ void nestedForLoopWhileOp(QCProgramBuilder& b) { }, [&] { b.h(q); }); }); + return measureAndReturn(b, reg.qubits); } -void nestedForLoopCtrlOpWithSeparateQubit(QCProgramBuilder& b) { +Value nestedForLoopCtrlOpWithSeparateQubit(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(3); auto control = b.allocQubit(); b.h(control); @@ -1603,9 +1946,10 @@ void nestedForLoopCtrlOpWithSeparateQubit(QCProgramBuilder& b) { b.h(q0); b.cx(control, q0); }); + return b.measure(control); } -void nestedForLoopCtrlOpWithExtractedQubit(QCProgramBuilder& b) { +Value nestedForLoopCtrlOpWithExtractedQubit(QCProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.h(reg[0]); b.scfFor(1, 4, 1, [&](Value iv) { @@ -1613,6 +1957,7 @@ void nestedForLoopCtrlOpWithExtractedQubit(QCProgramBuilder& b) { b.h(q0); b.cx(reg[0], q0); }); + return b.measure(reg[0]); } } // namespace mlir::qc diff --git a/mlir/unittests/programs/qc_programs.h b/mlir/unittests/programs/qc_programs.h index 25d76718cc..4849d861c7 100644 --- a/mlir/unittests/programs/qc_programs.h +++ b/mlir/unittests/programs/qc_programs.h @@ -10,906 +10,934 @@ #pragma once +#include +#include + namespace mlir::qc { class QCProgramBuilder; /// Creates an empty QC Program. -void emptyQC(QCProgramBuilder& builder); +Value emptyQC(QCProgramBuilder& b); // --- Qubit Management ----------------------------------------------------- // /// Allocates a single qubit. -void allocQubit(QCProgramBuilder& b); +Value allocQubit(QCProgramBuilder& b); + +/// Allocates a single qubit without measuring it. +Value allocQubitNoMeasure(QCProgramBuilder& b); + +/// Allocates a qubit register of size `1`. +Value alloc1QubitRegister(QCProgramBuilder& b); /// Allocates a qubit register of size `2`. -void allocQubitRegister(QCProgramBuilder& b); +SmallVector allocQubitRegister(QCProgramBuilder& b); + +/// Allocates a qubit register of size `3`. +SmallVector alloc3QubitRegister(QCProgramBuilder& b); /// Allocates two qubit registers of size `2` and `3`. -void allocMultipleQubitRegisters(QCProgramBuilder& b); +SmallVector allocMultipleQubitRegisters(QCProgramBuilder& b); /// Allocates two qubit registers of size `2` and `3` and applies operations. -void allocMultipleQubitRegistersWithOps(QCProgramBuilder& b); +SmallVector allocMultipleQubitRegistersWithOps(QCProgramBuilder& b); /// Allocates a large qubit register. -void allocLargeRegister(QCProgramBuilder& b); +SmallVector allocLargeRegister(QCProgramBuilder& b); /// Allocates two inline qubits. -void staticQubits(QCProgramBuilder& b); +SmallVector staticQubits(QCProgramBuilder& b); + +/// Allocates two inline qubits without measuring them. +Value staticQubitsNoMeasure(QCProgramBuilder& b); /// Allocates two static qubits and applies operations. -void staticQubitsWithOps(QCProgramBuilder& b); +SmallVector staticQubitsWithOps(QCProgramBuilder& b); /// Allocates two static qubits and applies parametric gates. -void staticQubitsWithParametricOps(QCProgramBuilder& b); +SmallVector staticQubitsWithParametricOps(QCProgramBuilder& b); /// Allocates two static qubits and applies a two-target gate. -void staticQubitsWithTwoTargetOps(QCProgramBuilder& b); +SmallVector staticQubitsWithTwoTargetOps(QCProgramBuilder& b); /// Allocates two static qubits and applies a controlled gate. -void staticQubitsWithCtrl(QCProgramBuilder& b); +SmallVector staticQubitsWithCtrl(QCProgramBuilder& b); /// Allocates a static qubit and applies an inverse modifier. -void staticQubitsWithInv(QCProgramBuilder& b); +Value staticQubitsWithInv(QCProgramBuilder& b); /// Allocates duplicate static qubits and applies operations on both. -void staticQubitsWithDuplicates(QCProgramBuilder& b); +SmallVector staticQubitsWithDuplicates(QCProgramBuilder& b); /// Same as `staticQubitsWithDuplicates`, but with canonical static qubit /// retrievals. -void staticQubitsCanonical(QCProgramBuilder& b); +SmallVector staticQubitsCanonical(QCProgramBuilder& b); /// Allocates and explicitly deallocates a single qubit. -void allocDeallocPair(QCProgramBuilder& b); +Value allocDeallocPair(QCProgramBuilder& b); // --- Invalid / mixed addressing (unit tests) -------------------------------- /// @pre `builder.initialize()`. Fatal mixed addressing: static then dynamic /// alloc. -void mixedStaticThenDynamicQubit(QCProgramBuilder& b); +SmallVector mixedStaticThenDynamicQubit(QCProgramBuilder& b); /// @pre `builder.initialize()`. Fatal mixed addressing: dynamic register then /// static. -void mixedDynamicRegisterThenStaticQubit(QCProgramBuilder& b); +SmallVector mixedDynamicRegisterThenStaticQubit(QCProgramBuilder& b); // --- MeasureOp ------------------------------------------------------------ // /// Measures a single qubit into a single classical bit. -void singleMeasurementToSingleBit(QCProgramBuilder& b); +Value singleMeasurementToSingleBit(QCProgramBuilder& b); /// Repeatedly measures a single qubit into the same classical bit. -void repeatedMeasurementToSameBit(QCProgramBuilder& b); +Value repeatedMeasurementToSameBit(QCProgramBuilder& b); /// Repeatedly measures a single qubit into different classical bits. -void repeatedMeasurementToDifferentBits(QCProgramBuilder& b); +SmallVector repeatedMeasurementToDifferentBits(QCProgramBuilder& b); /// Measures multiple qubits into multiple classical bits. -void multipleClassicalRegistersAndMeasurements(QCProgramBuilder& b); +SmallVector +multipleClassicalRegistersAndMeasurements(QCProgramBuilder& b); /// Measures a single qubit into a single classical bit, without explicitly /// allocating a quantum or classical register. -void measurementWithoutRegisters(QCProgramBuilder& b); +Value measurementWithoutRegisters(QCProgramBuilder& b); // --- ResetOp -------------------------------------------------------------- // /// Resets a single qubit without any operations being applied. -void resetQubitWithoutOp(QCProgramBuilder& b); +Value resetQubitWithoutOp(QCProgramBuilder& b); /// Resets multiple qubits without any operations being applied. -void resetMultipleQubitsWithoutOp(QCProgramBuilder& b); +SmallVector resetMultipleQubitsWithoutOp(QCProgramBuilder& b); /// Repeatedly resets a single qubit without any operations being applied. -void repeatedResetWithoutOp(QCProgramBuilder& b); +Value repeatedResetWithoutOp(QCProgramBuilder& b); /// Resets a single qubit after a single operation. -void resetQubitAfterSingleOp(QCProgramBuilder& b); +Value resetQubitAfterSingleOp(QCProgramBuilder& b); /// Resets multiple qubits after a single operation. -void resetMultipleQubitsAfterSingleOp(QCProgramBuilder& b); +SmallVector resetMultipleQubitsAfterSingleOp(QCProgramBuilder& b); /// Repeatedly resets a single qubit after a single operation. -void repeatedResetAfterSingleOp(QCProgramBuilder& b); +Value repeatedResetAfterSingleOp(QCProgramBuilder& b); // --- GPhaseOp ------------------------------------------------------------- // /// Creates a circuit with just a global phase. -void globalPhase(QCProgramBuilder& b); +Value globalPhase(QCProgramBuilder& b); + +/// Creates a circuit with just a global phase and a single measured qubit. +Value globalPhaseAndMeasure(QCProgramBuilder& b); /// Creates a controlled global phase gate with a single control qubit. -void singleControlledGlobalPhase(QCProgramBuilder& b); +Value singleControlledGlobalPhase(QCProgramBuilder& b); /// Creates a multi-controlled global phase gate with multiple control qubits. -void multipleControlledGlobalPhase(QCProgramBuilder& b); +SmallVector multipleControlledGlobalPhase(QCProgramBuilder& b); /// Creates a circuit with a nested controlled global phase gate. -void nestedControlledGlobalPhase(QCProgramBuilder& b); +SmallVector nestedControlledGlobalPhase(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled global phase gate. -void trivialControlledGlobalPhase(QCProgramBuilder& b); +Value trivialControlledGlobalPhase(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a global phase gate. -void inverseGlobalPhase(QCProgramBuilder& b); +Value inverseGlobalPhase(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled global /// phase gate. -void inverseMultipleControlledGlobalPhase(QCProgramBuilder& b); +SmallVector inverseMultipleControlledGlobalPhase(QCProgramBuilder& b); // --- IdOp ----------------------------------------------------------------- // /// Creates a circuit with just an identity gate. -void identity(QCProgramBuilder& b); +Value identity(QCProgramBuilder& b); /// Creates a controlled identity gate with a single control qubit. -void singleControlledIdentity(QCProgramBuilder& b); +SmallVector singleControlledIdentity(QCProgramBuilder& b); + +/// Creates an identity gate on a single qubit in a two-qubit register. +SmallVector twoQubitsOneIdentity(QCProgramBuilder& b); + +/// Creates an identity gate on a single qubit in a three-qubit register. +SmallVector threeQubitsOneIdentity(QCProgramBuilder& b); /// Creates a multi-controlled identity gate with multiple control qubits. -void multipleControlledIdentity(QCProgramBuilder& b); +SmallVector multipleControlledIdentity(QCProgramBuilder& b); + +/// Creates an barrier gate on a single qubit in a two-qubit register. +SmallVector twoQubitsOneBarrier(QCProgramBuilder& b); /// Creates a circuit with a nested controlled identity gate. -void nestedControlledIdentity(QCProgramBuilder& b); +SmallVector nestedControlledIdentity(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled identity gate. -void trivialControlledIdentity(QCProgramBuilder& b); +Value trivialControlledIdentity(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an identity gate. -void inverseIdentity(QCProgramBuilder& b); +Value inverseIdentity(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled identity /// gate. -void inverseMultipleControlledIdentity(QCProgramBuilder& b); +SmallVector inverseMultipleControlledIdentity(QCProgramBuilder& b); // --- XOp ------------------------------------------------------------------ // /// Creates a circuit with just an X gate. -void x(QCProgramBuilder& b); +Value x(QCProgramBuilder& b); /// Creates a circuit with a single controlled X gate. -void singleControlledX(QCProgramBuilder& b); +SmallVector singleControlledX(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled X gate. -void multipleControlledX(QCProgramBuilder& b); +SmallVector multipleControlledX(QCProgramBuilder& b); /// Creates a circuit with a nested controlled X gate. -void nestedControlledX(QCProgramBuilder& b); +SmallVector nestedControlledX(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled X gate. -void trivialControlledX(QCProgramBuilder& b); +Value trivialControlledX(QCProgramBuilder& b); /// Creates a circuit with repeated controlled X gates. -void repeatedControlledX(QCProgramBuilder& b); +SmallVector repeatedControlledX(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an X gate. -void inverseX(QCProgramBuilder& b); +Value inverseX(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled X gate. -void inverseMultipleControlledX(QCProgramBuilder& b); +SmallVector inverseMultipleControlledX(QCProgramBuilder& b); // --- YOp ------------------------------------------------------------------ // /// Creates a circuit with just a Y gate. -void y(QCProgramBuilder& b); +Value y(QCProgramBuilder& b); /// Creates a circuit with a single controlled Y gate. -void singleControlledY(QCProgramBuilder& b); +SmallVector singleControlledY(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled Y gate. -void multipleControlledY(QCProgramBuilder& b); +SmallVector multipleControlledY(QCProgramBuilder& b); /// Creates a circuit with a nested controlled Y gate. -void nestedControlledY(QCProgramBuilder& b); +SmallVector nestedControlledY(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled Y gate. -void trivialControlledY(QCProgramBuilder& b); +Value trivialControlledY(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a Y gate. -void inverseY(QCProgramBuilder& b); +Value inverseY(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Y gate. -void inverseMultipleControlledY(QCProgramBuilder& b); +SmallVector inverseMultipleControlledY(QCProgramBuilder& b); // --- ZOp ------------------------------------------------------------------ // /// Creates a circuit with just a Z gate. -void z(QCProgramBuilder& b); +Value z(QCProgramBuilder& b); /// Creates a circuit with a single controlled Z gate. -void singleControlledZ(QCProgramBuilder& b); +SmallVector singleControlledZ(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled Z gate. -void multipleControlledZ(QCProgramBuilder& b); +SmallVector multipleControlledZ(QCProgramBuilder& b); /// Creates a circuit with a nested controlled Z gate. -void nestedControlledZ(QCProgramBuilder& b); +SmallVector nestedControlledZ(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled Z gate. -void trivialControlledZ(QCProgramBuilder& b); +Value trivialControlledZ(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a Z gate. -void inverseZ(QCProgramBuilder& b); +Value inverseZ(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Z gate. -void inverseMultipleControlledZ(QCProgramBuilder& b); +SmallVector inverseMultipleControlledZ(QCProgramBuilder& b); // --- HOp ------------------------------------------------------------------ // /// Creates a circuit with just an H gate. -void h(QCProgramBuilder& b); +Value h(QCProgramBuilder& b); /// Creates a circuit with a single controlled H gate. -void singleControlledH(QCProgramBuilder& b); +SmallVector singleControlledH(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled H gate. -void multipleControlledH(QCProgramBuilder& b); +SmallVector multipleControlledH(QCProgramBuilder& b); /// Creates a circuit with a nested controlled H gate. -void nestedControlledH(QCProgramBuilder& b); +SmallVector nestedControlledH(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled H gate. -void trivialControlledH(QCProgramBuilder& b); +Value trivialControlledH(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an H gate. -void inverseH(QCProgramBuilder& b); +Value inverseH(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled H gate. -void inverseMultipleControlledH(QCProgramBuilder& b); +SmallVector inverseMultipleControlledH(QCProgramBuilder& b); /// Creates a circuit with just an H gate and no qubit register. -void hWithoutRegister(QCProgramBuilder& b); +Value hWithoutRegister(QCProgramBuilder& b); // --- SOp ------------------------------------------------------------------ // /// Creates a circuit with just an S gate. -void s(QCProgramBuilder& b); +Value s(QCProgramBuilder& b); /// Creates a circuit with a single controlled S gate. -void singleControlledS(QCProgramBuilder& b); +SmallVector singleControlledS(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled S gate. -void multipleControlledS(QCProgramBuilder& b); +SmallVector multipleControlledS(QCProgramBuilder& b); /// Creates a circuit with a nested controlled S gate. -void nestedControlledS(QCProgramBuilder& b); +SmallVector nestedControlledS(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled S gate. -void trivialControlledS(QCProgramBuilder& b); +Value trivialControlledS(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an S gate. -void inverseS(QCProgramBuilder& b); +Value inverseS(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled S gate. -void inverseMultipleControlledS(QCProgramBuilder& b); +SmallVector inverseMultipleControlledS(QCProgramBuilder& b); // --- SdgOp ---------------------------------------------------------------- // /// Creates a circuit with just an Sdg gate. -void sdg(QCProgramBuilder& b); +Value sdg(QCProgramBuilder& b); /// Creates a circuit with a single controlled Sdg gate. -void singleControlledSdg(QCProgramBuilder& b); +SmallVector singleControlledSdg(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled Sdg gate. -void multipleControlledSdg(QCProgramBuilder& b); +SmallVector multipleControlledSdg(QCProgramBuilder& b); /// Creates a circuit with a nested controlled Sdg gate. -void nestedControlledSdg(QCProgramBuilder& b); +SmallVector nestedControlledSdg(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled Sdg gate. -void trivialControlledSdg(QCProgramBuilder& b); +Value trivialControlledSdg(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an Sdg gate. -void inverseSdg(QCProgramBuilder& b); +Value inverseSdg(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Sdg gate. -void inverseMultipleControlledSdg(QCProgramBuilder& b); +SmallVector inverseMultipleControlledSdg(QCProgramBuilder& b); // --- TOp ------------------------------------------------------------------ // /// Creates a circuit with just a T gate. -void t_(QCProgramBuilder& b); // NOLINT(*-identifier-naming) +Value t_(QCProgramBuilder& b); // NOLINT(*-identifier-naming) /// Creates a circuit with a single controlled T gate. -void singleControlledT(QCProgramBuilder& b); +SmallVector singleControlledT(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled T gate. -void multipleControlledT(QCProgramBuilder& b); +SmallVector multipleControlledT(QCProgramBuilder& b); /// Creates a circuit with a nested controlled T gate. -void nestedControlledT(QCProgramBuilder& b); +SmallVector nestedControlledT(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled T gate. -void trivialControlledT(QCProgramBuilder& b); +Value trivialControlledT(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a T gate. -void inverseT(QCProgramBuilder& b); +Value inverseT(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled T gate. -void inverseMultipleControlledT(QCProgramBuilder& b); +SmallVector inverseMultipleControlledT(QCProgramBuilder& b); // --- TdgOp ---------------------------------------------------------------- // /// Creates a circuit with just a Tdg gate. -void tdg(QCProgramBuilder& b); +Value tdg(QCProgramBuilder& b); /// Creates a circuit with a single controlled Tdg gate. -void singleControlledTdg(QCProgramBuilder& b); +SmallVector singleControlledTdg(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled Tdg gate. -void multipleControlledTdg(QCProgramBuilder& b); +SmallVector multipleControlledTdg(QCProgramBuilder& b); /// Creates a circuit with a nested controlled Tdg gate. -void nestedControlledTdg(QCProgramBuilder& b); +SmallVector nestedControlledTdg(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled Tdg gate. -void trivialControlledTdg(QCProgramBuilder& b); +Value trivialControlledTdg(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a Tdg gate. -void inverseTdg(QCProgramBuilder& b); +Value inverseTdg(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Tdg gate. -void inverseMultipleControlledTdg(QCProgramBuilder& b); +SmallVector inverseMultipleControlledTdg(QCProgramBuilder& b); // --- SXOp ----------------------------------------------------------------- // /// Creates a circuit with just an SX gate. -void sx(QCProgramBuilder& b); +Value sx(QCProgramBuilder& b); /// Creates a circuit with a single controlled SX gate. -void singleControlledSx(QCProgramBuilder& b); +SmallVector singleControlledSx(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled SX gate. -void multipleControlledSx(QCProgramBuilder& b); +SmallVector multipleControlledSx(QCProgramBuilder& b); /// Creates a circuit with a nested controlled SX gate. -void nestedControlledSx(QCProgramBuilder& b); +SmallVector nestedControlledSx(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled SX gate. -void trivialControlledSx(QCProgramBuilder& b); +Value trivialControlledSx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an SX gate. -void inverseSx(QCProgramBuilder& b); +Value inverseSx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled SX gate. -void inverseMultipleControlledSx(QCProgramBuilder& b); +SmallVector inverseMultipleControlledSx(QCProgramBuilder& b); // --- SXdgOp --------------------------------------------------------------- // /// Creates a circuit with just an SXdg gate. -void sxdg(QCProgramBuilder& b); +Value sxdg(QCProgramBuilder& b); /// Creates a circuit with a single controlled SXdg gate. -void singleControlledSxdg(QCProgramBuilder& b); +SmallVector singleControlledSxdg(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled SXdg gate. -void multipleControlledSxdg(QCProgramBuilder& b); +SmallVector multipleControlledSxdg(QCProgramBuilder& b); /// Creates a circuit with a nested controlled SXdg gate. -void nestedControlledSxdg(QCProgramBuilder& b); +SmallVector nestedControlledSxdg(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled SXdg gate. -void trivialControlledSxdg(QCProgramBuilder& b); +Value trivialControlledSxdg(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an SXdg gate. -void inverseSxdg(QCProgramBuilder& b); +Value inverseSxdg(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled SXdg /// gate. -void inverseMultipleControlledSxdg(QCProgramBuilder& b); +SmallVector inverseMultipleControlledSxdg(QCProgramBuilder& b); // --- RXOp ----------------------------------------------------------------- // /// Creates a circuit with just an RX gate. -void rx(QCProgramBuilder& b); +Value rx(QCProgramBuilder& b); /// Creates a circuit with a single controlled RX gate. -void singleControlledRx(QCProgramBuilder& b); +SmallVector singleControlledRx(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled RX gate. -void multipleControlledRx(QCProgramBuilder& b); +SmallVector multipleControlledRx(QCProgramBuilder& b); /// Creates a circuit with a nested controlled RX gate. -void nestedControlledRx(QCProgramBuilder& b); +SmallVector nestedControlledRx(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled RX gate. -void trivialControlledRx(QCProgramBuilder& b); +Value trivialControlledRx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RX gate. -void inverseRx(QCProgramBuilder& b); +Value inverseRx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RX gate. -void inverseMultipleControlledRx(QCProgramBuilder& b); +SmallVector inverseMultipleControlledRx(QCProgramBuilder& b); // --- RYOp ----------------------------------------------------------------- // /// Creates a circuit with just an RY gate. -void ry(QCProgramBuilder& b); +Value ry(QCProgramBuilder& b); /// Creates a circuit with a single controlled RY gate. -void singleControlledRy(QCProgramBuilder& b); +SmallVector singleControlledRy(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled RY gate. -void multipleControlledRy(QCProgramBuilder& b); +SmallVector multipleControlledRy(QCProgramBuilder& b); /// Creates a circuit with a nested controlled RY gate. -void nestedControlledRy(QCProgramBuilder& b); +SmallVector nestedControlledRy(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled RY gate. -void trivialControlledRy(QCProgramBuilder& b); +Value trivialControlledRy(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RY gate. -void inverseRy(QCProgramBuilder& b); +Value inverseRy(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RY gate. -void inverseMultipleControlledRy(QCProgramBuilder& b); +SmallVector inverseMultipleControlledRy(QCProgramBuilder& b); // --- RZOp ----------------------------------------------------------------- // /// Creates a circuit with just an RZ gate. -void rz(QCProgramBuilder& b); +Value rz(QCProgramBuilder& b); /// Creates a circuit with a single controlled RZ gate. -void singleControlledRz(QCProgramBuilder& b); +SmallVector singleControlledRz(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled RZ gate. -void multipleControlledRz(QCProgramBuilder& b); +SmallVector multipleControlledRz(QCProgramBuilder& b); /// Creates a circuit with a nested controlled RZ gate. -void nestedControlledRz(QCProgramBuilder& b); +SmallVector nestedControlledRz(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled RZ gate. -void trivialControlledRz(QCProgramBuilder& b); +Value trivialControlledRz(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RZ gate. -void inverseRz(QCProgramBuilder& b); +Value inverseRz(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RZ gate. -void inverseMultipleControlledRz(QCProgramBuilder& b); +SmallVector inverseMultipleControlledRz(QCProgramBuilder& b); // --- POp ------------------------------------------------------------------ // /// Creates a circuit with just a P gate. -void p(QCProgramBuilder& b); +Value p(QCProgramBuilder& b); /// Creates a circuit with a single controlled P gate. -void singleControlledP(QCProgramBuilder& b); +SmallVector singleControlledP(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled P gate. -void multipleControlledP(QCProgramBuilder& b); +SmallVector multipleControlledP(QCProgramBuilder& b); /// Creates a circuit with a nested controlled P gate. -void nestedControlledP(QCProgramBuilder& b); +SmallVector nestedControlledP(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled P gate. -void trivialControlledP(QCProgramBuilder& b); +Value trivialControlledP(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a P gate. -void inverseP(QCProgramBuilder& b); +Value inverseP(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled P gate. -void inverseMultipleControlledP(QCProgramBuilder& b); +SmallVector inverseMultipleControlledP(QCProgramBuilder& b); // --- ROp ------------------------------------------------------------------ // /// Creates a circuit with just an R gate. -void r(QCProgramBuilder& b); +Value r(QCProgramBuilder& b); /// Creates a circuit with a single controlled R gate. -void singleControlledR(QCProgramBuilder& b); +SmallVector singleControlledR(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled R gate. -void multipleControlledR(QCProgramBuilder& b); +SmallVector multipleControlledR(QCProgramBuilder& b); /// Creates a circuit with a nested controlled R gate. -void nestedControlledR(QCProgramBuilder& b); +SmallVector nestedControlledR(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled R gate. -void trivialControlledR(QCProgramBuilder& b); +Value trivialControlledR(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an R gate. -void inverseR(QCProgramBuilder& b); +Value inverseR(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled R gate. -void inverseMultipleControlledR(QCProgramBuilder& b); +SmallVector inverseMultipleControlledR(QCProgramBuilder& b); // --- U2Op ----------------------------------------------------------------- // /// Creates a circuit with just a U2 gate. -void u2(QCProgramBuilder& b); +Value u2(QCProgramBuilder& b); /// Creates a circuit with a single controlled U2 gate. -void singleControlledU2(QCProgramBuilder& b); +SmallVector singleControlledU2(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled U2 gate. -void multipleControlledU2(QCProgramBuilder& b); +SmallVector multipleControlledU2(QCProgramBuilder& b); /// Creates a circuit with a nested controlled U2 gate. -void nestedControlledU2(QCProgramBuilder& b); +SmallVector nestedControlledU2(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled U2 gate. -void trivialControlledU2(QCProgramBuilder& b); +Value trivialControlledU2(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a U2 gate. -void inverseU2(QCProgramBuilder& b); +Value inverseU2(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled U2 gate. -void inverseMultipleControlledU2(QCProgramBuilder& b); +SmallVector inverseMultipleControlledU2(QCProgramBuilder& b); // --- UOp ------------------------------------------------------------------ // /// Creates a circuit with just a U gate. -void u(QCProgramBuilder& b); +Value u(QCProgramBuilder& b); /// Creates a circuit with a single controlled U gate. -void singleControlledU(QCProgramBuilder& b); +SmallVector singleControlledU(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled U gate. -void multipleControlledU(QCProgramBuilder& b); +SmallVector multipleControlledU(QCProgramBuilder& b); /// Creates a circuit with a nested controlled U gate. -void nestedControlledU(QCProgramBuilder& b); +SmallVector nestedControlledU(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled U gate. -void trivialControlledU(QCProgramBuilder& b); +Value trivialControlledU(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a U gate. -void inverseU(QCProgramBuilder& b); +Value inverseU(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled U gate. -void inverseMultipleControlledU(QCProgramBuilder& b); +SmallVector inverseMultipleControlledU(QCProgramBuilder& b); // --- SWAPOp --------------------------------------------------------------- // /// Creates a circuit with just a SWAP gate. -void swap(QCProgramBuilder& b); +SmallVector swap(QCProgramBuilder& b); /// Creates a circuit with a single controlled SWAP gate. -void singleControlledSwap(QCProgramBuilder& b); +SmallVector singleControlledSwap(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled SWAP gate. -void multipleControlledSwap(QCProgramBuilder& b); +SmallVector multipleControlledSwap(QCProgramBuilder& b); /// Creates a circuit with a nested controlled SWAP gate. -void nestedControlledSwap(QCProgramBuilder& b); +SmallVector nestedControlledSwap(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled SWAP gate. -void trivialControlledSwap(QCProgramBuilder& b); +SmallVector trivialControlledSwap(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a SWAP gate. -void inverseSwap(QCProgramBuilder& b); +SmallVector inverseSwap(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled SWAP /// gate. -void inverseMultipleControlledSwap(QCProgramBuilder& b); +SmallVector inverseMultipleControlledSwap(QCProgramBuilder& b); // --- iSWAPOp -------------------------------------------------------------- // /// Creates a circuit with just an iSWAP gate. -void iswap(QCProgramBuilder& b); +SmallVector iswap(QCProgramBuilder& b); /// Creates a circuit with a single controlled iSWAP gate. -void singleControlledIswap(QCProgramBuilder& b); +SmallVector singleControlledIswap(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled iSWAP gate. -void multipleControlledIswap(QCProgramBuilder& b); +SmallVector multipleControlledIswap(QCProgramBuilder& b); /// Creates a circuit with a nested controlled iSWAP gate. -void nestedControlledIswap(QCProgramBuilder& b); +SmallVector nestedControlledIswap(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled iSWAP gate. -void trivialControlledIswap(QCProgramBuilder& b); +SmallVector trivialControlledIswap(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an iSWAP gate. -void inverseIswap(QCProgramBuilder& b); +SmallVector inverseIswap(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled iSWAP /// gate. -void inverseMultipleControlledIswap(QCProgramBuilder& b); +SmallVector inverseMultipleControlledIswap(QCProgramBuilder& b); // --- DCXOp ---------------------------------------------------------------- // /// Creates a circuit with just a DCX gate. -void dcx(QCProgramBuilder& b); +SmallVector dcx(QCProgramBuilder& b); /// Creates a circuit with a single controlled DCX gate. -void singleControlledDcx(QCProgramBuilder& b); +SmallVector singleControlledDcx(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled DCX gate. -void multipleControlledDcx(QCProgramBuilder& b); +SmallVector multipleControlledDcx(QCProgramBuilder& b); /// Creates a circuit with a nested controlled DCX gate. -void nestedControlledDcx(QCProgramBuilder& b); +SmallVector nestedControlledDcx(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled DCX gate. -void trivialControlledDcx(QCProgramBuilder& b); +SmallVector trivialControlledDcx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a DCX gate. -void inverseDcx(QCProgramBuilder& b); +SmallVector inverseDcx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled DCX gate. -void inverseMultipleControlledDcx(QCProgramBuilder& b); +SmallVector inverseMultipleControlledDcx(QCProgramBuilder& b); // --- ECROp ---------------------------------------------------------------- // /// Creates a circuit with just an ECR gate. -void ecr(QCProgramBuilder& b); +SmallVector ecr(QCProgramBuilder& b); /// Creates a circuit with a single controlled ECR gate. -void singleControlledEcr(QCProgramBuilder& b); +SmallVector singleControlledEcr(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled ECR gate. -void multipleControlledEcr(QCProgramBuilder& b); +SmallVector multipleControlledEcr(QCProgramBuilder& b); /// Creates a circuit with a nested controlled ECR gate. -void nestedControlledEcr(QCProgramBuilder& b); +SmallVector nestedControlledEcr(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled ECR gate. -void trivialControlledEcr(QCProgramBuilder& b); +SmallVector trivialControlledEcr(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an ECR gate. -void inverseEcr(QCProgramBuilder& b); +SmallVector inverseEcr(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled ECR gate. -void inverseMultipleControlledEcr(QCProgramBuilder& b); +SmallVector inverseMultipleControlledEcr(QCProgramBuilder& b); // --- RXXOp ---------------------------------------------------------------- // /// Creates a circuit with just an RXX gate. -void rxx(QCProgramBuilder& b); +SmallVector rxx(QCProgramBuilder& b); /// Creates a circuit with a single controlled RXX gate. -void singleControlledRxx(QCProgramBuilder& b); +SmallVector singleControlledRxx(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled RXX gate. -void multipleControlledRxx(QCProgramBuilder& b); +SmallVector multipleControlledRxx(QCProgramBuilder& b); /// Creates a circuit with a nested controlled RXX gate. -void nestedControlledRxx(QCProgramBuilder& b); +SmallVector nestedControlledRxx(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled RXX gate. -void trivialControlledRxx(QCProgramBuilder& b); +SmallVector trivialControlledRxx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RXX gate. -void inverseRxx(QCProgramBuilder& b); +SmallVector inverseRxx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RXX gate. -void inverseMultipleControlledRxx(QCProgramBuilder& b); +SmallVector inverseMultipleControlledRxx(QCProgramBuilder& b); /// Creates a circuit with a triple-controlled RXX gate. -void tripleControlledRxx(QCProgramBuilder& b); +SmallVector tripleControlledRxx(QCProgramBuilder& b); /// Creates a circuit with a four-controlled RXX gate. -void fourControlledRxx(QCProgramBuilder& b); +SmallVector fourControlledRxx(QCProgramBuilder& b); // --- RYYOp ---------------------------------------------------------------- // /// Creates a circuit with just an RYY gate. -void ryy(QCProgramBuilder& b); +SmallVector ryy(QCProgramBuilder& b); /// Creates a circuit with a single controlled RYY gate. -void singleControlledRyy(QCProgramBuilder& b); +SmallVector singleControlledRyy(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled RYY gate. -void multipleControlledRyy(QCProgramBuilder& b); +SmallVector multipleControlledRyy(QCProgramBuilder& b); /// Creates a circuit with a nested controlled RYY gate. -void nestedControlledRyy(QCProgramBuilder& b); +SmallVector nestedControlledRyy(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled RYY gate. -void trivialControlledRyy(QCProgramBuilder& b); +SmallVector trivialControlledRyy(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RYY gate. -void inverseRyy(QCProgramBuilder& b); +SmallVector inverseRyy(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RYY gate. -void inverseMultipleControlledRyy(QCProgramBuilder& b); +SmallVector inverseMultipleControlledRyy(QCProgramBuilder& b); // --- RZXOp ---------------------------------------------------------------- // /// Creates a circuit with just an RZX gate. -void rzx(QCProgramBuilder& b); +SmallVector rzx(QCProgramBuilder& b); /// Creates a circuit with a single controlled RZX gate. -void singleControlledRzx(QCProgramBuilder& b); +SmallVector singleControlledRzx(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled RZX gate. -void multipleControlledRzx(QCProgramBuilder& b); +SmallVector multipleControlledRzx(QCProgramBuilder& b); /// Creates a circuit with a nested controlled RZX gate. -void nestedControlledRzx(QCProgramBuilder& b); +SmallVector nestedControlledRzx(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled RZX gate. -void trivialControlledRzx(QCProgramBuilder& b); +SmallVector trivialControlledRzx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RZX gate. -void inverseRzx(QCProgramBuilder& b); +SmallVector inverseRzx(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RZX gate. -void inverseMultipleControlledRzx(QCProgramBuilder& b); +SmallVector inverseMultipleControlledRzx(QCProgramBuilder& b); // --- RZZOp ---------------------------------------------------------------- // /// Creates a circuit with just an RZZ gate. -void rzz(QCProgramBuilder& b); +SmallVector rzz(QCProgramBuilder& b); /// Creates a circuit with a single controlled RZZ gate. -void singleControlledRzz(QCProgramBuilder& b); +SmallVector singleControlledRzz(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled RZZ gate. -void multipleControlledRzz(QCProgramBuilder& b); +SmallVector multipleControlledRzz(QCProgramBuilder& b); /// Creates a circuit with a nested controlled RZZ gate. -void nestedControlledRzz(QCProgramBuilder& b); +SmallVector nestedControlledRzz(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled RZZ gate. -void trivialControlledRzz(QCProgramBuilder& b); +SmallVector trivialControlledRzz(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RZZ gate. -void inverseRzz(QCProgramBuilder& b); +SmallVector inverseRzz(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RZZ gate. -void inverseMultipleControlledRzz(QCProgramBuilder& b); +SmallVector inverseMultipleControlledRzz(QCProgramBuilder& b); // --- XXPlusYYOp ----------------------------------------------------------- // /// Creates a circuit with just an XXPlusYY gate. -void xxPlusYY(QCProgramBuilder& b); +SmallVector xxPlusYY(QCProgramBuilder& b); /// Creates a circuit with a single controlled XXPlusYY gate. -void singleControlledXxPlusYY(QCProgramBuilder& b); +SmallVector singleControlledXxPlusYY(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled XXPlusYY gate. -void multipleControlledXxPlusYY(QCProgramBuilder& b); +SmallVector multipleControlledXxPlusYY(QCProgramBuilder& b); /// Creates a circuit with a nested controlled XXPlusYY gate. -void nestedControlledXxPlusYY(QCProgramBuilder& b); +SmallVector nestedControlledXxPlusYY(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled XXPlusYY gate. -void trivialControlledXxPlusYY(QCProgramBuilder& b); +SmallVector trivialControlledXxPlusYY(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an XXPlusYY gate. -void inverseXxPlusYY(QCProgramBuilder& b); +SmallVector inverseXxPlusYY(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled XXPlusYY /// gate. -void inverseMultipleControlledXxPlusYY(QCProgramBuilder& b); +SmallVector inverseMultipleControlledXxPlusYY(QCProgramBuilder& b); // --- XXMinusYYOp ---------------------------------------------------------- // /// Creates a circuit with just an XXMinusYY gate. -void xxMinusYY(QCProgramBuilder& b); +SmallVector xxMinusYY(QCProgramBuilder& b); /// Creates a circuit with a single controlled XXMinusYY gate. -void singleControlledXxMinusYY(QCProgramBuilder& b); +SmallVector singleControlledXxMinusYY(QCProgramBuilder& b); /// Creates a circuit with a multi-controlled XXMinusYY gate. -void multipleControlledXxMinusYY(QCProgramBuilder& b); +SmallVector multipleControlledXxMinusYY(QCProgramBuilder& b); /// Creates a circuit with a nested controlled XXMinusYY gate. -void nestedControlledXxMinusYY(QCProgramBuilder& b); +SmallVector nestedControlledXxMinusYY(QCProgramBuilder& b); /// Creates a circuit with a trivial controlled XXMinusYY gate. -void trivialControlledXxMinusYY(QCProgramBuilder& b); +SmallVector trivialControlledXxMinusYY(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an XXMinusYY gate. -void inverseXxMinusYY(QCProgramBuilder& b); +SmallVector inverseXxMinusYY(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled XXMinusYY /// gate. -void inverseMultipleControlledXxMinusYY(QCProgramBuilder& b); +SmallVector inverseMultipleControlledXxMinusYY(QCProgramBuilder& b); // --- BarrierOp ------------------------------------------------------------ // /// Creates a circuit with a barrier. -void barrier(QCProgramBuilder& b); +Value barrier(QCProgramBuilder& b); /// Creates a circuit with a barrier on two qubits. -void barrierTwoQubits(QCProgramBuilder& b); +SmallVector barrierTwoQubits(QCProgramBuilder& b); /// Creates a circuit with a barrier on multiple qubits. -void barrierMultipleQubits(QCProgramBuilder& b); +SmallVector barrierMultipleQubits(QCProgramBuilder& b); /// Creates a circuit with a single controlled barrier. -void singleControlledBarrier(QCProgramBuilder& b); +SmallVector singleControlledBarrier(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a barrier. -void inverseBarrier(QCProgramBuilder& b); +Value inverseBarrier(QCProgramBuilder& b); // --- CtrlOp --------------------------------------------------------------- // /// Creates a circuit with a trivial ctrl modifier. -void trivialCtrl(QCProgramBuilder& b); +SmallVector trivialCtrl(QCProgramBuilder& b); /// Creates a circuit with an empty ctrl modifier. -void emptyCtrl(QCProgramBuilder& b); +SmallVector emptyCtrl(QCProgramBuilder& b); /// Creates a circuit with nested ctrl modifiers. -void nestedCtrl(QCProgramBuilder& b); +SmallVector nestedCtrl(QCProgramBuilder& b); /// Creates a circuit with triple nested ctrl modifiers. -void tripleNestedCtrl(QCProgramBuilder& b); +SmallVector tripleNestedCtrl(QCProgramBuilder& b); /// Creates a circuit with double nested ctrl modifiers with two qubits each. -void doubleNestedCtrlTwoQubits(QCProgramBuilder& b); +SmallVector doubleNestedCtrlTwoQubits(QCProgramBuilder& b); /// Creates a circuit with control modifiers interleaved by an inverse modifier. -void ctrlInvSandwich(QCProgramBuilder& b); +SmallVector ctrlInvSandwich(QCProgramBuilder& b); /// Creates a circuit with a control modifier applied to two gates. -void ctrlTwo(QCProgramBuilder& b); +SmallVector ctrlTwo(QCProgramBuilder& b); /// Creates a circuit with a control modifier applied to a controlled and a /// non-controlled gate. -void ctrlTwoMixed(QCProgramBuilder& b); +SmallVector ctrlTwoMixed(QCProgramBuilder& b); /// Creates a circuit with nested control modifiers applied to two gates. -void nestedCtrlTwo(QCProgramBuilder& b); +SmallVector nestedCtrlTwo(QCProgramBuilder& b); /// Creates a circuit with a control modifier applied to a inverse modifier /// applied to two gates. -void ctrlInvTwo(QCProgramBuilder& b); +SmallVector ctrlInvTwo(QCProgramBuilder& b); // --- InvOp ---------------------------------------------------------------- // /// Creates a circuit with an empty inverse modifier. -void emptyInv(QCProgramBuilder& b); +SmallVector emptyInv(QCProgramBuilder& b); /// Creates a circuit with nested inverse modifiers. -void nestedInv(QCProgramBuilder& b); +SmallVector nestedInv(QCProgramBuilder& b); /// Creates a circuit with triple nested inverse modifiers. -void tripleNestedInv(QCProgramBuilder& b); +SmallVector tripleNestedInv(QCProgramBuilder& b); /// Creates a circuit with inverse modifiers interleaved by a control modifier. -void invCtrlSandwich(QCProgramBuilder& b); +SmallVector invCtrlSandwich(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to two gates. -void invTwo(QCProgramBuilder& b); +SmallVector invTwo(QCProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a control modifier /// applied to two gates. -void invCtrlTwo(QCProgramBuilder& b); +SmallVector invCtrlTwo(QCProgramBuilder& b); // --- IfOp ----------------------------------------------------------------- // /// Creates a circuit with a simple if operation with one qubit. -void simpleIf(QCProgramBuilder& b); - -/// Creates a circuit with an if operation with two qubits. -void ifTwoQubits(QCProgramBuilder& b); +SmallVector simpleIf(QCProgramBuilder& b); /// Creates a circuit with an if operation with an else branch. -void ifElse(QCProgramBuilder& b); +SmallVector ifElse(QCProgramBuilder& b); + +/// Creates a circuit with an if operation with two qubits. +SmallVector ifTwoQubits(QCProgramBuilder& b); /// Creates a circuit with an if operation with a nested for operation with /// a register. -void nestedIfOpForLoop(QCProgramBuilder& b); +Value nestedIfOpForLoop(QCProgramBuilder& b); // --- WhileOp -------------------------------------------------------------- // /// Creates a circuit with a while operation using a while loop. -void simpleWhileReset(QCProgramBuilder& b); +Value simpleWhileReset(QCProgramBuilder& b); /// Creates a circuit with a while operation using a do-while loop. -void simpleDoWhileReset(QCProgramBuilder& b); +Value simpleDoWhileReset(QCProgramBuilder& b); // --- ForOp ---------------------------------------------------------------- // /// Creates a circuit with a simple for operation with a register. -void simpleForLoop(QCProgramBuilder& b); +SmallVector simpleForLoop(QCProgramBuilder& b); /// Creates a circuit with a for operation with a register and a qubit and a /// nested if operation. -void nestedForLoopIfOp(QCProgramBuilder& b); +Value nestedForLoopIfOp(QCProgramBuilder& b); /// Creates a circuit with a for operation with a register and a nested while /// operation. -void nestedForLoopWhileOp(QCProgramBuilder& b); +SmallVector nestedForLoopWhileOp(QCProgramBuilder& 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(QCProgramBuilder& b); +Value nestedForLoopCtrlOpWithSeparateQubit(QCProgramBuilder& 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(QCProgramBuilder& b); +Value nestedForLoopCtrlOpWithExtractedQubit(QCProgramBuilder& b); } // namespace mlir::qc diff --git a/mlir/unittests/programs/qco_programs.cpp b/mlir/unittests/programs/qco_programs.cpp index 6f715fa78e..4cafe6572d 100644 --- a/mlir/unittests/programs/qco_programs.cpp +++ b/mlir/unittests/programs/qco_programs.cpp @@ -14,1936 +14,2804 @@ #include #include +#include #include +#include #include #include +#include namespace mlir::qco { -void emptyQCO([[maybe_unused]] QCOProgramBuilder& builder) {} +/** + * @brief Measures the given `qtensor` and returns the measurement outcomes. + * @param b The `ProgramBuilder` used to perform the measurements. + * @param qTensor The `qtensor` to be measured. + * @param size The number of qubits in the `qtensor`. + * @return The result values. + */ +static SmallVector measureAndReturnQTensor(QCOProgramBuilder& b, + Value qTensor, + const int64_t size) { + SmallVector bits; + for (auto i = 0; i < size; ++i) { + auto [qTensorOut, qubit] = b.qtensorExtract(qTensor, i); + auto [q2, bit] = b.measure(qubit); + bits.push_back(bit); + qTensor = b.qtensorInsert(q2, qTensorOut, i); + } + return bits; +} -void allocQubit(QCOProgramBuilder& b) { b.allocQubit(); } +/** + * @brief Measures the given qubits and returns the measurement outcomes. + * @param b The `ProgramBuilder` used to perform the measurements. + * @param qubits The qubits to be measured. + * @return The result values. + */ +static SmallVector measureAndReturn(QCOProgramBuilder& b, + ValueRange qubits) { + return llvm::to_vector( + llvm::map_range(qubits, [&](Value q) { return b.measure(q).second; })); +} -void allocQubitRegister(QCOProgramBuilder& b) { b.allocQubitRegister(2); } +Value emptyQCO(QCOProgramBuilder& b) { return b.intConstant(0); } -void allocMultipleQubitRegisters(QCOProgramBuilder& b) { - b.allocQubitRegister(2); - b.allocQubitRegister(3); +Value allocQubit(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + return b.measure(q).second; } -void allocLargeRegister(QCOProgramBuilder& b) { b.allocQubitRegister(100); } +SmallVector alloc2Qubits(QCOProgramBuilder& b) { + auto q0 = b.allocQubit(); + auto q1 = b.allocQubit(); + return measureAndReturn(b, {q0, q1}); +} -void staticQubits(QCOProgramBuilder& b) { - b.staticQubit(0); - b.staticQubit(1); +Value allocQubitNoMeasure(QCOProgramBuilder& b) { + (void)b.allocQubit(); + return b.intConstant(0); +} + +Value alloc1QubitRegister(QCOProgramBuilder& b) { + auto reg = b.allocQubitRegister(1); + return b.measure(reg[0]).second; +} + +SmallVector alloc2QubitRegister(QCOProgramBuilder& b) { + auto reg = b.allocQubitRegister(2); + return measureAndReturn(b, reg.qubits); +} + +SmallVector alloc3QubitRegister(QCOProgramBuilder& b) { + auto reg = b.allocQubitRegister(3); + return measureAndReturn(b, reg.qubits); } -void staticQubitsWithOps(QCOProgramBuilder& b) { +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]}); +} + +Value allocLargeRegister(QCOProgramBuilder& b) { + auto r = b.allocQubitRegister(100); + return b.measure(r[0]).second; +} + +Value staticQubitsNoMeasure(QCOProgramBuilder& b) { + (void)b.staticQubit(0); + (void)b.staticQubit(1); + return b.intConstant(0); +} + +SmallVector staticQubits(QCOProgramBuilder& b) { + auto q1 = b.staticQubit(0); + auto q2 = b.staticQubit(1); + return measureAndReturn(b, {q1, q2}); +} + +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) { +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) { +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) { +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) { +Value staticQubitsWithInv(QCOProgramBuilder& b) { auto q0 = b.staticQubit(0); q0 = b.inv(q0, [&](Value qubit) { return b.t(qubit); }); + return b.measure(q0).second; } -void allocSinkPair(QCOProgramBuilder& b) { +Value allocSinkPair(QCOProgramBuilder& b) { auto q = b.allocQubit(); b.sink(q); + return b.intConstant(0); } -void mixedStaticThenDynamicQubit(QCOProgramBuilder& b) { - b.staticQubit(0); - b.allocQubit(); +SmallVector deadGatesProgram(QCOProgramBuilder& b) { + auto q0 = b.allocQubit(); + auto q1 = b.allocQubit(); + + auto [q0M, m0] = b.measure(q0); + auto [q1M, m1] = b.measure(q1); + + q0 = b.h(q0M); + auto [res0, res1] = b.cx(q0, q1M); + auto [_, c1] = b.measure(res1); + q0 = b.reset(res0); + + return {m0, m1}; } -void mixedDynamicRegisterThenStaticQubit(QCOProgramBuilder& b) { +Value deadGatesWithIfOpProgram(QCOProgramBuilder& b) { + auto q0 = b.allocQubit(); + auto q1 = b.allocQubit(); + q0 = b.h(q0); + auto [r0, c0] = b.measure(q0); + q0 = r0; + + // This is an `if` with memory effects - it can't be removed. + q1 = b.qcoIf( + c0, {q1}, + [&](ValueRange qubits) -> SmallVector { + auto q1Then = b.x(qubits[0]); + b.gphase(0.5); // This adds memory effects to the `IfOp`. + return {q1Then}; + }, + [&](ValueRange qubits) -> SmallVector { + auto q1Else = b.h(qubits[0]); + return {q1Else}; + })[0]; + + // This is an `if` without memory effects - it can be removed. + q1 = b.qcoIf( + c0, {q1}, + [&](ValueRange qubits) -> SmallVector { + auto q1Then = b.x(qubits[0]); + return {q1Then}; + }, + [&](ValueRange qubits) -> SmallVector { + auto q1Else = b.h(qubits[0]); + return {q1Else}; + })[0]; + + return c0; +} + +Value deadGatesWithIfOpSimplified(QCOProgramBuilder& b) { + auto q0 = b.allocQubit(); + auto q1 = b.allocQubit(); + q0 = b.h(q0); + auto [r0, c0] = b.measure(q0); + q0 = r0; + + // This is an `if` with memory effects - it can't be removed. + q1 = b.qcoIf( + c0, {q1}, + [&](ValueRange qubits) -> SmallVector { + auto q1Then = b.x(qubits[0]); + b.gphase(0.5); // Due to memory effect, the `IfOp` stays. + return {q1Then}; + }, + [&](ValueRange qubits) -> SmallVector { + auto q1Else = b.h(qubits[0]); + return {q1Else}; + })[0]; + + return c0; +} + +SmallVector mixedStaticThenDynamicQubit(QCOProgramBuilder& b) { + auto q0 = b.staticQubit(0); + auto q1 = b.allocQubit(); + return measureAndReturn(b, {q0, q1}); +} + +Value mixedDynamicRegisterThenStaticQubit(QCOProgramBuilder& b) { b.qtensorAlloc(2); - b.staticQubit(0); + auto q1 = b.staticQubit(0); + return b.measure(q1).second; } -void singleMeasurementToSingleBit(QCOProgramBuilder& b) { +Value 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; } -void repeatedMeasurementToSameBit(QCOProgramBuilder& b) { +Value 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 c3; } -void repeatedMeasurementToDifferentBits(QCOProgramBuilder& b) { +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}; } -void multipleClassicalRegistersAndMeasurements(QCOProgramBuilder& b) { +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 [q0, bit1] = b.measure(q[0], c0[0]); + auto [q1, bit2] = b.measure(q[1], c1[0]); + auto [q2, bit3] = b.measure(q[2], c1[1]); + return {bit1, bit2, bit3}; } -void measurementWithoutRegisters(QCOProgramBuilder& b) { +Value measurementWithoutRegisters(QCOProgramBuilder& b) { auto q = b.allocQubit(); - b.measure(q); + auto [q1, c] = b.measure(q); + return c; } -void resetQubitWithoutOp(QCOProgramBuilder& b) { +Value resetQubitWithoutOp(QCOProgramBuilder& b) { auto q = b.allocQubit(); q = b.reset(q); + return b.measure(q).second; } -void resetMultipleQubitsWithoutOp(QCOProgramBuilder& b) { +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.qubits); } -void repeatedResetWithoutOp(QCOProgramBuilder& b) { +Value repeatedResetWithoutOp(QCOProgramBuilder& b) { auto q = b.allocQubit(); q = b.reset(q); q = b.reset(q); q = b.reset(q); + return b.measure(q).second; } -void resetQubitAfterSingleOp(QCOProgramBuilder& b) { +Value resetQubitAfterSingleOp(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.h(q[0]); q[0] = b.reset(q[0]); + return b.measure(q[0]).second; } -void resetMultipleQubitsAfterSingleOp(QCOProgramBuilder& b) { +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.qubits); } -void repeatedResetAfterSingleOp(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void globalPhase(QCOProgramBuilder& b) { b.gphase(0.123); } +Value globalPhase(QCOProgramBuilder& b) { + b.gphase(0.123); + return b.intConstant(0); +} -void singleControlledGlobalPhase(QCOProgramBuilder& b) { +Value singleControlledGlobalPhase(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.cgphase(0.123, q[0]); + q[0] = b.cgphase(0.123, q[0]); + return b.measure(q[0]).second; } -void multipleControlledGlobalPhase(QCOProgramBuilder& b) { +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); } -void inverseGlobalPhase(QCOProgramBuilder& b) { +Value inverseGlobalPhase(QCOProgramBuilder& b) { b.inv(ValueRange{}, [&](ValueRange /*qubits*/) { b.gphase(-0.123); return SmallVector{}; }); + return b.intConstant(0); } -void inverseMultipleControlledGlobalPhase(QCOProgramBuilder& b) { +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); } -void identity(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - b.id(q[0]); +Value identity(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + q = b.id(q); + return b.measure(q).second; } -void singleControlledIdentity(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledIdentity(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledIdentity(QCOProgramBuilder& b) { +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], [&](Value target) { return b.id(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledIdentity(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - b.mcid({}, q[0]); +Value trivialControlledIdentity(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + auto res = b.mcid({}, q); + q = res.second; + return b.measure(q).second; } -void inverseIdentity(QCOProgramBuilder& b) { +Value inverseIdentity(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.id(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.id(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledIdentity(QCOProgramBuilder& b) { +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.qubits); } -void x(QCOProgramBuilder& b) { +Value x(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.x(q[0]); + q[0] = b.x(q[0]); + return b.measure(q[0]).second; } -void singleControlledX(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledX(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledX(QCOProgramBuilder& b) { +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], [&](Value target) { return b.x(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledX(QCOProgramBuilder& b) { +Value trivialControlledX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcx({}, q[0]); + auto res = b.mcx({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void repeatedControlledX(QCOProgramBuilder& b) { - auto tensor = b.qtensorAlloc(64); - - Value q0; - std::tie(tensor, q0) = b.qtensorExtract(tensor, 0); - - SmallVector values(63); - for (auto i = 1; i < 64; i++) { - Value qi; - std::tie(tensor, qi) = b.qtensorExtract(tensor, i); - values[i - 1] = qi; - } - - q0 = b.h(q0); - for (auto i = 1; i < 64; i++) { - std::tie(q0, values[i - 1]) = b.cx(q0, values[i - 1]); +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(); + 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) { +Value inverseX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.x(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.x(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledX(QCOProgramBuilder& b) { +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.qubits); } -void twoX(QCOProgramBuilder& b) { +Value twoX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.x(q[0]); q[0] = b.x(q[0]); + return b.measure(q[0]).second; } -void controlledTwoX(QCOProgramBuilder& b) { +SmallVector controlledTwoX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ctrl(q[0], q[1], [&](Value target) { + auto res = b.ctrl(q[0], q[1], [&](Value target) { target = b.x(target); return b.x(target); }); + return measureAndReturn(b, {res.first, res.second}); } -void inverseTwoX(QCOProgramBuilder& b) { +Value inverseTwoX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { + auto res = b.inv(q[0], [&](Value qubit) { qubit = b.x(qubit); qubit = b.x(qubit); return qubit; }); + return b.measure(res).second; } -void inverseGphaseX(QCOProgramBuilder& b) { +Value inverseGphaseX(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { + auto res = b.inv(q[0], [&](Value qubit) { b.gphase(-0.123); return b.x(qubit); }); + return b.measure(res).second; } -void inverseGphaseBarrier(QCOProgramBuilder& b) { +Value inverseGphaseBarrier(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { + auto res = b.inv(q[0], [&](Value qubit) { b.gphase(0.123); return b.barrier({qubit})[0]; }); + return b.measure(res).second; } -void inverseTwoBarriersInInv(QCOProgramBuilder& b) { +Value inverseTwoBarriersInInv(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { + auto res = b.inv(q[0], [&](Value qubit) { qubit = b.barrier({qubit})[0]; return b.barrier({qubit})[0]; }); + return b.measure(res).second; } -void y(QCOProgramBuilder& b) { +Value y(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.y(q[0]); + q[0] = b.y(q[0]); + return b.measure(q[0]).second; } -void singleControlledY(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledY(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledY(QCOProgramBuilder& b) { +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], [&](Value target) { return b.y(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledY(QCOProgramBuilder& b) { +Value trivialControlledY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcy({}, q[0]); + auto res = b.mcy({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void inverseY(QCOProgramBuilder& b) { +Value inverseY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.y(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.y(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledY(QCOProgramBuilder& b) { +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.qubits); } -void twoY(QCOProgramBuilder& b) { +Value twoY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.y(q[0]); q[0] = b.y(q[0]); + return b.measure(q[0]).second; } -void z(QCOProgramBuilder& b) { +Value z(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.z(q[0]); + q[0] = b.z(q[0]); + return b.measure(q[0]).second; } -void singleControlledZ(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledZ(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledZ(QCOProgramBuilder& b) { +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], [&](Value target) { return b.z(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledZ(QCOProgramBuilder& b) { +Value trivialControlledZ(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcz({}, q[0]); + auto res = b.mcz({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void inverseZ(QCOProgramBuilder& b) { +Value inverseZ(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.z(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.z(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledZ(QCOProgramBuilder& b) { +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.qubits); } -void twoZ(QCOProgramBuilder& b) { +Value twoZ(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.z(q[0]); q[0] = b.z(q[0]); + return b.measure(q[0]).second; } -void h(QCOProgramBuilder& b) { +Value h(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.h(q[0]); + q[0] = b.h(q[0]); + return b.measure(q[0]).second; } -void singleControlledH(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledH(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledH(QCOProgramBuilder& b) { +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], [&](Value target) { return b.h(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledH(QCOProgramBuilder& b) { +Value trivialControlledH(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mch({}, q[0]); + auto res = b.mch({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void inverseH(QCOProgramBuilder& b) { +Value inverseH(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.h(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.h(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledH(QCOProgramBuilder& b) { +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.qubits); } -void twoH(QCOProgramBuilder& b) { - auto q = b.allocQubitRegister(1); - q[0] = b.h(q[0]); - q[0] = b.h(q[0]); +Value twoH(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + q = b.h(q); + q = b.h(q); + return b.measure(q).second; } -void hWithoutRegister(QCOProgramBuilder& b) { +Value hWithoutRegister(QCOProgramBuilder& b) { auto q = b.allocQubit(); - b.h(q); + q = b.h(q); + return b.measure(q).second; } -void s(QCOProgramBuilder& b) { +Value s(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.s(q[0]); + q[0] = b.s(q[0]); + return b.measure(q[0]).second; } -void singleControlledS(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledS(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledS(QCOProgramBuilder& b) { +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], [&](Value target) { return b.s(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledS(QCOProgramBuilder& b) { +Value trivialControlledS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcs({}, q[0]); + auto res = b.mcs({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void inverseS(QCOProgramBuilder& b) { +Value inverseS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.s(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.s(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledS(QCOProgramBuilder& b) { +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.qubits); } -void sThenSdg(QCOProgramBuilder& b) { +Value sThenSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.s(q[0]); q[0] = b.sdg(q[0]); + return b.measure(q[0]).second; } -void twoS(QCOProgramBuilder& b) { +Value twoS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.s(q[0]); q[0] = b.s(q[0]); + return b.measure(q[0]).second; } -void sdg(QCOProgramBuilder& b) { +Value sdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.sdg(q[0]); + q[0] = b.sdg(q[0]); + return b.measure(q[0]).second; } -void singleControlledSdg(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledSdg(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledSdg(QCOProgramBuilder& b) { +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], [&](Value target) { return b.sdg(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledSdg(QCOProgramBuilder& b) { +Value trivialControlledSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcsdg({}, q[0]); + auto res = b.mcsdg({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void inverseSdg(QCOProgramBuilder& b) { +Value inverseSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.sdg(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.sdg(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledSdg(QCOProgramBuilder& b) { +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.qubits); } -void sdgThenS(QCOProgramBuilder& b) { +Value sdgThenS(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sdg(q[0]); q[0] = b.s(q[0]); + return b.measure(q[0]).second; } -void twoSdg(QCOProgramBuilder& b) { +Value twoSdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sdg(q[0]); q[0] = b.sdg(q[0]); + return b.measure(q[0]).second; } -void t_(QCOProgramBuilder& b) { +Value t_(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.t(q[0]); + q[0] = b.t(q[0]); + return b.measure(q[0]).second; } -void singleControlledT(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledT(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledT(QCOProgramBuilder& b) { +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], [&](Value target) { return b.t(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledT(QCOProgramBuilder& b) { +Value trivialControlledT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mct({}, q[0]); + auto res = b.mct({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void inverseT(QCOProgramBuilder& b) { +Value inverseT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.t(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.t(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledT(QCOProgramBuilder& b) { +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.qubits); } -void tThenTdg(QCOProgramBuilder& b) { +Value tThenTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.t(q[0]); q[0] = b.tdg(q[0]); + return b.measure(q[0]).second; } -void twoT(QCOProgramBuilder& b) { +Value twoT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.t(q[0]); q[0] = b.t(q[0]); + return b.measure(q[0]).second; } -void tdg(QCOProgramBuilder& b) { +Value tdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.tdg(q[0]); + q[0] = b.tdg(q[0]); + return b.measure(q[0]).second; } -void singleControlledTdg(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledTdg(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledTdg(QCOProgramBuilder& b) { +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], [&](Value target) { return b.tdg(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledTdg(QCOProgramBuilder& b) { +Value trivialControlledTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mctdg({}, q[0]); + auto res = b.mctdg({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void inverseTdg(QCOProgramBuilder& b) { +Value inverseTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.tdg(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.tdg(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledTdg(QCOProgramBuilder& b) { +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.qubits); } -void tdgThenT(QCOProgramBuilder& b) { +Value tdgThenT(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.tdg(q[0]); q[0] = b.t(q[0]); + return b.measure(q[0]).second; } -void twoTdg(QCOProgramBuilder& b) { +Value twoTdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.tdg(q[0]); q[0] = b.tdg(q[0]); + return b.measure(q[0]).second; } -void sx(QCOProgramBuilder& b) { +Value sx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.sx(q[0]); + q[0] = b.sx(q[0]); + return b.measure(q[0]).second; } -void singleControlledSx(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledSx(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledSx(QCOProgramBuilder& b) { +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], [&](Value target) { return b.sx(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledSx(QCOProgramBuilder& b) { +Value trivialControlledSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcsx({}, q[0]); + auto res = b.mcsx({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void inverseSx(QCOProgramBuilder& b) { +Value inverseSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.sx(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.sx(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledSx(QCOProgramBuilder& b) { +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.qubits); } -void sxThenSxdg(QCOProgramBuilder& b) { +Value sxThenSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sx(q[0]); q[0] = b.sxdg(q[0]); + return b.measure(q[0]).second; } -void twoSx(QCOProgramBuilder& b) { +Value twoSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sx(q[0]); q[0] = b.sx(q[0]); + return b.measure(q[0]).second; } -void sxdg(QCOProgramBuilder& b) { +Value sxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.sxdg(q[0]); + q[0] = b.sxdg(q[0]); + return b.measure(q[0]).second; } -void singleControlledSxdg(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledSxdg(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledSxdg(QCOProgramBuilder& b) { +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], [&](Value target) { return b.sxdg(target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledSxdg(QCOProgramBuilder& b) { +Value trivialControlledSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.mcsxdg({}, q[0]); + auto res = b.mcsxdg({}, q[0]); + q[0] = res.second; + return b.measure(q[0]).second; } -void inverseSxdg(QCOProgramBuilder& b) { +Value inverseSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.sxdg(qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.sxdg(qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledSxdg(QCOProgramBuilder& b) { +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.qubits); } -void sxdgThenSx(QCOProgramBuilder& b) { +Value sxdgThenSx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sxdg(q[0]); q[0] = b.sx(q[0]); + return b.measure(q[0]).second; } -void twoSxdg(QCOProgramBuilder& b) { +Value twoSxdg(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.sxdg(q[0]); q[0] = b.sxdg(q[0]); + return b.measure(q[0]).second; } -void rx(QCOProgramBuilder& b) { +Value rx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.rx(0.123, q[0]); + q[0] = b.rx(0.123, q[0]); + return b.measure(q[0]).second; } -void singleControlledRx(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledRx(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledRx(QCOProgramBuilder& b) { +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], [&](Value target) { return b.rx(0.123, target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledRx(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void inverseRx(QCOProgramBuilder& b) { +Value inverseRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.rx(-0.123, qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.rx(-0.123, qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledRx(QCOProgramBuilder& b) { +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.qubits); } -void twoRxOppositePhase(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void rxPiOver2(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void ry(QCOProgramBuilder& b) { +Value ry(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.ry(0.456, q[0]); + q[0] = b.ry(0.456, q[0]); + return b.measure(q[0]).second; } -void singleControlledRy(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledRy(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledRy(QCOProgramBuilder& b) { +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], [&](Value target) { return b.ry(0.456, target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledRy(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void inverseRy(QCOProgramBuilder& b) { +Value inverseRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.ry(-0.456, qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.ry(-0.456, qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledRy(QCOProgramBuilder& b) { +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.qubits); } -void twoRyOppositePhase(QCOProgramBuilder& b) { + +Value 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 b.measure(q[0]).second; } -void ryPiOver2(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void rz(QCOProgramBuilder& b) { +Value rz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.rz(0.789, q[0]); + q[0] = b.rz(0.789, q[0]); + return b.measure(q[0]).second; } -void singleControlledRz(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledRz(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledRz(QCOProgramBuilder& b) { +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], [&](Value target) { return b.rz(0.789, target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledRz(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void inverseRz(QCOProgramBuilder& b) { +Value inverseRz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.rz(-0.789, qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.rz(-0.789, qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledRz(QCOProgramBuilder& b) { +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.qubits); } -void twoRzOppositePhase(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void p(QCOProgramBuilder& b) { +Value p(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.p(0.123, q[0]); + q[0] = b.p(0.123, q[0]); + return b.measure(q[0]).second; } -void singleControlledP(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledP(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledP(QCOProgramBuilder& b) { +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], [&](Value target) { return b.p(0.123, target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledP(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void inverseP(QCOProgramBuilder& b) { +Value inverseP(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.p(-0.123, qubit); }); + auto res = b.inv(q[0], [&](Value qubit) { return b.p(-0.123, qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledP(QCOProgramBuilder& b) { +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.qubits); } -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]); +Value twoPOppositePhase(QCOProgramBuilder& b) { + auto q = b.allocQubit(); + q = b.p(0.123, q); + q = b.p(-0.123, q); + return b.measure(q).second; } -void r(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void singleControlledR(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledR(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledR(QCOProgramBuilder& b) { +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], [&](Value target) { return b.r(0.123, 0.456, target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledR(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void inverseR(QCOProgramBuilder& b) { +Value inverseR(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.r(-0.123, 0.456, qubit); }); + auto res = + b.inv(q[0], [&](Value qubit) { return b.r(-0.123, 0.456, qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledR(QCOProgramBuilder& b) { +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.qubits); } -void canonicalizeRToRx(QCOProgramBuilder& b) { +Value canonicalizeRToRx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.r(0.123, 0., q[0]); + return b.measure(q[0]).second; } -void canonicalizeRToRy(QCOProgramBuilder& b) { +Value canonicalizeRToRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.r(0.456, std::numbers::pi / 2, q[0]); + return b.measure(q[0]).second; } -void twoR(QCOProgramBuilder& b) { +Value twoR(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); q[0] = b.r(0.045, 0.456, q[0]); q[0] = b.r(0.078, 0.456, q[0]); + return b.measure(q[0]).second; } -void u2(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void singleControlledU2(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledU2(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledU2(QCOProgramBuilder& b) { +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], [&](Value target) { return b.u2(0.234, 0.567, target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledU2(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void inverseU2(QCOProgramBuilder& b) { +Value inverseU2(QCOProgramBuilder& b) { constexpr double pi = std::numbers::pi; auto q = b.allocQubitRegister(1); - b.inv(q[0], - [&](Value qubit) { return b.u2(-0.567 + pi, -0.234 - pi, qubit); }); + auto res = b.inv( + q[0], [&](Value qubit) { return b.u2(-0.567 + pi, -0.234 - pi, qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledU2(QCOProgramBuilder& b) { +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.qubits); } -void canonicalizeU2ToH(QCOProgramBuilder& b) { + +Value 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 b.measure(q[0]).second; } -void canonicalizeU2ToRx(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void canonicalizeU2ToRy(QCOProgramBuilder& b) { + +Value canonicalizeU2ToRy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.u2(0., 0., q[0]); + q[0] = b.u2(0., 0., q[0]); + return b.measure(q[0]).second; } -void u(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void singleControlledU(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledU(QCOProgramBuilder& b) { +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.qubits); } -void nestedControlledU(QCOProgramBuilder& b) { +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], [&](Value target) { return b.u(0.1, 0.2, 0.3, target); }); return SmallVector{innerControlsOut, innerTargetsOut}; }); + reg[0] = res.first[0]; + reg[1] = res.second[0]; + reg[2] = res.second[1]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledU(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void inverseU(QCOProgramBuilder& b) { +Value inverseU(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.u(-0.1, -0.3, -0.2, qubit); }); + auto res = + b.inv(q[0], [&](Value qubit) { return b.u(-0.1, -0.3, -0.2, qubit); }); + return b.measure(res).second; } -void inverseMultipleControlledU(QCOProgramBuilder& b) { +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.qubits); } -void canonicalizeUToP(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void canonicalizeUToRx(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void canonicalizeUToRy(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void canonicalizeUToU2(QCOProgramBuilder& b) { +Value 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 b.measure(q[0]).second; } -void swap(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledSwap(QCOProgramBuilder& b) { +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.qubits); } -void multipleControlledSwap(QCOProgramBuilder& b) { +SmallVector multipleControlledSwap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcswap({q[0], q[1]}, q[2], q[3]); + auto [c, t] = b.mcswap({q[0], q[1]}, q[2], q[3]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = t.first; + q[3] = t.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledSwap(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = b.swap(innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledSwap(QCOProgramBuilder& b) { +SmallVector trivialControlledSwap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcswap({}, q[0], q[1]); + auto [c, t] = b.mcswap({}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseSwap(QCOProgramBuilder& b) { +SmallVector inverseSwap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { - auto res = b.swap(qubits[0], qubits[1]); - return SmallVector{res.first, res.second}; + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto [fst, snd] = b.swap(qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledSwap(QCOProgramBuilder& b) { +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.qubits); } -void twoSwap(QCOProgramBuilder& b) { +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.qubits); } -void twoSwapSwappedTargets(QCOProgramBuilder& b) { +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.qubits); } -void iswap(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledIswap(QCOProgramBuilder& b) { +SmallVector singleControlledIswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.ciswap(q[0], q[1], q[2]); + auto [c, t] = b.ciswap(q[0], q[1], q[2]); + q[0] = c; + q[1] = t.first; + q[2] = t.second; + return measureAndReturn(b, q.qubits); } -void multipleControlledIswap(QCOProgramBuilder& b) { +SmallVector multipleControlledIswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mciswap({q[0], q[1]}, q[2], q[3]); + auto [c, t] = b.mciswap({q[0], q[1]}, q[2], q[3]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = t.first; + q[3] = t.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledIswap(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = + b.iswap(innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledIswap(QCOProgramBuilder& b) { +SmallVector trivialControlledIswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mciswap({}, q[0], q[1]); + auto [c, t] = b.mciswap({}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseIswap(QCOProgramBuilder& b) { +SmallVector inverseIswap(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { - auto res = b.iswap(qubits[0], qubits[1]); - return SmallVector{res.first, res.second}; + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto [fst, snd] = b.iswap(qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledIswap(QCOProgramBuilder& b) { +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.qubits); } -void dcx(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledDcx(QCOProgramBuilder& b) { +SmallVector singleControlledDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cdcx(q[0], q[1], q[2]); + auto [c, t] = b.cdcx(q[0], q[1], q[2]); + q[0] = c; + q[1] = t.first; + q[2] = t.second; + return measureAndReturn(b, q.qubits); } -void multipleControlledDcx(QCOProgramBuilder& b) { +SmallVector multipleControlledDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcdcx({q[0], q[1]}, q[2], q[3]); + auto [c, t] = b.mcdcx({q[0], q[1]}, q[2], q[3]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = t.first; + q[3] = t.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledDcx(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = b.dcx(innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledDcx(QCOProgramBuilder& b) { +SmallVector trivialControlledDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcdcx({}, q[0], q[1]); + auto [c, t] = b.mcdcx({}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseDcx(QCOProgramBuilder& b) { +SmallVector inverseDcx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[1], q[0]}, [&](ValueRange qubits) { - auto res = b.dcx(qubits[0], qubits[1]); - return SmallVector{res.first, res.second}; + auto res = b.inv({q[1], q[0]}, [&](ValueRange qubits) { + auto [fst, snd] = b.dcx(qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[1] = res[0]; + q[0] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledDcx(QCOProgramBuilder& b) { +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.qubits); } -void twoDcx(QCOProgramBuilder& b) { +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.qubits); } -void twoDcxSwappedTargets(QCOProgramBuilder& b) { +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.qubits); } -void ecr(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledEcr(QCOProgramBuilder& b) { +SmallVector singleControlledEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cecr(q[0], q[1], q[2]); + auto [c, t] = b.cecr(q[0], q[1], q[2]); + q[0] = c; + q[1] = t.first; + q[2] = t.second; + return measureAndReturn(b, q.qubits); } -void multipleControlledEcr(QCOProgramBuilder& b) { +SmallVector multipleControlledEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcecr({q[0], q[1]}, q[2], q[3]); + auto [fst, snd] = b.mcecr({q[0], q[1]}, q[2], q[3]); + q[0] = fst[0]; + q[1] = fst[1]; + q[2] = snd.first; + q[3] = snd.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledEcr(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = b.ecr(innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledEcr(QCOProgramBuilder& b) { +SmallVector trivialControlledEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcecr({}, q[0], q[1]); + auto [c, t] = b.mcecr({}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseEcr(QCOProgramBuilder& b) { +SmallVector inverseEcr(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { - auto res = b.ecr(qubits[0], qubits[1]); - return SmallVector{res.first, res.second}; + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto [fst, snd] = b.ecr(qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledEcr(QCOProgramBuilder& b) { +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.qubits); } -void twoEcr(QCOProgramBuilder& b) { +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.qubits); } -void rxx(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledRxx(QCOProgramBuilder& b) { +SmallVector singleControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.crxx(0.123, q[0], q[1], q[2]); + auto [c, t] = b.crxx(0.123, q[0], q[1], q[2]); + q[0] = c; + q[1] = t.first; + q[2] = t.second; + return measureAndReturn(b, q.qubits); } -void multipleControlledRxx(QCOProgramBuilder& b) { +SmallVector multipleControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcrxx(0.123, {q[0], q[1]}, q[2], q[3]); + auto [c, t] = b.mcrxx(0.123, {q[0], q[1]}, q[2], q[3]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = t.first; + q[3] = t.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledRxx(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = + b.rxx(0.123, innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledRxx(QCOProgramBuilder& b) { +SmallVector trivialControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcrxx(0.123, {}, q[0], q[1]); + auto [c, t] = b.mcrxx(0.123, {}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseRxx(QCOProgramBuilder& b) { +SmallVector inverseRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { - auto res = b.rxx(-0.123, qubits[0], qubits[1]); - return SmallVector{res.first, res.second}; + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto [fst, snd] = b.rxx(-0.123, qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledRxx(QCOProgramBuilder& b) { +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.qubits); } -void tripleControlledRxx(QCOProgramBuilder& b) { +SmallVector tripleControlledRxx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(5); - b.mcrxx(0.123, {q[0], q[1], q[2]}, q[3], q[4]); + auto [c, t] = b.mcrxx(0.123, {q[0], q[1], q[2]}, q[3], q[4]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = c[2]; + q[3] = t.first; + q[4] = t.second; + return measureAndReturn(b, q.qubits); } -void fourControlledRxx(QCOProgramBuilder& b) { +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 [c, t] = b.mcrxx(0.123, {q[0], q[1], q[2], q[3]}, q[4], q[5]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = c[2]; + q[3] = c[3]; + q[4] = t.first; + q[5] = t.second; + return measureAndReturn(b, q.qubits); } -void twoRxx(QCOProgramBuilder& b) { +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.qubits); } -void twoRxxSwappedTargets(QCOProgramBuilder& b) { +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.qubits); } -void twoRxxOppositePhase(QCOProgramBuilder& b) { +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.qubits); } -void twoRxxOppositePhaseSwappedTargets(QCOProgramBuilder& b) { +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.qubits); } -void ryy(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledRyy(QCOProgramBuilder& b) { +SmallVector singleControlledRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cryy(0.123, q[0], q[1], q[2]); + auto [c, t] = b.cryy(0.123, q[0], q[1], q[2]); + q[0] = c; + q[1] = t.first; + q[2] = t.second; + return measureAndReturn(b, q.qubits); } -void multipleControlledRyy(QCOProgramBuilder& b) { +SmallVector multipleControlledRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcryy(0.123, {q[0], q[1]}, q[2], q[3]); + auto [c, t] = b.mcryy(0.123, {q[0], q[1]}, q[2], q[3]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = t.first; + q[3] = t.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledRyy(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = + b.ryy(0.123, innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledRyy(QCOProgramBuilder& b) { +SmallVector trivialControlledRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcryy(0.123, {}, q[0], q[1]); + auto [c, t] = b.mcryy(0.123, {}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseRyy(QCOProgramBuilder& b) { +SmallVector inverseRyy(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { - auto res = b.ryy(-0.123, qubits[0], qubits[1]); - return SmallVector{res.first, res.second}; + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto [fst, snd] = b.ryy(-0.123, qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledRyy(QCOProgramBuilder& b) { +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.qubits); } -void twoRyy(QCOProgramBuilder& b) { +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.qubits); } -void twoRyyOppositePhaseSwappedTargets(QCOProgramBuilder& b) { +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.qubits); } -void twoRyyOppositePhase(QCOProgramBuilder& b) { +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.qubits); } -void twoRyySwappedTargets(QCOProgramBuilder& b) { +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.qubits); } -void rzx(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledRzx(QCOProgramBuilder& b) { +SmallVector singleControlledRzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.crzx(0.123, q[0], q[1], q[2]); + auto [c, t] = b.crzx(0.123, q[0], q[1], q[2]); + q[0] = c; + q[1] = t.first; + q[2] = t.second; + return measureAndReturn(b, q.qubits); } -void multipleControlledRzx(QCOProgramBuilder& b) { +SmallVector multipleControlledRzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcrzx(0.123, {q[0], q[1]}, q[2], q[3]); + auto [c, t] = b.mcrzx(0.123, {q[0], q[1]}, q[2], q[3]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = t.first; + q[3] = t.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledRzx(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = + b.rzx(0.123, innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledRzx(QCOProgramBuilder& b) { +SmallVector trivialControlledRzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcrzx(0.123, {}, q[0], q[1]); + auto [c, t] = b.mcrzx(0.123, {}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseRzx(QCOProgramBuilder& b) { +SmallVector inverseRzx(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { - auto res = b.rzx(-0.123, qubits[0], qubits[1]); - return SmallVector{res.first, res.second}; + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto [fst, snd] = b.rzx(-0.123, qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledRzx(QCOProgramBuilder& b) { +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.qubits); } -void twoRzxOppositePhase(QCOProgramBuilder& b) { +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.qubits); } -void rzz(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledRzz(QCOProgramBuilder& b) { +SmallVector singleControlledRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.crzz(0.123, q[0], q[1], q[2]); + auto [c, t] = b.crzz(0.123, q[0], q[1], q[2]); + q[0] = c; + q[1] = t.first; + q[2] = t.second; + return measureAndReturn(b, q.qubits); } -void multipleControlledRzz(QCOProgramBuilder& b) { +SmallVector multipleControlledRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(4); - b.mcrzz(0.123, {q[0], q[1]}, q[2], q[3]); + auto [c, t] = b.mcrzz(0.123, {q[0], q[1]}, q[2], q[3]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = t.first; + q[3] = t.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledRzz(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = + b.rzz(0.123, innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledRzz(QCOProgramBuilder& b) { +SmallVector trivialControlledRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcrzz(0.123, {}, q[0], q[1]); + auto [c, t] = b.mcrzz(0.123, {}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseRzz(QCOProgramBuilder& b) { +SmallVector inverseRzz(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { - auto res = b.rzz(-0.123, qubits[0], qubits[1]); - return SmallVector{res.first, res.second}; + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto [fst, snd] = b.rzz(-0.123, qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledRzz(QCOProgramBuilder& b) { +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.qubits); } -void twoRzz(QCOProgramBuilder& b) { +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.qubits); } -void twoRzzSwappedTargets(QCOProgramBuilder& b) { +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.qubits); } -void twoRzzOppositePhase(QCOProgramBuilder& b) { +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.qubits); } -void twoRzzOppositePhaseSwappedTargets(QCOProgramBuilder& b) { +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.qubits); } -void xxPlusYY(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledXxPlusYY(QCOProgramBuilder& b) { +SmallVector singleControlledXxPlusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cxx_plus_yy(0.123, 0.456, q[0], q[1], q[2]); + auto [c, t] = b.cxx_plus_yy(0.123, 0.456, q[0], q[1], q[2]); + q[0] = c; + q[1] = t.first; + q[2] = t.second; + return measureAndReturn(b, q.qubits); } -void multipleControlledXxPlusYY(QCOProgramBuilder& b) { +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 [c, t] = b.mcxx_plus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = t.first; + q[3] = t.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledXxPlusYY(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = b.xx_plus_yy( + 0.123, 0.456, innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledXxPlusYY(QCOProgramBuilder& b) { +SmallVector trivialControlledXxPlusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcxx_plus_yy(0.123, 0.456, {}, q[0], q[1]); + auto [c, t] = b.mcxx_plus_yy(0.123, 0.456, {}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseXxPlusYY(QCOProgramBuilder& b) { +SmallVector inverseXxPlusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - 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}; + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto [fst, snd] = b.xx_plus_yy(-0.123, 0.456, qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledXxPlusYY(QCOProgramBuilder& b) { +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.qubits); } -void twoXxPlusYYOppositePhase(QCOProgramBuilder& b) { +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.qubits); } -void twoXxPlusYYSwappedTargets(QCOProgramBuilder& b) { +SmallVector twoXxPlusYYSwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.xx_plus_yy(0.045, 0.456, q[0], q[1]); std::tie(q[1], q[0]) = b.xx_plus_yy(0.078, 0.456, q[1], q[0]); + return measureAndReturn(b, q.qubits); } -void xxMinusYY(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledXxMinusYY(QCOProgramBuilder& b) { +SmallVector singleControlledXxMinusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.cxx_minus_yy(0.123, 0.456, q[0], q[1], q[2]); + auto [c, t] = b.cxx_minus_yy(0.123, 0.456, q[0], q[1], q[2]); + q[0] = c; + q[1] = t.first; + q[2] = t.second; + return measureAndReturn(b, q.qubits); } -void multipleControlledXxMinusYY(QCOProgramBuilder& b) { +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 [c, t] = b.mcxx_minus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + q[0] = c[0]; + q[1] = c[1]; + q[2] = t.first; + q[3] = t.second; + return measureAndReturn(b, q.qubits); } -void nestedControlledXxMinusYY(QCOProgramBuilder& b) { +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 [c, t] = + 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 [fst, snd] = b.xx_minus_yy( + 0.123, 0.456, innerTargets[0], innerTargets[1]); + return SmallVector{fst, snd}; + }); + return llvm::to_vector( + llvm::concat(innerControlsOut, innerTargetsOut)); + }); + reg[0] = c[0]; + reg[1] = t[0]; + reg[2] = t[1]; + reg[3] = t[2]; + return measureAndReturn(b, reg.qubits); } -void trivialControlledXxMinusYY(QCOProgramBuilder& b) { +SmallVector trivialControlledXxMinusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.mcxx_minus_yy(0.123, 0.456, {}, q[0], q[1]); + auto [c, t] = b.mcxx_minus_yy(0.123, 0.456, {}, q[0], q[1]); + q[0] = t.first; + q[1] = t.second; + return measureAndReturn(b, q.qubits); } -void inverseXxMinusYY(QCOProgramBuilder& b) { +SmallVector inverseXxMinusYY(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - 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}; + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { + auto [fst, snd] = b.xx_minus_yy(-0.123, 0.456, qubits[0], qubits[1]); + return SmallVector{fst, snd}; }); + q[0] = res[0]; + q[1] = res[1]; + return measureAndReturn(b, q.qubits); } -void inverseMultipleControlledXxMinusYY(QCOProgramBuilder& b) { +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.qubits); } -void twoXxMinusYYOppositePhase(QCOProgramBuilder& b) { +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.qubits); } -void twoXxMinusYYSwappedTargets(QCOProgramBuilder& b) { +SmallVector twoXxMinusYYSwappedTargets(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.xx_minus_yy(0.045, 0.456, q[0], q[1]); std::tie(q[1], q[0]) = b.xx_minus_yy(0.078, 0.456, q[1], q[0]); + return measureAndReturn(b, q.qubits); } -void barrier(QCOProgramBuilder& b) { +Value barrier(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.barrier(q[0]); + q[0] = b.barrier(q[0])[0]; + return b.measure(q[0]).second; } -void barrierTwoQubits(QCOProgramBuilder& b) { +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.qubits); } -void barrierMultipleQubits(QCOProgramBuilder& b) { +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.qubits); } -void singleControlledBarrier(QCOProgramBuilder& b) { +Value singleControlledBarrier(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); - b.ctrl(q[1], q[0], [&](Value target) { return b.barrier({target})[0]; }); + auto res = + b.ctrl(q[1], q[0], [&](Value target) { return b.barrier({target})[0]; }); + return b.measure(res.second).second; } -void inverseBarrier(QCOProgramBuilder& b) { +Value inverseBarrier(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); - b.inv(q[0], [&](Value qubit) { return b.barrier({qubit})[0]; }); + auto res = b.inv(q[0], [&](Value qubit) { return b.barrier({qubit})[0]; }); + return b.measure(res).second; } -void twoBarrier(QCOProgramBuilder& b) { +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.qubits); } -void trivialCtrl(QCOProgramBuilder& b) { +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); } -void emptyCtrl(QCOProgramBuilder& b) { +SmallVector emptyCtrl(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.rxx(0.123, q[0], q[1]); - b.ctrl(q[0], q[1], [&](Value target) { return target; }); + auto [res0, res1] = b.ctrl(q[0], q[1], [&](Value target) { return target; }); + return measureAndReturn(b, {res0, res1}); } -void nestedCtrl(QCOProgramBuilder& b) { +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]); @@ -1952,11 +2820,16 @@ 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.qubits); } -void tripleNestedCtrl(QCOProgramBuilder& b) { +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) { @@ -1973,25 +2846,40 @@ 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.qubits); } -void doubleNestedCtrlTwoQubits(QCOProgramBuilder& b) { +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.qubits); } -void ctrlInvSandwich(QCOProgramBuilder& b) { +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] = @@ -2004,35 +2892,44 @@ 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.qubits); } -void ctrlTwo(QCOProgramBuilder& b) { +SmallVector ctrlTwo(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 i0 = targets[0]; auto i1 = targets[1]; i0 = b.x(i0); std::tie(i0, i1) = b.rxx(0.123, i0, i1); return SmallVector{i0, i1}; }); + return measureAndReturn( + b, {res.first[0], res.first[1], res.second[0], res.second[1]}); } -void ctrlTwoMixed(QCOProgramBuilder& b) { +SmallVector ctrlTwoMixed(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 i0 = targets[0]; auto i1 = targets[1]; std::tie(i0, i1) = b.cx(i0, i1); std::tie(i0, i1) = b.rxx(0.123, i0, i1); return SmallVector{i0, i1}; }); + return measureAndReturn( + b, {res.first[0], res.first[1], res.second[0], res.second[1]}); } -void nestedCtrlTwo(QCOProgramBuilder& b) { +SmallVector nestedCtrlTwo(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& [controlsOut, targetsOut] = b.ctrl( targets[0], {targets[1], targets[2]}, [&](ValueRange innerTargets) { auto i0 = innerTargets[0]; @@ -2043,11 +2940,13 @@ void nestedCtrlTwo(QCOProgramBuilder& b) { }); return llvm::to_vector(llvm::concat(controlsOut, targetsOut)); }); + return measureAndReturn( + b, {res.first[0], res.second[0], res.second[1], res.second[2]}); } -void ctrlInvTwo(QCOProgramBuilder& b) { +SmallVector ctrlInvTwo(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(3); - b.ctrl(q[0], {q[1], q[2]}, [&](ValueRange targets) { + auto res = b.ctrl(q[0], {q[1], q[2]}, [&](ValueRange targets) { auto inner = b.inv(targets, [&](ValueRange qubits) { auto i0 = qubits[0]; auto i1 = qubits[1]; @@ -2057,28 +2956,33 @@ void ctrlInvTwo(QCOProgramBuilder& b) { }); return llvm::to_vector(inner); }); + return measureAndReturn(b, {res.first[0], res.second[0], res.second[1]}); } -void emptyInv(QCOProgramBuilder& b) { +SmallVector emptyInv(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(2); std::tie(q[0], q[1]) = b.rxx(0.123, q[0], q[1]); - b.inv({q[0], q[1]}, [&](ValueRange qubits) { return qubits; }); + auto res = b.inv({q[0], q[1]}, [&](ValueRange qubits) { return qubits; }); + return measureAndReturn(b, res); } -void nestedInv(QCOProgramBuilder& b) { +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.qubits); } -void tripleNestedInv(QCOProgramBuilder& b) { +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) { @@ -2086,15 +2990,18 @@ 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.qubits); } -void invCtrlSandwich(QCOProgramBuilder& b) { +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 = @@ -2102,26 +3009,31 @@ 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.qubits); } -void invTwo(QCOProgramBuilder& b) { +SmallVector invTwo(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 i0 = qubits[0]; auto i1 = qubits[1]; i0 = b.x(i0); std::tie(i0, i1) = b.rxx(0.123, i0, i1); return SmallVector{i0, i1}; }); + return measureAndReturn(b, res); } -void invCtrlTwo(QCOProgramBuilder& b) { +SmallVector invCtrlTwo(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 i0 = targets[0]; @@ -2132,45 +3044,56 @@ void invCtrlTwo(QCOProgramBuilder& b) { }); return llvm::to_vector(llvm::concat(controlsOut, targetsOut)); }); + return measureAndReturn(b, res); } -void simpleIf(QCOProgramBuilder& b) { +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]; + auto [q1, bit] = b.measure(q[0]); + return {measureResult, bit}; } -void ifWithAngle(QCOProgramBuilder& b) { +Value ifWithAngle(QCOProgramBuilder& b) { auto q = b.allocQubitRegister(1); auto theta = b.floatConstant(0.123); auto q0 = b.h(q[0]); auto [measuredQubit, measureResult] = b.measure(q0); - b.qcoIf(measureResult, measuredQubit, [&](ValueRange args) { + q0 = b.qcoIf(measureResult, measuredQubit, [&](ValueRange args) { auto innerQubit = b.rx(theta, args[0]); return SmallVector{innerQubit}; - }); + })[0]; + return b.measure(q0).second; } -void ifTwoQubits(QCOProgramBuilder& b) { +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]; + auto [q0_, c0] = b.measure(q[0]); + auto [q1, c1] = b.measure(q[1]); + return {measureResult, c0, c1}; } -void ifElse(QCOProgramBuilder& b) { +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]); @@ -2180,25 +3103,30 @@ void ifElse(QCOProgramBuilder& b) { auto innerQubit = b.z(args[0]); return SmallVector{innerQubit}; }); + q[0] = res[0]; + auto [q0_, c0] = b.measure(q[0]); + return {measureResult, c0}; } -void ifOneQubitOneTensor(QCOProgramBuilder& b) { +Value 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 b.measure(ifRes[0]).second; } -void constantTrueIf(QCOProgramBuilder& b) { +Value 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]); @@ -2208,11 +3136,12 @@ void constantTrueIf(QCOProgramBuilder& b) { auto innerQubit = b.z(args[0]); return SmallVector{innerQubit}; }); + return b.measure(ifRes[0]).second; } -void constantFalseIf(QCOProgramBuilder& b) { +Value 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]); @@ -2222,13 +3151,14 @@ void constantFalseIf(QCOProgramBuilder& b) { auto innerQubit = b.z(args[0]); return SmallVector{innerQubit}; }); + return b.measure(ifRes[0]).second; } -void nestedTrueIf(QCOProgramBuilder& b) { +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]); @@ -2236,13 +3166,15 @@ void nestedTrueIf(QCOProgramBuilder& b) { }); return llvm::to_vector(innerResult); }); + auto [q1, c] = b.measure(ifRes[0]); + return {measureResult, c}; } -void nestedFalseIf(QCOProgramBuilder& b) { +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]); @@ -2258,65 +3190,78 @@ void nestedFalseIf(QCOProgramBuilder& b) { }); return llvm::to_vector(innerResult); }); + auto [q1, c] = b.measure(ifRes[0]); + return {measureResult, c}; } -void qtensorAlloc(QCOProgramBuilder& b) { b.qtensorAlloc(3); } +SmallVector qtensorAlloc(QCOProgramBuilder& b) { + (void)b.qtensorAlloc(3); + return measureAndReturn(b, {}); +} -void qtensorDealloc(QCOProgramBuilder& b) { +SmallVector qtensorDealloc(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); b.qtensorDealloc(qtensor); + return measureAndReturn(b, {}); } -void qtensorFromElements(QCOProgramBuilder& b) { +SmallVector qtensorFromElements(QCOProgramBuilder& b) { auto q0 = b.allocQubit(); auto q1 = b.allocQubit(); auto q2 = b.allocQubit(); - b.qtensorFromElements({q0, q1, q2}); + (void)b.qtensorFromElements({q0, q1, q2}); + return measureAndReturn(b, {}); } -void qtensorExtract(QCOProgramBuilder& b) { +Value qtensorExtract(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); - b.qtensorExtract(qtensor, 0); + auto [t, q] = b.qtensorExtract(qtensor, 0); + return b.measure(q).second; } -void qtensorInsert(QCOProgramBuilder& b) { +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); + (void)b.qtensorInsert(q1, extractOutTensor, 0); + return measureAndReturn(b, {}); } -void qtensorExtractInsertIndexMismatch(QCOProgramBuilder& b) { +SmallVector qtensorExtractInsertIndexMismatch(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); auto [extractOutTensor, q0] = b.qtensorExtract(qtensor, 0); - b.qtensorInsert(q0, extractOutTensor, 1); + (void)b.qtensorInsert(q0, extractOutTensor, 1); + return measureAndReturn(b, {}); } -void qtensorExtractInsertSameIndex(QCOProgramBuilder& b) { +SmallVector qtensorExtractInsertSameIndex(QCOProgramBuilder& b) { auto qtensor = b.qtensorAlloc(3); auto [extractOutTensor, q0] = b.qtensorExtract(qtensor, 0); - b.qtensorInsert(q0, extractOutTensor, 0); + (void)b.qtensorInsert(q0, extractOutTensor, 0); + return measureAndReturn(b, {}); } -void qtensorInsertExtractIndexMismatch(QCOProgramBuilder& b) { +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); + (void)b.qtensorInsert(q2, extractOutTensor1, 0); + return measureAndReturn(b, {}); } -void qtensorInsertExtractSameIndex(QCOProgramBuilder& b) { +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); + (void)b.qtensorInsert(q2, extractOutTensor1, 0); + return measureAndReturn(b, {}); } -void qtensorChain(QCOProgramBuilder& b) { +SmallVector qtensorChain(QCOProgramBuilder& b) { Value q0; Value q1; Value q2; @@ -2332,9 +3277,11 @@ void qtensorChain(QCOProgramBuilder& b) { qtensor = b.qtensorInsert(q1, qtensor, 1); qtensor = b.qtensorInsert(q0, qtensor, 0); b.qtensorDealloc(qtensor); + + return measureAndReturn(b, {}); } -void qtensorAlternativeChain(QCOProgramBuilder& b) { +SmallVector qtensorAlternativeChain(QCOProgramBuilder& b) { Value q0; Value q1; Value q2; @@ -2350,12 +3297,14 @@ void qtensorAlternativeChain(QCOProgramBuilder& b) { qtensor = b.qtensorInsert(q1, qtensor, 1); qtensor = b.qtensorInsert(q2, qtensor, 2); b.qtensorDealloc(qtensor); + + return measureAndReturn(b, {}); } -void simpleWhileReset(QCOProgramBuilder& b) { +Value 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]); @@ -2366,11 +3315,12 @@ void simpleWhileReset(QCOProgramBuilder& b) { auto q3 = b.h(iterArgs[0]); return SmallVector{q3}; }); + return b.measure(scfWhile[0]).second; } -void simpleDoWhileReset(QCOProgramBuilder& b) { +Value simpleDoWhileReset(QCOProgramBuilder& b) { auto q0 = b.allocQubit(); - b.scfWhile( + auto scfWhile = b.scfWhile( ValueRange{q0}, [&](ValueRange iterArgs) { auto q1 = b.h(iterArgs[0]); @@ -2379,46 +3329,54 @@ void simpleDoWhileReset(QCOProgramBuilder& b) { return SmallVector{q2}; }, [&](ValueRange iterArgs) { return llvm::to_vector(iterArgs); }); + return b.measure(scfWhile[0]).second; } -void simpleForLoop(QCOProgramBuilder& b) { +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 measureAndReturnQTensor(b, scfFor[0], 2); }; -void forLoopWithAngle(QCOProgramBuilder& b) { +Value forLoopWithAngle(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(2); auto theta = b.floatConstant(0.123); - b.scfFor(0, 2, 1, {reg.value}, [&](Value iv, ValueRange iterArgs) { - auto [t0, q0] = b.qtensorExtract(iterArgs[0], iv); - auto q1 = b.rx(theta, 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.rx(theta, q0); + auto insert = b.qtensorInsert(q1, t0, iv); + return SmallVector{insert}; + }); + auto [newReg, q] = b.qtensorExtract(scfFor[0], 0); + return b.measure(q).second; +} -void nestedForLoopIfOp(QCOProgramBuilder& b) { +Value 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 b.measure(scfFor[1]).second; } -void nestedForLoopWhileOp(QCOProgramBuilder& b) { +SmallVector nestedForLoopWhileOp(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(2); auto loopResult = b.scfFor(0, 2, 1, {reg.value}, [&](Value iv, ValueRange iterArgs) { @@ -2427,57 +3385,63 @@ 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 innerIterArgs) { + auto [q1, measureResult] = b.measure(innerIterArgs[0]); + b.scfCondition(measureResult, q1); + return SmallVector{q1}; + }, + [&](ValueRange innerIterArgs) { + auto q2 = b.h(innerIterArgs[0]); + return SmallVector{q2}; + }); + auto insert = b.qtensorInsert(whileResult[0], t0, iv); + return SmallVector{insert}; + }); + return measureAndReturnQTensor(b, scfFor[0], 2); } -void nestedForLoopCtrlOpWithSeparateQubit(QCOProgramBuilder& b) { +Value 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 [controlOut, targetOut] = - b.ctrl(iterArgs[1], q1, [&](Value target) { return b.x(target); }); - auto insert = b.qtensorInsert(targetOut, t0, iv); - return SmallVector{insert, controlOut}; - }); + 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 [controlOut, targetOut] = + b.ctrl(iterArgs[1], q1, [&](Value target) { return b.x(target); }); + auto insert = b.qtensorInsert(targetOut, t0, iv); + return SmallVector{insert, controlOut}; + }); + return b.measure(scfFor[1]).second; } -void nestedForLoopCtrlOpWithExtractedQubit(QCOProgramBuilder& b) { +Value 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 [controlOut, targetOut] = - b.ctrl(iterArgs[1], q1, [&](Value target) { return b.x(target); }); - auto insert = b.qtensorInsert(targetOut, t0, iv); - return SmallVector{insert, controlOut}; - }); + 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 [controlOut, targetOut] = + b.ctrl(iterArgs[1], q1, [&](Value target) { return b.x(target); }); + auto insert = b.qtensorInsert(targetOut, t0, iv); + return SmallVector{insert, controlOut}; + }); + return b.measure(scfFor[1]).second; } -void nestedIfOpForLoop(QCOProgramBuilder& b) { +Value 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]); @@ -2493,16 +3457,17 @@ void nestedIfOpForLoop(QCOProgramBuilder& b) { }); return SmallVector{scfFor[0], args[1]}; }); + return b.measure(ifRes[1]).second; } -void nestedIfOpForLoopWithAngle(QCOProgramBuilder& b) { +Value nestedIfOpForLoopWithAngle(QCOProgramBuilder& b) { auto reg = b.allocQubitRegister(3); auto q0 = b.allocQubit(); auto theta1 = b.floatConstant(0.123); auto theta2 = b.floatConstant(0.456); auto q1 = b.h(q0); auto [q2, cond] = b.measure(q1); - b.qcoIf( + auto res = b.qcoIf( cond, {reg.value, q2}, [&](ValueRange args) { auto q3 = b.rx(theta1, args[1]); @@ -2518,6 +3483,129 @@ void nestedIfOpForLoopWithAngle(QCOProgramBuilder& b) { }); return SmallVector{scfFor[0], args[1]}; }); + return b.measure(res[1]).second; +} + +SmallVector controlledXH(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + auto [ctrl, targ] = b.ctrl(q[0], q[1], [&](Value target) { + target = b.x(target); + return b.h(target); + }); + return measureAndReturn(b, {ctrl, targ}); +} + +SmallVector controlledInverseHT(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + auto [ctrl, targ] = b.ctrl(q[0], q[1], [&](ValueRange targets) { + auto wire = b.inv({targets[0]}, [&](ValueRange innerTargets) { + auto inner = b.h(innerTargets[0]); + inner = b.t(inner); + return SmallVector{inner}; + })[0]; + return SmallVector{wire}; + }); + return measureAndReturn(b, {ctrl[0], targ[0]}); +} + +SmallVector inverseTwoRxRy(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + auto res = b.inv({q[0], q[1]}, [&](ValueRange targets) { + auto w0 = b.rx(0.2, targets[0]); + auto w1 = b.ry(0.3, targets[1]); + return SmallVector{w0, w1}; + }); + return measureAndReturn(b, res); +} + +SmallVector inverseCxThenRz(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + auto res = b.inv({q[0], q[1]}, [&](ValueRange targets) { + auto w0 = targets[0]; + auto w1 = targets[1]; + std::tie(w0, w1) = b.cx(w0, w1); + w1 = b.rz(0.4, w1); + return SmallVector{w0, w1}; + }); + return measureAndReturn(b, res); +} + +SmallVector inverseDcxThenRz(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + auto res = b.inv({q[0], q[1]}, [&](ValueRange targets) { + auto w0 = targets[0]; + auto w1 = targets[1]; + std::tie(w0, w1) = b.dcx(w0, w1); + w1 = b.rz(0.4, w1); + return SmallVector{w0, w1}; + }); + return measureAndReturn(b, res); +} + +Value inverseGphaseBarrierX(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(1); + auto res = b.inv(q[0], [&](Value target) { + b.gphase(0.25); + auto wire = b.barrier({target})[0]; + wire = b.x(wire); + return wire; + }); + return b.measure(res).second; +} + +Value inverseNestedInvHAndT(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(1); + auto res = b.inv(q[0], [&](Value target) { + auto wire = b.inv(target, [&](Value inner) { return b.h(inner); }); + return b.t(wire); + }); + return b.measure(res).second; +} + +SmallVector inverseNestedInvHAndX(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + auto res = b.inv({q[0], q[1]}, [&](ValueRange targets) { + auto w0 = b.inv(targets[0], [&](Value inner) { return b.h(inner); }); + auto w1 = b.x(targets[1]); + return SmallVector{w0, w1}; + }); + return measureAndReturn(b, res); +} + +SmallVector inverseThreeWireRxRyRz(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(3); + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange targets) { + auto w0 = b.rx(0.2, targets[0]); + auto w1 = b.ry(0.3, targets[1]); + auto w2 = b.rz(0.4, targets[2]); + return SmallVector{w0, w1, w2}; + }); + return measureAndReturn(b, res); +} + +SmallVector inverseThreeWireNestedTwoInv(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(3); + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange targets) { + auto inner = b.inv({targets[0], targets[1]}, [&](ValueRange innerTargets) { + auto w0 = b.rx(0.2, innerTargets[0]); + auto w1 = b.ry(0.3, innerTargets[1]); + return SmallVector{w0, w1}; + }); + auto w2 = b.rz(0.4, targets[2]); + return SmallVector{inner[0], inner[1], w2}; + }); + return measureAndReturn(b, res); +} + +SmallVector inverseWithThreeQubitOpInBody(QCOProgramBuilder& b) { + auto q = b.allocQubitRegister(3); + auto res = b.inv({q[0], q[1], q[2]}, [&](ValueRange targets) { + auto [controls, innerTarget] = + b.ctrl({targets[0], targets[1]}, targets[2], + [&](Value inner) { return b.x(inner); }); + return SmallVector{controls[0], controls[1], innerTarget}; + }); + return measureAndReturn(b, res); } } // namespace mlir::qco diff --git a/mlir/unittests/programs/qco_programs.h b/mlir/unittests/programs/qco_programs.h index b568b4b02f..f764e7ab09 100644 --- a/mlir/unittests/programs/qco_programs.h +++ b/mlir/unittests/programs/qco_programs.h @@ -10,1146 +10,1197 @@ #pragma once +#include +#include + namespace mlir::qco { class QCOProgramBuilder; /// Creates an empty QCO program. -void emptyQCO(QCOProgramBuilder& builder); +Value emptyQCO(QCOProgramBuilder& builder); // --- Qubit Management ----------------------------------------------------- // /// Allocates a single qubit. -void allocQubit(QCOProgramBuilder& b); +Value allocQubit(QCOProgramBuilder& b); + +/// Allocates two individual qubits. +SmallVector alloc2Qubits(QCOProgramBuilder& b); + +/// Allocates a single qubit that is not measured. +Value allocQubitNoMeasure(QCOProgramBuilder& b); + +/// Allocates a qubit register of size `1`. +Value alloc1QubitRegister(QCOProgramBuilder& b); /// Allocates a qubit register of size `2`. -void allocQubitRegister(QCOProgramBuilder& b); +SmallVector alloc2QubitRegister(QCOProgramBuilder& b); + +/// Allocates a qubit register of size `3`. +SmallVector alloc3QubitRegister(QCOProgramBuilder& b); /// Allocates two qubit registers of size `2` and `3`. -void allocMultipleQubitRegisters(QCOProgramBuilder& b); +SmallVector allocMultipleQubitRegisters(QCOProgramBuilder& b); /// Allocates a large qubit register. -void allocLargeRegister(QCOProgramBuilder& b); +Value allocLargeRegister(QCOProgramBuilder& b); /// Allocates two inline qubits. -void staticQubits(QCOProgramBuilder& b); +SmallVector staticQubits(QCOProgramBuilder& b); + +/// Allocates two inline qubits without measuring them. +Value staticQubitsNoMeasure(QCOProgramBuilder& b); /// Allocates two static qubits and applies operations. -void staticQubitsWithOps(QCOProgramBuilder& b); +SmallVector staticQubitsWithOps(QCOProgramBuilder& b); /// Allocates two static qubits and applies parametric gates. -void staticQubitsWithParametricOps(QCOProgramBuilder& b); +SmallVector staticQubitsWithParametricOps(QCOProgramBuilder& b); /// Allocates two static qubits and applies a two-target gate. -void staticQubitsWithTwoTargetOps(QCOProgramBuilder& b); +SmallVector staticQubitsWithTwoTargetOps(QCOProgramBuilder& b); /// Allocates two static qubits and applies a controlled gate. -void staticQubitsWithCtrl(QCOProgramBuilder& b); +SmallVector staticQubitsWithCtrl(QCOProgramBuilder& b); /// Allocates a static qubit and applies an inverse modifier. -void staticQubitsWithInv(QCOProgramBuilder& b); +Value staticQubitsWithInv(QCOProgramBuilder& b); /// Allocates and explicitly sinks a single qubit. -void allocSinkPair(QCOProgramBuilder& b); +Value allocSinkPair(QCOProgramBuilder& b); + +/// Allocates two qubits and performs a set of dead gates on them. +SmallVector deadGatesProgram(QCOProgramBuilder& b); + +/// Allocates two qubits and performs a set of dead gates on them, including +/// `if` operations. +Value deadGatesWithIfOpProgram(QCOProgramBuilder& b); + +/// Allocates two qubits and performs only non-dead `if` operations. +Value deadGatesWithIfOpSimplified(QCOProgramBuilder& b); // --- Invalid / mixed addressing (unit tests) -------------------------------- /// @pre `builder.initialize()`. Fatal mixed addressing: static then dynamic /// alloc. -void mixedStaticThenDynamicQubit(QCOProgramBuilder& b); +SmallVector mixedStaticThenDynamicQubit(QCOProgramBuilder& b); /// @pre `builder.initialize()`. Fatal mixed addressing: `qtensor` alloc then /// static. -void mixedDynamicRegisterThenStaticQubit(QCOProgramBuilder& b); +Value mixedDynamicRegisterThenStaticQubit(QCOProgramBuilder& b); // --- MeasureOp ------------------------------------------------------------ // /// Measures a single qubit into a single classical bit. -void singleMeasurementToSingleBit(QCOProgramBuilder& b); +Value singleMeasurementToSingleBit(QCOProgramBuilder& b); /// Repeatedly measures a single qubit into the same classical bit. -void repeatedMeasurementToSameBit(QCOProgramBuilder& b); +Value repeatedMeasurementToSameBit(QCOProgramBuilder& b); /// Repeatedly measures a single qubit into different classical bits. -void repeatedMeasurementToDifferentBits(QCOProgramBuilder& b); +SmallVector repeatedMeasurementToDifferentBits(QCOProgramBuilder& b); /// Measures multiple qubits into multiple classical bits. -void multipleClassicalRegistersAndMeasurements(QCOProgramBuilder& b); +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); +Value measurementWithoutRegisters(QCOProgramBuilder& b); // --- ResetOp -------------------------------------------------------------- // /// Resets a single qubit without any operations being applied. -void resetQubitWithoutOp(QCOProgramBuilder& b); +Value resetQubitWithoutOp(QCOProgramBuilder& b); /// Resets multiple qubits without any operations being applied. -void resetMultipleQubitsWithoutOp(QCOProgramBuilder& b); +SmallVector resetMultipleQubitsWithoutOp(QCOProgramBuilder& b); /// Repeatedly resets a single qubit without any operations being applied. -void repeatedResetWithoutOp(QCOProgramBuilder& b); +Value repeatedResetWithoutOp(QCOProgramBuilder& b); /// Resets a single qubit after a single operation. -void resetQubitAfterSingleOp(QCOProgramBuilder& b); +Value resetQubitAfterSingleOp(QCOProgramBuilder& b); /// Resets multiple qubits after a single operation. -void resetMultipleQubitsAfterSingleOp(QCOProgramBuilder& b); +SmallVector resetMultipleQubitsAfterSingleOp(QCOProgramBuilder& b); /// Repeatedly resets a single qubit after a single operation. -void repeatedResetAfterSingleOp(QCOProgramBuilder& b); +Value repeatedResetAfterSingleOp(QCOProgramBuilder& b); // --- GPhaseOp ------------------------------------------------------------- // /// Creates a circuit with just a global phase. -void globalPhase(QCOProgramBuilder& b); +Value globalPhase(QCOProgramBuilder& b); /// Creates a controlled global phase gate with a single control qubit. -void singleControlledGlobalPhase(QCOProgramBuilder& b); +Value singleControlledGlobalPhase(QCOProgramBuilder& b); /// Creates a multi-controlled global phase gate with multiple control qubits. -void multipleControlledGlobalPhase(QCOProgramBuilder& b); +SmallVector multipleControlledGlobalPhase(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a global phase gate. -void inverseGlobalPhase(QCOProgramBuilder& b); +Value inverseGlobalPhase(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled global /// phase gate. -void inverseMultipleControlledGlobalPhase(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledGlobalPhase(QCOProgramBuilder& b); // --- IdOp ----------------------------------------------------------------- // /// Creates a circuit with just an identity gate. -void identity(QCOProgramBuilder& b); +Value identity(QCOProgramBuilder& b); /// Creates a controlled identity gate with a single control qubit. -void singleControlledIdentity(QCOProgramBuilder& b); +SmallVector singleControlledIdentity(QCOProgramBuilder& b); /// Creates a multi-controlled identity gate with multiple control qubits. -void multipleControlledIdentity(QCOProgramBuilder& b); +SmallVector multipleControlledIdentity(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled identity gate. -void nestedControlledIdentity(QCOProgramBuilder& b); +SmallVector nestedControlledIdentity(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled identity gate. -void trivialControlledIdentity(QCOProgramBuilder& b); +Value trivialControlledIdentity(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an identity gate. -void inverseIdentity(QCOProgramBuilder& b); +Value inverseIdentity(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled identity /// gate. -void inverseMultipleControlledIdentity(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledIdentity(QCOProgramBuilder& b); // --- XOp ------------------------------------------------------------------ // /// Creates a circuit with just an X gate. -void x(QCOProgramBuilder& b); +Value x(QCOProgramBuilder& b); /// Creates a circuit with a single controlled X gate. -void singleControlledX(QCOProgramBuilder& b); +SmallVector singleControlledX(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled X gate. -void multipleControlledX(QCOProgramBuilder& b); +SmallVector multipleControlledX(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled X gate. -void nestedControlledX(QCOProgramBuilder& b); +SmallVector nestedControlledX(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled X gate. -void trivialControlledX(QCOProgramBuilder& b); +Value trivialControlledX(QCOProgramBuilder& b); /// Creates a circuit with repeated controlled X gates. -void repeatedControlledX(QCOProgramBuilder& b); +SmallVector repeatedControlledX(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an X gate. -void inverseX(QCOProgramBuilder& b); +Value inverseX(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled X gate. -void inverseMultipleControlledX(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledX(QCOProgramBuilder& b); /// Creates a circuit with two subsequent X gates. -void twoX(QCOProgramBuilder& b); +Value twoX(QCOProgramBuilder& b); /// Creates a circuit with a control modifier applied to two subsequent X gates. -void controlledTwoX(QCOProgramBuilder& b); +SmallVector controlledTwoX(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to two subsequent X /// gates. -void inverseTwoX(QCOProgramBuilder& b); +Value inverseTwoX(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a global phase and an /// X gate. -void inverseGphaseX(QCOProgramBuilder& b); +Value inverseGphaseX(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a global phase and a /// barrier. -void inverseGphaseBarrier(QCOProgramBuilder& b); +Value inverseGphaseBarrier(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to two consecutive /// barriers. -void inverseTwoBarriersInInv(QCOProgramBuilder& b); +Value inverseTwoBarriersInInv(QCOProgramBuilder& b); // --- YOp ------------------------------------------------------------------ // /// Creates a circuit with just a Y gate. -void y(QCOProgramBuilder& b); +Value y(QCOProgramBuilder& b); /// Creates a circuit with a single controlled Y gate. -void singleControlledY(QCOProgramBuilder& b); +SmallVector singleControlledY(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled Y gate. -void multipleControlledY(QCOProgramBuilder& b); +SmallVector multipleControlledY(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled Y gate. -void nestedControlledY(QCOProgramBuilder& b); +SmallVector nestedControlledY(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled Y gate. -void trivialControlledY(QCOProgramBuilder& b); +Value trivialControlledY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a Y gate. -void inverseY(QCOProgramBuilder& b); +Value inverseY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Y gate. -void inverseMultipleControlledY(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledY(QCOProgramBuilder& b); /// Creates a circuit with two Y gates in a row. -void twoY(QCOProgramBuilder& b); +Value twoY(QCOProgramBuilder& b); // --- ZOp ------------------------------------------------------------------ // /// Creates a circuit with just a Z gate. -void z(QCOProgramBuilder& b); +Value z(QCOProgramBuilder& b); /// Creates a circuit with a single controlled Z gate. -void singleControlledZ(QCOProgramBuilder& b); +SmallVector singleControlledZ(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled Z gate. -void multipleControlledZ(QCOProgramBuilder& b); +SmallVector multipleControlledZ(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled Z gate. -void nestedControlledZ(QCOProgramBuilder& b); +SmallVector nestedControlledZ(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled Z gate. -void trivialControlledZ(QCOProgramBuilder& b); +Value trivialControlledZ(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a Z gate. -void inverseZ(QCOProgramBuilder& b); +Value inverseZ(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Z gate. -void inverseMultipleControlledZ(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledZ(QCOProgramBuilder& b); /// Creates a circuit with two Z gates in a row. -void twoZ(QCOProgramBuilder& b); +Value twoZ(QCOProgramBuilder& b); // --- HOp ------------------------------------------------------------------ // /// Creates a circuit with just an H gate. -void h(QCOProgramBuilder& b); +Value h(QCOProgramBuilder& b); /// Creates a circuit with a single controlled H gate. -void singleControlledH(QCOProgramBuilder& b); +SmallVector singleControlledH(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled H gate. -void multipleControlledH(QCOProgramBuilder& b); +SmallVector multipleControlledH(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled H gate. -void nestedControlledH(QCOProgramBuilder& b); +SmallVector nestedControlledH(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled H gate. -void trivialControlledH(QCOProgramBuilder& b); +Value trivialControlledH(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an H gate. -void inverseH(QCOProgramBuilder& b); +Value inverseH(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled H gate. -void inverseMultipleControlledH(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledH(QCOProgramBuilder& b); /// Creates a circuit with two H gates in a row. -void twoH(QCOProgramBuilder& b); +Value twoH(QCOProgramBuilder& b); /// Creates a circuit with just an H gate and no qubit register. -void hWithoutRegister(QCOProgramBuilder& b); +Value hWithoutRegister(QCOProgramBuilder& b); // --- SOp ------------------------------------------------------------------ // /// Creates a circuit with just an S gate. -void s(QCOProgramBuilder& b); +Value s(QCOProgramBuilder& b); /// Creates a circuit with a single controlled S gate. -void singleControlledS(QCOProgramBuilder& b); +SmallVector singleControlledS(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled S gate. -void multipleControlledS(QCOProgramBuilder& b); +SmallVector multipleControlledS(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled S gate. -void nestedControlledS(QCOProgramBuilder& b); +SmallVector nestedControlledS(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled S gate. -void trivialControlledS(QCOProgramBuilder& b); +Value trivialControlledS(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an S gate. -void inverseS(QCOProgramBuilder& b); +Value inverseS(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled S gate. -void inverseMultipleControlledS(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledS(QCOProgramBuilder& b); /// Creates a circuit with an S gate followed by an Sdg gate. -void sThenSdg(QCOProgramBuilder& b); +Value sThenSdg(QCOProgramBuilder& b); /// Creates a circuit with two S gates in a row. -void twoS(QCOProgramBuilder& b); +Value twoS(QCOProgramBuilder& b); // --- SdgOp ---------------------------------------------------------------- // /// Creates a circuit with just an Sdg gate. -void sdg(QCOProgramBuilder& b); +Value sdg(QCOProgramBuilder& b); /// Creates a circuit with a single controlled Sdg gate. -void singleControlledSdg(QCOProgramBuilder& b); +SmallVector singleControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled Sdg gate. -void multipleControlledSdg(QCOProgramBuilder& b); +SmallVector multipleControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled Sdg gate. -void nestedControlledSdg(QCOProgramBuilder& b); +SmallVector nestedControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled Sdg gate. -void trivialControlledSdg(QCOProgramBuilder& b); +Value trivialControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an Sdg gate. -void inverseSdg(QCOProgramBuilder& b); +Value inverseSdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Sdg gate. -void inverseMultipleControlledSdg(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledSdg(QCOProgramBuilder& b); /// Creates a circuit with an Sdg gate followed an S gate. -void sdgThenS(QCOProgramBuilder& b); +Value sdgThenS(QCOProgramBuilder& b); /// Creates a circuit with two Sdg gates in a row. -void twoSdg(QCOProgramBuilder& b); +Value twoSdg(QCOProgramBuilder& b); // --- TOp ------------------------------------------------------------------ // /// Creates a circuit with just a T gate. -void t_(QCOProgramBuilder& b); // NOLINT(*-identifier-naming) +Value t_(QCOProgramBuilder& b); // NOLINT(*-identifier-naming) /// Creates a circuit with a single controlled T gate. -void singleControlledT(QCOProgramBuilder& b); +SmallVector singleControlledT(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled T gate. -void multipleControlledT(QCOProgramBuilder& b); +SmallVector multipleControlledT(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled T gate. -void nestedControlledT(QCOProgramBuilder& b); +SmallVector nestedControlledT(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled T gate. -void trivialControlledT(QCOProgramBuilder& b); +Value trivialControlledT(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a T gate. -void inverseT(QCOProgramBuilder& b); +Value inverseT(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled T gate. -void inverseMultipleControlledT(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledT(QCOProgramBuilder& b); /// Creates a circuit with a T gate followed by a Tdg gate. -void tThenTdg(QCOProgramBuilder& b); +Value tThenTdg(QCOProgramBuilder& b); /// Creates a circuit with two T gates in a row. -void twoT(QCOProgramBuilder& b); +Value twoT(QCOProgramBuilder& b); // --- TdgOp ---------------------------------------------------------------- // /// Creates a circuit with just a Tdg gate. -void tdg(QCOProgramBuilder& b); +Value tdg(QCOProgramBuilder& b); /// Creates a circuit with a single controlled Tdg gate. -void singleControlledTdg(QCOProgramBuilder& b); +SmallVector singleControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled Tdg gate. -void multipleControlledTdg(QCOProgramBuilder& b); +SmallVector multipleControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled Tdg gate. -void nestedControlledTdg(QCOProgramBuilder& b); +SmallVector nestedControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled Tdg gate. -void trivialControlledTdg(QCOProgramBuilder& b); +Value trivialControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a Tdg gate. -void inverseTdg(QCOProgramBuilder& b); +Value inverseTdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled Tdg gate. -void inverseMultipleControlledTdg(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledTdg(QCOProgramBuilder& b); /// Creates a circuit with a Tdg gate followed by a T gate. -void tdgThenT(QCOProgramBuilder& b); +Value tdgThenT(QCOProgramBuilder& b); /// Creates a circuit with two Tdg gates in a row. -void twoTdg(QCOProgramBuilder& b); +Value twoTdg(QCOProgramBuilder& b); // --- SXOp ----------------------------------------------------------------- // /// Creates a circuit with just an SX gate. -void sx(QCOProgramBuilder& b); +Value sx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled SX gate. -void singleControlledSx(QCOProgramBuilder& b); +SmallVector singleControlledSx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled SX gate. -void multipleControlledSx(QCOProgramBuilder& b); +SmallVector multipleControlledSx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled SX gate. -void nestedControlledSx(QCOProgramBuilder& b); +SmallVector nestedControlledSx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled SX gate. -void trivialControlledSx(QCOProgramBuilder& b); +Value trivialControlledSx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an SX gate. -void inverseSx(QCOProgramBuilder& b); +Value inverseSx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled SX gate. -void inverseMultipleControlledSx(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledSx(QCOProgramBuilder& b); /// Creates a circuit with an SX gate followed by an SXdg gate. -void sxThenSxdg(QCOProgramBuilder& b); +Value sxThenSxdg(QCOProgramBuilder& b); /// Creates a circuit with two SX gates in a row. -void twoSx(QCOProgramBuilder& b); +Value twoSx(QCOProgramBuilder& b); // --- SXdgOp --------------------------------------------------------------- // /// Creates a circuit with just an SXdg gate. -void sxdg(QCOProgramBuilder& b); +Value sxdg(QCOProgramBuilder& b); /// Creates a circuit with a single controlled SXdg gate. -void singleControlledSxdg(QCOProgramBuilder& b); +SmallVector singleControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled SXdg gate. -void multipleControlledSxdg(QCOProgramBuilder& b); +SmallVector multipleControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled SXdg gate. -void nestedControlledSxdg(QCOProgramBuilder& b); +SmallVector nestedControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled SXdg gate. -void trivialControlledSxdg(QCOProgramBuilder& b); +Value trivialControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an SXdg gate. -void inverseSxdg(QCOProgramBuilder& b); +Value inverseSxdg(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled SXdg /// gate. -void inverseMultipleControlledSxdg(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledSxdg(QCOProgramBuilder& b); /// Creates a circuit with an SXdg gate followed by an SX gate. -void sxdgThenSx(QCOProgramBuilder& b); +Value sxdgThenSx(QCOProgramBuilder& b); /// Creates a circuit with two SXdg gates in a row. -void twoSxdg(QCOProgramBuilder& b); +Value twoSxdg(QCOProgramBuilder& b); // --- RXOp ----------------------------------------------------------------- // /// Creates a circuit with just an RX gate. -void rx(QCOProgramBuilder& b); +Value rx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RX gate. -void singleControlledRx(QCOProgramBuilder& b); +SmallVector singleControlledRx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RX gate. -void multipleControlledRx(QCOProgramBuilder& b); +SmallVector multipleControlledRx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RX gate. -void nestedControlledRx(QCOProgramBuilder& b); +SmallVector nestedControlledRx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RX gate. -void trivialControlledRx(QCOProgramBuilder& b); +Value trivialControlledRx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RX gate. -void inverseRx(QCOProgramBuilder& b); +Value inverseRx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RX gate. -void inverseMultipleControlledRx(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledRx(QCOProgramBuilder& b); /// Creates a circuit with two RX gates in a row with opposite phases. -void twoRxOppositePhase(QCOProgramBuilder& b); +Value twoRxOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with an RX gate with an angle of pi/2. -void rxPiOver2(QCOProgramBuilder& b); +Value rxPiOver2(QCOProgramBuilder& b); // --- RYOp ----------------------------------------------------------------- // /// Creates a circuit with just an RY gate. -void ry(QCOProgramBuilder& b); +Value ry(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RY gate. -void singleControlledRy(QCOProgramBuilder& b); +SmallVector singleControlledRy(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RY gate. -void multipleControlledRy(QCOProgramBuilder& b); +SmallVector multipleControlledRy(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RY gate. -void nestedControlledRy(QCOProgramBuilder& b); +SmallVector nestedControlledRy(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RY gate. -void trivialControlledRy(QCOProgramBuilder& b); +Value trivialControlledRy(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RY gate. -void inverseRy(QCOProgramBuilder& b); +Value inverseRy(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RY gate. -void inverseMultipleControlledRy(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledRy(QCOProgramBuilder& b); /// Creates a circuit with two RY gates in a row with opposite phases. -void twoRyOppositePhase(QCOProgramBuilder& b); +Value twoRyOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with an RY gate with an angle of pi/2. -void ryPiOver2(QCOProgramBuilder& b); +Value ryPiOver2(QCOProgramBuilder& b); // --- RZOp ----------------------------------------------------------------- // /// Creates a circuit with just an RZ gate. -void rz(QCOProgramBuilder& b); +Value rz(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RZ gate. -void singleControlledRz(QCOProgramBuilder& b); +SmallVector singleControlledRz(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RZ gate. -void multipleControlledRz(QCOProgramBuilder& b); +SmallVector multipleControlledRz(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RZ gate. -void nestedControlledRz(QCOProgramBuilder& b); +SmallVector nestedControlledRz(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RZ gate. -void trivialControlledRz(QCOProgramBuilder& b); +Value trivialControlledRz(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RZ gate. -void inverseRz(QCOProgramBuilder& b); +Value inverseRz(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RZ gate. -void inverseMultipleControlledRz(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledRz(QCOProgramBuilder& b); /// Creates a circuit with two RZ gates in a row with opposite phases. -void twoRzOppositePhase(QCOProgramBuilder& b); +Value twoRzOppositePhase(QCOProgramBuilder& b); // --- POp ------------------------------------------------------------------ // /// Creates a circuit with just a P gate. -void p(QCOProgramBuilder& b); +Value p(QCOProgramBuilder& b); /// Creates a circuit with a single controlled P gate. -void singleControlledP(QCOProgramBuilder& b); +SmallVector singleControlledP(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled P gate. -void multipleControlledP(QCOProgramBuilder& b); +SmallVector multipleControlledP(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled P gate. -void nestedControlledP(QCOProgramBuilder& b); +SmallVector nestedControlledP(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled P gate. -void trivialControlledP(QCOProgramBuilder& b); +Value trivialControlledP(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a P gate. -void inverseP(QCOProgramBuilder& b); +Value inverseP(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled P gate. -void inverseMultipleControlledP(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledP(QCOProgramBuilder& b); /// Creates a circuit with two P gates in a row with opposite phases. -void twoPOppositePhase(QCOProgramBuilder& b); +Value twoPOppositePhase(QCOProgramBuilder& b); // --- ROp ------------------------------------------------------------------ // /// Creates a circuit with just an R gate. -void r(QCOProgramBuilder& b); +Value r(QCOProgramBuilder& b); /// Creates a circuit with a single controlled R gate. -void singleControlledR(QCOProgramBuilder& b); +SmallVector singleControlledR(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled R gate. -void multipleControlledR(QCOProgramBuilder& b); +SmallVector multipleControlledR(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled R gate. -void nestedControlledR(QCOProgramBuilder& b); +SmallVector nestedControlledR(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled R gate. -void trivialControlledR(QCOProgramBuilder& b); +Value trivialControlledR(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an R gate. -void inverseR(QCOProgramBuilder& b); +Value inverseR(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled R gate. -void inverseMultipleControlledR(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledR(QCOProgramBuilder& b); /// Creates a circuit with an R gate that can be canonicalized to an RX gate. -void canonicalizeRToRx(QCOProgramBuilder& b); +Value canonicalizeRToRx(QCOProgramBuilder& b); /// Creates a circuit with an R gate that can be canonicalized to an RY gate. -void canonicalizeRToRy(QCOProgramBuilder& b); +Value canonicalizeRToRy(QCOProgramBuilder& b); /// Creates a circuit with two R gates in a row with the same `phi`. -void twoR(QCOProgramBuilder& b); +Value twoR(QCOProgramBuilder& b); // --- U2Op ----------------------------------------------------------------- // /// Creates a circuit with just a U2 gate. -void u2(QCOProgramBuilder& b); +Value u2(QCOProgramBuilder& b); /// Creates a circuit with a single controlled U2 gate. -void singleControlledU2(QCOProgramBuilder& b); +SmallVector singleControlledU2(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled U2 gate. -void multipleControlledU2(QCOProgramBuilder& b); +SmallVector multipleControlledU2(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled U2 gate. -void nestedControlledU2(QCOProgramBuilder& b); +SmallVector nestedControlledU2(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled U2 gate. -void trivialControlledU2(QCOProgramBuilder& b); +Value trivialControlledU2(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a U2 gate. -void inverseU2(QCOProgramBuilder& b); +Value inverseU2(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled U2 gate. -void inverseMultipleControlledU2(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledU2(QCOProgramBuilder& b); /// Creates a circuit with a U2 gate that can be canonicalized to an H gate. -void canonicalizeU2ToH(QCOProgramBuilder& b); +Value canonicalizeU2ToH(QCOProgramBuilder& b); /// Creates a circuit with a U2 gate that can be canonicalized to an RX gate. -void canonicalizeU2ToRx(QCOProgramBuilder& b); +Value canonicalizeU2ToRx(QCOProgramBuilder& b); /// Creates a circuit with a U2 gate that can be canonicalized to an RY gate. -void canonicalizeU2ToRy(QCOProgramBuilder& b); +Value canonicalizeU2ToRy(QCOProgramBuilder& b); // --- UOp ------------------------------------------------------------------ // /// Creates a circuit with just a U gate. -void u(QCOProgramBuilder& b); +Value u(QCOProgramBuilder& b); /// Creates a circuit with a single controlled U gate. -void singleControlledU(QCOProgramBuilder& b); +SmallVector singleControlledU(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled U gate. -void multipleControlledU(QCOProgramBuilder& b); +SmallVector multipleControlledU(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled U gate. -void nestedControlledU(QCOProgramBuilder& b); +SmallVector nestedControlledU(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled U gate. -void trivialControlledU(QCOProgramBuilder& b); +Value trivialControlledU(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a U gate. -void inverseU(QCOProgramBuilder& b); +Value inverseU(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled U gate. -void inverseMultipleControlledU(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledU(QCOProgramBuilder& b); /// Creates a circuit with a U gate that can be canonicalized to a P gate. -void canonicalizeUToP(QCOProgramBuilder& b); +Value canonicalizeUToP(QCOProgramBuilder& b); /// Creates a circuit with a U gate that can be canonicalized to an RX gate. -void canonicalizeUToRx(QCOProgramBuilder& b); +Value canonicalizeUToRx(QCOProgramBuilder& b); /// Creates a circuit with a U gate that can be canonicalized to an RY gate. -void canonicalizeUToRy(QCOProgramBuilder& b); +Value canonicalizeUToRy(QCOProgramBuilder& b); /// Creates a circuit with a U gate that can be canonicalized to a U2 gate. -void canonicalizeUToU2(QCOProgramBuilder& b); +Value canonicalizeUToU2(QCOProgramBuilder& b); // --- SWAPOp --------------------------------------------------------------- // /// Creates a circuit with just a SWAP gate. -void swap(QCOProgramBuilder& b); +SmallVector swap(QCOProgramBuilder& b); /// Creates a circuit with a single controlled SWAP gate. -void singleControlledSwap(QCOProgramBuilder& b); +SmallVector singleControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled SWAP gate. -void multipleControlledSwap(QCOProgramBuilder& b); +SmallVector multipleControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled SWAP gate. -void nestedControlledSwap(QCOProgramBuilder& b); +SmallVector nestedControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled SWAP gate. -void trivialControlledSwap(QCOProgramBuilder& b); +SmallVector trivialControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a SWAP gate. -void inverseSwap(QCOProgramBuilder& b); +SmallVector inverseSwap(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled SWAP /// gate. -void inverseMultipleControlledSwap(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledSwap(QCOProgramBuilder& b); /// Creates a circuit with two SWAP gates in a row. -void twoSwap(QCOProgramBuilder& b); +SmallVector twoSwap(QCOProgramBuilder& b); /// Creates a circuit with two SWAP gates in a row with swapped targets. -void twoSwapSwappedTargets(QCOProgramBuilder& b); +SmallVector twoSwapSwappedTargets(QCOProgramBuilder& b); // --- iSWAPOp -------------------------------------------------------------- // /// Creates a circuit with just an iSWAP gate. -void iswap(QCOProgramBuilder& b); +SmallVector iswap(QCOProgramBuilder& b); /// Creates a circuit with a single controlled iSWAP gate. -void singleControlledIswap(QCOProgramBuilder& b); +SmallVector singleControlledIswap(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled iSWAP gate. -void multipleControlledIswap(QCOProgramBuilder& b); +SmallVector multipleControlledIswap(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled iSWAP gate. -void nestedControlledIswap(QCOProgramBuilder& b); +SmallVector nestedControlledIswap(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled iSWAP gate. -void trivialControlledIswap(QCOProgramBuilder& b); +SmallVector trivialControlledIswap(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an iSWAP gate. -void inverseIswap(QCOProgramBuilder& b); +SmallVector inverseIswap(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled iSWAP /// gate. -void inverseMultipleControlledIswap(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledIswap(QCOProgramBuilder& b); // --- DCXOp ---------------------------------------------------------------- // /// Creates a circuit with just a DCX gate. -void dcx(QCOProgramBuilder& b); +SmallVector dcx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled DCX gate. -void singleControlledDcx(QCOProgramBuilder& b); +SmallVector singleControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled DCX gate. -void multipleControlledDcx(QCOProgramBuilder& b); +SmallVector multipleControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled DCX gate. -void nestedControlledDcx(QCOProgramBuilder& b); +SmallVector nestedControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled DCX gate. -void trivialControlledDcx(QCOProgramBuilder& b); +SmallVector trivialControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a DCX gate. -void inverseDcx(QCOProgramBuilder& b); +SmallVector inverseDcx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled DCX gate. -void inverseMultipleControlledDcx(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledDcx(QCOProgramBuilder& b); /// Creates a circuit with two DCX gates in a row with identical targets. -void twoDcx(QCOProgramBuilder& b); +SmallVector twoDcx(QCOProgramBuilder& b); /// Creates a circuit with two DCX gates in a row with swapped targets. -void twoDcxSwappedTargets(QCOProgramBuilder& b); +SmallVector twoDcxSwappedTargets(QCOProgramBuilder& b); // --- ECROp ---------------------------------------------------------------- // /// Creates a circuit with just an ECR gate. -void ecr(QCOProgramBuilder& b); +SmallVector ecr(QCOProgramBuilder& b); /// Creates a circuit with a single controlled ECR gate. -void singleControlledEcr(QCOProgramBuilder& b); +SmallVector singleControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled ECR gate. -void multipleControlledEcr(QCOProgramBuilder& b); +SmallVector multipleControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled ECR gate. -void nestedControlledEcr(QCOProgramBuilder& b); +SmallVector nestedControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled ECR gate. -void trivialControlledEcr(QCOProgramBuilder& b); +SmallVector trivialControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an ECR gate. -void inverseEcr(QCOProgramBuilder& b); +SmallVector inverseEcr(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled ECR gate. -void inverseMultipleControlledEcr(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledEcr(QCOProgramBuilder& b); /// Creates a circuit with two ECR gates in a row. -void twoEcr(QCOProgramBuilder& b); +SmallVector twoEcr(QCOProgramBuilder& b); // --- RXXOp ---------------------------------------------------------------- // /// Creates a circuit with just an RXX gate. -void rxx(QCOProgramBuilder& b); +SmallVector rxx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RXX gate. -void singleControlledRxx(QCOProgramBuilder& b); +SmallVector singleControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RXX gate. -void multipleControlledRxx(QCOProgramBuilder& b); +SmallVector multipleControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RXX gate. -void nestedControlledRxx(QCOProgramBuilder& b); +SmallVector nestedControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RXX gate. -void trivialControlledRxx(QCOProgramBuilder& b); +SmallVector trivialControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RXX gate. -void inverseRxx(QCOProgramBuilder& b); +SmallVector inverseRxx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RXX gate. -void inverseMultipleControlledRxx(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a triple-controlled RXX gate. -void tripleControlledRxx(QCOProgramBuilder& b); +SmallVector tripleControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with a four-controlled RXX gate. -void fourControlledRxx(QCOProgramBuilder& b); +SmallVector fourControlledRxx(QCOProgramBuilder& b); /// Creates a circuit with two RXX gates in a row. -void twoRxx(QCOProgramBuilder& b); +SmallVector twoRxx(QCOProgramBuilder& b); /// Creates a circuit with two RXX gates in a row with swapped targets. -void twoRxxSwappedTargets(QCOProgramBuilder& b); +SmallVector twoRxxSwappedTargets(QCOProgramBuilder& b); /// Creates a circuit with two RXX gates in a row with opposite phases. -void twoRxxOppositePhase(QCOProgramBuilder& b); +SmallVector twoRxxOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with two RXX gates in a row with opposite phases and /// swapped targets. -void twoRxxOppositePhaseSwappedTargets(QCOProgramBuilder& b); +SmallVector twoRxxOppositePhaseSwappedTargets(QCOProgramBuilder& b); // --- RYYOp ---------------------------------------------------------------- // /// Creates a circuit with just an RYY gate. -void ryy(QCOProgramBuilder& b); +SmallVector ryy(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RYY gate. -void singleControlledRyy(QCOProgramBuilder& b); +SmallVector singleControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RYY gate. -void multipleControlledRyy(QCOProgramBuilder& b); +SmallVector multipleControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RYY gate. -void nestedControlledRyy(QCOProgramBuilder& b); +SmallVector nestedControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RYY gate. -void trivialControlledRyy(QCOProgramBuilder& b); +SmallVector trivialControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RYY gate. -void inverseRyy(QCOProgramBuilder& b); +SmallVector inverseRyy(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RYY gate. -void inverseMultipleControlledRyy(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledRyy(QCOProgramBuilder& b); /// Creates a circuit with two RYY gates in a row. -void twoRyy(QCOProgramBuilder& b); +SmallVector twoRyy(QCOProgramBuilder& b); /// Creates a circuit with two RYY gates in a row with swapped targets. -void twoRyySwappedTargets(QCOProgramBuilder& b); +SmallVector twoRyySwappedTargets(QCOProgramBuilder& b); /// Creates a circuit with two RYY gates in a row with opposite phases. -void twoRyyOppositePhase(QCOProgramBuilder& b); +SmallVector twoRyyOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with two RYY gates in a row with opposite phases and /// swapped targets. -void twoRyyOppositePhaseSwappedTargets(QCOProgramBuilder& b); +SmallVector twoRyyOppositePhaseSwappedTargets(QCOProgramBuilder& b); // --- RZXOp ---------------------------------------------------------------- // /// Creates a circuit with just an RZX gate. -void rzx(QCOProgramBuilder& b); +SmallVector rzx(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RZX gate. -void singleControlledRzx(QCOProgramBuilder& b); +SmallVector singleControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RZX gate. -void multipleControlledRzx(QCOProgramBuilder& b); +SmallVector multipleControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RZX gate. -void nestedControlledRzx(QCOProgramBuilder& b); +SmallVector nestedControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RZX gate. -void trivialControlledRzx(QCOProgramBuilder& b); +SmallVector trivialControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RZX gate. -void inverseRzx(QCOProgramBuilder& b); +SmallVector inverseRzx(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RZX gate. -void inverseMultipleControlledRzx(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledRzx(QCOProgramBuilder& b); /// Creates a circuit with two RZX gates in a row with opposite phases. -void twoRzxOppositePhase(QCOProgramBuilder& b); +SmallVector twoRzxOppositePhase(QCOProgramBuilder& b); // --- RZZOp ---------------------------------------------------------------- // /// Creates a circuit with just an RZZ gate. -void rzz(QCOProgramBuilder& b); +SmallVector rzz(QCOProgramBuilder& b); /// Creates a circuit with a single controlled RZZ gate. -void singleControlledRzz(QCOProgramBuilder& b); +SmallVector singleControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled RZZ gate. -void multipleControlledRzz(QCOProgramBuilder& b); +SmallVector multipleControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled RZZ gate. -void nestedControlledRzz(QCOProgramBuilder& b); +SmallVector nestedControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled RZZ gate. -void trivialControlledRzz(QCOProgramBuilder& b); +SmallVector trivialControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an RZZ gate. -void inverseRzz(QCOProgramBuilder& b); +SmallVector inverseRzz(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled RZZ gate. -void inverseMultipleControlledRzz(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledRzz(QCOProgramBuilder& b); /// Creates a circuit with two RZZ gates in a row. -void twoRzz(QCOProgramBuilder& b); +SmallVector twoRzz(QCOProgramBuilder& b); /// Creates a circuit with two RZZ gates in a row with swapped targets. -void twoRzzSwappedTargets(QCOProgramBuilder& b); +SmallVector twoRzzSwappedTargets(QCOProgramBuilder& b); /// Creates a circuit with two RZZ gates in a row with opposite phases. -void twoRzzOppositePhase(QCOProgramBuilder& b); +SmallVector twoRzzOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with two RZZ gates in a row with opposite phases and /// swapped targets. -void twoRzzOppositePhaseSwappedTargets(QCOProgramBuilder& b); +SmallVector twoRzzOppositePhaseSwappedTargets(QCOProgramBuilder& b); // --- XXPlusYYOp ----------------------------------------------------------- // /// Creates a circuit with just an XXPlusYY gate. -void xxPlusYY(QCOProgramBuilder& b); +SmallVector xxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with a single controlled XXPlusYY gate. -void singleControlledXxPlusYY(QCOProgramBuilder& b); +SmallVector singleControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled XXPlusYY gate. -void multipleControlledXxPlusYY(QCOProgramBuilder& b); +SmallVector multipleControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled XXPlusYY gate. -void nestedControlledXxPlusYY(QCOProgramBuilder& b); +SmallVector nestedControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled XXPlusYY gate. -void trivialControlledXxPlusYY(QCOProgramBuilder& b); +SmallVector trivialControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an XXPlusYY gate. -void inverseXxPlusYY(QCOProgramBuilder& b); +SmallVector inverseXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled XXPlusYY /// gate. -void inverseMultipleControlledXxPlusYY(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledXxPlusYY(QCOProgramBuilder& b); /// Creates a circuit with two XXPlusYY gates in a row with opposite phases. -void twoXxPlusYYOppositePhase(QCOProgramBuilder& b); +SmallVector twoXxPlusYYOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with two XXPlusYY gates in a row with swapped targets. -void twoXxPlusYYSwappedTargets(QCOProgramBuilder& b); +SmallVector twoXxPlusYYSwappedTargets(QCOProgramBuilder& b); // --- XXMinusYYOp ---------------------------------------------------------- // /// Creates a circuit with just an XXMinusYY gate. -void xxMinusYY(QCOProgramBuilder& b); +SmallVector xxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with a single controlled XXMinusYY gate. -void singleControlledXxMinusYY(QCOProgramBuilder& b); +SmallVector singleControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with a multi-controlled XXMinusYY gate. -void multipleControlledXxMinusYY(QCOProgramBuilder& b); +SmallVector multipleControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with a nested controlled XXMinusYY gate. -void nestedControlledXxMinusYY(QCOProgramBuilder& b); +SmallVector nestedControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with a trivial controlled XXMinusYY gate. -void trivialControlledXxMinusYY(QCOProgramBuilder& b); +SmallVector trivialControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to an XXMinusYY gate. -void inverseXxMinusYY(QCOProgramBuilder& b); +SmallVector inverseXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a controlled XXMinusYY /// gate. -void inverseMultipleControlledXxMinusYY(QCOProgramBuilder& b); +SmallVector inverseMultipleControlledXxMinusYY(QCOProgramBuilder& b); /// Creates a circuit with two XXMinusYY gates in a row with opposite phases. -void twoXxMinusYYOppositePhase(QCOProgramBuilder& b); +SmallVector twoXxMinusYYOppositePhase(QCOProgramBuilder& b); /// Creates a circuit with two XXMinusYY gates in a row with swapped targets. -void twoXxMinusYYSwappedTargets(QCOProgramBuilder& b); +SmallVector twoXxMinusYYSwappedTargets(QCOProgramBuilder& b); // --- BarrierOp ------------------------------------------------------------ // /// Creates a circuit with a barrier. -void barrier(QCOProgramBuilder& b); +Value barrier(QCOProgramBuilder& b); /// Creates a circuit with a barrier on two qubits. -void barrierTwoQubits(QCOProgramBuilder& b); +SmallVector barrierTwoQubits(QCOProgramBuilder& b); /// Creates a circuit with a barrier on multiple qubits. -void barrierMultipleQubits(QCOProgramBuilder& b); +SmallVector barrierMultipleQubits(QCOProgramBuilder& b); /// Creates a circuit with a single controlled barrier. -void singleControlledBarrier(QCOProgramBuilder& b); +Value singleControlledBarrier(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a barrier. -void inverseBarrier(QCOProgramBuilder& b); +Value inverseBarrier(QCOProgramBuilder& b); /// Creates a circuit with two barriers in a row with overlapping qubits. -void twoBarrier(QCOProgramBuilder& b); +SmallVector twoBarrier(QCOProgramBuilder& b); // --- CtrlOp --------------------------------------------------------------- // /// Creates a circuit with a trivial ctrl modifier. -void trivialCtrl(QCOProgramBuilder& b); +SmallVector trivialCtrl(QCOProgramBuilder& b); /// Creates a circuit with an empty ctrl modifier. -void emptyCtrl(QCOProgramBuilder& b); +SmallVector emptyCtrl(QCOProgramBuilder& b); /// Creates a circuit with nested ctrl modifiers. -void nestedCtrl(QCOProgramBuilder& b); +SmallVector nestedCtrl(QCOProgramBuilder& b); /// Creates a circuit with triple nested ctrl modifiers. -void tripleNestedCtrl(QCOProgramBuilder& b); +SmallVector tripleNestedCtrl(QCOProgramBuilder& b); /// Creates a circuit with double nested ctrl modifiers with two qubits each. -void doubleNestedCtrlTwoQubits(QCOProgramBuilder& b); +SmallVector doubleNestedCtrlTwoQubits(QCOProgramBuilder& b); /// Creates a circuit with control modifiers interleaved by an inverse modifier. -void ctrlInvSandwich(QCOProgramBuilder& b); +SmallVector ctrlInvSandwich(QCOProgramBuilder& b); /// Creates a circuit with a control modifier applied to two gates. -void ctrlTwo(QCOProgramBuilder& b); +SmallVector ctrlTwo(QCOProgramBuilder& b); /// Creates a circuit with a control modifier applied to a controlled and a /// non-controlled gate. -void ctrlTwoMixed(QCOProgramBuilder& b); +SmallVector ctrlTwoMixed(QCOProgramBuilder& b); /// Creates a circuit with nested control modifiers applied to two gates. -void nestedCtrlTwo(QCOProgramBuilder& b); +SmallVector nestedCtrlTwo(QCOProgramBuilder& b); /// Creates a circuit with a control modifier applied to an inverse modifier /// applied to two gates. -void ctrlInvTwo(QCOProgramBuilder& b); +SmallVector ctrlInvTwo(QCOProgramBuilder& b); // --- InvOp ---------------------------------------------------------------- // /// Creates a circuit with an empty inverse modifier. -void emptyInv(QCOProgramBuilder& b); +SmallVector emptyInv(QCOProgramBuilder& b); /// Creates a circuit with nested inverse modifiers. -void nestedInv(QCOProgramBuilder& b); +SmallVector nestedInv(QCOProgramBuilder& b); /// Creates a circuit with triple nested inverse modifiers. -void tripleNestedInv(QCOProgramBuilder& b); +SmallVector tripleNestedInv(QCOProgramBuilder& b); /// Creates a circuit with inverse modifiers interleaved by a control modifier. -void invCtrlSandwich(QCOProgramBuilder& b); +SmallVector invCtrlSandwich(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to two gates. -void invTwo(QCOProgramBuilder& b); +SmallVector invTwo(QCOProgramBuilder& b); /// Creates a circuit with an inverse modifier applied to a control modifier /// applied to two gates. -void invCtrlTwo(QCOProgramBuilder& b); +SmallVector invCtrlTwo(QCOProgramBuilder& b); // --- IfOp ---------------------------------------------------------------- // /// Creates a circuit with a simple if operation with one qubit. -void simpleIf(QCOProgramBuilder& b); +SmallVector simpleIf(QCOProgramBuilder& b); /// Creates a circuit with an if operation with a parameterized gate. -void ifWithAngle(QCOProgramBuilder& b); +Value ifWithAngle(QCOProgramBuilder& b); /// Creates a circuit with an if operation with two qubits. -void ifTwoQubits(QCOProgramBuilder& b); +SmallVector ifTwoQubits(QCOProgramBuilder& b); /// Creates a circuit with an if operation with an else branch. -void ifElse(QCOProgramBuilder& b); +SmallVector ifElse(QCOProgramBuilder& b); /// Creates a circuit with an if operation with one qubit and one register. -void ifOneQubitOneTensor(QCOProgramBuilder& b); +Value ifOneQubitOneTensor(QCOProgramBuilder& b); /// Creates a circuit with an if operation that uses a constant true as /// condition. -void constantTrueIf(QCOProgramBuilder& b); +Value constantTrueIf(QCOProgramBuilder& b); /// Creates a circuit with an if operation that uses a constant false as /// condition. -void constantFalseIf(QCOProgramBuilder& b); +Value constantFalseIf(QCOProgramBuilder& b); /// Creates a circuit with a nested if operation in the then branch that uses /// the same condition. -void nestedTrueIf(QCOProgramBuilder& b); +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); +SmallVector nestedFalseIf(QCOProgramBuilder& b); /// Creates a circuit with an if operation with a nested for operation with /// a register. -void nestedIfOpForLoop(QCOProgramBuilder& b); +Value nestedIfOpForLoop(QCOProgramBuilder& b); /// Creates a circuit with an if operation with a nested for operation and /// parameterized gates. -void nestedIfOpForLoopWithAngle(QCOProgramBuilder& b); +Value nestedIfOpForLoopWithAngle(QCOProgramBuilder& b); // --- WhileOp -------------------------------------------------------------- // /// Creates a circuit with a while operation using a while loop. -void simpleWhileReset(QCOProgramBuilder& b); +Value simpleWhileReset(QCOProgramBuilder& b); /// Creates a circuit with a while operation using a do-while loop. -void simpleDoWhileReset(QCOProgramBuilder& b); +Value simpleDoWhileReset(QCOProgramBuilder& b); // --- ForOp ---------------------------------------------------------------- // /// Creates a circuit with a simple for operation with a register. -void simpleForLoop(QCOProgramBuilder& b); +SmallVector simpleForLoop(QCOProgramBuilder& b); /// Creates a circuit with a for operation with a parameterized gate. -void forLoopWithAngle(QCOProgramBuilder& b); +Value forLoopWithAngle(QCOProgramBuilder& b); /// Creates a circuit with a for operation with a register and a qubit and a /// nested if operation. -void nestedForLoopIfOp(QCOProgramBuilder& b); +Value nestedForLoopIfOp(QCOProgramBuilder& b); /// Creates a circuit with a for operation with a register and a nested while /// operation. -void nestedForLoopWhileOp(QCOProgramBuilder& b); +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); +Value 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); +Value nestedForLoopCtrlOpWithExtractedQubit(QCOProgramBuilder& b); // --- QTensor Operations -------------------------------------------------- // /// Allocates a tensor of size `3`. -void qtensorAlloc(QCOProgramBuilder& b); +SmallVector qtensorAlloc(QCOProgramBuilder& b); /// Allocates and explicitly deallocates a tensor. -void qtensorDealloc(QCOProgramBuilder& b); +SmallVector qtensorDealloc(QCOProgramBuilder& b); /// Constructs a tensor with from_elements. -void qtensorFromElements(QCOProgramBuilder& b); +SmallVector qtensorFromElements(QCOProgramBuilder& b); /// Extracts a qubit from a tensor. -void qtensorExtract(QCOProgramBuilder& b); +Value qtensorExtract(QCOProgramBuilder& b); /// Inserts a qubit into a tensor. -void qtensorInsert(QCOProgramBuilder& b); +SmallVector qtensorInsert(QCOProgramBuilder& b); /// Extracts a qubit from a tensor and inserts it immediately at a different /// index. -void qtensorExtractInsertIndexMismatch(QCOProgramBuilder& b); +SmallVector qtensorExtractInsertIndexMismatch(QCOProgramBuilder& b); /// Extracts a qubit from a tensor and inserts it immediately at the same index. -void qtensorExtractInsertSameIndex(QCOProgramBuilder& b); +SmallVector qtensorExtractInsertSameIndex(QCOProgramBuilder& b); /// Inserts a qubit into a tensor and extracts it immediately at a different /// index. -void qtensorInsertExtractIndexMismatch(QCOProgramBuilder& b); +SmallVector qtensorInsertExtractIndexMismatch(QCOProgramBuilder& b); /// Inserts a qubit into a tensor and extracts it immediately at the same index. -void qtensorInsertExtractSameIndex(QCOProgramBuilder& b); +SmallVector qtensorInsertExtractSameIndex(QCOProgramBuilder& b); /// Extracts three qubits with ascending index (0, 1, 2), performs a /// computation, and finally inserts the qubits in ascending order (0, 1, 2). -void qtensorChain(QCOProgramBuilder& b); +SmallVector qtensorChain(QCOProgramBuilder& b); /// Performs the same computation as the `qtensorChain` function, but uses /// qubits immediately after the extract and inserts the qubits in descending /// order (2, 1, 0). -void qtensorAlternativeChain(QCOProgramBuilder& b); +SmallVector qtensorAlternativeChain(QCOProgramBuilder& b); + +SmallVector controlledXH(QCOProgramBuilder& b); + +SmallVector controlledInverseHT(QCOProgramBuilder& b); + +SmallVector inverseTwoRxRy(QCOProgramBuilder& b); + +SmallVector inverseCxThenRz(QCOProgramBuilder& b); + +SmallVector inverseDcxThenRz(QCOProgramBuilder& b); + +Value inverseGphaseBarrierX(QCOProgramBuilder& b); + +Value inverseNestedInvHAndT(QCOProgramBuilder& b); + +SmallVector inverseNestedInvHAndX(QCOProgramBuilder& b); + +SmallVector inverseThreeWireRxRyRz(QCOProgramBuilder& b); + +SmallVector inverseThreeWireNestedTwoInv(QCOProgramBuilder& b); + +SmallVector inverseWithThreeQubitOpInBody(QCOProgramBuilder& b); } // namespace mlir::qco diff --git a/mlir/unittests/programs/qir_programs.cpp b/mlir/unittests/programs/qir_programs.cpp index 948a74b889..1eb9efae9e 100644 --- a/mlir/unittests/programs/qir_programs.cpp +++ b/mlir/unittests/programs/qir_programs.cpp @@ -12,22 +12,77 @@ #include "mlir/Dialect/QIR/Builder/QIRProgramBuilder.h" +#include + +#include #include namespace mlir::qir { -void emptyQIR([[maybe_unused]] QIRProgramBuilder& builder) {} +/** + * @brief Measures the given qubits, records the outcomes and returns + * a single `i64` exit code with the value 0. + * @param b The QIRProgramBuilder used to perform the measurements and create + * the struct. + * @param qubits The qubits to be measured. + * @param inRegister Whether to store the results in a classical result array or + * not. + * @param startIndex The starting index for measurement outcomes. + * @return The result value. + */ +static Value measureAndRecord(QIRProgramBuilder& b, ValueRange qubits, + bool inRegister, int64_t startIndex = 0) { + + if (qubits.empty()) { + return b.intConstant(0); + } + QIRProgramBuilder::ClassicalRegister resultArray; + if (inRegister) { + resultArray = b.allocClassicalBitRegister( + static_cast(qubits.size()), "meas"); + } -void allocQubit(QIRProgramBuilder& b) { b.allocQubitRegister(1); } + for (auto i = 0L; i < qubits.size(); ++i) { + inRegister ? b.measure(qubits[i], resultArray[i]) + : b.measure(qubits[i], startIndex + i); + } + + return b.intConstant(0); +} -void allocQubitRegister(QIRProgramBuilder& b) { b.allocQubitRegister(2); } +template Value emptyQIR(QIRProgramBuilder& b) { + return measureAndRecord(b, {}, IntoRegister); +} + +template Value allocQubit(QIRProgramBuilder& b) { + auto q = b.allocQubit(); + return measureAndRecord(b, {q}, IntoRegister); +} + +template Value alloc1QubitRegister(QIRProgramBuilder& b) { + auto q = b.allocQubitRegister(1); + return measureAndRecord(b, q.qubits, IntoRegister); +} + +template Value allocQubitRegister(QIRProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + return measureAndRecord(b, q.qubits, IntoRegister); +} + +template Value alloc3QubitRegister(QIRProgramBuilder& b) { + auto q = b.allocQubitRegister(3); + return measureAndRecord(b, q.qubits, IntoRegister); +} -void allocMultipleQubitRegisters(QIRProgramBuilder& b) { - b.allocQubitRegister(2); - b.allocQubitRegister(3); +template +Value allocMultipleQubitRegisters(QIRProgramBuilder& b) { + auto q0 = b.allocQubitRegister(2); + auto q1 = b.allocQubitRegister(3); + return measureAndRecord(b, {q0[0], q0[1], q1[0], q1[1], q1[2]}, IntoRegister); } -void allocMultipleQubitRegistersWithOps(QIRProgramBuilder& b) { +template +Value allocMultipleQubitRegistersWithOps(QIRProgramBuilder& b) { auto q0 = b.allocQubitRegister(2); auto q1 = b.allocQubitRegister(3); b.h(q0[0]); @@ -35,47 +90,57 @@ void allocMultipleQubitRegistersWithOps(QIRProgramBuilder& b) { b.h(q1[0]); b.h(q1[1]); b.h(q1[2]); + return measureAndRecord(b, {q0[0], q0[1], q1[0], q1[1], q1[2]}, IntoRegister); } -void allocLargeRegister(QIRProgramBuilder& b) { b.allocQubitRegister(100); } +template Value allocLargeRegister(QIRProgramBuilder& b) { + auto q = b.allocQubitRegister(100); + return measureAndRecord(b, {q[0], q[99]}, IntoRegister); +} -void staticQubits(QIRProgramBuilder& b) { - b.staticQubit(0); - b.staticQubit(1); +Value staticQubits(QIRProgramBuilder& b) { + auto q0 = b.staticQubit(0); + auto q1 = b.staticQubit(1); + return measureAndRecord(b, {q0, q1}, false); } -void staticQubitsWithOps(QIRProgramBuilder& b) { +Value staticQubitsWithOps(QIRProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); b.h(q0); b.h(q1); + return measureAndRecord(b, {q0, q1}, false); } -void staticQubitsWithParametricOps(QIRProgramBuilder& b) { +Value staticQubitsWithParametricOps(QIRProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); b.rx(std::numbers::pi / 4., q0); b.p(std::numbers::pi / 2., q1); + return measureAndRecord(b, {q0, q1}, false); } -void staticQubitsWithTwoTargetOps(QIRProgramBuilder& b) { +Value staticQubitsWithTwoTargetOps(QIRProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); b.rzz(0.123, q0, q1); + return measureAndRecord(b, {q0, q1}, false); } -void staticQubitsWithCtrl(QIRProgramBuilder& b) { +Value staticQubitsWithCtrl(QIRProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); b.cx(q0, q1); + return measureAndRecord(b, {q0, q1}, false); } -void staticQubitsWithInv(QIRProgramBuilder& b) { +Value staticQubitsWithInv(QIRProgramBuilder& b) { auto q0 = b.staticQubit(0); b.tdg(q0); + return measureAndRecord(b, {q0}, false); } -void staticQubitsWithDuplicates(QIRProgramBuilder& b) { +Value staticQubitsWithDuplicates(QIRProgramBuilder& b) { auto q0a = b.staticQubit(0); auto q1a = b.staticQubit(1); auto q0b = b.staticQubit(0); @@ -85,9 +150,10 @@ void staticQubitsWithDuplicates(QIRProgramBuilder& b) { b.rzz(0.123, q0b, q1b); b.cx(q0b, q1b); b.tdg(q0a); + return measureAndRecord(b, {q0b, q1b}, false); } -void staticQubitsCanonical(QIRProgramBuilder& b) { +Value staticQubitsCanonical(QIRProgramBuilder& b) { auto q0 = b.staticQubit(0); auto q1 = b.staticQubit(1); b.rx(std::numbers::pi / 4., q0); @@ -95,541 +161,679 @@ void staticQubitsCanonical(QIRProgramBuilder& b) { b.rzz(0.123, q0, q1); b.cx(q0, q1); b.tdg(q0); + return measureAndRecord(b, {q0, q1}, false); } -void mixedStaticThenDynamicQubit(QIRProgramBuilder& b) { - b.staticQubit(0); - b.allocQubit(); +Value mixedStaticThenDynamicQubit(QIRProgramBuilder& b) { + auto q0 = b.staticQubit(0); + auto q1 = b.allocQubit(); + return measureAndRecord(b, {q0, q1}, false); } -void mixedDynamicRegisterThenStaticQubit(QIRProgramBuilder& b) { - b.allocQubitRegister(2); - b.staticQubit(0); +Value mixedDynamicRegisterThenStaticQubit(QIRProgramBuilder& b) { + auto q0 = b.allocQubitRegister(2); + auto q1 = b.staticQubit(0); + return measureAndRecord(b, {q0[0], q0[1], q1}, false); } -void singleMeasurementToSingleBit(QIRProgramBuilder& b) { +template +Value singleMeasurementToSingleBit(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto c = b.allocClassicalBitRegister(1); b.measure(q[0], c[0]); + return b.intConstant(0); } -void repeatedMeasurementToSameBit(QIRProgramBuilder& b) { +template +Value repeatedMeasurementToSameBit(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto c = b.allocClassicalBitRegister(1); b.measure(q[0], c[0]); b.measure(q[0], c[0]); b.measure(q[0], c[0]); + return b.intConstant(0); } -void repeatedMeasurementToDifferentBits(QIRProgramBuilder& b) { +template +Value repeatedMeasurementToDifferentBits(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); const auto c = b.allocClassicalBitRegister(3); b.measure(q[0], c[0]); b.measure(q[0], c[1]); b.measure(q[0], c[2]); + return b.intConstant(0); } -void multipleClassicalRegistersAndMeasurements(QIRProgramBuilder& b) { +template +Value multipleClassicalRegistersAndMeasurements(QIRProgramBuilder& 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]); + return b.intConstant(0); } -void measurementWithoutRegisters(QIRProgramBuilder& b) { +template +Value measurementWithoutRegisters(QIRProgramBuilder& b) { auto q = b.allocQubit(); - b.measure(q, 0); + auto bit = b.measure(q, 0); + return b.intConstant(0); } -void resetQubitWithoutOp(QIRProgramBuilder& b) { +template Value resetQubitWithoutOp(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.reset(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void resetMultipleQubitsWithoutOp(QIRProgramBuilder& b) { +template +Value resetMultipleQubitsWithoutOp(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.reset(q[0]); b.reset(q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void repeatedResetWithoutOp(QIRProgramBuilder& b) { +template +Value repeatedResetWithoutOp(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.reset(q[0]); b.reset(q[0]); b.reset(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void resetQubitAfterSingleOp(QIRProgramBuilder& b) { +template +Value resetQubitAfterSingleOp(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.h(q[0]); b.reset(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void resetMultipleQubitsAfterSingleOp(QIRProgramBuilder& b) { +template +Value resetMultipleQubitsAfterSingleOp(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.h(q[0]); b.reset(q[0]); b.h(q[1]); b.reset(q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void repeatedResetAfterSingleOp(QIRProgramBuilder& b) { +template +Value repeatedResetAfterSingleOp(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.h(q[0]); b.reset(q[0]); b.reset(q[0]); b.reset(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void globalPhase(QIRProgramBuilder& b) { b.gphase(0.123); } +template Value globalPhase(QIRProgramBuilder& b) { + b.gphase(0.123); + return measureAndRecord(b, {}, IntoRegister); +} -void identity(QIRProgramBuilder& b) { +template Value identity(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.id(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledIdentity(QIRProgramBuilder& b) { +template +Value singleControlledIdentity(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cid(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledIdentity(QIRProgramBuilder& b) { +template Value twoQubitsOneIdentity(QIRProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + b.id(q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); +} + +template +Value threeQubitsOneIdentity(QIRProgramBuilder& b) { + auto q = b.allocQubitRegister(3); + b.id(q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); +} + +template +Value multipleControlledIdentity(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcid({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void x(QIRProgramBuilder& b) { +template Value x(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.x(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledX(QIRProgramBuilder& b) { +template Value singleControlledX(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cx(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledX(QIRProgramBuilder& b) { +template Value multipleControlledX(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcx({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void y(QIRProgramBuilder& b) { +template Value y(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.y(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledY(QIRProgramBuilder& b) { +template Value singleControlledY(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cy(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledY(QIRProgramBuilder& b) { +template Value multipleControlledY(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcy({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void z(QIRProgramBuilder& b) { +template Value z(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.z(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledZ(QIRProgramBuilder& b) { +template Value singleControlledZ(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cz(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledZ(QIRProgramBuilder& b) { +template Value multipleControlledZ(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcz({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void h(QIRProgramBuilder& b) { +template Value h(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.h(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledH(QIRProgramBuilder& b) { +template Value singleControlledH(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ch(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledH(QIRProgramBuilder& b) { +template Value multipleControlledH(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mch({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void hWithoutRegister(QIRProgramBuilder& b) { +template Value hWithoutRegister(QIRProgramBuilder& b) { auto q = b.allocQubit(); b.h(q); + return measureAndRecord(b, {q}, false); } -void s(QIRProgramBuilder& b) { +template Value s(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.s(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledS(QIRProgramBuilder& b) { +template Value singleControlledS(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cs(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledS(QIRProgramBuilder& b) { +template Value multipleControlledS(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcs({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void sdg(QIRProgramBuilder& b) { +template Value sdg(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.sdg(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledSdg(QIRProgramBuilder& b) { +template Value singleControlledSdg(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.csdg(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledSdg(QIRProgramBuilder& b) { +template Value multipleControlledSdg(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcsdg({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void t_(QIRProgramBuilder& b) { +template +Value t_(QIRProgramBuilder& b) { // NOLINT(*-identifier-naming) auto q = b.allocQubitRegister(1); b.t(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledT(QIRProgramBuilder& b) { +template Value singleControlledT(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ct(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledT(QIRProgramBuilder& b) { +template Value multipleControlledT(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mct({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void tdg(QIRProgramBuilder& b) { +template Value tdg(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.tdg(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledTdg(QIRProgramBuilder& b) { +template Value singleControlledTdg(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ctdg(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledTdg(QIRProgramBuilder& b) { +template Value multipleControlledTdg(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mctdg({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void sx(QIRProgramBuilder& b) { +template Value sx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.sx(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledSx(QIRProgramBuilder& b) { +template Value singleControlledSx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.csx(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledSx(QIRProgramBuilder& b) { +template Value multipleControlledSx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcsx({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void sxdg(QIRProgramBuilder& b) { +template Value sxdg(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.sxdg(q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledSxdg(QIRProgramBuilder& b) { +template Value singleControlledSxdg(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.csxdg(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledSxdg(QIRProgramBuilder& b) { +template +Value multipleControlledSxdg(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcsxdg({q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void rx(QIRProgramBuilder& b) { +template Value rx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.rx(0.123, q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledRx(QIRProgramBuilder& b) { +template Value singleControlledRx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.crx(0.123, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledRx(QIRProgramBuilder& b) { +template Value multipleControlledRx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcrx(0.123, {q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void ry(QIRProgramBuilder& b) { +template Value ry(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.ry(0.456, q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledRy(QIRProgramBuilder& b) { +template Value singleControlledRy(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cry(0.456, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledRy(QIRProgramBuilder& b) { +template Value multipleControlledRy(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcry(0.456, {q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void rz(QIRProgramBuilder& b) { +template Value rz(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.rz(0.789, q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledRz(QIRProgramBuilder& b) { +template Value singleControlledRz(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.crz(0.789, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledRz(QIRProgramBuilder& b) { +template Value multipleControlledRz(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcrz(0.789, {q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void p(QIRProgramBuilder& b) { +template Value p(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.p(0.123, q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledP(QIRProgramBuilder& b) { +template Value singleControlledP(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cp(0.123, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledP(QIRProgramBuilder& b) { +template Value multipleControlledP(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcp(0.123, {q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void r(QIRProgramBuilder& b) { +template Value r(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.r(0.123, 0.456, q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledR(QIRProgramBuilder& b) { +template Value singleControlledR(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cr(0.123, 0.456, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledR(QIRProgramBuilder& b) { +template Value multipleControlledR(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcr(0.123, 0.456, {q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void u2(QIRProgramBuilder& b) { +template Value u2(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.u2(0.234, 0.567, q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledU2(QIRProgramBuilder& b) { +template Value singleControlledU2(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cu2(0.234, 0.567, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledU2(QIRProgramBuilder& b) { +template Value multipleControlledU2(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcu2(0.234, 0.567, {q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void u(QIRProgramBuilder& b) { +template Value u(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.u(0.1, 0.2, 0.3, q[0]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledU(QIRProgramBuilder& b) { +template Value singleControlledU(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.cu(0.1, 0.2, 0.3, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledU(QIRProgramBuilder& b) { +template Value multipleControlledU(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.mcu(0.1, 0.2, 0.3, {q[0], q[1]}, q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void swap(QIRProgramBuilder& b) { +template Value swap(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.swap(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledSwap(QIRProgramBuilder& b) { +template Value singleControlledSwap(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cswap(q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledSwap(QIRProgramBuilder& b) { +template +Value multipleControlledSwap(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcswap({q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void iswap(QIRProgramBuilder& b) { +template Value iswap(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.iswap(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledIswap(QIRProgramBuilder& b) { +template Value singleControlledIswap(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.ciswap(q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledIswap(QIRProgramBuilder& b) { +template +Value multipleControlledIswap(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mciswap({q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void dcx(QIRProgramBuilder& b) { +template Value dcx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.dcx(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledDcx(QIRProgramBuilder& b) { +template Value singleControlledDcx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cdcx(q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledDcx(QIRProgramBuilder& b) { +template Value multipleControlledDcx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcdcx({q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void ecr(QIRProgramBuilder& b) { +template Value ecr(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ecr(q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledEcr(QIRProgramBuilder& b) { +template Value singleControlledEcr(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cecr(q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledEcr(QIRProgramBuilder& b) { +template Value multipleControlledEcr(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcecr({q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void rxx(QIRProgramBuilder& b) { +template Value rxx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.rxx(0.123, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledRxx(QIRProgramBuilder& b) { +template Value singleControlledRxx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.crxx(0.123, q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledRxx(QIRProgramBuilder& b) { +template Value multipleControlledRxx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcrxx(0.123, {q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void tripleControlledRxx(QIRProgramBuilder& b) { +template Value tripleControlledRxx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(5); b.mcrxx(0.123, {q[0], q[1], q[2]}, q[3], q[4]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void ryy(QIRProgramBuilder& b) { +template Value ryy(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.ryy(0.123, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledRyy(QIRProgramBuilder& b) { +template Value singleControlledRyy(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cryy(0.123, q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledRyy(QIRProgramBuilder& b) { +template Value multipleControlledRyy(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcryy(0.123, {q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void rzx(QIRProgramBuilder& b) { +template Value rzx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.rzx(0.123, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledRzx(QIRProgramBuilder& b) { +template Value singleControlledRzx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.crzx(0.123, q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledRzx(QIRProgramBuilder& b) { +template Value multipleControlledRzx(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcrzx(0.123, {q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void rzz(QIRProgramBuilder& b) { +template Value rzz(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.rzz(0.123, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledRzz(QIRProgramBuilder& b) { +template Value singleControlledRzz(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.crzz(0.123, q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledRzz(QIRProgramBuilder& b) { +template Value multipleControlledRzz(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcrzz(0.123, {q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void xxPlusYY(QIRProgramBuilder& b) { +template Value xxPlusYY(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.xx_plus_yy(0.123, 0.456, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledXxPlusYY(QIRProgramBuilder& b) { +template +Value singleControlledXxPlusYY(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cxx_plus_yy(0.123, 0.456, q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledXxPlusYY(QIRProgramBuilder& b) { +template +Value multipleControlledXxPlusYY(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcxx_plus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void xxMinusYY(QIRProgramBuilder& b) { +template Value xxMinusYY(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.xx_minus_yy(0.123, 0.456, q[0], q[1]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void singleControlledXxMinusYY(QIRProgramBuilder& b) { +template +Value singleControlledXxMinusYY(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(3); b.cxx_minus_yy(0.123, 0.456, q[0], q[1], q[2]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void multipleControlledXxMinusYY(QIRProgramBuilder& b) { +template +Value multipleControlledXxMinusYY(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcxx_minus_yy(0.123, 0.456, {q[0], q[1]}, q[2], q[3]); + return measureAndRecord(b, q.qubits, IntoRegister); } -void simpleIf(QIRProgramBuilder& b) { +template Value simpleIf(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.h(q[0]); auto cond = b.measure(q[0], 0); b.scfIf(cond, [&] { b.x(q[0]); }); + return measureAndRecord(b, q.qubits, IntoRegister, 1); } -void ifElse(QIRProgramBuilder& b) { +template Value ifElse(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(1); b.h(q[0]); auto cond = b.measure(q[0], 0); b.scfIf(cond, [&] { b.x(q[0]); }, [&] { b.z(q[0]); }); + return measureAndRecord(b, q.qubits, IntoRegister, 1); } -void ifTwoQubits(QIRProgramBuilder& b) { +template Value ifTwoQubits(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(2); b.h(q[0]); auto cond = b.measure(q[0], 0); @@ -637,13 +841,14 @@ void ifTwoQubits(QIRProgramBuilder& b) { b.x(q[0]); b.x(q[1]); }); + return measureAndRecord(b, q.qubits, IntoRegister, 1); } -void nestedIfOpForLoop(QIRProgramBuilder& b) { +template Value nestedIfOpForLoop(QIRProgramBuilder& b) { auto reg = b.allocQubitRegister(3); auto q0 = b.allocQubit(); b.h(q0); - auto cond = b.measure(q0, 0); + auto cond = b.measure(q0, 0, false); b.scfIf( cond, [&] { b.h(q0); }, [&] { @@ -652,50 +857,55 @@ void nestedIfOpForLoop(QIRProgramBuilder& b) { b.h(q1); }); }); + return measureAndRecord(b, {q0}, IntoRegister, 1); } -void simpleWhileReset(QIRProgramBuilder& b) { +template Value simpleWhileReset(QIRProgramBuilder& b) { auto q = b.allocQubit(); b.h(q); b.scfWhile( [&] { - auto measureResult = b.measure(q, 0); + auto measureResult = b.measure(q, 0, false); return measureResult; }, [&] { b.h(q); }); + return measureAndRecord(b, {q}, IntoRegister, 1); } -void simpleDoWhileReset(QIRProgramBuilder& b) { +template Value simpleDoWhileReset(QIRProgramBuilder& b) { auto q = b.allocQubit(); b.scfWhile([&] { b.h(q); - auto measureResult = b.measure(q, 0); + auto measureResult = b.measure(q, 0, false); return measureResult; }); + return measureAndRecord(b, {q}, IntoRegister, 1); } -void simpleForLoop(QIRProgramBuilder& b) { +template Value simpleForLoop(QIRProgramBuilder& b) { auto reg = b.allocQubitRegister(2); b.scfFor(0, 2, 1, [&](Value iv) { auto q = b.load(reg.value, iv); b.h(q); }); + return measureAndRecord(b, reg.qubits, IntoRegister); }; -void nestedForLoopIfOp(QIRProgramBuilder& b) { +template Value nestedForLoopIfOp(QIRProgramBuilder& b) { auto reg = b.allocQubitRegister(2); auto qCond = b.allocQubit(); b.scfFor(0, 2, 1, [&](Value iv) { b.h(qCond); - auto cond = b.measure(qCond, 0); + auto cond = b.measure(qCond, 0, false); b.scfIf(cond, [&] { auto q = b.load(reg.value, iv); b.h(q); }); }); + return measureAndRecord(b, {qCond}, IntoRegister, 1); } -void nestedForLoopWhileOp(QIRProgramBuilder& b) { +template Value nestedForLoopWhileOp(QIRProgramBuilder& b) { auto reg = b.allocQubitRegister(2); b.scfFor(0, 2, 1, [&](Value iv) { auto q = b.load(reg.value, iv); @@ -705,14 +915,16 @@ void nestedForLoopWhileOp(QIRProgramBuilder& b) { auto q = b.load(reg.value, iv); b.scfWhile( [&] { - auto measureResult = b.measure(q, 0); + auto measureResult = b.measure(q, 0, false); return measureResult; }, [&] { b.h(q); }); }); + return measureAndRecord(b, reg.qubits, IntoRegister, 1); } -void nestedForLoopCtrlOpWithSeparateQubit(QIRProgramBuilder& b) { +template +Value nestedForLoopCtrlOpWithSeparateQubit(QIRProgramBuilder& b) { auto reg = b.allocQubitRegister(3); auto control = b.allocQubit(); b.h(control); @@ -721,9 +933,11 @@ void nestedForLoopCtrlOpWithSeparateQubit(QIRProgramBuilder& b) { b.h(q0); b.cx(control, q0); }); + return measureAndRecord(b, {control}, IntoRegister); } -void nestedForLoopCtrlOpWithExtractedQubit(QIRProgramBuilder& b) { +template +Value nestedForLoopCtrlOpWithExtractedQubit(QIRProgramBuilder& b) { auto reg = b.allocQubitRegister(4); b.h(reg[0]); b.scfFor(1, 4, 1, [&](Value iv) { @@ -731,12 +945,262 @@ void nestedForLoopCtrlOpWithExtractedQubit(QIRProgramBuilder& b) { b.h(q0); b.cx(reg[0], q0); }); + return measureAndRecord(b, {reg[0]}, IntoRegister); } -void ctrlTwo(QIRProgramBuilder& b) { +template Value ctrlTwo(QIRProgramBuilder& b) { auto q = b.allocQubitRegister(4); b.mcx({q[0], q[1]}, q[2]); b.mcrxx(0.123, {q[0], q[1]}, q[2], q[3]); -} - + return measureAndRecord(b, q.qubits, IntoRegister); +} + +// Instantiate the templates for IntoRegister = false +template Value emptyQIR(QIRProgramBuilder& builder); +template Value allocQubit(QIRProgramBuilder& b); +template Value alloc1QubitRegister(QIRProgramBuilder& b); +template Value allocQubitRegister(QIRProgramBuilder& b); +template Value alloc3QubitRegister(QIRProgramBuilder& b); +template Value allocMultipleQubitRegisters(QIRProgramBuilder& b); +template Value allocMultipleQubitRegistersWithOps(QIRProgramBuilder& b); +template Value allocLargeRegister(QIRProgramBuilder& b); +template Value singleMeasurementToSingleBit(QIRProgramBuilder& b); +template Value repeatedMeasurementToSameBit(QIRProgramBuilder& b); +template Value repeatedMeasurementToDifferentBits(QIRProgramBuilder& b); +template Value +multipleClassicalRegistersAndMeasurements(QIRProgramBuilder& b); +template Value measurementWithoutRegisters(QIRProgramBuilder& b); +template Value resetQubitWithoutOp(QIRProgramBuilder& b); +template Value resetMultipleQubitsWithoutOp(QIRProgramBuilder& b); +template Value repeatedResetWithoutOp(QIRProgramBuilder& b); +template Value resetQubitAfterSingleOp(QIRProgramBuilder& b); +template Value resetMultipleQubitsAfterSingleOp(QIRProgramBuilder& b); +template Value repeatedResetAfterSingleOp(QIRProgramBuilder& b); +template Value globalPhase(QIRProgramBuilder& b); +template Value identity(QIRProgramBuilder& b); +template Value singleControlledIdentity(QIRProgramBuilder& b); +template Value twoQubitsOneIdentity(QIRProgramBuilder& b); +template Value threeQubitsOneIdentity(QIRProgramBuilder& b); +template Value multipleControlledIdentity(QIRProgramBuilder& b); +template Value x(QIRProgramBuilder& b); +template Value singleControlledX(QIRProgramBuilder& b); +template Value multipleControlledX(QIRProgramBuilder& b); +template Value y(QIRProgramBuilder& b); +template Value singleControlledY(QIRProgramBuilder& b); +template Value multipleControlledY(QIRProgramBuilder& b); +template Value z(QIRProgramBuilder& b); +template Value singleControlledZ(QIRProgramBuilder& b); +template Value multipleControlledZ(QIRProgramBuilder& b); +template Value h(QIRProgramBuilder& b); +template Value singleControlledH(QIRProgramBuilder& b); +template Value multipleControlledH(QIRProgramBuilder& b); +template Value hWithoutRegister(QIRProgramBuilder& b); +template Value s(QIRProgramBuilder& b); +template Value singleControlledS(QIRProgramBuilder& b); +template Value multipleControlledS(QIRProgramBuilder& b); +template Value sdg(QIRProgramBuilder& b); +template Value singleControlledSdg(QIRProgramBuilder& b); +template Value multipleControlledSdg(QIRProgramBuilder& b); +template Value t_(QIRProgramBuilder& b); +template Value singleControlledT(QIRProgramBuilder& b); +template Value multipleControlledT(QIRProgramBuilder& b); +template Value tdg(QIRProgramBuilder& b); +template Value singleControlledTdg(QIRProgramBuilder& b); +template Value multipleControlledTdg(QIRProgramBuilder& b); +template Value sx(QIRProgramBuilder& b); +template Value singleControlledSx(QIRProgramBuilder& b); +template Value multipleControlledSx(QIRProgramBuilder& b); +template Value sxdg(QIRProgramBuilder& b); +template Value singleControlledSxdg(QIRProgramBuilder& b); +template Value multipleControlledSxdg(QIRProgramBuilder& b); +template Value rx(QIRProgramBuilder& b); +template Value singleControlledRx(QIRProgramBuilder& b); +template Value multipleControlledRx(QIRProgramBuilder& b); +template Value ry(QIRProgramBuilder& b); +template Value singleControlledRy(QIRProgramBuilder& b); +template Value multipleControlledRy(QIRProgramBuilder& b); +template Value rz(QIRProgramBuilder& b); +template Value singleControlledRz(QIRProgramBuilder& b); +template Value multipleControlledRz(QIRProgramBuilder& b); +template Value p(QIRProgramBuilder& b); +template Value singleControlledP(QIRProgramBuilder& b); +template Value multipleControlledP(QIRProgramBuilder& b); +template Value r(QIRProgramBuilder& b); +template Value singleControlledR(QIRProgramBuilder& b); +template Value multipleControlledR(QIRProgramBuilder& b); +template Value u2(QIRProgramBuilder& b); +template Value singleControlledU2(QIRProgramBuilder& b); +template Value multipleControlledU2(QIRProgramBuilder& b); +template Value u(QIRProgramBuilder& b); +template Value singleControlledU(QIRProgramBuilder& b); +template Value multipleControlledU(QIRProgramBuilder& b); +template Value swap(QIRProgramBuilder& b); +template Value singleControlledSwap(QIRProgramBuilder& b); +template Value multipleControlledSwap(QIRProgramBuilder& b); +template Value iswap(QIRProgramBuilder& b); +template Value singleControlledIswap(QIRProgramBuilder& b); +template Value multipleControlledIswap(QIRProgramBuilder& b); +template Value dcx(QIRProgramBuilder& b); +template Value singleControlledDcx(QIRProgramBuilder& b); +template Value multipleControlledDcx(QIRProgramBuilder& b); +template Value ecr(QIRProgramBuilder& b); +template Value singleControlledEcr(QIRProgramBuilder& b); +template Value multipleControlledEcr(QIRProgramBuilder& b); +template Value rxx(QIRProgramBuilder& b); +template Value singleControlledRxx(QIRProgramBuilder& b); +template Value multipleControlledRxx(QIRProgramBuilder& b); +template Value tripleControlledRxx(QIRProgramBuilder& b); +template Value ryy(QIRProgramBuilder& b); +template Value singleControlledRyy(QIRProgramBuilder& b); +template Value multipleControlledRyy(QIRProgramBuilder& b); +template Value rzx(QIRProgramBuilder& b); +template Value singleControlledRzx(QIRProgramBuilder& b); +template Value multipleControlledRzx(QIRProgramBuilder& b); +template Value rzz(QIRProgramBuilder& b); +template Value singleControlledRzz(QIRProgramBuilder& b); +template Value multipleControlledRzz(QIRProgramBuilder& b); +template Value xxPlusYY(QIRProgramBuilder& b); +template Value singleControlledXxPlusYY(QIRProgramBuilder& b); +template Value multipleControlledXxPlusYY(QIRProgramBuilder& b); +template Value xxMinusYY(QIRProgramBuilder& b); +template Value singleControlledXxMinusYY(QIRProgramBuilder& b); +template Value multipleControlledXxMinusYY(QIRProgramBuilder& b); +template Value simpleIf(QIRProgramBuilder& b); +template Value ifElse(QIRProgramBuilder& b); +template Value ifTwoQubits(QIRProgramBuilder& b); +template Value nestedIfOpForLoop(QIRProgramBuilder& b); +template Value simpleWhileReset(QIRProgramBuilder& b); +template Value simpleDoWhileReset(QIRProgramBuilder& b); +template Value simpleForLoop(QIRProgramBuilder& b); +template Value nestedForLoopIfOp(QIRProgramBuilder& b); +template Value nestedForLoopWhileOp(QIRProgramBuilder& b); +template Value +nestedForLoopCtrlOpWithSeparateQubit(QIRProgramBuilder& b); +template Value +nestedForLoopCtrlOpWithExtractedQubit(QIRProgramBuilder& b); +template Value ctrlTwo(QIRProgramBuilder& b); + +// Instantiate the templates for IntoRegister = true +template Value emptyQIR(QIRProgramBuilder& builder); +template Value allocQubit(QIRProgramBuilder& b); +template Value alloc1QubitRegister(QIRProgramBuilder& b); +template Value allocQubitRegister(QIRProgramBuilder& b); +template Value alloc3QubitRegister(QIRProgramBuilder& b); +template Value allocMultipleQubitRegisters(QIRProgramBuilder& b); +template Value allocMultipleQubitRegistersWithOps(QIRProgramBuilder& b); +template Value allocLargeRegister(QIRProgramBuilder& b); +template Value singleMeasurementToSingleBit(QIRProgramBuilder& b); +template Value repeatedMeasurementToSameBit(QIRProgramBuilder& b); +template Value repeatedMeasurementToDifferentBits(QIRProgramBuilder& b); +template Value +multipleClassicalRegistersAndMeasurements(QIRProgramBuilder& b); +template Value measurementWithoutRegisters(QIRProgramBuilder& b); +template Value resetQubitWithoutOp(QIRProgramBuilder& b); +template Value resetMultipleQubitsWithoutOp(QIRProgramBuilder& b); +template Value repeatedResetWithoutOp(QIRProgramBuilder& b); +template Value resetQubitAfterSingleOp(QIRProgramBuilder& b); +template Value resetMultipleQubitsAfterSingleOp(QIRProgramBuilder& b); +template Value repeatedResetAfterSingleOp(QIRProgramBuilder& b); +template Value globalPhase(QIRProgramBuilder& b); +template Value identity(QIRProgramBuilder& b); +template Value singleControlledIdentity(QIRProgramBuilder& b); +template Value twoQubitsOneIdentity(QIRProgramBuilder& b); +template Value threeQubitsOneIdentity(QIRProgramBuilder& b); +template Value multipleControlledIdentity(QIRProgramBuilder& b); +template Value x(QIRProgramBuilder& b); +template Value singleControlledX(QIRProgramBuilder& b); +template Value multipleControlledX(QIRProgramBuilder& b); +template Value y(QIRProgramBuilder& b); +template Value singleControlledY(QIRProgramBuilder& b); +template Value multipleControlledY(QIRProgramBuilder& b); +template Value z(QIRProgramBuilder& b); +template Value singleControlledZ(QIRProgramBuilder& b); +template Value multipleControlledZ(QIRProgramBuilder& b); +template Value h(QIRProgramBuilder& b); +template Value singleControlledH(QIRProgramBuilder& b); +template Value multipleControlledH(QIRProgramBuilder& b); +template Value hWithoutRegister(QIRProgramBuilder& b); +template Value s(QIRProgramBuilder& b); +template Value singleControlledS(QIRProgramBuilder& b); +template Value multipleControlledS(QIRProgramBuilder& b); +template Value sdg(QIRProgramBuilder& b); +template Value singleControlledSdg(QIRProgramBuilder& b); +template Value multipleControlledSdg(QIRProgramBuilder& b); +template Value t_(QIRProgramBuilder& b); +template Value singleControlledT(QIRProgramBuilder& b); +template Value multipleControlledT(QIRProgramBuilder& b); +template Value tdg(QIRProgramBuilder& b); +template Value singleControlledTdg(QIRProgramBuilder& b); +template Value multipleControlledTdg(QIRProgramBuilder& b); +template Value sx(QIRProgramBuilder& b); +template Value singleControlledSx(QIRProgramBuilder& b); +template Value multipleControlledSx(QIRProgramBuilder& b); +template Value sxdg(QIRProgramBuilder& b); +template Value singleControlledSxdg(QIRProgramBuilder& b); +template Value multipleControlledSxdg(QIRProgramBuilder& b); +template Value rx(QIRProgramBuilder& b); +template Value singleControlledRx(QIRProgramBuilder& b); +template Value multipleControlledRx(QIRProgramBuilder& b); +template Value ry(QIRProgramBuilder& b); +template Value singleControlledRy(QIRProgramBuilder& b); +template Value multipleControlledRy(QIRProgramBuilder& b); +template Value rz(QIRProgramBuilder& b); +template Value singleControlledRz(QIRProgramBuilder& b); +template Value multipleControlledRz(QIRProgramBuilder& b); +template Value p(QIRProgramBuilder& b); +template Value singleControlledP(QIRProgramBuilder& b); +template Value multipleControlledP(QIRProgramBuilder& b); +template Value r(QIRProgramBuilder& b); +template Value singleControlledR(QIRProgramBuilder& b); +template Value multipleControlledR(QIRProgramBuilder& b); +template Value u2(QIRProgramBuilder& b); +template Value singleControlledU2(QIRProgramBuilder& b); +template Value multipleControlledU2(QIRProgramBuilder& b); +template Value u(QIRProgramBuilder& b); +template Value singleControlledU(QIRProgramBuilder& b); +template Value multipleControlledU(QIRProgramBuilder& b); +template Value swap(QIRProgramBuilder& b); +template Value singleControlledSwap(QIRProgramBuilder& b); +template Value multipleControlledSwap(QIRProgramBuilder& b); +template Value iswap(QIRProgramBuilder& b); +template Value singleControlledIswap(QIRProgramBuilder& b); +template Value multipleControlledIswap(QIRProgramBuilder& b); +template Value dcx(QIRProgramBuilder& b); +template Value singleControlledDcx(QIRProgramBuilder& b); +template Value multipleControlledDcx(QIRProgramBuilder& b); +template Value ecr(QIRProgramBuilder& b); +template Value singleControlledEcr(QIRProgramBuilder& b); +template Value multipleControlledEcr(QIRProgramBuilder& b); +template Value rxx(QIRProgramBuilder& b); +template Value singleControlledRxx(QIRProgramBuilder& b); +template Value multipleControlledRxx(QIRProgramBuilder& b); +template Value tripleControlledRxx(QIRProgramBuilder& b); +template Value ryy(QIRProgramBuilder& b); +template Value singleControlledRyy(QIRProgramBuilder& b); +template Value multipleControlledRyy(QIRProgramBuilder& b); +template Value rzx(QIRProgramBuilder& b); +template Value singleControlledRzx(QIRProgramBuilder& b); +template Value multipleControlledRzx(QIRProgramBuilder& b); +template Value rzz(QIRProgramBuilder& b); +template Value singleControlledRzz(QIRProgramBuilder& b); +template Value multipleControlledRzz(QIRProgramBuilder& b); +template Value xxPlusYY(QIRProgramBuilder& b); +template Value singleControlledXxPlusYY(QIRProgramBuilder& b); +template Value multipleControlledXxPlusYY(QIRProgramBuilder& b); +template Value xxMinusYY(QIRProgramBuilder& b); +template Value singleControlledXxMinusYY(QIRProgramBuilder& b); +template Value multipleControlledXxMinusYY(QIRProgramBuilder& b); +template Value simpleIf(QIRProgramBuilder& b); +template Value ifElse(QIRProgramBuilder& b); +template Value ifTwoQubits(QIRProgramBuilder& b); +template Value nestedIfOpForLoop(QIRProgramBuilder& b); +template Value simpleWhileReset(QIRProgramBuilder& b); +template Value simpleDoWhileReset(QIRProgramBuilder& b); +template Value simpleForLoop(QIRProgramBuilder& b); +template Value nestedForLoopIfOp(QIRProgramBuilder& b); +template Value nestedForLoopWhileOp(QIRProgramBuilder& b); +template Value nestedForLoopCtrlOpWithSeparateQubit(QIRProgramBuilder& b); +template Value +nestedForLoopCtrlOpWithExtractedQubit(QIRProgramBuilder& b); +template Value ctrlTwo(QIRProgramBuilder& b); } // namespace mlir::qir diff --git a/mlir/unittests/programs/qir_programs.h b/mlir/unittests/programs/qir_programs.h index afa3daaef6..b58a3ff396 100644 --- a/mlir/unittests/programs/qir_programs.h +++ b/mlir/unittests/programs/qir_programs.h @@ -10,468 +10,567 @@ #pragma once +#include + namespace mlir::qir { class QIRProgramBuilder; /// Creates an empty QIR program. -void emptyQIR(QIRProgramBuilder& builder); +template Value emptyQIR(QIRProgramBuilder& builder); // --- Qubit Management ----------------------------------------------------- // /// Allocates a single qubit. -void allocQubit(QIRProgramBuilder& b); +template Value allocQubit(QIRProgramBuilder& b); + +/// Allocates a qubit register of size `1`. +template +Value alloc1QubitRegister(QIRProgramBuilder& b); /// Allocates a qubit register of size `2`. -void allocQubitRegister(QIRProgramBuilder& b); +template +Value allocQubitRegister(QIRProgramBuilder& b); + +/// Allocates a qubit register of size `3`. +template +Value alloc3QubitRegister(QIRProgramBuilder& b); /// Allocates two qubit registers of size `2` and `3`. -void allocMultipleQubitRegisters(QIRProgramBuilder& b); +template +Value allocMultipleQubitRegisters(QIRProgramBuilder& b); /// Allocates two qubit registers of size `2` and `3` and applies operations. -void allocMultipleQubitRegistersWithOps(QIRProgramBuilder& b); +template +Value allocMultipleQubitRegistersWithOps(QIRProgramBuilder& b); /// Allocates a large qubit register. -void allocLargeRegister(QIRProgramBuilder& b); +template +Value allocLargeRegister(QIRProgramBuilder& b); /// Allocates two inline qubits. -void staticQubits(QIRProgramBuilder& b); +Value staticQubits(QIRProgramBuilder& b); /// Allocates two static qubits and applies operations. -void staticQubitsWithOps(QIRProgramBuilder& b); +Value staticQubitsWithOps(QIRProgramBuilder& b); /// Allocates two static qubits and applies parametric gates. -void staticQubitsWithParametricOps(QIRProgramBuilder& b); +Value staticQubitsWithParametricOps(QIRProgramBuilder& b); /// Allocates two static qubits and applies a two-target gate. -void staticQubitsWithTwoTargetOps(QIRProgramBuilder& b); +Value staticQubitsWithTwoTargetOps(QIRProgramBuilder& b); /// Allocates two static qubits and applies a controlled gate. -void staticQubitsWithCtrl(QIRProgramBuilder& b); +Value staticQubitsWithCtrl(QIRProgramBuilder& b); /// Allocates a static qubit and applies the inverse of a T gate (Tdg). -void staticQubitsWithInv(QIRProgramBuilder& b); +Value staticQubitsWithInv(QIRProgramBuilder& b); /// Allocates duplicate static qubits and applies operations on both. -void staticQubitsWithDuplicates(QIRProgramBuilder& b); +Value staticQubitsWithDuplicates(QIRProgramBuilder& b); /// Same as `staticQubitsWithDuplicates`, but with canonical static qubit /// retrievals. -void staticQubitsCanonical(QIRProgramBuilder& b); +Value staticQubitsCanonical(QIRProgramBuilder& b); // --- Invalid / mixed addressing (unit tests) -------------------------------- /// @pre `builder.initialize()`. Fatal mixed addressing: static then dynamic /// alloc. -void mixedStaticThenDynamicQubit(QIRProgramBuilder& b); +Value mixedStaticThenDynamicQubit(QIRProgramBuilder& b); /// @pre `builder.initialize()`. Fatal mixed addressing: dynamic register then /// static. -void mixedDynamicRegisterThenStaticQubit(QIRProgramBuilder& b); +Value mixedDynamicRegisterThenStaticQubit(QIRProgramBuilder& b); // --- MeasureOp ------------------------------------------------------------ // /// Measures a single qubit into a single classical bit. -void singleMeasurementToSingleBit(QIRProgramBuilder& b); +template +Value singleMeasurementToSingleBit(QIRProgramBuilder& b); /// Repeatedly measures a single qubit into the same classical bit. -void repeatedMeasurementToSameBit(QIRProgramBuilder& b); +template +Value repeatedMeasurementToSameBit(QIRProgramBuilder& b); /// Repeatedly measures a single qubit into different classical bits. -void repeatedMeasurementToDifferentBits(QIRProgramBuilder& b); +template +Value repeatedMeasurementToDifferentBits(QIRProgramBuilder& b); /// Measures multiple qubits into multiple classical bits. -void multipleClassicalRegistersAndMeasurements(QIRProgramBuilder& b); +template +Value multipleClassicalRegistersAndMeasurements(QIRProgramBuilder& b); /// Measures a single qubit into a single classical bit, without explicitly /// allocating a quantum or classical register. -void measurementWithoutRegisters(QIRProgramBuilder& b); +template +Value measurementWithoutRegisters(QIRProgramBuilder& b); // --- ResetOp -------------------------------------------------------------- // /// Resets a single qubit without any operations being applied. -void resetQubitWithoutOp(QIRProgramBuilder& b); +template +Value resetQubitWithoutOp(QIRProgramBuilder& b); /// Resets multiple qubits without any operations being applied. -void resetMultipleQubitsWithoutOp(QIRProgramBuilder& b); +template +Value resetMultipleQubitsWithoutOp(QIRProgramBuilder& b); /// Repeatedly resets a single qubit without any operations being applied. -void repeatedResetWithoutOp(QIRProgramBuilder& b); +template +Value repeatedResetWithoutOp(QIRProgramBuilder& b); /// Resets a single qubit after a single operation. -void resetQubitAfterSingleOp(QIRProgramBuilder& b); +template +Value resetQubitAfterSingleOp(QIRProgramBuilder& b); /// Resets multiple qubits after a single operation. -void resetMultipleQubitsAfterSingleOp(QIRProgramBuilder& b); +template +Value resetMultipleQubitsAfterSingleOp(QIRProgramBuilder& b); /// Repeatedly resets a single qubit after a single operation. -void repeatedResetAfterSingleOp(QIRProgramBuilder& b); +template +Value repeatedResetAfterSingleOp(QIRProgramBuilder& b); // --- GPhaseOp ------------------------------------------------------------- // /// Creates a circuit with just a global phase. -void globalPhase(QIRProgramBuilder& b); +template Value globalPhase(QIRProgramBuilder& b); // --- IdOp ----------------------------------------------------------------- // /// Creates a circuit with just an identity gate. -void identity(QIRProgramBuilder& b); +template Value identity(QIRProgramBuilder& b); /// Creates a controlled identity gate with a single control qubit. -void singleControlledIdentity(QIRProgramBuilder& b); +template +Value singleControlledIdentity(QIRProgramBuilder& b); + +/// Creates an identity gate on a single qubit in a two-qubit register. +template +Value twoQubitsOneIdentity(QIRProgramBuilder& b); + +/// Creates an identity gate on a single qubit in a three-qubit register. +template +Value threeQubitsOneIdentity(QIRProgramBuilder& b); /// Creates a multi-controlled identity gate with multiple control qubits. -void multipleControlledIdentity(QIRProgramBuilder& b); +template +Value multipleControlledIdentity(QIRProgramBuilder& b); // --- XOp ------------------------------------------------------------------ // /// Creates a circuit with just an X gate. -void x(QIRProgramBuilder& b); +template Value x(QIRProgramBuilder& b); /// Creates a circuit with a single controlled X gate. -void singleControlledX(QIRProgramBuilder& b); +template +Value singleControlledX(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled X gate. -void multipleControlledX(QIRProgramBuilder& b); +template +Value multipleControlledX(QIRProgramBuilder& b); // --- YOp ------------------------------------------------------------------ // /// Creates a circuit with just a Y gate. -void y(QIRProgramBuilder& b); +template Value y(QIRProgramBuilder& b); /// Creates a circuit with a single controlled Y gate. -void singleControlledY(QIRProgramBuilder& b); +template +Value singleControlledY(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled Y gate. -void multipleControlledY(QIRProgramBuilder& b); +template +Value multipleControlledY(QIRProgramBuilder& b); // --- ZOp ------------------------------------------------------------------ // /// Creates a circuit with just a Z gate. -void z(QIRProgramBuilder& b); +template Value z(QIRProgramBuilder& b); /// Creates a circuit with a single controlled Z gate. -void singleControlledZ(QIRProgramBuilder& b); +template +Value singleControlledZ(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled Z gate. -void multipleControlledZ(QIRProgramBuilder& b); +template +Value multipleControlledZ(QIRProgramBuilder& b); // --- HOp ------------------------------------------------------------------ // /// Creates a circuit with just an H gate. -void h(QIRProgramBuilder& b); +template Value h(QIRProgramBuilder& b); /// Creates a circuit with a single controlled H gate. -void singleControlledH(QIRProgramBuilder& b); +template +Value singleControlledH(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled H gate. -void multipleControlledH(QIRProgramBuilder& b); +template +Value multipleControlledH(QIRProgramBuilder& b); /// Creates a circuit with just an H gate and no qubit register. -void hWithoutRegister(QIRProgramBuilder& b); +template +Value hWithoutRegister(QIRProgramBuilder& b); // --- SOp ------------------------------------------------------------------ // /// Creates a circuit with just an S gate. -void s(QIRProgramBuilder& b); +template Value s(QIRProgramBuilder& b); /// Creates a circuit with a single controlled S gate. -void singleControlledS(QIRProgramBuilder& b); +template +Value singleControlledS(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled S gate. -void multipleControlledS(QIRProgramBuilder& b); +template +Value multipleControlledS(QIRProgramBuilder& b); // --- SdgOp ---------------------------------------------------------------- // /// Creates a circuit with just an Sdg gate. -void sdg(QIRProgramBuilder& b); +template Value sdg(QIRProgramBuilder& b); /// Creates a circuit with a single controlled Sdg gate. -void singleControlledSdg(QIRProgramBuilder& b); +template +Value singleControlledSdg(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled Sdg gate. -void multipleControlledSdg(QIRProgramBuilder& b); +template +Value multipleControlledSdg(QIRProgramBuilder& b); // --- TOp ------------------------------------------------------------------ // /// Creates a circuit with just a T gate. -void t_(QIRProgramBuilder& b); // NOLINT(*-identifier-naming) +template +Value t_(QIRProgramBuilder& b); // NOLINT(*-identifier-naming) /// Creates a circuit with a single controlled T gate. -void singleControlledT(QIRProgramBuilder& b); +template +Value singleControlledT(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled T gate. -void multipleControlledT(QIRProgramBuilder& b); +template +Value multipleControlledT(QIRProgramBuilder& b); // --- TdgOp ---------------------------------------------------------------- // /// Creates a circuit with just a Tdg gate. -void tdg(QIRProgramBuilder& b); +template Value tdg(QIRProgramBuilder& b); /// Creates a circuit with a single controlled Tdg gate. -void singleControlledTdg(QIRProgramBuilder& b); +template +Value singleControlledTdg(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled Tdg gate. -void multipleControlledTdg(QIRProgramBuilder& b); +template +Value multipleControlledTdg(QIRProgramBuilder& b); // --- SXOp ----------------------------------------------------------------- // /// Creates a circuit with just an SX gate. -void sx(QIRProgramBuilder& b); +template Value sx(QIRProgramBuilder& b); /// Creates a circuit with a single controlled SX gate. -void singleControlledSx(QIRProgramBuilder& b); +template +Value singleControlledSx(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled SX gate. -void multipleControlledSx(QIRProgramBuilder& b); +template +Value multipleControlledSx(QIRProgramBuilder& b); // --- SXdgOp --------------------------------------------------------------- // /// Creates a circuit with just an SXdg gate. -void sxdg(QIRProgramBuilder& b); +template Value sxdg(QIRProgramBuilder& b); /// Creates a circuit with a single controlled SXdg gate. -void singleControlledSxdg(QIRProgramBuilder& b); +template +Value singleControlledSxdg(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled SXdg gate. -void multipleControlledSxdg(QIRProgramBuilder& b); +template +Value multipleControlledSxdg(QIRProgramBuilder& b); // --- RXOp ----------------------------------------------------------------- // /// Creates a circuit with just an RX gate. -void rx(QIRProgramBuilder& b); +template Value rx(QIRProgramBuilder& b); /// Creates a circuit with a single controlled RX gate. -void singleControlledRx(QIRProgramBuilder& b); +template +Value singleControlledRx(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled RX gate. -void multipleControlledRx(QIRProgramBuilder& b); +template +Value multipleControlledRx(QIRProgramBuilder& b); // --- RYOp ----------------------------------------------------------------- // /// Creates a circuit with just an RY gate. -void ry(QIRProgramBuilder& b); +template Value ry(QIRProgramBuilder& b); /// Creates a circuit with a single controlled RY gate. -void singleControlledRy(QIRProgramBuilder& b); +template +Value singleControlledRy(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled RY gate. -void multipleControlledRy(QIRProgramBuilder& b); +template +Value multipleControlledRy(QIRProgramBuilder& b); // --- RZOp ----------------------------------------------------------------- // /// Creates a circuit with just an RZ gate. -void rz(QIRProgramBuilder& b); +template Value rz(QIRProgramBuilder& b); /// Creates a circuit with a single controlled RZ gate. -void singleControlledRz(QIRProgramBuilder& b); +template +Value singleControlledRz(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled RZ gate. -void multipleControlledRz(QIRProgramBuilder& b); +template +Value multipleControlledRz(QIRProgramBuilder& b); // --- POp ------------------------------------------------------------------ // /// Creates a circuit with just a P gate. -void p(QIRProgramBuilder& b); +template Value p(QIRProgramBuilder& b); /// Creates a circuit with a single controlled P gate. -void singleControlledP(QIRProgramBuilder& b); +template +Value singleControlledP(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled P gate. -void multipleControlledP(QIRProgramBuilder& b); +template +Value multipleControlledP(QIRProgramBuilder& b); // --- ROp ------------------------------------------------------------------ // /// Creates a circuit with just an R gate. -void r(QIRProgramBuilder& b); +template Value r(QIRProgramBuilder& b); /// Creates a circuit with a single controlled R gate. -void singleControlledR(QIRProgramBuilder& b); +template +Value singleControlledR(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled R gate. -void multipleControlledR(QIRProgramBuilder& b); +template +Value multipleControlledR(QIRProgramBuilder& b); // --- U2Op ----------------------------------------------------------------- // /// Creates a circuit with just a U2 gate. -void u2(QIRProgramBuilder& b); +template Value u2(QIRProgramBuilder& b); /// Creates a circuit with a single controlled U2 gate. -void singleControlledU2(QIRProgramBuilder& b); +template +Value singleControlledU2(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled U2 gate. -void multipleControlledU2(QIRProgramBuilder& b); +template +Value multipleControlledU2(QIRProgramBuilder& b); // --- UOp ------------------------------------------------------------------ // /// Creates a circuit with just a U gate. -void u(QIRProgramBuilder& b); +template Value u(QIRProgramBuilder& b); /// Creates a circuit with a single controlled U gate. -void singleControlledU(QIRProgramBuilder& b); +template +Value singleControlledU(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled U gate. -void multipleControlledU(QIRProgramBuilder& b); +template +Value multipleControlledU(QIRProgramBuilder& b); // --- SWAPOp --------------------------------------------------------------- // /// Creates a circuit with just a SWAP gate. -void swap(QIRProgramBuilder& b); +template Value swap(QIRProgramBuilder& b); /// Creates a circuit with a single controlled SWAP gate. -void singleControlledSwap(QIRProgramBuilder& b); +template +Value singleControlledSwap(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled SWAP gate. -void multipleControlledSwap(QIRProgramBuilder& b); +template +Value multipleControlledSwap(QIRProgramBuilder& b); // --- iSWAPOp -------------------------------------------------------------- // /// Creates a circuit with just an iSWAP gate. -void iswap(QIRProgramBuilder& b); +template Value iswap(QIRProgramBuilder& b); /// Creates a circuit with a single controlled iSWAP gate. -void singleControlledIswap(QIRProgramBuilder& b); +template +Value singleControlledIswap(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled iSWAP gate. -void multipleControlledIswap(QIRProgramBuilder& b); +template +Value multipleControlledIswap(QIRProgramBuilder& b); // --- DCXOp ---------------------------------------------------------------- // /// Creates a circuit with just a DCX gate. -void dcx(QIRProgramBuilder& b); +template Value dcx(QIRProgramBuilder& b); /// Creates a circuit with a single controlled DCX gate. -void singleControlledDcx(QIRProgramBuilder& b); +template +Value singleControlledDcx(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled DCX gate. -void multipleControlledDcx(QIRProgramBuilder& b); +template +Value multipleControlledDcx(QIRProgramBuilder& b); // --- ECROp ---------------------------------------------------------------- // /// Creates a circuit with just an ECR gate. -void ecr(QIRProgramBuilder& b); +template Value ecr(QIRProgramBuilder& b); /// Creates a circuit with a single controlled ECR gate. -void singleControlledEcr(QIRProgramBuilder& b); +template +Value singleControlledEcr(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled ECR gate. -void multipleControlledEcr(QIRProgramBuilder& b); +template +Value multipleControlledEcr(QIRProgramBuilder& b); // --- RXXOp ---------------------------------------------------------------- // /// Creates a circuit with just an RXX gate. -void rxx(QIRProgramBuilder& b); +template Value rxx(QIRProgramBuilder& b); /// Creates a circuit with a single controlled RXX gate. -void singleControlledRxx(QIRProgramBuilder& b); +template +Value singleControlledRxx(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled RXX gate. -void multipleControlledRxx(QIRProgramBuilder& b); +template +Value multipleControlledRxx(QIRProgramBuilder& b); /// Creates a circuit with a triple-controlled RXX gate. -void tripleControlledRxx(QIRProgramBuilder& b); +template +Value tripleControlledRxx(QIRProgramBuilder& b); // --- RYYOp ---------------------------------------------------------------- // /// Creates a circuit with just an RYY gate. -void ryy(QIRProgramBuilder& b); +template Value ryy(QIRProgramBuilder& b); /// Creates a circuit with a single controlled RYY gate. -void singleControlledRyy(QIRProgramBuilder& b); +template +Value singleControlledRyy(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled RYY gate. -void multipleControlledRyy(QIRProgramBuilder& b); +template +Value multipleControlledRyy(QIRProgramBuilder& b); // --- RZXOp ---------------------------------------------------------------- // /// Creates a circuit with just an RZX gate. -void rzx(QIRProgramBuilder& b); +template Value rzx(QIRProgramBuilder& b); /// Creates a circuit with a single controlled RZX gate. -void singleControlledRzx(QIRProgramBuilder& b); +template +Value singleControlledRzx(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled RZX gate. -void multipleControlledRzx(QIRProgramBuilder& b); +template +Value multipleControlledRzx(QIRProgramBuilder& b); // --- RZZOp ---------------------------------------------------------------- // /// Creates a circuit with just an RZZ gate. -void rzz(QIRProgramBuilder& b); +template Value rzz(QIRProgramBuilder& b); /// Creates a circuit with a single controlled RZZ gate. -void singleControlledRzz(QIRProgramBuilder& b); +template +Value singleControlledRzz(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled RZZ gate. -void multipleControlledRzz(QIRProgramBuilder& b); +template +Value multipleControlledRzz(QIRProgramBuilder& b); // --- XXPlusYYOp ----------------------------------------------------------- // /// Creates a circuit with just an XXPlusYY gate. -void xxPlusYY(QIRProgramBuilder& b); +template Value xxPlusYY(QIRProgramBuilder& b); /// Creates a circuit with a single controlled XXPlusYY gate. -void singleControlledXxPlusYY(QIRProgramBuilder& b); +template +Value singleControlledXxPlusYY(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled XXPlusYY gate. -void multipleControlledXxPlusYY(QIRProgramBuilder& b); +template +Value multipleControlledXxPlusYY(QIRProgramBuilder& b); // --- XXMinusYYOp ---------------------------------------------------------- // /// Creates a circuit with just an XXMinusYY gate. -void xxMinusYY(QIRProgramBuilder& b); +template Value xxMinusYY(QIRProgramBuilder& b); /// Creates a circuit with a single controlled XXMinusYY gate. -void singleControlledXxMinusYY(QIRProgramBuilder& b); +template +Value singleControlledXxMinusYY(QIRProgramBuilder& b); /// Creates a circuit with a multi-controlled XXMinusYY gate. -void multipleControlledXxMinusYY(QIRProgramBuilder& b); +template +Value multipleControlledXxMinusYY(QIRProgramBuilder& b); // --- IfOp ----------------------------------------------------------------- // /// Creates a circuit with a simple if operation with one qubit. -void simpleIf(QIRProgramBuilder& b); +template Value simpleIf(QIRProgramBuilder& b); /// Creates a circuit with an if operation with an else branch. -void ifElse(QIRProgramBuilder& b); +template Value ifElse(QIRProgramBuilder& b); /// Creates a circuit with an if operation with two qubits. -void ifTwoQubits(QIRProgramBuilder& b); +template Value ifTwoQubits(QIRProgramBuilder& b); /// Creates a circuit with an if operation with a nested for operation with /// a register. -void nestedIfOpForLoop(QIRProgramBuilder& b); +template +Value nestedIfOpForLoop(QIRProgramBuilder& b); // --- WhileOp -------------------------------------------------------------- // /// Creates a circuit with a while operation using a while loop. -void simpleWhileReset(QIRProgramBuilder& b); +template +Value simpleWhileReset(QIRProgramBuilder& b); /// Creates a circuit with a while operation using a do-while loop. -void simpleDoWhileReset(QIRProgramBuilder& b); +template +Value simpleDoWhileReset(QIRProgramBuilder& b); // --- ForOp ---------------------------------------------------------------- // /// Creates a circuit with a simple for operation with a register. -void simpleForLoop(QIRProgramBuilder& b); +template Value simpleForLoop(QIRProgramBuilder& b); /// Creates a circuit with a for operation with a register and a qubit and a /// nested if operation. -void nestedForLoopIfOp(QIRProgramBuilder& b); +template +Value nestedForLoopIfOp(QIRProgramBuilder& b); /// Creates a circuit with a for operation with a register and a nested while /// operation. -void nestedForLoopWhileOp(QIRProgramBuilder& b); +template +Value nestedForLoopWhileOp(QIRProgramBuilder& 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(QIRProgramBuilder& b); +template +Value nestedForLoopCtrlOpWithSeparateQubit(QIRProgramBuilder& 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(QIRProgramBuilder& b); +template +Value nestedForLoopCtrlOpWithExtractedQubit(QIRProgramBuilder& b); // --- CtrlOp --------------------------------------------------------------- // /// Creates a circuit with a control modifier applied to two gates. -void ctrlTwo(QIRProgramBuilder& b); +template Value ctrlTwo(QIRProgramBuilder& b); } // namespace mlir::qir diff --git a/mlir/unittests/programs/quantum_computation_programs.cpp b/mlir/unittests/programs/quantum_computation_programs.cpp index f0b9b305cd..d473a61bb4 100644 --- a/mlir/unittests/programs/quantum_computation_programs.cpp +++ b/mlir/unittests/programs/quantum_computation_programs.cpp @@ -22,19 +22,27 @@ namespace qc { -void allocQubit(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); } +void allocQubit(QuantumComputation& comp) { + auto qr = comp.addQubitRegister(1, "q"); + comp.measureAll(true, false); +} void allocQubitRegister(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); + comp.measureAll(true, false); } void allocMultipleQubitRegisters(QuantumComputation& comp) { comp.addQubitRegister(2, "reg0"); comp.addQubitRegister(3, "reg1"); + comp.measureAll(true, false); } void allocLargeRegister(QuantumComputation& comp) { comp.addQubitRegister(100, "q"); + comp.addClassicalRegister(2, "meas"); + comp.measure(0, 0); + comp.measure(99, 1); } void singleMeasurementToSingleBit(QuantumComputation& comp) { @@ -72,6 +80,7 @@ void resetQubitAfterSingleOp(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.h(0); comp.reset(0); + comp.measureAll(true, false); } void resetMultipleQubitsAfterSingleOp(QuantumComputation& comp) { @@ -80,6 +89,7 @@ void resetMultipleQubitsAfterSingleOp(QuantumComputation& comp) { comp.reset(0); comp.h(1); comp.reset(1); + comp.measureAll(true, false); } void repeatedResetAfterSingleOp(QuantumComputation& comp) { @@ -88,6 +98,7 @@ void repeatedResetAfterSingleOp(QuantumComputation& comp) { comp.reset(0); comp.reset(0); comp.reset(0); + comp.measureAll(true, false); } void globalPhase(QuantumComputation& comp) { comp.gphase(0.123); } @@ -95,451 +106,541 @@ void globalPhase(QuantumComputation& comp) { comp.gphase(0.123); } void identity(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.i(0); + comp.measureAll(true, false); } void singleControlledIdentity(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); - comp.ci(1, 0); + comp.ci(0, 1); + comp.measureAll(true, false); } void multipleControlledIdentity(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); - comp.mci({2, 1}, 0); + comp.mci({0, 1}, 2); + comp.measureAll(true, false); } void x(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.x(0); + comp.measureAll(true, false); } void singleControlledX(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.cx(0, 1); + comp.measureAll(true, false); } void multipleControlledX(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcx({0, 1}, 2); + comp.measureAll(true, false); } void y(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.y(0); + comp.measureAll(true, false); } void singleControlledY(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.cy(0, 1); + comp.measureAll(true, false); } void multipleControlledY(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcy({0, 1}, 2); + comp.measureAll(true, false); } void z(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.z(0); + comp.measureAll(true, false); } void singleControlledZ(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.cz(0, 1); + comp.measureAll(true, false); } void multipleControlledZ(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcz({0, 1}, 2); + comp.measureAll(true, false); } void h(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.h(0); + comp.measureAll(true, false); } void singleControlledH(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.ch(0, 1); + comp.measureAll(true, false); } void multipleControlledH(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mch({0, 1}, 2); + comp.measureAll(true, false); } void s(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.s(0); + comp.measureAll(true, false); } void singleControlledS(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.cs(0, 1); + comp.measureAll(true, false); } void multipleControlledS(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcs({0, 1}, 2); + comp.measureAll(true, false); } void sdg(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.sdg(0); + comp.measureAll(true, false); } void singleControlledSdg(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.csdg(0, 1); + comp.measureAll(true, false); } void multipleControlledSdg(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcsdg({0, 1}, 2); + comp.measureAll(true, false); } void t_(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.t(0); + comp.measureAll(true, false); } void singleControlledT(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.ct(0, 1); + comp.measureAll(true, false); } void multipleControlledT(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mct({0, 1}, 2); + comp.measureAll(true, false); } void tdg(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.tdg(0); + comp.measureAll(true, false); } void singleControlledTdg(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.ctdg(0, 1); + comp.measureAll(true, false); } void multipleControlledTdg(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mctdg({0, 1}, 2); + comp.measureAll(true, false); } void sx(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.sx(0); + comp.measureAll(true, false); } void singleControlledSx(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.csx(0, 1); + comp.measureAll(true, false); } void multipleControlledSx(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcsx({0, 1}, 2); + comp.measureAll(true, false); } void sxdg(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.sxdg(0); + comp.measureAll(true, false); } void singleControlledSxdg(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.csxdg(0, 1); + comp.measureAll(true, false); } void multipleControlledSxdg(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcsxdg({0, 1}, 2); + comp.measureAll(true, false); } void rx(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.rx(0.123, 0); + comp.measureAll(true, false); } void singleControlledRx(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.crx(0.123, 0, 1); + comp.measureAll(true, false); } void multipleControlledRx(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcrx(0.123, {0, 1}, 2); + comp.measureAll(true, false); } void ry(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.ry(0.456, 0); + comp.measureAll(true, false); } void singleControlledRy(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.cry(0.456, 0, 1); + comp.measureAll(true, false); } void multipleControlledRy(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcry(0.456, {0, 1}, 2); + comp.measureAll(true, false); } void rz(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.rz(0.789, 0); + comp.measureAll(true, false); } void singleControlledRz(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.crz(0.789, 0, 1); + comp.measureAll(true, false); } void multipleControlledRz(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcrz(0.789, {0, 1}, 2); + comp.measureAll(true, false); } void p(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.p(0.123, 0); + comp.measureAll(true, false); } void singleControlledP(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.cp(0.123, 0, 1); + comp.measureAll(true, false); } void multipleControlledP(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcp(0.123, {0, 1}, 2); + comp.measureAll(true, false); } void r(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.r(0.123, 0.456, 0); + comp.measureAll(true, false); } void singleControlledR(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.cr(0.123, 0.456, 0, 1); + comp.measureAll(true, false); } void multipleControlledR(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcr(0.123, 0.456, {0, 1}, 2); + comp.measureAll(true, false); } void u2(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.u2(0.234, 0.567, 0); + comp.measureAll(true, false); } void singleControlledU2(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.cu2(0.234, 0.567, 0, 1); + comp.measureAll(true, false); } void multipleControlledU2(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcu2(0.234, 0.567, {0, 1}, 2); + comp.measureAll(true, false); } void u(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.u(0.1, 0.2, 0.3, 0); + comp.measureAll(true, false); } void singleControlledU(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.cu(0.1, 0.2, 0.3, 0, 1); + comp.measureAll(true, false); } void multipleControlledU(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.mcu(0.1, 0.2, 0.3, {0, 1}, 2); + comp.measureAll(true, false); } void swap(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.swap(0, 1); + comp.measureAll(true, false); } void singleControlledSwap(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.cswap(0, 1, 2); + comp.measureAll(true, false); } void multipleControlledSwap(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mcswap({0, 1}, 2, 3); + comp.measureAll(true, false); } void iswap(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.iswap(0, 1); + comp.measureAll(true, false); } void singleControlledIswap(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.ciswap(0, 1, 2); + comp.measureAll(true, false); } void multipleControlledIswap(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mciswap({0, 1}, 2, 3); + comp.measureAll(true, false); } void inverseIswap(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.iswapdg(0, 1); + comp.measureAll(true, false); } void inverseMultipleControlledIswap(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mciswapdg({0, 1}, 2, 3); + comp.measureAll(true, false); } void dcx(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.dcx(0, 1); + comp.measureAll(true, false); } void singleControlledDcx(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.cdcx(0, 1, 2); + comp.measureAll(true, false); } void multipleControlledDcx(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mcdcx({0, 1}, 2, 3); + comp.measureAll(true, false); } void ecr(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.ecr(0, 1); + comp.measureAll(true, false); } void singleControlledEcr(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.cecr(0, 1, 2); + comp.measureAll(true, false); } void multipleControlledEcr(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mcecr({0, 1}, 2, 3); + comp.measureAll(true, false); } void rxx(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.rxx(0.123, 0, 1); + comp.measureAll(true, false); } void singleControlledRxx(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.crxx(0.123, 0, 1, 2); + comp.measureAll(true, false); } void multipleControlledRxx(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mcrxx(0.123, {0, 1}, 2, 3); + comp.measureAll(true, false); } void tripleControlledRxx(QuantumComputation& comp) { comp.addQubitRegister(5, "q"); comp.mcrxx(0.123, {0, 1, 2}, 3, 4); + comp.measureAll(true, false); } void ryy(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.ryy(0.123, 0, 1); + comp.measureAll(true, false); } void singleControlledRyy(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.cryy(0.123, 0, 1, 2); + comp.measureAll(true, false); } void multipleControlledRyy(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mcryy(0.123, {0, 1}, 2, 3); + comp.measureAll(true, false); } void rzx(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.rzx(0.123, 0, 1); + comp.measureAll(true, false); } void singleControlledRzx(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.crzx(0.123, 0, 1, 2); + comp.measureAll(true, false); } void multipleControlledRzx(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mcrzx(0.123, {0, 1}, 2, 3); + comp.measureAll(true, false); } void rzz(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.rzz(0.123, 0, 1); + comp.measureAll(true, false); } void singleControlledRzz(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.crzz(0.123, 0, 1, 2); + comp.measureAll(true, false); } void multipleControlledRzz(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mcrzz(0.123, {0, 1}, 2, 3); + comp.measureAll(true, false); } void xxPlusYY(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.xx_plus_yy(0.123, 0.456, 0, 1); + comp.measureAll(true, false); } void singleControlledXxPlusYY(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.cxx_plus_yy(0.123, 0.456, 0, 1, 2); + comp.measureAll(true, false); } void multipleControlledXxPlusYY(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mcxx_plus_yy(0.123, 0.456, {0, 1}, 2, 3); + comp.measureAll(true, false); } void xxMinusYY(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.xx_minus_yy(0.123, 0.456, 0, 1); + comp.measureAll(true, false); } void singleControlledXxMinusYY(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.cxx_minus_yy(0.123, 0.456, 0, 1, 2); + comp.measureAll(true, false); } void multipleControlledXxMinusYY(QuantumComputation& comp) { comp.addQubitRegister(4, "q"); comp.mcxx_minus_yy(0.123, 0.456, {0, 1}, 2, 3); + comp.measureAll(true, false); } void barrier(QuantumComputation& comp) { comp.addQubitRegister(1, "q"); comp.barrier(0); + comp.measureAll(true, false); } void barrierTwoQubits(QuantumComputation& comp) { comp.addQubitRegister(2, "q"); comp.barrier({0, 1}); + comp.measureAll(true, false); } void barrierMultipleQubits(QuantumComputation& comp) { comp.addQubitRegister(3, "q"); comp.barrier({0, 1, 2}); + comp.measureAll(true, false); } void ctrlTwo(QuantumComputation& comp) { @@ -551,6 +652,7 @@ void ctrlTwo(QuantumComputation& comp) { compound.addControl(0); compound.addControl(1); comp.emplace_back(std::move(compound)); + comp.measureAll(true, false); } void ctrlTwoMixed(QuantumComputation& comp) { @@ -562,6 +664,7 @@ void ctrlTwoMixed(QuantumComputation& comp) { compound.addControl(0); compound.addControl(1); comp.emplace_back(std::move(compound)); + comp.measureAll(true, false); } void simpleIf(QuantumComputation& comp) { @@ -570,6 +673,8 @@ void simpleIf(QuantumComputation& comp) { comp.h(q[0]); comp.measure(q[0], c[0]); comp.if_(X, q[0], c[0]); + const auto& c2 = comp.addClassicalRegister(1, "meas"); + comp.measure(q[0], c2[0]); } void ifTwoQubits(QuantumComputation& comp) { @@ -583,6 +688,7 @@ void ifTwoQubits(QuantumComputation& comp) { IfElseOperation ifElse( std::make_unique(std::move(compound)), nullptr, c[0]); comp.emplace_back(std::move(ifElse)); + comp.measureAll(true, false); } void ifElse(QuantumComputation& comp) { @@ -592,6 +698,7 @@ void ifElse(QuantumComputation& comp) { comp.measure(q[0], c[0]); comp.ifElse(std::make_unique(q[0], X), std::make_unique(q[0], Z), c[0]); + comp.measureAll(true, false); } } // namespace qc diff --git a/python/mqt/core/ir/__init__.pyi b/python/mqt/core/ir/__init__.pyi index 69ea76967a..b95847f98b 100644 --- a/python/mqt/core/ir/__init__.pyi +++ b/python/mqt/core/ir/__init__.pyi @@ -1850,15 +1850,17 @@ class QuantumComputation(MutableSequence[operations.Operation]): cbits: The classical bits to store the results """ - def measure_all(self, *, add_bits: bool = True) -> None: + def measure_all(self, *, add_bits: bool = True, add_barrier: bool = True) -> None: """Measure all qubits and store the results in classical bits. Details: If `add_bits` is `True`, a new classical register (named "`meas`") with the same size as the number of qubits will be added to the circuit and the results will be stored in it. If `add_bits` is `False`, the classical register must already exist and have a sufficient number of bits to store the results. + If `add_barrier` is `True`, a barrier is added before the measurements. Args: add_bits: Whether to explicitly add a classical register + add_barrier: Whether to add a barrier before the measurements """ @overload diff --git a/src/ir/QuantumComputation.cpp b/src/ir/QuantumComputation.cpp index e0b63f17b0..7b018582fd 100644 --- a/src/ir/QuantumComputation.cpp +++ b/src/ir/QuantumComputation.cpp @@ -1541,7 +1541,7 @@ void QuantumComputation::measure(const Targets& qubits, emplace_back(qubits, bits); } -void QuantumComputation::measureAll(const bool addBits) { +void QuantumComputation::measureAll(const bool addBits, const bool addBarrier) { if (addBits) { addClassicalRegister(getNqubits(), "meas"); } @@ -1553,7 +1553,9 @@ void QuantumComputation::measureAll(const bool addBits) { throw std::runtime_error(ss.str()); } - barrier(); + if (addBarrier) { + barrier(); + } Qubit start = 0U; if (addBits) { start = static_cast(classicalRegisters.at("meas").getStartIndex()); diff --git a/src/qasm3/Parser.cpp b/src/qasm3/Parser.cpp index 04ae35473b..ce45d9f1f2 100644 --- a/src/qasm3/Parser.cpp +++ b/src/qasm3/Parser.cpp @@ -168,7 +168,11 @@ std::shared_ptr Parser::parseStatement() { if (current().kind == Token::Kind::Const) { scan(); - return parseDeclaration(true); + return parseDeclaration(true, false); + } + if (current().kind == Token::Kind::Output) { + scan(); + return parseDeclaration(false, true); } if (current().kind == Token::Kind::Int || @@ -181,7 +185,7 @@ std::shared_ptr Parser::parseStatement() { current().kind == Token::Kind::Duration || current().kind == Token::Kind::CReg || current().kind == Token::Kind::Qreg) { - return parseDeclaration(false); + return parseDeclaration(false, false); } if (current().kind == Token::Kind::InitialLayout) { @@ -558,7 +562,8 @@ std::shared_ptr Parser::parseGateOperand() { return std::make_shared(parseIndexedIdentifier()); } -std::shared_ptr Parser::parseDeclaration(bool isConst) { +std::shared_ptr Parser::parseDeclaration(bool isConst, + bool isOutput) { auto const tBegin = current(); auto [type, isOldStyleDeclaration] = parseType(); Token const identifier = expect(Token::Kind::Identifier); @@ -588,7 +593,7 @@ std::shared_ptr Parser::parseDeclaration(bool isConst) { auto const tEnd = expect(Token::Kind::Semicolon); auto statement = std::make_shared(DeclarationStatement{ - makeDebugInfo(tBegin, tEnd), isConst, type, name, expression}); + makeDebugInfo(tBegin, tEnd), isConst, isOutput, type, name, expression}); return statement; }