Skip to content

Implement ppm_specs pass #1794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
eacfe86
test new print spec pass
ritu-thombre99 May 30, 2025
24e0afd
fix some descriptions
ritu-thombre99 May 30, 2025
ca994e4
fix passes.td file
ritu-thombre99 Jun 1, 2025
54c2460
4 stats recorded
ritu-thombre99 Jun 2, 2025
1f6ac67
implement ppm_spec logic
ritu-thombre99 Jun 4, 2025
ba5fb0c
slicing working
ritu-thombre99 Jun 5, 2025
940a16a
revert ppm_compilation
ritu-thombre99 Jun 5, 2025
dca7989
working in frontend
ritu-thombre99 Jun 6, 2025
09512cf
format and comment
ritu-thombre99 Jun 6, 2025
2b53308
track with main
ritu-thombre99 Jun 6, 2025
aa16ead
check if opt contains json
ritu-thombre99 Jun 8, 2025
ef174bf
resolve PR comments
ritu-thombre99 Jun 11, 2025
3304c10
fix formatting
ritu-thombre99 Jun 11, 2025
726237a
track with main
ritu-thombre99 Jun 11, 2025
ddc30f1
check nullptr for num_qubit
ritu-thombre99 Jun 11, 2025
eeffd55
move get_ppm_spec() API function out of jit.py and compiler.py; remov…
paul0403 Jun 12, 2025
bc4efce
remove ppm_specs from unnecessary places
ritu-thombre99 Jun 12, 2025
2dc9fc2
code cleanup
ritu-thombre99 Jun 12, 2025
f17706a
assert dynamic qubit count
ritu-thombre99 Jun 12, 2025
05ef5c3
formatting
ritu-thombre99 Jun 12, 2025
c1d5322
track with main
ritu-thombre99 Jun 12, 2025
f72df33
resolve some PR comments
ritu-thombre99 Jun 12, 2025
19900c7
check op type instead of name:
ritu-thombre99 Jun 12, 2025
d88e70f
Merge branch 'main' into ritu/ppm_specs
ritu-thombre99 Jun 13, 2025
34aa5ff
separate count functions
ritu-thombre99 Jun 13, 2025
ecae329
remove snake_case
ritu-thombre99 Jun 13, 2025
1260335
add frontend pytests
ritu-thombre99 Jun 13, 2025
641a416
formatting changes
ritu-thombre99 Jun 13, 2025
341e75b
fix pytests
ritu-thombre99 Jun 13, 2025
29d5b74
mlir test
ritu-thombre99 Jun 13, 2025
b596d18
update with main
ritu-thombre99 Jun 13, 2025
04e914e
mlir test with ppm specs
ritu-thombre99 Jun 13, 2025
e4c17b9
fix asserts
ritu-thombre99 Jun 13, 2025
a2265be
lit tests
ritu-thombre99 Jun 13, 2025
b282b0b
lit tests
ritu-thombre99 Jun 13, 2025
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
2 changes: 2 additions & 0 deletions frontend/catalyst/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
"""
import glob
import importlib
import json

Check notice on line 19 in frontend/catalyst/compiler.py

View check run for this annotation

codefactor.io / CodeFactor

frontend/catalyst/compiler.py#L19

Unused import json (unused-import)
import logging
import os
import pathlib
import platform
import re

Check notice on line 24 in frontend/catalyst/compiler.py

View check run for this annotation

codefactor.io / CodeFactor

frontend/catalyst/compiler.py#L24

Unused import re (unused-import)
import shutil
import subprocess
import sys
Expand Down
2 changes: 2 additions & 0 deletions frontend/catalyst/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
ppm_compilation,
ppr_to_ppm,
to_ppr,
get_ppm_spec,
)
from catalyst.passes.pass_api import Pass, PassPlugin, apply_pass, apply_pass_plugin

Expand All @@ -58,4 +59,5 @@
"merge_ppr_ppm",
"ppr_to_ppm",
"ppm_compilation",
"get_ppm_spec",
)
19 changes: 19 additions & 0 deletions frontend/catalyst/passes/builtin_passes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,29 @@
"""This module exposes built-in Catalyst MLIR passes to the frontend."""

import functools
import re

from catalyst.compiler import _quantum_opt
from catalyst.passes.pass_api import PassPipelineWrapper


def get_ppm_spec(QJIT):
"""TODO: docstring"""

if QJIT.mlir is not None:
# aot mode
raw_result = _quantum_opt(
("--pass-pipeline", "builtin.module(ppm_specs)"), [], stdin=QJIT.mlir
)

# breakpoint()
regex_search_for_json = re.search(r"\{.*?\}", raw_result, re.DOTALL)
return regex_search_for_json.group(0)

else:
raise "ppm passes only support aot mode, please make sure ..."

Check notice on line 38 in frontend/catalyst/passes/builtin_passes.py

View check run for this annotation

codefactor.io / CodeFactor

frontend/catalyst/passes/builtin_passes.py#L38

Raising str while only classes or instances are allowed (raising-bad-type)


## API ##
def cancel_inverses(qnode):
"""
Expand Down
1 change: 1 addition & 0 deletions frontend/catalyst/passes/pass_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,4 +382,5 @@ def _API_name_to_pass_name():
"merge_ppr_ppm": "merge_ppr_ppm",
"ppr_to_ppm": "ppr_to_ppm",
"ppm_compilation": "ppm_compilation",
"ppm_specs": "ppm_specs",
}
1 change: 1 addition & 0 deletions mlir/include/QEC/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ std::unique_ptr<mlir::Pass> createCommuteCliffordPastPPMPass();
std::unique_ptr<mlir::Pass> createDecomposeNonCliffordPPRPass();
std::unique_ptr<mlir::Pass> createDecomposeCliffordPPRPass();
std::unique_ptr<mlir::Pass> createCliffordTToPPMPass();
std::unique_ptr<mlir::Pass> createCountPPMSpecsPass();

} // namespace catalyst
6 changes: 6 additions & 0 deletions mlir/include/QEC/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,10 @@ def CliffordTToPPMPass : Pass<"ppm_compilation"> {
let options = [MaxPauliSizeOption, DecomposeMethodOption, AvoidYMeasureOption];
}

