bloqade-circuit 0.7.13__py3-none-any.whl → 0.8.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 (136) hide show
  1. bloqade/analysis/address/__init__.py +8 -4
  2. bloqade/analysis/address/analysis.py +119 -29
  3. bloqade/analysis/address/impls.py +290 -87
  4. bloqade/analysis/address/lattice.py +209 -24
  5. bloqade/analysis/fidelity/analysis.py +2 -2
  6. bloqade/analysis/measure_id/impls.py +3 -27
  7. bloqade/cirq_utils/__init__.py +3 -1
  8. bloqade/cirq_utils/emit/__init__.py +3 -0
  9. bloqade/cirq_utils/emit/base.py +243 -0
  10. bloqade/cirq_utils/emit/gate.py +104 -0
  11. bloqade/cirq_utils/emit/noise.py +90 -0
  12. bloqade/cirq_utils/emit/qubit.py +35 -0
  13. bloqade/cirq_utils/lowering.py +664 -0
  14. bloqade/native/__init__.py +0 -1
  15. bloqade/native/_prelude.py +3 -3
  16. bloqade/native/dialects/gate/__init__.py +2 -0
  17. bloqade/native/dialects/gate/_dialect.py +3 -0
  18. bloqade/native/dialects/{gates → gate}/_interface.py +5 -5
  19. bloqade/native/dialects/{gates → gate}/stmts.py +5 -5
  20. bloqade/native/stdlib/broadcast.py +19 -19
  21. bloqade/native/stdlib/simple.py +14 -13
  22. bloqade/native/upstream/__init__.py +5 -0
  23. bloqade/native/upstream/squin2native.py +136 -0
  24. bloqade/pyqrack/__init__.py +1 -2
  25. bloqade/pyqrack/device.py +6 -17
  26. bloqade/pyqrack/native.py +17 -17
  27. bloqade/pyqrack/reg.py +1 -6
  28. bloqade/pyqrack/squin/gate/__init__.py +1 -0
  29. bloqade/pyqrack/squin/gate/gate.py +136 -0
  30. bloqade/pyqrack/squin/noise/native.py +120 -54
  31. bloqade/pyqrack/squin/qubit.py +25 -41
  32. bloqade/pyqrack/target.py +2 -2
  33. bloqade/qasm2/dialects/core/address.py +21 -12
  34. bloqade/qasm2/dialects/noise/fidelity.py +2 -6
  35. bloqade/qasm2/dialects/noise/model.py +2 -1
  36. bloqade/qasm2/passes/parallel.py +3 -1
  37. bloqade/qasm2/rewrite/__init__.py +0 -1
  38. bloqade/qasm2/rewrite/noise/heuristic_noise.py +7 -17
  39. bloqade/qasm2/rewrite/parallel_to_glob.py +28 -15
  40. bloqade/qasm2/rewrite/parallel_to_uop.py +2 -8
  41. bloqade/qubit/__init__.py +12 -0
  42. bloqade/qubit/_dialect.py +3 -0
  43. bloqade/qubit/_interface.py +49 -0
  44. bloqade/qubit/_prelude.py +45 -0
  45. bloqade/qubit/analysis/__init__.py +1 -0
  46. bloqade/qubit/analysis/address_impl.py +40 -0
  47. bloqade/qubit/stdlib/__init__.py +2 -0
  48. bloqade/qubit/stdlib/_new.py +34 -0
  49. bloqade/qubit/stdlib/broadcast.py +62 -0
  50. bloqade/qubit/stdlib/simple.py +59 -0
  51. bloqade/qubit/stmts.py +60 -0
  52. bloqade/rewrite/passes/aggressive_unroll.py +2 -1
  53. bloqade/squin/__init__.py +44 -17
  54. bloqade/squin/analysis/__init__.py +0 -1
  55. bloqade/squin/analysis/schedule.py +2 -2
  56. bloqade/squin/gate/__init__.py +2 -0
  57. bloqade/squin/gate/_dialect.py +3 -0
  58. bloqade/squin/gate/_interface.py +98 -0
  59. bloqade/squin/gate/stmts.py +119 -0
  60. bloqade/squin/groups.py +4 -21
  61. bloqade/squin/noise/__init__.py +1 -9
  62. bloqade/squin/noise/_dialect.py +1 -1
  63. bloqade/squin/noise/_interface.py +45 -0
  64. bloqade/squin/noise/stmts.py +65 -29
  65. bloqade/squin/rewrite/U3_to_clifford.py +70 -51
  66. bloqade/squin/rewrite/__init__.py +0 -2
  67. bloqade/squin/rewrite/remove_dangling_qubits.py +2 -2
  68. bloqade/squin/rewrite/wrap_analysis.py +4 -35
  69. bloqade/squin/stdlib/broadcast/__init__.py +34 -0
  70. bloqade/squin/stdlib/broadcast/_qubit.py +4 -0
  71. bloqade/squin/stdlib/broadcast/gate.py +260 -0
  72. bloqade/squin/stdlib/broadcast/noise.py +144 -0
  73. bloqade/squin/stdlib/simple/__init__.py +33 -0
  74. bloqade/squin/stdlib/simple/gate.py +242 -0
  75. bloqade/squin/stdlib/simple/noise.py +126 -0
  76. bloqade/stim/__init__.py +1 -0
  77. bloqade/stim/_wrappers.py +6 -0
  78. bloqade/stim/dialects/noise/emit.py +6 -1
  79. bloqade/stim/dialects/noise/stmts.py +5 -3
  80. bloqade/stim/emit/stim_str.py +2 -0
  81. bloqade/stim/parse/lowering.py +12 -17
  82. bloqade/stim/passes/__init__.py +0 -1
  83. bloqade/stim/passes/flatten.py +26 -0
  84. bloqade/stim/passes/simplify_ifs.py +6 -1
  85. bloqade/stim/passes/squin_to_stim.py +4 -70
  86. bloqade/stim/rewrite/__init__.py +0 -4
  87. bloqade/stim/rewrite/ifs_to_stim.py +23 -29
  88. bloqade/stim/rewrite/qubit_to_stim.py +96 -51
  89. bloqade/stim/rewrite/squin_measure.py +9 -18
  90. bloqade/stim/rewrite/squin_noise.py +132 -108
  91. bloqade/stim/rewrite/util.py +5 -204
  92. bloqade/types.py +10 -0
  93. {bloqade_circuit-0.7.13.dist-info → bloqade_circuit-0.8.0.dist-info}/METADATA +2 -2
  94. {bloqade_circuit-0.7.13.dist-info → bloqade_circuit-0.8.0.dist-info}/RECORD +96 -100
  95. bloqade/native/dialects/gates/__init__.py +0 -3
  96. bloqade/native/dialects/gates/_dialect.py +0 -3
  97. bloqade/pyqrack/squin/op.py +0 -180
  98. bloqade/pyqrack/squin/runtime.py +0 -543
  99. bloqade/pyqrack/squin/wire.py +0 -51
  100. bloqade/squin/_typeinfer.py +0 -20
  101. bloqade/squin/analysis/address_impl.py +0 -71
  102. bloqade/squin/analysis/nsites/__init__.py +0 -9
  103. bloqade/squin/analysis/nsites/analysis.py +0 -50
  104. bloqade/squin/analysis/nsites/impls.py +0 -99
  105. bloqade/squin/analysis/nsites/lattice.py +0 -49
  106. bloqade/squin/cirq/__init__.py +0 -306
  107. bloqade/squin/cirq/emit/emit_circuit.py +0 -129
  108. bloqade/squin/cirq/emit/noise.py +0 -49
  109. bloqade/squin/cirq/emit/op.py +0 -176
  110. bloqade/squin/cirq/emit/qubit.py +0 -58
  111. bloqade/squin/cirq/emit/runtime.py +0 -242
  112. bloqade/squin/cirq/lowering.py +0 -439
  113. bloqade/squin/lowering.py +0 -80
  114. bloqade/squin/noise/_wrapper.py +0 -36
  115. bloqade/squin/noise/rewrite.py +0 -129
  116. bloqade/squin/op/__init__.py +0 -41
  117. bloqade/squin/op/_dialect.py +0 -3
  118. bloqade/squin/op/_wrapper.py +0 -121
  119. bloqade/squin/op/number.py +0 -5
  120. bloqade/squin/op/rewrite.py +0 -46
  121. bloqade/squin/op/stdlib.py +0 -62
  122. bloqade/squin/op/stmts.py +0 -300
  123. bloqade/squin/op/traits.py +0 -43
  124. bloqade/squin/op/types.py +0 -128
  125. bloqade/squin/parallel.py +0 -200
  126. bloqade/squin/qubit.py +0 -194
  127. bloqade/squin/rewrite/canonicalize.py +0 -60
  128. bloqade/squin/rewrite/desugar.py +0 -102
  129. bloqade/squin/stdlib/channel.py +0 -86
  130. bloqade/squin/stdlib/gate.py +0 -201
  131. bloqade/squin/types.py +0 -8
  132. bloqade/squin/wire.py +0 -201
  133. bloqade/stim/rewrite/wire_identity_elimination.py +0 -24
  134. bloqade/stim/rewrite/wire_to_stim.py +0 -57
  135. {bloqade_circuit-0.7.13.dist-info → bloqade_circuit-0.8.0.dist-info}/WHEEL +0 -0
  136. {bloqade_circuit-0.7.13.dist-info → bloqade_circuit-0.8.0.dist-info}/licenses/LICENSE +0 -0
