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.

Files changed (153) hide show
  1. bloqade/analysis/__init__.py +0 -0
  2. bloqade/analysis/address/__init__.py +11 -0
  3. bloqade/analysis/address/analysis.py +60 -0
  4. bloqade/analysis/address/impls.py +228 -0
  5. bloqade/analysis/address/lattice.py +85 -0
  6. bloqade/noise/__init__.py +1 -0
  7. bloqade/noise/native/__init__.py +20 -0
  8. bloqade/noise/native/_dialect.py +3 -0
  9. bloqade/noise/native/_wrappers.py +34 -0
  10. bloqade/noise/native/model.py +347 -0
  11. bloqade/noise/native/rewrite.py +35 -0
  12. bloqade/noise/native/stmts.py +46 -0
  13. bloqade/pyqrack/__init__.py +18 -0
  14. bloqade/pyqrack/base.py +131 -0
  15. bloqade/pyqrack/noise/__init__.py +0 -0
  16. bloqade/pyqrack/noise/native.py +100 -0
  17. bloqade/pyqrack/qasm2/__init__.py +0 -0
  18. bloqade/pyqrack/qasm2/core.py +79 -0
  19. bloqade/pyqrack/qasm2/parallel.py +46 -0
  20. bloqade/pyqrack/qasm2/uop.py +247 -0
  21. bloqade/pyqrack/reg.py +109 -0
  22. bloqade/pyqrack/target.py +112 -0
  23. bloqade/qasm2/__init__.py +19 -0
  24. bloqade/qasm2/_wrappers.py +674 -0
  25. bloqade/qasm2/dialects/__init__.py +10 -0
  26. bloqade/qasm2/dialects/core/__init__.py +3 -0
  27. bloqade/qasm2/dialects/core/_dialect.py +3 -0
  28. bloqade/qasm2/dialects/core/_emit.py +68 -0
  29. bloqade/qasm2/dialects/core/_typeinfer.py +23 -0
  30. bloqade/qasm2/dialects/core/address.py +38 -0
  31. bloqade/qasm2/dialects/core/stmts.py +94 -0
  32. bloqade/qasm2/dialects/expr/__init__.py +3 -0
  33. bloqade/qasm2/dialects/expr/_dialect.py +3 -0
  34. bloqade/qasm2/dialects/expr/_emit.py +103 -0
  35. bloqade/qasm2/dialects/expr/_from_python.py +86 -0
  36. bloqade/qasm2/dialects/expr/_interp.py +75 -0
  37. bloqade/qasm2/dialects/expr/stmts.py +262 -0
  38. bloqade/qasm2/dialects/glob.py +45 -0
  39. bloqade/qasm2/dialects/indexing.py +64 -0
  40. bloqade/qasm2/dialects/inline.py +76 -0
  41. bloqade/qasm2/dialects/noise.py +16 -0
  42. bloqade/qasm2/dialects/parallel.py +110 -0
  43. bloqade/qasm2/dialects/uop/__init__.py +4 -0
  44. bloqade/qasm2/dialects/uop/_dialect.py +3 -0
  45. bloqade/qasm2/dialects/uop/_emit.py +211 -0
  46. bloqade/qasm2/dialects/uop/schedule.py +89 -0
  47. bloqade/qasm2/dialects/uop/stmts.py +325 -0
  48. bloqade/qasm2/emit/__init__.py +1 -0
  49. bloqade/qasm2/emit/base.py +72 -0
  50. bloqade/qasm2/emit/gate.py +102 -0
  51. bloqade/qasm2/emit/main.py +106 -0
  52. bloqade/qasm2/emit/target.py +165 -0
  53. bloqade/qasm2/glob.py +24 -0
  54. bloqade/qasm2/groups.py +120 -0
  55. bloqade/qasm2/parallel.py +48 -0
  56. bloqade/qasm2/parse/__init__.py +37 -0
  57. bloqade/qasm2/parse/ast.py +235 -0
  58. bloqade/qasm2/parse/build.py +289 -0
  59. bloqade/qasm2/parse/lowering.py +553 -0
  60. bloqade/qasm2/parse/parser.py +5 -0
  61. bloqade/qasm2/parse/print.py +293 -0
  62. bloqade/qasm2/parse/qasm2.lark +75 -0
  63. bloqade/qasm2/parse/visitor.py +16 -0
  64. bloqade/qasm2/parse/visitor.pyi +39 -0
  65. bloqade/qasm2/passes/__init__.py +5 -0
  66. bloqade/qasm2/passes/fold.py +94 -0
  67. bloqade/qasm2/passes/glob.py +119 -0
  68. bloqade/qasm2/passes/noise.py +61 -0
  69. bloqade/qasm2/passes/parallel.py +176 -0
  70. bloqade/qasm2/passes/py2qasm.py +63 -0
  71. bloqade/qasm2/passes/qasm2py.py +61 -0
  72. bloqade/qasm2/rewrite/__init__.py +12 -0
  73. bloqade/qasm2/rewrite/desugar.py +28 -0
  74. bloqade/qasm2/rewrite/glob.py +103 -0
  75. bloqade/qasm2/rewrite/heuristic_noise.py +247 -0
  76. bloqade/qasm2/rewrite/native_gates.py +447 -0
  77. bloqade/qasm2/rewrite/parallel_to_uop.py +83 -0
  78. bloqade/qasm2/rewrite/register.py +45 -0
  79. bloqade/qasm2/rewrite/uop_to_parallel.py +395 -0
  80. bloqade/qasm2/types.py +39 -0
  81. bloqade/qbraid/__init__.py +2 -0
  82. bloqade/qbraid/lowering.py +324 -0
  83. bloqade/qbraid/schema.py +252 -0
  84. bloqade/qbraid/simulation_result.py +99 -0
  85. bloqade/qbraid/target.py +86 -0
  86. bloqade/squin/__init__.py +2 -0
  87. bloqade/squin/analysis/__init__.py +0 -0
  88. bloqade/squin/analysis/nsites/__init__.py +8 -0
  89. bloqade/squin/analysis/nsites/analysis.py +52 -0
  90. bloqade/squin/analysis/nsites/impls.py +69 -0
  91. bloqade/squin/analysis/nsites/lattice.py +49 -0
  92. bloqade/squin/analysis/schedule.py +244 -0
  93. bloqade/squin/groups.py +38 -0
  94. bloqade/squin/op/__init__.py +132 -0
  95. bloqade/squin/op/_dialect.py +3 -0
  96. bloqade/squin/op/complex.py +6 -0
  97. bloqade/squin/op/stmts.py +220 -0
  98. bloqade/squin/op/traits.py +43 -0
  99. bloqade/squin/op/types.py +10 -0
  100. bloqade/squin/qubit.py +118 -0
  101. bloqade/squin/wire.py +103 -0
  102. bloqade/stim/__init__.py +6 -0
  103. bloqade/stim/_wrappers.py +186 -0
  104. bloqade/stim/dialects/__init__.py +5 -0
  105. bloqade/stim/dialects/aux/__init__.py +11 -0
  106. bloqade/stim/dialects/aux/_dialect.py +3 -0
  107. bloqade/stim/dialects/aux/emit.py +102 -0
  108. bloqade/stim/dialects/aux/interp.py +39 -0
  109. bloqade/stim/dialects/aux/lowering.py +40 -0
  110. bloqade/stim/dialects/aux/stmts/__init__.py +14 -0
  111. bloqade/stim/dialects/aux/stmts/annotate.py +47 -0
  112. bloqade/stim/dialects/aux/stmts/const.py +95 -0
  113. bloqade/stim/dialects/aux/types.py +19 -0
  114. bloqade/stim/dialects/collapse/__init__.py +3 -0
  115. bloqade/stim/dialects/collapse/_dialect.py +3 -0
  116. bloqade/stim/dialects/collapse/emit.py +68 -0
  117. bloqade/stim/dialects/collapse/stmts/__init__.py +3 -0
  118. bloqade/stim/dialects/collapse/stmts/measure.py +45 -0
  119. bloqade/stim/dialects/collapse/stmts/pp_measure.py +14 -0
  120. bloqade/stim/dialects/collapse/stmts/reset.py +26 -0
  121. bloqade/stim/dialects/gate/__init__.py +3 -0
  122. bloqade/stim/dialects/gate/_dialect.py +3 -0
  123. bloqade/stim/dialects/gate/emit.py +87 -0
  124. bloqade/stim/dialects/gate/stmts/__init__.py +14 -0
  125. bloqade/stim/dialects/gate/stmts/base.py +31 -0
  126. bloqade/stim/dialects/gate/stmts/clifford_1q.py +53 -0
  127. bloqade/stim/dialects/gate/stmts/clifford_2q.py +11 -0
  128. bloqade/stim/dialects/gate/stmts/control_2q.py +21 -0
  129. bloqade/stim/dialects/gate/stmts/pp.py +15 -0
  130. bloqade/stim/dialects/noise/__init__.py +3 -0
  131. bloqade/stim/dialects/noise/_dialect.py +3 -0
  132. bloqade/stim/dialects/noise/emit.py +66 -0
  133. bloqade/stim/dialects/noise/stmts.py +77 -0
  134. bloqade/stim/emit/__init__.py +1 -0
  135. bloqade/stim/emit/stim.py +54 -0
  136. bloqade/stim/groups.py +26 -0
  137. bloqade/test_utils.py +35 -0
  138. bloqade/types.py +24 -0
  139. bloqade/visual/__init__.py +1 -0
  140. bloqade/visual/animation/__init__.py +0 -0
  141. bloqade/visual/animation/animate.py +267 -0
  142. bloqade/visual/animation/base.py +346 -0
  143. bloqade/visual/animation/gate_event.py +24 -0
  144. bloqade/visual/animation/runtime/__init__.py +0 -0
  145. bloqade/visual/animation/runtime/aod.py +36 -0
  146. bloqade/visual/animation/runtime/atoms.py +55 -0
  147. bloqade/visual/animation/runtime/ppoly.py +50 -0
  148. bloqade/visual/animation/runtime/qpustate.py +119 -0
  149. bloqade/visual/animation/runtime/utils.py +43 -0
  150. bloqade_circuit-0.1.0.dist-info/METADATA +70 -0
  151. bloqade_circuit-0.1.0.dist-info/RECORD +153 -0
  152. bloqade_circuit-0.1.0.dist-info/WHEEL +4 -0
  153. bloqade_circuit-0.1.0.dist-info/licenses/LICENSE +234 -0
