Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions mlir/include/mlir/Dialect/QC/Builder/QCProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,25 @@ class QCProgramBuilder final : public OpBuilder {
QCProgramBuilder& ctrl(ValueRange controls,
const std::function<void(OpBuilder&)>& body);

/**
* @brief Apply an inverse (i.e., adjoint) operation.
*
* @param body Function that builds the body containing the operation to
* invert
* @return Reference to this builder for method chaining
*
* @par Example:
* ```c++
* builder.inv([&](auto& b) { b.s(q0); });
* ```
* ```mlir
* qc.inv {
* qc.s %q0 : !qc.qubit
* }
* ```
*/
QCProgramBuilder& inv(const std::function<void(OpBuilder&)>& body);

//===--------------------------------------------------------------------===//
// Deallocation
//===--------------------------------------------------------------------===//
Expand Down
44 changes: 44 additions & 0 deletions mlir/include/mlir/Dialect/QC/IR/QCOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -973,4 +973,48 @@ def CtrlOp : QCOp<"ctrl",
let hasVerifier = 1;
}

def InvOp : QCOp<"inv",
traits = [
UnitaryOpInterface,
SingleBlockImplicitTerminator<"::mlir::qc::YieldOp">,
RecursiveMemoryEffects
]> {
let summary = "Invert a unitary operation";
let description = [{
A modifier operation that inverts the unitary operation defined in its body
region.

Example:
```mlir
qc.inv {
qc.s %q0 : !qc.qubit
}
```
}];

let regions = (region SizedRegion<1>:$body);
let assemblyFormat = "$body attr-dict";

let extraClassDeclaration = [{
[[nodiscard]] UnitaryOpInterface getBodyUnitary();
size_t getNumQubits();
size_t getNumTargets();
size_t getNumControls();
Value getQubit(size_t i);
Value getTarget(size_t i);
Value getControl(size_t i);
size_t getNumParams();
Value getParameter(size_t i);
static StringRef getBaseSymbol() { return "inv"; }
}];

let builders = [
OpBuilder<(ins "UnitaryOpInterface":$bodyUnitary)>,
OpBuilder<(ins "const std::function<void(OpBuilder &)>&":$bodyBuilder)>
];

let hasCanonicalizer = 1;
let hasVerifier = 1;
}

#endif // QC_OPS
24 changes: 24 additions & 0 deletions mlir/include/mlir/Dialect/QCO/Builder/QCOProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,30 @@ class QCOProgramBuilder final : public OpBuilder {
ctrl(ValueRange controls, ValueRange targets,
const std::function<ValueRange(OpBuilder&, ValueRange)>& body);

/**
* @brief Apply an inverse operation
*
* @param targets Target qubits
* @param body Function that builds the body containing the target operation
* @return Output target qubits
*
* @par Example:
* ```c++
* targets_out = builder.inv(q0_in, [&](auto& b) {
* auto q0_res = b.s(q0_in);
* return {q0_res};
* });
* ```
* ```mlir
* %targets_out = qco.inv %q0_in {
* %q0_res = qco.s %q0_in : !qco.qubit -> !qco.qubit
* qco.yield %q0_res
* } : {!qco.qubit} -> {!qco.qubit}
* ```
*/
ValueRange inv(ValueRange targets,
const std::function<ValueRange(OpBuilder&, ValueRange)>& body);

//===--------------------------------------------------------------------===//
// Deallocation
//===--------------------------------------------------------------------===//
Expand Down
64 changes: 64 additions & 0 deletions mlir/include/mlir/Dialect/QCO/IR/QCOOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1106,4 +1106,68 @@ def CtrlOp : QCOOp<"ctrl", traits =
let hasVerifier = 1;
}

