microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/pipeline-issue-debugging

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/pip/tests-integration/devices/validation/__init__.py

96lines · modecode

1# Copyright (c) Microsoft Corporation.
2# Licensed under the MIT License.
3
4from pyqir import QirModuleVisitor, is_entry_point, qubit_id, required_num_qubits
5
6
7class ValidateBeginEndParallel(QirModuleVisitor):
8 """
9 Ensure that only one parallel section is active at a time and that they all begin and end in the same block.
10 """
11
12 def _on_block(self, block):
13 self.parallel = False
14 super()._on_block(block)
15 if self.parallel:
16 raise ValueError("Unmatched __quantum__rt__begin_parallel at end of block")
17
18 def _on_call_instr(self, call):
19 if call.callee.name == "__quantum__rt__begin_parallel":
20 if self.parallel:
21 raise ValueError(
22 "Nested __quantum__rt__begin_parallel in parallel section"
23 )
24 self.parallel = True
25 elif call.callee.name == "__quantum__rt__end_parallel":
26 if not self.parallel:
27 raise ValueError("Unmatched __quantum__rt__end_parallel")
28 self.parallel = False
29
30
31class PerQubitOrdering(QirModuleVisitor):
32 """
33 Get the ordering of instructions on each qubit as a data structure.
34 """
35
36 qubit_instructions: list[list[str]]
37
38 def _on_function(self, function):
39 if is_entry_point(function):
40 num_qubits = required_num_qubits(function)
41 if num_qubits is None:
42 raise ValueError("Entry function must have a known number of qubits")
43 self.qubit_instructions = [[] for _ in range(num_qubits)]
44 if len(function.basic_blocks) > 1:
45 raise ValueError(
46 "Entry function must have a single basic block for per-qubit ordering analysis"
47 )
48 super()._on_function(function)
49
50 def _on_call_instr(self, call):
51 if call.callee.name == "__quantum__qis__sx__body":
52 self._on_qis_sx(call, call.args[0])
53 else:
54 super()._on_call_instr(call)
55
56 def _on_qis_cz(self, call, ctrl, target):
57 ctrl_id = qubit_id(ctrl)
58 target_id = qubit_id(target)
59 assert (
60 ctrl_id is not None and target_id is not None
61 ), "Qubit ids should be known"
62 self.qubit_instructions[ctrl_id].append(str(call))
63 self.qubit_instructions[target_id].append(str(call))
64
65 def _on_qis_sx(self, call, target):
66 target_id = qubit_id(target)
67 assert target_id is not None, "Qubit id should be known"
68 self.qubit_instructions[target_id].append(str(call))
69
70 def _on_qis_rz(self, call, angle, target):
71 target_id = qubit_id(target)
72 assert target_id is not None, "Qubit id should be known"
73 self.qubit_instructions[target_id].append(str(call))
74
75 def _on_qis_mresetz(self, call, target, result):
76 target_id = qubit_id(target)
77 assert target_id is not None, "Qubit id should be known"
78 self.qubit_instructions[target_id].append(str(call))
79
80
81def check_qubit_ordering_unchanged(
82 after: PerQubitOrdering, before: PerQubitOrdering
83) -> None:
84 for q, (after_instrs, before_instrs) in enumerate(
85 zip(after.qubit_instructions, before.qubit_instructions)
86 ):
87 if before_instrs != after_instrs:
88 print("Reordering changed the per-qubit instruction order:")
89 print(f"Qubit {q}:")
90 print(" Before:")
91 for instr in before_instrs:
92 print(f" {instr}")
93 print(" After:")
94 for instr in after_instrs:
95 print(f" {instr}")
96 raise RuntimeError("Reordering changed the per-qubit instruction order")
97