diff --git a/.github/change-filters.yml b/.github/change-filters.yml index f5127387..b672c566 100644 --- a/.github/change-filters.yml +++ b/.github/change-filters.yml @@ -15,5 +15,6 @@ rust: python: - *rust-core - "tket2-py/**" + - "tket2-eccs/**" - "pyproject.toml" - "poetry.lock" diff --git a/.github/workflows/python-pure-wheels.yml b/.github/workflows/python-pure-wheels.yml new file mode 100644 index 00000000..e012cf6d --- /dev/null +++ b/.github/workflows/python-pure-wheels.yml @@ -0,0 +1,60 @@ +name: Build and publish pure python wheels +# Builds and publishes the pure wheels on pypi. +# +# This does not include the main `tket2-py` package, which is built using maturin. +# See `python-wheels.yml` for that workflow. +# +# When running on a release event or as a workflow dispatch for a tag, +# and if the tag matches `{package}-v*`, +# this workflow will publish the wheels to pypi. +# If the version is already published, pypi just ignores it. + +on: + workflow_dispatch: + push: + branches: + - main + release: + types: + - published + +jobs: + build-publish: + name: Build and publish wheels + runs-on: ubuntu-latest + strategy: + matrix: + package: + - 'tket2-eccs' + + steps: + - uses: actions/checkout@v4 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.5 + - name: Install poetry + run: pipx install poetry + - name: Set up Python '3.10' + uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: "poetry" + + - name: Build sdist and wheels + run: | + cd ${{ matrix.package }} + poetry build -o ../dist + + - name: Upload the built packages as artifacts + uses: actions/upload-artifact@v4 + with: + name: build-${{ matrix.package }}-sdist + path: | + dist/*.tar.gz + dist/*.whl + + - name: Publish to PyPI + if: ${{ (github.event_name == 'release' && github.ref_type == 'tag' && startsWith(github.ref, format('refs/tags/{0}-v', matrix.package)) ) || (github.event_name == 'workflow_dispatch' && github.ref_type == 'tag' && startsWith(github.ref, format('refs/tags/{0}-v', matrix.package)) ) }} + run: | + cd ${{ matrix.package }} + poetry config pypi-token.pypi ${{ secrets.PYPI_PUBLISH }} + poetry publish --dist-dir ../dist --skip-existing diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d1b66f5c..f5332249 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -85,7 +85,8 @@ repos: - id: py-test name: pytest description: Run python tests - entry: poetry run -- sh -c "maturin develop && pytest --cov=./ --cov-report=html" + # Ensure that we are using the local version of `tket2-eccs` and not the one from PyPI + entry: poetry run -- sh -c "poetry install -C tket2-eccs && maturin develop && pytest --cov=./ --cov-report=html" language: system files: \.py$ pass_filenames: false diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 87776faf..3cf9fd00 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,4 @@ { - "tket2-py": "0.1.0a4" + "tket2-py": "0.1.0a4", + "tket2-eccs": "0.0.0" } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 29ccb4e6..b2aa5b58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,3 +68,7 @@ urlencoding = "2.1.2" webbrowser = "1.0.0" cool_asserts = "2.0.3" zstd = "0.13.2" + +[profile.release.package.tket2-py] +# Some configurations to reduce the size of tket2 wheels +strip = true diff --git a/justfile b/justfile index dc3b24bb..badeb82a 100644 --- a/justfile +++ b/justfile @@ -14,12 +14,16 @@ check: # Compile the wheels for the python package. build: + #!/usr/bin/env bash + set -euo pipefail + # Ensure that we are using the local version of `pytket-eccs` + poetry install -C tket2-eccs poetry run -- maturin build --release # Run all the tests. test language="[rust|python]" : (_run_lang language \ "poetry run cargo test --all-features --workspace" \ - "poetry run maturin develop && poetry run pytest" + "poetry install -C tket2-eccs && poetry run maturin develop && poetry run pytest" ) # Auto-fix all clippy warnings. @@ -37,7 +41,7 @@ format language="[rust|python]": (_run_lang language \ # Generate a test coverage report. coverage language="[rust|python]": (_run_lang language \ "poetry run -- cargo llvm-cov --lcov > lcov.info" \ - "poetry run -- maturin develop && poetry run pytest --cov=./ --cov-report=html" + "poetry install -C tket2-eccs && poetry run -- maturin develop && poetry run pytest --cov=./ --cov-report=html" ) # Load a shell with all the dependencies installed diff --git a/poetry.lock b/poetry.lock index d0d391c9..efdb4fdc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -987,6 +987,19 @@ mpmath = ">=1.1.0,<1.4" [package.extras] dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"] +[[package]] +name = "tket2-eccs" +version = "0.1.0a4" +description = "Precompiled rewrite sets for the tket 2 compiler" +optional = false +python-versions = "^3.10" +files = [] +develop = true + +[package.source] +type = "directory" +url = "tket2-eccs" + [[package]] name = "tomli" version = "2.0.1" @@ -1043,4 +1056,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "efdc0517bec3808efe89eda8bd30825263ff97e19978bc097b77e1ad05606dec" +content-hash = "88363821a01c67d2fb6cf2c59e8585083e8d3b56e0fc31050d833b324e83830c" diff --git a/pyproject.toml b/pyproject.toml index 0183b86c..0c7573e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "tket2-py" version = "0.1.0a4" -description = "pytket extension for the tket 2 compiler" +description = "Quantinuum's TKET2 Quantum Compiler" classifiers = [ "Environment :: Console", "Programming Language :: Python :: 3.10", @@ -25,10 +25,12 @@ packages = [{ include = "tket2-py" }] [tool.poetry.dependencies] python = "^3.10" + # Note: Be sure to update the dependency versions in [project.dependencies] as well # # Poetry does not currently follow PEP 621, it will be supported on poetry 2 # https://github.com/python-poetry/poetry/issues/3332 +tket2_eccs = { path = "tket2-eccs", develop = true } pytket = "1.30.0" hugr = "^0.5.0" @@ -68,12 +70,16 @@ maintainers = [ { name = "TKET development team", email = "tket-support@quantinuum.com" }, ] version = "0.1.0a4" -description = "pytket extension for the tket 2 compiler" +description = "Quantinuum's TKET2 Quantum Compiler" requires-python = ">=3.10" license = { file = "LICENCE" } # Note: Be sure to update the dependency versions in [tool.poetry.dependencies] as well -dependencies = ['pytket >= 1.29.2, < 2', 'hugr >= 0.5.0, < 0.6'] +dependencies = [ + 'pytket >= 1.29.2, < 2', + 'hugr >= 0.5.0, < 0.6', + 'tket2_eccs >= 0.1.0, < 0.2', +] [project.urls] homepage = "https://github.com/CQCL/tket2" diff --git a/release-please-config.json b/release-please-config.json index 81341034..5c08fa1a 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -13,6 +13,15 @@ "draft": false, "prerelease": false, "draft-pull-request": true + }, + "tket2-eccs": { + "release-type": "python", + "component": "tket2-eccs", + "package-name": "tket2_eccs", + "include-component-in-tag": true, + "draft": false, + "prerelease": false, + "draft-pull-request": true } }, "changelog-sections": [ diff --git a/scripts/compile-test-eccs.sh b/scripts/compile-test-eccs.sh index fcf73ce2..47d074ad 100755 --- a/scripts/compile-test-eccs.sh +++ b/scripts/compile-test-eccs.sh @@ -23,7 +23,7 @@ done # Additional hard-coded step: # The python package contains a copy of the nam_6_3 ecc, # which must be manually copied. -PY_ECCS_DIR="$DIR/../tket2-py/tket2/data" +PY_ECCS_DIR="$DIR/../tket2-eccs/src/tket2_eccs/data" nam_6_3="$ECCS_DIR/nam_6_3.rwr" PY_NAM_6_3="$PY_ECCS_DIR/nam_6_3.rwr" diff --git a/tket2-eccs/.DS_Store b/tket2-eccs/.DS_Store new file mode 100644 index 00000000..c88a062b Binary files /dev/null and b/tket2-eccs/.DS_Store differ diff --git a/tket2-eccs/.gitignore b/tket2-eccs/.gitignore new file mode 100644 index 00000000..a7ea2e93 --- /dev/null +++ b/tket2-eccs/.gitignore @@ -0,0 +1,2 @@ +# Python wheel artifacts +dist diff --git a/tket2-eccs/CHANGELOG.md b/tket2-eccs/CHANGELOG.md new file mode 100644 index 00000000..825c32f0 --- /dev/null +++ b/tket2-eccs/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog diff --git a/tket2-eccs/README.md b/tket2-eccs/README.md new file mode 100644 index 00000000..618b0d6e --- /dev/null +++ b/tket2-eccs/README.md @@ -0,0 +1,36 @@ +# tket2-eccs + +[![pypi][]](https://pypi.org/project/tket2/) +[![codecov][]](https://codecov.io/gh/CQCL/tket2) +[![py-version][]](https://pypi.org/project/tket2/) + + [codecov]: https://img.shields.io/codecov/c/gh/CQCL/tket2?logo=codecov + [py-version]: https://img.shields.io/pypi/pyversions/tket2 + [pypi]: https://img.shields.io/pypi/v/tket2 + +This is an auxiliary Python package containing compiler rewrite sets used for `tket2`'s optimisation passes. + +This package is intended to be used as an internal dependency for `tket2`. +See https://pypi.org/project/tket2/ for the main package. + + +## Install + +TKET2-eccs can be installed via `pip`. + +```sh +pip install tket2_eccs +``` + +## Development + +See [DEVELOPMENT.md] information on how to develop and contribute to this package. + + [DEVELOPMENT.md]: https://github.com/CQCL/tket2/blob/main/DEVELOPMENT.md + + +## License + +This project is licensed under Apache License, Version 2.0 ([LICENCE][] or http://www.apache.org/licenses/LICENSE-2.0). + + [LICENCE]: https://github.com/CQCL/tket2/blob/main/LICENCE diff --git a/tket2-eccs/poetry.lock b/tket2-eccs/poetry.lock new file mode 100644 index 00000000..a9b02223 --- /dev/null +++ b/tket2-eccs/poetry.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +package = [] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "53f2eabc9c26446fbcc00d348c47878e118afc2054778c3c803a0a8028af27d9" diff --git a/tket2-eccs/pyproject.toml b/tket2-eccs/pyproject.toml new file mode 100644 index 00000000..9e5da58a --- /dev/null +++ b/tket2-eccs/pyproject.toml @@ -0,0 +1,63 @@ +[tool.poetry] +name = "tket2-eccs" +version = "0.1.0" +description = "Precompiled rewrite sets for the tket 2 compiler" +classifiers = [ + "Environment :: Console", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "License :: OSI Approved :: Apache Software License", + "Operating System :: MacOS :: MacOS X", + "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering", +] +authors = ["TKET development team "] +maintainers = ["TKET development team "] +include = ["pyproject.toml"] +license = "Apache-2.0" +readme = "README.md" + +packages = [{ include = "tket2_eccs", from = "src" }] + +[tool.poetry.dependencies] +python = "^3.10" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[project] +name = "tket2_eccs" +classifiers = [ + "Environment :: Console", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "License :: OSI Approved :: Apache Software License", + "Operating System :: MacOS :: MacOS X", + "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering", +] +authors = [ + { name = "TKET development team", email = "tket-support@quantinuum.com" }, +] +maintainers = [ + { name = "TKET development team", email = "tket-support@quantinuum.com" }, +] +version = "0.1.0" +description = "Precompiled rewrite sets for the tket 2 compiler" +requires-python = ">=3.10" +license = { file = "LICENCE" } + +dependencies = [] + +[project.urls] +homepage = "https://github.com/CQCL/tket2" +repository = "https://github.com/CQCL/tket2" diff --git a/tket2-eccs/src/tket2_eccs/__init__.py b/tket2-eccs/src/tket2_eccs/__init__.py new file mode 100644 index 00000000..df34a79c --- /dev/null +++ b/tket2-eccs/src/tket2_eccs/__init__.py @@ -0,0 +1,27 @@ +"""`tket2-eccs` is a Python package containing compiler rewrite sets used for `tket2`'s optimisation passes. + +This package is intended to be used as an internal dependency for `tket2`. +""" + +# This is updated by our release-please workflow, triggered by this +# annotation: x-release-please-version +__version__ = "0.1.0" + +from importlib import resources +from pathlib import Path + + +def nam_6_3() -> Path: + """Get the path to the included `nam_6_3.rwr` rewriter. + + This is a rewrite set obtained from the equivalence classes of circuits with + up to 3 qubits and 6 gates on the Nam gateset, as + generated by TASO. + + See https://dl.acm.org/doi/10.1145/3341301.3359630 + """ + with resources.as_file( + resources.files("tket2_eccs").joinpath("data/nam_6_3.rwr") + ) as r: + rewriter = Path(r) + return rewriter diff --git a/tket2-py/tket2/data/nam_6_3.rwr b/tket2-eccs/src/tket2_eccs/data/nam_6_3.rwr similarity index 100% rename from tket2-py/tket2/data/nam_6_3.rwr rename to tket2-eccs/src/tket2_eccs/data/nam_6_3.rwr diff --git a/tket2-eccs/src/tket2_eccs/py.typed b/tket2-eccs/src/tket2_eccs/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/tket2-py/README.md b/tket2-py/README.md index 5b798293..fd1008c9 100644 --- a/tket2-py/README.md +++ b/tket2-py/README.md @@ -34,7 +34,7 @@ See the [Getting Started][getting-started] guide and the other [examples]. ## Development -This package uses [pyo3](https://pyo3.rs/v0.16.4/) and +This package uses [pyo3](https://pyo3.rs/latest/) and [maturin](https://github.com/PyO3/maturin) to bind TKET2 functionality to python as the `tket2` package. @@ -56,4 +56,4 @@ See [DEVELOPMENT.md] for more information. This project is licensed under Apache License, Version 2.0 ([LICENCE][] or http://www.apache.org/licenses/LICENSE-2.0). - [LICENCE]: ./LICENCE + [LICENCE]: https://github.com/CQCL/tket2/blob/main/LICENCE diff --git a/tket2-py/tket2/passes.py b/tket2-py/tket2/passes.py index c10333dc..ae593329 100644 --- a/tket2-py/tket2/passes.py +++ b/tket2-py/tket2/passes.py @@ -1,6 +1,5 @@ from pathlib import Path from typing import Optional -from importlib import resources from pytket import Circuit from pytket.passes import CustomPass, BasePass @@ -49,10 +48,14 @@ def badger_pass( `log_dir` and `rebase` are optional and will be passed on to the Badger optimiser if provided.""" if rewriter is None: - with resources.as_file( - resources.files("tket2").joinpath("data/nam_6_3.rwr") - ) as r: - rewriter = Path(r) + try: + import tket2_eccs + except ImportError: + raise ValueError( + "The default rewriter is not available. Please specify a path to a rewriter or install tket2-eccs." + ) + + rewriter = tket2_eccs.nam_6_3() opt = optimiser.BadgerOptimiser.load_precompiled(rewriter) def apply(circuit: Circuit) -> Circuit: diff --git a/tket2-py/tket2/rewrite.py b/tket2-py/tket2/rewrite.py index 06f34e05..b658e000 100644 --- a/tket2-py/tket2/rewrite.py +++ b/tket2-py/tket2/rewrite.py @@ -1,8 +1,6 @@ # Re-export native bindings from ._tket2.rewrite import ECCRewriter, CircuitRewrite, Subcircuit -from importlib import resources - __all__ = [ "default_ecc_rewriter", # Bindings. @@ -15,8 +13,12 @@ def default_ecc_rewriter() -> ECCRewriter: """Load the default ecc rewriter.""" - # TODO: Cite, explain what this is - with resources.as_file( - resources.files("tket2").joinpath("data/nam_6_3.rwr") - ) as rewriter: - return ECCRewriter.load_precompiled(rewriter) + try: + import tket2_eccs + except ImportError: + raise ValueError( + "The default rewriter is not available. Please specify a path to a rewriter or install tket2-eccs." + ) + + rewriter = tket2_eccs.nam_6_3() + return ECCRewriter.load_precompiled(rewriter)