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.
- bloqade/analysis/address/__init__.py +8 -4
- bloqade/analysis/address/analysis.py +123 -33
- bloqade/analysis/address/impls.py +293 -90
- bloqade/analysis/address/lattice.py +209 -24
- bloqade/analysis/fidelity/analysis.py +11 -23
- bloqade/analysis/measure_id/__init__.py +4 -1
- bloqade/analysis/measure_id/analysis.py +29 -20
- bloqade/analysis/measure_id/impls.py +72 -31
- bloqade/annotate/__init__.py +6 -0
- bloqade/annotate/_dialect.py +3 -0
- bloqade/annotate/_interface.py +22 -0
- bloqade/annotate/stmts.py +29 -0
- bloqade/annotate/types.py +13 -0
- bloqade/cirq_utils/__init__.py +4 -2
- bloqade/cirq_utils/emit/__init__.py +3 -0
- bloqade/cirq_utils/emit/base.py +246 -0
- bloqade/cirq_utils/emit/gate.py +104 -0
- bloqade/cirq_utils/emit/noise.py +90 -0
- bloqade/cirq_utils/emit/qubit.py +35 -0
- bloqade/cirq_utils/lowering.py +660 -0
- bloqade/cirq_utils/noise/__init__.py +0 -2
- bloqade/cirq_utils/noise/_two_zone_utils.py +7 -15
- bloqade/cirq_utils/noise/model.py +151 -191
- bloqade/cirq_utils/noise/transform.py +2 -2
- bloqade/cirq_utils/parallelize.py +9 -6
- bloqade/gemini/__init__.py +1 -0
- bloqade/gemini/analysis/__init__.py +3 -0
- bloqade/gemini/analysis/logical_validation/__init__.py +1 -0
- bloqade/gemini/analysis/logical_validation/analysis.py +17 -0
- bloqade/gemini/analysis/logical_validation/impls.py +101 -0
- bloqade/gemini/groups.py +67 -0
- bloqade/native/__init__.py +23 -0
- bloqade/native/_prelude.py +45 -0
- bloqade/native/dialects/__init__.py +0 -0
- bloqade/native/dialects/gate/__init__.py +2 -0
- bloqade/native/dialects/gate/_dialect.py +3 -0
- bloqade/native/dialects/gate/_interface.py +32 -0
- bloqade/native/dialects/gate/stmts.py +31 -0
- bloqade/native/stdlib/__init__.py +0 -0
- bloqade/native/stdlib/broadcast.py +246 -0
- bloqade/native/stdlib/simple.py +220 -0
- bloqade/native/upstream/__init__.py +4 -0
- bloqade/native/upstream/squin2native.py +79 -0
- bloqade/pyqrack/__init__.py +2 -2
- bloqade/pyqrack/base.py +7 -1
- bloqade/pyqrack/device.py +190 -4
- bloqade/pyqrack/native.py +49 -0
- bloqade/pyqrack/reg.py +6 -6
- bloqade/pyqrack/squin/gate/__init__.py +1 -0
- bloqade/pyqrack/squin/gate/gate.py +136 -0
- bloqade/pyqrack/squin/noise/native.py +120 -54
- bloqade/pyqrack/squin/qubit.py +39 -36
- bloqade/pyqrack/target.py +5 -4
- bloqade/pyqrack/task.py +114 -7
- bloqade/qasm2/_qasm_loading.py +3 -3
- bloqade/qasm2/dialects/core/address.py +21 -12
- bloqade/qasm2/dialects/expr/_emit.py +19 -8
- bloqade/qasm2/dialects/expr/stmts.py +7 -7
- bloqade/qasm2/dialects/noise/fidelity.py +4 -8
- bloqade/qasm2/dialects/noise/model.py +2 -1
- bloqade/qasm2/emit/base.py +16 -11
- bloqade/qasm2/emit/gate.py +11 -8
- bloqade/qasm2/emit/main.py +103 -3
- bloqade/qasm2/emit/target.py +9 -5
- bloqade/qasm2/groups.py +3 -2
- bloqade/qasm2/parse/lowering.py +0 -1
- bloqade/qasm2/passes/fold.py +14 -73
- bloqade/qasm2/passes/glob.py +2 -2
- bloqade/qasm2/passes/noise.py +1 -1
- bloqade/qasm2/passes/parallel.py +7 -5
- bloqade/qasm2/rewrite/__init__.py +0 -1
- bloqade/qasm2/rewrite/noise/heuristic_noise.py +7 -17
- bloqade/qasm2/rewrite/parallel_to_glob.py +28 -15
- bloqade/qasm2/rewrite/parallel_to_uop.py +2 -8
- bloqade/qasm2/rewrite/register.py +2 -2
- bloqade/qasm2/rewrite/uop_to_parallel.py +4 -2
- bloqade/qbraid/lowering.py +1 -0
- bloqade/qbraid/schema.py +2 -2
- bloqade/qubit/__init__.py +12 -0
- bloqade/qubit/_dialect.py +3 -0
- bloqade/qubit/_interface.py +49 -0
- bloqade/qubit/_prelude.py +45 -0
- bloqade/qubit/analysis/__init__.py +1 -0
- bloqade/qubit/analysis/address_impl.py +40 -0
- bloqade/qubit/stdlib/__init__.py +2 -0
- bloqade/qubit/stdlib/_new.py +34 -0
- bloqade/qubit/stdlib/broadcast.py +62 -0
- bloqade/qubit/stdlib/simple.py +59 -0
- bloqade/qubit/stmts.py +60 -0
- bloqade/rewrite/passes/__init__.py +6 -0
- bloqade/rewrite/passes/aggressive_unroll.py +103 -0
- bloqade/rewrite/passes/callgraph.py +116 -0
- bloqade/rewrite/passes/canonicalize_ilist.py +20 -14
- bloqade/rewrite/rules/split_ifs.py +18 -1
- bloqade/squin/__init__.py +47 -14
- bloqade/squin/analysis/__init__.py +0 -1
- bloqade/squin/analysis/schedule.py +10 -11
- bloqade/squin/gate/__init__.py +2 -0
- bloqade/squin/gate/_dialect.py +3 -0
- bloqade/squin/gate/_interface.py +98 -0
- bloqade/squin/gate/stmts.py +125 -0
- bloqade/squin/groups.py +5 -22
- bloqade/squin/noise/__init__.py +1 -10
- bloqade/squin/noise/_dialect.py +1 -1
- bloqade/squin/noise/_interface.py +45 -0
- bloqade/squin/noise/stmts.py +66 -28
- bloqade/squin/rewrite/U3_to_clifford.py +70 -51
- bloqade/squin/rewrite/__init__.py +0 -2
- bloqade/squin/rewrite/remove_dangling_qubits.py +2 -2
- bloqade/squin/rewrite/wrap_analysis.py +4 -35
- bloqade/squin/stdlib/__init__.py +0 -0
- bloqade/squin/stdlib/broadcast/__init__.py +34 -0
- bloqade/squin/stdlib/broadcast/_qubit.py +4 -0
- bloqade/squin/stdlib/broadcast/gate.py +260 -0
- bloqade/squin/stdlib/broadcast/noise.py +144 -0
- bloqade/squin/stdlib/simple/__init__.py +33 -0
- bloqade/squin/stdlib/simple/gate.py +242 -0
- bloqade/squin/stdlib/simple/noise.py +126 -0
- bloqade/stim/__init__.py +1 -0
- bloqade/stim/_wrappers.py +6 -0
- bloqade/stim/dialects/auxiliary/emit.py +19 -18
- bloqade/stim/dialects/collapse/emit_str.py +7 -8
- bloqade/stim/dialects/gate/emit.py +9 -10
- bloqade/stim/dialects/noise/emit.py +17 -13
- bloqade/stim/dialects/noise/stmts.py +5 -3
- bloqade/stim/emit/__init__.py +1 -0
- bloqade/stim/emit/impls.py +16 -0
- bloqade/stim/emit/stim_str.py +48 -31
- bloqade/stim/groups.py +12 -2
- bloqade/stim/parse/lowering.py +14 -17
- bloqade/stim/passes/__init__.py +3 -1
- bloqade/stim/passes/flatten.py +26 -0
- bloqade/stim/passes/simplify_ifs.py +16 -2
- bloqade/stim/passes/squin_to_stim.py +18 -60
- bloqade/stim/rewrite/__init__.py +3 -4
- bloqade/stim/rewrite/get_record_util.py +24 -0
- bloqade/stim/rewrite/ifs_to_stim.py +29 -31
- bloqade/stim/rewrite/qubit_to_stim.py +90 -41
- bloqade/stim/rewrite/set_detector_to_stim.py +68 -0
- bloqade/stim/rewrite/set_observable_to_stim.py +52 -0
- bloqade/stim/rewrite/squin_measure.py +11 -79
- bloqade/stim/rewrite/squin_noise.py +134 -108
- bloqade/stim/rewrite/util.py +5 -192
- bloqade/test_utils.py +1 -1
- bloqade/types.py +10 -0
- bloqade/validation/__init__.py +2 -0
- bloqade/validation/analysis/__init__.py +5 -0
- bloqade/validation/analysis/analysis.py +41 -0
- bloqade/validation/analysis/lattice.py +58 -0
- bloqade/validation/kernel_validation.py +77 -0
- {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.9.1.dist-info}/METADATA +5 -6
- bloqade_circuit-0.9.1.dist-info/RECORD +265 -0
- bloqade/pyqrack/squin/op.py +0 -166
- bloqade/pyqrack/squin/runtime.py +0 -535
- bloqade/pyqrack/squin/wire.py +0 -51
- bloqade/rewrite/rules/flatten_ilist.py +0 -51
- bloqade/rewrite/rules/inline_getitem_ilist.py +0 -31
- bloqade/squin/_typeinfer.py +0 -20
- bloqade/squin/analysis/address_impl.py +0 -71
- bloqade/squin/analysis/nsites/__init__.py +0 -9
- bloqade/squin/analysis/nsites/analysis.py +0 -50
- bloqade/squin/analysis/nsites/impls.py +0 -92
- bloqade/squin/analysis/nsites/lattice.py +0 -49
- bloqade/squin/cirq/__init__.py +0 -265
- bloqade/squin/cirq/emit/emit_circuit.py +0 -109
- bloqade/squin/cirq/emit/noise.py +0 -49
- bloqade/squin/cirq/emit/op.py +0 -125
- bloqade/squin/cirq/emit/qubit.py +0 -60
- bloqade/squin/cirq/emit/runtime.py +0 -242
- bloqade/squin/cirq/lowering.py +0 -440
- bloqade/squin/lowering.py +0 -54
- bloqade/squin/noise/_wrapper.py +0 -40
- bloqade/squin/noise/rewrite.py +0 -111
- bloqade/squin/op/__init__.py +0 -41
- bloqade/squin/op/_dialect.py +0 -3
- bloqade/squin/op/_wrapper.py +0 -121
- bloqade/squin/op/number.py +0 -5
- bloqade/squin/op/rewrite.py +0 -46
- bloqade/squin/op/stdlib.py +0 -62
- bloqade/squin/op/stmts.py +0 -276
- bloqade/squin/op/traits.py +0 -43
- bloqade/squin/op/types.py +0 -26
- bloqade/squin/qubit.py +0 -184
- bloqade/squin/rewrite/canonicalize.py +0 -60
- bloqade/squin/rewrite/desugar.py +0 -124
- bloqade/squin/types.py +0 -8
- bloqade/squin/wire.py +0 -201
- bloqade/stim/rewrite/wire_identity_elimination.py +0 -24
- bloqade/stim/rewrite/wire_to_stim.py +0 -57
- bloqade_circuit-0.6.2.dist-info/RECORD +0 -234
- {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.9.1.dist-info}/WHEEL +0 -0
- {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.9.1.dist-info}/licenses/LICENSE +0 -0
bloqade/cirq_utils/__init__.py
CHANGED
|
@@ -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
|
-
|
|
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,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 ()
|