18
18
import attrs
19
19
import numpy as np
20
20
21
+ import cirq .circuits as circuits
21
22
import cirq .ops as ops
22
23
import cirq .protocols as protocols
23
24
import cirq .transformers .transformer_api as transformer_api
@@ -79,16 +80,16 @@ def _get_structure(
79
80
yield (stop + 1 , n - 1 )
80
81
81
82
82
- def _merge (g1 : cirq .Gate , g2 : cirq .Gate ) -> cirq .Gate :
83
+ def _merge (g1 : cirq .Gate , g2 : cirq .Gate , q : cirq . Qid , tags : Sequence ) -> cirq .Operation :
83
84
u1 = protocols .unitary (g1 )
84
85
u2 = protocols .unitary (g2 )
85
- return ops .PhasedXZGate .from_matrix (u2 @ u1 )
86
+ return ops .PhasedXZGate .from_matrix (u2 @ u1 )( q ). with_tags ( * tags )
86
87
87
88
88
89
@transformer_api .transformer
89
90
@attrs .frozen
90
91
class IdleMomentsGauge :
91
- """A transformer that inserts identity-preserving "gauge" gates around idle qubit moments.
92
+ r """A transformer that inserts identity-preserving "gauge" gates around idle qubit moments.
92
93
93
94
This transformer identifies sequences of consecutive idle moments on a single qubit
94
95
that meet a `min_length` threshold. For each such sequence, it inserts a randomly
@@ -104,8 +105,8 @@ class IdleMomentsGauge:
104
105
105
106
gauges: A sequence of `cirq.Gate` objects to randomly select from.
106
107
Can be a custom tuple or a string alias:
107
- - `"pauli"`: Uses single-qubit Pauli gates (I, X, Y, Z).
108
- - `"clifford"`: Uses all 24 single-qubit Clifford gates.
108
+ - `"pauli"`: Uses single-qubit Pauli gates (I, X, Y, Z).
109
+ - `"clifford"`: Uses all 24 single-qubit Clifford gates.
109
110
110
111
gauges_inverse: An optional sequence of `cirq.Gate` objects representing
111
112
the inverses of gates in `gauges`. The `k`-th gate in `gauges_inverse`
@@ -123,6 +124,7 @@ class IdleMomentsGauge:
123
124
gauge_ending: If `True`, applies a gauge to idle moments at the circuit's end,
124
125
after the last qubit operation. Defaults to `False`.
125
126
"""
127
+
126
128
min_length : int = attrs .field (
127
129
validator = (attrs .validators .instance_of (int ), attrs .validators .ge (1 ))
128
130
)
@@ -211,7 +213,7 @@ def __call__(
211
213
for q in op .qubits :
212
214
active_moments [q ].append ((m_id , is_mergable ))
213
215
214
- single_qubit_moments = [{q : op . gate for op in m if len (op .qubits ) == 1 } for m in circuit ]
216
+ single_qubit_moments = [{q : op for op in m if len (op .qubits ) == 1 } for m in circuit ]
215
217
non_single_qubit_moments = [[op for op in m if len (op .qubits ) != 1 ] for m in circuit ]
216
218
217
219
for q , active in active_moments .items ():
@@ -220,34 +222,23 @@ def __call__(
220
222
):
221
223
gate_index = rng .choice (len (self .gauges ))
222
224
gate = self .gauges [gate_index ]
223
- gate_inv = self .gauges [gate_index ]
225
+ gate_inv = self .gauges_inverse [gate_index ]
224
226
225
- if existing_gate := single_qubit_moments [s ].get (q , None ):
226
- single_qubit_moments [s ][q ] = _merge (existing_gate , gate )
227
+ if existing_op := single_qubit_moments [s ].get (q , None ):
228
+ single_qubit_moments [s ][q ] = _merge (existing_op . gate , gate , q , existing_op . tags )
227
229
else :
228
- single_qubit_moments [s ][q ] = gate
230
+ single_qubit_moments [s ][q ] = gate ( q )
229
231
230
- if existing_gate := single_qubit_moments [e ].get (q , None ):
231
- single_qubit_moments [e ][q ] = _merge (gate_inv , existing_gate )
232
+ if existing_op := single_qubit_moments [e ].get (q , None ):
233
+ single_qubit_moments [e ][q ] = _merge (
234
+ gate_inv , existing_op .gate , q , existing_op .tags
235
+ )
232
236
else :
233
- single_qubit_moments [e ][q ] = gate_inv
237
+ single_qubit_moments [e ][q ] = gate_inv ( q )
234
238
235
- return cirq .Circuit .from_moments (
239
+ return circuits .Circuit .from_moments (
236
240
* (
237
- [g ( q ) for q , g in sq .items ()] + nsq
241
+ [op for op in sq .values ()] + nsq
238
242
for sq , nsq in zip (single_qubit_moments , non_single_qubit_moments , strict = True )
239
243
)
240
244
)
241
-
242
-
243
- if __name__ == '__main__' :
244
- tr = IdleMomentsGauge (2 , gauges = 'pauli' , gauge_beginning = True )
245
- print (tr )
246
-
247
- import cirq
248
-
249
- # c = cirq.Circuit.from_moments(cirq.X(cirq.q(0)), [], [], cirq.X(cirq.q(0)))
250
- # c = cirq.Circuit.from_moments([], [], cirq.X(cirq.q(0)))
251
- c = cirq .Circuit .from_moments ([], [], cirq .X (cirq .q (0 )).with_tags ('ignore' ))
252
- print (c )
253
- print (tr (c , context = cirq .TransformerContext (tags_to_ignore = ("ignore" ,))))
0 commit comments