bloqade/squin/op/types.py DELETED
@@ -1,128 +0,0 @@
1
- from typing import Generic, TypeVar, overload
2
-
3
- from kirin import types
4
-
5
-
6
- class Op:
7
-
8
- def __matmul__(self, other: "Op") -> "Op":
9
- raise NotImplementedError("@ can only be used within a squin kernel program")
10
-
11
- @overload
12
- def __mul__(self, other: "Op") -> "Op": ...
13
-
14
- @overload
15
- def __mul__(self, other: complex) -> "Op": ...
16
-
17
- def __mul__(self, other) -> "Op":
18
- raise NotImplementedError("@ can only be used within a squin kernel program")
19
-
20
- def __rmul__(self, other: complex) -> "Op":
21
- raise NotImplementedError("@ can only be used within a squin kernel program")
22
-
23
-
24
- OpType = types.PyClass(Op)
25
-
26
-
27
- class CompositeOp(Op):
28
- pass
29
-
30
-
31
- CompositeOpType = types.PyClass(CompositeOp)
32
-
33
- LhsType = TypeVar("LhsType", bound=Op)
34
- RhsType = TypeVar("RhsType", bound=Op)
35
-
36
-
37
- class BinaryOp(Op, Generic[LhsType, RhsType]):
38
- lhs: LhsType
39
- rhs: RhsType
40
-
41
-
42
- BinaryOpType = types.Generic(BinaryOp, OpType, OpType)
43
-
44
-
45
- class Mult(BinaryOp[LhsType, RhsType]):
46
- pass
47
-
48
-
49
- MultType = types.Generic(Mult, OpType, OpType)
50
-
51
-
52
- class Kron(BinaryOp[LhsType, RhsType]):
53
- pass
54
-
55
-
56
- KronType = types.Generic(Kron, OpType, OpType)
57
-
58
-
59
- class MultiQubitPauliOp(Op):
60
- pass
61
-
62
-
63
- MultiQubitPauliOpType = types.PyClass(MultiQubitPauliOp)
64
-
65
-
66
- class PauliStringOp(MultiQubitPauliOp):
67
- pass
68
-
69
-
70
- PauliStringType = types.PyClass(PauliStringOp)
71
-
72
-
73
- class PauliOp(MultiQubitPauliOp):
74
- pass
75
-
76
-
77
- PauliOpType = types.PyClass(PauliOp)
78
-
79
-
80
- class XOp(PauliOp):
81
- pass
82
-
83
-
84
- XOpType = types.PyClass(XOp)
85
-
86
-
87
- class YOp(PauliOp):
88
- pass
89
-
90
-
91
- YOpType = types.PyClass(YOp)
92
-
93
-
94
- class ZOp(PauliOp):
95
- pass
96
-
97
-
98
- ZOpType = types.PyClass(ZOp)
99
-
100
-
101
- ControlledOp = TypeVar("ControlledOp", bound=Op)
102
-
103
-
104
- class ControlOp(CompositeOp, Generic[ControlledOp]):
105
- op: ControlledOp
106
-
107
-
108
- ControlledOpType = types.TypeVar("ControlledOp", bound=OpType)
109
- ControlOpType = types.Generic(ControlOp, ControlledOpType)
110
- CXOpType = ControlOpType[XOpType]
111
- CYOpType = ControlOpType[YOpType]
112
- CZOpType = ControlOpType[ZOpType]
113
-
114
- RotationAxis = TypeVar("RotationAxis", bound=Op)
115
-
116
-
117
- class ROp(CompositeOp, Generic[RotationAxis]):
118
- axis: RotationAxis
119
- angle: float
120
-
121
-
122
- ROpType = types.Generic(ROp, OpType)
123
- RxOpType = ROpType[XOpType]
124
- RyOpType = ROpType[YOpType]
125
- RzOpType = ROpType[ZOpType]
126
-
127
-
128
- NumOperators = types.TypeVar("NumOperators", bound=types.Int)
bloqade/squin/parallel.py DELETED
@@ -1,200 +0,0 @@
1
- from typing import Any, TypeVar
2
-
3
- from kirin.dialects import ilist
4
-
5
- from bloqade.types import Qubit
6
-
7
- from . import op as _op, qubit as _qubit
8
- from .groups import kernel
9
-
10
-
11
- @kernel
12
- def x(qubits: ilist.IList[Qubit, Any]) -> None:
13
- """x gate applied to qubits in parallel."""
14
- op = _op.x()
15
- _qubit.broadcast(op, qubits)
16
-
17
-
18
- @kernel
19
- def y(qubits: ilist.IList[Qubit, Any]) -> None:
20
- """y gate applied to qubits in parallel."""
21
- op = _op.y()
22
- _qubit.broadcast(op, qubits)
23
-
24
-
25
- @kernel
26
- def z(qubits: ilist.IList[Qubit, Any]) -> None:
27
- """z gate applied to qubits in parallel."""
28
- op = _op.z()
29
- _qubit.broadcast(op, qubits)
30
-
31
-
32
- @kernel
33
- def sqrt_x(qubits: ilist.IList[Qubit, Any]) -> None:
34
- """Square root x gate applied to qubits in parallel."""
35
- op = _op.sqrt_x()
36
- _qubit.broadcast(op, qubits)
37
-
38
-
39
- @kernel
40
- def sqrt_y(qubits: ilist.IList[Qubit, Any]) -> None:
41
- """Square root y gate applied to qubits in parallel."""
42
- op = _op.sqrt_y()
43
- _qubit.broadcast(op, qubits)
44
-
45
-
46
- @kernel
47
- def sqrt_z(qubits: ilist.IList[Qubit, Any]) -> None:
48
- """Square root gate applied to qubits in parallel."""
49
- op = _op.s()
50
- _qubit.broadcast(op, qubits)
51
-
52
-
53
- @kernel
54
- def h(qubits: ilist.IList[Qubit, Any]) -> None:
55
- """Hadamard gate applied to qubits in parallel."""
56
- op = _op.h()
57
- _qubit.broadcast(op, qubits)
58
-
59
-
60
- @kernel
61
- def s(qubits: ilist.IList[Qubit, Any]) -> None:
62
- """s gate applied to qubits in parallel."""
63
- op = _op.s()
64
- _qubit.broadcast(op, qubits)
65
-
66
-
67
- @kernel
68
- def t(qubits: ilist.IList[Qubit, Any]) -> None:
69
- """t gate applied to qubits in parallel."""
70
- op = _op.t()
71
- _qubit.broadcast(op, qubits)
72
-
73
-
74
- @kernel
75
- def p0(qubits: ilist.IList[Qubit, Any]) -> None:
76
- """Projector on 0 applied to qubits in parallel."""
77
- op = _op.p0()
78
- _qubit.broadcast(op, qubits)
79
-
80
-
81
- @kernel
82
- def p1(qubits: ilist.IList[Qubit, Any]) -> None:
83
- """Projector on 1 applied to qubits in parallel."""
84
- op = _op.p1()
85
- _qubit.broadcast(op, qubits)
86
-
87
-
88
- @kernel
89
- def spin_n(qubits: ilist.IList[Qubit, Any]) -> None:
90
- """Spin lowering gate applied to qubits in parallel."""
91
- op = _op.spin_n()
92
- _qubit.broadcast(op, qubits)
93
-
94
-
95
- @kernel
96
- def spin_p(qubits: ilist.IList[Qubit, Any]) -> None:
97
- """Spin raising gate applied to qubits in parallel."""
98
- op = _op.spin_p()
99
- _qubit.broadcast(op, qubits)
100
-
101
-
102
- @kernel
103
- def reset(qubits: ilist.IList[Qubit, Any]) -> None:
104
- """Reset qubit to 0."""
105
- op = _op.reset()
106
- _qubit.broadcast(op, qubits)
107
-
108
-
109
- N = TypeVar("N")
110
-
111
-
112
- @kernel
113
- def cx(controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]) -> None:
114
- """Controlled x gate applied to controls and targets in parallel."""
115
- op = _op.cx()
116
- _qubit.broadcast(op, controls, targets)
117
-
118
-
119
- @kernel
120
- def cy(controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]) -> None:
121
- """Controlled y gate applied to controls and targets in parallel."""
122
- op = _op.cy()
123
- _qubit.broadcast(op, controls, targets)
124
-
125
-
126
- @kernel
127
- def cz(controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]) -> None:
128
- """Controlled z gate applied to controls and targets in parallel."""
129
- op = _op.cz()
130
- _qubit.broadcast(op, controls, targets)
131
-
132
-
133
- @kernel
134
- def ch(controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]) -> None:
135
- """Controlled Hadamard gate applied to controls and targets in parallel."""
136
- op = _op.ch()
137
- _qubit.broadcast(op, controls, targets)
138
-
139
-
140
- @kernel
141
- def u(theta: float, phi: float, lam: float, qubits: ilist.IList[Qubit, Any]) -> None:
142
- """3D rotation gate applied to controls and targets in parallel."""
143
- op = _op.u(theta, phi, lam)
144
- _qubit.broadcast(op, qubits)
145
-
146
-
147
- @kernel
148
- def rx(theta: float, qubits: ilist.IList[Qubit, Any]) -> None:
149
- """Rotation X gate applied to qubits in parallel."""
150
- op = _op.rot(_op.x(), theta)
151
- _qubit.broadcast(op, qubits)
152
-
153
-
154
- @kernel
155
- def ry(theta: float, qubits: ilist.IList[Qubit, Any]) -> None:
156
- """Rotation Y gate applied to qubits in parallel."""
157
- op = _op.rot(_op.y(), theta)
158
- _qubit.broadcast(op, qubits)
159
-
160
-
161
- @kernel
162
- def rz(theta: float, qubits: ilist.IList[Qubit, Any]) -> None:
163
- """Rotation Z gate applied to qubits in parallel."""
164
- op = _op.rot(_op.z(), theta)
165
- _qubit.broadcast(op, qubits)
166
-
167
-
168
- @kernel
169
- def sqrt_x_adj(qubits: ilist.IList[Qubit, Any]) -> None:
170
- """Adjoint sqrt_x gate applied to qubits in parallel."""
171
- op = _op.sqrt_x()
172
- _qubit.broadcast(_op.adjoint(op), qubits)
173
-
174
-
175
- @kernel
176
- def sqrt_y_adj(qubits: ilist.IList[Qubit, Any]) -> None:
177
- """Adjoint sqrt_y gate applied to qubits in parallel."""
178
- op = _op.sqrt_y()
179
- _qubit.broadcast(_op.adjoint(op), qubits)
180
-
181
-
182
- @kernel
183
- def sqrt_z_adj(qubits: ilist.IList[Qubit, Any]) -> None:
184
- """Adjoint square root z gate applied to qubits in parallel."""
185
- op = _op.s()
186
- _qubit.broadcast(_op.adjoint(op), qubits)
187
-
188
-
189
- @kernel
190
- def s_adj(qubits: ilist.IList[Qubit, Any]) -> None:
191
- """Adjoint s gate applied to qubits in parallel."""
192
- op = _op.s()
193
- _qubit.broadcast(_op.adjoint(op), qubits)
194
-
195
-
196
- @kernel
197
- def t_adj(qubits: ilist.IList[Qubit, Any]) -> None:
198
- """Adjoint t gate applied to qubits in parallel."""
199
- op = _op.t()
200
- _qubit.broadcast(_op.adjoint(op), qubits)
bloqade/squin/qubit.py DELETED
@@ -1,194 +0,0 @@
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, TypeVar, overload
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
- from .types import MeasurementResult, MeasurementResultType
21
- from .lowering import ApplyAnyCallLowering, BroadcastCallLowering
22
-
23
- dialect = ir.Dialect("squin.qubit")
24
-
25
-
26
- @statement(dialect=dialect)
27
- class New(ir.Statement):
28
- traits = frozenset({lowering.FromPythonCall()})
29
- n_qubits: ir.SSAValue = info.argument(types.Int)
30
- result: ir.ResultValue = info.result(ilist.IListType[QubitType, types.Any])
31
-
32
-
33
- @statement(dialect=dialect)
34
- class Apply(ir.Statement):
35
- traits = frozenset({lowering.FromPythonCall()})
36
- operator: ir.SSAValue = info.argument(OpType)
37
- qubits: tuple[ir.SSAValue, ...] = info.argument(QubitType)
38
-
39
-
40
- @statement(dialect=dialect)
41
- class ApplyAny(ir.Statement):
42
- # NOTE: custom lowering to deal with vararg calls
43
- traits = frozenset({ApplyAnyCallLowering()})
44
- operator: ir.SSAValue = info.argument(OpType)
45
- qubits: tuple[ir.SSAValue, ...] = info.argument()
46
-
47
-
48
- @statement(dialect=dialect)
49
- class Broadcast(ir.Statement):
50
- traits = frozenset({BroadcastCallLowering()})
51
- operator: ir.SSAValue = info.argument(OpType)
52
- qubits: tuple[ir.SSAValue, ...] = info.argument(ilist.IListType[QubitType])
53
-
54
-
55
- @statement(dialect=dialect)
56
- class MeasureAny(ir.Statement):
57
- name = "measure"
58
-
59
- traits = frozenset({lowering.FromPythonCall()})
60
- input: ir.SSAValue = info.argument(types.Any)
61
- result: ir.ResultValue = info.result(types.Any)
62
-
63
-
64
- @statement(dialect=dialect)
65
- class MeasureQubit(ir.Statement):
66
- name = "measure.qubit"
67
-
68
- traits = frozenset({lowering.FromPythonCall()})
69
- qubit: ir.SSAValue = info.argument(QubitType)
70
- result: ir.ResultValue = info.result(MeasurementResultType)
71
-
72
-
73
- @statement(dialect=dialect)
74
- class MeasureQubitList(ir.Statement):
75
- name = "measure.qubit.list"
76
-
77
- traits = frozenset({lowering.FromPythonCall()})
78
- qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
79
- result: ir.ResultValue = info.result(ilist.IListType[MeasurementResultType])
80
-
81
-
82
- @statement(dialect=dialect)
83
- class QubitId(ir.Statement):
84
- traits = frozenset({lowering.FromPythonCall(), ir.Pure()})
85
- qubit: ir.SSAValue = info.argument(QubitType)
86
- result: ir.ResultValue = info.result(types.Int)
87
-
88
-
89
- @statement(dialect=dialect)
90
- class MeasurementId(ir.Statement):
91
- traits = frozenset({lowering.FromPythonCall(), ir.Pure()})
92
- measurement: ir.SSAValue = info.argument(MeasurementResultType)
93
- result: ir.ResultValue = info.result(types.Int)
94
-
95
-
96
- # NOTE: no dependent types in Python, so we have to mark it Any...
97
- @wraps(New)
98
- def new(n_qubits: int) -> ilist.IList[Qubit, Any]:
99
- """Create a new list of qubits.
100
-
101
- Args:
102
- n_qubits(int): The number of qubits to create.
103
-
104
- Returns:
105
- (ilist.IList[Qubit, n_qubits]) A list of qubits.
106
- """
107
- ...
108
-
109
-
110
- @wraps(ApplyAny)
111
- def apply(operator: Op, *qubits: Qubit) -> None:
112
- """Apply an operator to qubits. The number of qubit arguments must match the
113
- size of the operator.
114
-
115
- Note, that when considering atom loss, lost qubits will be skipped.
116
-
117
- Args:
118
- operator: The operator to apply.
119
- *qubits: The qubits to apply the operator to. The number of qubits must
120
- match the size of the operator.
121
-
122
- Returns:
123
- None
124
- """
125
- ...
126
-
127
-
128
- @overload
129
- def measure(input: Qubit) -> MeasurementResult: ...
130
- @overload
131
- def measure(
132
- input: ilist.IList[Qubit, Any] | list[Qubit],
133
- ) -> ilist.IList[MeasurementResult, Any]: ...
134
-
135
-
136
- @wraps(MeasureAny)
137
- def measure(input: Any) -> Any:
138
- """Measure a qubit or qubits in the list.
139
-
140
- Args:
141
- input: A qubit or a list of qubits to measure.
142
-
143
- Returns:
144
- MeasurementResult | list[MeasurementResult]: The result of the measurement. If a single qubit is measured,
145
- a single result is returned. If a list of qubits is measured, a list of results
146
- is returned.
147
- A MeasurementResult can represent both 0 and 1, but also atoms that are lost.
148
- """
149
- ...
150
-
151
-
152
- OpSize = TypeVar("OpSize")
153
-
154
-
155
- @wraps(Broadcast)
156
- def broadcast(operator: Op, *qubits: ilist.IList[Qubit, OpSize] | list[Qubit]) -> None:
157
- """Broadcast and apply an operator to lists of qubits. The number of qubit lists must
158
- match the size of the operator and the lists must be of same length. The operator is
159
- then applied to the list elements similar to what python's map function does.
160
-
161
- ## Usage examples
162
-
163
- ```python
164
- from bloqade import squin
165
-
166
- @squin.kernel
167
- def ghz():
168
- controls = squin.qubit.new(4)
169
- targets = squin.qubit.new(4)
170
-
171
- h = squin.op.h()
172
- squin.qubit.broadcast(h, controls)
173
-
174
- cx = squin.op.cx()
175
- squin.qubit.broadcast(cx, controls, targets)
176
- ```
177
-
178
- Args:
179
- operator: The operator to broadcast and apply.
180
- qubits: The list of qubits to broadcast and apply the operator to. The size of the list
181
- must be inferable and match the number of qubits expected by the operator.
182
-
183
- Returns:
184
- None
185
- """
186
- ...
187
-
188
-
189
- @wraps(QubitId)
190
- def get_qubit_id(qubit: Qubit) -> int: ...
191
-
192
-
193
- @wraps(MeasurementId)
194
- def get_measurement_id(measurement: MeasurementResult) -> int: ...
@@ -1,60 +0,0 @@
1
- from typing import cast
2
-
3
- from kirin import ir
4
- from kirin.rewrite import abc
5
- from kirin.dialects import cf
6
-
7
- from .. import wire
8
-
9
-
10
- class CanonicalizeWired(abc.RewriteRule):
11
- def rewrite_Statement(self, node: ir.Statement) -> abc.RewriteResult:
12
-
13
- if (
14
- not isinstance(node, wire.Wired)
15
- or len(node.qubits) != 0
16
- or (parent_region := node.parent_region) is None
17
- ):
18
- return abc.RewriteResult()
19
-
20
- parent_block = cast(ir.Block, node.parent_block)
21
-
22
- # the body doesn't contain any quantum operations so we can safely inline the
23
- # body into the parent block
24
-
25
- # move all statements after `node` in the current block into another block
26
- after_block = ir.Block()
27
-
28
- stmt = node.next_stmt
29
- while stmt is not None:
30
- stmt.detach()
31
- after_block.stmts.append(stmt)
32
- stmt = node.next_stmt
33
-
34
- # remap all results of the node to the arguments of the after_block
35
- for result in node.results:
36
- arg = after_block.args.append_from(result.type, result.name)
37
- result.replace_by(arg)
38
-
39
- parent_block_idx = parent_region._block_idx[parent_block]
40
- # insert goto of parent block to the body block of the node.
41
- parent_region.blocks.insert(parent_block_idx + 1, after_block)
42
- # insert all blocks of the body of the node after the parent region
43
- # making sure to convert any yield statements to jump statements to the after_block
44
- parent_block.stmts.append(
45
- cf.Branch(
46
- arguments=(),
47
- successor=node.body.blocks[0],
48
- )
49
- )
50
- for block in reversed(node.body.blocks):
51
- block.detach()
52
- if isinstance((yield_stmt := block.last_stmt), wire.Yield):
53
- yield_stmt.replace_by(
54
- cf.Branch(yield_stmt.values, successor=after_block)
55
- )
56
-
57
- parent_region.blocks.insert(parent_block_idx + 1, block)
58
-
59
- node.delete()
60
- return abc.RewriteResult(has_done_something=True)
@@ -1,102 +0,0 @@
1
- from warnings import warn
2
-
3
- from kirin import ir, types
4
- from kirin.dialects import py, ilist
5
- from kirin.rewrite.abc import RewriteRule, RewriteResult
6
-
7
- from bloqade.squin.qubit import (
8
- Apply,
9
- ApplyAny,
10
- QubitType,
11
- MeasureAny,
12
- MeasureQubit,
13
- MeasureQubitList,
14
- )
15
-
16
-
17
- class MeasureDesugarRule(RewriteRule):
18
- """
19
- Desugar measure operations in the circuit.
20
- """
21
-
22
- def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
23
-
24
- if not isinstance(node, MeasureAny):
25
- return RewriteResult()
26
-
27
- if node.input.type.is_subseteq(QubitType):
28
- node.replace_by(
29
- MeasureQubit(
30
- qubit=node.input,
31
- )
32
- )
33
- return RewriteResult(has_done_something=True)
34
- elif node.input.type.is_subseteq(ilist.IListType[QubitType, types.Any]):
35
- node.replace_by(
36
- MeasureQubitList(
37
- qubits=node.input,
38
- )
39
- )
40
- return RewriteResult(has_done_something=True)
41
-
42
- return RewriteResult()
43
-
44
-
45
- class ApplyDesugarRule(RewriteRule):
46
- """
47
- Desugar apply operators in the kernel.
48
-
49
- NOTE: this pass can be removed once we decide to disallow the syntax apply(op: Op, qubits: list)
50
- """
51
-
52
- def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
53
-
54
- if not isinstance(node, ApplyAny):
55
- return RewriteResult()
56
-
57
- op = node.operator
58
- qubits = node.qubits
59
-
60
- if len(qubits) == 0:
61
- # NOTE: this is invalid syntax, but we don't error in rewrites
62
- return RewriteResult()
63
-
64
- if all(q.type.is_subseteq(QubitType) for q in qubits):
65
- # NOTE: this is the syntax we want; the entire rewrite becomes unnecessary
66
- # once we disallow the old syntax (just wrap Apply directly)
67
- apply_stmt = Apply(op, qubits)
68
- node.replace_by(apply_stmt)
69
- return RewriteResult(has_done_something=True)
70
-
71
- if len(qubits) > 1:
72
- # NOTE: multiple arguments, that aren't qubits, let's bail
73
- return RewriteResult()
74
-
75
- qubit_type = qubits[0].type
76
- is_qubit_list = qubit_type.is_subseteq(ilist.IListType[QubitType, types.Any])
77
-
78
- if not is_qubit_list:
79
- return RewriteResult()
80
-
81
- # NOTE: deprecated syntax: we have a single list of qubits here
82
- warn(
83
- "The syntax `apply(operator: Op, qubits: list[Qubit])` is deprecated and may already lead to errors. Use `apply(operator: Op, *qubits: Qubit)` instead."
84
- )
85
- if not isinstance(qubit_type.vars[1], types.Literal):
86
- # NOTE: unknown size, nothing we can do here, it will probably error down the road somewhere
87
- return RewriteResult()
88
-
89
- n = qubit_type.vars[1].data
90
- if not isinstance(n, int):
91
- # wat?
92
- return RewriteResult()
93
-
94
- qubits_rewrite = []
95
- for i in range(n):
96
- (idx := py.Constant(i)).insert_before(node)
97
- (get_item := py.GetItem(qubits[0], idx.result)).insert_before(node)
98
- qubits_rewrite.append(get_item.result)
99
-
100
- apply_stmt = Apply(op, tuple(qubits_rewrite))
101
- node.replace_by(apply_stmt)
102
- return RewriteResult(has_done_something=True)