def CountPPMSpecsPass : Pass<"ppm_specs"> {
let summary = "Count specs in Pauli Product Measurement operations.";

let constructor = "catalyst::createCountPPMSpecsPass()";
}

#endif // QEC_PASSES
1 change: 1 addition & 0 deletions mlir/lib/Catalyst/Transforms/RegisterAllPasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ void catalyst::registerAllCatalystPasses()
mlir::registerPass(catalyst::createCliffordTToPPMPass);
mlir::registerPass(catalyst::createDecomposeNonCliffordPPRPass);
mlir::registerPass(catalyst::createDecomposeCliffordPPRPass);
mlir::registerPass(catalyst::createCountPPMSpecsPass);
mlir::registerPass(catalyst::createDetensorizeSCFPass);
mlir::registerPass(catalyst::createDisableAssertionPass);
mlir::registerPass(catalyst::createDisentangleCNOTPass);
Expand Down
23 changes: 22 additions & 1 deletion mlir/lib/QEC/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ file(GLOB SRC
commute_clifford_t_ppr.cpp
CommuteCliffordPastPPM.cpp
commute_clifford_past_ppm.cpp
CountPPMSpecs.cpp
decompose_non_clifford_ppr.cpp
DecomposeNonCliffordPPR.cpp
decompose_clifford_ppr.cpp
Expand All @@ -31,7 +32,27 @@ set(DEPENDS

add_mlir_library(${LIBRARY_NAME} STATIC ${SRC} LINK_LIBS PRIVATE ${LIBS} DEPENDS ${DEPENDS})
target_compile_features(${LIBRARY_NAME} PUBLIC cxx_std_20)

include(FetchContent)
FetchContent_Declare(json
URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz
URL_HASH SHA256=d6c65aca6b1ed68e7a182f4757257b107ae403032760ed6ef121c9d55e81757d
DOWNLOAD_EXTRACT_TIMESTAMP true
SYSTEM
)
FetchContent_MakeAvailable(json)
target_link_libraries(${LIBRARY_NAME}
PRIVATE nlohmann_json::nlohmann_json
)

if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
set_source_files_properties(
CountPPMSpecs.cpp
COMPILE_FLAGS "-Wno-covered-switch-default"
)
endif()

target_include_directories(${LIBRARY_NAME} PUBLIC
.
${PROJECT_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/include)
${CMAKE_BINARY_DIR}/include)
109 changes: 109 additions & 0 deletions mlir/lib/QEC/Transforms/CountPPMSpecs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2025 Xanadu Quantum Technologies Inc.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#define DEBUG_TYPE "ppm_specs"

#include <algorithm>
#include <string>

#include <nlohmann/json.hpp>

#include "mlir/IR/PatternMatch.h"
#include "mlir/Pass/Pass.h"

#include "QEC/IR/QECDialect.h"

using namespace llvm;
using namespace mlir;
using namespace catalyst;
using namespace catalyst::qec;
using json = nlohmann::json;

namespace catalyst {
namespace qec {

#define GEN_PASS_DEF_COUNTPPMSPECSPASS
#define GEN_PASS_DECL_COUNTPPMSPECSPASS
#include "QEC/Transforms/Passes.h.inc"

struct CountPPMSpecsPass : public impl::CountPPMSpecsPassBase<CountPPMSpecsPass> {
using CountPPMSpecsPassBase::CountPPMSpecsPassBase;

void print_specs()
{
llvm::BumpPtrAllocator string_allocator;
llvm::DenseMap<StringRef, int> PPM_Specs;
PPM_Specs["num_logical_qubits"] = 0;
PPM_Specs["num_of_ppm"] = 0;

// Walk over all operations in the IR (could be ModuleOp or FuncOp)
getOperation()->walk([&](Operation *op) {
// Skip top-level container ops if desired
if (isa<ModuleOp>(op))
return;

StringRef gate_name = op->getName().getStringRef();

if (gate_name == "quantum.alloc") {
auto num_qubits_attr = op->getAttrOfType<mlir::IntegerAttr>("nqubits_attr");
assert(num_qubits_attr == nullptr && "num_qubits_attr is a dynamic SSA value");
u_int64_t num_qubits =
num_qubits_attr ? static_cast<u_int64_t>(num_qubits_attr.getInt()) : 0;
PPM_Specs["num_logical_qubits"] = num_qubits;
}

if (gate_name == "qec.ppm") {
PPM_Specs["num_of_ppm"]++;
}

if (gate_name == "qec.ppr") {
auto rotation_attr = op->getAttrOfType<mlir::IntegerAttr>("rotation_kind");
auto pauli_product_attr = op->getAttrOfType<mlir::ArrayAttr>("pauli_product");
int16_t rotation_kind =
rotation_attr ? static_cast<int16_t>(rotation_attr.getInt()) : 0;
if (rotation_kind) {
llvm::StringSaver saver(string_allocator);
StringRef num_pi_key =
saver.save("num_pi" + std::to_string(abs(rotation_kind)) + "_gates");
StringRef max_weight_pi_key =
saver.save("max_weight_pi" + std::to_string(abs(rotation_kind)));

if (PPM_Specs.find(llvm::StringRef(num_pi_key)) == PPM_Specs.end()) {
PPM_Specs[num_pi_key] = 1;
PPM_Specs[max_weight_pi_key] = static_cast<int>(pauli_product_attr.size());
}
else {
PPM_Specs[num_pi_key]++;
PPM_Specs[max_weight_pi_key] =
std::max(PPM_Specs[max_weight_pi_key],
static_cast<int>(pauli_product_attr.size()));
}
}
}
});

json PPM_Specs_Json = PPM_Specs;
llvm::outs() << PPM_Specs_Json.dump(4) << "\n";
return;
}

void runOnOperation() final { print_specs(); }
};

} // namespace qec

/// Create a pass for lowering operations in the `QECDialect`.
std::unique_ptr<Pass> createCountPPMSpecsPass() { return std::make_unique<CountPPMSpecsPass>(); }

} // namespace catalyst
Loading