Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update to pytket qir 0.13.0 #499

Merged
merged 7 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Unreleased

* Fix handling of unused bits in local emulator.
* Update machine specs in offline API.
* Update pytket-qir version requirement to 0.13.
* Add language option for profile compatible QIR

0.37.0 (August 2024)
--------------------
Expand Down
49 changes: 41 additions & 8 deletions pytket/extensions/quantinuum/backends/quantinuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,17 @@ class DeviceNotAvailable(Exception):
class Language(Enum):
"""Language used for submission of circuits."""

QASM = "OPENQASM 2.0"
QIR = "QIR 1.0"
QASM = 0 # "OPENQASM 2.0"
QIR = 1 # pytket qir with classical functions: "QIR 1.0"
PQIR = 2 # profile QIR: "QIR 1.0"


def _language2str(language: Language) -> str:
"""returns matching string for Language enum"""
if language == Language.QASM:
return "OPENQASM 2.0"
else:
return "QIR 1.0"


# DEFAULT_CREDENTIALS_STORAGE for use with the DEFAULT_API_HANDLER.
Expand Down Expand Up @@ -835,7 +844,7 @@ def submit_program(
"name": name or f"{self._label}",
"count": n_shots,
"machine": self._device_name,
"language": language.value,
"language": _language2str(language),
"program": program,
"priority": "normal",
"options": {
Expand All @@ -858,6 +867,8 @@ def submit_program(
if wasm_file_handler is not None:
if self.backend_info and not self.backend_info.misc.get("wasm", False):
raise WasmUnsupported("Backend does not support wasm calls.")
# body["bytecode_base64"] = wasm_file_handler._wasm_file_encoded
# see https://github.com/CQCL/pytket-quantinuum/issues/496
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we leaving this change for another PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, using body["cfl"] gives a warning, but the suggested body["bytecode_base64"] is not yet working, or we are missing details on how to use it. There is an issue linked, I will try to solve this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's not how I would interpret the warning, looks to me like it's coming from Python, not L4?

body["cfl"] = wasm_file_handler._wasm_file_encoded.decode("utf-8")

body["options"].update(self._process_circuits_options)
Expand Down Expand Up @@ -1032,8 +1043,10 @@ def process_circuits(
).items():
for i in range(count):
results_selection.append((name, i))

else:
assert language == Language.QIR
assert language == Language.QIR or language == Language.PQIR
profile = language == Language.PQIR
for name, count in Counter(bit.reg_name for bit in c0.bits).items():
for i in range(count):
results_selection.append((name, i))
Expand All @@ -1046,6 +1059,7 @@ def process_circuits(
"circuit generated by pytket-qir",
QIRFormat.BINARY,
wfh=wasm_fh,
profile=profile,
),
)
).decode("utf-8")
Expand Down Expand Up @@ -1490,10 +1504,29 @@ def _convert_result(
c_bits = [Bit(name, ind) for name, ind in results_selection]

# Construct the shots table
stacked_array = [
[int(resultdict[name][i][-1 - ind]) for name, ind in results_selection]
for i in range(n_shots)
]

try:
stacked_array = [
[int(resultdict[name][i][-1 - ind]) for name, ind in results_selection]
for i in range(n_shots)
]
except IndexError:
# this is only a temporary solution and not fully working
# see issue https://github.com/CQCL/pytket-quantinuum/issues/501
stacked_array = [
[
int(
bin(int(resultdict[name][i])).replace(
"0b",
"0000000000000000000000000000000000000\
00000000000000000000000000", # 0 * 63
)[-1 - ind]
)
for name, ind in results_selection
]
for i in range(n_shots)
]

return BackendResult(
c_bits=c_bits,
shots=OutcomeArray.from_readouts(stacked_array),
Expand Down
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@
packages=find_namespace_packages(include=["pytket.*"]),
include_package_data=True,
install_requires=[
"pytket >= 1.31.0",
"pytket-qir >= 0.13",
"pytket >= 1.33.0",
"pytket-qir >= 0.12.0",
"pytket-qir >= 0.13",
"requests >= 2.2",
"types-requests",
"websockets >= 7.0",
Expand Down
54 changes: 34 additions & 20 deletions tests/integration/backend_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

@pytest.mark.skipif(skip_remote_tests, reason=REASON)
@pytest.mark.parametrize("authenticated_quum_backend_qa", [None], indirect=True)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(120)
def test_quantinuum(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand Down Expand Up @@ -144,7 +144,7 @@ def test_max_classical_register(
@pytest.mark.parametrize(
"authenticated_quum_backend_qa", [{"device_name": "H1-1SC"}], indirect=True
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(120)
def test_bell(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand All @@ -166,7 +166,7 @@ def test_bell(
[{"device_name": "H1-1SC", "label": "test 3"}],
indirect=True,
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(120)
def test_multireg(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand Down Expand Up @@ -382,7 +382,14 @@ def test_cost_estimate_bad_syntax_checker(
[{"device_name": name} for name in pytest.ALL_SYNTAX_CHECKER_NAMES], # type: ignore
indirect=True,
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize(
"language",
[
Language.QASM,
Language.QIR,
Language.PQIR,
],
)
@pytest.mark.timeout(120)
def test_classical(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand Down Expand Up @@ -435,6 +442,7 @@ def test_classical(
"language",
[
Language.QIR,
Language.PQIR,
pytest.param(
Language.QASM,
marks=pytest.mark.xfail(reason="https://github.com/CQCL/tket/issues/1173"),
Expand Down Expand Up @@ -467,7 +475,7 @@ def test_division(
[{"device_name": name} for name in pytest.ALL_SYNTAX_CHECKER_NAMES], # type: ignore
indirect=True,
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(120)
def test_postprocess(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand Down Expand Up @@ -543,7 +551,7 @@ def test_shots_bits_edgecases(n_shots, n_bits) -> None:
@pytest.mark.parametrize(
"authenticated_quum_backend_qa", [{"device_name": "H1-1E"}], indirect=True
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(200)
def test_simulator(
authenticated_quum_handler: QuantinuumAPI,
Expand Down Expand Up @@ -637,7 +645,7 @@ def test_batching(
[{"device_name": name} for name in pytest.ALL_SYNTAX_CHECKER_NAMES], # type: ignore
indirect=True,
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(120)
def test_submission_with_group(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand All @@ -662,7 +670,7 @@ def test_submission_with_group(
@pytest.mark.parametrize(
"authenticated_quum_backend_qa", [{"device_name": "H1-1SC"}], indirect=True
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(120)
def test_zzphase(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand Down Expand Up @@ -763,6 +771,7 @@ def test_device_state(
[
Language.QASM,
Language.QIR,
Language.PQIR,
],
)
@pytest.mark.timeout(120)
Expand Down Expand Up @@ -796,6 +805,7 @@ def test_wasm_qa(
[
Language.QASM,
Language.QIR,
Language.PQIR,
],
)
@pytest.mark.timeout(120)
Expand Down Expand Up @@ -883,7 +893,7 @@ def test_submit_qasm(
[{"device_name": name} for name in pytest.ALL_SYNTAX_CHECKER_NAMES], # type: ignore
indirect=True,
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(120)
def test_options(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand All @@ -905,7 +915,7 @@ def test_options(
[{"device_name": name} for name in pytest.ALL_SYNTAX_CHECKER_NAMES], # type: ignore
indirect=True,
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(120)
def test_tk2(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand Down Expand Up @@ -1055,7 +1065,7 @@ def test_qir_conversion(authenticated_quum_backend_qa: QuantinuumBackend) -> Non
c0 = Circuit(2).H(0).CX(0, 1).measure_all()
b = authenticated_quum_backend_qa
c = b.get_compiled_circuit(c0)
h = b.process_circuit(c, n_shots=10, language=Language.QIR)
h = b.process_circuit(c, n_shots=10, language=Language.PQIR)
r = b.get_result(h)
shots = r.get_shots()
assert len(shots) == 10
Expand Down Expand Up @@ -1142,13 +1152,14 @@ def test_scratch_removal(authenticated_quum_backend_qa: QuantinuumBackend) -> No
[
Language.QASM,
Language.QIR,
Language.PQIR,
],
)
@pytest.mark.timeout(120)
def test_wasm_collatz(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
) -> None:
wasfile = WasmFileHandler(
wasmfile = WasmFileHandler(
str(Path(__file__).parent.parent / "wasm" / "collatz.wasm")
)
c = Circuit(8)
Expand All @@ -1160,13 +1171,13 @@ def test_wasm_collatz(
c.H(i)
c.Measure(Qubit(i), Bit("a", i))
# Compute the value of the Collatz function on this value.
c.add_wasm_to_reg("collatz", wasfile, [a], [b])
c.add_wasm_to_reg("collatz", wasmfile, [a], [b])

backend = authenticated_quum_backend_qa

c = backend.get_compiled_circuit(c)
h = backend.process_circuit(
c, n_shots=10, wasm_file_handler=wasfile, language=language
c, n_shots=10, wasm_file_handler=wasmfile, language=language
)

r = backend.get_result(h)
Expand Down Expand Up @@ -1199,13 +1210,16 @@ def collatz(n: int) -> int:
[
Language.QASM,
Language.QIR,
Language.PQIR,
],
)
@pytest.mark.timeout(120)
def test_wasm_state(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
) -> None:
wasfile = WasmFileHandler(str(Path(__file__).parent.parent / "wasm" / "state.wasm"))
wasmfile = WasmFileHandler(
str(Path(__file__).parent.parent / "wasm" / "state.wasm")
)
c = Circuit(8)
a = c.add_c_register("a", 8).to_list() # measurement results
b = c.add_c_register("b", 4) # final count
Expand All @@ -1216,20 +1230,20 @@ def test_wasm_state(
c.H(i)
c.Measure(Qubit(i), a[i])
# Count the number of 1s in the "a" register and store in the "b" register.
c.add_wasm_to_reg("set_c", wasfile, [s], []) # set c to zero
c.add_wasm_to_reg("set_c", wasmfile, [s], []) # set c to zero
for i in range(8):
# Copy a[i] to s
c.add_c_copybits([a[i]], [Bit("s", 0)])
# Conditionally increment the counter
c.add_wasm_to_reg("conditional_increment_c", wasfile, [s], [])
c.add_wasm_to_reg("conditional_increment_c", wasmfile, [s], [])
# Put the counter into "b"
c.add_wasm_to_reg("get_c", wasfile, [], [b])
c.add_wasm_to_reg("get_c", wasmfile, [], [b])

backend = authenticated_quum_backend_qa

c = backend.get_compiled_circuit(c)
h = backend.process_circuit(
c, n_shots=10, wasm_file_handler=wasfile, language=language
c, n_shots=10, wasm_file_handler=wasmfile, language=language
)

r = backend.get_result(h)
Expand Down Expand Up @@ -1278,7 +1292,7 @@ def test_Rz_removal_before_measurements() -> None:
@pytest.mark.parametrize(
"authenticated_quum_backend_qa", [{"device_name": "H1-1E"}], indirect=True
)
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
@pytest.mark.timeout(120)
def test_noiseless_emulation(
authenticated_quum_backend_qa: QuantinuumBackend, language: Language
Expand Down
18 changes: 10 additions & 8 deletions tests/integration/qir/test_pytket_qir_6.ll
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ entry:
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
call void @mz_to_creg_bit(%Qubit* null, i1* %2, i64 4)
%7 = call i1 @get_creg_bit(i1* %2, i64 4)
%8 = zext i1 %7 to i64
call void @set_creg_to_int(i1* %2, i64 %8)
br i1 %7, label %then, label %else

then: ; preds = %entry
Expand All @@ -36,14 +38,14 @@ else: ; preds = %entry
continue: ; preds = %else, %then
call void @__quantum__qis__h__body(%Qubit* null)
call void @__quantum__rt__tuple_start_record_output()
%8 = call i64 @get_int_from_creg(i1* %0)
call void @__quantum__rt__int_record_output(i64 %8, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @0, i32 0, i32 0))
%9 = call i64 @get_int_from_creg(i1* %1)
call void @__quantum__rt__int_record_output(i64 %9, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0))
%10 = call i64 @get_int_from_creg(i1* %2)
call void @__quantum__rt__int_record_output(i64 %10, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @2, i32 0, i32 0))
%11 = call i64 @get_int_from_creg(i1* %3)
call void @__quantum__rt__int_record_output(i64 %11, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0))
%9 = call i64 @get_int_from_creg(i1* %0)
call void @__quantum__rt__int_record_output(i64 %9, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @0, i32 0, i32 0))
%10 = call i64 @get_int_from_creg(i1* %1)
call void @__quantum__rt__int_record_output(i64 %10, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0))
%11 = call i64 @get_int_from_creg(i1* %2)
call void @__quantum__rt__int_record_output(i64 %11, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @2, i32 0, i32 0))
%12 = call i64 @get_int_from_creg(i1* %3)
call void @__quantum__rt__int_record_output(i64 %12, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @3, i32 0, i32 0))
call void @__quantum__rt__tuple_end_record_output()
ret void
}
Expand Down
7 changes: 4 additions & 3 deletions tests/unit/offline_backend_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
)


@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
def test_quantinuum_offline(language: Language) -> None:
qapioffline = QuantinuumAPIOffline()
backend = QuantinuumBackend(
Expand All @@ -56,7 +56,7 @@ def test_quantinuum_offline(language: Language) -> None:
"name": "test 1",
"count": 4,
"machine": "H1-1",
"language": language.value,
"language": "OPENQASM 2.0" if language == Language.QASM else "QIR 1.0",
"program": "...", # not checked
"priority": "normal",
"options": {"simulator": "state-vector", "error-model": True, "tket": {}},
Expand Down Expand Up @@ -95,7 +95,7 @@ def test_max_classical_register_ii() -> None:
backend._check_all_circuits([c])


@pytest.mark.parametrize("language", [Language.QASM, Language.QIR])
@pytest.mark.parametrize("language", [Language.QASM, Language.QIR, Language.PQIR])
def test_tket_pass_submission(language: Language) -> None:
backend = QuantinuumBackend(device_name="H1-1SC", machine_debug=True)

Expand Down Expand Up @@ -125,6 +125,7 @@ def test_tket_pass_submission(language: Language) -> None:
[
Language.QASM,
Language.QIR,
Language.PQIR,
],
)
def test_shots_bits_edgecases(n_shots, n_bits, language: Language) -> None:
Expand Down
Loading