microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
minestarks/circuit-magic

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/pip/tests/test_qsharp.py

903lines ยท 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_run_with_complex_udt() -> None:
527 qsharp.init()
528 val = qsharp.run(
529 """
530 {
531 new Std.Math.Complex { Real = 2., Imag = 3. }
532 }
533 """,
534 2,
535 )[0]
536 assert val == 2 + 3j
537
538
539def test_identity_returning_complex_udt() -> None:
540 qsharp.init()
541 qsharp.eval("function Identity(a : Std.Math.Complex) : Std.Math.Complex { a }")
542 assert qsharp.code.Identity(2 + 3j) == 2 + 3j
543
544
545def test_run_with_udt() -> None:
546 qsharp.init()
547 val = qsharp.run(
548 """
549 {
550 struct Data { a : Int, b : Int }
551 new Data { a = 2, b = 3 }
552 }
553 """,
554 2,
555 )[0]
556 assert val.a == 2 and val.b == 3
557
558
559def test_callables_exposed_into_env() -> None:
560 qsharp.init()
561 qsharp.eval("function Four() : Int { 4 }")
562 assert qsharp.code.Four() == 4, "callable should be available"
563 qsharp.eval("function Add(a : Int, b : Int) : Int { a + b }")
564 assert qsharp.code.Four() == 4, "first callable should still be available"
565 assert qsharp.code.Add(2, 3) == 5, "second callable should be available"
566 # After init, the callables should be cleared and no longer available
567 qsharp.init()
568 with pytest.raises(AttributeError):
569 qsharp.code.Four()
570
571
572def test_callable_exposed_into_env_complex_types() -> None:
573 qsharp.eval(
574 "function Complicated(a : Int, b : (Double, BigInt)) : ((Double, BigInt), Int) { (b, a) }"
575 )
576 assert qsharp.code.Complicated(2, (3.0, 4000000000000000000000)) == (
577 (3.0, 4000000000000000000000),
578 2,
579 ), "callables that take complex types should marshall them correctly"
580
581
582def test_callable_exposed_into_env_with_array() -> None:
583 qsharp.init()
584 qsharp.eval("function Smallest(a : Int[]) : Int { Std.Math.Min(a)}")
585 assert (
586 qsharp.code.Smallest([1, 2, 3, 0, 4, 5]) == 0
587 ), "callable that takes array should work"
588
589
590def test_callable_with_int_exposed_into_env_fails_incorrect_types() -> None:
591 qsharp.init()
592 qsharp.eval("function Identity(a : Int) : Int { a }")
593 assert qsharp.code.Identity(4) == 4
594 with pytest.raises(TypeError):
595 qsharp.code.Identity("4")
596 with pytest.raises(TypeError):
597 qsharp.code.Identity(4.0)
598 with pytest.raises(OverflowError):
599 qsharp.code.Identity(4000000000000000000000)
600 with pytest.raises(TypeError):
601 qsharp.code.Identity([4])
602
603
604def test_callable_with_double_exposed_into_env_fails_incorrect_types() -> None:
605 qsharp.init()
606 qsharp.eval("function Identity(a : Double) : Double { a }")
607 assert qsharp.code.Identity(4.0) == 4.0
608 assert qsharp.code.Identity(4) == 4.0
609 with pytest.raises(TypeError):
610 qsharp.code.Identity("4")
611 with pytest.raises(TypeError):
612 qsharp.code.Identity([4])
613
614
615def test_callable_with_bigint_exposed_into_env_fails_incorrect_types() -> None:
616 qsharp.init()
617 qsharp.eval("function Identity(a : BigInt) : BigInt { a }")
618 assert qsharp.code.Identity(4000000000000000000000) == 4000000000000000000000
619 with pytest.raises(TypeError):
620 qsharp.code.Identity("4")
621 with pytest.raises(TypeError):
622 qsharp.code.Identity(4.0)
623
624
625def test_callable_with_string_exposed_into_env_fails_incorrect_types() -> None:
626 qsharp.init()
627 qsharp.eval("function Identity(a : String) : String { a }")
628 assert qsharp.code.Identity("4") == "4"
629 with pytest.raises(TypeError):
630 qsharp.code.Identity(4)
631 with pytest.raises(TypeError):
632 qsharp.code.Identity(4.0)
633 with pytest.raises(TypeError):
634 qsharp.code.Identity([4])
635
636
637def test_callable_with_bool_exposed_into_env_fails_incorrect_types() -> None:
638 qsharp.init()
639 qsharp.eval("function Identity(a : Bool) : Bool { a }")
640 assert qsharp.code.Identity(True) == True
641 with pytest.raises(TypeError):
642 qsharp.code.Identity("4")
643 with pytest.raises(TypeError):
644 qsharp.code.Identity(4)
645 with pytest.raises(TypeError):
646 qsharp.code.Identity(4.0)
647 with pytest.raises(TypeError):
648 qsharp.code.Identity([4])
649
650
651def test_callable_with_array_exposed_into_env_fails_incorrect_types() -> None:
652 qsharp.init()
653 qsharp.eval("function Identity(a : Int[]) : Int[] { a }")
654 assert qsharp.code.Identity([4, 5, 6]) == [4, 5, 6]
655 assert qsharp.code.Identity([]) == []
656 assert qsharp.code.Identity((4, 5, 6)) == [4, 5, 6]
657 # This assert tests Iterables, numpy arrays fall under this category.
658 assert qsharp.code.Identity((elt for elt in range(4, 7))) == [4, 5, 6]
659 with pytest.raises(TypeError):
660 qsharp.code.Identity(4)
661 with pytest.raises(TypeError):
662 qsharp.code.Identity("4")
663 with pytest.raises(TypeError):
664 qsharp.code.Identity(4.0)
665 with pytest.raises(TypeError):
666 qsharp.code.Identity([1, 2, 3.0])
667
668
669def test_callable_with_tuple_exposed_into_env_fails_incorrect_types() -> None:
670 qsharp.init()
671 qsharp.eval("function Identity(a : (Int, Double)) : (Int, Double) { a }")
672 assert qsharp.code.Identity((4, 5.0)) == (4, 5.0)
673 assert qsharp.code.Identity((4, 5)) == (4, 5.0)
674 assert qsharp.code.Identity([4, 5.0]) == (4, 5.0)
675 with pytest.raises(TypeError):
676 qsharp.code.Identity((4, 5, 6))
677 with pytest.raises(TypeError):
678 qsharp.code.Identity(4)
679 with pytest.raises(TypeError):
680 qsharp.code.Identity("4")
681 with pytest.raises(TypeError):
682 qsharp.code.Identity(4.0)
683 with pytest.raises(TypeError):
684 qsharp.code.Identity([4.0, 5])
685
686
687def test_callables_in_namespaces_exposed_into_env_submodules_and_removed_on_reinit() -> (
688 None
689):
690 qsharp.init()
691 # callables should be created with their namespaces
692 qsharp.eval("namespace Test { function Four() : Int { 4 } }")
693 qsharp.eval("function Identity(a : Int) : Int { a }")
694 # should be able to import callables from env and namespace submodule
695 from qsharp.code import Identity
696 from qsharp.code.Test import Four
697
698 assert Identity(4) == 4
699 assert Four() == 4
700 qsharp.init()
701 # namespaces should be removed
702 with pytest.raises(AttributeError):
703 qsharp.code.Test
704 with pytest.raises(AttributeError):
705 qsharp.code.Identity()
706 # imported callables should fail gracefully
707 with pytest.raises(qsharp.QSharpError):
708 Four()
709
710
711def test_callables_with_unsupported_types_raise_errors_on_call() -> None:
712 qsharp.init()
713 qsharp.eval("function Unsupported(a : Int, q : Qubit) : Unit { }")
714 with pytest.raises(qsharp.QSharpError, match="unsupported input type: `Qubit`"):
715 qsharp.code.Unsupported()
716
717
718def test_callables_with_unsupported_types_in_tuples_raise_errors_on_call() -> None:
719 qsharp.init()
720 qsharp.eval("function Unsupported(q : (Int, Qubit)[]) : Unit { }")
721 with pytest.raises(qsharp.QSharpError, match="unsupported input type: `Qubit`"):
722 qsharp.code.Unsupported()
723
724
725def test_callables_with_unsupported_return_types_raise_errors_on_call() -> None:
726 qsharp.init()
727 qsharp.eval('function Unsupported() : Qubit { fail "won\'t be called" }')
728 with pytest.raises(qsharp.QSharpError, match="unsupported output type: `Qubit`"):
729 qsharp.code.Unsupported()
730
731
732def test_callable_with_unsupported_udt_type_raises_error_on_call() -> None:
733 qsharp.init()
734 qsharp.eval(
735 """
736 newtype Data = (Int, Double);
737 function Unsupported(a : Data) : Unit { }
738 """
739 )
740 with pytest.raises(
741 qsharp.QSharpError, match='unsupported input type: `UDT<"Data":'
742 ):
743 qsharp.code.Unsupported()
744
745
746def test_callable_with_unsupported_udt_return_type_raises_error_on_call() -> None:
747 qsharp.init()
748 qsharp.eval(
749 """
750 newtype Data = (Int, Double);
751 function Unsupported() : Data { fail "won\'t be called" }
752 """
753 )
754 with pytest.raises(
755 qsharp.QSharpError, match='unsupported output type: `UDT<"Data":'
756 ):
757 qsharp.code.Unsupported()
758
759
760def test_returning_unsupported_udt_from_eval_raises_error_on_call() -> None:
761 qsharp.init()
762 with pytest.raises(
763 TypeError, match="structs with anonymous fields are not supported: Data"
764 ):
765 qsharp.eval(
766 """
767 {
768 newtype Data = (Int, Double);
769 Data(2, 3.0)
770 }
771 """
772 )
773
774
775def test_struct_call_constructor_exposed_into_env() -> None:
776 qsharp.init()
777 qsharp.eval("struct CustomUDT { a : Int }")
778 val = qsharp.code.CustomUDT(2)
779 assert val.a == 2
780
781
782def test_udts_are_accepted_as_input() -> None:
783 qsharp.init()
784 qsharp.eval(
785 """
786 struct Data { a : Int, b : Int }
787 function SwapData(data : Data) : Data {
788 new Data { a = data.b, b = data.a }
789 }
790 """
791 )
792 # Dict
793 val = qsharp.code.SwapData({"a": 2, "b": 3})
794 assert val.a == 3 and val.b == 2
795
796 # qsharp.code class
797 val = qsharp.code.SwapData(qsharp.code.Data(2, 3))
798 assert val.a == 3 and val.b == 2
799
800 # Custom class
801 class CustomData:
802 def __init__(self, a, b):
803 self.a = a
804 self.b = b
805
806 val = qsharp.code.SwapData(CustomData(2, 3))
807 assert val.a == 3 and val.b == 2
808
809 # Custom class with slots
810 class CustomDataWithSlots:
811 __slots__ = ["a", "b"]
812
813 def __init__(self, a, b):
814 self.a = a
815 self.b = b
816
817 val = qsharp.code.SwapData(CustomDataWithSlots(2, 3))
818 assert val.a == 3 and val.b == 2
819
820 # Custom class with slots and dynamic values
821 class CustomDataWithSlotsAndDynValues:
822 __slots__ = ["a", "__dict__"]
823
824 def __init__(self, a):
825 self.a = a
826
827 data = CustomDataWithSlotsAndDynValues(2)
828 data.b = 3
829 val = qsharp.code.SwapData(data)
830 assert val.a == 3 and val.b == 2
831
832
833def test_lambdas_not_exposed_into_env() -> None:
834 qsharp.init()
835 qsharp.eval("a -> a + 1")
836 assert not hasattr(qsharp.code, "<lambda>")
837 qsharp.eval("q => I(q)")
838 assert not hasattr(qsharp.code, "<lambda>")
839
840
841def test_circuit_from_callable() -> None:
842 qsharp.init()
843 qsharp.eval(
844 """
845 operation Foo() : Unit {
846 use q1 = Qubit();
847 use q2 = Qubit();
848 X(q1);
849 }
850 """
851 )
852 circuit = qsharp.circuit(qsharp.code.Foo)
853 assert str(circuit) == dedent(
854 """\
855 q_0 โ”€โ”€ X โ”€โ”€
856 q_1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€
857 """
858 )
859
860
861def test_circuit_from_callable_with_args() -> None:
862 qsharp.init()
863 qsharp.eval(
864 """
865 operation Foo(nQubits : Int) : Unit {
866 use qs = Qubit[nQubits];
867 ApplyToEach(X, qs);
868 }
869 """
870 )
871 circuit = qsharp.circuit(qsharp.code.Foo, 2)
872 assert str(circuit) == dedent(
873 """\
874 q_0 โ”€โ”€ X โ”€โ”€
875 q_1 โ”€โ”€ X โ”€โ”€
876 """
877 )
878
879
880def test_circuit_with_measure_from_callable() -> None:
881 qsharp.init()
882 qsharp.eval("operation Foo() : Result { use q = Qubit(); H(q); return M(q) }")
883 circuit = qsharp.circuit(qsharp.code.Foo)
884 assert str(circuit) == dedent(
885 """\
886 q_0 โ”€โ”€ H โ”€โ”€โ”€โ”€ M โ”€โ”€
887 โ•˜โ•โ•โ•
888 """
889 )
890
891
892def test_swap_label_circuit_from_callable() -> None:
893 qsharp.init()
894 qsharp.eval(
895 "operation Foo() : Unit { use q1 = Qubit(); use q2 = Qubit(); X(q1); Relabel([q1, q2], [q2, q1]); X(q2); }"
896 )
897 circuit = qsharp.circuit(qsharp.code.Foo)
898 assert str(circuit) == dedent(
899 """\
900 q_0 โ”€โ”€ X โ”€โ”€โ”€โ”€ X โ”€โ”€
901 q_1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
902 """
903 )
904