microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.28.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/pip/qsharp/_device/_atom/_decomp.py

510lines · modecode

1# Copyright (c) Microsoft Corporation.
2# Licensed under the MIT License.
3
4from pyqir import (
5 FloatConstant,
6 const,
7 Function,
8 FunctionType,
9 PointerType,
10 Type,
11 result,
12 Context,
13 Linkage,
14 QirModuleVisitor,
15 required_num_results,
16)
17from math import pi
18from ._utils import TOLERANCE
19
20
21class DecomposeMultiQubitToCZ(QirModuleVisitor):
22 """
23 Decomposes all multi-qubit gates to CZ gates and single qubit gates.
24 """
25
26 h_func: Function
27 s_func: Function
28 sadj_func: Function
29 t_func: Function
30 tadj_func: Function
31 rz_func: Function
32 cz_func: Function
33
34 def _on_module(self, module):
35 void = Type.void(module.context)
36 qubit_ty = PointerType(Type.void(module.context))
37 self.double_ty = Type.double(module.context)
38 # Find or create all the needed functions.
39 for func in module.functions:
40 match func.name:
41 case "__quantum__qis__h__body":
42 self.h_func = func
43 case "__quantum__qis__s__body":
44 self.s_func = func
45 case "__quantum__qis__s__adj":
46 self.sadj_func = func
47 case "__quantum__qis__t__body":
48 self.t_func = func
49 case "__quantum__qis__t__adj":
50 self.tadj_func = func
51 case "__quantum__qis__rz__body":
52 self.rz_func = func
53 case "__quantum__qis__cz__body":
54 self.cz_func = func
55 if not hasattr(self, "h_func"):
56 self.h_func = Function(
57 FunctionType(void, [qubit_ty]),
58 Linkage.EXTERNAL,
59 "__quantum__qis__h__body",
60 module,
61 )
62 if not hasattr(self, "s_func"):
63 self.s_func = Function(
64 FunctionType(void, [qubit_ty]),
65 Linkage.EXTERNAL,
66 "__quantum__qis__s__body",
67 module,
68 )
69 if not hasattr(self, "sadj_func"):
70 self.sadj_func = Function(
71 FunctionType(void, [qubit_ty]),
72 Linkage.EXTERNAL,
73 "__quantum__qis__s__adj",
74 module,
75 )
76 if not hasattr(self, "t_func"):
77 self.t_func = Function(
78 FunctionType(void, [qubit_ty]),
79 Linkage.EXTERNAL,
80 "__quantum__qis__t__body",
81 module,
82 )
83 if not hasattr(self, "tadj_func"):
84 self.tadj_func = Function(
85 FunctionType(void, [qubit_ty]),
86 Linkage.EXTERNAL,
87 "__quantum__qis__t__adj",
88 module,
89 )
90 if not hasattr(self, "rz_func"):
91 self.rz_func = Function(
92 FunctionType(void, [self.double_ty, qubit_ty]),
93 Linkage.EXTERNAL,
94 "__quantum__qis__rz__body",
95 module,
96 )
97 if not hasattr(self, "cz_func"):
98 self.cz_func = Function(
99 FunctionType(void, [qubit_ty, qubit_ty]),
100 Linkage.EXTERNAL,
101 "__quantum__qis__cz__body",
102 module,
103 )
104 super()._on_module(module)
105
106 def _on_qis_ccx(self, call, ctrl1, ctrl2, target):
107 self.builder.insert_before(call)
108 self.builder.call(self.h_func, [target])
109 self.builder.call(self.tadj_func, [ctrl1])
110 self.builder.call(self.tadj_func, [ctrl2])
111 self.builder.call(self.h_func, [ctrl1])
112 self.builder.call(self.cz_func, [target, ctrl1])
113 self.builder.call(self.h_func, [ctrl1])
114 self.builder.call(self.t_func, [ctrl1])
115 self.builder.call(self.h_func, [target])
116 self.builder.call(self.cz_func, [ctrl2, target])
117 self.builder.call(self.h_func, [target])
118 self.builder.call(self.h_func, [ctrl1])
119 self.builder.call(self.cz_func, [ctrl2, ctrl1])
120 self.builder.call(self.h_func, [ctrl1])
121 self.builder.call(self.t_func, [target])
122 self.builder.call(self.tadj_func, [ctrl1])
123 self.builder.call(self.h_func, [target])
124 self.builder.call(self.cz_func, [ctrl2, target])
125 self.builder.call(self.h_func, [target])
126 self.builder.call(self.h_func, [ctrl1])
127 self.builder.call(self.cz_func, [target, ctrl1])
128 self.builder.call(self.h_func, [ctrl1])
129 self.builder.call(self.tadj_func, [target])
130 self.builder.call(self.t_func, [ctrl1])
131 self.builder.call(self.h_func, [ctrl1])
132 self.builder.call(self.cz_func, [ctrl2, ctrl1])
133 self.builder.call(self.h_func, [ctrl1])
134 self.builder.call(self.h_func, [target])
135 call.erase()
136
137 def _on_qis_cx(self, call, ctrl, target):
138 self.builder.insert_before(call)
139 self.builder.call(self.h_func, [target])
140 self.builder.call(self.cz_func, [ctrl, target])
141 self.builder.call(self.h_func, [target])
142 call.erase()
143
144 def _on_qis_cy(self, call, ctrl, target):
145 self.builder.insert_before(call)
146 self.builder.call(self.sadj_func, [target])
147 self.builder.call(self.h_func, [target])
148 self.builder.call(self.cz_func, [ctrl, target])
149 self.builder.call(self.h_func, [target])
150 self.builder.call(self.s_func, [target])
151 call.erase()
152
153 def _on_qis_rxx(self, call, angle, target1, target2):
154 self.builder.insert_before(call)
155 self.builder.call(self.h_func, [target2])
156 self.builder.call(self.cz_func, [target2, target1])
157 self.builder.call(self.h_func, [target1])
158 self.builder.call(self.rz_func, [angle, target1])
159 self.builder.call(self.h_func, [target1])
160 self.builder.call(self.cz_func, [target2, target1])
161 self.builder.call(self.h_func, [target2])
162 call.erase()
163
164 def _on_qis_ryy(self, call, angle, target1, target2):
165 self.builder.insert_before(call)
166 self.builder.call(self.sadj_func, [target1])
167 self.builder.call(self.sadj_func, [target2])
168 self.builder.call(self.h_func, [target2])
169 self.builder.call(self.cz_func, [target2, target1])
170 self.builder.call(self.h_func, [target1])
171 self.builder.call(self.rz_func, [angle, target1])
172 self.builder.call(self.h_func, [target1])
173 self.builder.call(self.cz_func, [target2, target1])
174 self.builder.call(self.h_func, [target2])
175 self.builder.call(self.s_func, [target2])
176 self.builder.call(self.s_func, [target1])
177 call.erase()
178
179 def _on_qis_rzz(self, call, angle, target1, target2):
180 self.builder.insert_before(call)
181 self.builder.call(self.h_func, [target1])
182 self.builder.call(self.cz_func, [target2, target1])
183 self.builder.call(self.h_func, [target1])
184 self.builder.call(self.rz_func, [angle, target1])
185 self.builder.call(self.h_func, [target1])
186 self.builder.call(self.cz_func, [target2, target1])
187 self.builder.call(self.h_func, [target1])
188 call.erase()
189
190 def _on_qis_swap(self, call, target1, target2):
191 self.builder.insert_before(call)
192 self.builder.call(self.h_func, [target2])
193 self.builder.call(self.cz_func, [target1, target2])
194 self.builder.call(self.h_func, [target2])
195 self.builder.call(self.h_func, [target1])
196 self.builder.call(self.cz_func, [target2, target1])
197 self.builder.call(self.h_func, [target1])
198 self.builder.call(self.h_func, [target2])
199 self.builder.call(self.cz_func, [target1, target2])
200 self.builder.call(self.h_func, [target2])
201 call.erase()
202
203
204class DecomposeSingleRotationToRz(QirModuleVisitor):
205 """
206 Decomposes all single qubit rotations to Rz gates.
207 """
208
209 h_func: Function
210 s_func: Function
211 sadj_func: Function
212 rz_func: Function
213
214 def _on_module(self, module):
215 void = Type.void(module.context)
216 qubit_ty = PointerType(Type.void(module.context))
217 self.double_ty = Type.double(module.context)
218 # Find or create all the needed functions.
219 for func in module.functions:
220 match func.name:
221 case "__quantum__qis__h__body":
222 self.h_func = func
223 case "__quantum__qis__s__body":
224 self.s_func = func
225 case "__quantum__qis__s__adj":
226 self.sadj_func = func
227 case "__quantum__qis__rz__body":
228 self.rz_func = func
229 if not hasattr(self, "h_func"):
230 self.h_func = Function(
231 FunctionType(void, [qubit_ty]),
232 Linkage.EXTERNAL,
233 "__quantum__qis__h__body",
234 module,
235 )
236 if not hasattr(self, "s_func"):
237 self.s_func = Function(
238 FunctionType(void, [qubit_ty]),
239 Linkage.EXTERNAL,
240 "__quantum__qis__s__body",
241 module,
242 )
243 if not hasattr(self, "sadj_func"):
244 self.sadj_func = Function(
245 FunctionType(void, [qubit_ty]),
246 Linkage.EXTERNAL,
247 "__quantum__qis__s__adj",
248 module,
249 )
250 if not hasattr(self, "rz_func"):
251 self.rz_func = Function(
252 FunctionType(void, [self.double_ty, qubit_ty]),
253 Linkage.EXTERNAL,
254 "__quantum__qis__rz__body",
255 module,
256 )
257 super()._on_module(module)
258
259 def _on_qis_rx(self, call, angle, target):
260 self.builder.insert_before(call)
261 self.builder.call(self.h_func, [target])
262 self.builder.call(
263 self.rz_func,
264 [angle, target],
265 )
266 self.builder.call(self.h_func, [target])
267 call.erase()
268
269 def _on_qis_ry(self, call, angle, target):
270 self.builder.insert_before(call)
271 self.builder.call(self.sadj_func, [target])
272 self.builder.call(self.h_func, [target])
273 self.builder.call(
274 self.rz_func,
275 [angle, target],
276 )
277 self.builder.call(self.h_func, [target])
278 self.builder.call(self.s_func, [target])
279 call.erase()
280
281
282class DecomposeSingleQubitToRzSX(QirModuleVisitor):
283 """
284 Decomposes all single qubit gates to Rz and Sx gates.
285 """
286
287 sx_func: Function
288 rz_func: Function
289
290 def _on_module(self, module):
291 void = Type.void(module.context)
292 qubit_ty = PointerType(Type.void(module.context))
293 self.double_ty = Type.double(module.context)
294 # Find or create all the needed functions.
295 for func in module.functions:
296 match func.name:
297 case "__quantum__qis__sx__body":
298 self.sx_func = func
299 case "__quantum__qis__rz__body":
300 self.rz_func = func
301 if not hasattr(self, "sx_func"):
302 self.sx_func = Function(
303 FunctionType(void, [qubit_ty]),
304 Linkage.EXTERNAL,
305 "__quantum__qis__sx__body",
306 module,
307 )
308 if not hasattr(self, "rz_func"):
309 self.rz_func = Function(
310 FunctionType(void, [self.double_ty, qubit_ty]),
311 Linkage.EXTERNAL,
312 "__quantum__qis__rz__body",
313 module,
314 )
315 super()._on_module(module)
316
317 def _on_qis_h(self, call, target):
318 self.builder.insert_before(call)
319 self.builder.call(
320 self.rz_func,
321 [const(self.double_ty, pi / 2), target],
322 )
323 self.builder.call(self.sx_func, [target])
324 self.builder.call(
325 self.rz_func,
326 [const(self.double_ty, pi / 2), target],
327 )
328 call.erase()
329
330 def _on_qis_s(self, call, target):
331 self.builder.insert_before(call)
332 self.builder.call(
333 self.rz_func,
334 [const(self.double_ty, pi / 2), target],
335 )
336 call.erase()
337
338 def _on_qis_s_adj(self, call, target):
339 self.builder.insert_before(call)
340 self.builder.call(
341 self.rz_func,
342 [const(self.double_ty, -pi / 2), target],
343 )
344 call.erase()
345
346 def _on_qis_t(self, call, target):
347 self.builder.insert_before(call)
348 self.builder.call(
349 self.rz_func,
350 [const(self.double_ty, pi / 4), target],
351 )
352 call.erase()
353
354 def _on_qis_t_adj(self, call, target):
355 self.builder.insert_before(call)
356 self.builder.call(
357 self.rz_func,
358 [const(self.double_ty, -pi / 4), target],
359 )
360 call.erase()
361
362 def _on_qis_x(self, call, target):
363 self.builder.insert_before(call)
364 self.builder.call(self.sx_func, [target])
365 self.builder.call(self.sx_func, [target])
366 call.erase()
367
368 def _on_qis_y(self, call, target):
369 self.builder.insert_before(call)
370 self.builder.call(self.sx_func, [target])
371 self.builder.call(self.sx_func, [target])
372 self.builder.call(
373 self.rz_func,
374 [const(self.double_ty, pi), target],
375 )
376 call.erase()
377
378 def _on_qis_z(self, call, target):
379 self.builder.insert_before(call)
380 self.builder.call(
381 self.rz_func,
382 [const(self.double_ty, pi), target],
383 )
384 call.erase()
385
386
387class DecomposeRzAnglesToCliffordGates(QirModuleVisitor):
388 """
389 Ensure that the module only contains Clifford gates instead of rotation angles.
390 """
391
392 THREE_PI_OVER_2 = 3 * pi / 2
393 PI_OVER_2 = pi / 2
394 TWO_PI = 2 * pi
395
396 z_func: Function
397 s_func: Function
398 sadj_func: Function
399
400 def _on_module(self, module):
401 void = Type.void(module.context)
402 qubit_ty = PointerType(Type.void(module.context))
403 self.double_ty = Type.double(module.context)
404 # Find or create all the needed functions.
405 for func in module.functions:
406 match func.name:
407 case "__quantum__qis__s__body":
408 self.s_func = func
409 case "__quantum__qis__s__adj":
410 self.sadj_func = func
411 case "__quantum__qis__z__body":
412 self.z_func = func
413
414 if not hasattr(self, "s_func"):
415 self.s_func = Function(
416 FunctionType(void, [qubit_ty]),
417 Linkage.EXTERNAL,
418 "__quantum__qis__s__body",
419 module,
420 )
421 if not hasattr(self, "sadj_func"):
422 self.sadj_func = Function(
423 FunctionType(void, [qubit_ty]),
424 Linkage.EXTERNAL,
425 "__quantum__qis__s__adj",
426 module,
427 )
428 if not hasattr(self, "z_func"):
429 self.z_func = Function(
430 FunctionType(void, [qubit_ty]),
431 Linkage.EXTERNAL,
432 "__quantum__qis__z__body",
433 module,
434 )
435
436 super()._on_module(module)
437
438 def _on_qis_rz(self, call, angle, target):
439 if not isinstance(angle, FloatConstant):
440 raise ValueError("Angle used in RZ must be a constant")
441 angle = angle.value
442
443 self.builder.insert_before(call)
444
445 if (
446 abs(angle - self.THREE_PI_OVER_2) < TOLERANCE
447 or abs(angle + self.PI_OVER_2) < TOLERANCE
448 ):
449 self.builder.call(self.sadj_func, [target])
450 elif abs(angle - pi) < TOLERANCE or abs(angle + pi) < TOLERANCE:
451 self.builder.call(self.z_func, [target])
452 elif (
453 abs(angle - self.PI_OVER_2) < TOLERANCE
454 or abs(angle + self.THREE_PI_OVER_2) < TOLERANCE
455 ):
456 self.builder.call(self.s_func, [target])
457 elif (
458 angle < TOLERANCE
459 or abs(angle - self.TWO_PI) < TOLERANCE
460 or abs(angle + self.TWO_PI) < TOLERANCE
461 ):
462 # I, drop it
463 pass
464 else:
465 raise ValueError(
466 f"Angle {angle} used in RZ is not a Clifford compatible rotation angle"
467 )
468
469 call.erase()
470
471
472class ReplaceResetWithMResetZ(QirModuleVisitor):
473 """
474 Replaces all reset operations with a call to mresetz using a new, ignored result identifier.
475 """
476
477 context: Context
478 mresetz_func: Function
479 next_result_id: int
480
481 def _on_module(self, module):
482 self.context = module.context
483 void = Type.void(self.context)
484 qubit_ty = PointerType(Type.void(self.context))
485 result_ty = PointerType(Type.void(self.context))
486 # Find or create the intrinsic mresetz function
487 for func in module.functions:
488 match func.name:
489 case "__quantum__qis__mresetz__body":
490 self.mresetz_func = func
491 if not hasattr(self, "mresetz_func"):
492 self.mresetz_func = Function(
493 FunctionType(void, [qubit_ty, result_ty]),
494 Linkage.EXTERNAL,
495 "__quantum__qis__mresetz__body",
496 module,
497 )
498 super()._on_module(module)
499
500 def _on_function(self, function):
501 self.next_result_id = required_num_results(function) or 0
502 super()._on_function(function)
503
504 def _on_qis_reset(self, call, target):
505 self.builder.insert_before(call)
506 # Create a new result identifier to ignore the measurement result
507 result_id = result(self.context, self.next_result_id)
508 self.next_result_id += 1
509 self.builder.call(self.mresetz_func, [target, result_id])
510 call.erase()
511