12
12
# See the License for the specific language governing permissions and
13
13
# limitations under the License.
14
14
15
- """An optimization pass that combines adjacent single-qubit rotations ."""
15
+ """An optimization pass that combines adjacent series of gates on two qubits ."""
16
16
17
17
from typing import Callable , List , Optional , Sequence , Tuple , cast , TYPE_CHECKING
18
18
19
+ import abc
19
20
import numpy as np
20
21
21
22
from cirq import circuits , ops , protocols
25
26
import cirq
26
27
27
28
28
- class MergeInteractions (circuits .PointOptimizer ):
29
- """Combines series of adjacent one and two-qubit gates operating on a pair
30
- of qubits."""
29
+ class MergeInteractionsAbc (circuits .PointOptimizer , metaclass = abc . ABCMeta ):
30
+ """Combines series of adjacent one- and two-qubit, non-parametrized gates
31
+ operating on a pair of qubits."""
31
32
32
33
def __init__ (
33
34
self ,
34
35
tolerance : float = 1e-8 ,
35
- allow_partial_czs : bool = True ,
36
36
post_clean_up : Callable [[Sequence [ops .Operation ]], ops .OP_TREE ] = lambda op_list : op_list ,
37
37
) -> None :
38
+ """
39
+ Args:
40
+ tolerance: A limit on the amount of absolute error introduced by the
41
+ construction.
42
+ post_clean_up: This function is called on each set of optimized
43
+ operations before they are put into the circuit to replace the
44
+ old operations.
45
+ """
38
46
super ().__init__ (post_clean_up = post_clean_up )
39
47
self .tolerance = tolerance
40
- self .allow_partial_czs = allow_partial_czs
41
48
42
49
def optimization_at (
43
50
self , circuit : circuits .Circuit , index : int , op : ops .Operation
@@ -63,10 +70,8 @@ def optimization_at(
63
70
if not switch_to_new and old_interaction_count <= 1 :
64
71
return None
65
72
66
- # Find a max-3-cz construction.
67
- new_operations = two_qubit_decompositions .two_qubit_matrix_to_operations (
68
- op .qubits [0 ], op .qubits [1 ], matrix , self .allow_partial_czs , self .tolerance , False
69
- )
73
+ # Find a (possibly ideal) decomposition of the merged operations.
74
+ new_operations = self ._two_qubit_matrix_to_operations (op .qubits [0 ], op .qubits [1 ], matrix )
70
75
new_interaction_count = len (
71
76
[new_op for new_op in new_operations if len (new_op .qubits ) == 2 ]
72
77
)
@@ -82,12 +87,29 @@ def optimization_at(
82
87
new_operations = new_operations ,
83
88
)
84
89
90
+ @abc .abstractmethod
85
91
def _may_keep_old_op (self , old_op : 'cirq.Operation' ) -> bool :
86
92
"""Returns True if the old two-qubit operation may be left unchanged
87
93
without decomposition."""
88
- if self .allow_partial_czs :
89
- return isinstance (old_op .gate , ops .CZPowGate )
90
- return isinstance (old_op .gate , ops .CZPowGate ) and old_op .gate .exponent == 1
94
+
95
+ @abc .abstractmethod
96
+ def _two_qubit_matrix_to_operations (
97
+ self ,
98
+ q0 : 'cirq.Qid' ,
99
+ q1 : 'cirq.Qid' ,
100
+ mat : np .ndarray ,
101
+ ) -> Sequence ['cirq.Operation' ]:
102
+ """Decomposes the merged two-qubit gate unitary into the minimum number
103
+ of two-qubit gates.
104
+
105
+ Args:
106
+ q0: The first qubit being operated on.
107
+ q1: The other qubit being operated on.
108
+ mat: Defines the operation to apply to the pair of qubits.
109
+
110
+ Returns:
111
+ A list of operations implementing the matrix.
112
+ """
91
113
92
114
def _op_to_matrix (
93
115
self , op : ops .Operation , qubits : Tuple ['cirq.Qid' , ...]
@@ -130,7 +152,7 @@ def _op_to_matrix(
130
152
131
153
def _scan_two_qubit_ops_into_matrix (
132
154
self , circuit : circuits .Circuit , index : Optional [int ], qubits : Tuple ['cirq.Qid' , ...]
133
- ) -> Tuple [List [ops .Operation ], List [int ], np .ndarray ]:
155
+ ) -> Tuple [Sequence [ops .Operation ], List [int ], np .ndarray ]:
134
156
"""Accumulates operations affecting the given pair of qubits.
135
157
136
158
The scan terminates when it hits the end of the circuit, finds an
@@ -181,3 +203,55 @@ def _flip_kron_order(mat4x4: np.ndarray) -> np.ndarray:
181
203
for j in range (4 ):
182
204
result [order [i ], order [j ]] = mat4x4 [i , j ]
183
205
return result
206
+
207
+
208
+ class MergeInteractions (MergeInteractionsAbc ):
209
+ """Combines series of adjacent one- and two-qubit, non-parametrized gates
210
+ operating on a pair of qubits and replaces each series with the minimum
211
+ number of CZ gates."""
212
+
213
+ def __init__ (
214
+ self ,
215
+ tolerance : float = 1e-8 ,
216
+ allow_partial_czs : bool = True ,
217
+ post_clean_up : Callable [[Sequence [ops .Operation ]], ops .OP_TREE ] = lambda op_list : op_list ,
218
+ ) -> None :
219
+ """
220
+ Args:
221
+ tolerance: A limit on the amount of absolute error introduced by the
222
+ construction.
223
+ allow_partial_czs: Enables the use of Partial-CZ gates.
224
+ post_clean_up: This function is called on each set of optimized
225
+ operations before they are put into the circuit to replace the
226
+ old operations.
227
+ """
228
+ super ().__init__ (tolerance = tolerance , post_clean_up = post_clean_up )
229
+ self .allow_partial_czs = allow_partial_czs
230
+
231
+ def _may_keep_old_op (self , old_op : 'cirq.Operation' ) -> bool :
232
+ """Returns True if the old two-qubit operation may be left unchanged
233
+ without decomposition."""
234
+ if self .allow_partial_czs :
235
+ return isinstance (old_op .gate , ops .CZPowGate )
236
+ return isinstance (old_op .gate , ops .CZPowGate ) and old_op .gate .exponent == 1
237
+
238
+ def _two_qubit_matrix_to_operations (
239
+ self ,
240
+ q0 : 'cirq.Qid' ,
241
+ q1 : 'cirq.Qid' ,
242
+ mat : np .ndarray ,
243
+ ) -> Sequence ['cirq.Operation' ]:
244
+ """Decomposes the merged two-qubit gate unitary into the minimum number
245
+ of CZ gates.
246
+
247
+ Args:
248
+ q0: The first qubit being operated on.
249
+ q1: The other qubit being operated on.
250
+ mat: Defines the operation to apply to the pair of qubits.
251
+
252
+ Returns:
253
+ A list of operations implementing the matrix.
254
+ """
255
+ return two_qubit_decompositions .two_qubit_matrix_to_operations (
256
+ q0 , q1 , mat , self .allow_partial_czs , self .tolerance , False
257
+ )
0 commit comments