From b0f041f262c4757b5f519d3a28f0c2b2d038f623 Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Mon, 2 Dec 2024 18:10:22 +0000 Subject: [PATCH] feat!: qsystem std functions with updated primitives (#679) Closes #625 Closes #645 - hseries renamed to qsystem BREAKING CHANGE: hseries primitive functions moved to std.qsystem BREAKING CHANGE: measure_return renamed to `project_z` --- guppylang/std/_internal/compiler/quantum.py | 23 +++-- guppylang/std/qsystem/__init__.py | 108 ++++++++++++++++++++ guppylang/std/qsystem/functional.py | 68 ++++++++++++ guppylang/std/quantum.py | 72 ++----------- guppylang/std/quantum_functional.py | 25 +---- pyproject.toml | 5 +- tests/integration/test_inout.py | 3 +- tests/integration/test_linear.py | 4 +- tests/integration/test_qsystem.py | 53 ++++++++++ tests/integration/test_quantum.py | 37 +++---- tests/integration/test_tket.py | 7 +- uv.lock | 8 +- 12 files changed, 283 insertions(+), 130 deletions(-) create mode 100644 guppylang/std/qsystem/__init__.py create mode 100644 guppylang/std/qsystem/functional.py create mode 100644 tests/integration/test_qsystem.py diff --git a/guppylang/std/_internal/compiler/quantum.py b/guppylang/std/_internal/compiler/quantum.py index 149798af..25a2477b 100644 --- a/guppylang/std/_internal/compiler/quantum.py +++ b/guppylang/std/_internal/compiler/quantum.py @@ -5,9 +5,10 @@ from __future__ import annotations from hugr import Wire, ops +from hugr import ext as he from hugr import tys as ht from hugr.std.float import FLOAT_T -from tket2_exts import futures, hseries, quantum, result, rotation +from tket2_exts import futures, qsystem, quantum, result, rotation from guppylang.definition.custom import CustomInoutCallCompiler from guppylang.definition.value import CallReturnWires @@ -17,7 +18,7 @@ # ---------------------------------------------- FUTURES_EXTENSION = futures() -HSERIES_EXTENSION = hseries() +QSYSTEM_EXTENSION = qsystem() QUANTUM_EXTENSION = quantum() RESULT_EXTENSION = result() ROTATION_EXTENSION = rotation() @@ -27,7 +28,7 @@ TKET2_EXTENSIONS = [ FUTURES_EXTENSION, - HSERIES_EXTENSION, + QSYSTEM_EXTENSION, QUANTUM_EXTENSION, RESULT_EXTENSION, ROTATION_EXTENSION, @@ -46,15 +47,25 @@ def from_halfturns_unchecked() -> ops.ExtOp: # ------------------------------------------------------ -class MeasureReturnCompiler(CustomInoutCallCompiler): - """Compiler for the `measure_return` function.""" +class InoutMeasureCompiler(CustomInoutCallCompiler): + """Compiler for the measure functions with an inout qubit + such as the `project_z` function.""" + + opname: str + ext: he.Extension + + def __init__(self, opname: str | None = None, ext: he.Extension | None = None): + self.opname = opname or "Measure" + self.ext = ext or QUANTUM_EXTENSION def compile_with_inouts(self, args: list[Wire]) -> CallReturnWires: from guppylang.std._internal.util import quantum_op [q] = args [q, bit] = self.builder.add_op( - quantum_op("Measure")(ht.FunctionType([ht.Qubit], [ht.Qubit, ht.Bool]), []), + quantum_op(self.opname, ext=self.ext)( + ht.FunctionType([ht.Qubit], [ht.Qubit, ht.Bool]), [] + ), q, ) return CallReturnWires(regular_returns=[bit], inout_returns=[q]) diff --git a/guppylang/std/qsystem/__init__.py b/guppylang/std/qsystem/__init__.py new file mode 100644 index 00000000..66b96227 --- /dev/null +++ b/guppylang/std/qsystem/__init__.py @@ -0,0 +1,108 @@ +from typing import no_type_check + +from guppylang.decorator import guppy +from guppylang.module import GuppyModule +from guppylang.std import angles +from guppylang.std._internal.compiler.quantum import ( + QSYSTEM_EXTENSION, + InoutMeasureCompiler, +) +from guppylang.std._internal.util import quantum_op +from guppylang.std.angles import angle +from guppylang.std.builtins import owned +from guppylang.std.quantum import qubit + +qsystem = GuppyModule("qsystem") + +qsystem.load(qubit) +qsystem.load_all(angles) + + +@guppy(qsystem) +@no_type_check +def phased_x(q: qubit, angle1: angle, angle2: angle) -> None: + f1 = float(angle1) + f2 = float(angle2) + _phased_x(q, f1, f2) + + +@guppy.hugr_op(quantum_op("ZZMax", ext=QSYSTEM_EXTENSION), module=qsystem) +@no_type_check +def zz_max(q1: qubit, q2: qubit) -> None: ... + + +@guppy(qsystem) +@no_type_check +def zz_phase(q1: qubit, q2: qubit, angle: angle) -> None: + f = float(angle) + _zz_phase(q1, q2, f) + + +@guppy(qsystem) +@no_type_check +def rz(q: qubit, angle: angle) -> None: + f1 = float(angle) + _rz(q, f1) + + +@guppy.hugr_op(quantum_op("Measure", ext=QSYSTEM_EXTENSION), module=qsystem) +@no_type_check +def measure(q: qubit @ owned) -> bool: ... + + +@guppy.custom(InoutMeasureCompiler("MeasureReset", QSYSTEM_EXTENSION), module=qsystem) +@no_type_check +def measure_and_reset(q: qubit) -> bool: + """MeasureReset operation from the qsystem extension.""" + + +@guppy.hugr_op(quantum_op("Reset", ext=QSYSTEM_EXTENSION), module=qsystem) +@no_type_check +def reset(q: qubit) -> None: ... + + +# TODO +# @guppy.hugr_op(quantum_op("TryQAlloc", ext=QSYSTEM_EXTENSION), module=qsystem) +# @no_type_check +# def _try_qalloc() -> Option[qubit]: +# .. + + +@guppy.hugr_op(quantum_op("QFree", ext=QSYSTEM_EXTENSION), module=qsystem) +@no_type_check +def qfree(q: qubit @ owned) -> None: ... + + +# ------------------------------------------------------ +# --------- Internal definitions ----------------------- +# ------------------------------------------------------ + + +@guppy.hugr_op(quantum_op("PhasedX", ext=QSYSTEM_EXTENSION), module=qsystem) +@no_type_check +def _phased_x(q: qubit, angle1: float, angle2: float) -> None: + """PhasedX operation from the qsystem extension. + + See `guppylang.std.qsystem.phased_x` for a public definition that + accepts angle parameters. + """ + + +@guppy.hugr_op(quantum_op("ZZPhase", ext=QSYSTEM_EXTENSION), module=qsystem) +@no_type_check +def _zz_phase(q1: qubit, q2: qubit, angle: float) -> None: + """ZZPhase operation from the qsystem extension. + + See `guppylang.std.qsystem.phased_x` for a public definition that + accepts angle parameters. + """ + + +@guppy.hugr_op(quantum_op("Rz", ext=QSYSTEM_EXTENSION), module=qsystem) +@no_type_check +def _rz(q: qubit, angle: float) -> None: + """Rz operation from the qsystem extension. + + See `guppylang.std.qsystem.rz` for a public definition that + accepts angle parameters. + """ diff --git a/guppylang/std/qsystem/functional.py b/guppylang/std/qsystem/functional.py new file mode 100644 index 00000000..002f55a1 --- /dev/null +++ b/guppylang/std/qsystem/functional.py @@ -0,0 +1,68 @@ +from typing import no_type_check + +from guppylang.decorator import guppy +from guppylang.module import GuppyModule +from guppylang.std import angles, qsystem +from guppylang.std.angles import angle +from guppylang.std.builtins import owned +from guppylang.std.quantum import qubit + +qsystem_functional = GuppyModule("qsystem_functional") + +qsystem_functional.load(qubit, qsystem) +qsystem_functional.load_all(angles) + + +@guppy(qsystem_functional) +@no_type_check +def phased_x(q: qubit @ owned, angle1: angle, angle2: angle) -> qubit: + qsystem.phased_x(q, angle1, angle2) + return q + + +@guppy(qsystem_functional) +@no_type_check +def zz_phase(q1: qubit @ owned, q2: qubit @ owned, angle: angle) -> tuple[qubit, qubit]: + qsystem.zz_phase(q1, q2, angle) + return q1, q2 + + +@guppy(qsystem_functional) +@no_type_check +def measure_and_reset(q: qubit @ owned) -> tuple[qubit, bool]: + b = qsystem.measure_and_reset(q) + return q, b + + +@guppy(qsystem_functional) +@no_type_check +def zz_max(q1: qubit @ owned, q2: qubit @ owned) -> tuple[qubit, qubit]: + qsystem.zz_max(q1, q2) + return q1, q2 + + +@guppy(qsystem_functional) +@no_type_check +def rz(q: qubit @ owned, angle: angle) -> qubit: + qsystem.rz(q, angle) + return q + + +@guppy(qsystem_functional) +@no_type_check +def measure(q: qubit @ owned) -> bool: + result = qsystem.measure(q) + return result + + +@guppy(qsystem_functional) +@no_type_check +def qfree(q: qubit @ owned) -> None: + qsystem.qfree(q) + + +@guppy(qsystem_functional) +@no_type_check +def reset(q: qubit @ owned) -> qubit: + qsystem.reset(q) + return q diff --git a/guppylang/std/quantum.py b/guppylang/std/quantum.py index aa1ab8d7..2fb03b70 100644 --- a/guppylang/std/quantum.py +++ b/guppylang/std/quantum.py @@ -8,8 +8,7 @@ from guppylang.decorator import guppy from guppylang.std._internal.compiler.quantum import ( - HSERIES_EXTENSION, - MeasureReturnCompiler, + InoutMeasureCompiler, RotationCompiler, ) from guppylang.std._internal.util import quantum_op @@ -33,17 +32,8 @@ def measure(self: "qubit" @ owned) -> bool: @guppy @no_type_check - def measure_return(self: "qubit") -> bool: - return measure_return(self) - - @guppy - @no_type_check - def measure_reset(self: "qubit") -> bool: - """Projective measure and reset without discarding the qubit.""" - res = self.measure_return() - if res: - x(self) - return res + def project_z(self: "qubit") -> bool: + return project_z(self) @guppy @no_type_check @@ -106,11 +96,6 @@ def tdg(q: qubit) -> None: ... def sdg(q: qubit) -> None: ... -@guppy.hugr_op(quantum_op("ZZMax", ext=HSERIES_EXTENSION)) -@no_type_check -def zz_max(q1: qubit, q2: qubit) -> None: ... - - @guppy.custom(RotationCompiler("Rz")) @no_type_check def rz(q: qubit, angle: angle) -> None: ... @@ -141,9 +126,9 @@ def toffoli(control1: qubit, control2: qubit, target: qubit) -> None: ... def dirty_qubit() -> qubit: ... -@guppy.custom(MeasureReturnCompiler()) +@guppy.custom(InoutMeasureCompiler()) @no_type_check -def measure_return(q: qubit) -> bool: ... +def project_z(q: qubit) -> bool: ... @guppy.hugr_op(quantum_op("QFree")) @@ -151,54 +136,11 @@ def measure_return(q: qubit) -> bool: ... def discard(q: qubit @ owned) -> None: ... -@guppy -@no_type_check -def measure(q: qubit @ owned) -> bool: - res = measure_return(q) - discard(q) - return res - - -@guppy -@no_type_check -def phased_x(q: qubit, angle1: angle, angle2: angle) -> None: - f1 = float(angle1) - f2 = float(angle2) - _phased_x(q, f1, f2) - - -@guppy +@guppy.hugr_op(quantum_op("MeasureFree")) @no_type_check -def zz_phase(q1: qubit, q2: qubit, angle: angle) -> None: - f = float(angle) - _zz_phase(q1, q2, f) +def measure(q: qubit @ owned) -> bool: ... @guppy.hugr_op(quantum_op("Reset")) @no_type_check def reset(q: qubit) -> None: ... - - -# ------------------------------------------------------ -# --------- Internal definitions ----------------------- -# ------------------------------------------------------ - - -@guppy.hugr_op(quantum_op("PhasedX", ext=HSERIES_EXTENSION)) -@no_type_check -def _phased_x(q: qubit, angle1: float, angle2: float) -> None: - """PhasedX operation from the hseries extension. - - See `guppylang.prelude.quantum.phased_x` for a public definition that - accepts angle parameters. - """ - - -@guppy.hugr_op(quantum_op("ZZPhase", ext=HSERIES_EXTENSION)) -@no_type_check -def _zz_phase(q1: qubit, q2: qubit, angle: float) -> None: - """ZZPhase operation from the hseries extension. - - See `guppylang.prelude.quantum.phased_x` for a public definition that - accepts angle parameters. - """ diff --git a/guppylang/std/quantum_functional.py b/guppylang/std/quantum_functional.py index 408e9da7..6338f1e6 100644 --- a/guppylang/std/quantum_functional.py +++ b/guppylang/std/quantum_functional.py @@ -95,13 +95,6 @@ def sdg(q: qubit @ owned) -> qubit: return q -@guppy(quantum_functional) -@no_type_check -def zz_max(q1: qubit @ owned, q2: qubit @ owned) -> tuple[qubit, qubit]: - quantum.zz_max(q1, q2) - return q1, q2 - - @guppy(quantum_functional) @no_type_check def rz(q: qubit @ owned, angle: angle) -> qubit: @@ -141,20 +134,6 @@ def toffoli( return control1, control2, target -@guppy(quantum_functional) -@no_type_check -def phased_x(q: qubit @ owned, angle1: angle, angle2: angle) -> qubit: - quantum.phased_x(q, angle1, angle2) - return q - - -@guppy(quantum_functional) -@no_type_check -def zz_phase(q1: qubit @ owned, q2: qubit @ owned, angle: angle) -> tuple[qubit, qubit]: - quantum.zz_phase(q1, q2, angle) - return q1, q2 - - @guppy(quantum_functional) @no_type_check def reset(q: qubit @ owned) -> qubit: @@ -164,6 +143,6 @@ def reset(q: qubit @ owned) -> qubit: @guppy(quantum_functional) @no_type_check -def measure_return(q: qubit @ owned) -> tuple[qubit, bool]: - b = quantum.measure_return(q) +def project_z(q: qubit @ owned) -> tuple[qubit, bool]: + b = quantum.project_z(q) return q, b diff --git a/pyproject.toml b/pyproject.toml index 2fc1f374..7b501a58 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ "pydantic >=2.7.0b1,<3", "typing-extensions >=4.9.0,<5", "hugr >=0.9.0,<0.10", - "tket2-exts>=0.1.0,<0.2", + "tket2-exts>=0.2.0,<0.3", ] [project.optional-dependencies] @@ -84,7 +84,8 @@ execute-llvm = { workspace = true } # Uncomment these to test the latest dependency version during development #hugr = { git = "https://github.com/CQCL/hugr", subdirectory = "hugr-py", rev = "4cbe890ab4e72090708ff83592c0771caf2335df" } -#tket2 = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-py", rev = "e3f9da1abe28f31cb249de2e06be846ab48d9708" } +# tket2-exts = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-exts", branch = "ss/rename" } + [build-system] requires = ["hatchling"] diff --git a/tests/integration/test_inout.py b/tests/integration/test_inout.py index 347936a3..ce2ffd80 100644 --- a/tests/integration/test_inout.py +++ b/tests/integration/test_inout.py @@ -370,8 +370,7 @@ def test_self_qubit(validate): def test() -> bool: q0 = qubit() - result = q0.measure_reset() - q0.measure_return() + result = q0.project_z() q0.measure() qubit().discard() return result diff --git a/tests/integration/test_linear.py b/tests/integration/test_linear.py index 918e90d9..03a5cdc0 100644 --- a/tests/integration/test_linear.py +++ b/tests/integration/test_linear.py @@ -4,7 +4,7 @@ from guppylang.std.quantum import qubit, measure import guppylang.std.quantum_functional as quantum_functional -from guppylang.std.quantum_functional import cx, t, h, measure_return +from guppylang.std.quantum_functional import cx, t, h, project_z from guppylang.tys.ty import NoneType import pytest @@ -44,7 +44,7 @@ def test_linear_return_order(validate): @guppy(module) def test(q: qubit @owned) -> tuple[qubit, bool]: - return measure_return(q) + return project_z(q) validate(module.compile()) diff --git a/tests/integration/test_qsystem.py b/tests/integration/test_qsystem.py new file mode 100644 index 00000000..18a2caf7 --- /dev/null +++ b/tests/integration/test_qsystem.py @@ -0,0 +1,53 @@ +from hugr.package import ModulePointer + +import guppylang.decorator +from guppylang.module import GuppyModule +from guppylang.std.angles import angle + +from guppylang.std.builtins import owned +from guppylang.std.quantum import qubit +from guppylang.std.qsystem.functional import ( + phased_x, + zz_phase, + qsystem_functional, + measure_and_reset, + zz_max, + rz, + measure, + qfree, +) + + +def compile_qsystem_guppy(fn) -> ModulePointer: + """A decorator that combines @guppy with HUGR compilation. + + Modified version of `tests.util.compile_guppy` that loads the qsytem module. + """ + assert not isinstance( + fn, + GuppyModule, + ), "`@compile_qsystem_guppy` does not support extra arguments." + + module = GuppyModule("module") + module.load(angle, qubit) + module.load_all(qsystem_functional) + guppylang.decorator.guppy(module)(fn) + return module.compile() + + +def test_qsystem(validate): + """Compile various operations from the qsystem extension.""" + + @compile_qsystem_guppy + def test(q1: qubit @ owned, q2: qubit @ owned, a1: angle) -> bool: + q1 = phased_x(q1, a1, a1) + q1, q2 = zz_phase(q1, q2, a1) + q1 = rz(q1, a1) + q1, q2 = zz_max(q1, q2) + q1, b = measure_and_reset(q1) + q1 = reset(q1) + b = measure(q1) + qfree(q2) + return b + + validate(test) diff --git a/tests/integration/test_quantum.py b/tests/integration/test_quantum.py index 5a3deb66..56d8cfa1 100644 --- a/tests/integration/test_quantum.py +++ b/tests/integration/test_quantum.py @@ -1,21 +1,14 @@ """Various tests for the functions defined in `guppylang.prelude.quantum`.""" -import pytest - from hugr.package import ModulePointer import guppylang.decorator -from guppylang.decorator import guppy from guppylang.module import GuppyModule from guppylang.std.angles import angle -from guppylang.std.builtins import owned, py -from guppylang.std.quantum import ( - dirty_qubit, - discard, - measure, - qubit -) +from guppylang.std.builtins import owned + +from guppylang.std.quantum import dirty_qubit, discard, measure, qubit from guppylang.std.quantum_functional import ( cx, cy, @@ -28,17 +21,14 @@ z, tdg, sdg, - zz_max, - phased_x, rx, ry, rz, crz, toffoli, - zz_phase, reset, quantum_functional, - measure_return, + project_z, ) @@ -71,7 +61,7 @@ def test() -> tuple[bool, bool]: def test_1qb_op(validate): @compile_quantum_guppy - def test(q: qubit @owned) -> qubit: + def test(q: qubit @ owned) -> qubit: q = h(q) q = t(q) q = s(q) @@ -87,11 +77,10 @@ def test(q: qubit @owned) -> qubit: def test_2qb_op(validate): @compile_quantum_guppy - def test(q1: qubit @owned, q2: qubit @owned) -> tuple[qubit, qubit]: + def test(q1: qubit @ owned, q2: qubit @ owned) -> tuple[qubit, qubit]: q1, q2 = cx(q1, q2) q1, q2 = cy(q1, q2) q1, q2 = cz(q1, q2) - q1, q2 = zz_max(q1, q2) return (q1, q2) validate(test) @@ -99,7 +88,9 @@ def test(q1: qubit @owned, q2: qubit @owned) -> tuple[qubit, qubit]: def test_3qb_op(validate): @compile_quantum_guppy - def test(q1: qubit @owned, q2: qubit @owned, q3: qubit @owned) -> tuple[qubit, qubit, qubit]: + def test( + q1: qubit @ owned, q2: qubit @ owned, q3: qubit @ owned + ) -> tuple[qubit, qubit, qubit]: q1, q2, q3 = toffoli(q1, q2, q3) return (q1, q2, q3) @@ -110,8 +101,8 @@ def test_measure_ops(validate): """Compile various measurement-related operations.""" @compile_quantum_guppy - def test(q1: qubit @owned, q2: qubit @owned) -> tuple[bool, bool]: - q1, b1 = measure_return(q1) + def test(q1: qubit @ owned, q2: qubit @ owned) -> tuple[bool, bool]: + q1, b1 = project_z(q1) q1 = discard(q1) q2 = reset(q2) b2 = measure(q2) @@ -124,11 +115,11 @@ def test_parametric(validate): """Compile various parametric operations.""" @compile_quantum_guppy - def test(q1: qubit @owned, q2: qubit @owned, a1: angle, a2: angle, a3: angle) -> tuple[qubit, qubit]: + def test( + q1: qubit @ owned, q2: qubit @ owned, a1: angle, a2: angle, a3: angle + ) -> tuple[qubit, qubit]: q1 = rx(q1, a1) q1 = ry(q1, a1) q2 = rz(q2, a3) - q1 = phased_x(q1, a1, a2) - q1, q2 = zz_phase(q1, q2, a1) q1, q2 = crz(q1, q2, a3) return (q1, q2) diff --git a/tests/integration/test_tket.py b/tests/integration/test_tket.py index 9ff5b46d..2035bac4 100644 --- a/tests/integration/test_tket.py +++ b/tests/integration/test_tket.py @@ -12,16 +12,17 @@ from importlib.util import find_spec -import math import pytest from guppylang.decorator import guppy from guppylang.module import GuppyModule from guppylang.std.angles import pi -from guppylang.std.builtins import owned, py +from guppylang.std.builtins import owned from guppylang.std import quantum +from guppylang.std.qsystem.functional import phased_x from guppylang.std.quantum import measure, qubit -from guppylang.std.quantum_functional import phased_x, rz, zz_max +from guppylang.std.quantum_functional import rz +from guppylang.std.qsystem.functional import zz_max from tests.util import guppy_to_circuit tket2_installed = find_spec("tket2") is not None diff --git a/uv.lock b/uv.lock index 46ad0e6c..4d95e9b3 100644 --- a/uv.lock +++ b/uv.lock @@ -618,7 +618,7 @@ requires-dist = [ { name = "pytket", marker = "extra == 'pytket'", specifier = ">=1.34" }, { name = "sphinx", marker = "extra == 'docs'", specifier = ">=7.2.6,<9" }, { name = "sphinx-book-theme", marker = "extra == 'docs'", specifier = ">=1.1.2,<2" }, - { name = "tket2-exts", specifier = ">=0.1.0,<0.2" }, + { name = "tket2-exts", specifier = ">=0.2.0,<0.3" }, { name = "typing-extensions", specifier = ">=4.9.0,<5" }, ] @@ -2243,14 +2243,14 @@ wheels = [ [[package]] name = "tket2-exts" -version = "0.1.0" +version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "hugr" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f7/bf/4f3bc7dd20df43189eb228e446f8e5094dbf3120604707487dc4fe2194b2/tket2_exts-0.1.0.tar.gz", hash = "sha256:6ab2117ec776d61efab3e7dd5ccfa5e619ad8c2b971f954e930a89ced3381cd0", size = 8727 } +sdist = { url = "https://files.pythonhosted.org/packages/0e/56/d9435d4f4fc56af1193b50195e0fe9ff8192919caff0c978ce915d41ecae/tket2_exts-0.2.0.tar.gz", hash = "sha256:bbff2b27ab795fa045efb4c58d4fcdf0e9c94137d1aa5c49677cc8315b5ecfb8", size = 9306 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/81/4c76678510a3168fe036e33a1d4e8a6f72b56421de10bf40851485f9ed4d/tket2_exts-0.1.0-py3-none-any.whl", hash = "sha256:2ab0253c7f8bfea908578a2ae800b7468f093217c3fb998c3a4e1c109e673163", size = 14317 }, + { url = "https://files.pythonhosted.org/packages/98/82/4865a9d308b039f89c85020b6537b940d84ab6160d6c7520b911123dd459/tket2_exts-0.2.0-py3-none-any.whl", hash = "sha256:e9c207c90ff03e60faa1e4a1950f5bdf3ddfea8775e5f6f4bf80840d38a807a2", size = 14575 }, ] [[package]]