Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4e21ec1
initial steps for squin to stim rewrite
johnzl-777 Apr 14, 2025
89a17fd
Wrap rewrite pass
johnzl-777 Apr 14, 2025
f6105bb
confirm analysis wrapping works
johnzl-777 Apr 14, 2025
ad3a7dc
Merge branch 'main' into 19-rewrite-from-squin-to-stim
johnzl-777 Apr 14, 2025
7c70b5e
going to bed
johnzl-777 Apr 15, 2025
e55a8fb
preliminary handling of Apply
johnzl-777 Apr 15, 2025
e76b3f3
support for control gates confirmed
johnzl-777 Apr 15, 2025
7ba5670
finally put everything into a pass
johnzl-777 Apr 16, 2025
f3203da
partially working reset rewrite
johnzl-777 Apr 17, 2025
20d4214
account for MeasureAndReset
johnzl-777 Apr 17, 2025
300f9d7
account for MeasureAndReset, fix up address analysis
johnzl-777 Apr 17, 2025
c137221
Merge branch 'main' into 19-rewrite-from-squin-to-stim
johnzl-777 Apr 18, 2025
13ae8a5
more testing, verification implemented
johnzl-777 Apr 18, 2025
59f763d
remove test call
johnzl-777 Apr 18, 2025
9427571
simple site verification test
johnzl-777 Apr 18, 2025
e45c10c
saving remaining work before move to codegen
johnzl-777 Apr 22, 2025
1a67a03
Merge branch 'main' into 19-rewrite-from-squin-to-stim
johnzl-777 Apr 23, 2025
9b6562f
Merge branch 'main' into 19-rewrite-from-squin-to-stim
Roger-luo May 13, 2025
30b8a97
account for MeasureQubit, MeasureQubitIlist as well as Broadcast func…
johnzl-777 May 14, 2025
615a30b
revise tests
johnzl-777 May 14, 2025
47691e2
remove unnecessary comment
johnzl-777 May 14, 2025
c8c38ae
Move wrap analysis rewrite into its own file
johnzl-777 May 14, 2025
72e5f3f
split out reusable utility functions into a seperate file
johnzl-777 May 14, 2025
4731fe0
fix export problem
johnzl-777 May 14, 2025
410bcbc
split out rewrite rules, factor in feedback on rewriting wrap/unwrap …
johnzl-777 May 15, 2025
cab4ab6
get control statement logic to work in wire dialect, simplify stateme…
johnzl-777 May 15, 2025
c810544
use dict instead of match, just care about type comparison
johnzl-777 May 15, 2025
fb9ff37
use replace_by, fix analysis impl
johnzl-777 May 15, 2025
e6c92b7
first round of meeting feedback implemented
johnzl-777 May 15, 2025
9316a0e
split out Measure rewrite into its own rule
johnzl-777 May 15, 2025
e3b478a
add tests but codegen is acting weird
johnzl-777 May 15, 2025
0f759b8
remove site-target dimension check
johnzl-777 May 15, 2025
877755e
Merge branch 'main' into 19-rewrite-from-squin-to-stim
johnzl-777 May 15, 2025
4faf282
Merge branch 'main' into 19-rewrite-from-squin-to-stim
johnzl-777 May 16, 2025
dbc105c
implement second round review feedback
johnzl-777 May 16, 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
14 changes: 14 additions & 0 deletions src/bloqade/analysis/address/impls.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,20 @@
):
return frame.get_values(stmt.inputs)

@interp.impl(squin.wire.MeasureAndReset)
def measure_and_reset(
self,
interp_: AddressAnalysis,
frame: ForwardFrame[Address],
stmt: squin.wire.MeasureAndReset,
):

# take the address data from the incoming wire
# and propagate that forward to the new wire generated.
# The first entry can safely be NotQubit because
# it's an integer
return (NotQubit(), frame.get(stmt.wire))

Check warning on line 221 in src/bloqade/analysis/address/impls.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/analysis/address/impls.py#L221

Added line #L221 was not covered by tests