def InvOp : QCOOp<"inv", traits =
[
UnitaryOpInterface,
SameOperandsAndResultType,
SameOperandsAndResultShape,
SingleBlock,
RecursiveMemoryEffects
]> {
let summary = "Invert a unitary operation";
let description = [{
A modifier operation that inverts the unitary operation defined in its body
region. The operation takes a variadic number of target qubits as inputs and
produces corresponding output qubits.

Example:
```mlir
%targets_out = qco.inv %targets_in {
%targets_res = qco.s %targets_in : !qco.qubit -> !qco.qubit
qco.yield %targets_res : !qco.qubit
} : {!qco.qubit} -> {!qco.qubit}
```
}];

let arguments = (ins Arg<Variadic<QubitType>, "the target qubits", [MemRead]>:$targets_in);
let results = (outs Variadic<QubitType>:$targets_out);
let regions = (region SizedRegion<1>:$body);
let assemblyFormat = [{
$targets_in
$body attr-dict `:`
`{` type($targets_in) `}`
`->`
`{` type($targets_out) `}`
}];

let extraClassDeclaration = [{
UnitaryOpInterface getBodyUnitary();
size_t getNumQubits();
size_t getNumTargets();
size_t getNumControls();
Value getInputQubit(size_t i);
Value getOutputQubit(size_t i);
Value getInputTarget(size_t i);
Value getOutputTarget(size_t i);
Value getInputControl(size_t i);
Value getOutputControl(size_t i);
Value getInputForOutput(Value output);
Value getOutputForInput(Value input);
size_t getNumParams();
Value getParameter(size_t i);
static StringRef getBaseSymbol() { return "inv"; }
}];

let builders = [
OpBuilder<(ins "ValueRange":$targets), [{
build($_builder, $_state, targets.getTypes(), targets);
}]>,
OpBuilder<(ins "ValueRange":$targets, "UnitaryOpInterface":$bodyUnitary)>,
OpBuilder<(ins "ValueRange":$targets, "const std::function<ValueRange(OpBuilder &, ValueRange)>&":$bodyBuilder)>
];

let hasCanonicalizer = 1;
let hasVerifier = 1;
}

#endif // QCOOPS
61 changes: 49 additions & 12 deletions mlir/lib/Conversion/QCOToQC/QCOToQC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,43 @@ struct ConvertQCOCtrlOp final : OpConversionPattern<qco::CtrlOp> {
}
};

/**
* @brief Converts qco.inv to qc.inv
*
* @par Example:
* ```mlir
* %targets_out = qco.inv %q0_in {
* %q0_res = qco.s %q0_in : !qco.qubit -> !qco.qubit
* qco.yield %q0_res
* } : {!qco.qubit} -> {!qco.qubit}
* ```
* is converted to
* ```mlir
* qc.inv {
* qc.s %q0 : !qc.qubit
* }
* ```
*/
struct ConvertQCOInvOp final : OpConversionPattern<qco::InvOp> {
using OpConversionPattern::OpConversionPattern;

LogicalResult
matchAndRewrite(qco::InvOp op, OpAdaptor adaptor,
ConversionPatternRewriter& rewriter) const override {
// Create qc.inv operation
auto qcOp = qc::InvOp::create(rewriter, op->getLoc());

// Clone body region from QCO to QC
auto& dstRegion = qcOp.getBody();
rewriter.cloneRegionBefore(op.getBody(), dstRegion, dstRegion.end());

// Replace the output qubits with the same QC references
rewriter.replaceOp(op, adaptor.getOperands());

return success();
}
};

