microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.18.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/pip/tests-integration/interop_qiskit/test_qir.py

234lines · modecode

1# Copyright (c) Microsoft Corporation.
2# Licensed under the MIT License.
3
4import os
5from typing import Optional
6
7import pytest
8from qsharp import TargetProfile, QSharpError
9
10from . import QISKIT_AVAILABLE, SKIP_REASON, ignore_on_failure
11
12
13if QISKIT_AVAILABLE:
14 from .test_circuits import (
15 generate_repro_information,
16 )
17 from qsharp.interop.qiskit import (
18 OutputSemantics,
19 QSharpBackend,
20 QasmError,
21 QirTarget,
22 )
23 from qiskit.circuit import QuantumCircuit, Parameter, Gate
24 from qiskit.circuit.quantumcircuit import QubitSpecifier
25
26
27def get_resource_path(file_name: Optional[str] = None) -> str:
28 current_directory = os.path.dirname(os.path.abspath(__file__))
29 if file_name is None:
30 return os.path.join(current_directory, "resources")
31 return os.path.join(current_directory, "resources", file_name)
32
33
34def read_resource_file(file_name: str) -> str:
35 resource_path = get_resource_path(file_name)
36 with open(resource_path, encoding="utf-8") as f:
37 return f.read()
38
39
40@pytest.mark.skipif(not QISKIT_AVAILABLE, reason=SKIP_REASON)
41def test_generating_qir_with_unbound_param_raises():
42 theta = Parameter("theta")
43
44 circuit = QuantumCircuit(1)
45 circuit.name = "test"
46 circuit.rx(theta, 0)
47 circuit.measure_all()
48
49 target_profile = TargetProfile.Base
50 backend = QSharpBackend(target_profile=target_profile)
51 try:
52 with pytest.raises(QSharpError) as ex:
53 _ = backend.qir(circuit)
54 message = str(ex.value)
55 assert "Circuit has unbound input parameters" in message
56 assert "help: Parameters: theta: Double" in message
57 except AssertionError:
58 raise
59 except Exception as ex:
60 additional_info = generate_repro_information(circuit, backend)
61 raise RuntimeError(additional_info) from ex
62
63
64@pytest.mark.skipif(not QISKIT_AVAILABLE, reason=SKIP_REASON)
65def test_generating_qir_with_bound_param_with_wrong_type_raises():
66 theta = Parameter("theta")
67
68 circuit = QuantumCircuit(1)
69 circuit.name = "test"
70 circuit.rx(theta, 0)
71 circuit.measure_all()
72
73 target_profile = TargetProfile.Base
74 backend = QSharpBackend(target_profile=target_profile)
75 try:
76 with pytest.raises(QSharpError) as ex:
77 _ = backend.qir(circuit, params="true")
78 message = str(ex)
79 assert "Circuit has unbound input parameters" in message
80 assert "help: Parameters: theta: Double" in message
81 except AssertionError:
82 raise
83 except Exception as ex:
84 additional_info = generate_repro_information(circuit, backend)
85 raise RuntimeError(additional_info) from ex
86
87
88@pytest.mark.skipif(not QISKIT_AVAILABLE, reason=SKIP_REASON)
89def test_generating_qir_with_bound_param():
90 theta = Parameter("theta")
91
92 circuit = QuantumCircuit(1)
93 circuit.name = "test"
94 circuit.rx(theta, 0)
95 circuit.measure_all()
96 circuit.assign_parameters({"theta": 0.5}, inplace=True)
97
98 target_profile = TargetProfile.Base
99 backend = QSharpBackend(target_profile=target_profile)
100 try:
101 qir = backend.qir(circuit)
102 assert qir is not None
103 except AssertionError:
104 raise
105 except Exception as ex:
106 additional_info = generate_repro_information(circuit, backend)
107 raise RuntimeError(additional_info) from ex
108
109
110@pytest.mark.skipif(not QISKIT_AVAILABLE, reason=SKIP_REASON)
111def test_generating_qir_without_measuring_into_all_registers_raises():
112 circuit = QuantumCircuit(2, 2)
113 circuit.rx(0.5, 0)
114
115 target_profile = TargetProfile.Base
116 backend = QSharpBackend(target_profile=target_profile)
117 try:
118 with pytest.raises(QSharpError) as ex:
119 _ = backend.qir(circuit)
120 assert "ensure all output registers have been measured into." in str(ex)
121 except AssertionError:
122 raise
123 except Exception as ex:
124 additional_info = generate_repro_information(circuit, backend)
125 raise RuntimeError(additional_info) from ex
126
127
128@pytest.mark.skipif(not QISKIT_AVAILABLE, reason=SKIP_REASON)
129def test_generating_qir_without_registers_raises():
130 circuit = QuantumCircuit(2)
131 circuit.rx(0.5, 0)
132
133 target_profile = TargetProfile.Base
134 backend = QSharpBackend(target_profile=target_profile)
135 try:
136 with pytest.raises(QasmError) as ex:
137 _ = backend.qir(circuit)
138 assert "Qiskit circuits must have output registers" in str(ex)
139 except AssertionError:
140 raise
141 except Exception as ex:
142 additional_info = generate_repro_information(circuit, backend)
143 raise RuntimeError(additional_info) from ex
144
145
146@pytest.mark.skipif(not QISKIT_AVAILABLE, reason=SKIP_REASON)
147def test_custom_qir_intrinsics_generates_qir():
148 expected_qir = read_resource_file("custom_intrinsics.ll")
149
150 def my_gate(self: QuantumCircuit, qubit: QubitSpecifier):
151 return self.append(Gate(name="my_gate", num_qubits=1, params=[]), [qubit])
152
153 QuantumCircuit.my_gate = my_gate
154
155 class CustomTarget(QirTarget):
156 def __init__(self):
157 super().__init__()
158 self.add_instruction(
159 Gate(name="my_gate", num_qubits=1, params=[]), name="my_gate"
160 )
161
162 target = CustomTarget()
163 circuit = QuantumCircuit(1, 1)
164 circuit.my_gate(0)
165 circuit.measure(0, 0)
166
167 target_profile = TargetProfile.Adaptive_RI
168
169 options = {
170 "search_path": get_resource_path(),
171 "includes": ("stdgates.inc", "custom_intrinsics.inc"),
172 }
173
174 backend = QSharpBackend(target_profile=target_profile, target=target)
175 qir = backend.qir(circuit, **options)
176 assert qir == expected_qir
177
178
179@pytest.mark.skipif(not QISKIT_AVAILABLE, reason=SKIP_REASON)
180def test_custom_qir_intrinsics_is_simulatable():
181 def my_gate(self: QuantumCircuit, qubit: QubitSpecifier):
182 return self.append(Gate(name="my_gate", num_qubits=1, params=[]), [qubit])
183
184 QuantumCircuit.my_gate = my_gate
185
186 class CustomTarget(QirTarget):
187 def __init__(self):
188 super().__init__()
189 self.add_instruction(
190 Gate(name="my_gate", num_qubits=1, params=[]), name="my_gate"
191 )
192
193 target = CustomTarget()
194 circuit = QuantumCircuit(1, 1)
195 circuit.my_gate(0)
196 circuit.measure(0, 0)
197
198 target_profile = TargetProfile.Adaptive_RI
199
200 options = {
201 "search_path": get_resource_path(),
202 "includes": ("stdgates.inc", "custom_intrinsics.inc"),
203 }
204
205 backend = QSharpBackend(target_profile=target_profile, target=target)
206 result = backend.run(circuit, **options).result()
207 assert result.get_counts() == {"1": 1024}
208
209
210@pytest.mark.skipif(not QISKIT_AVAILABLE, reason=SKIP_REASON)
211def test_qir_smoke() -> None:
212 circuit = QuantumCircuit(2, 2)
213 circuit.x(0)
214 circuit.cx(0, 1)
215 circuit.measure_all(add_bits=False)
216 backend = QSharpBackend(target_profile=TargetProfile.Base)
217 res = backend.qir(circuit)
218 assert res is not None
219
220
221@pytest.mark.skipif(not QISKIT_AVAILABLE, reason=SKIP_REASON)
222def test_qir_re_output_single_unit_tuple() -> None:
223 circuit = QuantumCircuit(2, 2)
224 circuit.x(0)
225 circuit.cx(0, 1)
226 circuit.measure_all(add_bits=False)
227
228 backend = QSharpBackend(target_profile=TargetProfile.Adaptive_RI)
229 output_semantics = OutputSemantics.ResourceEstimation
230
231 res = backend.qir(circuit, output_semantics=output_semantics)
232 assert res is not None
233 call = "call void @__quantum__rt__tuple_record_output(i64 0, i8* null)"
234 assert call in res
235