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
|
@@ -0,0 +1,660 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from dataclasses import field, dataclass
|
|
3
|
+
|
|
4
|
+
import cirq
|
|
5
|
+
from kirin import ir, types, lowering
|
|
6
|
+
from kirin.rewrite import Walk, CFGCompactify
|
|
7
|
+
from kirin.dialects import py, scf, func, ilist
|
|
8
|
+
|
|
9
|
+
from bloqade import qubit
|
|
10
|
+
from bloqade.squin import gate, noise, kernel, qalloc
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def load_circuit(
|
|
14
|
+
circuit: cirq.Circuit,
|
|
15
|
+
kernel_name: str = "main",
|
|
16
|
+
dialects: ir.DialectGroup = kernel,
|
|
17
|
+
register_as_argument: bool = False,
|
|
18
|
+
return_register: bool = False,
|
|
19
|
+
register_argument_name: str = "q",
|
|
20
|
+
globals: dict[str, Any] | None = None,
|
|
21
|
+
file: str | None = None,
|
|
22
|
+
lineno_offset: int = 0,
|
|
23
|
+
col_offset: int = 0,
|
|
24
|
+
compactify: bool = True,
|
|
25
|
+
):
|
|
26
|
+
"""Converts a cirq.Circuit object into a squin kernel.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
circuit (cirq.Circuit): The circuit to load.
|
|
30
|
+
|
|
31
|
+
Keyword Args:
|
|
32
|
+
kernel_name (str): The name of the kernel to load. Defaults to "main".
|
|
33
|
+
dialects (ir.DialectGroup | None): The dialects to use. Defaults to `squin.kernel`.
|
|
34
|
+
register_as_argument (bool): Determine whether the resulting kernel function should accept
|
|
35
|
+
a single `ilist.IList[Qubit, Any]` argument that is a list of qubits used within the
|
|
36
|
+
function. This allows you to compose kernel functions generated from circuits.
|
|
37
|
+
Defaults to `False`.
|
|
38
|
+
return_register (bool): Determine whether the resulting kernel functionr returns a
|
|
39
|
+
single value of type `ilist.IList[Qubit, Any]` that is the list of qubits used
|
|
40
|
+
in the kernel function. Useful when you want to compose multiple kernel functions
|
|
41
|
+
generated from circuits. Defaults to `False`.
|
|
42
|
+
register_argument_name (str): The name of the argument that represents the qubit register.
|
|
43
|
+
Only used when `register_as_argument=True`. Defaults to "q".
|
|
44
|
+
globals (dict[str, Any] | None): The global variables to use. Defaults to None.
|
|
45
|
+
file (str | None): The file name for error reporting. Defaults to None.
|
|
46
|
+
lineno_offset (int): The line number offset for error reporting. Defaults to 0.
|
|
47
|
+
col_offset (int): The column number offset for error reporting. Defaults to 0.
|
|
48
|
+
compactify (bool): Whether to compactify the output. Defaults to True.
|
|
49
|
+
|
|
50
|
+
## Usage Examples:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
# from cirq's "hello qubit" example
|
|
54
|
+
import cirq
|
|
55
|
+
from bloqade.cirq_utils import load_circuit
|
|
56
|
+
|
|
57
|
+
# Pick a qubit.
|
|
58
|
+
qubit = cirq.GridQubit(0, 0)
|
|
59
|
+
|
|
60
|
+
# Create a circuit.
|
|
61
|
+
circuit = cirq.Circuit(
|
|
62
|
+
cirq.X(qubit)**0.5, # Square root of NOT.
|
|
63
|
+
cirq.measure(qubit, key='m') # Measurement.
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# load the circuit as squin
|
|
67
|
+
main = load_circuit(circuit)
|
|
68
|
+
|
|
69
|
+
# print the resulting IR
|
|
70
|
+
main.print()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
You can also compose kernel functions generated from circuits by passing in
|
|
74
|
+
and / or returning the respective quantum registers:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
import cirq
|
|
78
|
+
from bloqade.cirq_utils import load_circuit
|
|
79
|
+
from bloqade import squin
|
|
80
|
+
|
|
81
|
+
q = cirq.LineQubit.range(2)
|
|
82
|
+
circuit = cirq.Circuit(cirq.H(q[0]), cirq.CX(*q))
|
|
83
|
+
|
|
84
|
+
get_entangled_qubits = load_circuit(
|
|
85
|
+
circuit, return_register=True, kernel_name="get_entangled_qubits"
|
|
86
|
+
)
|
|
87
|
+
get_entangled_qubits.print()
|
|
88
|
+
|
|
89
|
+
entangle_qubits = load_circuit(
|
|
90
|
+
circuit, register_as_argument=True, kernel_name="entangle_qubits"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
@squin.kernel
|
|
94
|
+
def main():
|
|
95
|
+
qreg = get_entangled_qubits()
|
|
96
|
+
qreg2 = squin.qalloc(1)
|
|
97
|
+
entangle_qubits([qreg[1], qreg2[0]])
|
|
98
|
+
return squin.qubit.measure(qreg2)
|
|
99
|
+
```
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
target = Squin(dialects, circuit)
|
|
103
|
+
body = target.run(
|
|
104
|
+
circuit,
|
|
105
|
+
source=str(circuit), # TODO: proper source string
|
|
106
|
+
file=file,
|
|
107
|
+
globals=globals,
|
|
108
|
+
lineno_offset=lineno_offset,
|
|
109
|
+
col_offset=col_offset,
|
|
110
|
+
compactify=compactify,
|
|
111
|
+
register_as_argument=register_as_argument,
|
|
112
|
+
register_argument_name=register_argument_name,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if return_register:
|
|
116
|
+
return_value = target.qreg
|
|
117
|
+
else:
|
|
118
|
+
return_value = func.ConstantNone()
|
|
119
|
+
body.blocks[0].stmts.append(return_value)
|
|
120
|
+
|
|
121
|
+
return_node = func.Return(value_or_stmt=return_value)
|
|
122
|
+
body.blocks[0].stmts.append(return_node)
|
|
123
|
+
|
|
124
|
+
self_arg_name = kernel_name + "_self"
|
|
125
|
+
arg_names = [self_arg_name]
|
|
126
|
+
if register_as_argument:
|
|
127
|
+
args = (target.qreg.type,)
|
|
128
|
+
arg_names.append(register_argument_name)
|
|
129
|
+
else:
|
|
130
|
+
args = ()
|
|
131
|
+
|
|
132
|
+
# NOTE: add _self as argument; need to know signature before so do it after lowering
|
|
133
|
+
signature = func.Signature(args, return_node.value.type)
|
|
134
|
+
body.blocks[0].args.insert_from(
|
|
135
|
+
0,
|
|
136
|
+
types.Generic(ir.Method, types.Tuple.where(signature.inputs), signature.output),
|
|
137
|
+
self_arg_name,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
code = func.Function(
|
|
141
|
+
sym_name=kernel_name,
|
|
142
|
+
signature=signature,
|
|
143
|
+
body=body,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
mt = ir.Method(
|
|
147
|
+
sym_name=kernel_name,
|
|
148
|
+
arg_names=arg_names,
|
|
149
|
+
dialects=dialects,
|
|
150
|
+
code=code,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
assert (run_pass := kernel.run_pass) is not None
|
|
154
|
+
run_pass(mt, typeinfer=True)
|
|
155
|
+
|
|
156
|
+
return mt
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
CirqNode = (
|
|
160
|
+
cirq.Circuit
|
|
161
|
+
| cirq.FrozenCircuit
|
|
162
|
+
| cirq.Moment
|
|
163
|
+
| cirq.Gate
|
|
164
|
+
| cirq.Qid
|
|
165
|
+
| cirq.Operation
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
DecomposeNode = (
|
|
169
|
+
cirq.SwapPowGate
|
|
170
|
+
| cirq.ISwapPowGate
|
|
171
|
+
| cirq.PhasedXPowGate
|
|
172
|
+
| cirq.PhasedXZGate
|
|
173
|
+
| cirq.CSwapGate
|
|
174
|
+
| cirq.XXPowGate
|
|
175
|
+
| cirq.YYPowGate
|
|
176
|
+
| cirq.CCXPowGate
|
|
177
|
+
| cirq.CCZPowGate
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@dataclass
|
|
182
|
+
class Squin(lowering.LoweringABC[cirq.Circuit]):
|
|
183
|
+
"""Lower a cirq.Circuit object to a squin kernel"""
|
|
184
|
+
|
|
185
|
+
circuit: cirq.Circuit
|
|
186
|
+
qreg: ir.SSAValue = field(init=False)
|
|
187
|
+
qreg_index: dict[cirq.Qid, int] = field(init=False, default_factory=dict)
|
|
188
|
+
next_qreg_index: int = field(init=False, default=0)
|
|
189
|
+
|
|
190
|
+
two_qubit_paulis = (
|
|
191
|
+
"IX",
|
|
192
|
+
"IY",
|
|
193
|
+
"IZ",
|
|
194
|
+
"XI",
|
|
195
|
+
"XX",
|
|
196
|
+
"XY",
|
|
197
|
+
"XZ",
|
|
198
|
+
"YI",
|
|
199
|
+
"YX",
|
|
200
|
+
"YY",
|
|
201
|
+
"YZ",
|
|
202
|
+
"ZI",
|
|
203
|
+
"ZX",
|
|
204
|
+
"ZY",
|
|
205
|
+
"ZZ",
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
def __post_init__(self):
|
|
209
|
+
# TODO: sort by cirq ordering
|
|
210
|
+
qbits = sorted(self.circuit.all_qubits())
|
|
211
|
+
self.qreg_index = {qid: idx for (idx, qid) in enumerate(qbits)}
|
|
212
|
+
|
|
213
|
+
def lower_qubit_getindex(self, state: lowering.State[cirq.Circuit], qid: cirq.Qid):
|
|
214
|
+
index = self.qreg_index[qid]
|
|
215
|
+
index_ssa = state.current_frame.push(py.Constant(index)).result
|
|
216
|
+
qbit_getitem = state.current_frame.push(py.GetItem(self.qreg, index_ssa))
|
|
217
|
+
return qbit_getitem.result
|
|
218
|
+
|
|
219
|
+
def lower_qubit_getindices(
|
|
220
|
+
self, state: lowering.State[cirq.Circuit], qids: tuple[cirq.Qid, ...]
|
|
221
|
+
):
|
|
222
|
+
qbits_getitem = [self.lower_qubit_getindex(state, qid) for qid in qids]
|
|
223
|
+
qbits = state.current_frame.push(ilist.New(values=qbits_getitem))
|
|
224
|
+
return qbits.result
|
|
225
|
+
|
|
226
|
+
def run(
|
|
227
|
+
self,
|
|
228
|
+
stmt: cirq.Circuit,
|
|
229
|
+
*,
|
|
230
|
+
source: str | None = None,
|
|
231
|
+
globals: dict[str, Any] | None = None,
|
|
232
|
+
file: str | None = None,
|
|
233
|
+
lineno_offset: int = 0,
|
|
234
|
+
col_offset: int = 0,
|
|
235
|
+
compactify: bool = True,
|
|
236
|
+
register_as_argument: bool = False,
|
|
237
|
+
register_argument_name: str = "q",
|
|
238
|
+
) -> ir.Region:
|
|
239
|
+
|
|
240
|
+
state = lowering.State(
|
|
241
|
+
self,
|
|
242
|
+
file=file,
|
|
243
|
+
lineno_offset=lineno_offset,
|
|
244
|
+
col_offset=col_offset,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
with state.frame([stmt], globals=globals, finalize_next=False) as frame:
|
|
248
|
+
|
|
249
|
+
# NOTE: need a register of qubits before lowering statements
|
|
250
|
+
if register_as_argument:
|
|
251
|
+
# NOTE: register as argument to the kernel; we have freedom of choice for the name here
|
|
252
|
+
frame.curr_block.args.append_from(
|
|
253
|
+
ilist.IListType[qubit.QubitType, types.Any],
|
|
254
|
+
name=register_argument_name,
|
|
255
|
+
)
|
|
256
|
+
self.qreg = frame.curr_block.args[0]
|
|
257
|
+
else:
|
|
258
|
+
# NOTE: create a new register of appropriate size
|
|
259
|
+
n_qubits = len(self.qreg_index)
|
|
260
|
+
n = frame.push(py.Constant(n_qubits))
|
|
261
|
+
self.qreg = frame.push(func.Invoke((n.result,), callee=qalloc)).result
|
|
262
|
+
|
|
263
|
+
self.visit(state, stmt)
|
|
264
|
+
|
|
265
|
+
if compactify:
|
|
266
|
+
Walk(CFGCompactify()).rewrite(frame.curr_region)
|
|
267
|
+
|
|
268
|
+
region = frame.curr_region
|
|
269
|
+
|
|
270
|
+
return region
|
|
271
|
+
|
|
272
|
+
def visit(
|
|
273
|
+
self, state: lowering.State[cirq.Circuit], node: CirqNode
|
|
274
|
+
) -> lowering.Result:
|
|
275
|
+
name = node.__class__.__name__
|
|
276
|
+
return getattr(self, f"visit_{name}", self.generic_visit)(state, node)
|
|
277
|
+
|
|
278
|
+
def generic_visit(self, state: lowering.State[cirq.Circuit], node: CirqNode):
|
|
279
|
+
if isinstance(node, CirqNode):
|
|
280
|
+
raise lowering.BuildError(
|
|
281
|
+
f"Cannot lower {node.__class__.__name__} node: {node}"
|
|
282
|
+
)
|
|
283
|
+
raise lowering.BuildError(f"Cannot lower {node}")
|
|
284
|
+
|
|
285
|
+
# return self.visit_Operation(state, node)
|
|
286
|
+
|
|
287
|
+
def lower_literal(self, state: lowering.State[cirq.Circuit], value) -> ir.SSAValue:
|
|
288
|
+
raise lowering.BuildError("Literals not supported in cirq circuit")
|
|
289
|
+
|
|
290
|
+
def lower_global(
|
|
291
|
+
self, state: lowering.State[cirq.Circuit], node: CirqNode
|
|
292
|
+
) -> lowering.LoweringABC.Result:
|
|
293
|
+
raise lowering.BuildError("Literals not supported in cirq circuit")
|
|
294
|
+
|
|
295
|
+
def visit_Circuit(
|
|
296
|
+
self,
|
|
297
|
+
state: lowering.State[cirq.Circuit],
|
|
298
|
+
node: cirq.Circuit | cirq.FrozenCircuit,
|
|
299
|
+
) -> lowering.Result:
|
|
300
|
+
for moment in node:
|
|
301
|
+
self.visit_Moment(state, moment)
|
|
302
|
+
|
|
303
|
+
def visit_Moment(
|
|
304
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.Moment
|
|
305
|
+
) -> lowering.Result:
|
|
306
|
+
for op_ in node.operations:
|
|
307
|
+
self.visit(state, op_)
|
|
308
|
+
|
|
309
|
+
def visit_GateOperation(
|
|
310
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation
|
|
311
|
+
):
|
|
312
|
+
if isinstance(node.gate, DecomposeNode):
|
|
313
|
+
# NOTE: easier to decompose these, but for that we need the qubits too,
|
|
314
|
+
# so we need to do this within this method
|
|
315
|
+
for subnode in cirq.decompose_once(node):
|
|
316
|
+
self.visit(state, subnode)
|
|
317
|
+
return
|
|
318
|
+
|
|
319
|
+
# NOTE: just forward to the appropriate method by getting the name
|
|
320
|
+
name = node.gate.__class__.__name__
|
|
321
|
+
return getattr(self, f"visit_{name}", self.generic_visit)(state, node)
|
|
322
|
+
|
|
323
|
+
def visit_TaggedOperation(
|
|
324
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.TaggedOperation
|
|
325
|
+
):
|
|
326
|
+
return self.visit(state, node.untagged)
|
|
327
|
+
|
|
328
|
+
def visit_ClassicallyControlledOperation(
|
|
329
|
+
self,
|
|
330
|
+
state: lowering.State[cirq.Circuit],
|
|
331
|
+
node: cirq.ClassicallyControlledOperation,
|
|
332
|
+
):
|
|
333
|
+
conditions: list[ir.SSAValue] = []
|
|
334
|
+
for outcome in node.classical_controls:
|
|
335
|
+
key = outcome.key
|
|
336
|
+
if isinstance(key, cirq.MeasurementKey):
|
|
337
|
+
key = key.name
|
|
338
|
+
measurement_outcome = state.current_frame.defs[key]
|
|
339
|
+
|
|
340
|
+
if measurement_outcome.type.is_subseteq(ilist.IListType):
|
|
341
|
+
# NOTE: there is currently no convenient ilist.any method, so we need to use foldl
|
|
342
|
+
# with a simple function that just does an or
|
|
343
|
+
|
|
344
|
+
def bool_op_or(x: bool, y: bool) -> bool:
|
|
345
|
+
return x or y
|
|
346
|
+
|
|
347
|
+
f_code = state.current_frame.push(
|
|
348
|
+
lowering.Python(self.dialects).python_function(bool_op_or)
|
|
349
|
+
)
|
|
350
|
+
fn = ir.Method(
|
|
351
|
+
mod=None,
|
|
352
|
+
py_func=bool_op_or,
|
|
353
|
+
sym_name="bool_op_or",
|
|
354
|
+
arg_names=[],
|
|
355
|
+
dialects=self.dialects,
|
|
356
|
+
code=f_code,
|
|
357
|
+
)
|
|
358
|
+
f_const = state.current_frame.push(py.constant.Constant(fn))
|
|
359
|
+
init_val = state.current_frame.push(py.Constant(False)).result
|
|
360
|
+
condition = state.current_frame.push(
|
|
361
|
+
ilist.Foldl(f_const.result, measurement_outcome, init=init_val)
|
|
362
|
+
).result
|
|
363
|
+
else:
|
|
364
|
+
condition = measurement_outcome
|
|
365
|
+
|
|
366
|
+
conditions.append(condition)
|
|
367
|
+
|
|
368
|
+
if len(conditions) == 1:
|
|
369
|
+
condition = conditions[0]
|
|
370
|
+
else:
|
|
371
|
+
condition = state.current_frame.push(
|
|
372
|
+
py.boolop.And(conditions[0], conditions[1])
|
|
373
|
+
).result
|
|
374
|
+
for next_cond in conditions[2:]:
|
|
375
|
+
condition = state.current_frame.push(
|
|
376
|
+
py.boolop.And(condition, next_cond)
|
|
377
|
+
).result
|
|
378
|
+
|
|
379
|
+
then_stmt = self.visit(state, node.without_classical_controls())
|
|
380
|
+
|
|
381
|
+
assert isinstance(
|
|
382
|
+
then_stmt, ir.Statement
|
|
383
|
+
), f"Expected operation of classically controlled node {node} to be lowered to a statement, got type {type(then_stmt)}. \
|
|
384
|
+
Please report this issue!"
|
|
385
|
+
|
|
386
|
+
# NOTE: remove stmt from parent block
|
|
387
|
+
then_stmt.detach()
|
|
388
|
+
then_body = ir.Block((then_stmt,))
|
|
389
|
+
then_body.args.append_from(types.Bool, name="cond")
|
|
390
|
+
then_body.stmts.append(scf.Yield())
|
|
391
|
+
|
|
392
|
+
else_body = ir.Block(())
|
|
393
|
+
else_body.args.append_from(types.Bool, name="cond")
|
|
394
|
+
else_body.stmts.append(scf.Yield())
|
|
395
|
+
|
|
396
|
+
return state.current_frame.push(
|
|
397
|
+
scf.IfElse(condition, then_body=then_body, else_body=else_body)
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
def visit_MeasurementGate(
|
|
401
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation
|
|
402
|
+
):
|
|
403
|
+
qubits = self.lower_qubit_getindices(state, node.qubits)
|
|
404
|
+
stmt = state.current_frame.push(qubit.stmts.Measure(qubits))
|
|
405
|
+
|
|
406
|
+
# NOTE: add for classically controlled lowering
|
|
407
|
+
key = node.gate.key
|
|
408
|
+
if isinstance(key, cirq.MeasurementKey):
|
|
409
|
+
key = key.name
|
|
410
|
+
state.current_frame.defs[key] = stmt.result
|
|
411
|
+
|
|
412
|
+
return stmt
|
|
413
|
+
|
|
414
|
+
def visit_SingleQubitPauliStringGateOperation(
|
|
415
|
+
self,
|
|
416
|
+
state: lowering.State[cirq.Circuit],
|
|
417
|
+
node: cirq.SingleQubitPauliStringGateOperation,
|
|
418
|
+
):
|
|
419
|
+
if isinstance(node.pauli, cirq.IdentityGate):
|
|
420
|
+
# TODO: do we need an identity gate in gate?
|
|
421
|
+
return
|
|
422
|
+
|
|
423
|
+
qargs = self.lower_qubit_getindices(state, (node.qubit,))
|
|
424
|
+
match node.pauli:
|
|
425
|
+
case cirq.X:
|
|
426
|
+
gate_stmt = gate.stmts.X
|
|
427
|
+
case cirq.Y:
|
|
428
|
+
gate_stmt = gate.stmts.Y
|
|
429
|
+
case cirq.Z:
|
|
430
|
+
gate_stmt = gate.stmts.Z
|
|
431
|
+
case _:
|
|
432
|
+
raise lowering.BuildError(f"Unexpected Pauli operation {node.pauli}")
|
|
433
|
+
|
|
434
|
+
return state.current_frame.push(gate_stmt(qargs))
|
|
435
|
+
|
|
436
|
+
def visit_HPowGate(self, state: lowering.State[cirq.Circuit], node: cirq.HPowGate):
|
|
437
|
+
qargs = self.lower_qubit_getindices(state, node.qubits)
|
|
438
|
+
|
|
439
|
+
if node.gate.exponent % 2 == 1:
|
|
440
|
+
return state.current_frame.push(gate.stmts.H(qargs))
|
|
441
|
+
|
|
442
|
+
# NOTE: decompose into products of paulis for arbitrary exponents according to _decompose_ method
|
|
443
|
+
for subnode in cirq.decompose_once(node):
|
|
444
|
+
self.visit(state, subnode)
|
|
445
|
+
|
|
446
|
+
def visit_XPowGate(
|
|
447
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation
|
|
448
|
+
):
|
|
449
|
+
qargs = self.lower_qubit_getindices(state, node.qubits)
|
|
450
|
+
if node.gate.exponent % 2 == 1:
|
|
451
|
+
return state.current_frame.push(gate.stmts.X(qargs))
|
|
452
|
+
|
|
453
|
+
angle = state.current_frame.push(py.Constant(0.5 * node.gate.exponent))
|
|
454
|
+
return state.current_frame.push(gate.stmts.Rx(angle.result, qargs))
|
|
455
|
+
|
|
456
|
+
def visit_YPowGate(
|
|
457
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation
|
|
458
|
+
):
|
|
459
|
+
qargs = self.lower_qubit_getindices(state, node.qubits)
|
|
460
|
+
if node.gate.exponent % 2 == 1:
|
|
461
|
+
return state.current_frame.push(gate.stmts.Y(qargs))
|
|
462
|
+
|
|
463
|
+
angle = state.current_frame.push(py.Constant(0.5 * node.gate.exponent))
|
|
464
|
+
return state.current_frame.push(gate.stmts.Ry(angle.result, qargs))
|
|
465
|
+
|
|
466
|
+
def visit_ZPowGate(
|
|
467
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation
|
|
468
|
+
):
|
|
469
|
+
qargs = self.lower_qubit_getindices(state, node.qubits)
|
|
470
|
+
|
|
471
|
+
if abs(node.gate.exponent) == 0.5:
|
|
472
|
+
adjoint = node.gate.exponent < 0
|
|
473
|
+
return state.current_frame.push(gate.stmts.S(adjoint=adjoint, qubits=qargs))
|
|
474
|
+
|
|
475
|
+
if abs(node.gate.exponent) == 0.25:
|
|
476
|
+
adjoint = node.gate.exponent < 0
|
|
477
|
+
return state.current_frame.push(gate.stmts.T(adjoint=adjoint, qubits=qargs))
|
|
478
|
+
|
|
479
|
+
if node.gate.exponent % 2 == 1:
|
|
480
|
+
return state.current_frame.push(gate.stmts.Z(qubits=qargs))
|
|
481
|
+
|
|
482
|
+
angle = state.current_frame.push(py.Constant(0.5 * node.gate.exponent))
|
|
483
|
+
return state.current_frame.push(gate.stmts.Rz(angle.result, qargs))
|
|
484
|
+
|
|
485
|
+
def visit_Rx(self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation):
|
|
486
|
+
qargs = self.lower_qubit_getindices(state, node.qubits)
|
|
487
|
+
angle = state.current_frame.push(py.Constant(value=0.5 * node.gate.exponent))
|
|
488
|
+
return state.current_frame.push(gate.stmts.Rx(angle.result, qargs))
|
|
489
|
+
|
|
490
|
+
def visit_Ry(self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation):
|
|
491
|
+
qargs = self.lower_qubit_getindices(state, node.qubits)
|
|
492
|
+
angle = state.current_frame.push(py.Constant(value=0.5 * node.gate.exponent))
|
|
493
|
+
return state.current_frame.push(gate.stmts.Ry(angle.result, qargs))
|
|
494
|
+
|
|
495
|
+
def visit_Rz(self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation):
|
|
496
|
+
qargs = self.lower_qubit_getindices(state, node.qubits)
|
|
497
|
+
angle = state.current_frame.push(py.Constant(value=0.5 * node.gate.exponent))
|
|
498
|
+
return state.current_frame.push(gate.stmts.Rz(angle.result, qargs))
|
|
499
|
+
|
|
500
|
+
def visit_CXPowGate(
|
|
501
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation
|
|
502
|
+
):
|
|
503
|
+
if node.gate.exponent % 2 == 0:
|
|
504
|
+
return
|
|
505
|
+
|
|
506
|
+
if node.gate.exponent % 2 != 1:
|
|
507
|
+
raise lowering.BuildError("Exponents of CX gate are not supported!")
|
|
508
|
+
|
|
509
|
+
control, target = node.qubits
|
|
510
|
+
control_qarg = self.lower_qubit_getindices(state, (control,))
|
|
511
|
+
target_qarg = self.lower_qubit_getindices(state, (target,))
|
|
512
|
+
return state.current_frame.push(
|
|
513
|
+
gate.stmts.CX(controls=control_qarg, targets=target_qarg)
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
def visit_CZPowGate(
|
|
517
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation
|
|
518
|
+
):
|
|
519
|
+
if node.gate.exponent % 2 == 0:
|
|
520
|
+
return
|
|
521
|
+
|
|
522
|
+
if node.gate.exponent % 2 != 1:
|
|
523
|
+
raise lowering.BuildError("Exponents of CZ gate are not supported!")
|
|
524
|
+
|
|
525
|
+
control, target = node.qubits
|
|
526
|
+
control_qarg = self.lower_qubit_getindices(state, (control,))
|
|
527
|
+
target_qarg = self.lower_qubit_getindices(state, (target,))
|
|
528
|
+
return state.current_frame.push(
|
|
529
|
+
gate.stmts.CZ(controls=control_qarg, targets=target_qarg)
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
def visit_ZZPowGate(
|
|
533
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.GateOperation
|
|
534
|
+
):
|
|
535
|
+
if node.gate.exponent % 2 == 0:
|
|
536
|
+
return
|
|
537
|
+
|
|
538
|
+
qubit1, qubit2 = node.qubits
|
|
539
|
+
qarg1 = self.lower_qubit_getindices(state, (qubit1,))
|
|
540
|
+
qarg2 = self.lower_qubit_getindices(state, (qubit2,))
|
|
541
|
+
|
|
542
|
+
if node.gate.exponent % 2 == 1:
|
|
543
|
+
state.current_frame.push(gate.stmts.X(qarg1))
|
|
544
|
+
state.current_frame.push(gate.stmts.X(qarg2))
|
|
545
|
+
return
|
|
546
|
+
|
|
547
|
+
# NOTE: arbitrary exponent, write as CX * Rz * CX (up to global phase)
|
|
548
|
+
state.current_frame.push(gate.stmts.CX(qarg1, qarg2))
|
|
549
|
+
angle = state.current_frame.push(py.Constant(0.5 * node.gate.exponent))
|
|
550
|
+
state.current_frame.push(gate.stmts.Rz(angle.result, qarg2))
|
|
551
|
+
state.current_frame.push(gate.stmts.CX(qarg1, qarg2))
|
|
552
|
+
|
|
553
|
+
def visit_ControlledOperation(
|
|
554
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.ControlledOperation
|
|
555
|
+
):
|
|
556
|
+
match node.gate.sub_gate:
|
|
557
|
+
case cirq.X:
|
|
558
|
+
stmt = gate.stmts.CX
|
|
559
|
+
case cirq.Y:
|
|
560
|
+
stmt = gate.stmts.CY
|
|
561
|
+
case cirq.Z:
|
|
562
|
+
stmt = gate.stmts.CZ
|
|
563
|
+
case _:
|
|
564
|
+
raise lowering.BuildError(
|
|
565
|
+
f"Cannot lowering controlled operation: {node}"
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
control, target = node.qubits
|
|
569
|
+
control_qarg = self.lower_qubit_getindices(state, (control,))
|
|
570
|
+
target_qarg = self.lower_qubit_getindices(state, (target,))
|
|
571
|
+
return state.current_frame.push(stmt(control_qarg, target_qarg))
|
|
572
|
+
|
|
573
|
+
def visit_FrozenCircuit(
|
|
574
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.FrozenCircuit
|
|
575
|
+
):
|
|
576
|
+
return self.visit_Circuit(state, node)
|
|
577
|
+
|
|
578
|
+
def visit_CircuitOperation(
|
|
579
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.CircuitOperation
|
|
580
|
+
):
|
|
581
|
+
reps = node.repetitions
|
|
582
|
+
|
|
583
|
+
if not isinstance(reps, int):
|
|
584
|
+
raise lowering.BuildError(
|
|
585
|
+
f"Cannot lower CircuitOperation with non-integer repetitions: {node}"
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
if reps > 1:
|
|
589
|
+
raise lowering.BuildError(
|
|
590
|
+
"Repetitions of circuit operatiosn not yet supported"
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
return self.visit(state, node.circuit)
|
|
594
|
+
|
|
595
|
+
def visit_BitFlipChannel(
|
|
596
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.BitFlipChannel
|
|
597
|
+
):
|
|
598
|
+
p = node.gate.p
|
|
599
|
+
p_x = state.current_frame.push(py.Constant(p)).result
|
|
600
|
+
p_y = p_z = state.current_frame.push(py.Constant(0)).result
|
|
601
|
+
qubits = self.lower_qubit_getindices(state, node.qubits)
|
|
602
|
+
return state.current_frame.push(
|
|
603
|
+
noise.stmts.SingleQubitPauliChannel(px=p_x, py=p_y, pz=p_z, qubits=qubits)
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
def visit_DepolarizingChannel(
|
|
607
|
+
self, state: lowering.State[cirq.Circuit], node: cirq.DepolarizingChannel
|
|
608
|
+
):
|
|
609
|
+
p = state.current_frame.push(py.Constant(node.gate.p)).result
|
|
610
|
+
qubits = self.lower_qubit_getindices(state, node.qubits)
|
|
611
|
+
return state.current_frame.push(noise.stmts.Depolarize(p, qubits=qubits))
|
|
612
|
+
|
|
613
|
+
def visit_AsymmetricDepolarizingChannel(
|
|
614
|
+
self,
|
|
615
|
+
state: lowering.State[cirq.Circuit],
|
|
616
|
+
node: cirq.AsymmetricDepolarizingChannel,
|
|
617
|
+
):
|
|
618
|
+
nqubits = node.gate.num_qubits()
|
|
619
|
+
if nqubits > 2:
|
|
620
|
+
raise lowering.BuildError(
|
|
621
|
+
"AsymmetricDepolarizingChannel applied to more than 2 qubits is not supported!"
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
if nqubits == 1:
|
|
625
|
+
qubits = self.lower_qubit_getindices(state, node.qubits)
|
|
626
|
+
p_x = state.current_frame.push(py.Constant(node.gate.p_x)).result
|
|
627
|
+
p_y = state.current_frame.push(py.Constant(node.gate.p_y)).result
|
|
628
|
+
p_z = state.current_frame.push(py.Constant(node.gate.p_z)).result
|
|
629
|
+
return state.current_frame.push(
|
|
630
|
+
noise.stmts.SingleQubitPauliChannel(p_x, p_y, p_z, qubits)
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
# NOTE: nqubits == 2
|
|
634
|
+
error_probs = node.gate.error_probabilities
|
|
635
|
+
probability_values = []
|
|
636
|
+
p0 = None
|
|
637
|
+
for key in self.two_qubit_paulis:
|
|
638
|
+
p = error_probs.get(key)
|
|
639
|
+
|
|
640
|
+
if p is None:
|
|
641
|
+
if p0 is None:
|
|
642
|
+
p0 = state.current_frame.push(py.Constant(0)).result
|
|
643
|
+
p_ssa = p0
|
|
644
|
+
else:
|
|
645
|
+
p_ssa = state.current_frame.push(py.Constant(p)).result
|
|
646
|
+
probability_values.append(p_ssa)
|
|
647
|
+
|
|
648
|
+
probabilities = state.current_frame.push(
|
|
649
|
+
ilist.New(values=probability_values)
|
|
650
|
+
).result
|
|
651
|
+
|
|
652
|
+
control, target = node.qubits
|
|
653
|
+
control_qarg = self.lower_qubit_getindices(state, (control,))
|
|
654
|
+
target_qarg = self.lower_qubit_getindices(state, (target,))
|
|
655
|
+
|
|
656
|
+
return state.current_frame.push(
|
|
657
|
+
noise.stmts.TwoQubitPauliChannel(
|
|
658
|
+
probabilities, controls=control_qarg, targets=target_qarg
|
|
659
|
+
)
|
|
660
|
+
)
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
from .model import (
|
|
4
4
|
GeminiOneZoneNoiseModel as GeminiOneZoneNoiseModel,
|
|
5
5
|
GeminiTwoZoneNoiseModel as GeminiTwoZoneNoiseModel,
|
|
6
|
-
GeminiOneZoneNoiseModelABC as GeminiOneZoneNoiseModelABC,
|
|
7
|
-
GeminiOneZoneNoiseModelCorrelated as GeminiOneZoneNoiseModelCorrelated,
|
|
8
6
|
GeminiOneZoneNoiseModelConflictGraphMoves as GeminiOneZoneNoiseModelConflictGraphMoves,
|
|
9
7
|
)
|
|
10
8
|
from .transform import transform_circuit as transform_circuit
|