bloqade-circuit 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bloqade-circuit might be problematic. Click here for more details.
- bloqade/analysis/__init__.py +0 -0
- bloqade/analysis/address/__init__.py +11 -0
- bloqade/analysis/address/analysis.py +60 -0
- bloqade/analysis/address/impls.py +228 -0
- bloqade/analysis/address/lattice.py +85 -0
- bloqade/noise/__init__.py +1 -0
- bloqade/noise/native/__init__.py +20 -0
- bloqade/noise/native/_dialect.py +3 -0
- bloqade/noise/native/_wrappers.py +34 -0
- bloqade/noise/native/model.py +347 -0
- bloqade/noise/native/rewrite.py +35 -0
- bloqade/noise/native/stmts.py +46 -0
- bloqade/pyqrack/__init__.py +18 -0
- bloqade/pyqrack/base.py +131 -0
- bloqade/pyqrack/noise/__init__.py +0 -0
- bloqade/pyqrack/noise/native.py +100 -0
- bloqade/pyqrack/qasm2/__init__.py +0 -0
- bloqade/pyqrack/qasm2/core.py +79 -0
- bloqade/pyqrack/qasm2/parallel.py +46 -0
- bloqade/pyqrack/qasm2/uop.py +247 -0
- bloqade/pyqrack/reg.py +109 -0
- bloqade/pyqrack/target.py +112 -0
- bloqade/qasm2/__init__.py +19 -0
- bloqade/qasm2/_wrappers.py +674 -0
- bloqade/qasm2/dialects/__init__.py +10 -0
- bloqade/qasm2/dialects/core/__init__.py +3 -0
- bloqade/qasm2/dialects/core/_dialect.py +3 -0
- bloqade/qasm2/dialects/core/_emit.py +68 -0
- bloqade/qasm2/dialects/core/_typeinfer.py +23 -0
- bloqade/qasm2/dialects/core/address.py +38 -0
- bloqade/qasm2/dialects/core/stmts.py +94 -0
- bloqade/qasm2/dialects/expr/__init__.py +3 -0
- bloqade/qasm2/dialects/expr/_dialect.py +3 -0
- bloqade/qasm2/dialects/expr/_emit.py +103 -0
- bloqade/qasm2/dialects/expr/_from_python.py +86 -0
- bloqade/qasm2/dialects/expr/_interp.py +75 -0
- bloqade/qasm2/dialects/expr/stmts.py +262 -0
- bloqade/qasm2/dialects/glob.py +45 -0
- bloqade/qasm2/dialects/indexing.py +64 -0
- bloqade/qasm2/dialects/inline.py +76 -0
- bloqade/qasm2/dialects/noise.py +16 -0
- bloqade/qasm2/dialects/parallel.py +110 -0
- bloqade/qasm2/dialects/uop/__init__.py +4 -0
- bloqade/qasm2/dialects/uop/_dialect.py +3 -0
- bloqade/qasm2/dialects/uop/_emit.py +211 -0
- bloqade/qasm2/dialects/uop/schedule.py +89 -0
- bloqade/qasm2/dialects/uop/stmts.py +325 -0
- bloqade/qasm2/emit/__init__.py +1 -0
- bloqade/qasm2/emit/base.py +72 -0
- bloqade/qasm2/emit/gate.py +102 -0
- bloqade/qasm2/emit/main.py +106 -0
- bloqade/qasm2/emit/target.py +165 -0
- bloqade/qasm2/glob.py +24 -0
- bloqade/qasm2/groups.py +120 -0
- bloqade/qasm2/parallel.py +48 -0
- bloqade/qasm2/parse/__init__.py +37 -0
- bloqade/qasm2/parse/ast.py +235 -0
- bloqade/qasm2/parse/build.py +289 -0
- bloqade/qasm2/parse/lowering.py +553 -0
- bloqade/qasm2/parse/parser.py +5 -0
- bloqade/qasm2/parse/print.py +293 -0
- bloqade/qasm2/parse/qasm2.lark +75 -0
- bloqade/qasm2/parse/visitor.py +16 -0
- bloqade/qasm2/parse/visitor.pyi +39 -0
- bloqade/qasm2/passes/__init__.py +5 -0
- bloqade/qasm2/passes/fold.py +94 -0
- bloqade/qasm2/passes/glob.py +119 -0
- bloqade/qasm2/passes/noise.py +61 -0
- bloqade/qasm2/passes/parallel.py +176 -0
- bloqade/qasm2/passes/py2qasm.py +63 -0
- bloqade/qasm2/passes/qasm2py.py +61 -0
- bloqade/qasm2/rewrite/__init__.py +12 -0
- bloqade/qasm2/rewrite/desugar.py +28 -0
- bloqade/qasm2/rewrite/glob.py +103 -0
- bloqade/qasm2/rewrite/heuristic_noise.py +247 -0
- bloqade/qasm2/rewrite/native_gates.py +447 -0
- bloqade/qasm2/rewrite/parallel_to_uop.py +83 -0
- bloqade/qasm2/rewrite/register.py +45 -0
- bloqade/qasm2/rewrite/uop_to_parallel.py +395 -0
- bloqade/qasm2/types.py +39 -0
- bloqade/qbraid/__init__.py +2 -0
- bloqade/qbraid/lowering.py +324 -0
- bloqade/qbraid/schema.py +252 -0
- bloqade/qbraid/simulation_result.py +99 -0
- bloqade/qbraid/target.py +86 -0
- bloqade/squin/__init__.py +2 -0
- bloqade/squin/analysis/__init__.py +0 -0
- bloqade/squin/analysis/nsites/__init__.py +8 -0
- bloqade/squin/analysis/nsites/analysis.py +52 -0
- bloqade/squin/analysis/nsites/impls.py +69 -0
- bloqade/squin/analysis/nsites/lattice.py +49 -0
- bloqade/squin/analysis/schedule.py +244 -0
- bloqade/squin/groups.py +38 -0
- bloqade/squin/op/__init__.py +132 -0
- bloqade/squin/op/_dialect.py +3 -0
- bloqade/squin/op/complex.py +6 -0
- bloqade/squin/op/stmts.py +220 -0
- bloqade/squin/op/traits.py +43 -0
- bloqade/squin/op/types.py +10 -0
- bloqade/squin/qubit.py +118 -0
- bloqade/squin/wire.py +103 -0
- bloqade/stim/__init__.py +6 -0
- bloqade/stim/_wrappers.py +186 -0
- bloqade/stim/dialects/__init__.py +5 -0
- bloqade/stim/dialects/aux/__init__.py +11 -0
- bloqade/stim/dialects/aux/_dialect.py +3 -0
- bloqade/stim/dialects/aux/emit.py +102 -0
- bloqade/stim/dialects/aux/interp.py +39 -0
- bloqade/stim/dialects/aux/lowering.py +40 -0
- bloqade/stim/dialects/aux/stmts/__init__.py +14 -0
- bloqade/stim/dialects/aux/stmts/annotate.py +47 -0
- bloqade/stim/dialects/aux/stmts/const.py +95 -0
- bloqade/stim/dialects/aux/types.py +19 -0
- bloqade/stim/dialects/collapse/__init__.py +3 -0
- bloqade/stim/dialects/collapse/_dialect.py +3 -0
- bloqade/stim/dialects/collapse/emit.py +68 -0
- bloqade/stim/dialects/collapse/stmts/__init__.py +3 -0
- bloqade/stim/dialects/collapse/stmts/measure.py +45 -0
- bloqade/stim/dialects/collapse/stmts/pp_measure.py +14 -0
- bloqade/stim/dialects/collapse/stmts/reset.py +26 -0
- bloqade/stim/dialects/gate/__init__.py +3 -0
- bloqade/stim/dialects/gate/_dialect.py +3 -0
- bloqade/stim/dialects/gate/emit.py +87 -0
- bloqade/stim/dialects/gate/stmts/__init__.py +14 -0
- bloqade/stim/dialects/gate/stmts/base.py +31 -0
- bloqade/stim/dialects/gate/stmts/clifford_1q.py +53 -0
- bloqade/stim/dialects/gate/stmts/clifford_2q.py +11 -0
- bloqade/stim/dialects/gate/stmts/control_2q.py +21 -0
- bloqade/stim/dialects/gate/stmts/pp.py +15 -0
- bloqade/stim/dialects/noise/__init__.py +3 -0
- bloqade/stim/dialects/noise/_dialect.py +3 -0
- bloqade/stim/dialects/noise/emit.py +66 -0
- bloqade/stim/dialects/noise/stmts.py +77 -0
- bloqade/stim/emit/__init__.py +1 -0
- bloqade/stim/emit/stim.py +54 -0
- bloqade/stim/groups.py +26 -0
- bloqade/test_utils.py +35 -0
- bloqade/types.py +24 -0
- bloqade/visual/__init__.py +1 -0
- bloqade/visual/animation/__init__.py +0 -0
- bloqade/visual/animation/animate.py +267 -0
- bloqade/visual/animation/base.py +346 -0
- bloqade/visual/animation/gate_event.py +24 -0
- bloqade/visual/animation/runtime/__init__.py +0 -0
- bloqade/visual/animation/runtime/aod.py +36 -0
- bloqade/visual/animation/runtime/atoms.py +55 -0
- bloqade/visual/animation/runtime/ppoly.py +50 -0
- bloqade/visual/animation/runtime/qpustate.py +119 -0
- bloqade/visual/animation/runtime/utils.py +43 -0
- bloqade_circuit-0.1.0.dist-info/METADATA +70 -0
- bloqade_circuit-0.1.0.dist-info/RECORD +153 -0
- bloqade_circuit-0.1.0.dist-info/WHEEL +4 -0
- bloqade_circuit-0.1.0.dist-info/licenses/LICENSE +234 -0
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from . import impls as impls
|
|
2
|
+
from .lattice import (
|
|
3
|
+
Address as Address,
|
|
4
|
+
NotQubit as NotQubit,
|
|
5
|
+
AddressReg as AddressReg,
|
|
6
|
+
AnyAddress as AnyAddress,
|
|
7
|
+
AddressWire as AddressWire,
|
|
8
|
+
AddressQubit as AddressQubit,
|
|
9
|
+
AddressTuple as AddressTuple,
|
|
10
|
+
)
|
|
11
|
+
from .analysis import AddressAnalysis as AddressAnalysis
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from typing import TypeVar
|
|
2
|
+
from dataclasses import field
|
|
3
|
+
|
|
4
|
+
from kirin import ir, interp
|
|
5
|
+
from kirin.analysis import Forward, const
|
|
6
|
+
from kirin.analysis.forward import ForwardFrame
|
|
7
|
+
|
|
8
|
+
from bloqade.types import QubitType
|
|
9
|
+
|
|
10
|
+
from .lattice import Address
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AddressAnalysis(Forward[Address]):
|
|
14
|
+
"""
|
|
15
|
+
This analysis pass can be used to track the global addresses of qubits and wires.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
keys = ["qubit.address"]
|
|
19
|
+
lattice = Address
|
|
20
|
+
next_address: int = field(init=False)
|
|
21
|
+
|
|
22
|
+
def initialize(self):
|
|
23
|
+
super().initialize()
|
|
24
|
+
self.next_address: int = 0
|
|
25
|
+
return self
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def qubit_count(self) -> int:
|
|
29
|
+
"""Total number of qubits found by the analysis."""
|
|
30
|
+
return self.next_address
|
|
31
|
+
|
|
32
|
+
T = TypeVar("T")
|
|
33
|
+
|
|
34
|
+
def get_const_value(self, typ: type[T], value: ir.SSAValue) -> T:
|
|
35
|
+
if isinstance(hint := value.hints.get("const"), const.Value):
|
|
36
|
+
data = hint.data
|
|
37
|
+
if isinstance(data, typ):
|
|
38
|
+
return hint.data
|
|
39
|
+
raise interp.InterpreterError(
|
|
40
|
+
f"Expected constant value <type = {typ}>, got {data}"
|
|
41
|
+
)
|
|
42
|
+
raise interp.InterpreterError(
|
|
43
|
+
f"Expected constant value <type = {typ}>, got {value}"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def eval_stmt_fallback(
|
|
47
|
+
self, frame: ForwardFrame[Address], stmt: ir.Statement
|
|
48
|
+
) -> tuple[Address, ...] | interp.SpecialValue[Address]:
|
|
49
|
+
return tuple(
|
|
50
|
+
(
|
|
51
|
+
self.lattice.top()
|
|
52
|
+
if result.type.is_subseteq(QubitType)
|
|
53
|
+
else self.lattice.bottom()
|
|
54
|
+
)
|
|
55
|
+
for result in stmt.results
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def run_method(self, method: ir.Method, args: tuple[Address, ...]):
|
|
59
|
+
# NOTE: we do not support dynamic calls here, thus no need to propagate method object
|
|
60
|
+
return self.run_callable(method.code, (self.lattice.bottom(),) + args)
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""
|
|
2
|
+
qubit.address method table for a few builtin dialects.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from kirin import interp
|
|
6
|
+
from kirin.analysis import ForwardFrame, const
|
|
7
|
+
from kirin.dialects import cf, py, scf, func, ilist
|
|
8
|
+
|
|
9
|
+
from bloqade import squin
|
|
10
|
+
|
|
11
|
+
from .lattice import (
|
|
12
|
+
Address,
|
|
13
|
+
NotQubit,
|
|
14
|
+
AddressReg,
|
|
15
|
+
AddressWire,
|
|
16
|
+
AddressQubit,
|
|
17
|
+
AddressTuple,
|
|
18
|
+
)
|
|
19
|
+
from .analysis import AddressAnalysis
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@py.binop.dialect.register(key="qubit.address")
|
|
23
|
+
class PyBinOp(interp.MethodTable):
|
|
24
|
+
|
|
25
|
+
@interp.impl(py.Add)
|
|
26
|
+
def add(self, interp: AddressAnalysis, frame: interp.Frame, stmt: py.Add):
|
|
27
|
+
lhs = frame.get(stmt.lhs)
|
|
28
|
+
rhs = frame.get(stmt.rhs)
|
|
29
|
+
|
|
30
|
+
if isinstance(lhs, AddressTuple) and isinstance(rhs, AddressTuple):
|
|
31
|
+
return (AddressTuple(data=lhs.data + rhs.data),)
|
|
32
|
+
else:
|
|
33
|
+
return (NotQubit(),)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@py.tuple.dialect.register(key="qubit.address")
|
|
37
|
+
class PyTuple(interp.MethodTable):
|
|
38
|
+
@interp.impl(py.tuple.New)
|
|
39
|
+
def new_tuple(
|
|
40
|
+
self,
|
|
41
|
+
interp: AddressAnalysis,
|
|
42
|
+
frame: interp.Frame,
|
|
43
|
+
stmt: py.tuple.New,
|
|
44
|
+
):
|
|
45
|
+
return (AddressTuple(frame.get_values(stmt.args)),)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@ilist.dialect.register(key="qubit.address")
|
|
49
|
+
class IList(interp.MethodTable):
|
|
50
|
+
@interp.impl(ilist.New)
|
|
51
|
+
def new_ilist(
|
|
52
|
+
self,
|
|
53
|
+
interp: AddressAnalysis,
|
|
54
|
+
frame: interp.Frame,
|
|
55
|
+
stmt: ilist.New,
|
|
56
|
+
):
|
|
57
|
+
return (AddressTuple(frame.get_values(stmt.values)),)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@py.list.dialect.register(key="qubit.address")
|
|
61
|
+
class PyList(interp.MethodTable):
|
|
62
|
+
@interp.impl(py.list.New)
|
|
63
|
+
def new_ilist(
|
|
64
|
+
self,
|
|
65
|
+
interp: AddressAnalysis,
|
|
66
|
+
frame: interp.Frame,
|
|
67
|
+
stmt: py.list.New,
|
|
68
|
+
):
|
|
69
|
+
return (AddressTuple(frame.get_values(stmt.args)),)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@py.indexing.dialect.register(key="qubit.address")
|
|
73
|
+
class PyIndexing(interp.MethodTable):
|
|
74
|
+
@interp.impl(py.GetItem)
|
|
75
|
+
def getitem(self, interp: AddressAnalysis, frame: interp.Frame, stmt: py.GetItem):
|
|
76
|
+
# Integer index into the thing being indexed
|
|
77
|
+
idx = interp.get_const_value(int, stmt.index)
|
|
78
|
+
# The object being indexed into
|
|
79
|
+
obj = frame.get(stmt.obj)
|
|
80
|
+
# The `data` attributes holds onto other Address types
|
|
81
|
+
# so we just extract that here
|
|
82
|
+
if isinstance(obj, AddressTuple):
|
|
83
|
+
return (obj.data[idx],)
|
|
84
|
+
# an AddressReg is guaranteed to just have some sequence
|
|
85
|
+
# of integers which is directly pluggable to AddressQubit
|
|
86
|
+
elif isinstance(obj, AddressReg):
|
|
87
|
+
return (AddressQubit(obj.data[idx]),)
|
|
88
|
+
else:
|
|
89
|
+
return (NotQubit(),)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@py.assign.dialect.register(key="qubit.address")
|
|
93
|
+
class PyAssign(interp.MethodTable):
|
|
94
|
+
@interp.impl(py.Alias)
|
|
95
|
+
def alias(self, interp: AddressAnalysis, frame: interp.Frame, stmt: py.Alias):
|
|
96
|
+
return (frame.get(stmt.value),)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@func.dialect.register(key="qubit.address")
|
|
100
|
+
class Func(interp.MethodTable):
|
|
101
|
+
@interp.impl(func.Return)
|
|
102
|
+
def return_(self, _: AddressAnalysis, frame: interp.Frame, stmt: func.Return):
|
|
103
|
+
return interp.ReturnValue(frame.get(stmt.value))
|
|
104
|
+
|
|
105
|
+
# TODO: replace with the generic implementation
|
|
106
|
+
@interp.impl(func.Invoke)
|
|
107
|
+
def invoke(self, interp_: AddressAnalysis, frame: interp.Frame, stmt: func.Invoke):
|
|
108
|
+
_, ret = interp_.run_method(
|
|
109
|
+
stmt.callee,
|
|
110
|
+
interp_.permute_values(
|
|
111
|
+
stmt.callee.arg_names, frame.get_values(stmt.inputs), stmt.kwargs
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
return (ret,)
|
|
115
|
+
|
|
116
|
+
# TODO: support lambda?
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@cf.dialect.register(key="qubit.address")
|
|
120
|
+
class Cf(cf.typeinfer.TypeInfer):
|
|
121
|
+
# NOTE: cf just re-use the type infer method table
|
|
122
|
+
# it's the same process as type infer.
|
|
123
|
+
pass
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@scf.dialect.register(key="qubit.address")
|
|
127
|
+
class Scf(scf.absint.Methods):
|
|
128
|
+
|
|
129
|
+
@interp.impl(scf.For)
|
|
130
|
+
def for_loop(
|
|
131
|
+
self,
|
|
132
|
+
interp_: AddressAnalysis,
|
|
133
|
+
frame: ForwardFrame[Address],
|
|
134
|
+
stmt: scf.For,
|
|
135
|
+
):
|
|
136
|
+
if not isinstance(hint := stmt.iterable.hints.get("const"), const.Value):
|
|
137
|
+
return interp_.eval_stmt_fallback(frame, stmt)
|
|
138
|
+
|
|
139
|
+
iterable = hint.data
|
|
140
|
+
loop_vars = frame.get_values(stmt.initializers)
|
|
141
|
+
body_block = stmt.body.blocks[0]
|
|
142
|
+
block_args = body_block.args
|
|
143
|
+
|
|
144
|
+
# NOTE: we need to actually run iteration in case there are
|
|
145
|
+
# new allocations/re-assign in the loop body.
|
|
146
|
+
for _ in iterable:
|
|
147
|
+
with interp_.state.new_frame(interp_.new_frame(stmt)) as body_frame:
|
|
148
|
+
body_frame.entries.update(frame.entries)
|
|
149
|
+
body_frame.set_values(
|
|
150
|
+
block_args,
|
|
151
|
+
(NotQubit(),) + loop_vars,
|
|
152
|
+
)
|
|
153
|
+
loop_vars = interp_.run_ssacfg_region(body_frame, stmt.body)
|
|
154
|
+
|
|
155
|
+
if loop_vars is None:
|
|
156
|
+
loop_vars = ()
|
|
157
|
+
elif isinstance(loop_vars, interp.ReturnValue):
|
|
158
|
+
return loop_vars
|
|
159
|
+
|
|
160
|
+
if isinstance(body_block.last_stmt, func.Return):
|
|
161
|
+
frame.worklist.append(interp.Successor(body_block, NotQubit(), *loop_vars))
|
|
162
|
+
return # if terminate is Return, there is no result
|
|
163
|
+
|
|
164
|
+
return loop_vars
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# Address lattice elements we can work with:
|
|
168
|
+
## NotQubit (bottom), AnyAddress (top)
|
|
169
|
+
|
|
170
|
+
## AddressTuple -> data: tuple[Address, ...]
|
|
171
|
+
### Recursive type, could contain itself or other variants
|
|
172
|
+
### This pops up in cases where you can have an IList/Tuple
|
|
173
|
+
### That contains elements that could be other Address types
|
|
174
|
+
|
|
175
|
+
## AddressReg -> data: Sequence[int]
|
|
176
|
+
### specific to creation of a register of qubits
|
|
177
|
+
|
|
178
|
+
## AddressQubit -> data: int
|
|
179
|
+
### Base qubit address type
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@squin.wire.dialect.register(key="qubit.address")
|
|
183
|
+
class SquinWireMethodTable(interp.MethodTable):
|
|
184
|
+
|
|
185
|
+
@interp.impl(squin.wire.Unwrap)
|
|
186
|
+
def unwrap(
|
|
187
|
+
self,
|
|
188
|
+
interp_: AddressAnalysis,
|
|
189
|
+
frame: ForwardFrame[Address],
|
|
190
|
+
stmt: squin.wire.Unwrap,
|
|
191
|
+
):
|
|
192
|
+
|
|
193
|
+
origin_qubit = frame.get(stmt.qubit)
|
|
194
|
+
|
|
195
|
+
return (AddressWire(origin_qubit=origin_qubit),)
|
|
196
|
+
|
|
197
|
+
@interp.impl(squin.wire.Apply)
|
|
198
|
+
def apply(
|
|
199
|
+
self,
|
|
200
|
+
interp_: AddressAnalysis,
|
|
201
|
+
frame: ForwardFrame[Address],
|
|
202
|
+
stmt: squin.wire.Apply,
|
|
203
|
+
):
|
|
204
|
+
|
|
205
|
+
origin_qubits = tuple(
|
|
206
|
+
[frame.get(input_elem).origin_qubit for input_elem in stmt.inputs]
|
|
207
|
+
)
|
|
208
|
+
new_address_wires = tuple(
|
|
209
|
+
[AddressWire(origin_qubit=origin_qubit) for origin_qubit in origin_qubits]
|
|
210
|
+
)
|
|
211
|
+
return new_address_wires
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@squin.qubit.dialect.register(key="qubit.address")
|
|
215
|
+
class SquinQubitMethodTable(interp.MethodTable):
|
|
216
|
+
|
|
217
|
+
# This can be treated like a QRegNew impl
|
|
218
|
+
@interp.impl(squin.qubit.New)
|
|
219
|
+
def new(
|
|
220
|
+
self,
|
|
221
|
+
interp_: AddressAnalysis,
|
|
222
|
+
frame: ForwardFrame[Address],
|
|
223
|
+
stmt: squin.qubit.New,
|
|
224
|
+
):
|
|
225
|
+
n_qubits = interp_.get_const_value(int, stmt.n_qubits)
|
|
226
|
+
addr = AddressReg(range(interp_.next_address, interp_.next_address + n_qubits))
|
|
227
|
+
interp_.next_address += n_qubits
|
|
228
|
+
return (addr,)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from typing import Sequence, final
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
from kirin.lattice import (
|
|
5
|
+
SingletonMeta,
|
|
6
|
+
BoundedLattice,
|
|
7
|
+
SimpleJoinMixin,
|
|
8
|
+
SimpleMeetMixin,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class Address(
|
|
14
|
+
SimpleJoinMixin["Address"],
|
|
15
|
+
SimpleMeetMixin["Address"],
|
|
16
|
+
BoundedLattice["Address"],
|
|
17
|
+
):
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def bottom(cls) -> "Address":
|
|
21
|
+
return NotQubit()
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def top(cls) -> "Address":
|
|
25
|
+
return AnyAddress()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@final
|
|
29
|
+
@dataclass
|
|
30
|
+
class NotQubit(Address, metaclass=SingletonMeta):
|
|
31
|
+
|
|
32
|
+
def is_subseteq(self, other: Address) -> bool:
|
|
33
|
+
return True
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@final
|
|
37
|
+
@dataclass
|
|
38
|
+
class AnyAddress(Address, metaclass=SingletonMeta):
|
|
39
|
+
|
|
40
|
+
def is_subseteq(self, other: Address) -> bool:
|
|
41
|
+
return isinstance(other, AnyAddress)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@final
|
|
45
|
+
@dataclass
|
|
46
|
+
class AddressTuple(Address):
|
|
47
|
+
data: tuple[Address, ...]
|
|
48
|
+
|
|
49
|
+
def is_subseteq(self, other: Address) -> bool:
|
|
50
|
+
if isinstance(other, AddressTuple):
|
|
51
|
+
return all(a.is_subseteq(b) for a, b in zip(self.data, other.data))
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@final
|
|
56
|
+
@dataclass
|
|
57
|
+
class AddressReg(Address):
|
|
58
|
+
data: Sequence[int]
|
|
59
|
+
|
|
60
|
+
def is_subseteq(self, other: Address) -> bool:
|
|
61
|
+
if isinstance(other, AddressReg):
|
|
62
|
+
return self.data == other.data
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@final
|
|
67
|
+
@dataclass
|
|
68
|
+
class AddressQubit(Address):
|
|
69
|
+
data: int
|
|
70
|
+
|
|
71
|
+
def is_subseteq(self, other: Address) -> bool:
|
|
72
|
+
if isinstance(other, AddressQubit):
|
|
73
|
+
return self.data == other.data
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@final
|
|
78
|
+
@dataclass
|
|
79
|
+
class AddressWire(Address):
|
|
80
|
+
origin_qubit: AddressQubit
|
|
81
|
+
|
|
82
|
+
def is_subseteq(self, other: Address) -> bool:
|
|
83
|
+
if isinstance(other, AddressWire):
|
|
84
|
+
return self.origin_qubit == self.origin_qubit
|
|
85
|
+
return False
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from . import native as native
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""NOTE: This module is not guaranteed to be supported long-term in bloqade. We will be
|
|
2
|
+
moving towards a more general approach to noise modeling in the future."""
|
|
3
|
+
|
|
4
|
+
from .model import (
|
|
5
|
+
GateNoiseParams as GateNoiseParams,
|
|
6
|
+
TwoRowZoneModel as TwoRowZoneModel,
|
|
7
|
+
MoveNoiseModelABC as MoveNoiseModelABC,
|
|
8
|
+
)
|
|
9
|
+
from .stmts import (
|
|
10
|
+
PauliChannel as PauliChannel,
|
|
11
|
+
CZPauliChannel as CZPauliChannel,
|
|
12
|
+
AtomLossChannel as AtomLossChannel,
|
|
13
|
+
)
|
|
14
|
+
from .rewrite import RemoveNoisePass as RemoveNoisePass
|
|
15
|
+
from ._dialect import dialect as dialect
|
|
16
|
+
from ._wrappers import (
|
|
17
|
+
pauli_channel as pauli_channel,
|
|
18
|
+
cz_pauli_channel as cz_pauli_channel,
|
|
19
|
+
atom_loss_channel as atom_loss_channel,
|
|
20
|
+
)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from kirin.dialects import ilist
|
|
4
|
+
from kirin.lowering import wraps
|
|
5
|
+
|
|
6
|
+
from bloqade.noise import native
|
|
7
|
+
from bloqade.qasm2.types import Qubit
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@wraps(native.AtomLossChannel)
|
|
11
|
+
def atom_loss_channel(
|
|
12
|
+
qargs: ilist.IList[Qubit, Any] | list, *, prob: float
|
|
13
|
+
) -> None: ...
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@wraps(native.PauliChannel)
|
|
17
|
+
def pauli_channel(
|
|
18
|
+
qargs: ilist.IList[Qubit, Any] | list, *, px: float, py: float, pz: float
|
|
19
|
+
) -> None: ...
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@wraps(native.CZPauliChannel)
|
|
23
|
+
def cz_pauli_channel(
|
|
24
|
+
ctrls: ilist.IList[Qubit, Any] | list,
|
|
25
|
+
qarg2: ilist.IList[Qubit, Any] | list,
|
|
26
|
+
*,
|
|
27
|
+
px_ctrl: float,
|
|
28
|
+
py_ctrl: float,
|
|
29
|
+
pz_ctrl: float,
|
|
30
|
+
px_qarg: float,
|
|
31
|
+
py_qarg: float,
|
|
32
|
+
pz_qarg: float,
|
|
33
|
+
paired: bool,
|
|
34
|
+
) -> None: ...
|