@@ -0,0 +1,220 @@
1
+ from kirin import ir, types, lowering
2
+ from kirin.decl import info, statement
3
+
4
+ from .types import OpType
5
+ from .traits import Unitary, HasSites, FixedSites, MaybeUnitary
6
+ from .complex import Complex
7
+ from ._dialect import dialect
8
+
9
+
10
+ @statement
11
+ class Operator(ir.Statement):
12
+ pass
13
+
14
+
15
+ @statement
16
+ class PrimitiveOp(Operator):
17
+ pass
18
+
19
+
20
+ @statement
21
+ class CompositeOp(Operator):
22
+ pass
23
+
24
+
25
+ @statement
26
+ class BinaryOp(CompositeOp):
27
+ lhs: ir.SSAValue = info.argument(OpType)
28
+ rhs: ir.SSAValue = info.argument(OpType)
29
+ result: ir.ResultValue = info.result(OpType)
30
+
31
+
32
+ @statement(dialect=dialect)
33
+ class Kron(BinaryOp):
34
+ traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
35
+ is_unitary: bool = info.attribute(default=False)
36
+
37
+
38
+ @statement(dialect=dialect)
39
+ class Mult(BinaryOp):
40
+ traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
41
+ is_unitary: bool = info.attribute(default=False)
42
+
43
+
44
+ @statement(dialect=dialect)
45
+ class Adjoint(CompositeOp):
46
+ traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
47
+ is_unitary: bool = info.attribute(default=False)
48
+ op: ir.SSAValue = info.argument(OpType)
49
+ result: ir.ResultValue = info.result(OpType)
50
+
51
+
52
+ @statement(dialect=dialect)
53
+ class Scale(CompositeOp):
54
+ traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
55
+ is_unitary: bool = info.attribute(default=False)
56
+ op: ir.SSAValue = info.argument(OpType)
57
+ factor: ir.SSAValue = info.argument(Complex)
58
+ result: ir.ResultValue = info.result(OpType)
59
+
60
+
61
+ @statement(dialect=dialect)
62
+ class Control(CompositeOp):
63
+ traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
64
+ is_unitary: bool = info.attribute(default=False)
65
+ op: ir.SSAValue = info.argument(OpType)
66
+ n_controls: int = info.attribute()
67
+ result: ir.ResultValue = info.result(OpType)
68
+
69
+
70
+ @statement(dialect=dialect)
71
+ class Rot(CompositeOp):
72
+ traits = frozenset({ir.Pure(), lowering.FromPythonCall(), Unitary()})
73
+ axis: ir.SSAValue = info.argument(OpType)
74
+ angle: ir.SSAValue = info.argument(types.Float)
75
+ result: ir.ResultValue = info.result(OpType)
76
+
77
+
78
+ @statement(dialect=dialect)
79
+ class Identity(CompositeOp):
80
+ traits = frozenset({ir.Pure(), lowering.FromPythonCall(), Unitary(), HasSites()})
81
+ sites: int = info.attribute()
82
+ result: ir.ResultValue = info.result(OpType)
83
+
84
+
85
+ @statement
86
+ class ConstantOp(PrimitiveOp):
87
+ traits = frozenset(
88
+ {ir.Pure(), lowering.FromPythonCall(), ir.ConstantLike(), FixedSites(1)}
89
+ )
90
+ result: ir.ResultValue = info.result(OpType)
91
+
92
+
93
+ @statement
94
+ class ConstantUnitary(ConstantOp):
95
+ traits = frozenset(
96
+ {
97
+ ir.Pure(),
98
+ lowering.FromPythonCall(),
99
+ ir.ConstantLike(),
100
+ Unitary(),
101
+ FixedSites(1),
102
+ }
103
+ )
104
+
105
+
106
+ @statement(dialect=dialect)
107
+ class PhaseOp(PrimitiveOp):
108
+ """
109
+ A phase operator.
110
+
111
+ $$
112
+ PhaseOp(theta) = e^{i \theta} I
113
+ $$
114
+ """
115
+
116
+ traits = frozenset({ir.Pure(), lowering.FromPythonCall(), Unitary(), FixedSites(1)})
117
+ theta: ir.SSAValue = info.argument(types.Float)
118
+ result: ir.ResultValue = info.result(OpType)
119
+
120
+
121
+ @statement(dialect=dialect)
122
+ class ShiftOp(PrimitiveOp):
123
+ """
124
+ A phase shift operator.
125
+
126
+ $$
127
+ Shift(theta) = \\begin{bmatrix} 1 & 0 \\\\ 0 & e^{i \\theta} \\end{bmatrix}
128
+ $$
129
+ """
130
+
131
+ traits = frozenset({ir.Pure(), lowering.FromPythonCall(), Unitary(), FixedSites(1)})
132
+ theta: ir.SSAValue = info.argument(types.Float)
133
+ result: ir.ResultValue = info.result(OpType)
134
+
135
+
136
+ @statement
137
+ class PauliOp(ConstantUnitary):
138
+ pass
139
+
140
+
141
+ @statement(dialect=dialect)
142
+ class X(PauliOp):
143
+ pass
144
+
145
+
146
+ @statement(dialect=dialect)
147
+ class Y(PauliOp):
148
+ pass
149
+
150
+
151
+ @statement(dialect=dialect)
152
+ class Z(PauliOp):
153
+ pass
154
+
155
+
156
+ @statement(dialect=dialect)
157
+ class H(ConstantUnitary):
158
+ pass
159
+
160
+
161
+ @statement(dialect=dialect)
162
+ class S(ConstantUnitary):
163
+ pass
164
+
165
+
166
+ @statement(dialect=dialect)
167
+ class T(ConstantUnitary):
168
+ pass
169
+
170
+
171
+ @statement(dialect=dialect)
172
+ class P0(ConstantOp):
173
+ """
174
+ The $P_0$ projection operator.
175
+
176
+ $$
177
+ P0 = \\begin{bmatrix} 1 & 0 \\\\ 0 & 0 \\end{bmatrix}
178
+ $$
179
+ """
180
+
181
+ pass
182
+
183
+
184
+ @statement(dialect=dialect)
185
+ class P1(ConstantOp):
186
+ """
187
+ The $P_1$ projection operator.
188
+
189
+ $$
190
+ P1 = \\begin{bmatrix} 0 & 0 \\\\ 0 & 1 \\end{bmatrix}
191
+ $$
192
+ """
193
+
194
+ pass
195
+
196
+
197
+ @statement(dialect=dialect)
198
+ class Sn(ConstantOp):
199
+ """
200
+ $S_{-}$ operator.
201
+
202
+ $$
203
+ Sn = \\frac{1}{2} (S_x - i S_y) = \\frac{1}{2} \\begin{bmatrix} 0 & 0 \\\\ 1 & 0 \\end{bmatrix}
204
+ $$
205
+ """
206
+
207
+ pass
208
+
209
+
210
+ @statement(dialect=dialect)
211
+ class Sp(ConstantOp):
212
+ """
213
+ $S_{+}$ operator.
214
+
215
+ $$
216
+ Sp = \\frac{1}{2} (S_x + i S_y) = \\frac{1}{2}\\begin{bmatrix} 0 & 1 \\\\ 0 & 0 \\end{bmatrix}
217
+ $$
218
+ """
219
+
220
+ pass
@@ -0,0 +1,43 @@
1
+ from typing import cast
2
+ from dataclasses import dataclass
3
+
4
+ from kirin import ir
5
+
6
+
7
+ @dataclass(frozen=True)
8
+ class FixedSites(ir.StmtTrait):
9
+ data: int
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class HasSites(ir.StmtTrait):
14
+ """An operator with a `sites` attribute."""
15
+
16
+ def get_sites(self, stmt: ir.Statement):
17
+ attr = stmt.get_attr_or_prop("sites")
18
+ if attr is None:
19
+ raise ValueError(f"Missing sites attribute in {stmt}")
20
+ return cast(ir.PyAttr[int], attr).data
21
+
22
+ def set_sites(self, stmt: ir.Statement, value: int):
23
+ stmt.attributes["sites"] = ir.PyAttr(value)
24
+ return
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class Unitary(ir.StmtTrait):
29
+ pass
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class MaybeUnitary(ir.StmtTrait):
34
+
35
+ def is_unitary(self, stmt: ir.Statement):
36
+ attr = stmt.get_attr_or_prop("is_unitary")
37
+ if attr is None:
38
+ return False
39
+ return cast(ir.PyAttr[bool], attr).data
40
+
41
+ def set_unitary(self, stmt: ir.Statement, value: bool):
42
+ stmt.attributes["is_unitary"] = ir.PyAttr(value)
43
+ return
@@ -0,0 +1,10 @@
1
+ from kirin import types
2
+
3
+
4
+ class Op:
5
+
6
+ def __matmul__(self, other: "Op") -> "Op":
7
+ raise NotImplementedError("@ can only be used within a squin kernel program")
8
+
9
+
10
+ OpType = types.PyClass(Op)
bloqade/squin/qubit.py ADDED
@@ -0,0 +1,118 @@
1
+ """qubit dialect for squin language.
2
+
3
+ This dialect defines the operations that can be performed on qubits.
4
+
5
+ Depends on:
6
+ - `bloqade.squin.op`: provides the `OpType` type and semantics for operators applied to qubits.
7
+ - `kirin.dialects.ilist`: provides the `ilist.IListType` type for lists of qubits.
8
+ """
9
+
10
+ from typing import Any
11
+
12
+ from kirin import ir, types, lowering
13
+ from kirin.decl import info, statement
14
+ from kirin.dialects import ilist
15
+ from kirin.lowering import wraps
16
+
17
+ from bloqade.types import Qubit, QubitType
18
+ from bloqade.squin.op.types import Op, OpType
19
+
20
+ dialect = ir.Dialect("squin.qubit")
21
+
22
+
23
+ @statement(dialect=dialect)
24
+ class New(ir.Statement):
25
+ traits = frozenset({lowering.FromPythonCall()})
26
+ n_qubits: ir.SSAValue = info.argument(types.Int)
27
+ result: ir.ResultValue = info.result(ilist.IListType[QubitType, types.Any])
28
+
29
+
30
+ @statement(dialect=dialect)
31
+ class Apply(ir.Statement):
32
+ traits = frozenset({lowering.FromPythonCall()})
33
+ operator: ir.SSAValue = info.argument(OpType)
34
+ qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
35
+
36
+
37
+ @statement(dialect=dialect)
38
+ class Measure(ir.Statement):
39
+ traits = frozenset({lowering.FromPythonCall()})
40
+ qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
41
+ result: ir.ResultValue = info.result(types.Int)
42
+
43
+
44
+ @statement(dialect=dialect)
45
+ class MeasureAndReset(ir.Statement):
46
+ traits = frozenset({lowering.FromPythonCall()})
47
+ qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
48
+ result: ir.ResultValue = info.result(types.Int)
49
+
50
+
51
+ @statement(dialect=dialect)
52
+ class Reset(ir.Statement):
53
+ qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
54
+
55
+
56
+ # NOTE: no dependent types in Python, so we have to mark it Any...
57
+ @wraps(New)
58
+ def new(n_qubits: int) -> ilist.IList[Qubit, Any]:
59
+ """Create a new list of qubits.
60
+
61
+ Args:
62
+ n_qubits(int): The number of qubits to create.
63
+
64
+ Returns:
65
+ (ilist.IList[Qubit, n_qubits]) A list of qubits.
66
+ """
67
+ ...
68
+
69
+
70
+ @wraps(Apply)
71
+ def apply(operator: Op, qubits: ilist.IList[Qubit, Any] | list[Qubit]) -> None:
72
+ """Apply an operator to a list of qubits.
73
+
74
+ Args:
75
+ operator: The operator to apply.
76
+ qubits: The list of qubits to apply the operator to. The size of the list
77
+ must be inferable and match the number of qubits expected by the operator.
78
+
79
+ Returns:
80
+ None
81
+ """
82
+ ...
83
+
84
+
85
+ @wraps(Measure)
86
+ def measure(qubits: ilist.IList[Qubit, Any]) -> int:
87
+ """Measure the qubits in the list."
88
+
89
+ Args:
90
+ qubits: The list of qubits to measure.
91
+
92
+ Returns:
93
+ int: The result of the measurement.
94
+ """
95
+ ...
96
+
97
+
98
+ @wraps(MeasureAndReset)
99
+ def measure_and_reset(qubits: ilist.IList[Qubit, Any]) -> int:
100
+ """Measure the qubits in the list and reset them."
101
+
102
+ Args:
103
+ qubits: The list of qubits to measure and reset.
104
+
105
+ Returns:
106
+ int: The result of the measurement.
107
+ """
108
+ ...
109
+
110
+
111
+ @wraps(Reset)
112
+ def reset(qubits: ilist.IList[Qubit, Any]) -> None:
113
+ """Reset the qubits in the list."
114
+
115
+ Args:
116
+ qubits: The list of qubits to reset.
117
+ """
118
+ ...
bloqade/squin/wire.py ADDED
@@ -0,0 +1,103 @@
1
+ """A NVIDIA QUAKE-like wire dialect.
2
+
3
+ This dialect is expected to be used in combination with the operator dialect
4
+ as an intermediate representation for analysis and optimization of quantum
5
+ circuits. Thus we do not define wrapping functions for the statements in this
6
+ dialect.
7
+ """
8
+
9
+ from kirin import ir, types, interp, lowering
10
+ from kirin.decl import info, statement
11
+
12
+ from bloqade.types import QubitType
13
+
14
+ from .op.types import OpType
15
+
16
+ # from kirin.lowering import wraps
17
+
18
+ # from .op.types import Op, OpType
19
+
20
+ dialect = ir.Dialect("squin.wire")
21
+
22
+
23
+ class WireTerminator(ir.StmtTrait):
24
+ pass
25
+
26
+
27
+ class Wire:
28
+ pass
29
+
30
+
31
+ WireType = types.PyClass(Wire)
32
+
33
+
34
+ # no return value for `wrap`
35
+ @statement(dialect=dialect)
36
+ class Wrap(ir.Statement):
37
+ traits = frozenset({lowering.FromPythonCall(), WireTerminator()})
38
+ wire: ir.SSAValue = info.argument(WireType)
39
+ qubit: ir.SSAValue = info.argument(QubitType)
40
+
41
+
42
+ # "Unwrap the quantum references to expose wires" -> From Quake Dialect documentation
43
+ # Unwrap(Qubit) -> Wire
44
+ @statement(dialect=dialect)
45
+ class Unwrap(ir.Statement):
46
+ traits = frozenset({lowering.FromPythonCall(), ir.Pure()})
47
+ qubit: ir.SSAValue = info.argument(QubitType)
48
+ result: ir.ResultValue = info.result(WireType)
49
+
50
+
51
+ # In Quake, you put a wire in and get a wire out when you "apply" an operator
52
+ # In this case though we just need to indicate that an operator is applied to list[wires]
53
+ @statement(dialect=dialect)
54
+ class Apply(ir.Statement): # apply(op, w1, w2, ...)
55
+ traits = frozenset({lowering.FromPythonCall(), ir.Pure()})
56
+ operator: ir.SSAValue = info.argument(OpType)
57
+ inputs: tuple[ir.SSAValue, ...] = info.argument(WireType)
58
+
59
+ def __init__(self, operator: ir.SSAValue, *args: ir.SSAValue):
60
+ result_types = tuple(WireType for _ in args)
61
+ super().__init__(
62
+ args=(operator,) + args,
63
+ result_types=result_types, # result types of the Apply statement, should all be WireTypes
64
+ args_slice={
65
+ "operator": 0,
66
+ "inputs": slice(1, None),
67
+ }, # pretty printing + syntax sugar
68
+ ) # custom lowering required for wrapper to work here
69
+
70
+
71
+ # NOTE: measurement cannot be pure because they will collapse the state
72
+ # of the qubit. The state is a hidden state that is not visible to
73
+ # the user in the wire dialect.
74
+ @statement(dialect=dialect)
75
+ class Measure(ir.Statement):
76
+ traits = frozenset({lowering.FromPythonCall(), WireTerminator()})
77
+ wire: ir.SSAValue = info.argument(WireType)
78
+ result: ir.ResultValue = info.result(types.Int)
79
+
80
+
81
+ @statement(dialect=dialect)
82
+ class MeasureAndReset(ir.Statement):
83
+ traits = frozenset({lowering.FromPythonCall(), WireTerminator()})
84
+ wire: ir.SSAValue = info.argument(WireType)
85
+ result: ir.ResultValue = info.result(types.Int)
86
+ out_wire: ir.ResultValue = info.result(WireType)
87
+
88
+
89
+ @statement(dialect=dialect)
90
+ class Reset(ir.Statement):
91
+ traits = frozenset({lowering.FromPythonCall(), WireTerminator()})
92
+ wire: ir.SSAValue = info.argument(WireType)
93
+
94
+
95
+ # Issue where constant propagation can't handle
96
+ # multiple return values from Apply properly
97
+ @dialect.register(key="constprop")
98
+ class ConstPropWire(interp.MethodTable):
99
+
100
+ @interp.impl(Apply)
101
+ def apply(self, interp, frame, stmt: Apply):
102
+
103
+ return frame.get_values(stmt.inputs)
@@ -0,0 +1,6 @@
1
+ from .groups import main as main
2
+ from ._wrappers import * # noqa: F403
3
+ from .dialects.aux import * # noqa F403
4
+ from .dialects.gate import * # noqa F403
5
+ from .dialects.noise import * # noqa F403
6
+ from .dialects.collapse import * # noqa F403
@@ -0,0 +1,186 @@
1
+ from typing import Union
2
+
3
+ from kirin.lowering import wraps
4
+
5
+ from .dialects import aux, gate, noise, collapse
6
+
7
+
8
+ # dialect:: gate
9
+ ## 1q
10
+ @wraps(gate.X)
11
+ def x(targets: tuple[int, ...], dagger: bool = False) -> None: ...
12
+
13
+
14
+ @wraps(gate.Y)
15
+ def y(targets: tuple[int, ...], dagger: bool = False) -> None: ...
16
+
17
+
18
+ @wraps(gate.Z)
19
+ def z(targets: tuple[int, ...], dagger: bool = False) -> None: ...
20
+
21
+
22
+ @wraps(gate.Identity)
23
+ def identity(targets: tuple[int, ...], dagger: bool = False) -> None: ...
24
+
25
+
26
+ @wraps(gate.H)
27
+ def h(targets: tuple[int, ...], dagger: bool = False) -> None: ...
28
+
29
+
30
+ @wraps(gate.S)
31
+ def s(targets: tuple[int, ...], dagger: bool = False) -> None: ...
32
+
33
+
34
+ @wraps(gate.SqrtX)
35
+ def sqrt_x(targets: tuple[int, ...], dagger: bool = False) -> None: ...
36
+
37
+
38
+ @wraps(gate.SqrtY)
39
+ def sqrt_y(targets: tuple[int, ...], dagger: bool = False) -> None: ...
40
+
41
+
42
+ @wraps(gate.SqrtZ)
43
+ def sqrt_z(targets: tuple[int, ...], dagger: bool = False) -> None: ...
44
+
45
+
46
+ ## clif 2q
47
+ @wraps(gate.Swap)
48
+ def swap(targets: tuple[int, ...], dagger: bool = False) -> None: ...
49
+
50
+
51
+ ## ctrl 2q
52
+ @wraps(gate.CX)
53
+ def cx(
54
+ controls: tuple[int, ...], targets: tuple[int, ...], dagger: bool = False
55
+ ) -> None: ...
56
+
57
+
58
+ @wraps(gate.CY)
59
+ def cy(
60
+ controls: tuple[int, ...], targets: tuple[int, ...], dagger: bool = False
61
+ ) -> None: ...
62
+
63
+
64
+ @wraps(gate.CZ)
65
+ def cz(
66
+ controls: tuple[int, ...], targets: tuple[int, ...], dagger: bool = False
67
+ ) -> None: ...
68
+
69
+
70
+ ## pp
71
+ @wraps(gate.SPP)
72
+ def spp(targets: tuple[aux.PauliString, ...], dagger=False) -> None: ...
73
+
74
+
75
+ # dialect:: aux
76
+ @wraps(aux.GetRecord)
77
+ def rec(id: int) -> aux.RecordResult: ...
78
+
79
+
80
+ @wraps(aux.Detector)
81
+ def detector(
82
+ coord: tuple[Union[int, float], ...], targets: tuple[aux.RecordResult, ...]
83
+ ) -> None: ...
84
+
85
+
86
+ @wraps(aux.ObservableInclude)
87
+ def observable_include(idx: int, targets: tuple[aux.RecordResult, ...]) -> None: ...
88
+
89
+
90
+ @wraps(aux.Tick)
91
+ def tick() -> None: ...
92
+
93
+
94
+ @wraps(aux.NewPauliString)
95
+ def pauli_string(
96
+ string: tuple[str, ...], flipped: tuple[bool, ...], targets: tuple[int, ...]
97
+ ) -> aux.PauliString: ...
98
+
99
+
100
+ # dialect:: collapse
101
+ @wraps(collapse.MZ)
102
+ def mz(p: float, targets: tuple[int, ...]) -> None: ...
103
+
104
+
105
+ @wraps(collapse.MY)
106
+ def my(p: float, targets: tuple[int, ...]) -> None: ...
107
+
108
+
109
+ @wraps(collapse.MX)
110
+ def mx(p: float, targets: tuple[int, ...]) -> None: ...
111
+
112
+
113
+ @wraps(collapse.MZZ)
114
+ def mzz(p: float, targets: tuple[int, ...]) -> None: ...
115
+
116
+
117
+ @wraps(collapse.MYY)
118
+ def myy(p: float, targets: tuple[int, ...]) -> None: ...
119
+
120
+
121
+ @wraps(collapse.MXX)
122
+ def mxx(p: float, targets: tuple[int, ...]) -> None: ...
123
+
124
+
125
+ @wraps(collapse.PPMeasurement)
126
+ def mpp(p: float, targets: tuple[aux.PauliString, ...]) -> None: ...
127
+
128
+
129
+ @wraps(collapse.RZ)
130
+ def rz(targets: tuple[int, ...]) -> None: ...
131
+
132
+
133
+ @wraps(collapse.RY)
134
+ def ry(targets: tuple[int, ...]) -> None: ...
135
+
136
+
137
+ @wraps(collapse.RX)
138
+ def rx(targets: tuple[int, ...]) -> None: ...
139
+
140
+
141
+ # dialect:: noise
142
+ @wraps(noise.Depolarize1)
143
+ def depolarize1(p: float, targets: tuple[int, ...]) -> None: ...
144
+
145
+
146
+ @wraps(noise.Depolarize2)
147
+ def depolarize2(p: float, targets: tuple[int, ...]) -> None: ...
148
+
149
+
150
+ @wraps(noise.PauliChannel1)
151
+ def pauli_channel1(
152
+ px: float, py: float, pz: float, targets: tuple[int, ...]
153
+ ) -> None: ...
154
+
155
+
156
+ @wraps(noise.PauliChannel2)
157
+ def pauli_channel2(
158
+ pix: float,
159
+ piy: float,
160
+ piz: float,
161
+ pxi: float,
162
+ pxx: float,
163
+ pxy: float,
164
+ pxz: float,
165
+ pyi: float,
166
+ pyx: float,
167
+ pyy: float,
168
+ pyz: float,
169
+ pzi: float,
170
+ pzx: float,
171
+ pzy: float,
172
+ pzz: float,
173
+ targets: tuple[int, ...],
174
+ ) -> None: ...
175
+
176
+
177
+ @wraps(noise.XError)
178
+ def x_error(p: float, targets: tuple[int, ...]) -> None: ...
179
+
180
+
181
+ @wraps(noise.YError)
182
+ def y_error(p: float, targets: tuple[int, ...]) -> None: ...
183
+
184
+
185
+ @wraps(noise.ZError)
186
+ def z_error(p: float, targets: tuple[int, ...]) -> None: ...
@@ -0,0 +1,5 @@
1
+ from . import aux as aux, gate as gate, noise as noise, collapse as collapse
2
+ from .aux.stmts import * # noqa F403
3
+ from .gate.stmts import * # noqa F403
4
+ from .noise.stmts import * # noqa F403
5
+ from .collapse.stmts import * # noqa F403
@@ -0,0 +1,11 @@
1
+ from . import lowering as lowering
2
+ from .emit import EmitStimAuxMethods as EmitStimAuxMethods
3
+ from .stmts import * # noqa F403
4
+ from .types import (
5
+ RecordType as RecordType,
6
+ PauliString as PauliString,
7
+ RecordResult as RecordResult,
8
+ PauliStringType as PauliStringType,
9
+ )
10
+ from .interp import StimAuxMethods as StimAuxMethods
11
+ from ._dialect import dialect as dialect
@@ -0,0 +1,3 @@
1
+ from kirin import ir
2
+
3
+ dialect = ir.Dialect("stim.aux")