Skip to content

Commit dccdc6d

Browse files
authored
Add canonicalize to extract (#2162)
**Context:** **Description of the Change:** Fix canonicalization of eliminating redundant `quantum.insert` and `quantum.extract` pairs. When extracting a qubit immediately after inserting it at the same index, the operations can be cancelled out while properly updating remaining uses of the register. For an example: ```mlir // Before canonicalization %1 = quantum.insert %0[%idx], %qubit1 : !quantum.reg, !quantum.bit %2 = quantum.extract %1[%idx] : !quantum.reg -> !quantum.bit ... %3 = quantum.insert %1[%i0], %qubit2 : !quantum.reg, !quantum.bit %4 = quantum.extract %1[%i1] : !quantum.reg -> !quantum.bit // ... use %1 // ... use %4 // After canonicalization // %2 directly uses %qubit1 // %3 and %4 updated to use %0 instead of %1 %3 = quantum.insert %0[%i0], %qubit2 : !quantum.reg, !quantum.bit %4 = quantum.extract %0[%i1] : !quantum.reg -> !quantum.bit // ... use %qubit1 // ... use %4 ``` **Benefits:** **Possible Drawbacks:** **Related GitHub Issues:**
1 parent 1e193e3 commit dccdc6d

File tree

3 files changed

+34
-11
lines changed

3 files changed

+34
-11
lines changed

doc/releases/changelog-dev.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,31 @@
4444

4545
* Fixes the translation of a workflow with different transforms applied to different qnodes.
4646
[(#2167)](https://github.com/PennyLaneAI/catalyst/pull/2167)
47+
48+
* Fix canonicalization of eliminating redundant `quantum.insert` and `quantum.extract` pairs.
49+
When extracting a qubit immediately after inserting it at the same index, the operations can
50+
be cancelled out while properly updating remaining uses of the register.
51+
[(#2162)](https://github.com/PennyLaneAI/catalyst/pull/2162)
52+
For an example:
53+
```mlir
54+
// Before canonicalization
55+
%1 = quantum.insert %0[%idx], %qubit1 : !quantum.reg, !quantum.bit
56+
%2 = quantum.extract %1[%idx] : !quantum.reg -> !quantum.bit
57+
...
58+
%3 = quantum.insert %1[%i0], %qubit2 : !quantum.reg, !quantum.bit
59+
%4 = quantum.extract %1[%i1] : !quantum.reg -> !quantum.bit
60+
// ... use %1
61+
// ... use %4
62+
63+
// After canonicalization
64+
// %2 directly uses %qubit1
65+
// %3 and %4 updated to use %0 instead of %1
66+
%3 = quantum.insert %0[%i0], %qubit2 : !quantum.reg, !quantum.bit
67+
%4 = quantum.extract %0[%i1] : !quantum.reg -> !quantum.bit
68+
// ... use %qubit1
69+
// ... use %4
70+
```
71+
4772

4873
<h3>Internal changes ⚙️</h3>
4974

@@ -75,4 +100,5 @@ Ali Asadi,
75100
Christina Lee,
76101
River McCubbin,
77102
Roberto Turrado,
78-
Paul Haochen Wang.
103+
Paul Haochen Wang,
104+
Hongsheng Zheng.

mlir/lib/Quantum/IR/QuantumOps.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,10 @@ LogicalResult ExtractOp::canonicalize(ExtractOp extract, mlir::PatternRewriter &
155155
bool bothDynamic = !extract.getIdxAttr().has_value() && !insert.getIdxAttr().has_value();
156156
bool staticallyEqual = bothStatic && extract.getIdxAttrAttr() == insert.getIdxAttrAttr();
157157
bool dynamicallyEqual = bothDynamic && extract.getIdx() == insert.getIdx();
158-
// if other users of insert are also `insert`, we are good to go
159-
bool valid = llvm::all_of(insert.getResult().getUsers(), [&](Operation *op) {
160-
return isa<InsertOp>(op) || op == extract.getOperation();
161-
});
162-
if ((staticallyEqual || dynamicallyEqual) && valid) {
158+
159+
bool inSameBlock = extract->getBlock() == insert->getBlock();
160+
161+
if ((staticallyEqual || dynamicallyEqual) && inSameBlock) {
163162
rewriter.replaceOp(extract, insert.getQubit());
164163
rewriter.replaceOp(insert, insert.getInQreg());
165164
return success();

mlir/test/Quantum/DecomposeLoweringTest.mlir

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,12 +388,10 @@ module @multi_wire_cnot_decomposition {
388388
// CHECK: [[QUBIT1:%.+]] = quantum.extract [[REG]][[[EXTRACTED]]] : !quantum.reg -> !quantum.bit
389389
// CHECK: [[RZ1:%.+]] = quantum.custom "RZ"([[CST_PI]]) [[QUBIT1]] : !quantum.bit
390390
// CHECK: [[RY1:%.+]] = quantum.custom "RY"([[CST_PI2]]) [[RZ1]] : !quantum.bit
391-
// CHECK: [[INSERT1:%.+]] = quantum.insert [[REG]][[[EXTRACTED]]], [[RY1]] : !quantum.reg, !quantum.bit
392391
// CHECK: [[EXTRACTED2:%.+]] = tensor.extract [[RESHAPE1]][] : tensor<i64>
393-
// CHECK: [[QUBIT0:%.+]] = quantum.extract [[INSERT1]][[[EXTRACTED2]]] : !quantum.reg -> !quantum.bit
394-
// CHECK: [[QUBIT1_2:%.+]] = quantum.extract [[INSERT1]][[[EXTRACTED]]] : !quantum.reg -> !quantum.bit
395-
// CHECK: [[CZ_RESULT:%.+]]:2 = quantum.custom "CZ"() [[QUBIT0]], [[QUBIT1_2]] : !quantum.bit, !quantum.bit
396-
// CHECK: [[INSERT2:%.+]] = quantum.insert [[INSERT1]][[[EXTRACTED2]]], [[CZ_RESULT]]#0 : !quantum.reg, !quantum.bit
392+
// CHECK: [[QUBIT0:%.+]] = quantum.extract [[REG]][[[EXTRACTED2]]] : !quantum.reg -> !quantum.bit
393+
// CHECK: [[CZ_RESULT:%.+]]:2 = quantum.custom "CZ"() [[QUBIT0]], [[RY1]] : !quantum.bit, !quantum.bit
394+
// CHECK: [[INSERT2:%.+]] = quantum.insert [[REG]][[[EXTRACTED2]]], [[CZ_RESULT]]#0 : !quantum.reg, !quantum.bit
397395
// CHECK: [[RZ2:%.+]] = quantum.custom "RZ"([[CST_PI]]) [[CZ_RESULT]]#1 : !quantum.bit
398396
// CHECK: [[RY2:%.+]] = quantum.custom "RY"([[CST_PI2]]) [[RZ2]] : !quantum.bit
399397
// CHECK: [[INSERT3:%.+]] = quantum.insert [[INSERT2]][[[EXTRACTED]]], [[RY2]] : !quantum.reg, !quantum.bit

0 commit comments

Comments
 (0)