From b31ffa86b5a6a501e9cc092b1e1d661687243ba7 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Tue, 30 Sep 2025 09:37:55 -0400 Subject: [PATCH 01/21] Add support of MCM for decompose pass --- mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index 9dcc4ea1ad..ebaf06b4d5 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -346,6 +346,9 @@ class OpSignatureAnalyzer { } qubit = customOp.getQubitOperands()[0]; } + else if (auto measureOp = dyn_cast_or_null(qubit.getDefiningOp())) { + qubit = measureOp.getInQubit(); + } } return nullptr; @@ -377,6 +380,9 @@ class OpSignatureAnalyzer { } } } + else if (auto measureOp = dyn_cast_or_null(qubit.getDefiningOp())) { + qubit = measureOp.getInQubit(); + } break; } From 407f16fe392cc449164060ec1039e4ea6bff2a38 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Tue, 30 Sep 2025 10:44:12 -0400 Subject: [PATCH 02/21] Add test --- mlir/test/Quantum/DecomposeLoweringTest.mlir | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/mlir/test/Quantum/DecomposeLoweringTest.mlir b/mlir/test/Quantum/DecomposeLoweringTest.mlir index 91bfbe7778..2a5b24eb54 100644 --- a/mlir/test/Quantum/DecomposeLoweringTest.mlir +++ b/mlir/test/Quantum/DecomposeLoweringTest.mlir @@ -508,3 +508,49 @@ module @cnot_alternative_decomposition { return %out_qubits_2#0, %out_qubits_4 : !quantum.bit, !quantum.bit } } + +// ----- + +module @mcm_example { + func.func public @test_mcm_hadamard() -> tensor<2xf64> { + %0 = quantum.alloc( 1) : !quantum.reg + %1 = quantum.extract %0[ 0] : !quantum.reg -> !quantum.bit + %mres, %out_qubit = quantum.measure %1 : i1, !quantum.bit + %2 = quantum.insert %0[ 0], %out_qubit : !quantum.reg, !quantum.bit + + // CHECK: [[RZ_QUBIT:%.+]] = quantum.custom "RZ"([[CST_0:%.+]]) + // CHECK: [[RY_QUBIT:%.+]] = quantum.custom "RY"([[CST_1:%.+]]) [[RZ_QUBIT]] : !quantum.bit + // CHECK: [[REG_1:%.+]] = quantum.insert [[REG:%.+]][[[EXTRACTED:%.+]]], [[RY_QUBIT]] : !quantum.reg, !quantum.bit + // CHECK-NOT: quantum.custom "Hadamard" + %3 = quantum.extract %2[ 0] : !quantum.reg -> !quantum.bit + %out_qubits = quantum.custom "Hadamard"() %3 : !quantum.bit + %4 = quantum.insert %2[ 0], %out_qubits : !quantum.reg, !quantum.bit + + %5 = quantum.compbasis qreg %4 : !quantum.obs + %6 = quantum.probs %5 : tensor<2xf64> + quantum.dealloc %4 : !quantum.reg + return %6 : tensor<2xf64> + } + + // Decomposition function should be applied and removed from the module + // CHECK-NOT: func.func public @rz_ry + func.func public @rz_ry(%arg0: !quantum.reg, %arg1: tensor<1xi64>) -> !quantum.reg attributes {llvm.linkage = #llvm.linkage, num_wires = 1 : i64, target_gate = "Hadamard"} { + %cst = arith.constant 3.1415926535897931 : f64 + %cst_0 = arith.constant 1.5707963267948966 : f64 + %0 = stablehlo.slice %arg1 [0:1] : (tensor<1xi64>) -> tensor<1xi64> + %1 = stablehlo.reshape %0 : (tensor<1xi64>) -> tensor + %extracted = tensor.extract %1[] : tensor + %2 = quantum.extract %arg0[%extracted] : !quantum.reg -> !quantum.bit + %out_qubits = quantum.custom "RZ"(%cst_0) %2 : !quantum.bit + %3 = stablehlo.slice %arg1 [0:1] : (tensor<1xi64>) -> tensor<1xi64> + %4 = stablehlo.reshape %3 : (tensor<1xi64>) -> tensor + %extracted_1 = tensor.extract %1[] : tensor + %5 = quantum.insert %arg0[%extracted_1], %out_qubits : !quantum.reg, !quantum.bit + %extracted_2 = tensor.extract %4[] : tensor + %6 = quantum.extract %5[%extracted_2] : !quantum.reg -> !quantum.bit + %out_qubits_3 = quantum.custom "RY"(%cst) %6 : !quantum.bit + %extracted_4 = tensor.extract %4[] : tensor + %7 = quantum.insert %5[%extracted_4], %out_qubits_3 : !quantum.reg, !quantum.bit + return %7 : !quantum.reg + } +} From ee3b0c2ad05e3bb18de8d00406e615ff983b988a Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Tue, 30 Sep 2025 11:32:42 -0400 Subject: [PATCH 03/21] Fix --- mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index ebaf06b4d5..2b4bbce295 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -382,6 +382,7 @@ class OpSignatureAnalyzer { } else if (auto measureOp = dyn_cast_or_null(qubit.getDefiningOp())) { qubit = measureOp.getInQubit(); + continue; } break; From d01ef10b237b8e689de87ec478831c16bd5c4064 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Fri, 3 Oct 2025 14:17:02 -0400 Subject: [PATCH 04/21] refactoring --- .../Transforms/DecomposeLoweringPatterns.cpp | 133 +++++++----------- 1 file changed, 54 insertions(+), 79 deletions(-) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index 2b4bbce295..db13074261 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "Quantum/IR/QuantumInterfaces.h" #define DEBUG_TYPE "decompose-lowering" #include @@ -40,6 +41,7 @@ namespace quantum { /// - A runtime Value (for dynamic indices computed at runtime) /// - An IntegerAttr (for compile-time constant indices) /// - Invalid/uninitialized (represented by std::monostate) +/// And a qreg value to represent the qreg that the index belongs to /// /// The struct uses std::variant to ensure only one type is active at a time, /// preventing invalid states. @@ -54,47 +56,44 @@ namespace quantum { /// Value idx = dynamicIdx.getValue(); // Get the Value /// } /// } -struct QubitIndex { +class QubitIndex { + private: // use monostate to represent the invalid index std::variant index; + Value qreg; - QubitIndex() : index(std::monostate()) {} - QubitIndex(Value val) : index(val) {} - QubitIndex(IntegerAttr attr) : index(attr) {} + public: + QubitIndex() : index(std::monostate()), qreg(nullptr) {} + QubitIndex(Value val, Value qreg) : index(val), qreg(qreg) {} + QubitIndex(IntegerAttr attr, Value qreg) : index(attr), qreg(qreg) {} bool isValue() const { return std::holds_alternative(index); } bool isAttr() const { return std::holds_alternative(index); } operator bool() const { return isValue() || isAttr(); } + Value getReg() const { return qreg; } Value getValue() const { return isValue() ? std::get(index) : nullptr; } IntegerAttr getAttr() const { return isAttr() ? std::get(index) : nullptr; } }; -// The goal of this class is to analyze the signature of a custom operation to get the enough +// The goal of this class is to analyze the signature of a quantum gate operation to get the enough // information to prepare the call operands and results for replacing the op to calling the // decomposition function. +// GateType can be QuantumGate or ParametrizedGate class OpSignatureAnalyzer { public: OpSignatureAnalyzer() = delete; OpSignatureAnalyzer(CustomOp op, bool enableQregMode) - : signature(OpSignature{ - .params = op.getParams(), - .inQubits = op.getInQubits(), - .inCtrlQubits = op.getInCtrlQubits(), - .inCtrlValues = op.getInCtrlValues(), - .outQubits = op.getOutQubits(), - .outCtrlQubits = op.getOutCtrlQubits(), - }) + : signature( + OpSignature{.params = op.getParams(), + .inQubits = op.getNonCtrlQubitOperands(), + .inCtrlQubits = op.getCtrlQubitOperands(), + .inCtrlValues = op.getCtrlValueOperands(), + .outQubits = op.getNonCtrlQubitResults(), + .outCtrlQubits = op.getCtrlQubitResults()}) { if (!enableQregMode) return; - signature.sourceQreg = getSourceQreg(signature.inQubits.front()); - if (!signature.sourceQreg) { - op.emitError("Cannot get source qreg"); - isValid = false; - return; - } - // input wire indices for (Value qubit : signature.inQubits) { const QubitIndex index = getExtractIndex(qubit); @@ -117,6 +116,9 @@ class OpSignatureAnalyzer { signature.inCtrlWireIndices.emplace_back(index); } + assert((signature.inWireIndices.size() + signature.inCtrlWireIndices.size()) > 0 && + "inWireIndices or inCtrlWireIndices should not be empty"); + // Output qubit indices are the same as input qubit indices signature.outQubitIndices = signature.inWireIndices; signature.outCtrlQubitIndices = signature.inCtrlWireIndices; @@ -124,6 +126,13 @@ class OpSignatureAnalyzer { operator bool() const { return isValid; } + Value getUpdatedQreg(PatternRewriter &rewriter, Location loc) + { + // FIXME: This will cause an issue when the decomposition function has cross-qreg + // inputs and outputs. Now, we just assume has only one qreg input, the global one exists. + return signature.inWireIndices[0].getReg(); + } + // Prepare the operands for calling the decomposition function // There are two cases: // 1. The first input is a qreg, which means the decomposition function is a qreg mode function @@ -144,15 +153,8 @@ class OpSignatureAnalyzer { int operandIdx = 0; if (isa(funcInputs[0])) { - Value updatedQreg = signature.sourceQreg; - for (auto [i, qubit] : llvm::enumerate(signature.inQubits)) { - const QubitIndex &index = signature.inWireIndices[i]; - updatedQreg = - rewriter.create(loc, updatedQreg.getType(), updatedQreg, - index.getValue(), index.getAttr(), qubit); - } + operands[operandIdx++] = getUpdatedQreg(rewriter, loc); - operands[operandIdx++] = updatedQreg; if (!signature.params.empty()) { auto [startIdx, endIdx] = findParamTypeRange(funcInputs, signature.params.size(), operandIdx); @@ -163,16 +165,11 @@ class OpSignatureAnalyzer { } } - if (!signature.inWireIndices.empty()) { - operands[operandIdx] = fromTensorOrAsIs(signature.inWireIndices, - funcInputs[operandIdx], rewriter, loc); - operandIdx++; - } - - if (!signature.inCtrlWireIndices.empty()) { - operands[operandIdx] = fromTensorOrAsIs(signature.inCtrlWireIndices, - funcInputs[operandIdx], rewriter, loc); - operandIdx++; + for (const auto &indices : {signature.inWireIndices, signature.inCtrlWireIndices}) { + if (!indices.empty()) { + operands[operandIdx++] = + fromTensorOrAsIs(indices, funcInputs[operandIdx], rewriter, loc); + } } } else { @@ -218,18 +215,16 @@ class OpSignatureAnalyzer { SmallVector newResults; rewriter.setInsertionPointAfter(callOp); - for (const QubitIndex &index : signature.outQubitIndices) { - auto extractOp = rewriter.create( - callOp.getLoc(), rewriter.getType(), qreg, index.getValue(), - index.getAttr()); - newResults.emplace_back(extractOp.getResult()); - } - for (const QubitIndex &index : signature.outCtrlQubitIndices) { - auto extractOp = rewriter.create( - callOp.getLoc(), rewriter.getType(), qreg, index.getValue(), - index.getAttr()); - newResults.emplace_back(extractOp.getResult()); + + for (const auto &indices : {signature.outQubitIndices, signature.outCtrlQubitIndices}) { + for (const auto &index : indices) { + auto extractOp = rewriter.create( + callOp.getLoc(), rewriter.getType(), qreg, index.getValue(), + index.getAttr()); + newResults.emplace_back(extractOp.getResult()); + } } + return newResults; } @@ -245,7 +240,6 @@ class OpSignatureAnalyzer { ValueRange outCtrlQubits; // Qreg mode specific information - Value sourceQreg = nullptr; SmallVector inWireIndices; SmallVector inCtrlWireIndices; SmallVector outQubitIndices; @@ -333,42 +327,21 @@ class OpSignatureAnalyzer { return values.front(); } - Value getSourceQreg(Value qubit) - { - while (qubit) { - if (auto extractOp = qubit.getDefiningOp()) { - return extractOp.getQreg(); - } - - if (auto customOp = dyn_cast_or_null(qubit.getDefiningOp())) { - if (customOp.getQubitOperands().empty()) { - break; - } - qubit = customOp.getQubitOperands()[0]; - } - else if (auto measureOp = dyn_cast_or_null(qubit.getDefiningOp())) { - qubit = measureOp.getInQubit(); - } - } - - return nullptr; - } - QubitIndex getExtractIndex(Value qubit) { while (qubit) { if (auto extractOp = qubit.getDefiningOp()) { if (Value idx = extractOp.getIdx()) { - return QubitIndex(idx); + return QubitIndex(idx, extractOp.getQreg()); } if (IntegerAttr idxAttr = extractOp.getIdxAttrAttr()) { - return QubitIndex(idxAttr); + return QubitIndex(idxAttr, extractOp.getQreg()); } } - if (auto customOp = dyn_cast_or_null(qubit.getDefiningOp())) { - auto qubitOperands = customOp.getQubitOperands(); - auto qubitResults = customOp.getQubitResults(); + if (auto gate = dyn_cast_or_null(qubit.getDefiningOp())) { + auto qubitOperands = gate.getQubitOperands(); + auto qubitResults = gate.getQubitResults(); auto it = llvm::find_if(qubitResults, [&](Value result) { return result == qubit; }); @@ -401,7 +374,8 @@ struct DecomposeLoweringRewritePattern : public OpRewritePattern { DecomposeLoweringRewritePattern(MLIRContext *context, const llvm::StringMap ®istry, const llvm::StringSet &gateSet) - : OpRewritePattern(context), decompositionRegistry(registry), targetGateSet(gateSet) + : OpRewritePattern(context), decompositionRegistry(registry), + targetGateSet(gateSet) { } @@ -428,11 +402,12 @@ struct DecomposeLoweringRewritePattern : public OpRewritePattern { assert(decompFunc.getFunctionType().getNumResults() >= 1 && "Decomposition function must have at least one result"); + rewriter.setInsertionPointAfter(op); + auto enableQreg = isa(decompFunc.getFunctionType().getInput(0)); auto analyzer = OpSignatureAnalyzer(op, enableQreg); assert(analyzer && "Analyzer should be valid"); - rewriter.setInsertionPointAfter(op); auto callOperands = analyzer.prepareCallOperands(decompFunc, rewriter, op.getLoc()); auto callOp = rewriter.create(op.getLoc(), decompFunc.getFunctionType().getResults(), @@ -460,4 +435,4 @@ void populateDecomposeLoweringPatterns(RewritePatternSet &patterns, } } // namespace quantum -} // namespace catalyst +} // namespace catalyst \ No newline at end of file From 29debbb94c349107ebad429cd4f6c8837179bd4b Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Fri, 3 Oct 2025 14:17:13 -0400 Subject: [PATCH 05/21] formatting --- .../Transforms/DecomposeLoweringPatterns.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index db13074261..e21b3cf4fb 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -83,13 +83,12 @@ class OpSignatureAnalyzer { public: OpSignatureAnalyzer() = delete; OpSignatureAnalyzer(CustomOp op, bool enableQregMode) - : signature( - OpSignature{.params = op.getParams(), - .inQubits = op.getNonCtrlQubitOperands(), - .inCtrlQubits = op.getCtrlQubitOperands(), - .inCtrlValues = op.getCtrlValueOperands(), - .outQubits = op.getNonCtrlQubitResults(), - .outCtrlQubits = op.getCtrlQubitResults()}) + : signature(OpSignature{.params = op.getParams(), + .inQubits = op.getNonCtrlQubitOperands(), + .inCtrlQubits = op.getCtrlQubitOperands(), + .inCtrlValues = op.getCtrlValueOperands(), + .outQubits = op.getNonCtrlQubitResults(), + .outCtrlQubits = op.getCtrlQubitResults()}) { if (!enableQregMode) return; From 211135c40ccdc9c5262eff0d8a5f014362ba797a Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Fri, 3 Oct 2025 14:24:18 -0400 Subject: [PATCH 06/21] fix --- mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index e21b3cf4fb..e5ae71b824 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -166,8 +166,9 @@ class OpSignatureAnalyzer { for (const auto &indices : {signature.inWireIndices, signature.inCtrlWireIndices}) { if (!indices.empty()) { - operands[operandIdx++] = + operands[operandIdx] = fromTensorOrAsIs(indices, funcInputs[operandIdx], rewriter, loc); + operandIdx++; } } } From ef06aa46636566ab1429995cf5f1ddc467f56820 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Fri, 3 Oct 2025 15:02:39 -0400 Subject: [PATCH 07/21] reorder include --- mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index e5ae71b824..3fb388017b 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "Quantum/IR/QuantumInterfaces.h" #define DEBUG_TYPE "decompose-lowering" #include @@ -26,6 +25,7 @@ #include "mlir/IR/PatternMatch.h" #include "mlir/IR/ValueRange.h" +#include "Quantum/IR/QuantumInterfaces.h" #include "Quantum/IR/QuantumOps.h" #include "Quantum/Transforms/Patterns.h" From 9aa4697ab2a96924d3e72733d5efbae789df7fd9 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Fri, 3 Oct 2025 15:16:26 -0400 Subject: [PATCH 08/21] update comment --- mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index 3fb388017b..7e0c9728e7 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -75,10 +75,9 @@ class QubitIndex { IntegerAttr getAttr() const { return isAttr() ? std::get(index) : nullptr; } }; -// The goal of this class is to analyze the signature of a quantum gate operation to get the enough +// The goal of this class is to analyze the signature of a custom operation to get the enough // information to prepare the call operands and results for replacing the op to calling the // decomposition function. -// GateType can be QuantumGate or ParametrizedGate class OpSignatureAnalyzer { public: OpSignatureAnalyzer() = delete; From 790446621ef568237378cf8c1f472f8ccd5e262f Mon Sep 17 00:00:00 2001 From: Paul <79805239+paul0403@users.noreply.github.com> Date: Mon, 6 Oct 2025 17:07:59 -0400 Subject: [PATCH 09/21] Prepare for next development cycle (v14) (#2097) Context: Setting up the repository for the next development cycle after v13 release. Description of the Change: - Add new changelog-dev.md file for v0.14.0 - Add changelog-dev reference to release_notes.rst - Update version in _version.py to 0.14.0-dev0 - Update rc_sync.yml for release manager name - Update build-nightly-release-candidate.yaml's schedule for this release --------- Co-authored-by: Mehrdad Malek <39844030+mehrdad2m@users.noreply.github.com> --- .../build-nightly-release-candidate.yaml | 8 ++++---- .github/workflows/rc_sync.yaml | 2 +- doc/dev/release_notes.rst | 2 ++ doc/releases/changelog-dev.md | 19 +++++++++++++++++++ frontend/catalyst/_version.py | 2 +- 5 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 doc/releases/changelog-dev.md diff --git a/.github/workflows/build-nightly-release-candidate.yaml b/.github/workflows/build-nightly-release-candidate.yaml index 34e5518697..c20c5216ad 100644 --- a/.github/workflows/build-nightly-release-candidate.yaml +++ b/.github/workflows/build-nightly-release-candidate.yaml @@ -2,14 +2,14 @@ name: Build Release Branch Nightly for TestPyPI on: schedule: - # Run from July 8th to July 13th at 02:00 UTC (10:00 PM EDT) - - cron: "0 2 8-13 7 *" + # Run from October 7th to October 12th at 02:00 UTC (10:00 PM EDT) + - cron: "0 2 7-12 10 *" workflow_dispatch: inputs: branch: description: 'Branch to build from' required: true - default: 'v0.12.0-rc' + default: 'v0.13.0-rc' jobs: setup: @@ -20,7 +20,7 @@ jobs: steps: - name: Set branch id: set_branch - run: echo "branch=${{ github.event.inputs.branch || 'v0.12.0-rc' }}" >> $GITHUB_OUTPUT + run: echo "branch=${{ github.event.inputs.branch || 'v0.13.0-rc' }}" >> $GITHUB_OUTPUT - name: Checkout Catalyst repo release branch uses: actions/checkout@v4 diff --git a/.github/workflows/rc_sync.yaml b/.github/workflows/rc_sync.yaml index 9f8c8868c5..7d3eadd1b8 100644 --- a/.github/workflows/rc_sync.yaml +++ b/.github/workflows/rc_sync.yaml @@ -83,4 +83,4 @@ jobs: pr_body: "Automatic sync from the release candidate to main during a feature freeze." pr_allow_empty: false pr_draft: false - pr_reviewer: "dime10,mehrdad2m" + pr_reviewer: "dime10,paul0403" diff --git a/doc/dev/release_notes.rst b/doc/dev/release_notes.rst index 201a4da558..7b6aba4e56 100644 --- a/doc/dev/release_notes.rst +++ b/doc/dev/release_notes.rst @@ -3,6 +3,8 @@ Release notes This page contains the release notes for Catalyst. +.. mdinclude:: ../releases/changelog-dev.md + .. mdinclude:: ../releases/changelog-0.13.0.md .. mdinclude:: ../releases/changelog-0.12.0.md diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md new file mode 100644 index 0000000000..4bdf910e6b --- /dev/null +++ b/doc/releases/changelog-dev.md @@ -0,0 +1,19 @@ +# Release 0.14.0 (development release) + +

New features since last release

+ +

Improvements 🛠

+ +

Breaking changes 💔

+ +

Deprecations 👋

+ +

Bug fixes 🐛

+ +

Internal changes ⚙️

+ +

Documentation 📝

+ +

Contributors ✍️

+ +This release contains contributions from (in alphabetical order): diff --git a/frontend/catalyst/_version.py b/frontend/catalyst/_version.py index 0a02dda8fb..e03910ca65 100644 --- a/frontend/catalyst/_version.py +++ b/frontend/catalyst/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.13.0" +__version__ = "0.14.0-dev0" From bed0d69311a646ee3bd350e6b7bd11477352c3f2 Mon Sep 17 00:00:00 2001 From: ringo-but-quantum Date: Tue, 7 Oct 2025 03:45:34 +0000 Subject: [PATCH 10/21] [no ci] bump nightly version --- frontend/catalyst/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/catalyst/_version.py b/frontend/catalyst/_version.py index e03910ca65..9c7bfbd24c 100644 --- a/frontend/catalyst/_version.py +++ b/frontend/catalyst/_version.py @@ -16,4 +16,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "0.14.0-dev0" +__version__ = "0.14.0-dev1" From 4d065d1a33dcb52789bf28cc8b17da058918fb6f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 10:10:57 -0400 Subject: [PATCH 11/21] Daily rc sync to main (#2098) Automatic sync from the release candidate to main during a feature freeze. --------- Co-authored-by: Jeffrey Kam Co-authored-by: Isaac De Vlugt <34751083+isaacdevlugt@users.noreply.github.com> Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> Co-authored-by: ringo-but-quantum Co-authored-by: Paul <79805239+paul0403@users.noreply.github.com> Co-authored-by: GitHub Actions Bot <> Co-authored-by: paul0403 --- doc/releases/changelog-0.13.0.md | 1 + frontend/catalyst/qfunc.py | 4 ++++ frontend/test/lit/test_mid_circuit_measurement.py | 6 +++--- frontend/test/pytest/test_mid_circuit_measurement.py | 7 ++++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/releases/changelog-0.13.0.md b/doc/releases/changelog-0.13.0.md index 39e60f1082..828aedc2b8 100644 --- a/doc/releases/changelog-0.13.0.md +++ b/doc/releases/changelog-0.13.0.md @@ -134,6 +134,7 @@ * Catalyst now supports returning classical and MCM values with the dynamic one-shot MCM method. [(#2004)](https://github.com/PennyLaneAI/catalyst/pull/2004) + [(#2090)](https://github.com/PennyLaneAI/catalyst/pull/2090) For example, the code below will generate 10 values, with an equal probability of 42 and 43 appearing. diff --git a/frontend/catalyst/qfunc.py b/frontend/catalyst/qfunc.py index b25453107e..38173c5eda 100644 --- a/frontend/catalyst/qfunc.py +++ b/frontend/catalyst/qfunc.py @@ -431,6 +431,10 @@ def _process_terminal_measurements(mcm_method, cpy_tape, out, snapshots, shot_ve result = jnp.squeeze(out[idx]) max_ndim = min(len(out[idx].shape), 2) + if out[idx].shape[0] == 1: + # Adding the first axis back when the first axis in the original + # array is 1, since it corresponds to the shot's dimension. + result = jnp.expand_dims(result, axis=0) if result.ndim == 1 and max_ndim == 2: result = jnp.expand_dims(result, axis=1) diff --git a/frontend/test/lit/test_mid_circuit_measurement.py b/frontend/test/lit/test_mid_circuit_measurement.py index e0544e3322..efea172a15 100644 --- a/frontend/test/lit/test_mid_circuit_measurement.py +++ b/frontend/test/lit/test_mid_circuit_measurement.py @@ -41,9 +41,9 @@ def test_one_shot_with_static_argnums(N): # CHECK: func.func private @one_shot_wrapper() -> tensor<1024xf64> # CHECK-DAG: [[one:%.+]] = arith.constant 1 : index - # CHECK-DAG: [[eleven:%.+]] = arith.constant 11 : index + # CHECK-DAG: [[ten:%.+]] = arith.constant 10 : index # CHECK-DAG: [[zero:%.+]] = arith.constant 0 : index - # CHECK: scf.for %arg0 = [[zero]] to [[eleven]] step [[one]] + # CHECK: scf.for %arg0 = [[zero]] to [[ten]] step [[one]] # CHECK: {{%.+}} = catalyst.launch_kernel @module_circ::@circ() : () -> tensor<1024xf64> # CHECK: func.func public @circ() -> tensor<1024xf64> @@ -53,7 +53,7 @@ def test_one_shot_with_static_argnums(N): dev = qml.device("lightning.qubit", wires=N) - @qml.set_shots(N + 1) + @qml.set_shots(N) @qml.qnode(dev, mcm_method="one-shot") def circ(): return qml.probs() diff --git a/frontend/test/pytest/test_mid_circuit_measurement.py b/frontend/test/pytest/test_mid_circuit_measurement.py index 5fe4fd9a4a..4e46569a75 100644 --- a/frontend/test/pytest/test_mid_circuit_measurement.py +++ b/frontend/test/pytest/test_mid_circuit_measurement.py @@ -424,7 +424,8 @@ def circuit(x): class TestDynamicOneShotIntegration: """Integration tests for QNodes using mcm_method="one-shot"/dynamic_one_shot.""" - def test_dynamic_one_shot_static_argnums(self, backend): + @pytest.mark.parametrize("shots", [1, 2]) + def test_dynamic_one_shot_static_argnums(self, backend, shots): """ Test static argnums is passed correctly to the one shot qnodes. """ @@ -433,14 +434,14 @@ def test_dynamic_one_shot_static_argnums(self, backend): def workflow(N): dev = qml.device(backend, wires=N) - @qml.set_shots(N + 1) + @qml.set_shots(N) @qml.qnode(dev, mcm_method="one-shot") def circ(): return qml.probs() return circ() - assert np.allclose(workflow(1), [1, 0]) + assert np.allclose(workflow(shots), [1 if i == 0 else 0 for i in range(2**shots)]) # pylint: disable=too-many-arguments @pytest.mark.parametrize( From f93aab781da4c4bf8d2889502df2b1823b20529d Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Tue, 7 Oct 2025 10:43:05 -0400 Subject: [PATCH 12/21] Add test --- .../from_plxpr/test_capture_integration.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/frontend/test/pytest/from_plxpr/test_capture_integration.py b/frontend/test/pytest/from_plxpr/test_capture_integration.py index 3f67d2b94b..68d0ad1c71 100644 --- a/frontend/test/pytest/from_plxpr/test_capture_integration.py +++ b/frontend/test/pytest/from_plxpr/test_capture_integration.py @@ -1313,6 +1313,38 @@ def circuit(x: float, y: float, z: float): assert jnp.allclose(circuit(1.5, 2.5, 3.5), capture_result) + def test_transform_graph_decompose_workflow(self, backend): + """Test the integration for a circuit with a 'decompose' graph transform.""" + + # Capture enabled + + qml.capture.enable() + qml.decomposition.enable_graph() + + @qjit(target="mlir") + @partial(qml.transforms.decompose, gate_set=[qml.RX, qml.RY, qml.RZ]) + @qml.qnode(qml.device(backend, wires=2)) + def captured_circuit(x: float, y: float, z: float): + qml.measure(0) + qml.Rot(x, y, z, 0) + return qml.expval(qml.PauliZ(0)) + + capture_result = captured_circuit(1.5, 2.5, 3.5) + + qml.decomposition.disable_graph() + qml.capture.disable() + + # Capture disabled + @qjit + @partial(qml.transforms.decompose, gate_set=[qml.RX, qml.RY, qml.RZ]) + @qml.qnode(qml.device(backend, wires=2)) + def circuit(x: float, y: float, z: float): + catalyst.measure(0) + qml.Rot(x, y, z, 0) + return qml.expval(qml.PauliZ(0)) + + assert jnp.allclose(circuit(1.5, 2.5, 3.5), capture_result) + def test_transform_map_wires_workflow(self, backend): """Test the integration for a circuit with a 'map_wires' transform.""" From d07e9f05b130cf2be0384d257cba68c60aa71160 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Tue, 7 Oct 2025 11:38:49 -0400 Subject: [PATCH 13/21] revert changes from latest main --- .../build-nightly-release-candidate.yaml | 8 ++++---- .github/workflows/rc_sync.yaml | 4 ++-- doc/dev/release_notes.rst | 2 -- doc/releases/changelog-dev.md | 19 ------------------- 4 files changed, 6 insertions(+), 27 deletions(-) delete mode 100644 doc/releases/changelog-dev.md diff --git a/.github/workflows/build-nightly-release-candidate.yaml b/.github/workflows/build-nightly-release-candidate.yaml index c20c5216ad..34e5518697 100644 --- a/.github/workflows/build-nightly-release-candidate.yaml +++ b/.github/workflows/build-nightly-release-candidate.yaml @@ -2,14 +2,14 @@ name: Build Release Branch Nightly for TestPyPI on: schedule: - # Run from October 7th to October 12th at 02:00 UTC (10:00 PM EDT) - - cron: "0 2 7-12 10 *" + # Run from July 8th to July 13th at 02:00 UTC (10:00 PM EDT) + - cron: "0 2 8-13 7 *" workflow_dispatch: inputs: branch: description: 'Branch to build from' required: true - default: 'v0.13.0-rc' + default: 'v0.12.0-rc' jobs: setup: @@ -20,7 +20,7 @@ jobs: steps: - name: Set branch id: set_branch - run: echo "branch=${{ github.event.inputs.branch || 'v0.13.0-rc' }}" >> $GITHUB_OUTPUT + run: echo "branch=${{ github.event.inputs.branch || 'v0.12.0-rc' }}" >> $GITHUB_OUTPUT - name: Checkout Catalyst repo release branch uses: actions/checkout@v4 diff --git a/.github/workflows/rc_sync.yaml b/.github/workflows/rc_sync.yaml index 7d3eadd1b8..860bee3d5d 100644 --- a/.github/workflows/rc_sync.yaml +++ b/.github/workflows/rc_sync.yaml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - + # Import Numpy/Pybind11 because it is imported in setup.py - name: Install Numpy and Pybind11 run: | @@ -83,4 +83,4 @@ jobs: pr_body: "Automatic sync from the release candidate to main during a feature freeze." pr_allow_empty: false pr_draft: false - pr_reviewer: "dime10,paul0403" + pr_reviewer: "dime10,mehrdad2m" diff --git a/doc/dev/release_notes.rst b/doc/dev/release_notes.rst index 7b6aba4e56..201a4da558 100644 --- a/doc/dev/release_notes.rst +++ b/doc/dev/release_notes.rst @@ -3,8 +3,6 @@ Release notes This page contains the release notes for Catalyst. -.. mdinclude:: ../releases/changelog-dev.md - .. mdinclude:: ../releases/changelog-0.13.0.md .. mdinclude:: ../releases/changelog-0.12.0.md diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md deleted file mode 100644 index 4bdf910e6b..0000000000 --- a/doc/releases/changelog-dev.md +++ /dev/null @@ -1,19 +0,0 @@ -# Release 0.14.0 (development release) - -

New features since last release

- -

Improvements 🛠

- -

Breaking changes 💔

- -

Deprecations 👋

- -

Bug fixes 🐛

- -

Internal changes ⚙️

- -

Documentation 📝

- -

Contributors ✍️

- -This release contains contributions from (in alphabetical order): From 0d1fe0f4ecc6683aeb6970f5df196fc3fd7b6f4c Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Tue, 7 Oct 2025 11:40:33 -0400 Subject: [PATCH 14/21] revert changes from main --- doc/releases/changelog-0.13.0.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/doc/releases/changelog-0.13.0.md b/doc/releases/changelog-0.13.0.md index ccc7d65588..e497540570 100644 --- a/doc/releases/changelog-0.13.0.md +++ b/doc/releases/changelog-0.13.0.md @@ -19,7 +19,7 @@ [(#2002)](https://github.com/PennyLaneAI/catalyst/pull/2002) Two new functions, ``qml.allocate()`` and ``qml.deallocate()``, [have been added to - PennyLane](https://docs.pennylane.ai/en/stable/development/release_notes.html#release-0-43-0) + PennyLane](https://docs.pennylane.ai/en/stable/development/release_notes.html#release-0-43-0) to support dynamic wire allocation. With Catalyst, these features can be accessed on ``lightning.qubit``, ``lightning.kokkos``, and ``lightning.gpu``. @@ -46,13 +46,13 @@ ``` In the above program, 2 qubits are allocated during device initialization, and 1 - additional qubit is allocated inside the circuit with ``qml.allocate(1)``. + additional qubit is allocated inside the circuit with ``qml.allocate(1)``. For more information on what ``qml.allocate`` and ``qml.deallocate`` do, please consult the [PennyLane v0.43 release notes](https://docs.pennylane.ai/en/stable/development/release_notes.html#release-0-43-0). However, there are some notable differences between the behaviour of these features - with ``qjit`` versus without. For details, please see the relevant sections in the + with ``qjit`` versus without. For details, please see the relevant sections in the [Catalyst sharp bits page](https://docs.pennylane.ai/projects/catalyst/en/stable/dev/sharp_bits.html#functionality-differences-from-pennylane). * A new quantum compilation pass that reduces the depth and count of non-Clifford Pauli product @@ -106,7 +106,7 @@ qml.H(wires=i) qml.T(wires=i) - return [measure(wires=i) for i in range(n)] + return [measure(wires=i) for i in range(n)] print(ppm_specs(circuit)) ``` @@ -116,7 +116,7 @@ {'circuit_0': {'depth_pi8_ppr': 4, 'depth_ppm': 1, 'logical_qubits': 3, 'max_weight_pi8': 3, 'num_of_ppm': 3, 'pi8_ppr': 6}} ``` - After performing the :func:`~.passes.to_ppr`, :func:`~.passes.commute_ppr`, and :func:`~.passes.merge_ppr_ppm`, + After performing the :func:`~.passes.to_ppr`, :func:`~.passes.commute_ppr`, and :func:`~.passes.merge_ppr_ppm`, passes, the circuit contains a depth of four of non-Clifford PPRs (`depth_pi8_ppr`). Subsequently applying the :func:`~.passes.t_layer_reduction` pass will move PPRs around via commutation, resulting in a circuit with a smaller PPR depth of three. @@ -141,8 +141,7 @@ ``` * Catalyst now supports returning classical and MCM values with the dynamic one-shot MCM method. - [(#2004)](https://github.com/PennyLaneAI/catalyst/pull/2004) - [(#2090)](https://github.com/PennyLaneAI/catalyst/pull/2090) + [(#2004)](https://github.com/PennyLaneAI/catalyst/pull/2004) [(#2090)](https://github.com/PennyLaneAI/catalyst/pull/2090) For example, the code below will generate 10 values, with an equal probability of 42 and 43 appearing. @@ -462,7 +461,7 @@ for example the one-shot mid circuit measurement transform. [(#2057)](https://github.com/PennyLaneAI/catalyst/pull/2057) This pass is part of a bottom-of-stack MBQC execution pathway, with a thin shim between the - PPR/PPM layer and MBQC to enable end-to-end compilation on a mocked backend. Also, in an MBQC gate + PPR/PPM layer and MBQC to enable end-to-end compilation on a mocked backend. Also, in an MBQC gate set, one of the gate `RotXZX` cannot yet be executed on available backends. ```python @@ -486,8 +485,8 @@ for example the one-shot mid circuit measurement transform.

Documentation 📝

-* Typos were fixed and supplemental information was added to the - docstrings for ``ppm_compilaion``, ``to_ppr``, ``commute_ppr``, +* Typos were fixed and supplemental information was added to the + docstrings for ``ppm_compilaion``, ``to_ppr``, ``commute_ppr``, ``ppr_to_ppm``, ``merge_ppr_ppm``, and ``ppm_specs``. [(#2050)](https://github.com/PennyLaneAI/catalyst/pull/2050) From 65cdd45bd97d33b6c4acb378724790923b1fe001 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Tue, 7 Oct 2025 13:38:21 -0400 Subject: [PATCH 15/21] update test --- .../from_plxpr/test_capture_integration.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/frontend/test/pytest/from_plxpr/test_capture_integration.py b/frontend/test/pytest/from_plxpr/test_capture_integration.py index 68d0ad1c71..7d1224b9e9 100644 --- a/frontend/test/pytest/from_plxpr/test_capture_integration.py +++ b/frontend/test/pytest/from_plxpr/test_capture_integration.py @@ -1325,8 +1325,13 @@ def test_transform_graph_decompose_workflow(self, backend): @partial(qml.transforms.decompose, gate_set=[qml.RX, qml.RY, qml.RZ]) @qml.qnode(qml.device(backend, wires=2)) def captured_circuit(x: float, y: float, z: float): - qml.measure(0) - qml.Rot(x, y, z, 0) + m = qml.measure(0) + + @qml.cond(m) + def cond_fn(): + qml.Rot(x, y, z, 0) + + cond_fn() return qml.expval(qml.PauliZ(0)) capture_result = captured_circuit(1.5, 2.5, 3.5) @@ -1339,8 +1344,13 @@ def captured_circuit(x: float, y: float, z: float): @partial(qml.transforms.decompose, gate_set=[qml.RX, qml.RY, qml.RZ]) @qml.qnode(qml.device(backend, wires=2)) def circuit(x: float, y: float, z: float): - catalyst.measure(0) - qml.Rot(x, y, z, 0) + m = catalyst.measure(0) + + @catalyst.cond(m) + def cond_fn(): + qml.Rot(x, y, z, 0) + + cond_fn() return qml.expval(qml.PauliZ(0)) assert jnp.allclose(circuit(1.5, 2.5, 3.5), capture_result) From ee232d3d5ae9810866beb733d4e840cf39e14854 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Tue, 7 Oct 2025 13:38:39 -0400 Subject: [PATCH 16/21] update changelog --- doc/releases/changelog-0.13.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/releases/changelog-0.13.0.md b/doc/releases/changelog-0.13.0.md index e497540570..695fd0be14 100644 --- a/doc/releases/changelog-0.13.0.md +++ b/doc/releases/changelog-0.13.0.md @@ -13,6 +13,7 @@ [(#2091)](https://github.com/PennyLaneAI/catalyst/pull/2091) [(#2029)](https://github.com/PennyLaneAI/catalyst/pull/2029) [(#2001)](https://github.com/PennyLaneAI/catalyst/pull/2001) + [(#2068)](https://github.com/PennyLaneAI/catalyst/pull/2068) * Catalyst now supports dynamic wire allocation with ``qml.allocate()`` and ``qml.deallocate()`` when program capture is enabled. From d2aa495d200bce9d32e7a52629a8d1152a468fcc Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Tue, 7 Oct 2025 13:39:35 -0400 Subject: [PATCH 17/21] Update mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> --- mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index 7e0c9728e7..5ef19272c7 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -434,4 +434,4 @@ void populateDecomposeLoweringPatterns(RewritePatternSet &patterns, } } // namespace quantum -} // namespace catalyst \ No newline at end of file +} // namespace catalyst From 5c654229d2cb6162ab72cce0057dd823880d6396 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Wed, 8 Oct 2025 10:52:47 -0400 Subject: [PATCH 18/21] Update doc/releases/changelog-0.13.0.md Co-authored-by: Ali Asadi <10773383+maliasadi@users.noreply.github.com> --- doc/releases/changelog-0.13.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/releases/changelog-0.13.0.md b/doc/releases/changelog-0.13.0.md index 695fd0be14..4324a7c5bd 100644 --- a/doc/releases/changelog-0.13.0.md +++ b/doc/releases/changelog-0.13.0.md @@ -11,9 +11,9 @@ and a ``UserWarning`` is raised. [(#2099)](https://github.com/PennyLaneAI/catalyst/pull/2099) [(#2091)](https://github.com/PennyLaneAI/catalyst/pull/2091) + [(#2068)](https://github.com/PennyLaneAI/catalyst/pull/2068) [(#2029)](https://github.com/PennyLaneAI/catalyst/pull/2029) [(#2001)](https://github.com/PennyLaneAI/catalyst/pull/2001) - [(#2068)](https://github.com/PennyLaneAI/catalyst/pull/2068) * Catalyst now supports dynamic wire allocation with ``qml.allocate()`` and ``qml.deallocate()`` when program capture is enabled. From dafca0e87ad1b9da66b0688ddd77eb106c727112 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Thu, 9 Oct 2025 13:23:38 -0400 Subject: [PATCH 19/21] Assert the decomp when reaching different qreg from an op --- .../Quantum/Transforms/DecomposeLoweringPatterns.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index 5ef19272c7..cbc586d51d 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -128,7 +128,15 @@ class OpSignatureAnalyzer { { // FIXME: This will cause an issue when the decomposition function has cross-qreg // inputs and outputs. Now, we just assume has only one qreg input, the global one exists. - return signature.inWireIndices[0].getReg(); + // raise an error if the qreg is not the same + Value qreg = signature.inWireIndices[0].getReg(); + + bool sameQreg = llvm::any_of( + llvm::concat(signature.inWireIndices, signature.inCtrlWireIndices), + [qreg](const auto &index) { return index.getReg() != qreg; }); + + assert(sameQreg && "The qreg of the input wires should be the same"); + return qreg; } // Prepare the operands for calling the decomposition function From 1ad5c8b94ac9115a64d645f4e504da6f22151702 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Thu, 9 Oct 2025 13:29:55 -0400 Subject: [PATCH 20/21] reorder the PR in changelog --- doc/releases/changelog-0.13.0.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/releases/changelog-0.13.0.md b/doc/releases/changelog-0.13.0.md index eec37eb429..66dd138ac2 100644 --- a/doc/releases/changelog-0.13.0.md +++ b/doc/releases/changelog-0.13.0.md @@ -9,11 +9,12 @@ Similar to PennyLane's behaviour, this experimental feature will fall back to the old system whenever the graph cannot find decomposition rules for all unsupported operators in the program, and a ``UserWarning`` is raised. - [(#2099)](https://github.com/PennyLaneAI/catalyst/pull/2099) - [(#2091)](https://github.com/PennyLaneAI/catalyst/pull/2091) - [(#2068)](https://github.com/PennyLaneAI/catalyst/pull/2068) - [(#2029)](https://github.com/PennyLaneAI/catalyst/pull/2029) [(#2001)](https://github.com/PennyLaneAI/catalyst/pull/2001) + [(#2029)](https://github.com/PennyLaneAI/catalyst/pull/2029) + [(#2068)](https://github.com/PennyLaneAI/catalyst/pull/2068) + [(#2091)](https://github.com/PennyLaneAI/catalyst/pull/2091) + [(#2099)](https://github.com/PennyLaneAI/catalyst/pull/2099) + * Catalyst now supports dynamic wire allocation with ``qml.allocate()`` and ``qml.deallocate()`` when program capture is enabled. From e09be4149efde3a36a34c1423fdfc39dfa9f1ec4 Mon Sep 17 00:00:00 2001 From: Hong-Sheng Zheng Date: Thu, 9 Oct 2025 13:49:19 -0400 Subject: [PATCH 21/21] fix --- .../Quantum/Transforms/DecomposeLoweringPatterns.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp index cbc586d51d..7d39c1d9f1 100644 --- a/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp +++ b/mlir/lib/Quantum/Transforms/DecomposeLoweringPatterns.cpp @@ -131,9 +131,13 @@ class OpSignatureAnalyzer { // raise an error if the qreg is not the same Value qreg = signature.inWireIndices[0].getReg(); - bool sameQreg = llvm::any_of( - llvm::concat(signature.inWireIndices, signature.inCtrlWireIndices), - [qreg](const auto &index) { return index.getReg() != qreg; }); + bool sameQreg = true; + for (const auto &index : signature.inWireIndices) { + sameQreg &= index.getReg() == qreg; + } + for (const auto &index : signature.inCtrlWireIndices) { + sameQreg &= index.getReg() == qreg; + } assert(sameQreg && "The qreg of the input wires should be the same"); return qreg;