/**
* @brief Converts qco.yield to qc.yield
*
Expand Down Expand Up @@ -854,18 +891,18 @@ struct QCOToQC final : impl::QCOToQCBase<QCOToQC> {

// Register operation conversion patterns
// Note: No state tracking needed - OpAdaptors handle type conversion
patterns.add<ConvertQCOAllocOp, ConvertQCODeallocOp, ConvertQCOStaticOp,
ConvertQCOMeasureOp, ConvertQCOResetOp, ConvertQCOGPhaseOp,
ConvertQCOIdOp, ConvertQCOXOp, ConvertQCOYOp, ConvertQCOZOp,
ConvertQCOHOp, ConvertQCOSOp, ConvertQCOSdgOp, ConvertQCOTOp,
ConvertQCOTdgOp, ConvertQCOSXOp, ConvertQCOSXdgOp,
ConvertQCORXOp, ConvertQCORYOp, ConvertQCORZOp, ConvertQCOPOp,
ConvertQCOROp, ConvertQCOU2Op, ConvertQCOUOp, ConvertQCOSWAPOp,
ConvertQCOiSWAPOp, ConvertQCODCXOp, ConvertQCOECROp,
ConvertQCORXXOp, ConvertQCORYYOp, ConvertQCORZXOp,
ConvertQCORZZOp, ConvertQCOXXPlusYYOp, ConvertQCOXXMinusYYOp,
ConvertQCOBarrierOp, ConvertQCOCtrlOp, ConvertQCOYieldOp>(
typeConverter, context);
patterns
.add<ConvertQCOAllocOp, ConvertQCODeallocOp, ConvertQCOStaticOp,
ConvertQCOMeasureOp, ConvertQCOResetOp, ConvertQCOGPhaseOp,
ConvertQCOIdOp, ConvertQCOXOp, ConvertQCOYOp, ConvertQCOZOp,
ConvertQCOHOp, ConvertQCOSOp, ConvertQCOSdgOp, ConvertQCOTOp,
ConvertQCOTdgOp, ConvertQCOSXOp, ConvertQCOSXdgOp, ConvertQCORXOp,
ConvertQCORYOp, ConvertQCORZOp, ConvertQCOPOp, ConvertQCOROp,
ConvertQCOU2Op, ConvertQCOUOp, ConvertQCOSWAPOp, ConvertQCOiSWAPOp,
ConvertQCODCXOp, ConvertQCOECROp, ConvertQCORXXOp, ConvertQCORYYOp,
ConvertQCORZXOp, ConvertQCORZZOp, ConvertQCOXXPlusYYOp,
ConvertQCOXXMinusYYOp, ConvertQCOBarrierOp, ConvertQCOCtrlOp,
ConvertQCOInvOp, ConvertQCOYieldOp>(typeConverter, context);

// Conversion of qco types in func.func signatures
// Note: This currently has limitations with signature changes
Expand Down
65 changes: 64 additions & 1 deletion mlir/lib/Conversion/QCToQCO/QCToQCO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,68 @@ struct ConvertQCCtrlOp final : StatefulOpConversionPattern<qc::CtrlOp> {
}
};

/**
* @brief Converts qc.inv to qco.inv
*
* @par Example:
* ```mlir
* qc.inv {
* qc.s %q0
* }
* ```
* is converted to
* ```mlir
* %targets_out = qco.inv %q0_in {
* %q0_res = qco.s %q0_in : !qco.qubit -> !qco.qubit
* qco.yield %q0_res
* } : {!qco.qubit} -> {!qco.qubit}
* ```
*/
struct ConvertQCInvOp final : StatefulOpConversionPattern<qc::InvOp> {
using StatefulOpConversionPattern::StatefulOpConversionPattern;

LogicalResult
matchAndRewrite(qc::InvOp op, OpAdaptor /*adaptor*/,
ConversionPatternRewriter& rewriter) const override {
auto& state = getState();
auto& qubitMap = state.qubitMap;

// Get QCO targets from state map
const auto numTargets = op.getNumTargets();
SmallVector<Value> qcoTargets;
qcoTargets.reserve(numTargets);
for (size_t i = 0; i < numTargets; ++i) {
const auto& qcTarget = op.getTarget(i);
assert(qubitMap.contains(qcTarget) && "QC qubit not found");
const auto& qcoTarget = qubitMap[qcTarget];
qcoTargets.push_back(qcoTarget);
}

// Create qco.inv
auto qcoOp = qco::InvOp::create(rewriter, op.getLoc(), qcoTargets);

// Update state map
if (state.inCtrlOp == 0) {
const auto targetsOut = qcoOp.getTargetsOut();
for (size_t i = 0; i < numTargets; ++i) {
const auto& qcTarget = op.getTarget(i);
qubitMap[qcTarget] = targetsOut[i];
}
}

// Update modifier information
state.inCtrlOp++;
state.targetsIn.try_emplace(state.inCtrlOp, qcoTargets);

// Clone body region from QC to QCO
auto& dstRegion = qcoOp.getBody();
rewriter.cloneRegionBefore(op.getBody(), dstRegion, dstRegion.end());

rewriter.eraseOp(op);
return success();
}
};

/**
* @brief Converts qc.yield to qco.yield
*
Expand Down Expand Up @@ -1216,7 +1278,8 @@ struct QCToQCO final : impl::QCToQCOBase<QCToQCO> {
ConvertQCDCXOp, ConvertQCECROp, ConvertQCRXXOp, ConvertQCRYYOp,
ConvertQCRZXOp, ConvertQCRZZOp, ConvertQCXXPlusYYOp,
ConvertQCXXMinusYYOp, ConvertQCBarrierOp, ConvertQCCtrlOp,
ConvertQCYieldOp>(typeConverter, context, &state);
ConvertQCInvOp, ConvertQCYieldOp>(typeConverter, context,
&state);

// Conversion of qc types in func.func signatures
// Note: This currently has limitations with signature
Expand Down
7 changes: 7 additions & 0 deletions mlir/lib/Dialect/QC/Builder/QCProgramBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,13 @@ QCProgramBuilder::ctrl(ValueRange controls,
return *this;
}

QCProgramBuilder&
QCProgramBuilder::inv(const std::function<void(OpBuilder&)>& body) {
checkFinalized();
InvOp::create(*this, loc, body);
return *this;
}

//===----------------------------------------------------------------------===//
// Deallocation
//===----------------------------------------------------------------------===//
Expand Down
Loading
Loading