Skip to content

Commit

Permalink
Merge pull request #204 from CQCL/203-incorrect-bitwidth-for-qasm-inp…
Browse files Browse the repository at this point in the history
…ut-with-pytket-1300

fix: Abstract WORDSIZE to specify maxwidth on qasm conversion
  • Loading branch information
qartik authored Jul 16, 2024
2 parents 2825bf1 + 414de00 commit bf714a2
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 18 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dependencies = [

[project.optional-dependencies]
docs = ["sphinx", "pydata_sphinx_theme"]
phirc = ["projectq", "quantum-pecos>=0.5.0.dev10"]
phirc = ["projectq", "quantum-pecos>=0.6.0.dev2"]
tests = ["pytest"]

[project.scripts]
Expand Down
10 changes: 6 additions & 4 deletions pytket/phir/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
##############################################################################
#
# Copyright (c) 2023 Quantinuum LLC All rights reserved.
# Copyright (c) 2023-2024 Quantinuum LLC All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
#
Expand All @@ -18,7 +18,7 @@
from phir.model import PHIRModel
from pytket.qasm.qasm import circuit_from_qasm_str, circuit_from_qasm_wasm

from .phirgen import genphir
from .phirgen import WORDSIZE, genphir
from .phirgen_parallel import genphir_parallel
from .place_and_route import place_and_route
from .qtm_machine import QTM_MACHINES_MAP, QtmMachine
Expand Down Expand Up @@ -100,10 +100,12 @@ def qasm_to_phir(
wasm_file.flush()
wasm_file.close()

circuit = circuit_from_qasm_wasm(qasm_file.name, wasm_file.name)
circuit = circuit_from_qasm_wasm(
qasm_file.name, wasm_file.name, maxwidth=WORDSIZE
)
finally:
Path.unlink(Path(qasm_file.name))
Path.unlink(Path(wasm_file.name))
else:
circuit = circuit_from_qasm_str(qasm)
circuit = circuit_from_qasm_str(qasm, maxwidth=WORDSIZE)
return pytket_to_phir(circuit, qtm_machine)
7 changes: 4 additions & 3 deletions pytket/phir/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
##############################################################################
#
# Copyright (c) 2023 Quantinuum LLC All rights reserved.
# Copyright (c) 2023-2024 Quantinuum LLC All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
#
Expand All @@ -16,6 +16,7 @@
from pecos.engines.hybrid_engine import HybridEngine
from pecos.foreign_objects.wasmtime import WasmtimeObj

from pytket.phir.phirgen import WORDSIZE
from pytket.qasm.qasm import (
circuit_from_qasm,
circuit_from_qasm_wasm,
Expand Down Expand Up @@ -60,10 +61,10 @@ def main() -> None:
circuit = None
if args.wasm_file:
print(f"Including WASM from file {args.wasm_file}")
circuit = circuit_from_qasm_wasm(file, args.wasm_file)
circuit = circuit_from_qasm_wasm(file, args.wasm_file, maxwidth=WORDSIZE)
wasm_pecos_obj = WasmtimeObj(args.wasm_file)
else:
circuit = circuit_from_qasm(file)
circuit = circuit_from_qasm(file, maxwidth=WORDSIZE)

match args.machine:
case "H1":
Expand Down
20 changes: 16 additions & 4 deletions pytket/phir/phirgen.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
##############################################################################
#
# Copyright (c) 2023 Quantinuum LLC All rights reserved.
# Copyright (c) 2023-2024 Quantinuum LLC All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
#
Expand All @@ -10,11 +10,17 @@

import json
import logging
import sys
from copy import deepcopy
from importlib.metadata import version
from typing import TYPE_CHECKING, Any, TypeAlias

from typing_extensions import assert_never
from pytket.qasm.qasm import QASMUnsupportedError

if sys.version_info >= (3, 11):
from typing import assert_never
else:
from typing_extensions import assert_never

import pytket
import pytket.circuit as tk
Expand Down Expand Up @@ -45,7 +51,10 @@
"version": "0.1.0",
"metadata": {"source": f'pytket-phir v{version("pytket-phir").split("+")[0]}'},
}
UINTMAX = 2 ** (64 if pytket.__dict__.get("bit_width_64", False) else 32) - 1

WASM_WORDSIZE = 32
WORDSIZE = 64 if pytket.__dict__.get("bit_width_64", False) else 32
UINTMAX = 2**WORDSIZE - 1

Var: TypeAlias = str
Bit: TypeAlias = list[Var | int] # e.g. [c, 0] for c[0]
Expand Down Expand Up @@ -477,6 +486,9 @@ def extract_wasm_args_and_returns(
only_args = command.args[:-slice_index]
# Eliminate conditional bits from the front of the args
input_args = only_args[len(only_args) - op.n_inputs :]
if any(arg.index[0] >= WASM_WORDSIZE for arg in input_args):
msg = "WASM support is limited to at most 32-bit registers"
raise QASMUnsupportedError(msg)
return (
dedupe_bits_to_registers(input_args),
dedupe_bits_to_registers(command.bits),
Expand Down Expand Up @@ -544,7 +556,7 @@ def get_decls(qbits: set["Qubit"], cbits: set[tkBit]) -> list[dict[str, str | in
decls += [
{
"data": "cvar_define",
"data_type": "u32",
"data_type": f"i{WORDSIZE}",
"variable": cvar,
"size": dim,
}
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ pre-commit==3.7.1
pydata_sphinx_theme==0.15.4
pytest==8.2.2
pytest-order==1.2.1
pytket==1.29.2
ruff==0.5.1
pytket==1.30.0
ruff==0.5.2
setuptools_scm==8.1.0
sphinx==7.3.7
sphinx==7.4.4
wasmtime==22.0.0
wheel==0.43.0
3 changes: 2 additions & 1 deletion tests/test_phirgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pytket.circuit import Bit, Circuit
from pytket.circuit.logic_exp import BitWiseOp, create_bit_logic_exp
from pytket.phir.api import pytket_to_phir
from pytket.phir.phirgen import WORDSIZE
from pytket.qasm.qasm import circuit_from_qasm_str
from pytket.unit_id import BitRegister

Expand All @@ -30,7 +31,7 @@ def test_multiple_sleep() -> None:
sleep(1) q[0];
sleep(2) q[1];
"""
circ = circuit_from_qasm_str(qasm)
circ = circuit_from_qasm_str(qasm, maxwidth=WORDSIZE)
phir = json.loads(pytket_to_phir(circ))
assert phir["ops"][2] == {"mop": "Idle", "args": [["q", 0]], "duration": [1.0, "s"]}
assert phir["ops"][4] == {"mop": "Idle", "args": [["q", 1]], "duration": [2.0, "s"]}
Expand Down
7 changes: 5 additions & 2 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
##############################################################################
#
# Copyright (c) 2023 Quantinuum LLC All rights reserved.
# Copyright (c) 2023-2024 Quantinuum LLC All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
#
Expand All @@ -13,6 +13,7 @@

from wasmtime import wat2wasm

from pytket.phir.phirgen import WORDSIZE
from pytket.phir.phirgen_parallel import genphir_parallel
from pytket.phir.place_and_route import place_and_route
from pytket.phir.qtm_machine import QTM_MACHINES_MAP, QtmMachine
Expand Down Expand Up @@ -69,7 +70,9 @@ def get_qasm_as_circuit(qasm_file: QasmFile) -> "Circuit":
Corresponding tket circuit
"""
this_dir = Path(Path(__file__).resolve()).parent
return circuit_from_qasm(f"{this_dir}/data/qasm/{qasm_file.name}.qasm")
return circuit_from_qasm(
f"{this_dir}/data/qasm/{qasm_file.name}.qasm", maxwidth=WORDSIZE
)


def get_phir_json(qasmfile: QasmFile, *, rebase: bool) -> "JsonDict":
Expand Down
41 changes: 41 additions & 0 deletions tests/test_wasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from pytket.circuit import Circuit, Qubit
from pytket.phir.api import pytket_to_phir, qasm_to_phir
from pytket.phir.qtm_machine import QtmMachine
from pytket.qasm.qasm import QASMUnsupportedError
from pytket.wasm.wasm import WasmFileHandler

from .test_utils import WatFile, get_wat_as_wasm_bytes
Expand Down Expand Up @@ -64,6 +65,26 @@ def test_qasm_to_phir_with_wasm() -> None:
}


def test_qasm_wasm_unsupported_reg_len() -> None:
"""Test that qasm containing calls to WASM with more than 32-bits fails."""
qasm = """
OPENQASM 2.0;
include "qelib1.inc";
creg cr[33];
cr = add(cr, cr);
"""

wasm_bytes = get_wat_as_wasm_bytes(WatFile.add)

with pytest.raises(
QASMUnsupportedError,
match="limited to at most 32-bit|try setting the `maxwidth` parameter",
):
qasm_to_phir(qasm, QtmMachine.H1, wasm_bytes=wasm_bytes)


@pytest.mark.order("first")
def test_pytket_with_wasm() -> None:
"""Test whether pytket works with WASM."""
Expand Down Expand Up @@ -142,6 +163,26 @@ def test_pytket_with_wasm() -> None:
}


def test_pytket_wasm_unsupported_reg_len() -> None:
"""Test that pytket circuit calling WASM with more than 32-bits fails."""
wasm_bytes = get_wat_as_wasm_bytes(WatFile.testfile)
try:
wasm_file = NamedTemporaryFile(suffix=".wasm", delete=False)
wasm_file.write(wasm_bytes)
wasm_file.flush()
wasm_file.close()

w = WasmFileHandler(wasm_file.name)

c = Circuit(0, 33)
c0 = c.add_c_register("c0", 33)

with pytest.raises(ValueError, match="only registers of at most 32 bits"):
c.add_wasm_to_reg("no_return", w, [c0], [])
finally:
Path.unlink(Path(wasm_file.name))


def test_conditional_wasm() -> None:
"""From https://github.com/CQCL/pytket-phir/issues/156 ."""
wasm_bytes = get_wat_as_wasm_bytes(WatFile.testfile)
Expand Down

0 comments on commit bf714a2

Please sign in to comment.