Skip to content

Commit

Permalink
Ensure an ion.yield operation is returning a region output to all p…
Browse files Browse the repository at this point in the history
…arallal protocol ops (#1475)

**Context:** During `quantum-to-ion` pass, when decomposing RX, RY and
MS gates to pulses in a `ParallelProtocolOp`'s region, the region was
terminated with yield ops without any operands. This means no SSA values
were actually yielded from the region. At the same time,
`ParallelProtocolOp` returns (variadic-length) values of type
`!quantum.bit`. This means the IR is ill-formed.

**Description of the Change:**
Ensure that all `ParallelProtocolOp`s will yield the input-ed qubit SSA
values by doing so in the builder, when building the region of the
`ParallelProtocolOp`.

**Benefits:** mlir is no longer ill-formed; increased readability
  • Loading branch information
paul0403 authored Jan 21, 2025
1 parent 682f7b6 commit 286e519
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 16 deletions.
27 changes: 16 additions & 11 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@

<h3>Internal changes ⚙️</h3>

* The `get_c_interface` method has been added to the OQD device, which enables retrieval of the C++
implementation of the device from Python. This allows `qjit` to accept an instance of the device
and connect to its runtime.
[(#1420)](https://github.com/PennyLaneAI/catalyst/pull/1420)

* `from_plxpr` now uses the `qml.capture.PlxprInterpreter` class for reduced code duplication.
[(#1398)](https://github.com/PennyLaneAI/catalyst/pull/1398)

Expand All @@ -30,17 +25,27 @@
* Replace `ValueRange` with `ResultRange` and `Value` with `OpResult` to better align with the semantics of `**QubitResult()` functions like `getNonCtrlQubitResults()`. This change ensures clearer intent and usage. Improve the `matchAndRewrite` function by using `replaceAllUsesWith` instead of for loop.
[(#1426)](https://github.com/PennyLaneAI/catalyst/pull/1426)

* Improved ion dialect to reduce redundant code generated. Added a string attribute `label` to Level.
Also changed the levels of a transition from `LevelAttr` to `string`
[(#1471)](https://github.com/PennyLaneAI/catalyst/pull/1471)
* Several changes for experimental support of trapped-ion OQD devices have been made, including:

- The `get_c_interface` method has been added to the OQD device, which enables retrieval of the C++
implementation of the device from Python. This allows `qjit` to accept an instance of the device
and connect to its runtime.
[(#1420)](https://github.com/PennyLaneAI/catalyst/pull/1420)

- Improved ion dialect to reduce redundant code generated. Added a string attribute `label` to Level.
Also changed the levels of a transition from `LevelAttr` to `string`
[(#1471)](https://github.com/PennyLaneAI/catalyst/pull/1471)

- The region of a `ParallelProtocolOp` is now always terminated with a `ion::YieldOp` with explicitly yielded SSA values. This ensures the op is well-formed, and improves readability.
[(#1475)](https://github.com/PennyLaneAI/catalyst/pull/1475)

<h3>Documentation 📝</h3>

<h3>Contributors ✍️</h3>

This release contains contributions from (in alphabetical order):

Christina Lee
Mehrdad Malekmohammadi
Sengthai Heng
Sengthai Heng,
Christina Lee,
Mehrdad Malekmohammadi,
Paul Haochen Wang.
9 changes: 7 additions & 2 deletions mlir/lib/Ion/IR/IonOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,23 @@ void ParallelProtocolOp::build(OpBuilder &builder, OperationState &result, Value
BodyBuilderFn bodyBuilder)
{
OpBuilder::InsertionGuard guard(builder);
Location loc = result.location;

result.addOperands(inQubits);
for (Value v : inQubits)
result.addTypes(v.getType());

Region *bodyRegion = result.addRegion();
Block *bodyBlock = builder.createBlock(bodyRegion);
for (Value v : inQubits)
for (Value v : inQubits) {
bodyBlock->addArgument(v.getType(), v.getLoc());
}

builder.setInsertionPointToStart(bodyBlock);
bodyBuilder(builder, result.location, bodyBlock->getArguments());
bodyBuilder(builder, loc, bodyBlock->getArguments());

builder.setInsertionPointToEnd(bodyBlock);
builder.create<ion::YieldOp>(loc, bodyBlock->getArguments());
}

//===----------------------------------------------------------------------===//
Expand Down
3 changes: 0 additions & 3 deletions mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ mlir::LogicalResult oneQubitGateToPulse(CustomOp op, mlir::PatternRewriter &rewr
auto qubit = qubits.front();
builder.create<ion::PulseOp>(loc, time, qubit, beam0toEAttr, phase1Attr);
builder.create<ion::PulseOp>(loc, time, qubit, beam1toEAttr, phase2Attr);
builder.create<ion::YieldOp>(loc);
});
rewriter.replaceOp(op, ppOp);
return success();
Expand Down Expand Up @@ -408,8 +407,6 @@ mlir::LogicalResult MSGateToPulse(CustomOp op, mlir::PatternRewriter &rewriter,
rewriter.getI64VectorAttr(beam.polarization),
rewriter.getI64VectorAttr(flipSign(beam.wavevector)));
builder.create<ion::PulseOp>(loc, time, qubit1, beam6Attr, phase0Attr);

builder.create<ion::YieldOp>(loc);
});
rewriter.replaceOp(op, ppOp);
return success();
Expand Down
7 changes: 7 additions & 0 deletions mlir/test/Ion/QuantumToIon.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit {
// CHECK-SAME: polarization = dense<[0, 1]> : vector<2xi64>,
// CHECK-SAME: wavevector = dense<[-2, 3]> : vector<2xi64>>,
// CHECK-SAME: phase = 0.000000e+00 : f64}
// CHECK-NEXT: ion.yield %arg1 : !quantum.bit
// CHECK-NEXT: }
%4 = quantum.custom "RX"(%arg0) %2 : !quantum.bit

Expand All @@ -135,6 +136,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit {
// CHECK-SAME: polarization = dense<[0, 1]> : vector<2xi64>,
// CHECK-SAME: wavevector = dense<[-2, 3]> : vector<2xi64>>,
// CHECK-SAME: phase = 3.1415926535{{[0-9]*}} : f64}
// CHECK-NEXT: ion.yield %arg1 : !quantum.bit
// CHECK-NEXT: }
%5 = quantum.custom "RY"(%arg0) %4 : !quantum.bit

Expand All @@ -158,6 +160,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit {
// CHECK-SAME: polarization = dense<[0, 1]> : vector<2xi64>,
// CHECK-SAME: wavevector = dense<[-2, 3]> : vector<2xi64>>,
// CHECK-SAME: phase = 0.000000e+00 : f64}
// CHECK-NEXT: ion.yield %arg1 : !quantum.bit
// CHECK-NEXT: }
%6 = quantum.custom "RX"(%arg0) %5 : !quantum.bit

Expand Down Expand Up @@ -213,6 +216,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit {
// CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>,
// CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>,
// CHECK-SAME: phase = 0.000000e+00 : f64}
// CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit
// CHECK-NEXT: }
%7:2 = quantum.custom "MS"(%arg0) %6, %3 : !quantum.bit, !quantum.bit
return %7#0: !quantum.bit
Expand Down Expand Up @@ -289,6 +293,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, !
// CHECK-SAME: polarization = dense<[7, 8]> : vector<2xi64>,
// CHECK-SAME: wavevector = dense<[-9, -10]> : vector<2xi64>>,
// CHECK-SAME: phase = 0.000000e+00 : f64}
// CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit
// CHECK-NEXT: }
%5:2 = quantum.custom "MS"(%arg0) %2, %3 : !quantum.bit, !quantum.bit

Expand Down Expand Up @@ -344,6 +349,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, !
// CHECK-SAME: polarization = dense<[1, 2]> : vector<2xi64>,
// CHECK-SAME: wavevector = dense<[3, -4]> : vector<2xi64>>,
// CHECK-SAME: phase = 0.000000e+00 : f64}
// CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit
// CHECK-NEXT: }
%6:2 = quantum.custom "MS"(%arg0) %5#0, %4 : !quantum.bit, !quantum.bit

Expand Down Expand Up @@ -399,6 +405,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, !
// CHECK-SAME: polarization = dense<[37, 42]> : vector<2xi64>,
// CHECK-SAME: wavevector = dense<[42, 37]> : vector<2xi64>>,
// CHECK-SAME: phase = 0.000000e+00 : f64}
// CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit
// CHECK-NEXT: }
%7:2 = quantum.custom "MS"(%arg0) %5#1, %6#1 : !quantum.bit, !quantum.bit
return %6#0, %7#0, %7#1: !quantum.bit, !quantum.bit, !quantum.bit
Expand Down

0 comments on commit 286e519

Please sign in to comment.