I am trying to implement a CNOT-propagation Pass in MLIR in Catalyst. An example .mlir
is as follows:
module {
func.func @my_circuit( ) -> (!quantum.bit, !quantum.bit) {
%0 = quantum.alloc( 2) : !quantum.reg
%1 = quantum.extract %0[ 0] : !quantum.reg -> !quantum.bit
%2 = quantum.extract %0[ 1] : !quantum.reg -> !quantum.bit
%3 = quantum.custom "PauliX"() %1 : !quantum.bit
%out_qubits:2 = quantum.custom "CNOT"() %3, %2 : !quantum.bit, !quantum.bit
return %out_qubits#0, %out_qubits#1 : !quantum.bit, !quantum.bit
}
}
// Expected Output
//module {
// func.func @my_circuit( ) -> (!quantum.bit, !quantum.bit) {
// %0 = quantum.alloc( 2) : !quantum.reg
// %1 = quantum.extract %0[ 0] : !quantum.reg -> !quantum.bit
// %2 = quantum.extract %0[ 1] : !quantum.reg -> !quantum.bit
// %out_qubits:2 = quantum.custom "CNOT"() %1, %2 : !quantum.bit, !quantum.bit
// %3 = quantum.custom "PauliX"() %out_qubits#0 : !quantum.bit
// %4 = quantum.custom "PauliX"() %out_qubits#1 : !quantum.bit
// return %3, %4 : !quantum.bit, !quantum.bit
// }
//}
The idea here is that X gate on control propagates to target after CNOT.
Here’s the rewrite
logic I have:
auto cnotOp = cast<quantum::CustomOp>(op);
Operation *definingOp = cnotOp.getInQubits().front().getDefiningOp();
auto xOp = cast<quantum::CustomOp>(definingOp);
mlir::Location opLoc = op->getLoc();
// Create new CNOT operation with original non-X input
SmallVector<mlir::Value> cnotInQubits;
cnotInQubits.push_back(xOp.getInQubits().front()); // Use input to X gate
cnotInQubits.push_back(cnotOp.getInQubits().back());
auto newCnotOp = rewriter.create<quantum::CustomOp>(
opLoc,
cnotOp.getOutQubits().getTypes(),
ValueRange{},
cnotOp.getParams(),
cnotInQubits,
"CNOT",
nullptr,
ValueRange{},
ValueRange{});
// Create X gates operating on CNOT outputs
auto xOp1 = rewriter.create<quantum::CustomOp>(
opLoc,
newCnotOp.getOutQubits().front().getType(),
ValueRange{},
xOp.getParams(),
newCnotOp.getOutQubits().front(),
"PauliX",
nullptr,
ValueRange{},
ValueRange{});
auto xOp2 = rewriter.create<quantum::CustomOp>(
opLoc,
newCnotOp.getOutQubits().back().getType(),
ValueRange{},
xOp.getParams(),
newCnotOp.getOutQubits().back(),
"PauliX",
nullptr,
ValueRange{},
ValueRange{});
SmallVector<mlir::Value> newOp;
newOp.push_back(newCnotOp.getOutQubits().front());
newOp.push_back(xOp1.getOutQubits().front());
newOp.push_back(xOp2.getOutQubits().front());
rewriter.replaceOp(cnotOp, newOp);
rewriter.eraseOp(xOp); // Remove original X gate
return success();
The trace output I get is:
catalyst-cli: /home/patel/projects/catalyst/mlir/llvm-project/mlir/lib/IR/PatternMatch.cpp:135: virtual void mlir::RewriterBase::replaceOp(mlir::Operation *, mlir::ValueRange): Assertion `op->getNumResults() == newValues.size() && "incorrect # of replacement values"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0. Program arguments: ./build/bin/catalyst-cli ../c3.mlir --tool=opt --catalyst-pipeline=pipe(cnot-propagation{func-name=my_circuit}) --mlir-print-ir-after-all --mlir-print-stacktrace-on-diagnostic
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0 catalyst-cli 0x00005ec2a24a60f7
1 catalyst-cli 0x00005ec2a24a3d1e
2 catalyst-cli 0x00005ec2a24a677a
3 libc.so.6 0x000072eb78842520
4 libc.so.6 0x000072eb788969fc pthread_kill + 300
5 libc.so.6 0x000072eb78842476 raise + 22
6 libc.so.6 0x000072eb788287f3 abort + 211
7 libc.so.6 0x000072eb7882871b
8 libc.so.6 0x000072eb78839e96
9 catalyst-cli 0x00005ec2a23d9a26
10 catalyst-cli 0x00005ec29e4ac952
11 catalyst-cli 0x00005ec2a225d9a9
12 catalyst-cli 0x00005ec2a225a2cf
13 catalyst-cli 0x00005ec2a22307a8
14 catalyst-cli 0x00005ec2a222cf7c
15 catalyst-cli 0x00005ec29e4ab83b
16 catalyst-cli 0x00005ec2a2282904
17 catalyst-cli 0x00005ec2a2282f31
18 catalyst-cli 0x00005ec2a22854b2
19 catalyst-cli 0x00005ec29cf6a68e
20 catalyst-cli 0x00005ec29cf6b916
21 catalyst-cli 0x00005ec29cf6f84c
22 libc.so.6 0x000072eb78829d90
23 libc.so.6 0x000072eb78829e40 __libc_start_main + 128
24 catalyst-cli 0x00005ec29cf65ee5
[1] 1897019 IOT instruction (core dumped) ./build/bin/catalyst-cli ../c3.mlir --tool=opt --mlir-print-ir-after-all
I am very new to MLIR and LLVM in general so my logic for rewrite operation might be unnecessary complicated – in which case, feel free to post any suggestions.