bloqade-circuit 0.6.2__py3-none-any.whl → 0.9.1__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.
Files changed (192) hide show
  1. bloqade/analysis/address/__init__.py +8 -4
  2. bloqade/analysis/address/analysis.py +123 -33
  3. bloqade/analysis/address/impls.py +293 -90
  4. bloqade/analysis/address/lattice.py +209 -24
  5. bloqade/analysis/fidelity/analysis.py +11 -23
  6. bloqade/analysis/measure_id/__init__.py +4 -1
  7. bloqade/analysis/measure_id/analysis.py +29 -20
  8. bloqade/analysis/measure_id/impls.py +72 -31
  9. bloqade/annotate/__init__.py +6 -0
  10. bloqade/annotate/_dialect.py +3 -0
  11. bloqade/annotate/_interface.py +22 -0
  12. bloqade/annotate/stmts.py +29 -0
  13. bloqade/annotate/types.py +13 -0
  14. bloqade/cirq_utils/__init__.py +4 -2
  15. bloqade/cirq_utils/emit/__init__.py +3 -0
  16. bloqade/cirq_utils/emit/base.py +246 -0
  17. bloqade/cirq_utils/emit/gate.py +104 -0
  18. bloqade/cirq_utils/emit/noise.py +90 -0
  19. bloqade/cirq_utils/emit/qubit.py +35 -0
  20. bloqade/cirq_utils/lowering.py +660 -0
  21. bloqade/cirq_utils/noise/__init__.py +0 -2
  22. bloqade/cirq_utils/noise/_two_zone_utils.py +7 -15
  23. bloqade/cirq_utils/noise/model.py +151 -191
  24. bloqade/cirq_utils/noise/transform.py +2 -2
  25. bloqade/cirq_utils/parallelize.py +9 -6
  26. bloqade/gemini/__init__.py +1 -0
  27. bloqade/gemini/analysis/__init__.py +3 -0
  28. bloqade/gemini/analysis/logical_validation/__init__.py +1 -0
  29. bloqade/gemini/analysis/logical_validation/analysis.py +17 -0
  30. bloqade/gemini/analysis/logical_validation/impls.py +101 -0
  31. bloqade/gemini/groups.py +67 -0
  32. bloqade/native/__init__.py +23 -0
  33. bloqade/native/_prelude.py +45 -0
  34. bloqade/native/dialects/__init__.py +0 -0
  35. bloqade/native/dialects/gate/__init__.py +2 -0
  36. bloqade/native/dialects/gate/_dialect.py +3 -0
  37. bloqade/native/dialects/gate/_interface.py +32 -0
  38. bloqade/native/dialects/gate/stmts.py +31 -0
  39. bloqade/native/stdlib/__init__.py +0 -0
  40. bloqade/native/stdlib/broadcast.py +246 -0
  41. bloqade/native/stdlib/simple.py +220 -0
  42. bloqade/native/upstream/__init__.py +4 -0
  43. bloqade/native/upstream/squin2native.py +79 -0
  44. bloqade/pyqrack/__init__.py +2 -2
  45. bloqade/pyqrack/base.py +7 -1
  46. bloqade/pyqrack/device.py +190 -4
  47. bloqade/pyqrack/native.py +49 -0
  48. bloqade/pyqrack/reg.py +6 -6
  49. bloqade/pyqrack/squin/gate/__init__.py +1 -0
  50. bloqade/pyqrack/squin/gate/gate.py +136 -0
  51. bloqade/pyqrack/squin/noise/native.py +120 -54
  52. bloqade/pyqrack/squin/qubit.py +39 -36
  53. bloqade/pyqrack/target.py +5 -4
  54. bloqade/pyqrack/task.py +114 -7
  55. bloqade/qasm2/_qasm_loading.py +3 -3
  56. bloqade/qasm2/dialects/core/address.py +21 -12
  57. bloqade/qasm2/dialects/expr/_emit.py +19 -8
  58. bloqade/qasm2/dialects/expr/stmts.py +7 -7
  59. bloqade/qasm2/dialects/noise/fidelity.py +4 -8
  60. bloqade/qasm2/dialects/noise/model.py +2 -1
  61. bloqade/qasm2/emit/base.py +16 -11
  62. bloqade/qasm2/emit/gate.py +11 -8
  63. bloqade/qasm2/emit/main.py +103 -3
  64. bloqade/qasm2/emit/target.py +9 -5
  65. bloqade/qasm2/groups.py +3 -2
  66. bloqade/qasm2/parse/lowering.py +0 -1
  67. bloqade/qasm2/passes/fold.py +14 -73
  68. bloqade/qasm2/passes/glob.py +2 -2
  69. bloqade/qasm2/passes/noise.py +1 -1
  70. bloqade/qasm2/passes/parallel.py +7 -5
  71. bloqade/qasm2/rewrite/__init__.py +0 -1
  72. bloqade/qasm2/rewrite/noise/heuristic_noise.py +7 -17
  73. bloqade/qasm2/rewrite/parallel_to_glob.py +28 -15
  74. bloqade/qasm2/rewrite/parallel_to_uop.py +2 -8
  75. bloqade/qasm2/rewrite/register.py +2 -2
  76. bloqade/qasm2/rewrite/uop_to_parallel.py +4 -2
  77. bloqade/qbraid/lowering.py +1 -0
  78. bloqade/qbraid/schema.py +2 -2
  79. bloqade/qubit/__init__.py +12 -0
  80. bloqade/qubit/_dialect.py +3 -0
  81. bloqade/qubit/_interface.py +49 -0
  82. bloqade/qubit/_prelude.py +45 -0
  83. bloqade/qubit/analysis/__init__.py +1 -0
  84. bloqade/qubit/analysis/address_impl.py +40 -0
  85. bloqade/qubit/stdlib/__init__.py +2 -0
  86. bloqade/qubit/stdlib/_new.py +34 -0
  87. bloqade/qubit/stdlib/broadcast.py +62 -0
  88. bloqade/qubit/stdlib/simple.py +59 -0
  89. bloqade/qubit/stmts.py +60 -0
  90. bloqade/rewrite/passes/__init__.py +6 -0
  91. bloqade/rewrite/passes/aggressive_unroll.py +103 -0
  92. bloqade/rewrite/passes/callgraph.py +116 -0
  93. bloqade/rewrite/passes/canonicalize_ilist.py +20 -14
  94. bloqade/rewrite/rules/split_ifs.py +18 -1
  95. bloqade/squin/__init__.py +47 -14
  96. bloqade/squin/analysis/__init__.py +0 -1
  97. bloqade/squin/analysis/schedule.py +10 -11
  98. bloqade/squin/gate/__init__.py +2 -0
  99. bloqade/squin/gate/_dialect.py +3 -0
  100. bloqade/squin/gate/_interface.py +98 -0
  101. bloqade/squin/gate/stmts.py +125 -0
  102. bloqade/squin/groups.py +5 -22
  103. bloqade/squin/noise/__init__.py +1 -10
  104. bloqade/squin/noise/_dialect.py +1 -1
  105. bloqade/squin/noise/_interface.py +45 -0
  106. bloqade/squin/noise/stmts.py +66 -28
  107. bloqade/squin/rewrite/U3_to_clifford.py +70 -51
  108. bloqade/squin/rewrite/__init__.py +0 -2
  109. bloqade/squin/rewrite/remove_dangling_qubits.py +2 -2
  110. bloqade/squin/rewrite/wrap_analysis.py +4 -35
  111. bloqade/squin/stdlib/__init__.py +0 -0
  112. bloqade/squin/stdlib/broadcast/__init__.py +34 -0
  113. bloqade/squin/stdlib/broadcast/_qubit.py +4 -0
  114. bloqade/squin/stdlib/broadcast/gate.py +260 -0
  115. bloqade/squin/stdlib/broadcast/noise.py +144 -0
  116. bloqade/squin/stdlib/simple/__init__.py +33 -0
  117. bloqade/squin/stdlib/simple/gate.py +242 -0
  118. bloqade/squin/stdlib/simple/noise.py +126 -0
  119. bloqade/stim/__init__.py +1 -0
  120. bloqade/stim/_wrappers.py +6 -0
  121. bloqade/stim/dialects/auxiliary/emit.py +19 -18
  122. bloqade/stim/dialects/collapse/emit_str.py +7 -8
  123. bloqade/stim/dialects/gate/emit.py +9 -10
  124. bloqade/stim/dialects/noise/emit.py +17 -13
  125. bloqade/stim/dialects/noise/stmts.py +5 -3
  126. bloqade/stim/emit/__init__.py +1 -0
  127. bloqade/stim/emit/impls.py +16 -0
  128. bloqade/stim/emit/stim_str.py +48 -31
  129. bloqade/stim/groups.py +12 -2
  130. bloqade/stim/parse/lowering.py +14 -17
  131. bloqade/stim/passes/__init__.py +3 -1
  132. bloqade/stim/passes/flatten.py +26 -0
  133. bloqade/stim/passes/simplify_ifs.py +16 -2
  134. bloqade/stim/passes/squin_to_stim.py +18 -60
  135. bloqade/stim/rewrite/__init__.py +3 -4
  136. bloqade/stim/rewrite/get_record_util.py +24 -0
  137. bloqade/stim/rewrite/ifs_to_stim.py +29 -31
  138. bloqade/stim/rewrite/qubit_to_stim.py +90 -41
  139. bloqade/stim/rewrite/set_detector_to_stim.py +68 -0
  140. bloqade/stim/rewrite/set_observable_to_stim.py +52 -0
  141. bloqade/stim/rewrite/squin_measure.py +11 -79
  142. bloqade/stim/rewrite/squin_noise.py +134 -108
  143. bloqade/stim/rewrite/util.py +5 -192
  144. bloqade/test_utils.py +1 -1
  145. bloqade/types.py +10 -0
  146. bloqade/validation/__init__.py +2 -0
  147. bloqade/validation/analysis/__init__.py +5 -0
  148. bloqade/validation/analysis/analysis.py +41 -0
  149. bloqade/validation/analysis/lattice.py +58 -0
  150. bloqade/validation/kernel_validation.py +77 -0
  151. {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.9.1.dist-info}/METADATA +5 -6
  152. bloqade_circuit-0.9.1.dist-info/RECORD +265 -0
  153. bloqade/pyqrack/squin/op.py +0 -166
  154. bloqade/pyqrack/squin/runtime.py +0 -535
  155. bloqade/pyqrack/squin/wire.py +0 -51
  156. bloqade/rewrite/rules/flatten_ilist.py +0 -51
  157. bloqade/rewrite/rules/inline_getitem_ilist.py +0 -31
  158. bloqade/squin/_typeinfer.py +0 -20
  159. bloqade/squin/analysis/address_impl.py +0 -71
  160. bloqade/squin/analysis/nsites/__init__.py +0 -9
  161. bloqade/squin/analysis/nsites/analysis.py +0 -50
  162. bloqade/squin/analysis/nsites/impls.py +0 -92
  163. bloqade/squin/analysis/nsites/lattice.py +0 -49
  164. bloqade/squin/cirq/__init__.py +0 -265
  165. bloqade/squin/cirq/emit/emit_circuit.py +0 -109
  166. bloqade/squin/cirq/emit/noise.py +0 -49
  167. bloqade/squin/cirq/emit/op.py +0 -125
  168. bloqade/squin/cirq/emit/qubit.py +0 -60
  169. bloqade/squin/cirq/emit/runtime.py +0 -242
  170. bloqade/squin/cirq/lowering.py +0 -440
  171. bloqade/squin/lowering.py +0 -54
  172. bloqade/squin/noise/_wrapper.py +0 -40
  173. bloqade/squin/noise/rewrite.py +0 -111
  174. bloqade/squin/op/__init__.py +0 -41
  175. bloqade/squin/op/_dialect.py +0 -3
  176. bloqade/squin/op/_wrapper.py +0 -121
  177. bloqade/squin/op/number.py +0 -5
  178. bloqade/squin/op/rewrite.py +0 -46
  179. bloqade/squin/op/stdlib.py +0 -62
  180. bloqade/squin/op/stmts.py +0 -276
  181. bloqade/squin/op/traits.py +0 -43
  182. bloqade/squin/op/types.py +0 -26
  183. bloqade/squin/qubit.py +0 -184
  184. bloqade/squin/rewrite/canonicalize.py +0 -60
  185. bloqade/squin/rewrite/desugar.py +0 -124
  186. bloqade/squin/types.py +0 -8
  187. bloqade/squin/wire.py +0 -201
  188. bloqade/stim/rewrite/wire_identity_elimination.py +0 -24
  189. bloqade/stim/rewrite/wire_to_stim.py +0 -57
  190. bloqade_circuit-0.6.2.dist-info/RECORD +0 -234
  191. {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.9.1.dist-info}/WHEEL +0 -0
  192. {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.9.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,8 +1,10 @@
1
- from . import noise as noise
1
+ from . import emit as emit, noise as noise, lowering as lowering
2
+ from .emit import emit_circuit as emit_circuit
3
+ from .lowering import load_circuit as load_circuit
2
4
  from .parallelize import (
3
5
  transpile as transpile,
4
6
  parallelize as parallelize,
5
- no_similarity as no_similarity,
7
+ remove_tags as remove_tags,
6
8
  auto_similarity as auto_similarity,
7
9
  block_similarity as block_similarity,
8
10
  moment_similarity as moment_similarity,
@@ -0,0 +1,3 @@
1
+ # NOTE: just to register methods
2
+ from . import gate as gate, noise as noise, qubit as qubit
3
+ from .base import emit_circuit as emit_circuit
@@ -0,0 +1,246 @@
1
+ from typing import Sequence
2
+ from warnings import warn
3
+ from dataclasses import field, dataclass
4
+
5
+ import cirq
6
+ from kirin import ir, types, interp
7
+ from kirin.emit import EmitABC, EmitFrame
8
+ from kirin.interp import MethodTable, impl
9
+ from kirin.dialects import py, func, ilist
10
+ from typing_extensions import Self
11
+
12
+ from bloqade.squin import kernel
13
+ from bloqade.rewrite.passes import AggressiveUnroll
14
+
15
+
16
+ def emit_circuit(
17
+ mt: ir.Method,
18
+ qubits: Sequence[cirq.Qid] | None = None,
19
+ circuit_qubits: Sequence[cirq.Qid] | None = None,
20
+ args: tuple = (),
21
+ ignore_returns: bool = False,
22
+ ) -> cirq.Circuit:
23
+ """Converts a squin.kernel method to a cirq.Circuit object.
24
+
25
+ Args:
26
+ mt (ir.Method): The kernel method from which to construct the circuit.
27
+
28
+ Keyword Args:
29
+ circuit_qubits (Sequence[cirq.Qid] | None):
30
+ A list of qubits to use as the qubits in the circuit. Defaults to None.
31
+ If this is None, then `cirq.LineQubit`s are inserted for every `squin.qalloc`
32
+ statement in the order they appear inside the kernel.
33
+ **Note**: If a list of qubits is provided, make sure that there is a sufficient
34
+ number of qubits for the resulting circuit.
35
+ args (tuple):
36
+ The arguments of the kernel function from which to emit a circuit.
37
+ ignore_returns (bool):
38
+ If `False`, emitting a circuit from a kernel that returns a value will error.
39
+ Set it to `True` in order to ignore the return value(s). Defaults to `False`.
40
+
41
+ ## Examples:
42
+
43
+ Here's a very basic example:
44
+
45
+ ```python
46
+ from bloqade import squin
47
+ from bloqade.cirq_utils import emit_circuit
48
+
49
+ @squin.kernel
50
+ def main():
51
+ q = squin.qalloc(2)
52
+ squin.h(q[0])
53
+ squin.cx(q[0], q[1])
54
+
55
+ circuit = emit_circuit(main)
56
+
57
+ print(circuit)
58
+ ```
59
+
60
+ You can also compose multiple kernels. Those are emitted as subcircuits within the "main" circuit.
61
+ Subkernels can accept arguments and return a value.
62
+
63
+ ```python
64
+ from bloqade import squin
65
+ from bloqade.cirq_utils import emit_circuit
66
+ from kirin.dialects import ilist
67
+ from typing import Literal
68
+ import cirq
69
+
70
+ @squin.kernel
71
+ def entangle(q: ilist.IList[squin.qubit.Qubit, Literal[2]]):
72
+ squin.h(q[0])
73
+ squin.cx(q[0], q[1])
74
+
75
+ @squin.kernel
76
+ def main():
77
+ q = squin.qalloc(2)
78
+ q2 = squin.qalloc(3)
79
+ squin.cx(q[1], q2[2])
80
+
81
+
82
+ # custom list of qubits on grid
83
+ qubits = [cirq.GridQubit(i, i+1) for i in range(5)]
84
+
85
+ circuit = emit_circuit(main, circuit_qubits=qubits)
86
+ print(circuit)
87
+
88
+ ```
89
+
90
+ We also passed in a custom list of qubits above. This allows you to provide a custom geometry
91
+ and manipulate the qubits in other circuits directly written in cirq as well.
92
+ """
93
+
94
+ if circuit_qubits is None and qubits is not None:
95
+ circuit_qubits = qubits
96
+ warn(
97
+ "The keyword argument `qubits` is deprecated. Use `circuit_qubits` instead."
98
+ )
99
+
100
+ if (
101
+ not ignore_returns
102
+ and isinstance(mt.code, func.Function)
103
+ and not mt.code.signature.output.is_subseteq(types.NoneType)
104
+ ):
105
+ raise interp.exceptions.InterpreterError(
106
+ "The method you are trying to convert to a circuit has a return value, but returning from a circuit is not supported."
107
+ " Set `ignore_returns = True` in order to simply ignore the return values and emit a circuit."
108
+ )
109
+
110
+ if len(args) != len(mt.args):
111
+ raise ValueError(
112
+ f"The method from which you're trying to emit a circuit takes {len(mt.args)} as input, but you passed in {len(args)} via the `args` keyword!"
113
+ )
114
+
115
+ emitter = EmitCirq(qubits=circuit_qubits)
116
+
117
+ symbol_op_trait = mt.code.get_trait(ir.SymbolOpInterface)
118
+ if (symbol_op_trait := mt.code.get_trait(ir.SymbolOpInterface)) is None:
119
+ raise interp.exceptions.InterpreterError(
120
+ "The method is not a symbol, cannot emit circuit!"
121
+ )
122
+
123
+ sym_name = symbol_op_trait.get_sym_name(mt.code).unwrap()
124
+
125
+ if (signature_trait := mt.code.get_trait(ir.HasSignature)) is None:
126
+ raise interp.exceptions.InterpreterError(
127
+ f"The method {sym_name} does not have a signature, cannot emit circuit!"
128
+ )
129
+
130
+ signature = signature_trait.get_signature(mt.code)
131
+ new_signature = func.Signature(inputs=(), output=signature.output)
132
+
133
+ callable_region = mt.callable_region.clone()
134
+ entry_block = callable_region.blocks[0]
135
+ args_ssa = list(entry_block.args)
136
+ first_stmt = entry_block.first_stmt
137
+
138
+ assert first_stmt is not None, "Method has no statements!"
139
+ if len(args_ssa) - 1 != len(args):
140
+ raise interp.exceptions.InterpreterError(
141
+ f"The method {sym_name} takes {len(args_ssa) - 1} arguments, but you passed in {len(args)} via the `args` keyword!"
142
+ )
143
+
144
+ for arg, arg_ssa in zip(args, args_ssa[1:], strict=True):
145
+ (value := py.Constant(arg)).insert_before(first_stmt)
146
+ arg_ssa.replace_by(value.result)
147
+ entry_block.args.delete(arg_ssa)
148
+
149
+ new_func = func.Function(
150
+ sym_name=sym_name, body=callable_region, signature=new_signature
151
+ )
152
+ mt_ = ir.Method(
153
+ dialects=mt.dialects,
154
+ code=new_func,
155
+ sym_name=sym_name,
156
+ )
157
+
158
+ AggressiveUnroll(mt_.dialects).fixpoint(mt_)
159
+ emitter.initialize()
160
+ emitter.run(mt_)
161
+ return emitter.circuit
162
+
163
+
164
+ @dataclass
165
+ class EmitCirqFrame(EmitFrame):
166
+ qubit_index: int = 0
167
+ qubits: Sequence[cirq.Qid] | None = None
168
+
169
+
170
+ def _default_kernel():
171
+ return kernel
172
+
173
+
174
+ @dataclass
175
+ class EmitCirq(EmitABC[EmitCirqFrame, cirq.Circuit]):
176
+ keys = ("emit.cirq", "emit.main")
177
+ dialects: ir.DialectGroup = field(default_factory=_default_kernel)
178
+ void = cirq.Circuit()
179
+ qubits: Sequence[cirq.Qid] | None = None
180
+ circuit: cirq.Circuit = field(default_factory=cirq.Circuit)
181
+
182
+ def initialize(self) -> Self:
183
+ return super().initialize()
184
+
185
+ def initialize_frame(
186
+ self, node: ir.Statement, *, has_parent_access: bool = False
187
+ ) -> EmitCirqFrame:
188
+ return EmitCirqFrame(
189
+ node, has_parent_access=has_parent_access, qubits=self.qubits
190
+ )
191
+
192
+ def reset(self):
193
+ self.circuit = cirq.Circuit()
194
+
195
+ def eval_fallback(self, frame: EmitCirqFrame, node: ir.Statement) -> tuple:
196
+ return tuple(None for _ in range(len(node.results)))
197
+
198
+
199
+ @func.dialect.register(key="emit.cirq")
200
+ class __FuncEmit(MethodTable):
201
+
202
+ @impl(func.Function)
203
+ def emit_func(self, emit: EmitCirq, frame: EmitCirqFrame, stmt: func.Function):
204
+ for block in stmt.body.blocks:
205
+ frame.current_block = block
206
+ for s in block.stmts:
207
+ frame.current_stmt = s
208
+ stmt_results = emit.frame_eval(frame, s)
209
+ if isinstance(stmt_results, tuple):
210
+ if len(stmt_results) != 0:
211
+ frame.set_values(s.results, stmt_results)
212
+ continue
213
+
214
+ return (emit.circuit,)
215
+
216
+ @impl(func.Invoke)
217
+ def emit_invoke(self, emit: EmitCirq, frame: EmitCirqFrame, stmt: func.Invoke):
218
+ raise interp.exceptions.InterpreterError(
219
+ "Function invokes should need to be inlined! "
220
+ "If you called the emit_circuit method, that should have happened, please report this issue."
221
+ )
222
+
223
+
224
+ @py.indexing.dialect.register(key="emit.cirq")
225
+ class __Concrete(interp.MethodTable):
226
+
227
+ @interp.impl(py.indexing.GetItem)
228
+ def getindex(self, interp, frame: interp.Frame, stmt: py.indexing.GetItem):
229
+ # NOTE: no support for indexing into single statements in cirq
230
+ return ()
231
+
232
+ @interp.impl(py.Constant)
233
+ def emit_constant(self, emit: EmitCirq, frame: EmitCirqFrame, stmt: py.Constant):
234
+ return (stmt.value.data,) # pyright: ignore[reportAttributeAccessIssue]
235
+
236
+
237
+ @ilist.dialect.register(key="emit.cirq")
238
+ class __IList(interp.MethodTable):
239
+ @interp.impl(ilist.New)
240
+ def new_ilist(
241
+ self,
242
+ emit: EmitCirq,
243
+ frame: interp.Frame,
244
+ stmt: ilist.New,
245
+ ):
246
+ return (ilist.IList(data=frame.get_values(stmt.values)),)
@@ -0,0 +1,104 @@
1
+ import math
2
+
3
+ import cirq
4
+ from kirin.interp import MethodTable, impl
5
+
6
+ from bloqade.squin import gate
7
+
8
+ from .base import EmitCirq, EmitCirqFrame
9
+
10
+
11
+ @gate.dialect.register(key="emit.cirq")
12
+ class __EmitCirqGateMethods(MethodTable):
13
+
14
+ @impl(gate.stmts.X)
15
+ @impl(gate.stmts.Y)
16
+ @impl(gate.stmts.Z)
17
+ @impl(gate.stmts.H)
18
+ def hermitian(
19
+ self, emit: EmitCirq, frame: EmitCirqFrame, stmt: gate.stmts.SingleQubitGate
20
+ ):
21
+ qubits = frame.get(stmt.qubits)
22
+ cirq_op = getattr(cirq, stmt.name.upper())
23
+ emit.circuit.append(cirq_op.on_each(qubits))
24
+ return ()
25
+
26
+ @impl(gate.stmts.S)
27
+ @impl(gate.stmts.T)
28
+ def unitary(
29
+ self,
30
+ emit: EmitCirq,
31
+ frame: EmitCirqFrame,
32
+ stmt: gate.stmts.SingleQubitNonHermitianGate,
33
+ ):
34
+ qubits = frame.get(stmt.qubits)
35
+ cirq_op = getattr(cirq, stmt.name.upper())
36
+ if stmt.adjoint:
37
+ cirq_op = cirq_op ** (-1)
38
+
39
+ emit.circuit.append(cirq_op.on_each(qubits))
40
+ return ()
41
+
42
+ @impl(gate.stmts.SqrtX)
43
+ @impl(gate.stmts.SqrtY)
44
+ def sqrt(
45
+ self,
46
+ emit: EmitCirq,
47
+ frame: EmitCirqFrame,
48
+ stmt: gate.stmts.SqrtX | gate.stmts.SqrtY,
49
+ ):
50
+ qubits = frame.get(stmt.qubits)
51
+
52
+ exponent = 0.5
53
+ if stmt.adjoint:
54
+ exponent *= -1
55
+
56
+ if isinstance(stmt, gate.stmts.SqrtX):
57
+ cirq_op = cirq.XPowGate(exponent=exponent)
58
+ else:
59
+ cirq_op = cirq.YPowGate(exponent=exponent)
60
+
61
+ emit.circuit.append(cirq_op.on_each(qubits))
62
+ return ()
63
+
64
+ @impl(gate.stmts.CX)
65
+ @impl(gate.stmts.CY)
66
+ @impl(gate.stmts.CZ)
67
+ def control(
68
+ self, emit: EmitCirq, frame: EmitCirqFrame, stmt: gate.stmts.ControlledGate
69
+ ):
70
+ controls = frame.get(stmt.controls)
71
+ targets = frame.get(stmt.targets)
72
+ cirq_op = getattr(cirq, stmt.name.upper())
73
+ cirq_qubits = [(ctrl, target) for ctrl, target in zip(controls, targets)]
74
+ emit.circuit.append(cirq_op.on_each(cirq_qubits))
75
+ return ()
76
+
77
+ @impl(gate.stmts.Rx)
78
+ @impl(gate.stmts.Ry)
79
+ @impl(gate.stmts.Rz)
80
+ def rot(self, emit: EmitCirq, frame: EmitCirqFrame, stmt: gate.stmts.RotationGate):
81
+ qubits = frame.get(stmt.qubits)
82
+
83
+ turns = frame.get(stmt.angle)
84
+ angle = turns * 2 * math.pi
85
+ cirq_op = getattr(cirq, stmt.name.title())(rads=angle)
86
+
87
+ emit.circuit.append(cirq_op.on_each(qubits))
88
+ return ()
89
+
90
+ @impl(gate.stmts.U3)
91
+ def u3(self, emit: EmitCirq, frame: EmitCirqFrame, stmt: gate.stmts.U3):
92
+ qubits = frame.get(stmt.qubits)
93
+
94
+ theta = frame.get(stmt.theta) * 2 * math.pi
95
+ phi = frame.get(stmt.phi) * 2 * math.pi
96
+ lam = frame.get(stmt.lam) * 2 * math.pi
97
+
98
+ emit.circuit.append(cirq.Rz(rads=lam).on_each(*qubits))
99
+
100
+ emit.circuit.append(cirq.Ry(rads=theta).on_each(*qubits))
101
+
102
+ emit.circuit.append(cirq.Rz(rads=phi).on_each(*qubits))
103
+
104
+ return ()
@@ -0,0 +1,90 @@
1
+ import cirq
2
+ from kirin.interp import MethodTable, impl
3
+
4
+ from bloqade.squin import noise
5
+
6
+ from .base import EmitCirq, EmitCirqFrame
7
+
8
+
9
+ @noise.dialect.register(key="emit.cirq")
10
+ class __EmitCirqNoiseMethods(MethodTable):
11
+
12
+ two_qubit_paulis = (
13
+ "IX",
14
+ "IY",
15
+ "IZ",
16
+ "XI",
17
+ "XX",
18
+ "XY",
19
+ "XZ",
20
+ "YI",
21
+ "YX",
22
+ "YY",
23
+ "YZ",
24
+ "ZI",
25
+ "ZX",
26
+ "ZY",
27
+ "ZZ",
28
+ )
29
+
30
+ @impl(noise.stmts.Depolarize)
31
+ def depolarize(
32
+ self, interp: EmitCirq, frame: EmitCirqFrame, stmt: noise.stmts.Depolarize
33
+ ):
34
+ p = frame.get(stmt.p)
35
+ qubits = frame.get(stmt.qubits)
36
+ cirfq_op = cirq.depolarize(p, n_qubits=1).on_each(qubits)
37
+ interp.circuit.append(cirfq_op)
38
+ return ()
39
+
40
+ @impl(noise.stmts.Depolarize2)
41
+ def depolarize2(
42
+ self, interp: EmitCirq, frame: EmitCirqFrame, stmt: noise.stmts.Depolarize2
43
+ ):
44
+ p = frame.get(stmt.p)
45
+ controls = frame.get(stmt.controls)
46
+ targets = frame.get(stmt.targets)
47
+ cirq_qubits = [(ctrl, target) for ctrl, target in zip(controls, targets)]
48
+ cirq_op = cirq.depolarize(p, n_qubits=2).on_each(cirq_qubits)
49
+ interp.circuit.append(cirq_op)
50
+ return ()
51
+
52
+ @impl(noise.stmts.SingleQubitPauliChannel)
53
+ def single_qubit_pauli_channel(
54
+ self,
55
+ interp: EmitCirq,
56
+ frame: EmitCirqFrame,
57
+ stmt: noise.stmts.SingleQubitPauliChannel,
58
+ ):
59
+ px = frame.get(stmt.px)
60
+ py = frame.get(stmt.py)
61
+ pz = frame.get(stmt.pz)
62
+ qubits = frame.get(stmt.qubits)
63
+
64
+ cirq_op = cirq.asymmetric_depolarize(px, py, pz).on_each(qubits)
65
+ interp.circuit.append(cirq_op)
66
+
67
+ return ()
68
+
69
+ @impl(noise.stmts.TwoQubitPauliChannel)
70
+ def two_qubit_pauli_channel(
71
+ self,
72
+ interp: EmitCirq,
73
+ frame: EmitCirqFrame,
74
+ stmt: noise.stmts.TwoQubitPauliChannel,
75
+ ):
76
+ ps = frame.get(stmt.probabilities)
77
+ error_probabilities = {
78
+ key: p for (key, p) in zip(self.two_qubit_paulis, ps) if p != 0
79
+ }
80
+
81
+ controls = frame.get(stmt.controls)
82
+ targets = frame.get(stmt.targets)
83
+ cirq_qubits = [(ctrl, target) for ctrl, target in zip(controls, targets)]
84
+
85
+ cirq_op = cirq.asymmetric_depolarize(
86
+ error_probabilities=error_probabilities
87
+ ).on_each(cirq_qubits)
88
+ interp.circuit.append(cirq_op)
89
+
90
+ return ()
@@ -0,0 +1,35 @@
1
+ import cirq
2
+ from kirin.interp import MethodTable, impl
3
+
4
+ from bloqade.qubit import stmts as qubit
5
+
6
+ from .base import EmitCirq, EmitCirqFrame
7
+
8
+
9
+ @qubit.dialect.register(key="emit.cirq")
10
+ class EmitCirqQubitMethods(MethodTable):
11
+ @impl(qubit.New)
12
+ def new(self, emit: EmitCirq, frame: EmitCirqFrame, stmt: qubit.New):
13
+ if frame.qubits is not None:
14
+ cirq_qubit = frame.qubits[frame.qubit_index]
15
+ else:
16
+ cirq_qubit = cirq.LineQubit(frame.qubit_index)
17
+
18
+ frame.qubit_index += 1
19
+ return (cirq_qubit,)
20
+
21
+ @impl(qubit.Measure)
22
+ def measure_qubit_list(
23
+ self, emit: EmitCirq, frame: EmitCirqFrame, stmt: qubit.Measure
24
+ ):
25
+ qbits = frame.get(stmt.qubits)
26
+ emit.circuit.append(cirq.measure(qbits))
27
+ return (emit.void,)
28
+
29
+ @impl(qubit.Reset)
30
+ def reset(self, emit: EmitCirq, frame: EmitCirqFrame, stmt: qubit.Reset):
31
+ qubits = frame.get(stmt.qubits)
32
+ emit.circuit.append(
33
+ cirq.ResetChannel().on_each(*qubits),
34
+ )
35
+ return ()