diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d0330315a..eb58acb8be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ with the exception that minor releases may include breaking changes. [#1569], [#1570], [#1572], [#1573], [#1580], [#1602], [#1620], [#1623], [#1624], [#1626], [#1627], [#1635], [#1638], [#1673], [#1675], [#1700], [#1710], [#1717], [#1728], [#1730], [#1749], [#1751], [#1762], [#1765], - [#1774], [#1781], [#1782], [#1787]) + [#1774], [#1780], [#1781], [#1782], [#1787]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**]) @@ -601,6 +601,7 @@ changelogs._ [#1787]: https://github.com/munich-quantum-toolkit/core/pull/1787 [#1782]: https://github.com/munich-quantum-toolkit/core/pull/1782 [#1781]: https://github.com/munich-quantum-toolkit/core/pull/1781 +[#1780]: https://github.com/munich-quantum-toolkit/core/pull/1780 [#1776]: https://github.com/munich-quantum-toolkit/core/pull/1776 [#1774]: https://github.com/munich-quantum-toolkit/core/pull/1774 [#1766]: https://github.com/munich-quantum-toolkit/core/pull/1766 diff --git a/mlir/include/mlir/Dialect/QC/Translation/TranslateQASM3ToQC.h b/mlir/include/mlir/Dialect/QC/Translation/TranslateQASM3ToQC.h new file mode 100644 index 0000000000..165136a500 --- /dev/null +++ b/mlir/include/mlir/Dialect/QC/Translation/TranslateQASM3ToQC.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 - 2026 Chair for Design Automation, TUM + * Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include +#include +#include + +namespace mlir { + +// Forward declarations +class MLIRContext; +class ModuleOp; + +namespace qc { + +/** + * @brief Translate an OpenQASM 3 program to a QC program. + * + * @param sourceMgr Source manager containing the OpenQASM3 program. + * @param context MLIRContext to create the module in. + */ +[[nodiscard]] OwningOpRef +translateQASM3ToQC(llvm::SourceMgr& sourceMgr, MLIRContext* context); + +/** + * @brief Translate an OpenQASM 3 program to a QC program. + * + * @param source String containing the OpenQASM3 program. + * @param context MLIRContext to create the module in. + */ +[[nodiscard]] OwningOpRef translateQASM3ToQC(StringRef source, + MLIRContext* context); + +} // namespace qc + +} // namespace mlir diff --git a/mlir/lib/Dialect/QC/Translation/CMakeLists.txt b/mlir/lib/Dialect/QC/Translation/CMakeLists.txt index a514f33df6..c1d403de3a 100644 --- a/mlir/lib/Dialect/QC/Translation/CMakeLists.txt +++ b/mlir/lib/Dialect/QC/Translation/CMakeLists.txt @@ -9,13 +9,15 @@ add_mlir_library( MLIRQCTranslation TranslateQuantumComputationToQC.cpp + TranslateQASM3ToQC.cpp LINK_LIBS MLIRArithDialect MLIRFuncDialect MLIRSCFDialect MLIRQCDialect MLIRQCProgramBuilder - MQT::CoreIR) + MQT::CoreIR + MQT::CoreQASM) mqt_mlir_target_use_project_options(MLIRQCTranslation) diff --git a/mlir/lib/Dialect/QC/Translation/TranslateQASM3ToQC.cpp b/mlir/lib/Dialect/QC/Translation/TranslateQASM3ToQC.cpp new file mode 100644 index 0000000000..bfc7bfe989 --- /dev/null +++ b/mlir/lib/Dialect/QC/Translation/TranslateQASM3ToQC.cpp @@ -0,0 +1,1064 @@ +/* + * Copyright (c) 2023 - 2026 Chair for Design Automation, TUM + * Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#include "mlir/Dialect/QC/Translation/TranslateQASM3ToQC.h" + +#include "ir/Definitions.hpp" +#include "ir/operations/OpType.hpp" +#include "mlir/Dialect/QC/Builder/QCProgramBuilder.h" +#include "mlir/Dialect/QC/IR/QCOps.h" +#include "qasm3/Exception.hpp" +#include "qasm3/Gate.hpp" +#include "qasm3/InstVisitor.hpp" +#include "qasm3/NestedEnvironment.hpp" +#include "qasm3/Parser.hpp" +#include "qasm3/Statement.hpp" +#include "qasm3/StdGates.hpp" +#include "qasm3/Types.hpp" +#include "qasm3/passes/ConstEvalPass.hpp" +#include "qasm3/passes/TypeCheckPass.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlir::qc { + +namespace { + +/// Signature: (builder, gate operands, evaluated parameters). +/// For gates with implicit controls (cx, ccx, ...), all qubits including +/// the controls are part of the range, matching OpenQASM 3 operand order. +using GateFn = + std::function)>; + +} // namespace + +/** + * @brief Build the table mapping OpenQASM 3 gate identifiers to + * QCProgramBuilder emitters. + * + * @details + * Each entry maps an OpenQASM 3 gate identifier to a lambda that emits the + * corresponding QC operation via the QCProgramBuilder. + */ +static llvm::StringMap buildGateDispatch() { + llvm::StringMap d; + + // ZeroTargetOneParameter + d["gphase"] = [](auto& b, auto /*q*/, auto p) { b.gphase(p[0]); }; + + // OneTargetZeroParameter + d["id"] = [](auto& b, auto q, auto) { b.id(q[0]); }; + d["x"] = [](auto& b, auto q, auto) { b.x(q[0]); }; + d["y"] = [](auto& b, auto q, auto) { b.y(q[0]); }; + d["z"] = [](auto& b, auto q, auto) { b.z(q[0]); }; + d["h"] = [](auto& b, auto q, auto) { b.h(q[0]); }; + d["s"] = [](auto& b, auto q, auto) { b.s(q[0]); }; + d["sdg"] = [](auto& b, auto q, auto) { b.sdg(q[0]); }; + d["t"] = [](auto& b, auto q, auto) { b.t(q[0]); }; + d["tdg"] = [](auto& b, auto q, auto) { b.tdg(q[0]); }; + d["sx"] = [](auto& b, auto q, auto) { b.sx(q[0]); }; + d["sxdg"] = [](auto& b, auto q, auto) { b.sxdg(q[0]); }; + + // OneTargetOneParameter + d["rx"] = [](auto& b, auto q, auto p) { b.rx(p[0], q[0]); }; + d["ry"] = [](auto& b, auto q, auto p) { b.ry(p[0], q[0]); }; + d["rz"] = [](auto& b, auto q, auto p) { b.rz(p[0], q[0]); }; + d["p"] = [](auto& b, auto q, auto p) { b.p(p[0], q[0]); }; + d["u1"] = [](auto& b, auto q, auto p) { b.p(p[0], q[0]); }; // alias + d["phase"] = [](auto& b, auto q, auto p) { b.p(p[0], q[0]); }; // alias + + // OneTargetTwoParameter + d["r"] = [](auto& b, auto q, auto p) { b.r(p[0], p[1], q[0]); }; + d["u2"] = [](auto& b, auto q, auto p) { b.u2(p[0], p[1], q[0]); }; + + // OneTargetThreeParameter + auto uFn = [](auto& b, auto q, auto p) { b.u(p[0], p[1], p[2], q[0]); }; + d["U"] = uFn; + d["u3"] = uFn; // alias + d["u"] = uFn; // alias + + // TwoTargetZeroParameter + d["swap"] = [](auto& b, auto q, auto) { b.swap(q[0], q[1]); }; + d["iswap"] = [](auto& b, auto q, auto) { b.iswap(q[0], q[1]); }; + d["dcx"] = [](auto& b, auto q, auto) { b.dcx(q[0], q[1]); }; + d["ecr"] = [](auto& b, auto q, auto) { b.ecr(q[0], q[1]); }; + + // TwoTargetOneParameter + d["rxx"] = [](auto& b, auto q, auto p) { b.rxx(p[0], q[0], q[1]); }; + d["ryy"] = [](auto& b, auto q, auto p) { b.ryy(p[0], q[0], q[1]); }; + d["rzx"] = [](auto& b, auto q, auto p) { b.rzx(p[0], q[0], q[1]); }; + d["rzz"] = [](auto& b, auto q, auto p) { b.rzz(p[0], q[0], q[1]); }; + + // TwoTargetTwoParameter + d["xx_plus_yy"] = [](auto& b, auto q, auto p) { + b.xx_plus_yy(p[0], p[1], q[0], q[1]); + }; + d["xx_minus_yy"] = [](auto& b, auto q, auto p) { + b.xx_minus_yy(p[0], p[1], q[0], q[1]); + }; + + // Controlled OneTargetZeroParameter + d["cx"] = [](auto& b, auto q, auto) { b.cx(q[0], q[1]); }; + d["cnot"] = [](auto& b, auto q, auto) { b.cx(q[0], q[1]); }; // alias + d["cy"] = [](auto& b, auto q, auto) { b.cy(q[0], q[1]); }; + d["cz"] = [](auto& b, auto q, auto) { b.cz(q[0], q[1]); }; + d["ch"] = [](auto& b, auto q, auto) { b.ch(q[0], q[1]); }; + d["csx"] = [](auto& b, auto q, auto) { b.csx(q[0], q[1]); }; + + // Controlled OneTargetOneParameter + d["crx"] = [](auto& b, auto q, auto p) { b.crx(p[0], q[0], q[1]); }; + d["cry"] = [](auto& b, auto q, auto p) { b.cry(p[0], q[0], q[1]); }; + d["crz"] = [](auto& b, auto q, auto p) { b.crz(p[0], q[0], q[1]); }; + d["cp"] = [](auto& b, auto q, auto p) { b.cp(p[0], q[0], q[1]); }; + d["cphase"] = [](auto& b, auto q, auto p) { + b.cp(p[0], q[0], q[1]); + }; // alias + + // Controlled TwoTargetZeroParameter + d["cswap"] = [](auto& b, auto q, auto) { b.cswap(q[0], q[1], q[2]); }; + d["fredkin"] = [](auto& b, auto q, auto) { + b.cswap(q[0], q[1], q[2]); + }; // alias + + // Multi-controlled gates + auto mcxFn = [](auto& b, auto q, auto) { b.mcx(q.drop_back(1), q.back()); }; + d["mcx"] = mcxFn; + d["mcx_gray"] = mcxFn; + + d["mcx_vchain"] = [](auto& b, auto q, auto) { + const size_t n = q.size() - ((q.size() + 1) / 2) + 2; + b.mcx(q.slice(0, n - 1), q[n - 1]); + }; + + d["mcx_recursive"] = [](auto& b, auto q, auto) { + const size_t n = (q.size() > 5) ? q.size() - 1 : q.size(); + b.mcx(q.slice(0, n - 1), q[n - 1]); + }; + + d["mcphase"] = [](auto& b, auto q, auto p) { + b.mcp(p[0], q.drop_back(1), q.back()); + }; + + return d; +} + +static llvm::StringMap> convertToStringMap( + const std::map>& sourceMap) { + llvm::StringMap> targetMap; + for (const auto& [key, value] : sourceMap) { + targetMap.insert(std::make_pair(key, value)); + } + return targetMap; +} + +namespace { + +/// Map from OpenQASM 3 gate identifier to QCProgramBuilder emitter. +const llvm::StringMap GATE_DISPATCH = buildGateDispatch(); + +/// Map of qubits in the current scope. +using QubitScope = llvm::StringMap>; + +/** + * @brief AST visitor that translates an OpenQASM 3 program to a QC program. + * + * @details + * Implements qasm3::InstVisitor to walk the AST produced by qasm3::Parser and + * emit QC operations via the QCProgramBuilder. + */ +class MLIRQasmImporter final : public qasm3::InstVisitor { +public: + explicit MLIRQasmImporter(MLIRContext* ctx) + : builder(ctx), typeCheckPass(constEvalPass), + gates(convertToStringMap(qasm3::STANDARD_GATES)) { + initBuiltins(); + builder.initialize(); + } + + void + visitProgram(const std::vector>& program) { + for (const auto& stmt : program) { + constEvalPass.processStatement(*stmt); + typeCheckPass.processStatement(*stmt); + stmt->accept(this); + } + } + + OwningOpRef finalize() { return builder.finalize(); } + +private: + QCProgramBuilder builder; + qasm3::const_eval::ConstEvalPass constEvalPass; + qasm3::type_checking::TypeCheckPass typeCheckPass; + qasm3::NestedEnvironment> + declarations; + + /// Map from qubit-register name to allocated qubit values. + QubitScope qubitRegisters; + + /// Map from classical-register name to ClassicalRegister. + llvm::StringMap classicalRegisters; + + /// Map from classical-register name to measurement results. + llvm::StringMap> bitValues; + + /// Map from gate identifier to OpenQASM 3 definition. + llvm::StringMap> gates; + + bool openQASM2CompatMode{false}; + + //===--- Initialization -----------------------------------------------===// + + void initBuiltins() { + using namespace qasm3::const_eval; + using namespace qasm3::type_checking; + + auto floatType = + InferredType{std::dynamic_pointer_cast( + std::make_shared>(qasm3::Float, + 64))}; + + auto addConstant = [&](const std::string& name, double value) { + constEvalPass.addConst(name, ConstEvalValue(value)); + typeCheckPass.addBuiltin(name, floatType); + }; + + addConstant("pi", ::qc::PI); + addConstant("π", ::qc::PI); + addConstant("tau", ::qc::TAU); + addConstant("τ", ::qc::TAU); + addConstant("euler", ::qc::E); + addConstant("ℇ", ::qc::E); + + const qasm3::GateInfo mcxInfo{.nControls = 0, + .nTargets = 0, + .nParameters = 0, + .type = ::qc::OpType::X}; + gates["mcx"] = std::make_shared(mcxInfo); + gates["mcx_gray"] = std::make_shared(mcxInfo); + gates["mcx_vchain"] = std::make_shared(mcxInfo); + gates["mcx_recursive"] = std::make_shared(mcxInfo); + + const qasm3::GateInfo mcphaseInfo{.nControls = 0, + .nTargets = 0, + .nParameters = 1, + .type = ::qc::OpType::P}; + gates["mcphase"] = std::make_shared(mcphaseInfo); + } + +public: + //===--- InstVisitor overrides ----------------------------------------===// + + void + visitGateStatement(std::shared_ptr stmt) override { + const auto& id = stmt->identifier; + if (stmt->isOpaque) { + if (!gates.contains(id)) { + throw qasm3::CompilerError("Unsupported opaque gate '" + id + "'.", + stmt->debugInfo); + } + return; + } + if (gates.contains(id)) { + throw qasm3::CompilerError("Gate '" + id + "' already declared.", + stmt->debugInfo); + } + std::vector params; + for (const auto& p : stmt->parameters->identifiers) { + const auto& param = p->identifier; + if (std::ranges::find(params, param) != params.end()) { + throw qasm3::CompilerError( + "Parameter is already declared in compound gate.", stmt->debugInfo); + } + params.push_back(param); + } + std::vector targets; + for (const auto& t : stmt->qubits->identifiers) { + const auto& target = t->identifier; + if (std::ranges::find(targets, target) != targets.end()) { + throw qasm3::CompilerError( + "Target is already declared in compound gate.", stmt->debugInfo); + } + targets.push_back(target); + } + gates[id] = std::make_shared( + std::move(params), std::move(targets), stmt->statements); + } + + void visitVersionDeclaration(const std::shared_ptr + versionDeclaration) override { + if (versionDeclaration->version < 3) { + openQASM2CompatMode = true; + } + } + + void visitDeclarationStatement( + std::shared_ptr stmt) override { + const auto& id = stmt->identifier; + if (declarations.find(id).has_value()) { + throw qasm3::CompilerError("Identifier '" + id + "' already declared.", + stmt->debugInfo); + } + declarations.emplace(id, stmt); + + if (stmt->isConst) { + // Nothing to emit + return; + } + + const auto sizedType = + std::dynamic_pointer_cast>( + std::get<1>(stmt->type)); + if (!sizedType) { + throw qasm3::CompilerError("Only sized types are supported.", + stmt->debugInfo); + } + const auto size = static_cast(sizedType->getDesignator()); + + switch (sizedType->type) { + case qasm3::Qubit: { + const auto& reg = builder.allocQubitRegister(size); + qubitRegisters[id] = reg.qubits; + break; + } + case qasm3::Bit: + case qasm3::Int: + case qasm3::Uint: { + classicalRegisters[id] = builder.allocClassicalBitRegister(size, id); + break; + } + default: + throw qasm3::CompilerError("Unsupported declaration type.", + stmt->debugInfo); + } + + // Handle declarations through measure expressions + if (stmt->expression) { + const auto& innerExpr = stmt->expression->expression; + if (const auto measureExpr = + std::dynamic_pointer_cast(innerExpr)) { + auto target = std::make_shared(id); + visitMeasureAssignment(target, measureExpr, stmt->debugInfo); + return; + } + throw qasm3::CompilerError( + "Only measure expressions can declare variables.", stmt->debugInfo); + } + } + + void visitInitialLayout( + std::shared_ptr /*initialLayout*/) override {} + + void visitOutputPermutation( + std::shared_ptr /*outputPermutation*/) + override {} + + void visitGateCallStatement( + std::shared_ptr stmt) override { + applyGateCallStatement(stmt, qubitRegisters); + } + + void visitAssignmentStatement( + std::shared_ptr stmt) override { + const auto& innerId = stmt->identifier->identifier; + assert(declarations.find(innerId).has_value()); + assert(!declarations.find(innerId)->get()->isConst); + + const auto& innerExpr = stmt->expression->expression; + if (const auto measureExpr = + std::dynamic_pointer_cast(innerExpr)) { + visitMeasureAssignment(stmt->identifier, measureExpr, stmt->debugInfo); + return; + } + + throw qasm3::CompilerError("Classical computations are not supported.", + stmt->debugInfo); + } + + void visitMeasureAssignment( + const std::shared_ptr& target, + const std::shared_ptr& measureExpr, + const std::shared_ptr& debugInfo) { + const auto& bits = resolveClassicalBits(target, debugInfo); + const auto& operand = resolveGateOperand(measureExpr->gate, debugInfo); + SmallVector qubits; + if (std::holds_alternative(operand)) { + qubits.push_back(std::get(operand)); + } else { + qubits = std::get>(operand); + } + if (bits.size() != qubits.size()) { + throw qasm3::CompilerError("The classical register and the quantum " + "register must have the same width.", + debugInfo); + } + for (const auto& [bit, qubit] : llvm::zip_equal(bits, qubits)) { + auto result = MeasureOp::create( + builder, qubit, builder.getStringAttr(bit.registerName), + builder.getI64IntegerAttr(bit.registerSize), + builder.getI64IntegerAttr(bit.registerIndex)) + .getResult(); + auto& regBits = bitValues[bit.registerName]; + const auto index = static_cast(bit.registerIndex); + if (regBits.size() <= index) { + regBits.resize(index + 1); + } + regBits[index] = result; + } + } + + void visitBarrierStatement( + std::shared_ptr stmt) override { + SmallVector qubits; + for (const auto& gate : stmt->gates) { + const auto& operand = resolveGateOperand(gate, stmt->debugInfo); + if (std::holds_alternative(operand)) { + qubits.push_back(std::get(operand)); + } else { + llvm::append_range(qubits, std::get>(operand)); + } + } + builder.barrier(qubits); + } + + void + visitResetStatement(std::shared_ptr stmt) override { + const auto& operand = resolveGateOperand(stmt->gate, stmt->debugInfo); + if (std::holds_alternative(operand)) { + builder.reset(std::get(operand)); + } else { + for (auto qubit : std::get>(operand)) { + builder.reset(qubit); + } + } + } + + void visitIfStatement(std::shared_ptr stmt) override { + if (stmt->thenStatements.empty() && stmt->elseStatements.empty()) { + throw qasm3::CompilerError( + "If statements with empty then and else blocks are not supported.", + stmt->debugInfo); + } + + auto condition = translateCondition(stmt->condition, stmt->debugInfo); + auto hasElse = !stmt->elseStatements.empty(); + + std::vector> thenStatements; + if (stmt->thenStatements.empty()) { + thenStatements = stmt->elseStatements; + hasElse = false; + auto trueValue = builder.boolConstant(true); + condition = + arith::XOrIOp::create(builder, condition, trueValue).getResult(); + } else { + thenStatements = stmt->thenStatements; + } + + auto ifOp = + scf::IfOp::create(builder, condition, /*withElseRegion=*/hasElse); + + // Save current insertion point + OpBuilder::InsertionGuard guard(builder); + + // Then block + builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); + emitBlockStatements(thenStatements, stmt->debugInfo); + + // Else block + if (hasElse) { + builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); + emitBlockStatements(stmt->elseStatements, stmt->debugInfo); + } + } + + //===--- Core gate application ----------------------------------------===// + + /** + * @brief Apply a GateCallStatement by emitting the corresponding QC + * operations. + * + * @param stmt The GateCallStatement to apply. + * @param scope The current qubit scope for resolving operands. If called from + * the main visitor, this is the top-level qubitRegisters map. If called + * recursively for a compound gate, this is the local scope of the + * CompoundGate. + */ + void + applyGateCallStatement(const std::shared_ptr& stmt, + const QubitScope& scope) { + const auto& id = stmt->identifier; + auto it = gates.find(id); + + // OpenQASM 2 compatibility: + // Strip leading c characters and treat them as implicit control modifiers + auto resolvedId = id; + size_t numCompatControls = 0; + if (openQASM2CompatMode && it == gates.end()) { + while (!resolvedId.empty() && resolvedId.front() == 'c') { + resolvedId = resolvedId.substr(1); + ++numCompatControls; + } + if (numCompatControls > 0) { + it = gates.find(resolvedId); + } + } + + if (it == gates.end()) { + throw qasm3::CompilerError("No OpenQASM definition found for gate '" + + id + "'.", + stmt->debugInfo); + } + + // Evaluate parameters to doubles + SmallVector params; + params.reserve(stmt->arguments.size()); + for (const auto& arg : stmt->arguments) { + auto result = constEvalPass.visit(arg); + if (!result.has_value()) { + throw qasm3::CompilerError("Gate parameter could not be evaluated.", + stmt->debugInfo); + } + params.push_back(result->toExpr()->asFP()); + } + + // Expand operands to MLIR values + SmallVector operands; + SmallVector> operandsBroadcasting; + auto broadcasting = false; + for (const auto& operand : stmt->operands) { + const auto& resolvedOperand = + resolveGateOperandInScope(operand, scope, stmt->debugInfo); + if (const auto* operand = std::get_if(&resolvedOperand)) { + operands.push_back(*operand); + } else if (const auto* operand = + std::get_if>(&resolvedOperand)) { + operandsBroadcasting.push_back(*operand); + broadcasting = true; + } + } + + if (broadcasting && !operands.empty()) { + throw qasm3::CompilerError("Gate operands must be single qubits or " + "quantum registers and not a mix of both.", + stmt->debugInfo); + } + + if (broadcasting && numCompatControls != 0) { + throw qasm3::CompilerError("OpenQASM 2 gates cannot be broadcasted.", + stmt->debugInfo); + } + + size_t broadcastWidth = 0; + if (broadcasting) { + for (const auto& operand : operandsBroadcasting) { + if (broadcastWidth == 0) { + broadcastWidth = operand.size(); + } else if (broadcastWidth != operand.size()) { + throw qasm3::CompilerError( + "All broadcasting operands must have the same width.", + stmt->debugInfo); + } + } + } + + auto invert = false; + size_t numControls = 0; + SmallVector posControls; + SmallVector negControls; + SmallVector> posControlsBroadcasting; + SmallVector> negControlsBroadcasting; + + // Parse modifiers + for (const auto& mod : stmt->modifiers) { + if (std::dynamic_pointer_cast(mod)) { + invert = !invert; + } else if (const auto* ctrlMod = + dynamic_cast(mod.get())) { + const auto n = + evaluatePositiveConstant(ctrlMod->expression, stmt->debugInfo, 1); + for (size_t i = 0; i < n; ++i, ++numControls) { + const auto positive = ctrlMod->ctrlType; + if (!broadcasting) { + if (numControls >= operands.size()) { + throw qasm3::CompilerError("Control index out of bounds.", + stmt->debugInfo); + } + auto operand = operands[numControls]; + if (positive) { + posControls.push_back(operand); + } else { + negControls.push_back(operand); + } + } else { + if (numControls >= operandsBroadcasting.size()) { + throw qasm3::CompilerError("Control index out of bounds.", + stmt->debugInfo); + } + const auto& operand = operandsBroadcasting[numControls]; + if (positive) { + posControlsBroadcasting.push_back(operand); + } else { + negControlsBroadcasting.push_back(operand); + } + } + } + } else { + throw qasm3::CompilerError( + "Only ctrl, negctrl, and inv modifiers are supported.", + stmt->debugInfo); + } + } + + // OpenQASM 2 compatibility: + // Append implicit control qubits + for (size_t i = 0; i < numCompatControls; ++i, ++numControls) { + if (numControls >= operands.size()) { + throw qasm3::CompilerError("Control index out of bounds.", + stmt->debugInfo); + } + posControls.push_back(operands[numControls]); + } + + // Remaining operands are target qubits + SmallVector targets; + SmallVector> targetsBroadcasting; + if (!broadcasting) { + targets = llvm::to_vector(llvm::drop_begin(operands, numControls)); + } else { + targetsBroadcasting = + llvm::to_vector(llvm::drop_begin(operandsBroadcasting, numControls)); + } + + // Inline compound gate + if (const auto* compound = + dynamic_cast(it->second.get())) { + if (broadcasting) { + throw qasm3::CompilerError( + "Broadcasted compound gates are not supported.", stmt->debugInfo); + } + applyCompoundGate(*compound, params, targets, posControls, negControls, + invert, stmt->debugInfo); + return; + } + + // Emit standard gate + const auto dispIt = GATE_DISPATCH.find(resolvedId); + if (dispIt == GATE_DISPATCH.end()) { + throw qasm3::CompilerError( + "No MLIR definition found for gate '" + id + "'.", stmt->debugInfo); + } + + if (it->second->getNParameters() != params.size()) { + throw qasm3::CompilerError("Invalid number of parameters for gate '" + + id + "'.", + stmt->debugInfo); + } + + if (!broadcasting) { + emitGate(dispIt->second, params, targets, posControls, negControls, + invert); + } else { + for (size_t b = 0; b < broadcastWidth; ++b) { + SmallVector bTargets; + bTargets.reserve(targetsBroadcasting.size()); + for (const auto& target : targetsBroadcasting) { + bTargets.push_back(target[b]); + } + SmallVector bPosControls; + bPosControls.reserve(posControlsBroadcasting.size()); + for (const auto& ctrl : posControlsBroadcasting) { + bPosControls.push_back(ctrl[b]); + } + SmallVector bNegControls; + bNegControls.reserve(negControlsBroadcasting.size()); + for (const auto& ctrl : negControlsBroadcasting) { + bNegControls.push_back(ctrl[b]); + } + emitGate(dispIt->second, params, bTargets, bPosControls, bNegControls, + invert); + } + } + } + + /// Helper function to build a gate with potential modifiers. + void buildModifiedGate(function_ref bodyFn, + ValueRange targets, ValueRange posControls, + ValueRange negControls, bool invert) { + auto wrappedBodyFn = [&](ValueRange qubits) { + if (invert) { + builder.inv(qubits, function_ref(bodyFn)); + } else { + bodyFn(qubits); + } + }; + + if (posControls.empty() && negControls.empty()) { + wrappedBodyFn(targets); + return; + } + + SmallVector controls; + controls.append(posControls.begin(), posControls.end()); + controls.append(negControls.begin(), negControls.end()); + + for (auto control : negControls) { + builder.x(control); + } + builder.ctrl(controls, targets, + function_ref(wrappedBodyFn)); + for (auto control : negControls) { + builder.x(control); + } + } + + /// Emit a standard gate. + void emitGate(const GateFn& gateFn, const SmallVector& params, + ValueRange targets, ValueRange posControls, + ValueRange negControls, bool invert) { + auto bodyFn = [&](ValueRange qubits) { gateFn(builder, qubits, params); }; + buildModifiedGate(bodyFn, targets, posControls, negControls, invert); + } + + /// Inline a compound gate. + void applyCompoundGate(const qasm3::CompoundGate& gate, + const SmallVector& params, ValueRange targets, + ValueRange posControls, ValueRange negControls, + bool invert, + const std::shared_ptr& debugInfo) { + assert(gate.parameterNames.size() == params.size()); + assert(gate.targetNames.size() == targets.size()); + + // Map from internal target name to index in targets list. This map is + // needed because the qubits may be aliased if the CompoundGate is inlined + // within a modifier region. + llvm::StringMap> targetsMap; + + for (const auto& [targetName, target] : + llvm::zip_equal(gate.targetNames, targets)) { + auto it = llvm::find(targets, target); + if (it == targets.end()) { + throw qasm3::CompilerError( + "Target '" + targetName + "' not found in operands.", debugInfo); + } + const auto index = + static_cast(std::distance(targets.begin(), it)); + targetsMap[targetName].push_back(index); + } + + // Bind parameters as constants + constEvalPass.pushEnv(); + for (size_t i = 0; i < gate.parameterNames.size(); ++i) { + constEvalPass.addConst(gate.parameterNames[i], + qasm3::const_eval::ConstEvalValue(params[i])); + } + + auto bodyFn = [&](ValueRange qubits) { + QubitScope localScope; + for (const auto& [name, indices] : targetsMap) { + SmallVector args; + for (auto index : indices) { + args.push_back(qubits[index]); + } + localScope[name] = std::move(args); + } + for (const auto& stmt : gate.body) { + if (const auto gateCall = + std::dynamic_pointer_cast(stmt)) { + applyGateCallStatement(gateCall, localScope); + continue; + } + throw qasm3::CompilerError("Compound operations with non-quantum " + "statements are not supported.", + debugInfo); + } + }; + + buildModifiedGate(bodyFn, targets, posControls, negControls, invert); + + constEvalPass.popEnv(); + } + + //===--- IfStatement helpers ------------------------------------------===// + + /// Helper function to emit quantum statements within an IfOp's then/else + /// regions. + void emitBlockStatements( + const std::vector>& statements, + const std::shared_ptr& debugInfo) { + for (const auto& stmt : statements) { + if (const auto gateCall = + std::dynamic_pointer_cast(stmt)) { + applyGateCallStatement(gateCall, qubitRegisters); + continue; + } + throw qasm3::CompilerError( + "If statements with non-quantum statements are not supported.", + debugInfo); + } + } + + /// Translate an OpenQASM 3 condition to MLIR. + [[nodiscard]] Value + translateCondition(const std::shared_ptr& condition, + const std::shared_ptr& debugInfo) { + // Single bit (c[0]) + if (const auto& id = + std::dynamic_pointer_cast(condition)) { + return lookupBitValue(id, debugInfo); + } + + // Unary negation (!c[0] or ~c[0]) + if (const auto unaryExpr = + std::dynamic_pointer_cast(condition)) { + if (unaryExpr->op != qasm3::UnaryExpression::LogicalNot && + unaryExpr->op != qasm3::UnaryExpression::BitwiseNot) { + throw qasm3::CompilerError( + "Only ! and ~ are supported in if statements.", debugInfo); + } + const auto& id = std::dynamic_pointer_cast( + unaryExpr->operand); + if (!id) { + throw qasm3::CompilerError("Unary expression has unsupported operand.", + debugInfo); + } + auto value = lookupBitValue(id, debugInfo); + auto trueValue = builder.boolConstant(true); + return arith::XOrIOp::create(builder, value, trueValue).getResult(); + } + + // Register comparison (creg == N, creg != N, etc.) + if (const auto binaryExpr = + std::dynamic_pointer_cast(condition)) { + throw qasm3::CompilerError("Register comparisons are not supported.", + debugInfo); + } + + throw qasm3::CompilerError( + "Unsupported condition expression in if statement.", debugInfo); + } + + /// Look up the most recent measurement result for a classical bit. + [[nodiscard]] Value + lookupBitValue(const std::shared_ptr& id, + const std::shared_ptr& debugInfo) const { + const auto& regName = id->identifier; + auto it = bitValues.find(regName); + if (it == bitValues.end()) { + throw qasm3::CompilerError("No classical bit of register '" + regName + + "' has been measured yet.", + debugInfo); + } + const auto& regBits = it->second; + + if (id->indices.empty()) { + assert(regBits.size() == 1); + return regBits[0]; + } + + if (id->indices.size() != 1 || + id->indices[0]->indexExpressions.size() != 1) { + throw qasm3::CompilerError("Only single-index expressions are supported.", + debugInfo); + } + const auto& indexExpression = id->indices[0]->indexExpressions[0]; + const auto index = evaluatePositiveConstant(indexExpression, debugInfo); + if (index >= regBits.size() || !regBits[index]) { + throw qasm3::CompilerError("Bit " + std::to_string(index) + + " of register '" + regName + + "' has been not measured yet.", + debugInfo); + } + return regBits[index]; + } + + //===--- Operand resolution helpers ------------------------------------===// + + /** + * @brief Resolve a qubit operand against the top-level qubitRegisters map. + * + * @return A variant containing + * - a `Value` if the operand is, e.g., `q[0]`, + * - a `Value` if the operand `q` is a single-qubit register, or + * - a `SmallVector` if the operand `q` is a multi-qubit register. + */ + [[nodiscard]] std::variant> + resolveGateOperand(const std::shared_ptr& operand, + const std::shared_ptr& debugInfo) { + return resolveGateOperandInScope(operand, qubitRegisters, debugInfo); + } + + /** + * @brief Resolve a qubit operand against @p scope. + * + * @return A variant containing + * - a `Value` if the operand is, e.g., `q[0]`, + * - a `Value` if the operand `q` is a single-qubit register, or + * - a `SmallVector` if the operand `q` is a multi-qubit register. + */ + [[nodiscard]] std::variant> + resolveGateOperandInScope( + const std::shared_ptr& operand, + const QubitScope& scope, + const std::shared_ptr& debugInfo) { + if (operand->isHardwareQubit()) { + return builder.staticQubit(operand->getHardwareQubit()); + } + + const auto& id = operand->getIdentifier(); + const auto& name = id->identifier; + auto it = scope.find(name); + if (it == scope.end()) { + throw qasm3::CompilerError("Unknown qubit register '" + name + "'.", + debugInfo); + } + + const auto& qubits = it->second; + + if (id->indices.empty()) { + if (qubits.size() == 1) { + return qubits[0]; + } + // Return full register + return qubits; + } + + if (id->indices.size() != 1 || + id->indices[0]->indexExpressions.size() != 1) { + throw qasm3::CompilerError("Only single-index expressions are supported.", + debugInfo); + } + const auto& indexExpression = id->indices[0]->indexExpressions[0]; + const auto index = evaluatePositiveConstant(indexExpression, debugInfo); + if (index >= qubits.size()) { + throw qasm3::CompilerError("Qubit index out of bounds.", debugInfo); + } + return qubits[index]; + } + + /// Resolve a classical bit operand. + [[nodiscard]] SmallVector resolveClassicalBits( + const std::shared_ptr& operand, + const std::shared_ptr& debugInfo) const { + const auto& name = operand->identifier; + auto it = classicalRegisters.find(name); + if (it == classicalRegisters.end()) { + throw qasm3::CompilerError("Unknown classical register '" + name + "'.", + debugInfo); + } + + const auto& creg = it->second; + SmallVector bits; + + if (operand->indices.empty()) { + for (int64_t i = 0; i < creg.size; ++i) { + bits.push_back(creg[i]); + } + return bits; + } + + if (operand->indices.size() != 1 || + operand->indices[0]->indexExpressions.size() != 1) { + throw qasm3::CompilerError("Only single-index expressions are supported.", + debugInfo); + } + const auto& indexExpression = operand->indices[0]->indexExpressions[0]; + const auto index = evaluatePositiveConstant(indexExpression, debugInfo); + if (std::cmp_greater_equal(index, creg.size)) { + throw qasm3::CompilerError("Classical bit index out of bounds.", + debugInfo); + } + bits.push_back(creg[static_cast(index)]); + return bits; + } + + /// Evaluate a constant expression to a positive integer. + static size_t + evaluatePositiveConstant(const std::shared_ptr& expr, + const std::shared_ptr& debugInfo, + size_t defaultValue = 0) { + if (!expr) { + return defaultValue; + } + const auto constVal = std::dynamic_pointer_cast(expr); + if (!constVal) { + throw qasm3::CompilerError("Expected a constant integer expression.", + debugInfo); + } + return static_cast(constVal->getUInt()); + } +}; + +} // namespace + +//===----------------------------------------------------------------------===// +// Public API +//===----------------------------------------------------------------------===// + +OwningOpRef translateQASM3ToQC(llvm::SourceMgr& sourceMgr, + MLIRContext* context) { + try { + auto buffer = + sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID())->getBuffer(); + std::string_view view(buffer.data(), buffer.size()); + std::istringstream input((std::string(view))); + + qasm3::Parser parser(input); + const auto program = parser.parseProgram(); + + MLIRQasmImporter importer(context); + importer.visitProgram(program); + return importer.finalize(); + } catch (const qasm3::CompilerError& e) { + llvm::errs() << "Import error: " << e.what() << "\n"; + return nullptr; + } catch (const std::exception& e) { + llvm::errs() << "Import error: " << e.what() << "\n"; + return nullptr; + } +} + +OwningOpRef translateQASM3ToQC(StringRef source, + MLIRContext* context) { + llvm::SourceMgr sourceMgr; + auto buffer = llvm::MemoryBuffer::getMemBufferCopy(source); + sourceMgr.AddNewSourceBuffer(std::move(buffer), SMLoc()); + return translateQASM3ToQC(sourceMgr, context); +} + +} // namespace mlir::qc diff --git a/mlir/tools/mqt-cc/CMakeLists.txt b/mlir/tools/mqt-cc/CMakeLists.txt index adf0cd32d3..022aa279d8 100644 --- a/mlir/tools/mqt-cc/CMakeLists.txt +++ b/mlir/tools/mqt-cc/CMakeLists.txt @@ -8,17 +8,7 @@ # Build the compiler driver executable add_mlir_tool(mqt-cc mqt-cc.cpp DEPENDS MQTCompilerPipeline SUPPORT_PLUGINS) -target_link_libraries( - mqt-cc - PRIVATE MQTCompilerPipeline - # Required for parsing .mlir files - MLIRParser - # Required for file I/O - MLIRSupport - # Required for OpenQASM parsing - MQT::CoreQASM - MQT::CoreIR - MLIRQCTranslation) +target_link_libraries(mqt-cc PRIVATE MQTCompilerPipeline MLIRParser MLIRSupport MLIRQCTranslation) mqt_mlir_target_use_project_options(mqt-cc) llvm_update_compile_flags(mqt-cc) diff --git a/mlir/tools/mqt-cc/mqt-cc.cpp b/mlir/tools/mqt-cc/mqt-cc.cpp index cc13e2cdba..d8fb75daa4 100644 --- a/mlir/tools/mqt-cc/mqt-cc.cpp +++ b/mlir/tools/mqt-cc/mqt-cc.cpp @@ -8,14 +8,11 @@ * Licensed under the MIT License */ -#include "ir/QuantumComputation.hpp" #include "mlir/Compiler/CompilerPipeline.h" #include "mlir/Dialect/QC/IR/QCDialect.h" -#include "mlir/Dialect/QC/Translation/TranslateQuantumComputationToQC.h" +#include "mlir/Dialect/QC/Translation/TranslateQASM3ToQC.h" #include "mlir/Dialect/QCO/IR/QCODialect.h" #include "mlir/Dialect/QTensor/IR/QTensorDialect.h" -#include "qasm3/Exception.hpp" -#include "qasm3/Importer.hpp" #include #include @@ -33,9 +30,9 @@ #include #include #include +#include #include -#include #include #include @@ -94,30 +91,26 @@ static llvm::cl::opt enableHadamardLifting( /** * @brief Load and parse a .qasm file */ -static OwningOpRef loadQASMFile(llvm::StringRef filename, +static OwningOpRef loadQASMFile(StringRef filename, MLIRContext* context) { - try { - // Parse the input QASM file - const ::qc::QuantumComputation qc = - qasm3::Importer::importf(filename.str()); - // Translate to MLIR dialect QC - return translateQuantumComputationToQC(context, qc); - } catch (const qasm3::CompilerError& exception) { - llvm::errs() << "Failed to parse QASM file '" << filename << "': '" - << exception.what() << "'\n"; - } catch (const std::exception& exception) { - llvm::errs() << "Failed to load QASM file '" << filename << "': '" - << exception.what() << "'\n"; + std::string errorMessage; + auto file = openInputFile(filename, &errorMessage); + if (!file) { + llvm::errs() << "Failed to load file '" << filename << "': '" + << errorMessage << "'\n"; + return nullptr; } - return nullptr; + + llvm::SourceMgr sourceMgr; + sourceMgr.AddNewSourceBuffer(std::move(file), SMLoc()); + return qc::translateQASM3ToQC(sourceMgr, context); } /** * @brief Load and parse a .mlir file */ -static OwningOpRef loadMLIRFile(llvm::StringRef filename, +static OwningOpRef loadMLIRFile(StringRef filename, MLIRContext* context) { - // Set up the input file std::string errorMessage; auto file = openInputFile(filename, &errorMessage); if (!file) { @@ -126,7 +119,6 @@ static OwningOpRef loadMLIRFile(llvm::StringRef filename, return nullptr; } - // Parse the input MLIR llvm::SourceMgr sourceMgr; sourceMgr.AddNewSourceBuffer(std::move(file), SMLoc()); return parseSourceFile(sourceMgr, context); @@ -135,8 +127,7 @@ static OwningOpRef loadMLIRFile(llvm::StringRef filename, /** * @brief Write the module to the output file */ -static mlir::LogicalResult writeOutput(ModuleOp module, - llvm::StringRef filename) { +static mlir::LogicalResult writeOutput(ModuleOp module, StringRef filename) { std::string errorMessage; const auto output = openOutputFile(filename, &errorMessage); if (!output) { @@ -153,13 +144,14 @@ int main(int argc, char** argv) { const llvm::InitLLVM y(argc, argv); // Parse command-line options; exit on error and print to stderr - llvm::cl::ParseCommandLineOptions(argc, argv, "MQT Core Compiler Driver\n"); + llvm::cl::ParseCommandLineOptions(argc, argv, + "MQT Compiler Collection Driver\n"); // Set up MLIR context with all required dialects DialectRegistry registry; registry .insert(); MLIRContext context(registry); diff --git a/mlir/unittests/Dialect/QC/Translation/CMakeLists.txt b/mlir/unittests/Dialect/QC/Translation/CMakeLists.txt index de8c687a8f..c711b25c8a 100644 --- a/mlir/unittests/Dialect/QC/Translation/CMakeLists.txt +++ b/mlir/unittests/Dialect/QC/Translation/CMakeLists.txt @@ -8,7 +8,7 @@ file(GLOB_RECURSE TEST_SOURCES "*.cpp") -set(target_name mqt-core-mlir-unittest-quantum-computation-translation) +set(target_name mqt-core-mlir-unittest-qc-translation) add_executable(${target_name} ${TEST_SOURCES}) target_link_libraries( @@ -19,6 +19,7 @@ target_link_libraries( MLIRQCProgramBuilder MLIRQCTranslation MLIRQCPrograms + MLIRQASMPrograms MLIRQuantumComputationPrograms MQT::CoreIR) diff --git a/mlir/unittests/Dialect/QC/Translation/test_qasm3_translation.cpp b/mlir/unittests/Dialect/QC/Translation/test_qasm3_translation.cpp new file mode 100644 index 0000000000..b18c858b2d --- /dev/null +++ b/mlir/unittests/Dialect/QC/Translation/test_qasm3_translation.cpp @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2023 - 2026 Chair for Design Automation, TUM + * Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#include "TestCaseUtils.h" +#include "mlir/Dialect/QC/Builder/QCProgramBuilder.h" +#include "mlir/Dialect/QC/IR/QCDialect.h" +#include "mlir/Dialect/QC/Translation/TranslateQASM3ToQC.h" +#include "mlir/Support/IRVerification.h" +#include "mlir/Support/Passes.h" +#include "qasm_programs.h" +#include "qc_programs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace mlir; + +namespace { + +struct QASM3TranslationTestCase { + std::string name; + std::string source; + mqt::test::NamedBuilder referenceBuilder; + + friend std::ostream& operator<<(std::ostream& os, + const QASM3TranslationTestCase& test); +}; + +// NOLINTNEXTLINE(llvm-prefer-static-over-anonymous-namespace) +std::ostream& operator<<(std::ostream& os, + const QASM3TranslationTestCase& test) { + return os << "QASM3Translation{" << test.name << ", reference=" + << mqt::test::displayName(test.referenceBuilder.name) << "}"; +} + +class QASM3TranslationTest + : public testing::TestWithParam { +protected: + std::unique_ptr context; + + void SetUp() override { + DialectRegistry registry; + registry.insert(); + context = std::make_unique(); + context->appendDialectRegistry(registry); + context->loadAllAvailableDialects(); + } +}; + +} // namespace + +static void twoX(qc::QCProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + b.x(q[0]); + b.x(q[1]); +} + +static void singleNegControlledX(qc::QCProgramBuilder& b) { + auto q = b.allocQubitRegister(2); + b.x(q[0]); + b.cx(q[0], q[1]); + b.x(q[0]); +} + +static void tripleControlledX(qc::QCProgramBuilder& b) { + auto q = b.allocQubitRegister(4); + b.mcx({q[0], q[1], q[2]}, q[3]); +} + +static void 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]); +} + +static void twoMixedControlledX(qc::QCProgramBuilder& b) { + auto q1 = b.allocQubitRegister(2); + auto q2 = b.allocQubitRegister(2); + auto q3 = b.allocQubitRegister(2); + b.x(q2[0]); + b.mcx({q1[0], q2[0]}, q3[0]); + b.x(q2[0]); + b.x(q2[1]); + b.mcx({q1[1], q2[1]}, q3[1]); + b.x(q2[1]); +} + +static void 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]); }); +} + +TEST_P(QASM3TranslationTest, ProgramEquivalence) { + const auto name = " (" + GetParam().name + ")"; + const auto& source = GetParam().source; + const auto referenceBuilder = GetParam().referenceBuilder; + mqt::test::DeferredPrinter printer; + + auto translated = qc::translateQASM3ToQC(source, context.get()); + ASSERT_TRUE(translated); + printer.record(translated.get(), "Translated QC IR" + name); + EXPECT_TRUE(verify(*translated).succeeded()); + + EXPECT_TRUE(runQCCleanupPipeline(translated.get()).succeeded()); + printer.record(translated.get(), "Canonicalized Translated QC IR" + name); + EXPECT_TRUE(verify(*translated).succeeded()); + + auto reference = + qc::QCProgramBuilder::build(context.get(), referenceBuilder.fn); + ASSERT_TRUE(reference); + printer.record(reference.get(), "Reference QC IR" + name); + EXPECT_TRUE(verify(*reference).succeeded()); + + EXPECT_TRUE(runQCCleanupPipeline(reference.get()).succeeded()); + printer.record(reference.get(), "Canonicalized Reference QC IR" + name); + EXPECT_TRUE(verify(*reference).succeeded()); + + EXPECT_TRUE( + areModulesEquivalentWithPermutations(translated.get(), reference.get())); +} + +INSTANTIATE_TEST_SUITE_P( + QASM3TranslationProgramsTest, QASM3TranslationTest, + testing::Values( + + QASM3TranslationTestCase{"AllocQubit", qasm::allocQubit, + MQT_NAMED_BUILDER(qc::allocQubit)}, + QASM3TranslationTestCase{"AllocQubitRegister", qasm::allocQubitRegister, + MQT_NAMED_BUILDER(qc::allocQubitRegister)}, + QASM3TranslationTestCase{ + "AllocMultipleQubitRegisters", qasm::allocMultipleQubitRegisters, + MQT_NAMED_BUILDER(qc::allocMultipleQubitRegisters)}, + QASM3TranslationTestCase{"AllocLargeRegister", qasm::allocLargeRegister, + MQT_NAMED_BUILDER(qc::allocLargeRegister)}, + QASM3TranslationTestCase{ + "SingleMeasurementToSingleBit", qasm::singleMeasurementToSingleBit, + MQT_NAMED_BUILDER(qc::singleMeasurementToSingleBit)}, + QASM3TranslationTestCase{ + "RepeatedMeasurementToSameBit", qasm::repeatedMeasurementToSameBit, + MQT_NAMED_BUILDER(qc::repeatedMeasurementToSameBit)}, + QASM3TranslationTestCase{ + "RepeatedMeasurementToDifferentBits", + qasm::repeatedMeasurementToDifferentBits, + MQT_NAMED_BUILDER(qc::repeatedMeasurementToDifferentBits)}, + QASM3TranslationTestCase{ + "MultipleClassicalRegistersAndMeasurements", + qasm::multipleClassicalRegistersAndMeasurements, + MQT_NAMED_BUILDER(qc::multipleClassicalRegistersAndMeasurements)}, + QASM3TranslationTestCase{ + "ResetQubitAfterSingleOp", qasm::resetQubitAfterSingleOp, + MQT_NAMED_BUILDER(qc::resetQubitAfterSingleOp)}, + QASM3TranslationTestCase{ + "ResetMultipleQubitsAfterSingleOp", + qasm::resetMultipleQubitsAfterSingleOp, + MQT_NAMED_BUILDER(qc::resetMultipleQubitsAfterSingleOp)}, + QASM3TranslationTestCase{ + "RepeatedResetAfterSingleOp", qasm::repeatedResetAfterSingleOp, + MQT_NAMED_BUILDER(qc::repeatedResetAfterSingleOp)}, + QASM3TranslationTestCase{"GlobalPhase", qasm::globalPhase, + MQT_NAMED_BUILDER(qc::globalPhase)}, + QASM3TranslationTestCase{"InverseGlobalPhase", qasm::inverseGlobalPhase, + 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{"X", qasm::x, MQT_NAMED_BUILDER(qc::x)}, + QASM3TranslationTestCase{"TwoX", qasm::twoX, MQT_NAMED_BUILDER(twoX)}, + QASM3TranslationTestCase{"SingleControlledX", qasm::singleControlledX, + MQT_NAMED_BUILDER(qc::singleControlledX)}, + QASM3TranslationTestCase{"SingleNegControlledX", + qasm::singleNegControlledX, + MQT_NAMED_BUILDER(singleNegControlledX)}, + QASM3TranslationTestCase{"MultipleControlledX", + qasm::multipleControlledX, + MQT_NAMED_BUILDER(qc::multipleControlledX)}, + QASM3TranslationTestCase{"TripleControlledXOpenQASM2", + qasm::tripleControlledXOpenQASM2, + MQT_NAMED_BUILDER(tripleControlledX)}, + QASM3TranslationTestCase{"MixedControlledX", qasm::mixedControlledX, + MQT_NAMED_BUILDER(mixedControlledX)}, + QASM3TranslationTestCase{"TwoMixedControlledX", + qasm::twoMixedControlledX, + MQT_NAMED_BUILDER(twoMixedControlledX)}, + QASM3TranslationTestCase{"InverseX", qasm::inverseX, + MQT_NAMED_BUILDER(qc::inverseX)}, + QASM3TranslationTestCase{ + "InverseMultipleControlledX", qasm::inverseMultipleControlledX, + MQT_NAMED_BUILDER(qc::inverseMultipleControlledX)}, + QASM3TranslationTestCase{"Y", qasm::y, MQT_NAMED_BUILDER(qc::y)}, + QASM3TranslationTestCase{"SingleControlledY", qasm::singleControlledY, + MQT_NAMED_BUILDER(qc::singleControlledY)}, + QASM3TranslationTestCase{"MultipleControlledY", + qasm::multipleControlledY, + MQT_NAMED_BUILDER(qc::multipleControlledY)}, + QASM3TranslationTestCase{"Z", qasm::z, MQT_NAMED_BUILDER(qc::z)}, + QASM3TranslationTestCase{"SingleControlledZ", qasm::singleControlledZ, + MQT_NAMED_BUILDER(qc::singleControlledZ)}, + QASM3TranslationTestCase{"MultipleControlledZ", + qasm::multipleControlledZ, + MQT_NAMED_BUILDER(qc::multipleControlledZ)}, + QASM3TranslationTestCase{"H", qasm::h, MQT_NAMED_BUILDER(qc::h)}, + QASM3TranslationTestCase{"SingleControlledH", qasm::singleControlledH, + MQT_NAMED_BUILDER(qc::singleControlledH)}, + QASM3TranslationTestCase{"MultipleControlledH", + qasm::multipleControlledH, + MQT_NAMED_BUILDER(qc::multipleControlledH)}, + QASM3TranslationTestCase{"S", qasm::s, MQT_NAMED_BUILDER(qc::s)}, + QASM3TranslationTestCase{"SingleControlledS", qasm::singleControlledS, + MQT_NAMED_BUILDER(qc::singleControlledS)}, + QASM3TranslationTestCase{"MultipleControlledS", + qasm::multipleControlledS, + MQT_NAMED_BUILDER(qc::multipleControlledS)}, + QASM3TranslationTestCase{"Sdg", qasm::sdg, MQT_NAMED_BUILDER(qc::sdg)}, + QASM3TranslationTestCase{"SingleControlledSdg", + qasm::singleControlledSdg, + MQT_NAMED_BUILDER(qc::singleControlledSdg)}, + QASM3TranslationTestCase{"MultipleControlledSdg", + qasm::multipleControlledSdg, + MQT_NAMED_BUILDER(qc::multipleControlledSdg)}, + QASM3TranslationTestCase{"T", qasm::t_, MQT_NAMED_BUILDER(qc::t_)}, + QASM3TranslationTestCase{"SingleControlledT", qasm::singleControlledT, + MQT_NAMED_BUILDER(qc::singleControlledT)}, + QASM3TranslationTestCase{"MultipleControlledT", + qasm::multipleControlledT, + MQT_NAMED_BUILDER(qc::multipleControlledT)}, + QASM3TranslationTestCase{"Tdg", qasm::tdg, MQT_NAMED_BUILDER(qc::tdg)}, + QASM3TranslationTestCase{"SingleControlledTdg", + qasm::singleControlledTdg, + MQT_NAMED_BUILDER(qc::singleControlledTdg)}, + QASM3TranslationTestCase{"MultipleControlledTdg", + qasm::multipleControlledTdg, + MQT_NAMED_BUILDER(qc::multipleControlledTdg)}, + QASM3TranslationTestCase{"SX", qasm::sx, MQT_NAMED_BUILDER(qc::sx)}, + QASM3TranslationTestCase{"SingleControlledSX", qasm::singleControlledSx, + MQT_NAMED_BUILDER(qc::singleControlledSx)}, + QASM3TranslationTestCase{"MultipleControlledSX", + qasm::multipleControlledSx, + MQT_NAMED_BUILDER(qc::multipleControlledSx)}, + QASM3TranslationTestCase{"SXdg", qasm::sxdg, + MQT_NAMED_BUILDER(qc::sxdg)}, + QASM3TranslationTestCase{"SingleControlledSXdg", + qasm::singleControlledSxdg, + MQT_NAMED_BUILDER(qc::singleControlledSxdg)}, + QASM3TranslationTestCase{"MultipleControlledSXdg", + qasm::multipleControlledSxdg, + MQT_NAMED_BUILDER(qc::multipleControlledSxdg)}, + QASM3TranslationTestCase{"RX", qasm::rx, MQT_NAMED_BUILDER(qc::rx)}, + QASM3TranslationTestCase{"SingleControlledRX", qasm::singleControlledRx, + MQT_NAMED_BUILDER(qc::singleControlledRx)}, + QASM3TranslationTestCase{"MultipleControlledRX", + qasm::multipleControlledRx, + MQT_NAMED_BUILDER(qc::multipleControlledRx)}, + QASM3TranslationTestCase{"RY", qasm::ry, MQT_NAMED_BUILDER(qc::ry)}, + QASM3TranslationTestCase{"SingleControlledRY", qasm::singleControlledRy, + MQT_NAMED_BUILDER(qc::singleControlledRy)}, + QASM3TranslationTestCase{"MultipleControlledRY", + qasm::multipleControlledRy, + MQT_NAMED_BUILDER(qc::multipleControlledRy)}, + QASM3TranslationTestCase{"RZ", qasm::rz, MQT_NAMED_BUILDER(qc::rz)}, + QASM3TranslationTestCase{"SingleControlledRZ", qasm::singleControlledRz, + MQT_NAMED_BUILDER(qc::singleControlledRz)}, + QASM3TranslationTestCase{"MultipleControlledRZ", + qasm::multipleControlledRz, + MQT_NAMED_BUILDER(qc::multipleControlledRz)}, + QASM3TranslationTestCase{"P", qasm::p, MQT_NAMED_BUILDER(qc::p)}, + QASM3TranslationTestCase{"SingleControlledP", qasm::singleControlledP, + MQT_NAMED_BUILDER(qc::singleControlledP)}, + QASM3TranslationTestCase{"MultipleControlledP", + qasm::multipleControlledP, + MQT_NAMED_BUILDER(qc::multipleControlledP)}, + QASM3TranslationTestCase{"R", qasm::r, MQT_NAMED_BUILDER(qc::r)}, + QASM3TranslationTestCase{"SingleControlledR", qasm::singleControlledR, + MQT_NAMED_BUILDER(qc::singleControlledR)}, + QASM3TranslationTestCase{"MultipleControlledR", + qasm::multipleControlledR, + MQT_NAMED_BUILDER(qc::multipleControlledR)}, + QASM3TranslationTestCase{"U2", qasm::u2, MQT_NAMED_BUILDER(qc::u2)}, + QASM3TranslationTestCase{"SingleControlledU2", qasm::singleControlledU2, + MQT_NAMED_BUILDER(qc::singleControlledU2)}, + QASM3TranslationTestCase{"MultipleControlledU2", + qasm::multipleControlledU2, + MQT_NAMED_BUILDER(qc::multipleControlledU2)}, + QASM3TranslationTestCase{"U", qasm::u, MQT_NAMED_BUILDER(qc::u)}, + QASM3TranslationTestCase{"SingleControlledU", qasm::singleControlledU, + MQT_NAMED_BUILDER(qc::singleControlledU)}, + QASM3TranslationTestCase{"MultipleControlledU", + qasm::multipleControlledU, + MQT_NAMED_BUILDER(qc::multipleControlledU)}, + QASM3TranslationTestCase{"SWAP", qasm::swap, + MQT_NAMED_BUILDER(qc::swap)}, + QASM3TranslationTestCase{"SingleControlledSWAP", + qasm::singleControlledSwap, + MQT_NAMED_BUILDER(qc::singleControlledSwap)}, + QASM3TranslationTestCase{"MultipleControlledSWAP", + qasm::multipleControlledSwap, + MQT_NAMED_BUILDER(qc::multipleControlledSwap)}, + QASM3TranslationTestCase{"iSWAP", qasm::iswap, + MQT_NAMED_BUILDER(qc::iswap)}, + QASM3TranslationTestCase{"SingleControllediSWAP", + qasm::singleControlledIswap, + MQT_NAMED_BUILDER(qc::singleControlledIswap)}, + QASM3TranslationTestCase{ + "MultipleControllediSWAP", qasm::multipleControlledIswap, + MQT_NAMED_BUILDER(qc::multipleControlledIswap)}, + QASM3TranslationTestCase{"InverseISWAP", qasm::inverseIswap, + MQT_NAMED_BUILDER(qc::inverseIswap)}, + QASM3TranslationTestCase{ + "InverseMultiControlledISWAP", qasm::inverseMultipleControlledIswap, + MQT_NAMED_BUILDER(qc::inverseMultipleControlledIswap)}, + QASM3TranslationTestCase{"DCX", qasm::dcx, MQT_NAMED_BUILDER(qc::dcx)}, + QASM3TranslationTestCase{"SingleControlledDCX", + qasm::singleControlledDcx, + MQT_NAMED_BUILDER(qc::singleControlledDcx)}, + QASM3TranslationTestCase{"MultipleControlledDCX", + qasm::multipleControlledDcx, + MQT_NAMED_BUILDER(qc::multipleControlledDcx)}, + QASM3TranslationTestCase{"ECR", qasm::ecr, MQT_NAMED_BUILDER(qc::ecr)}, + QASM3TranslationTestCase{"SingleControlledECR", + qasm::singleControlledEcr, + MQT_NAMED_BUILDER(qc::singleControlledEcr)}, + QASM3TranslationTestCase{"MultipleControlledECR", + qasm::multipleControlledEcr, + MQT_NAMED_BUILDER(qc::multipleControlledEcr)}, + QASM3TranslationTestCase{"RXX", qasm::rxx, MQT_NAMED_BUILDER(qc::rxx)}, + QASM3TranslationTestCase{"SingleControlledRXX", + qasm::singleControlledRxx, + MQT_NAMED_BUILDER(qc::singleControlledRxx)}, + QASM3TranslationTestCase{"MultipleControlledRXX", + qasm::multipleControlledRxx, + MQT_NAMED_BUILDER(qc::multipleControlledRxx)}, + QASM3TranslationTestCase{"TripleControlledRXX", + qasm::tripleControlledRxx, + MQT_NAMED_BUILDER(qc::tripleControlledRxx)}, + QASM3TranslationTestCase{"RYY", qasm::ryy, MQT_NAMED_BUILDER(qc::ryy)}, + QASM3TranslationTestCase{"SingleControlledRYY", + qasm::singleControlledRyy, + MQT_NAMED_BUILDER(qc::singleControlledRyy)}, + QASM3TranslationTestCase{"MultipleControlledRYY", + qasm::multipleControlledRyy, + MQT_NAMED_BUILDER(qc::multipleControlledRyy)}, + QASM3TranslationTestCase{"RZX", qasm::rzx, MQT_NAMED_BUILDER(qc::rzx)}, + QASM3TranslationTestCase{"SingleControlledRZX", + qasm::singleControlledRzx, + MQT_NAMED_BUILDER(qc::singleControlledRzx)}, + QASM3TranslationTestCase{"MultipleControlledRZX", + qasm::multipleControlledRzx, + MQT_NAMED_BUILDER(qc::multipleControlledRzx)}, + QASM3TranslationTestCase{"RZZ", qasm::rzz, MQT_NAMED_BUILDER(qc::rzz)}, + QASM3TranslationTestCase{"SingleControlledRZZ", + qasm::singleControlledRzz, + MQT_NAMED_BUILDER(qc::singleControlledRzz)}, + QASM3TranslationTestCase{"MultipleControlledRZZ", + qasm::multipleControlledRzz, + MQT_NAMED_BUILDER(qc::multipleControlledRzz)}, + QASM3TranslationTestCase{"XXPlusYY", qasm::xxPlusYY, + MQT_NAMED_BUILDER(qc::xxPlusYY)}, + QASM3TranslationTestCase{ + "SingleControlledXXPlusYY", qasm::singleControlledXxPlusYY, + MQT_NAMED_BUILDER(qc::singleControlledXxPlusYY)}, + QASM3TranslationTestCase{ + "MultipleControlledXXPlusYY", qasm::multipleControlledXxPlusYY, + MQT_NAMED_BUILDER(qc::multipleControlledXxPlusYY)}, + QASM3TranslationTestCase{"XXMinusYY", qasm::xxMinusYY, + MQT_NAMED_BUILDER(qc::xxMinusYY)}, + QASM3TranslationTestCase{ + "SingleControlledXXMinusYY", qasm::singleControlledXxMinusYY, + MQT_NAMED_BUILDER(qc::singleControlledXxMinusYY)}, + QASM3TranslationTestCase{ + "MultipleControlledXXMinusYY", qasm::multipleControlledXxMinusYY, + MQT_NAMED_BUILDER(qc::multipleControlledXxMinusYY)}, + QASM3TranslationTestCase{"Barrier", qasm::barrier, + MQT_NAMED_BUILDER(qc::barrier)}, + QASM3TranslationTestCase{"BarrierTwoQubits", qasm::barrierTwoQubits, + MQT_NAMED_BUILDER(qc::barrierTwoQubits)}, + QASM3TranslationTestCase{"BarrierMultipleQubits", + qasm::barrierMultipleQubits, + MQT_NAMED_BUILDER(qc::barrierMultipleQubits)}, + QASM3TranslationTestCase{"CtrlTwo", qasm::ctrlTwo, + MQT_NAMED_BUILDER(qc::ctrlTwo)}, + QASM3TranslationTestCase{"CtrlTwoMixed", qasm::ctrlTwoMixed, + MQT_NAMED_BUILDER(qc::ctrlTwoMixed)}, + QASM3TranslationTestCase{"SimpleIf", qasm::simpleIf, + MQT_NAMED_BUILDER(qc::simpleIf)}, + QASM3TranslationTestCase{"IfNot", qasm::ifNot, + MQT_NAMED_BUILDER(ifNot)}, + QASM3TranslationTestCase{"IfTwoQubits", qasm::ifTwoQubits, + MQT_NAMED_BUILDER(qc::ifTwoQubits)}, + QASM3TranslationTestCase{"IfEmptyThen", qasm::ifEmptyThen, + MQT_NAMED_BUILDER(ifNot)}, + QASM3TranslationTestCase{"IfElse", qasm::ifElse, + MQT_NAMED_BUILDER(qc::ifElse)})); diff --git a/mlir/unittests/programs/CMakeLists.txt b/mlir/unittests/programs/CMakeLists.txt index 8b58449e76..7fc03cf3d4 100644 --- a/mlir/unittests/programs/CMakeLists.txt +++ b/mlir/unittests/programs/CMakeLists.txt @@ -6,18 +6,32 @@ # # Licensed under the MIT License +add_library(MLIRQASMPrograms qasm_programs.cpp) +target_link_libraries(MLIRQASMPrograms PRIVATE MQT::ProjectOptions) +target_sources(MLIRQASMPrograms PUBLIC FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES + qasm_programs.h) + add_library(MLIRQCPrograms qc_programs.cpp) -target_link_libraries(MLIRQCPrograms PUBLIC MLIRQCProgramBuilder) +target_link_libraries( + MLIRQCPrograms + PUBLIC MLIRQCProgramBuilder + PRIVATE MQT::ProjectOptions) target_sources(MLIRQCPrograms PUBLIC FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES qc_programs.h) add_library(MLIRQCOPrograms qco_programs.cpp) -target_link_libraries(MLIRQCOPrograms PUBLIC MLIRQCOProgramBuilder) +target_link_libraries( + MLIRQCOPrograms + PUBLIC MLIRQCOProgramBuilder + PRIVATE MQT::ProjectOptions) target_sources(MLIRQCOPrograms PUBLIC FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES qco_programs.h) add_library(MLIRQIRPrograms qir_programs.cpp) -target_link_libraries(MLIRQIRPrograms PUBLIC MLIRQIRProgramBuilder) +target_link_libraries( + MLIRQIRPrograms + PUBLIC MLIRQIRProgramBuilder + PRIVATE MQT::ProjectOptions) target_sources(MLIRQIRPrograms PUBLIC FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES qir_programs.h) diff --git a/mlir/unittests/programs/qasm_programs.cpp b/mlir/unittests/programs/qasm_programs.cpp new file mode 100644 index 0000000000..2386d7e8c7 --- /dev/null +++ b/mlir/unittests/programs/qasm_programs.cpp @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2023 - 2026 Chair for Design Automation, TUM + * Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#include "qasm_programs.h" + +#include + +// NOLINTBEGIN(readability-identifier-naming) +namespace mlir::qasm { + +const std::string allocQubit = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit q; +)qasm"; + +const std::string allocQubitRegister = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +)qasm"; + +const std::string allocMultipleQubitRegisters = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q0; +qubit[3] q1; +)qasm"; + +const std::string allocLargeRegister = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[100] q; +)qasm"; + +const std::string singleMeasurementToSingleBit = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +bit[1] c; +measure q[0] -> c[0]; +)qasm"; + +const std::string repeatedMeasurementToSameBit = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +bit[1] c; +measure q[0] -> c[0]; +measure q[0] -> c[0]; +measure q[0] -> c[0]; +)qasm"; + +const std::string repeatedMeasurementToDifferentBits = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +bit[3] c; +measure q[0] -> c[0]; +measure q[0] -> c[1]; +measure q[0] -> c[2]; +)qasm"; + +const std::string multipleClassicalRegistersAndMeasurements = + R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[3] q; +bit[1] c0; +bit[2] c1; +measure q[0] -> c0[0]; +measure q[1] -> c1[0]; +measure q[2] -> c1[1]; +)qasm"; + +const std::string resetQubitAfterSingleOp = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +h q[0]; +reset q[0]; +)qasm"; + +const std::string resetMultipleQubitsAfterSingleOp = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +h q[0]; +reset q[0]; +h q[1]; +reset q[1]; +)qasm"; + +const std::string repeatedResetAfterSingleOp = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +h q[0]; +reset q[0]; +reset q[0]; +reset q[0]; +)qasm"; + +const std::string globalPhase = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +gphase(0.123); +)qasm"; + +const std::string inverseGlobalPhase = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +inv @ gphase(-0.123); +)qasm"; + +const std::string identity = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +id q[0]; +)qasm"; + +const std::string singleControlledIdentity = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ id q[0], q[1]; +)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]; +)qasm"; + +const std::string x = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +x q[0]; +)qasm"; + +const std::string twoX = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +x q; +)qasm"; + +const std::string singleControlledX = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ x q[0], q[1]; +)qasm"; + +const std::string singleNegControlledX = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +negctrl @ x q[0], q[1]; +)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]; +)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]; +)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]; +)qasm"; + +const std::string twoMixedControlledX = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q1; +qubit[2] q2; +qubit[2] q3; +ctrl @ negctrl @ x q1, q2, q3; +)qasm"; + +const std::string inverseX = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +inv @ x q[0]; +)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]; +)qasm"; + +const std::string y = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +y q[0]; +)qasm"; + +const std::string singleControlledY = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ y q[0], q[1]; +)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]; +)qasm"; + +const std::string z = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +z q[0]; +)qasm"; + +const std::string singleControlledZ = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ z q[0], q[1]; +)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]; +)qasm"; + +const std::string h = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +h q[0]; +)qasm"; + +const std::string singleControlledH = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ h q[0], q[1]; +)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]; +)qasm"; + +const std::string s = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +s q[0]; +)qasm"; + +const std::string singleControlledS = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ s q[0], q[1]; +)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]; +)qasm"; + +const std::string sdg = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +sdg q[0]; +)qasm"; + +const std::string singleControlledSdg = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ sdg q[0], q[1]; +)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]; +)qasm"; + +const std::string t_ = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +t q[0]; +)qasm"; + +const std::string singleControlledT = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ t q[0], q[1]; +)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]; +)qasm"; + +const std::string tdg = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +tdg q[0]; +)qasm"; + +const std::string singleControlledTdg = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ tdg q[0], q[1]; +)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]; +)qasm"; + +const std::string sx = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +sx q[0]; +)qasm"; + +const std::string singleControlledSx = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ sx q[0], q[1]; +)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]; +)qasm"; + +const std::string sxdg = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +sxdg q[0]; +)qasm"; + +const std::string singleControlledSxdg = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ sxdg q[0], q[1]; +)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]; +)qasm"; + +const std::string rx = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +rx(0.123) q[0]; +)qasm"; + +const std::string singleControlledRx = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ rx(0.123) q[0], q[1]; +)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]; +)qasm"; + +const std::string ry = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +ry(0.456) q[0]; +)qasm"; + +const std::string singleControlledRy = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ ry(0.456) q[0], q[1]; +)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]; +)qasm"; + +const std::string rz = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +rz(0.789) q[0]; +)qasm"; + +const std::string singleControlledRz = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ rz(0.789) q[0], q[1]; +)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]; +)qasm"; + +const std::string p = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +p(0.123) q[0]; +)qasm"; + +const std::string singleControlledP = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ctrl @ p(0.123) q[0], q[1]; +)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]; +)qasm"; + +const std::string r = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +r(0.123, 0.456) q[0]; +)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]; +)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]; +)qasm"; + +const std::string u2 = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +u2(0.234, 0.567) q[0]; +)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]; +)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]; +)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]; +)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]; +)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]; +)qasm"; + +const std::string swap = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +swap q[0], q[1]; +)qasm"; + +const std::string singleControlledSwap = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[3] q; +ctrl @ swap q[0], q[1], q[2]; +)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]; +)qasm"; + +const std::string iswap = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +iswap q[0], q[1]; +)qasm"; + +const std::string singleControlledIswap = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[3] q; +ctrl @ iswap q[0], q[1], q[2]; +)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]; +)qasm"; + +const std::string inverseIswap = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +inv @ iswap q[0], q[1]; +)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]; +)qasm"; + +const std::string dcx = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +dcx q[0], q[1]; +)qasm"; + +const std::string singleControlledDcx = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[3] q; +ctrl @ dcx q[0], q[1], q[2]; +)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]; +)qasm"; + +const std::string ecr = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ecr q[0], q[1]; +)qasm"; + +const std::string singleControlledEcr = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[3] q; +ctrl @ ecr q[0], q[1], q[2]; +)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]; +)qasm"; + +const std::string rxx = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +rxx(0.123) q[0], q[1]; +)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]; +)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]; +)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]; +)qasm"; + +const std::string ryy = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +ryy(0.123) q[0], q[1]; +)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]; +)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]; +)qasm"; + +const std::string rzx = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +rzx(0.123) q[0], q[1]; +)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]; +)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]; +)qasm"; + +const std::string rzz = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +rzz(0.123) q[0], q[1]; +)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]; +)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]; +)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]; +)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]; +)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]; +)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]; +)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]; +)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]; +)qasm"; + +const std::string barrier = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +barrier q[0]; +)qasm"; + +const std::string barrierTwoQubits = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +barrier q[0], q[1]; +)qasm"; + +const std::string barrierMultipleQubits = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[3] q; +barrier q[0], q[1], q[2]; +)qasm"; + +const std::string ctrlTwo = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[4] q; +gate compound q0, q1 { + x q0; + rxx(0.123) q0, q1; +} +ctrl(2) @ compound q[0], q[1], q[2], q[3]; +)qasm"; + +const std::string ctrlTwoMixed = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[4] q; +gate compound q0, q1 { + ctrl @ x q0, q1; + rxx(0.123) q0, q1; +} +ctrl(2) @ compound q[0], q[1], q[2], q[3]; +)qasm"; + +const std::string simpleIf = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +h q[0]; +bit c = measure q[0]; +if (c) { + x q[0]; +} +)qasm"; + +const std::string ifNot = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +h q[0]; +bit c = measure q[0]; +if (!c) { + x q[0]; +} +)qasm"; + +const std::string ifTwoQubits = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[2] q; +h q[0]; +bit c = measure q[0]; +if (c) { + x q[0]; + x q[1]; +} +)qasm"; + +const std::string ifEmptyThen = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +h q[0]; +bit c = measure q[0]; +if (c) { +} else { + x q[0]; +} +)qasm"; + +const std::string ifElse = R"qasm(OPENQASM 3.0; +include "stdgates.inc"; +qubit[1] q; +h q[0]; +bit c = measure q[0]; +if (c) { + x q[0]; +} else { + z q[0]; +} +)qasm"; + +} // namespace mlir::qasm +// NOLINTEND(readability-identifier-naming) diff --git a/mlir/unittests/programs/qasm_programs.h b/mlir/unittests/programs/qasm_programs.h new file mode 100644 index 0000000000..5da45582c7 --- /dev/null +++ b/mlir/unittests/programs/qasm_programs.h @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2023 - 2026 Chair for Design Automation, TUM + * Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include + +// NOLINTBEGIN(readability-identifier-naming) +namespace mlir::qasm { + +/// Allocates a single qubit. +extern const std::string allocQubit; + +/// Allocates a qubit register of size `2`. +extern const std::string allocQubitRegister; + +/// Allocates two qubit registers of size `2` and `3`. +extern const std::string allocMultipleQubitRegisters; + +/// Allocates a large qubit register. +extern const std::string allocLargeRegister; + +/// Measures a single qubit into a single classical bit. +extern const std::string singleMeasurementToSingleBit; + +/// Repeatedly measures a single qubit into the same classical bit. +extern const std::string repeatedMeasurementToSameBit; + +/// Repeatedly measures a single qubit into different classical bits. +extern const std::string repeatedMeasurementToDifferentBits; + +/// Measures multiple qubits into multiple classical bits. +extern const std::string multipleClassicalRegistersAndMeasurements; + +/// Resets a single qubit after a single operation. +extern const std::string resetQubitAfterSingleOp; + +/// Resets multiple qubits after a single operation. +extern const std::string resetMultipleQubitsAfterSingleOp; + +/// Repeatedly resets a single qubit after a single operation. +extern const std::string repeatedResetAfterSingleOp; + +/// Creates a circuit with just a global phase. +extern const std::string globalPhase; + +/// Creates a circuit with an inverse modifier applied to a global phase gate. +extern const std::string inverseGlobalPhase; + +/// Creates a circuit with just an identity gate. +extern const std::string identity; + +/// Creates a controlled identity gate with a single control qubit. +extern const std::string singleControlledIdentity; + +/// Creates a multi-controlled identity gate with multiple control qubits. +extern const std::string multipleControlledIdentity; + +/// Creates a circuit with just an X gate. +extern const std::string x; + +/// Creates a circuit with two X gates. +extern const std::string twoX; + +/// Creates a circuit with a single controlled X gate. +extern const std::string singleControlledX; + +/// Creates a circuit with a single negatively controlled X gate. +extern const std::string singleNegControlledX; + +/// Creates a circuit with a multi-controlled X gate. +extern const std::string multipleControlledX; + +/// Creates a circuit with a triple-controlled X gate in OpenQASM 2. +extern const std::string tripleControlledXOpenQASM2; + +/// Creates a circuit with an X gate that is positively and negatively +/// controlled. +extern const std::string mixedControlledX; + +/// Creates a circuit with two X gates that are positively and negatively +/// controlled. +extern const std::string twoMixedControlledX; + +/// Creates a circuit with an inverse modifier applied to an X gate. +extern const std::string inverseX; + +/// Creates a circuit with an inverse modifier applied to a controlled X gate. +extern const std::string inverseMultipleControlledX; + +/// Creates a circuit with just a Y gate. +extern const std::string y; + +/// Creates a circuit with a single controlled Y gate. +extern const std::string singleControlledY; + +/// Creates a circuit with a multi-controlled Y gate. +extern const std::string multipleControlledY; + +/// Creates a circuit with just a Z gate. +extern const std::string z; + +/// Creates a circuit with a single controlled Z gate. +extern const std::string singleControlledZ; + +/// Creates a circuit with a multi-controlled Z gate. +extern const std::string multipleControlledZ; + +/// Creates a circuit with just an H gate. +extern const std::string h; + +/// Creates a circuit with a single controlled H gate. +extern const std::string singleControlledH; + +/// Creates a circuit with a multi-controlled H gate. +extern const std::string multipleControlledH; + +/// Creates a circuit with just an S gate. +extern const std::string s; + +/// Creates a circuit with a single controlled S gate. +extern const std::string singleControlledS; + +/// Creates a circuit with a multi-controlled S gate. +extern const std::string multipleControlledS; + +/// Creates a circuit with just an Sdg gate. +extern const std::string sdg; + +/// Creates a circuit with a single controlled Sdg gate. +extern const std::string singleControlledSdg; + +/// Creates a circuit with a multi-controlled Sdg gate. +extern const std::string multipleControlledSdg; + +/// Creates a circuit with just a T gate. +extern const std::string t_; + +/// Creates a circuit with a single controlled T gate. +extern const std::string singleControlledT; + +/// Creates a circuit with a multi-controlled T gate. +extern const std::string multipleControlledT; + +/// Creates a circuit with just a Tdg gate. +extern const std::string tdg; + +/// Creates a circuit with a single controlled Tdg gate. +extern const std::string singleControlledTdg; + +/// Creates a circuit with a multi-controlled Tdg gate. +extern const std::string multipleControlledTdg; + +/// Creates a circuit with just an SX gate. +extern const std::string sx; + +/// Creates a circuit with a single controlled SX gate. +extern const std::string singleControlledSx; + +/// Creates a circuit with a multi-controlled SX gate. +extern const std::string multipleControlledSx; + +/// Creates a circuit with just an SXdg gate. +extern const std::string sxdg; + +/// Creates a circuit with a single controlled SXdg gate. +extern const std::string singleControlledSxdg; + +/// Creates a circuit with a multi-controlled SXdg gate. +extern const std::string multipleControlledSxdg; + +/// Creates a circuit with just an RX gate. +extern const std::string rx; + +/// Creates a circuit with a single controlled RX gate. +extern const std::string singleControlledRx; + +/// Creates a circuit with a multi-controlled RX gate. +extern const std::string multipleControlledRx; + +/// Creates a circuit with just an RY gate. +extern const std::string ry; + +/// Creates a circuit with a single controlled RY gate. +extern const std::string singleControlledRy; + +/// Creates a circuit with a multi-controlled RY gate. +extern const std::string multipleControlledRy; + +/// Creates a circuit with just an RZ gate. +extern const std::string rz; + +/// Creates a circuit with a single controlled RZ gate. +extern const std::string singleControlledRz; + +/// Creates a circuit with a multi-controlled RZ gate. +extern const std::string multipleControlledRz; + +/// Creates a circuit with just a P gate. +extern const std::string p; + +/// Creates a circuit with a single controlled P gate. +extern const std::string singleControlledP; + +/// Creates a circuit with a multi-controlled P gate. +extern const std::string multipleControlledP; + +/// Creates a circuit with just an R gate. +extern const std::string r; + +/// Creates a circuit with a single controlled R gate. +extern const std::string singleControlledR; + +/// Creates a circuit with a multi-controlled R gate. +extern const std::string multipleControlledR; + +/// Creates a circuit with just a U2 gate. +extern const std::string u2; + +/// Creates a circuit with a single controlled U2 gate. +extern const std::string singleControlledU2; + +/// Creates a circuit with a multi-controlled U2 gate. +extern const std::string multipleControlledU2; + +/// Creates a circuit with just a U gate. +extern const std::string u; + +/// Creates a circuit with a single controlled U gate. +extern const std::string singleControlledU; + +/// Creates a circuit with a multi-controlled U gate. +extern const std::string multipleControlledU; + +/// Creates a circuit with just a SWAP gate. +extern const std::string swap; + +/// Creates a circuit with a single controlled SWAP gate. +extern const std::string singleControlledSwap; + +/// Creates a circuit with a multi-controlled SWAP gate. +extern const std::string multipleControlledSwap; + +/// Creates a circuit with just an iSWAP gate. +extern const std::string iswap; + +/// Creates a circuit with a single controlled iSWAP gate. +extern const std::string singleControlledIswap; + +/// Creates a circuit with a multi-controlled iSWAP gate. +extern const std::string multipleControlledIswap; + +/// Creates a circuit with an inverse modifier applied to an iSWAP gate. +extern const std::string inverseIswap; + +/// Creates a circuit with an inverse modifier applied to a controlled iSWAP +/// gate. +extern const std::string inverseMultipleControlledIswap; + +/// Creates a circuit with just a DCX gate. +extern const std::string dcx; + +/// Creates a circuit with a single controlled DCX gate. +extern const std::string singleControlledDcx; + +/// Creates a circuit with a multi-controlled DCX gate. +extern const std::string multipleControlledDcx; + +/// Creates a circuit with just an ECR gate. +extern const std::string ecr; + +/// Creates a circuit with a single controlled ECR gate. +extern const std::string singleControlledEcr; + +/// Creates a circuit with a multi-controlled ECR gate. +extern const std::string multipleControlledEcr; + +/// Creates a circuit with just an RXX gate. +extern const std::string rxx; + +/// Creates a circuit with a single controlled RXX gate. +extern const std::string singleControlledRxx; + +/// Creates a circuit with a multi-controlled RXX gate. +extern const std::string multipleControlledRxx; + +/// Creates a circuit with a triple-controlled RXX gate. +extern const std::string tripleControlledRxx; + +/// Creates a circuit with just an RYY gate. +extern const std::string ryy; + +/// Creates a circuit with a single controlled RYY gate. +extern const std::string singleControlledRyy; + +/// Creates a circuit with a multi-controlled RYY gate. +extern const std::string multipleControlledRyy; + +/// Creates a circuit with just an RZX gate. +extern const std::string rzx; + +/// Creates a circuit with a single controlled RZX gate. +extern const std::string singleControlledRzx; + +/// Creates a circuit with a multi-controlled RZX gate. +extern const std::string multipleControlledRzx; + +/// Creates a circuit with just an RZZ gate. +extern const std::string rzz; + +/// Creates a circuit with a single controlled RZZ gate. +extern const std::string singleControlledRzz; + +/// Creates a circuit with a multi-controlled RZZ gate. +extern const std::string multipleControlledRzz; + +/// Creates a circuit with just an XXPlusYY gate. +extern const std::string xxPlusYY; + +/// Creates a circuit with a single controlled XXPlusYY gate. +extern const std::string singleControlledXxPlusYY; + +/// Creates a circuit with a multi-controlled XXPlusYY gate. +extern const std::string multipleControlledXxPlusYY; + +/// Creates a circuit with just an XXMinusYY gate. +extern const std::string xxMinusYY; + +/// Creates a circuit with a single controlled XXMinusYY gate. +extern const std::string singleControlledXxMinusYY; + +/// Creates a circuit with a multi-controlled XXMinusYY gate. +extern const std::string multipleControlledXxMinusYY; + +/// Creates a circuit with a barrier. +extern const std::string barrier; + +/// Creates a circuit with a barrier on two qubits. +extern const std::string barrierTwoQubits; + +/// Creates a circuit with a barrier on multiple qubits. +extern const std::string barrierMultipleQubits; + +/// Creates a circuit with a control modifier applied to two gates. +extern const std::string ctrlTwo; + +/// Creates a circuit with a control modifier applied to a controlled and a +/// non-controlled gate. +extern const std::string ctrlTwoMixed; + +/// Creates a circuit with a simple if operation with one qubit. +extern const std::string simpleIf; + +/// Creates a circuit with an if operation with a negated condition. +extern const std::string ifNot; + +/// Creates a circuit with an if operation with two qubits. +extern const std::string ifTwoQubits; + +/// Creates a circuit with an if operation with an empty then branch. +extern const std::string ifEmptyThen; + +/// Creates a circuit with an if operation with an else branch. +extern const std::string ifElse; + +} // namespace mlir::qasm +// NOLINTEND(readability-identifier-naming) diff --git a/test/circuits/bell.qasm b/test/circuits/bell.qasm deleted file mode 100644 index c8b3cff498..0000000000 --- a/test/circuits/bell.qasm +++ /dev/null @@ -1,5 +0,0 @@ -OPENQASM 2.0; -//include "qelib1.inc"; -qreg q[2]; -U(pi/2,0,pi) q[0]; -CX q[0],q[1];