@squin.qubit.dialect.register(key="qubit.address")
class SquinQubitMethodTable(interp.MethodTable):
Expand Down
1 change: 1 addition & 0 deletions src/bloqade/squin/analysis/nsites/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Need this for impl registration to work properly!
from . import impls as impls
from .lattice import (
Sites as Sites,
NoSites as NoSites,
AnySites as AnySites,
NumberSites as NumberSites,
Expand Down
26 changes: 25 additions & 1 deletion src/bloqade/squin/analysis/nsites/impls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from kirin import interp

from bloqade.squin import op
from bloqade.squin import op, wire

from .lattice import (
NoSites,
Expand All @@ -9,6 +9,30 @@
from .analysis import NSitesAnalysis


@wire.dialect.register(key="op.nsites")
class SquinWire(interp.MethodTable):

@interp.impl(wire.Apply)
@interp.impl(wire.Broadcast)
def apply(
self,
interp: NSitesAnalysis,
frame: interp.Frame,
stmt: wire.Apply | wire.Broadcast,
):

return tuple(frame.get(input) for input in stmt.inputs)

@interp.impl(wire.MeasureAndReset)
def measure_and_reset(
self, interp: NSitesAnalysis, frame: interp.Frame, stmt: wire.MeasureAndReset
):

# MeasureAndReset produces both a new wire
# and an integer which don't have any sites at all
return (NoSites(), NoSites())

Check warning on line 33 in src/bloqade/squin/analysis/nsites/impls.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/analysis/nsites/impls.py#L33

Added line #L33 was not covered by tests


@op.dialect.register(key="op.nsites")
class SquinOp(interp.MethodTable):

Expand Down
1 change: 1 addition & 0 deletions src/bloqade/squin/passes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .stim import SquinToStim as SquinToStim
68 changes: 68 additions & 0 deletions src/bloqade/squin/passes/stim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from dataclasses import dataclass

from kirin.passes import Fold
from kirin.rewrite import (
Walk,
Chain,
Fixpoint,
DeadCodeElimination,
CommonSubexpressionElimination,
)
from kirin.ir.method import Method
from kirin.passes.abc import Pass
from kirin.rewrite.abc import RewriteResult

from bloqade.squin.rewrite import (
SquinWireToStim,
SquinQubitToStim,
WrapSquinAnalysis,
SquinMeasureToStim,
SquinWireIdentityElimination,
)
from bloqade.analysis.address import AddressAnalysis
from bloqade.squin.analysis.nsites import (
NSitesAnalysis,
)


@dataclass
class SquinToStim(Pass):

def unsafe_run(self, mt: Method) -> RewriteResult:
fold_pass = Fold(mt.dialects)
# propagate constants
rewrite_result = fold_pass(mt)

# Get necessary analysis results to plug into hints
address_analysis = AddressAnalysis(mt.dialects)
address_frame, _ = address_analysis.run_analysis(mt)
site_analysis = NSitesAnalysis(mt.dialects)
sites_frame, _ = site_analysis.run_analysis(mt)

# Wrap Rewrite + SquinToStim can happen w/ standard walk
rewrite_result = (
Walk(
Chain(
WrapSquinAnalysis(
address_analysis=address_frame.entries,
op_site_analysis=sites_frame.entries,
),
SquinQubitToStim(),
SquinWireToStim(),
SquinMeasureToStim(), # reduce duplicated logic, can split out even more rules later
SquinWireIdentityElimination(),
)
)
.rewrite(mt.code)
.join(rewrite_result)
)

rewrite_result = (
Fixpoint(
Walk(Chain(DeadCodeElimination(), CommonSubexpressionElimination()))
)
.rewrite(mt.code)
.join(rewrite_result)
)

return rewrite_result
11 changes: 11 additions & 0 deletions src/bloqade/squin/rewrite/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from .wire_to_stim import SquinWireToStim as SquinWireToStim
from .qubit_to_stim import SquinQubitToStim as SquinQubitToStim
from .squin_measure import SquinMeasureToStim as SquinMeasureToStim
from .wrap_analysis import (
SitesAttribute as SitesAttribute,
AddressAttribute as AddressAttribute,
WrapSquinAnalysis as WrapSquinAnalysis,
)
from .wire_identity_elimination import (
SquinWireIdentityElimination as SquinWireIdentityElimination,
)
84 changes: 84 additions & 0 deletions src/bloqade/squin/rewrite/qubit_to_stim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from kirin import ir
from kirin.rewrite.abc import RewriteRule, RewriteResult

from bloqade import stim
from bloqade.squin import op, qubit
from bloqade.squin.rewrite.wrap_analysis import AddressAttribute
from bloqade.squin.rewrite.stim_rewrite_util import (
SQUIN_STIM_GATE_MAPPING,
rewrite_Control,
insert_qubit_idx_from_address,
)


class SquinQubitToStim(RewriteRule):

def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:

match node:
case qubit.Apply() | qubit.Broadcast():
return self.rewrite_Apply_and_Broadcast(node)
case qubit.Reset():
return self.rewrite_Reset(node)
case _:
return RewriteResult()

Check warning on line 24 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L18-L24

Added lines #L18 - L24 were not covered by tests

def rewrite_Apply_and_Broadcast(
self, stmt: qubit.Apply | qubit.Broadcast
) -> RewriteResult:
"""
Rewrite Apply and Broadcast nodes to their stim equivalent statements.
"""

# this is an SSAValue, need it to be the actual operator
applied_op = stmt.operator.owner
assert isinstance(applied_op, op.stmts.Operator)

Check warning on line 35 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L34-L35

Added lines #L34 - L35 were not covered by tests

if isinstance(applied_op, op.stmts.Control):
return rewrite_Control(stmt)

Check warning on line 38 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L37-L38

Added lines #L37 - L38 were not covered by tests

# need to handle Control through separate means
# but we can handle X, Y, Z, H, and S here just fine
stim_1q_op = SQUIN_STIM_GATE_MAPPING.get(type(applied_op))
if stim_1q_op is None:
return RewriteResult()

Check warning on line 44 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L42-L44

Added lines #L42 - L44 were not covered by tests

address_attr = stmt.qubits.hints.get("address")
if address_attr is None:
return RewriteResult()

Check warning on line 48 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L46-L48

Added lines #L46 - L48 were not covered by tests

assert isinstance(address_attr, AddressAttribute)
qubit_idx_ssas = insert_qubit_idx_from_address(

Check warning on line 51 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L50-L51

Added lines #L50 - L51 were not covered by tests
address=address_attr, stmt_to_insert_before=stmt
)

if qubit_idx_ssas is None:
return RewriteResult()

Check warning on line 56 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L55-L56

Added lines #L55 - L56 were not covered by tests

stim_1q_stmt = stim_1q_op(targets=tuple(qubit_idx_ssas))
stmt.replace_by(stim_1q_stmt)

Check warning on line 59 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L58-L59

Added lines #L58 - L59 were not covered by tests

return RewriteResult(has_done_something=True)

Check warning on line 61 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L61

Added line #L61 was not covered by tests

def rewrite_Reset(self, reset_stmt: qubit.Reset) -> RewriteResult:
qubit_ilist_ssa = reset_stmt.qubits

Check warning on line 64 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L64

Added line #L64 was not covered by tests
# qubits are in an ilist which makes up an AddressTuple
address_attr = qubit_ilist_ssa.hints.get("address")
if address_attr is None:
return RewriteResult()

Check warning on line 68 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L66-L68

Added lines #L66 - L68 were not covered by tests

assert isinstance(address_attr, AddressAttribute)
qubit_idx_ssas = insert_qubit_idx_from_address(

Check warning on line 71 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L70-L71

Added lines #L70 - L71 were not covered by tests
address=address_attr, stmt_to_insert_before=reset_stmt
)

if qubit_idx_ssas is None:
return RewriteResult()

Check warning on line 76 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L75-L76

Added lines #L75 - L76 were not covered by tests

stim_rz_stmt = stim.collapse.stmts.RZ(targets=qubit_idx_ssas)
reset_stmt.replace_by(stim_rz_stmt)

Check warning on line 79 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L78-L79

Added lines #L78 - L79 were not covered by tests

return RewriteResult(has_done_something=True)

Check warning on line 81 in src/bloqade/squin/rewrite/qubit_to_stim.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/qubit_to_stim.py#L81

Added line #L81 was not covered by tests


# put rewrites for measure statements in separate rule, then just have to dispatch
98 changes: 98 additions & 0 deletions src/bloqade/squin/rewrite/squin_measure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# create rewrite rule name SquinMeasureToStim using kirin
from kirin import ir
from kirin.dialects import py
from kirin.rewrite.abc import RewriteRule, RewriteResult

from bloqade import stim
from bloqade.squin import wire, qubit
from bloqade.squin.rewrite.wrap_analysis import AddressAttribute
from bloqade.squin.rewrite.stim_rewrite_util import (
is_measure_result_used,
insert_qubit_idx_from_address,
)


class SquinMeasureToStim(RewriteRule):
"""
Rewrite squin measure-related statements to stim statements.
"""

def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:

match node:
case qubit.MeasureQubit() | qubit.MeasureQubitList() | wire.Measure():
return self.rewrite_Measure(node)
case qubit.MeasureAndReset() | wire.MeasureAndReset():
return self.rewrite_MeasureAndReset(node)
case _:
return RewriteResult()

Check warning on line 28 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L22-L28

Added lines #L22 - L28 were not covered by tests

def rewrite_Measure(
self, measure_stmt: qubit.MeasureQubit | qubit.MeasureQubitList | wire.Measure
) -> RewriteResult:
if is_measure_result_used(measure_stmt):
return RewriteResult()

Check warning on line 34 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L33-L34

Added lines #L33 - L34 were not covered by tests

qubit_idx_ssas = self.get_qubit_idx_ssas(measure_stmt)
if qubit_idx_ssas is None:
return RewriteResult()

Check warning on line 38 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L36-L38

Added lines #L36 - L38 were not covered by tests

prob_noise_stmt = py.constant.Constant(0.0)
stim_measure_stmt = stim.collapse.MZ(

Check warning on line 41 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L40-L41

Added lines #L40 - L41 were not covered by tests
p=prob_noise_stmt.result,
targets=qubit_idx_ssas,
)
prob_noise_stmt.insert_before(measure_stmt)
measure_stmt.replace_by(stim_measure_stmt)

Check warning on line 46 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L45-L46

Added lines #L45 - L46 were not covered by tests

return RewriteResult(has_done_something=True)

Check warning on line 48 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L48

Added line #L48 was not covered by tests

def rewrite_MeasureAndReset(
self, meas_and_reset_stmt: qubit.MeasureAndReset | wire.MeasureAndReset
) -> RewriteResult:
if not is_measure_result_used(meas_and_reset_stmt):
return RewriteResult()

Check warning on line 54 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L53-L54

Added lines #L53 - L54 were not covered by tests

qubit_idx_ssas = self.get_qubit_idx_ssas(meas_and_reset_stmt)

Check warning on line 56 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L56

Added line #L56 was not covered by tests

if qubit_idx_ssas is None:
return RewriteResult()

Check warning on line 59 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L58-L59

Added lines #L58 - L59 were not covered by tests

error_p_stmt = py.Constant(0.0)
stim_mz_stmt = stim.collapse.MZ(targets=qubit_idx_ssas, p=error_p_stmt.result)
stim_rz_stmt = stim.collapse.RZ(

Check warning on line 63 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L61-L63

Added lines #L61 - L63 were not covered by tests
targets=qubit_idx_ssas,
)

error_p_stmt.insert_before(meas_and_reset_stmt)
stim_mz_stmt.insert_before(meas_and_reset_stmt)
meas_and_reset_stmt.replace_by(stim_rz_stmt)

Check warning on line 69 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L67-L69

Added lines #L67 - L69 were not covered by tests

return RewriteResult(has_done_something=True)

Check warning on line 71 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L71

Added line #L71 was not covered by tests

def get_qubit_idx_ssas(
self, measure_stmt: qubit.MeasureQubit | qubit.MeasureQubitList | wire.Measure
) -> tuple[ir.SSAValue, ...] | None:
"""
Extract the address attribute and insert qubit indices for the given measure statement.
"""
match measure_stmt:
case qubit.MeasureQubit():
address_attr = measure_stmt.qubit.hints.get("address")
case qubit.MeasureQubitList():
address_attr = measure_stmt.qubits.hints.get("address")
case wire.Measure():
address_attr = measure_stmt.wire.hints.get("address")
case _:
return None

Check warning on line 87 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L79-L87

Added lines #L79 - L87 were not covered by tests

if address_attr is None:
return None

Check warning on line 90 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L89-L90

Added lines #L89 - L90 were not covered by tests

assert isinstance(address_attr, AddressAttribute)

Check warning on line 92 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L92

Added line #L92 was not covered by tests

qubit_idx_ssas = insert_qubit_idx_from_address(

Check warning on line 94 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L94

Added line #L94 was not covered by tests
address=address_attr, stmt_to_insert_before=measure_stmt
)

return qubit_idx_ssas

Check warning on line 98 in src/bloqade/squin/rewrite/squin_measure.py

View check run for this annotation

Codecov / codecov/patch

src/bloqade/squin/rewrite/squin_measure.py#L98

Added line #L98 was not covered by tests
Loading