microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
8829ede154fe072649e1bb87bf1cbb81b7f96db0

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/pip/tests/test_qsharp.py

792lines · modecode

1# Copyright (c) Microsoft Corporation.
2# Licensed under the MIT License.
3
4from textwrap import dedent
5import pytest
6import qsharp
7import qsharp.code
8import qsharp.utils
9from contextlib import redirect_stdout
10import io
11
12# Tests for the Python library for Q#
13
14
15def test_stdout() -> None:
16 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
17 f = io.StringIO()
18 with redirect_stdout(f):
19 result = qsharp.eval('Message("Hello, world!")')
20
21 assert result is None
22 assert f.getvalue() == "Hello, world!\n"
23
24
25def test_stdout_multiple_lines() -> None:
26 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
27 f = io.StringIO()
28 with redirect_stdout(f):
29 qsharp.eval(
30 """
31 use q = Qubit();
32 Microsoft.Quantum.Diagnostics.DumpMachine();
33 Message("Hello!");
34 """
35 )
36
37 assert f.getvalue() == "STATE:\n|0⟩: 1.0000+0.0000𝑖\nHello!\n"
38
39
40def test_captured_stdout() -> None:
41 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
42 f = io.StringIO()
43 with redirect_stdout(f):
44 result = qsharp.eval(
45 '{Message("Hello, world!"); Message("Goodbye!")}', save_events=True
46 )
47 assert f.getvalue() == ""
48 assert len(result["messages"]) == 2
49 assert result["messages"][0] == "Hello, world!"
50 assert result["messages"][1] == "Goodbye!"
51
52
53def test_captured_matrix() -> None:
54 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
55 f = io.StringIO()
56 with redirect_stdout(f):
57 result = qsharp.eval(
58 "Std.Diagnostics.DumpOperation(1, qs => H(qs[0]))",
59 save_events=True,
60 )
61 assert f.getvalue() == ""
62 assert len(result["matrices"]) == 1
63 assert (
64 str(result["matrices"][0])
65 == "MATRIX:\n 0.7071+0.0000𝑖 0.7071+0.0000𝑖\n 0.7071+0.0000𝑖 −0.7071+0.0000𝑖"
66 )
67
68
69def test_quantum_seed() -> None:
70 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
71 qsharp.set_quantum_seed(42)
72 value1 = qsharp.eval(
73 "{ use qs = Qubit[32]; for q in qs { H(q); }; Microsoft.Quantum.Measurement.MResetEachZ(qs) }"
74 )
75 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
76 qsharp.set_quantum_seed(42)
77 value2 = qsharp.eval(
78 "{ use qs = Qubit[32]; for q in qs { H(q); }; Microsoft.Quantum.Measurement.MResetEachZ(qs) }"
79 )
80 assert value1 == value2
81 qsharp.set_quantum_seed(None)
82 value3 = qsharp.eval(
83 "{ use qs = Qubit[32]; for q in qs { H(q); }; Microsoft.Quantum.Measurement.MResetEachZ(qs) }"
84 )
85 assert value1 != value3
86
87
88def test_classical_seed() -> None:
89 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
90 qsharp.set_classical_seed(42)
91 value1 = qsharp.eval(
92 "{ mutable res = []; for _ in 0..15{ set res += [(Microsoft.Quantum.Random.DrawRandomInt(0, 100), Microsoft.Quantum.Random.DrawRandomDouble(0.0, 1.0))]; }; res }"
93 )
94 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
95 qsharp.set_classical_seed(42)
96 value2 = qsharp.eval(
97 "{ mutable res = []; for _ in 0..15{ set res += [(Microsoft.Quantum.Random.DrawRandomInt(0, 100), Microsoft.Quantum.Random.DrawRandomDouble(0.0, 1.0))]; }; res }"
98 )
99 assert value1 == value2
100 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
101 qsharp.set_classical_seed(None)
102 value3 = qsharp.eval(
103 "{ mutable res = []; for _ in 0..15{ set res += [(Microsoft.Quantum.Random.DrawRandomInt(0, 100), Microsoft.Quantum.Random.DrawRandomDouble(0.0, 1.0))]; }; res }"
104 )
105 assert value1 != value3
106
107
108def test_dump_machine() -> None:
109 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
110 qsharp.eval(
111 """
112 use q1 = Qubit();
113 use q2 = Qubit();
114 X(q1);
115 """
116 )
117 state_dump = qsharp.dump_machine()
118 assert state_dump.qubit_count == 2
119 assert len(state_dump) == 1
120 assert state_dump[2] == complex(1.0, 0.0)
121 assert state_dump.as_dense_state() == [0, 0, 1, 0]
122 qsharp.eval("X(q2);")
123 state_dump = qsharp.dump_machine()
124 assert state_dump.qubit_count == 2
125 assert len(state_dump) == 1
126 assert state_dump[3] == complex(1.0, 0.0)
127 assert state_dump.as_dense_state() == [0, 0, 0, 1]
128 qsharp.eval("H(q1);")
129 state_dump = qsharp.dump_machine()
130 assert state_dump.qubit_count == 2
131 assert len(state_dump) == 2
132 # Check that the state dump correctly supports iteration and membership checks
133 for idx in state_dump:
134 assert idx in state_dump
135 # Check that the state dump is correct and equivalence check ignores global phase, allowing passing
136 # in of different, potentially unnormalized states. The state should be
137 # |01⟩: 0.7071+0.0000𝑖, |11⟩: −0.7071+0.0000𝑖
138 assert state_dump.check_eq({1: complex(0.7071, 0.0), 3: complex(-0.7071, 0.0)})
139 assert state_dump.as_dense_state() == [
140 0,
141 0.7071067811865476,
142 0,
143 -0.7071067811865476,
144 ]
145 assert state_dump.check_eq({1: complex(0.0, 0.7071), 3: complex(0.0, -0.7071)})
146 assert state_dump.check_eq({1: complex(0.5, 0.0), 3: complex(-0.5, 0.0)})
147 assert state_dump.check_eq(
148 {1: complex(0.7071, 0.0), 3: complex(-0.7071, 0.0), 0: complex(0.0, 0.0)}
149 )
150 assert state_dump.check_eq([0.0, 0.5, 0.0, -0.5])
151 assert state_dump.check_eq([0.0, 0.5001, 0.00001, -0.5], tolerance=1e-3)
152 assert state_dump.check_eq(
153 [complex(0.0, 0.0), complex(0.0, -0.5), complex(0.0, 0.0), complex(0.0, 0.5)]
154 )
155 assert not state_dump.check_eq({1: complex(0.7071, 0.0), 3: complex(0.7071, 0.0)})
156 assert not state_dump.check_eq({1: complex(0.5, 0.0), 3: complex(0.0, 0.5)})
157 assert not state_dump.check_eq({2: complex(0.5, 0.0), 3: complex(-0.5, 0.0)})
158 assert not state_dump.check_eq([0.0, 0.5001, 0.0, -0.5], tolerance=1e-6)
159 # Reset the qubits and apply a small rotation to q1, to confirm that tolerance applies to the dump
160 # itself and not just the state.
161 qsharp.eval("ResetAll([q1, q2]);")
162 qsharp.eval("Ry(0.0001, q1);")
163 state_dump = qsharp.dump_machine()
164 assert state_dump.qubit_count == 2
165 assert len(state_dump) == 2
166 assert not state_dump.check_eq([1.0])
167 assert state_dump.check_eq([0.99999999875, 0.0, 4.999999997916667e-05])
168 assert state_dump.check_eq([1.0], tolerance=1e-4)
169
170
171def test_dump_operation() -> None:
172 qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted)
173 res = qsharp.utils.dump_operation("qs => ()", 1)
174 assert res == [
175 [complex(1.0, 0.0), complex(0.0, 0.0)],
176 [complex(0.0, 0.0), complex(1.0, 0.0)],
177 ]
178 res = qsharp.utils.dump_operation("qs => H(qs[0])", 1)
179 assert res == [
180 [complex(0.707107, 0.0), complex(0.707107, 0.0)],
181 [complex(0.707107, 0.0), complex(-0.707107, 0.0)],
182 ]
183 res = qsharp.utils.dump_operation("qs => CNOT(qs[0], qs[1])", 2)
184 assert res == [
185 [complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
186 [complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
187 [complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0)],
188 [complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0)],
189 ]
190 res = qsharp.utils.dump_operation("qs => CCNOT(qs[0], qs[1], qs[2])", 3)
191 assert res == [
192 [
193 complex(1.0, 0.0),
194 complex(0.0, 0.0),
195 complex(0.0, 0.0),
196 complex(0.0, 0.0),
197 complex(0.0, 0.0),
198 complex(0.0, 0.0),
199 complex(0.0, 0.0),
200 complex(0.0, 0.0),
201 ],
202 [
203 complex(0.0, 0.0),
204 complex(1.0, 0.0),
205 complex(0.0, 0.0),
206 complex(0.0, 0.0),
207 complex(0.0, 0.0),
208 complex(0.0, 0.0),
209 complex(0.0, 0.0),
210 complex(0.0, 0.0),
211 ],
212 [
213 complex(0.0, 0.0),
214 complex(0.0, 0.0),
215 complex(1.0, 0.0),
216 complex(0.0, 0.0),
217 complex(0.0, 0.0),
218 complex(0.0, 0.0),
219 complex(0.0, 0.0),
220 complex(0.0, 0.0),
221 ],
222 [
223 complex(0.0, 0.0),
224 complex(0.0, 0.0),
225 complex(0.0, 0.0),
226 complex(1.0, 0.0),
227 complex(0.0, 0.0),
228 complex(0.0, 0.0),
229 complex(0.0, 0.0),
230 complex(0.0, 0.0),
231 ],
232 [
233 complex(0.0, 0.0),
234 complex(0.0, 0.0),
235 complex(0.0, 0.0),
236 complex(0.0, 0.0),
237 complex(1.0, 0.0),
238 complex(0.0, 0.0),
239 complex(0.0, 0.0),
240 complex(0.0, 0.0),
241 ],
242 [
243 complex(0.0, 0.0),
244 complex(0.0, 0.0),
245 complex(0.0, 0.0),
246 complex(0.0, 0.0),
247 complex(0.0, 0.0),
248 complex(1.0, 0.0),
249 complex(0.0, 0.0),
250 complex(0.0, 0.0),
251 ],
252 [
253 complex(0.0, 0.0),
254 complex(0.0, 0.0),
255 complex(0.0, 0.0),
256 complex(0.0, 0.0),
257 complex(0.0, 0.0),
258 complex(0.0, 0.0),
259 complex(0.0, 0.0),
260 complex(1.0, 0.0),
261 ],
262 [
263 complex(0.0, 0.0),
264 complex(0.0, 0.0),
265 complex(0.0, 0.0),
266 complex(0.0, 0.0),
267 complex(0.0, 0.0),
268 complex(0.0, 0.0),
269 complex(1.0, 0.0),
270 complex(0.0, 0.0),
271 ],
272 ]
273 qsharp.eval(
274 "operation ApplySWAP(qs : Qubit[]) : Unit is Ctl + Adj { SWAP(qs[0], qs[1]); }"
275 )
276 res = qsharp.utils.dump_operation("ApplySWAP", 2)
277 assert res == [
278 [complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
279 [complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0)],
280 [complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
281 [complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0)],
282 ]
283 res = qsharp.utils.dump_operation("qs => ()", 8)
284 for i in range(8):
285 for j in range(8):
286 if i == j:
287 assert res[i][j] == complex(1.0, 0.0)
288 else:
289 assert res[i][j] == complex(0.0, 0.0)
290
291
292def test_run_with_noise_produces_noisy_results() -> None:
293 qsharp.init()
294 qsharp.set_quantum_seed(0)
295 result = qsharp.run(
296 "{ mutable errors=0; for _ in 0..100 { use q1=Qubit(); use q2=Qubit(); H(q1); CNOT(q1, q2); if MResetZ(q1) != MResetZ(q2) { set errors+=1; } } errors }",
297 shots=1,
298 noise=qsharp.BitFlipNoise(0.1),
299 )
300 assert result[0] > 5
301 result = qsharp.run(
302 "{ mutable errors=0; for _ in 0..100 { use q=Qubit(); if MResetZ(q) != Zero { set errors+=1; } } errors }",
303 shots=1,
304 noise=qsharp.BitFlipNoise(0.1),
305 )
306 assert result[0] > 5
307
308
309def test_run_with_loss_produces_lossy_results() -> None:
310 qsharp.init()
311 qsharp.set_quantum_seed(0)
312 result = qsharp.run(
313 "{ use q = Qubit(); X(q); MResetZ(q) }",
314 shots=1,
315 qubit_loss=1.0,
316 )
317 assert result[0] == qsharp.Result.Loss
318
319
320def test_compile_qir_input_data() -> None:
321 qsharp.init(target_profile=qsharp.TargetProfile.Base)
322 qsharp.eval("operation Program() : Result { use q = Qubit(); return M(q) }")
323 operation = qsharp.compile("Program()")
324 qir = operation._repr_qir_()
325 assert isinstance(qir, bytes)
326
327
328def test_compile_qir_str() -> None:
329 qsharp.init(target_profile=qsharp.TargetProfile.Base)
330 qsharp.eval("operation Program() : Result { use q = Qubit(); return MResetZ(q); }")
331 operation = qsharp.compile("Program()")
332 qir = str(operation)
333 assert "define void @ENTRYPOINT__main()" in qir
334 assert '"required_num_qubits"="1" "required_num_results"="1"' in qir
335
336
337def test_compile_qir_str_from_python_callable() -> None:
338 qsharp.init(target_profile=qsharp.TargetProfile.Base)
339 qsharp.eval("operation Program() : Result { use q = Qubit(); return MResetZ(q); }")
340 operation = qsharp.compile(qsharp.code.Program)
341 qir = str(operation)
342 assert "define void @ENTRYPOINT__main()" in qir
343 assert '"required_num_qubits"="1" "required_num_results"="1"' in qir
344
345
346def test_compile_qir_str_from_python_callable_with_single_arg() -> None:
347 qsharp.init(target_profile=qsharp.TargetProfile.Base)
348 qsharp.eval(
349 "operation Program(nQubits : Int) : Result[] { use qs = Qubit[nQubits]; MResetEachZ(qs) }"
350 )
351 operation = qsharp.compile(qsharp.code.Program, 5)
352 qir = str(operation)
353 assert "define void @ENTRYPOINT__main()" in qir
354 assert (
355 "call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 4 to %Result*), i8* null)"
356 in qir
357 )
358 assert '"required_num_qubits"="5" "required_num_results"="5"' in qir
359
360
361def test_compile_qir_str_from_python_callable_with_array_arg() -> None:
362 qsharp.init(target_profile=qsharp.TargetProfile.Base)
363 qsharp.eval(
364 "operation Program(nQubits : Int[]) : Result[] { use qs = Qubit[nQubits[1]]; MResetEachZ(qs) }"
365 )
366 operation = qsharp.compile(qsharp.code.Program, [5, 3])
367 qir = str(operation)
368 assert "define void @ENTRYPOINT__main()" in qir
369 assert (
370 "call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* null)"
371 in qir
372 )
373 assert (
374 "call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 4 to %Result*), i8* null)"
375 not in qir
376 )
377 assert '"required_num_qubits"="3" "required_num_results"="3"' in qir
378
379
380def test_compile_qir_str_from_python_callable_with_multiple_args() -> None:
381 qsharp.init(target_profile=qsharp.TargetProfile.Base)
382 qsharp.eval(
383 "operation Program(nQubits : Int, nResults : Int) : Result[] { use qs = Qubit[nQubits]; MResetEachZ(qs)[...nResults-1] }"
384 )
385 operation = qsharp.compile(qsharp.code.Program, 5, 3)
386 qir = str(operation)
387 assert "define void @ENTRYPOINT__main()" in qir
388 assert (
389 "call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* null)"
390 in qir
391 )
392 assert (
393 "call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 4 to %Result*), i8* null)"
394 not in qir
395 )
396 assert '"required_num_qubits"="5" "required_num_results"="5"' in qir
397
398
399def test_compile_qir_str_from_python_callable_with_multiple_args_passed_as_tuple() -> (
400 None
401):
402 qsharp.init(target_profile=qsharp.TargetProfile.Base)
403 qsharp.eval(
404 "operation Program(nQubits : Int, nResults : Int) : Result[] { use qs = Qubit[nQubits]; MResetEachZ(qs)[...nResults-1] }"
405 )
406 args = (5, 3)
407 operation = qsharp.compile(qsharp.code.Program, args)
408 qir = str(operation)
409 assert "define void @ENTRYPOINT__main()" in qir
410 assert (
411 "call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* null)"
412 in qir
413 )
414 assert (
415 "call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 4 to %Result*), i8* null)"
416 not in qir
417 )
418 assert '"required_num_qubits"="5" "required_num_results"="5"' in qir
419
420
421def test_init_from_provider_name() -> None:
422 config = qsharp.init(target_name="ionq.simulator")
423 assert config._config["targetProfile"] == "base"
424 config = qsharp.init(target_name="rigetti.sim.qvm")
425 assert config._config["targetProfile"] == "base"
426 config = qsharp.init(target_name="quantinuum.sim")
427 assert config._config["targetProfile"] == "adaptive_ri"
428 config = qsharp.init(target_name="Quantinuum")
429 assert config._config["targetProfile"] == "adaptive_ri"
430 config = qsharp.init(target_name="IonQ")
431 assert config._config["targetProfile"] == "base"
432
433
434def test_run_with_result(capsys) -> None:
435 qsharp.init()
436 qsharp.eval('operation Foo() : Result { Message("Hello, world!"); Zero }')
437 results = qsharp.run("Foo()", 3)
438 assert results == [qsharp.Result.Zero, qsharp.Result.Zero, qsharp.Result.Zero]
439 stdout = capsys.readouterr().out
440 assert stdout == "Hello, world!\nHello, world!\nHello, world!\n"
441
442
443def test_run_with_result_from_callable(capsys) -> None:
444 qsharp.init()
445 qsharp.eval(
446 'operation Foo() : Result { Message("Hello, world!"); use q = Qubit(); M(q) }'
447 )
448 results = qsharp.run(qsharp.code.Foo, 3)
449 assert results == [qsharp.Result.Zero, qsharp.Result.Zero, qsharp.Result.Zero]
450 stdout = capsys.readouterr().out
451 assert stdout == "Hello, world!\nHello, world!\nHello, world!\n"
452
453
454def test_run_with_result_from_callable_while_global_qubits_allocated(capsys) -> None:
455 qsharp.init()
456 qsharp.eval("use q = Qubit();")
457 qsharp.eval(
458 'operation Foo() : Result { Message("Hello, world!"); use q = Qubit(); M(q) }'
459 )
460 results = qsharp.run(qsharp.code.Foo, 3)
461 assert results == [qsharp.Result.Zero, qsharp.Result.Zero, qsharp.Result.Zero]
462 stdout = capsys.readouterr().out
463 assert stdout == "Hello, world!\nHello, world!\nHello, world!\n"
464
465
466def test_run_with_result_callback(capsys) -> None:
467 def on_result(result):
468 nonlocal called
469 called = True
470 assert result["result"] == qsharp.Result.Zero
471 assert str(result["events"]) == "[Hello, world!]"
472
473 called = False
474 qsharp.init()
475 qsharp.eval('operation Foo() : Result { Message("Hello, world!"); Zero }')
476 results = qsharp.run("Foo()", 3, on_result=on_result, save_events=True)
477 assert (
478 str(results)
479 == "[{'result': Zero, 'events': [Hello, world!], 'messages': ['Hello, world!'], 'matrices': [], 'dumps': []}, {'result': Zero, 'events': [Hello, world!], 'messages': ['Hello, world!'], 'matrices': [], 'dumps': []}, {'result': Zero, 'events': [Hello, world!], 'messages': ['Hello, world!'], 'matrices': [], 'dumps': []}]"
480 )
481 stdout = capsys.readouterr().out
482 assert stdout == ""
483 assert called
484
485
486def test_run_with_result_callback_from_callable_with_args(capsys) -> None:
487 def on_result(result):
488 nonlocal called
489 called = True
490 assert result["result"] == [qsharp.Result.Zero, qsharp.Result.Zero]
491 assert str(result["events"]) == "[Hello, world!]"
492
493 called = False
494 qsharp.init()
495 qsharp.eval(
496 'operation Foo(nResults : Int) : Result[] { Message("Hello, world!"); Repeated(Zero, nResults) }'
497 )
498 results = qsharp.run(qsharp.code.Foo, 3, 2, on_result=on_result, save_events=True)
499 assert (
500 str(results)
501 == "[{'result': [Zero, Zero], 'events': [Hello, world!], 'messages': ['Hello, world!'], 'matrices': [], 'dumps': []}, {'result': [Zero, Zero], 'events': [Hello, world!], 'messages': ['Hello, world!'], 'matrices': [], 'dumps': []}, {'result': [Zero, Zero], 'events': [Hello, world!], 'messages': ['Hello, world!'], 'matrices': [], 'dumps': []}]"
502 )
503 stdout = capsys.readouterr().out
504 assert stdout == ""
505 assert called
506
507
508def test_run_with_invalid_shots_produces_error() -> None:
509 qsharp.init()
510 qsharp.eval('operation Foo() : Result { Message("Hello, world!"); Zero }')
511 try:
512 qsharp.run("Foo()", -1)
513 except ValueError as e:
514 assert str(e) == "The number of shots must be greater than 0."
515 else:
516 assert False
517
518 try:
519 qsharp.run("Foo()", 0)
520 except ValueError as e:
521 assert str(e) == "The number of shots must be greater than 0."
522 else:
523 assert False
524
525
526def test_callables_exposed_into_env() -> None:
527 qsharp.init()
528 qsharp.eval("function Four() : Int { 4 }")
529 assert qsharp.code.Four() == 4, "callable should be available"
530 qsharp.eval("function Add(a : Int, b : Int) : Int { a + b }")
531 assert qsharp.code.Four() == 4, "first callable should still be available"
532 assert qsharp.code.Add(2, 3) == 5, "second callable should be available"
533 # After init, the callables should be cleared and no longer available
534 qsharp.init()
535 with pytest.raises(AttributeError):
536 qsharp.code.Four()
537
538
539def test_callable_exposed_into_env_complex_types() -> None:
540 qsharp.eval(
541 "function Complicated(a : Int, b : (Double, BigInt)) : ((Double, BigInt), Int) { (b, a) }"
542 )
543 assert qsharp.code.Complicated(2, (3.0, 4000000000000000000000)) == (
544 (3.0, 4000000000000000000000),
545 2,
546 ), "callables that take complex types should marshall them correctly"
547
548
549def test_callable_exposed_into_env_with_array() -> None:
550 qsharp.init()
551 qsharp.eval("function Smallest(a : Int[]) : Int { Std.Math.Min(a)}")
552 assert (
553 qsharp.code.Smallest([1, 2, 3, 0, 4, 5]) == 0
554 ), "callable that takes array should work"
555
556
557def test_callable_with_int_exposed_into_env_fails_incorrect_types() -> None:
558 qsharp.init()
559 qsharp.eval("function Identity(a : Int) : Int { a }")
560 assert qsharp.code.Identity(4) == 4
561 with pytest.raises(TypeError):
562 qsharp.code.Identity("4")
563 with pytest.raises(TypeError):
564 qsharp.code.Identity(4.0)
565 with pytest.raises(OverflowError):
566 qsharp.code.Identity(4000000000000000000000)
567 with pytest.raises(TypeError):
568 qsharp.code.Identity([4])
569
570
571def test_callable_with_double_exposed_into_env_fails_incorrect_types() -> None:
572 qsharp.init()
573 qsharp.eval("function Identity(a : Double) : Double { a }")
574 assert qsharp.code.Identity(4.0) == 4.0
575 assert qsharp.code.Identity(4) == 4.0
576 with pytest.raises(TypeError):
577 qsharp.code.Identity("4")
578 with pytest.raises(TypeError):
579 qsharp.code.Identity([4])
580
581
582def test_callable_with_bigint_exposed_into_env_fails_incorrect_types() -> None:
583 qsharp.init()
584 qsharp.eval("function Identity(a : BigInt) : BigInt { a }")
585 assert qsharp.code.Identity(4000000000000000000000) == 4000000000000000000000
586 with pytest.raises(TypeError):
587 qsharp.code.Identity("4")
588 with pytest.raises(TypeError):
589 qsharp.code.Identity(4.0)
590
591
592def test_callable_with_string_exposed_into_env_fails_incorrect_types() -> None:
593 qsharp.init()
594 qsharp.eval("function Identity(a : String) : String { a }")
595 assert qsharp.code.Identity("4") == "4"
596 with pytest.raises(TypeError):
597 qsharp.code.Identity(4)
598 with pytest.raises(TypeError):
599 qsharp.code.Identity(4.0)
600 with pytest.raises(TypeError):
601 qsharp.code.Identity([4])
602
603
604def test_callable_with_bool_exposed_into_env_fails_incorrect_types() -> None:
605 qsharp.init()
606 qsharp.eval("function Identity(a : Bool) : Bool { a }")
607 assert qsharp.code.Identity(True) == True
608 with pytest.raises(TypeError):
609 qsharp.code.Identity("4")
610 with pytest.raises(TypeError):
611 qsharp.code.Identity(4)
612 with pytest.raises(TypeError):
613 qsharp.code.Identity(4.0)
614 with pytest.raises(TypeError):
615 qsharp.code.Identity([4])
616
617
618def test_callable_with_array_exposed_into_env_fails_incorrect_types() -> None:
619 qsharp.init()
620 qsharp.eval("function Identity(a : Int[]) : Int[] { a }")
621 assert qsharp.code.Identity([4, 5, 6]) == [4, 5, 6]
622 assert qsharp.code.Identity([]) == []
623 assert qsharp.code.Identity((4, 5, 6)) == [4, 5, 6]
624 with pytest.raises(TypeError):
625 qsharp.code.Identity(4)
626 with pytest.raises(TypeError):
627 qsharp.code.Identity("4")
628 with pytest.raises(TypeError):
629 qsharp.code.Identity(4.0)
630 with pytest.raises(TypeError):
631 qsharp.code.Identity([1, 2, 3.0])
632
633
634def test_callable_with_tuple_exposed_into_env_fails_incorrect_types() -> None:
635 qsharp.init()
636 qsharp.eval("function Identity(a : (Int, Double)) : (Int, Double) { a }")
637 assert qsharp.code.Identity((4, 5.0)) == (4, 5.0)
638 assert qsharp.code.Identity((4, 5)) == (4, 5.0)
639 assert qsharp.code.Identity([4, 5.0]) == (4, 5.0)
640 with pytest.raises(qsharp.QSharpError):
641 qsharp.code.Identity((4, 5, 6))
642 with pytest.raises(TypeError):
643 qsharp.code.Identity(4)
644 with pytest.raises(TypeError):
645 qsharp.code.Identity("4")
646 with pytest.raises(TypeError):
647 qsharp.code.Identity(4.0)
648 with pytest.raises(TypeError):
649 qsharp.code.Identity([4.0, 5])
650
651
652def test_callables_in_namespaces_exposed_into_env_submodules_and_removed_on_reinit() -> (
653 None
654):
655 qsharp.init()
656 # callables should be created with their namespaces
657 qsharp.eval("namespace Test { function Four() : Int { 4 } }")
658 qsharp.eval("function Identity(a : Int) : Int { a }")
659 # should be able to import callables from env and namespace submodule
660 from qsharp.code import Identity
661 from qsharp.code.Test import Four
662
663 assert Identity(4) == 4
664 assert Four() == 4
665 qsharp.init()
666 # namespaces should be removed
667 with pytest.raises(AttributeError):
668 qsharp.code.Test
669 with pytest.raises(AttributeError):
670 qsharp.code.Identity()
671 # imported callables should fail gracefully
672 with pytest.raises(qsharp.QSharpError):
673 Four()
674
675
676def test_callables_with_unsupported_types_raise_errors_on_call() -> None:
677 qsharp.init()
678 qsharp.eval("function Unsupported(a : Int, q : Qubit) : Unit { }")
679 with pytest.raises(qsharp.QSharpError, match="unsupported input type: `Qubit`"):
680 qsharp.code.Unsupported()
681
682
683def test_callables_with_unsupported_types_in_tuples_raise_errors_on_call() -> None:
684 qsharp.init()
685 qsharp.eval("function Unsupported(q : (Int, Qubit)[]) : Unit { }")
686 with pytest.raises(qsharp.QSharpError, match="unsupported input type: `Qubit`"):
687 qsharp.code.Unsupported()
688
689
690def test_callables_with_unsupported_return_types_raise_errors_on_call() -> None:
691 qsharp.init()
692 qsharp.eval('function Unsupported() : Qubit { fail "won\'t be called" }')
693 with pytest.raises(qsharp.QSharpError, match="unsupported output type: `Qubit`"):
694 qsharp.code.Unsupported()
695
696
697def test_callables_with_unsupported_udt_types_raise_errors_on_call() -> None:
698 qsharp.init()
699 qsharp.eval("function Unsupported(a : Std.Math.Complex) : Unit { }")
700 with pytest.raises(
701 qsharp.QSharpError, match='unsupported input type: `UDT<"Complex":'
702 ):
703 qsharp.code.Unsupported()
704
705
706def test_callable_with_unsupported_udt_return_types_raise_errors_on_call() -> None:
707 qsharp.init()
708 qsharp.eval('function Unsupported() : Std.Math.Complex { fail "won\'t be called" }')
709 with pytest.raises(
710 qsharp.QSharpError, match='unsupported output type: `UDT<"Complex":'
711 ):
712 qsharp.code.Unsupported()
713
714
715def test_struct_call_constructor_not_exposed_into_env() -> None:
716 qsharp.init()
717 qsharp.eval("struct CustomUDT { a : Int }")
718 with pytest.raises(AttributeError):
719 qsharp.code.CustomUDT
720
721
722def test_lambdas_not_exposed_into_env() -> None:
723 qsharp.init()
724 qsharp.eval("a -> a + 1")
725 assert not hasattr(qsharp.code, "<lambda>")
726 qsharp.eval("q => I(q)")
727 assert not hasattr(qsharp.code, "<lambda>")
728
729
730def test_circuit_from_callable() -> None:
731 qsharp.init()
732 qsharp.eval(
733 """
734 operation Foo() : Unit {
735 use q1 = Qubit();
736 use q2 = Qubit();
737 X(q1);
738 }
739 """
740 )
741 circuit = qsharp.circuit(qsharp.code.Foo)
742 assert str(circuit) == dedent(
743 """\
744 q_0 ── X ──
745 q_1 ───────
746 """
747 )
748
749
750def test_circuit_from_callable_with_args() -> None:
751 qsharp.init()
752 qsharp.eval(
753 """
754 operation Foo(nQubits : Int) : Unit {
755 use qs = Qubit[nQubits];
756 ApplyToEach(X, qs);
757 }
758 """
759 )
760 circuit = qsharp.circuit(qsharp.code.Foo, 2)
761 assert str(circuit) == dedent(
762 """\
763 q_0 ── X ──
764 q_1 ── X ──
765 """
766 )
767
768
769def test_circuit_with_measure_from_callable() -> None:
770 qsharp.init()
771 qsharp.eval("operation Foo() : Result { use q = Qubit(); H(q); return M(q) }")
772 circuit = qsharp.circuit(qsharp.code.Foo)
773 assert str(circuit) == dedent(
774 """\
775 q_0 ── H ──── M ──
776 ╘═══
777 """
778 )
779
780
781def test_swap_label_circuit_from_callable() -> None:
782 qsharp.init()
783 qsharp.eval(
784 "operation Foo() : Unit { use q1 = Qubit(); use q2 = Qubit(); X(q1); Relabel([q1, q2], [q2, q1]); X(q2); }"
785 )
786 circuit = qsharp.circuit(qsharp.code.Foo)
787 assert str(circuit) == dedent(
788 """\
789 q_0 ── X ──── X ──
790 q_1 ──────────────
791 """
792 )
793