Skip to content

Commit

Permalink
update to pytket qir 0.13.0 (#499)
Browse files Browse the repository at this point in the history
* update to pytket-qir 0.13.0

* remove # pylint: disable=unused-import

* add link to result type issue

* combine QIR and PQIR, add language2str function

* fix mypy
  • Loading branch information
cqc-melf authored Oct 3, 2024
1 parent d93df26 commit b342e1d
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 40 deletions.
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
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

0 comments on commit b342e1d

Please sign in to comment.