From c4a82614b3bec58d746d4b9e2594a9f53e79d3c6 Mon Sep 17 00:00:00 2001 From: JaunatisBlue Date: Wed, 15 Apr 2026 21:10:21 +0800 Subject: [PATCH] Initialize --- .envrc | 9 + .github/workflows/deploy.yml | 22 + .github/workflows/publish.yml | 38 + .github/workflows/rules.yml | 38 + .gitignore | 162 + .pre-commit-config.yaml | 29 + LICENSE | 201 + README.md | 128 + doc/Makefile | 20 + doc/make.bat | 35 + doc/source/.gitignore | 1 + doc/source/QiboTN.png | Bin 0 -> 148816 bytes doc/source/_static/css/style.css | 7 + doc/source/_static/qibo_logo_dark.svg | 121 + doc/source/_static/qibo_logo_light.svg | 80 + doc/source/conf.py | 106 + doc/source/favicon.ico | Bin 0 -> 15406 bytes doc/source/getting-started/index.rst | 12 + doc/source/getting-started/installation.rst | 10 + doc/source/getting-started/quickstart.rst | 138 + doc/source/index.rst | 101 + .../qmatchatea_introduction.ipynb | 581 +++ examples/quimb_intro/quimb_introduction.ipynb | 572 +++ flake.lock | 323 ++ flake.nix | 61 + poetry.lock | 3944 +++++++++++++++++ pyproject.toml | 84 + src/qibotn/__init__.py | 5 + src/qibotn/backends/__init__.py | 55 + src/qibotn/backends/abstract.py | 35 + src/qibotn/backends/cutensornet.py | 169 + src/qibotn/backends/qmatchatea.py | 317 ++ src/qibotn/backends/quimb.py | 387 ++ src/qibotn/circuit_convertor.py | 246 + src/qibotn/circuit_to_mps.py | 47 + src/qibotn/eval.py | 497 +++ src/qibotn/eval_qu.py | 46 + src/qibotn/mps_contraction_helper.py | 118 + src/qibotn/mps_utils.py | 95 + src/qibotn/result.py | 66 + tests/config.py | 12 + tests/conftest.py | 66 + tests/test_circuit_execution.py | 91 + tests/test_cuquantum_cutensor_backend.py | 199 + tests/test_cuquantum_cutensor_mpi_backend.py | 315 ++ tests/test_expectation.py | 47 + tests/test_quimb_backend.py | 66 + 47 files changed, 9702 insertions(+) create mode 100644 .envrc create mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/rules.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 doc/Makefile create mode 100644 doc/make.bat create mode 100644 doc/source/.gitignore create mode 100644 doc/source/QiboTN.png create mode 100644 doc/source/_static/css/style.css create mode 100644 doc/source/_static/qibo_logo_dark.svg create mode 100644 doc/source/_static/qibo_logo_light.svg create mode 100644 doc/source/conf.py create mode 100644 doc/source/favicon.ico create mode 100644 doc/source/getting-started/index.rst create mode 100644 doc/source/getting-started/installation.rst create mode 100644 doc/source/getting-started/quickstart.rst create mode 100644 doc/source/index.rst create mode 100644 examples/qmatchatea_intro/qmatchatea_introduction.ipynb create mode 100644 examples/quimb_intro/quimb_introduction.ipynb create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 src/qibotn/__init__.py create mode 100644 src/qibotn/backends/__init__.py create mode 100644 src/qibotn/backends/abstract.py create mode 100644 src/qibotn/backends/cutensornet.py create mode 100644 src/qibotn/backends/qmatchatea.py create mode 100644 src/qibotn/backends/quimb.py create mode 100644 src/qibotn/circuit_convertor.py create mode 100644 src/qibotn/circuit_to_mps.py create mode 100644 src/qibotn/eval.py create mode 100644 src/qibotn/eval_qu.py create mode 100644 src/qibotn/mps_contraction_helper.py create mode 100644 src/qibotn/mps_utils.py create mode 100644 src/qibotn/result.py create mode 100644 tests/config.py create mode 100644 tests/conftest.py create mode 100644 tests/test_circuit_execution.py create mode 100644 tests/test_cuquantum_cutensor_backend.py create mode 100644 tests/test_cuquantum_cutensor_mpi_backend.py create mode 100644 tests/test_expectation.py create mode 100644 tests/test_quimb_backend.py diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3af52d8 --- /dev/null +++ b/.envrc @@ -0,0 +1,9 @@ +if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs=" +fi + +watch_file flake.nix +watch_file flake.lock +if ! use flake . --impure; then + echo "devenv could not be built. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2 +fi diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..74609a8 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,22 @@ +# A single CI script with github workflow +name: Build wheels + +on: + push: + release: + types: + - published + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest] + python-version: ["3.11", "3.12", "3.13"] + uses: qiboteam/workflows/.github/workflows/deploy-pip-poetry.yml@v1 + with: + os: ${{ matrix.os }} + python-version: ${{ matrix.python-version }} + publish: ${{ github.event_name == 'release' && github.event.action == 'published' && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.9' }} + poetry-extras: "--with docs,tests,analysis" + secrets: inherit diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..abdd660 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,38 @@ +name: docs + +on: + workflow_dispatch: + push: + branches: [main] + tags: + - "*" + +jobs: + evaluate-label: + runs-on: ubuntu-latest + outputs: + label: ${{ steps.label_step.outputs.version}} + steps: + - name: checks for the label + id: label_step + run: | + if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then + echo "version=latest" >> $GITHUB_OUTPUT + fi + if [[ "${{ github.ref_type }}" == "branch" ]] && [[ "${{ github.ref }}" != "refs/heads/main" ]]; then + exit 1 + fi + if [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "version=stable" >> $GITHUB_OUTPUT + fi + + deploy-docs: + needs: [evaluate-label] + uses: qiboteam/workflows/.github/workflows/deploy-ghpages-latest-stable.yml@v1 + with: + python-version: "3.11" + package-manager: "poetry" + dependency-path: "**/poetry.lock" + trigger-label: "${{needs.evaluate-label.outputs.label}}" + project: qibotn + poetry-extras: --with docs diff --git a/.github/workflows/rules.yml b/.github/workflows/rules.yml new file mode 100644 index 0000000..d93c231 --- /dev/null +++ b/.github/workflows/rules.yml @@ -0,0 +1,38 @@ +# A single CI script with github workflow +name: Tests + +env: + CUDA_PATH: + +on: + workflow_dispatch: + push: + pull_request: + types: [labeled] + +jobs: + check: + # job to check cuda availability for local gpu host runners + runs-on: ubuntu-latest + steps: + - id: step1 + run: echo "test=${{ env.CUDA_PATH != ''}}" >> "$GITHUB_OUTPUT" + - id: step2 + run: echo "test=${{ contains(github.event.pull_request.labels.*.name, 'run-workflow') || github.event_name == 'push' }}" >> "$GITHUB_OUTPUT" + outputs: + cuda_avail: ${{ fromJSON(steps.step1.outputs.test) && fromJSON(steps.step2.outputs.test) }} + + build: + # job to build + needs: check + if: ${{fromJSON(needs.check.outputs.cuda_avail)}} + strategy: + matrix: + os: [ubuntu-latest] + python-version: ["3.11", "3.12", "3.13"] + uses: qiboteam/workflows/.github/workflows/rules-poetry.yml@v1 + with: + os: ${{ matrix.os }} + python-version: ${{ matrix.python-version }} + poetry-extras: "--with analysis,tests" + secrets: inherit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7f051b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,162 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ +.devenv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..fc0e23e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,29 @@ +ci: + autofix_prs: true +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-toml + - id: debug-statements + - repo: https://github.com/psf/black-pre-commit-mirror + rev: 26.3.1 + hooks: + - id: black + - repo: https://github.com/pycqa/isort + rev: 8.0.1 + hooks: + - id: isort + args: ["--profile", "black"] + - repo: https://github.com/asottile/pyupgrade + rev: v3.21.2 + hooks: + - id: pyupgrade + - repo: https://github.com/hadialqattan/pycln + rev: v2.6.0 + hooks: + - id: pycln + args: [--config=pyproject.toml] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..78ed782 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 The QIBO team + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d587293 --- /dev/null +++ b/README.md @@ -0,0 +1,128 @@ +# Qibotn + +The tensor network translation module for Qibo to support large-scale simulation of quantum circuits and acceleration. + +## Supported Computation + +Tensor Network Types: + +- Tensornet (TN) +- Matrix Product States (MPS) + +Tensor Network contractions to: + +- dense vectors +- expecation values of given Pauli string + +The supported HPC configurations are: + +- single-node CPU +- single-node GPU or GPUs +- multi-node multi-GPU with Message Passing Interface (MPI) +- multi-node multi-GPU with NVIDIA Collective Communications Library (NCCL) + +Currently, the supported tensor network libraries are: + +- [cuQuantum](https://github.com/NVIDIA/cuQuantum), an NVIDIA SDK of optimized libraries and tools for accelerating quantum computing workflows. +- [quimb](https://quimb.readthedocs.io/en/latest/), an easy but fast python library for ‘quantum information many-body’ calculations, focusing primarily on tensor networks. + +## Installation + +To get started: + +```sh +pip install qibotn +``` + +to install the tools and dependencies. A few extras are provided, check `pyproject.toml` in +case you need them. + + + +## Contribute + +To contribute, please install using poetry: + +```sh +git clone https://github.com/qiboteam/qibotn.git +cd qibotn +poetry install +``` + +## Sample Codes + +### Single-Node Example + +The code below shows an example of how to activate the Cuquantum TensorNetwork backend of Qibo. + +```py +import numpy as np +from qibo import Circuit, gates +import qibo + +# Below shows how to set the computation_settings +# Note that for MPS_enabled and expectation_enabled parameters the accepted inputs are boolean or a dictionary with the format shown below. +# If computation_settings is not specified, the default setting is used in which all booleans will be False. +# This will trigger the dense vector computation of the tensornet. + +computation_settings = { + "MPI_enabled": False, + "MPS_enabled": { + "qr_method": False, + "svd_method": { + "partition": "UV", + "abs_cutoff": 1e-12, + }, + }, + "NCCL_enabled": False, + "expectation_enabled": False, +} + + +qibo.set_backend( + backend="qibotn", platform="cutensornet", runcard=computation_settings +) # cuQuantum +# qibo.set_backend(backend="qibotn", platform="qutensornet", runcard=computation_settings) #quimb + + +# Construct the circuit +c = Circuit(2) +# Add some gates +c.add(gates.H(0)) +c.add(gates.H(1)) + +# Execute the circuit and obtain the final state +result = c() + +print(result.state()) +``` + +Other examples of setting the computation_settings + +```py +# Expectation computation with specific Pauli String pattern +computation_settings = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": { + "pauli_string_pattern": "IXZ", + }, +} + +# Dense vector computation using multi node through MPI +computation_settings = { + "MPI_enabled": True, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": False, +} +``` + +### Multi-Node Example + +Multi-node is enabled by setting either the MPI or NCCL enabled flag to True in the computation settings. Below shows the script to launch on 2 nodes with 2 GPUs each. $node_list contains the IP of the nodes assigned. + +```sh +mpirun -n 4 -hostfile $node_list python test.py +``` diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/make.bat b/doc/make.bat new file mode 100644 index 0000000..dc1312a --- /dev/null +++ b/doc/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/doc/source/.gitignore b/doc/source/.gitignore new file mode 100644 index 0000000..7e26654 --- /dev/null +++ b/doc/source/.gitignore @@ -0,0 +1 @@ +api-reference/ diff --git a/doc/source/QiboTN.png b/doc/source/QiboTN.png new file mode 100644 index 0000000000000000000000000000000000000000..be6d9001fdf49f391f6690d582f5701a6de3ce90 GIT binary patch literal 148816 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 + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/doc/source/_static/qibo_logo_light.svg b/doc/source/_static/qibo_logo_light.svg new file mode 100644 index 0000000..bb907e7 --- /dev/null +++ b/doc/source/_static/qibo_logo_light.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 0000000..fe7b3d5 --- /dev/null +++ b/doc/source/conf.py @@ -0,0 +1,106 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +from pathlib import Path + +from sphinx.ext import apidoc + +import qibotn + +# sys.path.insert(0, os.path.abspath("..")) + + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "Qibotn" +copyright = "The Qibo team" +author = "The Qibo team" + +# The full version, including alpha/beta/rc tags +release = qibotn.__version__ + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + + +master_doc = "index" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.coverage", + "sphinx.ext.napoleon", + "sphinx.ext.intersphinx", + "sphinx_copybutton", + "sphinxcontrib.katex", +] + +templates_path = ["_templates"] +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "furo" +html_favicon = "favicon.ico" + +# custom title +html_title = "QiboTN · v" + release + +html_static_path = ["_static"] +html_show_sourcelink = False + +html_theme_options = { + "top_of_page_button": "edit", + "source_repository": "https://github.com/qiboteam/qibotn/", + "source_branch": "main", + "source_directory": "doc/source/", + "light_logo": "qibo_logo_dark.svg", + "dark_logo": "qibo_logo_light.svg", + "light_css_variables": { + "color-brand-primary": "#6400FF", + "color-brand-secondary": "#6400FF", + "color-brand-content": "#6400FF", + }, + "footer_icons": [ + { + "name": "GitHub", + "url": "https://github.com/qiboteam/qibotn", + "html": """ + + + + """, + "class": "", + }, + ], +} + +autodoc_mock_imports = ["cupy", "cuquantum"] + + +def run_apidoc(_): + """Extract autodoc directives from package structure.""" + source = Path(__file__).parent + docs_dest = source / "api-reference" + package = source.parents[1] / "src" / "qibotn" + apidoc.main(["--no-toc", "--module-first", "-o", str(docs_dest), str(package)]) + + +def setup(app): + app.add_css_file("css/style.css") + + app.connect("builder-inited", run_apidoc) diff --git a/doc/source/favicon.ico b/doc/source/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..62c493a6449aa2b8810c4c85f723ef1814f1e4ea GIT binary patch literal 15406 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 literal 0 HcmV?d00001 diff --git a/doc/source/getting-started/index.rst b/doc/source/getting-started/index.rst new file mode 100644 index 0000000..688df82 --- /dev/null +++ b/doc/source/getting-started/index.rst @@ -0,0 +1,12 @@ +Getting started +=============== + + +In this section we present the basic aspects of the Qibotn design and provide installation instructions. +Please visit the following sections to understand how ``qibotn`` works. + +.. toctree:: + :maxdepth: 1 + + installation + quickstart diff --git a/doc/source/getting-started/installation.rst b/doc/source/getting-started/installation.rst new file mode 100644 index 0000000..73f30cd --- /dev/null +++ b/doc/source/getting-started/installation.rst @@ -0,0 +1,10 @@ +Installation instructions +========================= + +QiboTN can be installed directly from the source repository on Github: + +.. code-block:: + + git clone https://github.com/qiboteam/qibotn.git + cd qibotn + poetry install diff --git a/doc/source/getting-started/quickstart.rst b/doc/source/getting-started/quickstart.rst new file mode 100644 index 0000000..7500e6a --- /dev/null +++ b/doc/source/getting-started/quickstart.rst @@ -0,0 +1,138 @@ +Quick start +=========== + +In this section, we provide examples on how to use Qibotn to execute tensor network +simulation of quantum circuit. First, we show how to use the Cutensornet and Quimb +backends, while in a second moment we show a complete example of usage of the Quantum +Matcha Tea Backend. + +Setting the backend with Cutensornet and Quimb +"""""""""""""""""""""""""""""""""""""""""""""" + +Among the backends provided by Qibotn, we have cutensornet (using cuQuantum library) +and qutensornet (using Quimb library) for tensor network based simulations. +At present, cutensornet backend works only for GPUs whereas qutensornet for CPUs. +These backend can be set using the following command line. + +To use cuQuantum library, cutensornet can be specified as follows:: + + qibo.set_backend( + backend="qibotn", platform="cutensornet", runcard=computation_settings + ) + +Similarly, to use Quimb library, qutensornet can be set as follows:: + + qibo.set_backend( + backend="qibotn", platform="qutensornet", runcard=computation_settings + ) + +Setting the runcard +""""""""""""""""""" + +The basic structure of the runcard is as follows:: + + computation_settings = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": { + "pauli_string_pattern": "IXZ", + }, + } + + +**MPI_enabled:** Setting this option *True* results in parallel execution of circuit using MPI (Message Passing Interface). At present, only works for cutensornet platform. + +**MPS_enabled:** This option is set *True* for Matrix Product State (MPS) based calculations where as general tensor network structure is used for *False* value. + +**NCCL_enabled:** This is set *True* for cutensoret interface for further acceleration while using Nvidia Collective Communication Library (NCCL). + +**expectation_enabled:** This option is set *True* while calculating expecation value of the circuit. Observable whose expectation value is to be calculated is passed as a string in the dict format as {"pauli_string_pattern": "observable"}. When the option is set *False*, the dense vector state of the circuit is calculated. + + +Basic example +""""""""""""" + +The following is a basic example to execute a two qubit circuit and print the final state in dense vector form using quimb backend:: + + import qibo + from qibo import Circuit, gates + + # Set the runcard + computation_settings = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": False, + } + + + # Set the quimb backend + qibo.set_backend( + backend="qibotn", platform="qutensornet", runcard=computation_settings + ) + + + # Construct the circuit with two qubits + c = Circuit(2) + + # Apply Hadamard gates on first and second qubit + c.add(gates.H(0)) + c.add(gates.H(1)) + + # Execute the circuit and obtain the final state + result = c() + + # Print the final state + print(result.state()) + + +Using the Quantum Matcha Tea backend +"""""""""""""""""""""""""""""""""""" + +In the following we show an example of how the Quantum Matcha Tea backend can be +used to execute a quantum circuit:: + + # We need Qibo to setup the circuit and the backend + from qibo import Circuit, gates + from qibo.models.encodings import ghz_state + from qibo.backends import construct_backend + + # We need Quantum Matcha Tea to customize the tensor network simulation + from qmatchatea import QCConvergenceParameters + + # Set the number of qubits + nqubits = 40 + + # Construct a circuit preparing a Quantum Fourier Transform + circuit = ghz_state(nqubits) + + # Construct the backend + backend = construct_backend(backend="qibotn", platform="qmatchatea") + + # Customize the low-level backend preferences according to Qibo's formalism + backend.set_device("/CPU:1") + backend.set_precision("double") + + # Customize the tensor network simulation itself + backend.configure_tn_simulation( + ansatz = "MPS", + convergence_params = QCConvergenceParameters(max_bond_dimension=50, cut_ratio=1e-6) + ) + + # Execute the tensor network simulation + outcome = backend.execute_circuit( + circuit = circuit, + nshots=1024, + ) + + # Print some results + print(outcome.probabilities()) + # Should print something like: {'0000000000000000000000000000000000000000': 0.5000000000000001, '1111111111111111111111111111111111111111': 0.5000000000000001} + print(outcome.frequencies()) + # Should print something like: {'0000000000000000000000000000000000000000': 488, '1111111111111111111111111111111111111111': 536} + + +By default, the simulator is choosing a specific method to compute the probabilities, +and for further information we recommend the user to refer to our High-Level-API +docstrings: :doc:`/api-reference/qibotn.backends`. diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 0000000..1353ac5 --- /dev/null +++ b/doc/source/index.rst @@ -0,0 +1,101 @@ +.. title:: + QiboTN + +What is QiboTN? +=============== + +Qibotn is an high-level library which integrates tensor network simulation within +the `Qibo `_ ecosystem. + +If you are familiar with Qibo, you will be well aware of the modularity we provide +through the use of our backends: after building a specific algorithm or quantum +circuit, any of our backends can be selected to perform operations on the +desired hardware (classical or quantum). + +Here, we extend this modularity to one of the most famous quantum inspired simulation +technique. + +We do this by relying on well-known and maintained packages, and integrating their +operation into our own dedicated backends. + +.. image:: QiboTN.png + + +As shown in the figure above, we currently support three different backends, which +correspond to the three mentioned packages: + - `cuQuantum `_: an NVIDIA SDK of optimized libraries and tools for accelerating quantum computing workflows (we refer to the specific `Cutensornet `_ library); + - `quimb `_: an easy but fast python library for ‘quantum information many-body’ calculations, focusing primarily on tensor networks; + - `Quantum Matcha Tea `_: a logical quantum computer emulator powered by matrix product states. Read `here `_ if you want to have an example on how using the Quantum Matcha Tea backend. + +.. warning:: + + There are currently two ways to use the three backends (`qmatchatea` is + slightly different from the others), but we are working to standardize the interface. + +Thanks to the mentioned packages, we currently support some tensor network ansatze: +Matrix Product States (MPS) on any mentioned backend, Tree Tensor Networks (TTN) +through the Quantum Matcha Tea backend and a more general Tensor Network (TN) ansatz through +Cutensornet and Quimb. + +Supported simulation features +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We support Tensor Network contractions to: + +- dense vectors (all the backends) +- expecation values of given Pauli string (Cutensornet and Qmatchatea) + +The supported HPC configurations are: + +- single-node CPU through Quimb and Qmatchatea +- single-node GPU or GPUs through Cutensornet and Qmatchatea +- multi-node multi-GPU with Message Passing Interface (MPI) through Cutensornet +- multi-node multi-GPU with NVIDIA Collective Communications Library (NCCL) through Cutensornet + + +How to Use the Documentation +============================ + +Welcome to the comprehensive documentation for QiboTN! This guide will help you navigate through the various sections and make the most of the resources available. + + +1. **Getting started**: Begin by referring to the + :doc:`/getting-started/installation/` guide to set up the ``QiboTN`` library in your environment. + +2. **Tutorials**: Explore the :doc:`getting-started/quickstart/` section for basic usage examples + + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + :caption: Introduction + + getting-started/index + +.. toctree:: + :maxdepth: 1 + :caption: Main documentation + + api-reference/qibotn + Developer guides + +.. toctree:: + :maxdepth: 1 + :caption: Documentation links + + Qibo docs + Qibolab docs + Qibocal docs + Qibosoq docs + Qibochem docs + Qibotn docs + Qibo-cloud-backends docs + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/examples/qmatchatea_intro/qmatchatea_introduction.ipynb b/examples/qmatchatea_intro/qmatchatea_introduction.ipynb new file mode 100644 index 0000000..6a338e2 --- /dev/null +++ b/examples/qmatchatea_intro/qmatchatea_introduction.ipynb @@ -0,0 +1,581 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "656bb283-ac6d-48d2-a029-3c417c9961f8", + "metadata": {}, + "source": [ + "## Introduction to Quantum Matcha Tea backend in QiboTN\n", + "\n", + "#### Some imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6722d94e-e311-48f9-b6df-c6d829bf67fb", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import numpy as np\n", + "from scipy import stats\n", + "\n", + "import qibo\n", + "from qibo import Circuit, gates, hamiltonians\n", + "from qibo.backends import construct_backend" + ] + }, + { + "cell_type": "markdown", + "id": "a009a5e0-cfd4-4a49-9f7c-e82f252c6147", + "metadata": {}, + "source": [ + "#### Some hyper parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "64162116-1555-4a68-811c-01593739d622", + "metadata": {}, + "outputs": [], + "source": [ + "# construct qibotn backend\n", + "qmatcha_backend = construct_backend(backend=\"qibotn\", platform=\"qmatchatea\")\n", + "\n", + "# set number of qubits\n", + "nqubits = 4\n", + "\n", + "# set numpy random seed\n", + "np.random.seed(42)" + ] + }, + { + "cell_type": "markdown", + "id": "252f5cd1-5932-4de6-8076-4a357d50ebad", + "metadata": {}, + "source": [ + "#### Constructing a parametric quantum circuit" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "4a22a172-f50d-411d-afa3-fa61937c7b3a", + "metadata": {}, + "outputs": [], + "source": [ + "def build_circuit(nqubits, nlayers):\n", + " \"\"\"Construct a parametric quantum circuit.\"\"\"\n", + " circ = Circuit(nqubits)\n", + " for _ in range(nlayers):\n", + " for q in range(nqubits):\n", + " circ.add(gates.RY(q=q, theta=0.))\n", + " circ.add(gates.RZ(q=q, theta=0.))\n", + " [circ.add(gates.CNOT(q%nqubits, (q+1)%nqubits) for q in range(nqubits))]\n", + " circ.add(gates.M(*range(nqubits)))\n", + " return circ" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "76f23c57-6d08-496b-9a27-52fb63bbfcb1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0: ─RY─RZ─o─────X─RY─RZ─o─────X─RY─RZ─o─────X─M─\n", + "1: ─RY─RZ─X─o───|─RY─RZ─X─o───|─RY─RZ─X─o───|─M─\n", + "2: ─RY─RZ───X─o─|─RY─RZ───X─o─|─RY─RZ───X─o─|─M─\n", + "3: ─RY─RZ─────X─o─RY─RZ─────X─o─RY─RZ─────X─o─M─\n" + ] + } + ], + "source": [ + "circuit = build_circuit(nqubits=nqubits, nlayers=3)\n", + "circuit.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "07b2c097-cea2-42ec-8f1d-b4bbb5b71d98", + "metadata": {}, + "outputs": [], + "source": [ + "# Setting random parameters\n", + "circuit.set_parameters(\n", + " parameters=np.random.uniform(-np.pi, np.pi, len(circuit.get_parameters())),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fd0cea52-03f5-4366-a01a-a5a84aa8ebc7", + "metadata": {}, + "source": [ + "#### Setting up the tensor network simulator\n", + "\n", + "Depending on the simulator, various parameters can be set. One can customize the tensor network execution via the `backend.configure_tn_simulation` function, whose face depends on the specific backend provider." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "2ee03e94-d794-4a51-9e76-01e8d8a259ba", + "metadata": {}, + "outputs": [], + "source": [ + "# Customization of the tensor network simulation in the case of qmatchatea\n", + "# Here we use only some of the possible arguments\n", + "qmatcha_backend.configure_tn_simulation(\n", + " ansatz=\"MPS\",\n", + " max_bond_dimension=10,\n", + " cut_ratio=1e-6,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "648d85b8-445d-4081-aeed-1691fbae67be", + "metadata": {}, + "source": [ + "#### Executing through the backend\n", + "\n", + "The `backend.execute_circuit` method can be used then. We can simulate results in three ways:\n", + "1. reconstruction of the final state (statevector like, only if `nqubits < 20` due to Quantum Matcha Tea setup) only if `return_array` is set to `True`;\n", + "2. computation of the relevant probabilities of the final state. There are three way of doing so, but we will see it directly into the docstrings;\n", + "3. reconstruction of the relevant state's frequencies (only if `nshots` is not `None`)." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "35a244c3-adba-4b8b-b28c-0ab592b0f7cf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'nqubits': 4,\n", + " 'backend': QMatchaTeaBackend(),\n", + " 'measures': None,\n", + " 'measured_probabilities': {'U': {'0000': (0.0, 0.08390937969317301),\n", + " '0001': (0.08390937969317301, 0.08858639088838134),\n", + " '0010': (0.08858639088838131, 0.1832549957082757),\n", + " '0011': (0.1832549957082757, 0.25896776804349736),\n", + " '0100': (0.2589677680434974, 0.33039716334036867),\n", + " '0101': (0.33039716334036867, 0.386620221067355),\n", + " '0110': (0.3866202210673549, 0.4380808691410473),\n", + " '0111': (0.4380808691410473, 0.47837271988834),\n", + " '1000': (0.47837271988834, 0.5916815553716759),\n", + " '1001': (0.5916815553716759, 0.5972581739037379),\n", + " '1010': (0.5972581739037378, 0.6359857590550054),\n", + " '1011': (0.6359857590550054, 0.6894851559808782),\n", + " '1100': (0.6894851559808783, 0.7030911408535467),\n", + " '1101': (0.7030911408535467, 0.8264027395524797),\n", + " '1110': (0.8264027395524797, 0.8981519382820797),\n", + " '1111': (0.8981519382820797, 0.9999999999999998)},\n", + " 'E': [None],\n", + " 'G': [None]},\n", + " 'prob_type': 'U',\n", + " 'statevector': None}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Simple execution (defaults)\n", + "outcome = qmatcha_backend.execute_circuit(circuit=circuit)\n", + "\n", + "# Print outcome\n", + "vars(outcome)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "60501c3d-2a44-421f-b434-4a508714b132", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'nqubits': 4,\n", + " 'backend': QMatchaTeaBackend(),\n", + " 'measures': None,\n", + " 'measured_probabilities': {'U': [None],\n", + " 'E': [None],\n", + " 'G': {'1110': 0.07174919872960005,\n", + " '1111': 0.10184806171792007,\n", + " '0010': 0.09466860481989439,\n", + " '0011': 0.07571277233522165}},\n", + " 'prob_type': 'G',\n", + " 'statevector': array([ 0.08809627-0.27595005j, 0.24859731-0.22695421j,\n", + " 0.18807826+0.18988408j, 0.09444097+0.06846085j,\n", + " 0.00470148+0.30764671j, 0.17371395-0.09247188j,\n", + " -0.18900305+0.12545316j, -0.17359753+0.20399288j,\n", + " -0.0517478 +0.04471215j, -0.0411739 -0.06230031j,\n", + " 0.22377064+0.07842041j, -0.21784975-0.27541439j,\n", + " -0.27208941+0.04098933j, -0.22748127+0.04185292j,\n", + " 0.17105258-0.10503745j, -0.01729753-0.31866731j])}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Execution with a specific probability type\n", + "# We use here \"E\", which is cutting some of the components if under a threshold\n", + "# We also retrieve the statevector\n", + "outcome = qmatcha_backend.execute_circuit(\n", + " circuit=circuit,\n", + " prob_type=\"G\",\n", + " prob_threshold=0.3,\n", + " return_array=True,\n", + ")\n", + "\n", + "# Print outcome\n", + "vars(outcome)" + ] + }, + { + "cell_type": "markdown", + "id": "84ec0b48-f6b4-495c-93b8-8e42d1a8b0df", + "metadata": {}, + "source": [ + "---\n", + "\n", + "One can access to the specific contents of the simulation outcome." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c0443efc-21ef-4ed5-9cf4-785d204a1881", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Probabilities:\n", + " [0.0717492 0.10184806 0.0946686 0.07571277]\n", + "\n", + "State:\n", + " [ 0.08809627-0.27595005j 0.24859731-0.22695421j 0.18807826+0.18988408j\n", + " 0.09444097+0.06846085j 0.00470148+0.30764671j 0.17371395-0.09247188j\n", + " -0.18900305+0.12545316j -0.17359753+0.20399288j -0.0517478 +0.04471215j\n", + " -0.0411739 -0.06230031j 0.22377064+0.07842041j -0.21784975-0.27541439j\n", + " -0.27208941+0.04098933j -0.22748127+0.04185292j 0.17105258-0.10503745j\n", + " -0.01729753-0.31866731j]\n", + "\n" + ] + } + ], + "source": [ + "print(f\"Probabilities:\\n {outcome.probabilities()}\\n\")\n", + "print(f\"State:\\n {outcome.state()}\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "9f477388-ca45-409a-a0ce-6603ec294e42", + "metadata": {}, + "source": [ + "---\n", + "\n", + "But frequencies cannot be accessed, since no shots have been set." + ] + }, + { + "cell_type": "markdown", + "id": "8e9413c7-602a-44ed-a50c-1c3dd4dd7494", + "metadata": {}, + "source": [ + "---\n", + "\n", + "We can then repeat the execution by setting the number of shots" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "68122cd3-662f-4fd1-bb9c-d33b6f5448dd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'nqubits': 4,\n", + " 'backend': QMatchaTeaBackend(),\n", + " 'measures': {'0000': 92,\n", + " '0001': 7,\n", + " '0010': 85,\n", + " '0011': 79,\n", + " '0100': 81,\n", + " '0101': 55,\n", + " '0110': 47,\n", + " '0111': 39,\n", + " '1000': 117,\n", + " '1001': 7,\n", + " '1010': 38,\n", + " '1011': 53,\n", + " '1100': 22,\n", + " '1101': 129,\n", + " '1110': 74,\n", + " '1111': 99},\n", + " 'measured_probabilities': {'U': [None],\n", + " 'E': {'0000': 0.08390937969317301,\n", + " '0010': 0.09466860481989439,\n", + " '0011': 0.07571277233522165,\n", + " '0100': 0.07142939529687124,\n", + " '0101': 0.05622305772698632,\n", + " '0110': 0.05146064807369245,\n", + " '1000': 0.11330883548333581,\n", + " '1011': 0.053499396925872765,\n", + " '1101': 0.12331159869893296,\n", + " '1110': 0.07174919872960005,\n", + " '1111': 0.10184806171792007},\n", + " 'G': [None]},\n", + " 'prob_type': 'E',\n", + " 'statevector': array([ 0.08809627-0.27595005j, 0.24859731-0.22695421j,\n", + " 0.18807826+0.18988408j, 0.09444097+0.06846085j,\n", + " 0.00470148+0.30764671j, 0.17371395-0.09247188j,\n", + " -0.18900305+0.12545316j, -0.17359753+0.20399288j,\n", + " -0.0517478 +0.04471215j, -0.0411739 -0.06230031j,\n", + " 0.22377064+0.07842041j, -0.21784975-0.27541439j,\n", + " -0.27208941+0.04098933j, -0.22748127+0.04185292j,\n", + " 0.17105258-0.10503745j, -0.01729753-0.31866731j])}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Execution with a specific probability type\n", + "# We use here \"E\", which is cutting some of the components if under a threshold\n", + "outcome = qmatcha_backend.execute_circuit(\n", + " circuit=circuit,\n", + " nshots=1024,\n", + " prob_type=\"E\",\n", + " prob_threshold=0.05,\n", + " return_array=True\n", + ")\n", + "\n", + "# Print outcome\n", + "vars(outcome)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "ef0e9591-ccca-4cdd-a81b-2bfb3caaf3d0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Frequencies:\n", + " {'0000': 92, '0001': 7, '0010': 85, '0011': 79, '0100': 81, '0101': 55, '0110': 47, '0111': 39, '1000': 117, '1001': 7, '1010': 38, '1011': 53, '1100': 22, '1101': 129, '1110': 74, '1111': 99}\n", + "\n", + "Probabilities:\n", + " [0.08390938 0.0946686 0.07571277 0.0714294 0.05622306 0.05146065\n", + " 0.11330884 0.0534994 0.1233116 0.0717492 0.10184806]\n", + "\n", + "State:\n", + " [ 0.08809627-0.27595005j 0.24859731-0.22695421j 0.18807826+0.18988408j\n", + " 0.09444097+0.06846085j 0.00470148+0.30764671j 0.17371395-0.09247188j\n", + " -0.18900305+0.12545316j -0.17359753+0.20399288j -0.0517478 +0.04471215j\n", + " -0.0411739 -0.06230031j 0.22377064+0.07842041j -0.21784975-0.27541439j\n", + " -0.27208941+0.04098933j -0.22748127+0.04185292j 0.17105258-0.10503745j\n", + " -0.01729753-0.31866731j]\n", + "\n" + ] + } + ], + "source": [ + "# Frequencies and probabilities\n", + "print(f\"Frequencies:\\n {outcome.frequencies()}\\n\")\n", + "print(f\"Probabilities:\\n {outcome.probabilities()}\\n\")\n", + "print(f\"State:\\n {outcome.state()}\\n\") # Only if return_array = True" + ] + }, + { + "cell_type": "markdown", + "id": "dd84f1f3-7aa5-4ad1-ae09-81e0aff75b5b", + "metadata": {}, + "source": [ + "### Compute expectation values\n", + "\n", + "Another important feature of this backend is the `expectation` function. In fact, we can compute expectation values of given observables thorugh a Qibo-friendly interface.\n", + "\n", + "---\n", + "\n", + "Let's start by importing some symbols, thanks to which we can build our observable." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "0b46e315-7786-4247-bd2a-83ea1c5842eb", + "metadata": {}, + "outputs": [], + "source": [ + "from qibo.symbols import Z, X" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "37385485-e8a3-4ab0-ad44-bcc4e9da24ca", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0: ─RY─RZ─o─────X─RY─RZ─o─────X─RY─RZ─o─────X─M─\n", + "1: ─RY─RZ─X─o───|─RY─RZ─X─o───|─RY─RZ─X─o───|─M─\n", + "2: ─RY─RZ───X─o─|─RY─RZ───X─o─|─RY─RZ───X─o─|─M─\n", + "3: ─RY─RZ─────X─o─RY─RZ─────X─o─RY─RZ─────X─o─M─\n" + ] + } + ], + "source": [ + "# We are going to compute the expval of an Hamiltonian\n", + "# On the state prepared by the following circuit\n", + "circuit.draw()\n", + "\n", + "circuit.set_parameters(\n", + " np.random.randn(len(circuit.get_parameters()))\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "ddecc910-7804-4199-8577-a7db38a16db8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Qibo 0.2.15|INFO|2025-02-12 14:36:17]: Using qibojit (numba) backend on /CPU:0\n" + ] + }, + { + "data": { + "text/latex": [ + "$\\displaystyle - 1.5 X_{0} Z_{2} + 0.5 Z_{0} Z_{1} + Z_{3}$" + ], + "text/plain": [ + "-1.5*X0*Z2 + 0.5*Z0*Z1 + Z3" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# We can create a symbolic Hamiltonian\n", + "form = 0.5 * Z(0) * Z(1) +- 1.5 * X(0) * Z(2) + Z(3)\n", + "hamiltonian = hamiltonians.SymbolicHamiltonian(form)\n", + "\n", + "# Let's show it\n", + "hamiltonian.form" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "163b70a3-814a-4a62-a98a-2ffca933a544", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.4355195352502318" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# And compute its expectation value\n", + "qmatcha_backend.expectation(\n", + " circuit=circuit,\n", + " observable=hamiltonian,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "2d8c4a9c-eca3-49d0-bdbf-ab054172c4e5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.43551953525022985" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Try with Qibo (which is by default using the Qibojit backend)\n", + "hamiltonian = hamiltonians.SymbolicHamiltonian(form)\n", + "hamiltonian.expectation(circuit().state())" + ] + }, + { + "cell_type": "markdown", + "id": "94df291c-9ddc-4b2e-8442-5fca00784bd8", + "metadata": {}, + "source": [ + "They match! 🥳" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/quimb_intro/quimb_introduction.ipynb b/examples/quimb_intro/quimb_introduction.ipynb new file mode 100644 index 0000000..5eaacc4 --- /dev/null +++ b/examples/quimb_intro/quimb_introduction.ipynb @@ -0,0 +1,572 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "656bb283-ac6d-48d2-a029-3c417c9961f8", + "metadata": {}, + "source": [ + "## Introduction to Quimb backend in QiboTN\n", + "\n", + "#### Some imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6722d94e-e311-48f9-b6df-c6d829bf67fb", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import numpy as np\n", + "# from scipy import stats\n", + "\n", + "# import qibo\n", + "from qibo import Circuit, gates, hamiltonians\n", + "from qibo.backends import construct_backend" + ] + }, + { + "cell_type": "markdown", + "id": "0c5a8939", + "metadata": {}, + "source": [ + "#### Some hyper parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64162116-1555-4a68-811c-01593739d622", + "metadata": {}, + "outputs": [], + "source": [ + "# construct qibotn backend\n", + "quimb_backend = construct_backend(backend=\"qibotn\", platform=\"quimb\")\n", + "\n", + "# set number of qubits\n", + "nqubits = 4\n", + "\n", + "# set numpy random seed\n", + "np.random.seed(42)\n", + "\n", + "quimb_backend.setup_backend_specifics(quimb_backend=\"jax\", contractions_optimizer='auto-hq')" + ] + }, + { + "cell_type": "markdown", + "id": "926cfea5", + "metadata": {}, + "source": [ + "Quimb accepts different methods for optimizing the way it does contractions, that we pass through \"contractions_optimizer\". \n", + "We could also define our own cotengra contraction optimizer! \n", + "\n", + "cotengra is a Python library designed for **optimising contraction trees** and performing efficient contractions of large tensor‐networks.\n", + "You can find it here: [https://github.com/jcmgray/cotengra](https://github.com/jcmgray/cotengra)\n", + "\n", + "For the sake of this tutorial however the default \"auto-hq\" will be fine :) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0a1da82", + "metadata": {}, + "outputs": [], + "source": [ + "import cotengra as ctg\n", + "ctg_opt = ctg.ReusableHyperOptimizer(\n", + " max_time=10,\n", + " minimize='combo',\n", + " slicing_opts=None,\n", + " parallel=True,\n", + " progbar=True\n", + ")\n", + "# quimb_backend.setup_backend_specifics(quimb_backend=\"jax\", contractions_optimizer='ctg_opt')" + ] + }, + { + "cell_type": "markdown", + "id": "252f5cd1-5932-4de6-8076-4a357d50ebad", + "metadata": {}, + "source": [ + "#### Constructing a parametric quantum circuit" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4a22a172-f50d-411d-afa3-fa61937c7b3a", + "metadata": {}, + "outputs": [], + "source": [ + "def build_circuit(nqubits, nlayers):\n", + " \"\"\"Construct a parametric quantum circuit.\"\"\"\n", + " circ = Circuit(nqubits)\n", + " for _ in range(nlayers):\n", + " for q in range(nqubits):\n", + " circ.add(gates.RY(q=q, theta=0.))\n", + " circ.add(gates.RZ(q=q, theta=0.))\n", + " [circ.add(gates.CNOT(q%nqubits, (q+1)%nqubits) for q in range(nqubits))]\n", + " circ.add(gates.M(*range(nqubits)))\n", + " return circ" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "76f23c57-6d08-496b-9a27-52fb63bbfcb1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0: ─RY─RZ─o─────X─RY─RZ─o─────X─RY─RZ─o─────X─M─\n", + "1: ─RY─RZ─X─o───|─RY─RZ─X─o───|─RY─RZ─X─o───|─M─\n", + "2: ─RY─RZ───X─o─|─RY─RZ───X─o─|─RY─RZ───X─o─|─M─\n", + "3: ─RY─RZ─────X─o─RY─RZ─────X─o─RY─RZ─────X─o─M─\n" + ] + } + ], + "source": [ + "circuit = build_circuit(nqubits=nqubits, nlayers=3)\n", + "circuit.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "07b2c097-cea2-42ec-8f1d-b4bbb5b71d98", + "metadata": {}, + "outputs": [], + "source": [ + "# Setting random parameters\n", + "circuit.set_parameters(\n", + " parameters=np.random.uniform(-np.pi, np.pi, len(circuit.get_parameters())),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fd0cea52-03f5-4366-a01a-a5a84aa8ebc7", + "metadata": {}, + "source": [ + "#### Setting up the tensor network simulator\n", + "\n", + "Depending on the simulator, various parameters can be set. One can customize the tensor network execution via the `backend.configure_tn_simulation` function, whose face depends on the specific backend provider." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "2ee03e94-d794-4a51-9e76-01e8d8a259ba", + "metadata": {}, + "outputs": [], + "source": [ + "# Customization of the tensor network simulation in the case of quimb backend\n", + "# Here we use only some of the possible arguments\n", + "quimb_backend.configure_tn_simulation(\n", + " #ansatz=\"MPS\",\n", + " max_bond_dimension=10\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "648d85b8-445d-4081-aeed-1691fbae67be", + "metadata": {}, + "source": [ + "#### Executing through the backend\n", + "\n", + "The `backend.execute_circuit` method can be used then. We can simulate results in three ways:\n", + "1. reconstruction of the final state only if `return_array` is set to `True`;\n", + "2. computation of the relevant probabilities of the final state.\n", + "3. reconstruction of the relevant state's frequencies (only if `nshots` is not `None`)." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "35a244c3-adba-4b8b-b28c-0ab592b0f7cf", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/andrea/python_envs/3.11/lib/python3.11/site-packages/quimb/tensor/circuit.py:215: SyntaxWarning: Unsupported operation ignored: creg\n", + " warnings.warn(\n", + "/home/andrea/python_envs/3.11/lib/python3.11/site-packages/quimb/tensor/circuit.py:215: SyntaxWarning: Unsupported operation ignored: measure\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "text/plain": [ + "{'nqubits': 4,\n", + " 'backend': qibotn (quimb),\n", + " 'measures': Counter({'1101': 14,\n", + " '1000': 12,\n", + " '0010': 11,\n", + " '0011': 11,\n", + " '0110': 9,\n", + " '0000': 8,\n", + " '1010': 7,\n", + " '1110': 6,\n", + " '0100': 5,\n", + " '1111': 5,\n", + " '1011': 5,\n", + " '0101': 4,\n", + " '0111': 1,\n", + " '0001': 1,\n", + " '1100': 1}),\n", + " 'measured_probabilities': {'1101': np.float64(0.12331159869893284),\n", + " '1000': np.float64(0.11330883548333684),\n", + " '0010': np.float64(0.0946686048198943),\n", + " '0011': np.float64(0.07571277233522157),\n", + " '0110': np.float64(0.051460648073692314),\n", + " '0000': np.float64(0.08390937969317334),\n", + " '1010': np.float64(0.03872758515126775),\n", + " '1110': np.float64(0.07174919872960006),\n", + " '0100': np.float64(0.07142939529687146),\n", + " '1111': np.float64(0.10184806171791994),\n", + " '1011': np.float64(0.053499396925872716),\n", + " '0101': np.float64(0.05622305772698606),\n", + " '0111': np.float64(0.040291850747292815),\n", + " '0001': np.float64(0.004677011195208322),\n", + " '1100': np.float64(0.013605984872668443)},\n", + " 'prob_type': 'default',\n", + " 'statevector': Array([[ 0.08809626-0.27595j ],\n", + " [-0.05174781+0.04471214j],\n", + " [ 0.00470146+0.30764672j],\n", + " [-0.27208942+0.04098931j],\n", + " [ 0.18807825+0.1898841j ],\n", + " [ 0.22377063+0.07842041j],\n", + " [-0.18900302+0.12545316j],\n", + " [ 0.17105258-0.10503745j],\n", + " [ 0.24859732-0.22695422j],\n", + " [-0.04117391-0.0623003j ],\n", + " [ 0.17371394-0.09247189j],\n", + " [-0.22748126+0.04185291j],\n", + " [ 0.09444097+0.06846087j],\n", + " [-0.21784975-0.2754144j ],\n", + " [-0.17359754+0.20399287j],\n", + " [-0.01729751-0.31866732j]], dtype=complex64)}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# # Simple execution (defaults)\n", + "outcome = quimb_backend.execute_circuit(circuit=circuit, nshots=100, return_array=True)\n", + "\n", + "# # Print outcome\n", + "vars(outcome)" + ] + }, + { + "cell_type": "markdown", + "id": "84ec0b48-f6b4-495c-93b8-8e42d1a8b0df", + "metadata": {}, + "source": [ + "---\n", + "\n", + "One can access to the specific contents of the simulation outcome." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c0443efc-21ef-4ed5-9cf4-785d204a1881", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Probabilities:\n", + " {'1101': np.float64(0.12331159869893284), '1000': np.float64(0.11330883548333684), '0010': np.float64(0.0946686048198943), '0011': np.float64(0.07571277233522157), '0110': np.float64(0.051460648073692314), '0000': np.float64(0.08390937969317334), '1010': np.float64(0.03872758515126775), '1110': np.float64(0.07174919872960006), '0100': np.float64(0.07142939529687146), '1111': np.float64(0.10184806171791994), '1011': np.float64(0.053499396925872716), '0101': np.float64(0.05622305772698606), '0111': np.float64(0.040291850747292815), '0001': np.float64(0.004677011195208322), '1100': np.float64(0.013605984872668443)}\n", + "\n", + "State:\n", + " [[ 0.08809626-0.27595j ]\n", + " [-0.05174781+0.04471214j]\n", + " [ 0.00470146+0.30764672j]\n", + " [-0.27208942+0.04098931j]\n", + " [ 0.18807825+0.1898841j ]\n", + " [ 0.22377063+0.07842041j]\n", + " [-0.18900302+0.12545316j]\n", + " [ 0.17105258-0.10503745j]\n", + " [ 0.24859732-0.22695422j]\n", + " [-0.04117391-0.0623003j ]\n", + " [ 0.17371394-0.09247189j]\n", + " [-0.22748126+0.04185291j]\n", + " [ 0.09444097+0.06846087j]\n", + " [-0.21784975-0.2754144j ]\n", + " [-0.17359754+0.20399287j]\n", + " [-0.01729751-0.31866732j]]\n", + "\n" + ] + } + ], + "source": [ + "print(f\"Probabilities:\\n {outcome.probabilities()}\\n\")\n", + "print(f\"State:\\n {outcome.state()}\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "9531f9d6", + "metadata": {}, + "source": [ + "### Compute expectation values\n", + "\n", + "Another important feature of this backend is the `expectation` function. In fact, we can compute expectation values of given observables thorugh a Qibo-friendly interface.\n", + "\n", + "---\n", + "\n", + "Let's start by importing some symbols, thanks to which we can build our observable." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "647f2073", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import jax\n", + "from qibo.backends import construct_backend\n", + "from qibo import Circuit, gates" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "74c63a41", + "metadata": {}, + "outputs": [], + "source": [ + "# construct qibotn backend\n", + "quimb_backend = construct_backend(backend=\"qibotn\", platform=\"quimb\")\n", + "\n", + "quimb_backend.setup_backend_specifics(\n", + " quimb_backend =\"jax\", \n", + " contractions_optimizer='auto-hq'\n", + " )\n", + "\n", + "quimb_backend.configure_tn_simulation(\n", + " max_bond_dimension=10\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "b2a0decb", + "metadata": {}, + "outputs": [], + "source": [ + "from qibo.symbols import X, Z, Y\n", + "from qibo.hamiltonians import XXZ\n", + "\n", + "# define Hamiltonian\n", + "hamiltonian = XXZ(4, dense=False, backend=quimb_backend)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "bd734be8", + "metadata": {}, + "outputs": [], + "source": [ + "# define circuit\n", + "def build_circuit(nqubits, nlayers):\n", + " circ = Circuit(nqubits)\n", + " for layer in range(nlayers):\n", + " for q in range(nqubits):\n", + " circ.add(gates.RY(q=q, theta=0.))\n", + " circ.add(gates.RZ(q=q, theta=0.))\n", + " circ.add(gates.RX(q=q, theta=0.))\n", + " for q in range(nqubits - 1):\n", + " circ.add(gates.CNOT(q, q + 1))\n", + " circ.add(gates.SWAP(q, q + 1))\n", + " circ.add(gates.M(*range(nqubits)))\n", + " return circ\n", + "\n", + "def build_circuit_problematic(nqubits, nlayers):\n", + " circ = Circuit(nqubits)\n", + " for _ in range(nlayers):\n", + " for q in range(nqubits):\n", + " circ.add(gates.RY(q=q, theta=0.))\n", + " circ.add(gates.RZ(q=q, theta=0.))\n", + " [circ.add(gates.CNOT(q%nqubits, (q+1)%nqubits) for q in range(nqubits))]\n", + " circ.add(gates.M(*range(nqubits)))\n", + " return circ\n", + "\n", + "\n", + "nqubits = 4\n", + "circuit = build_circuit(nqubits=nqubits, nlayers=3)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "fe63ff24", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expectation value: 2.0\n", + "Elapsed time: 0.0268 seconds\n" + ] + } + ], + "source": [ + "start = time.time()\n", + "expval = hamiltonian.expectation(circuit)\n", + "\n", + "elapsed = time.time() - start\n", + "print(f\"Expectation value: {expval}\")\n", + "print(f\"Elapsed time: {elapsed:.4f} seconds\")" + ] + }, + { + "cell_type": "markdown", + "id": "d976a849", + "metadata": {}, + "source": [ + "Try with Qibo (which is by default using the Qibojit backend)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "fb1436c8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Qibo 0.2.21|INFO|2025-10-27 16:24:00]: Using numpy backend on /CPU:0\n", + "WARNING:root:Calculation of expectation values starting from the state is deprecated, use the ``expectation_from_state`` method if you really need it, or simply pass the circuit you want to calculate the expectation value from.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expectation value: 2.0\n", + "Elapsed time: 0.0360 seconds\n" + ] + } + ], + "source": [ + "sym_hamiltonian = XXZ(4, dense=False, backend=None)\n", + "\n", + "# Let's show it\n", + "sym_hamiltonian.form\n", + "\n", + "# Compute expectation value\n", + "start = time.time()\n", + "result = sym_hamiltonian.expectation(circuit().state())\n", + "elapsed = time.time() - start\n", + "print(f\"Expectation value: {result}\")\n", + "print(f\"Elapsed time: {elapsed:.4f} seconds\")" + ] + }, + { + "cell_type": "markdown", + "id": "77bef077", + "metadata": {}, + "source": [ + "They match! 🥳" + ] + }, + { + "cell_type": "markdown", + "id": "50130ae6", + "metadata": {}, + "source": [ + "We can also compute gradient of expectation function" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "6a3b26e4", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/andrea/python_envs/3.11/lib/python3.11/site-packages/quimb/tensor/circuit.py:4927: UserWarning: Unsupported options for computing local_expectation with an MPS circuit supplied, ignoring: R, None, None, jax, None\n", + " warnings.warn(\n", + "/home/andrea/python_envs/3.11/lib/python3.11/site-packages/quimb/tensor/circuit.py:4927: UserWarning: Unsupported options for computing local_expectation with an MPS circuit supplied, ignoring: R, None, None, jax, None\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-0.24630009 0.8370421 -0.11103702 -0.12855841 0.41325414 -0.0628037\n", + " 0.51638705 0.794163 -0.27972788 -1.0718998 0.02731732 1.0153619\n", + " -0.34494495 1.5744264 0.26920277 -0.36333832 0.12331417 0.5196531\n", + " 1.1294655 0.29257926 -0.18237355 0.8914014 -0.9471657 0.3492473\n", + " -0.3477673 0.24325958 0.04818404 -0.87983793 0.47196424 0.36605012\n", + " 1.005 0.65054715 -0.94860053 0.14459445 0.36571163 -0.2550101 ]\n" + ] + } + ], + "source": [ + "def f(circuit, hamiltonian, params):\n", + " circuit.set_parameters(params)\n", + " return hamiltonian.expectation(\n", + " circuit=circuit,\n", + " )\n", + "\n", + "parameters = np.random.uniform(-np.pi, np.pi, size=len(circuit.get_parameters()))\n", + "print(jax.grad(f, argnums=2)(circuit, hamiltonian, parameters))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aeafa5a6-2afa-429c-a101-effa84bac1d2", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..39d808d --- /dev/null +++ b/flake.lock @@ -0,0 +1,323 @@ +{ + "nodes": { + "devenv": { + "inputs": { + "flake-compat": "flake-compat", + "nix": "nix", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1710144971, + "narHash": "sha256-CjTOdoBvT/4AQncTL20SDHyJNgsXZjtGbz62yDIUYnM=", + "owner": "cachix", + "repo": "devenv", + "rev": "6c0bad0045f1e1802f769f7890f6a59504825f4d", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "id": "flake-utils", + "type": "indirect" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "devenv", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "lowdown-src": { + "flake": false, + "locked": { + "lastModified": 1633514407, + "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=", + "owner": "kristapsdz", + "repo": "lowdown", + "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8", + "type": "github" + }, + "original": { + "owner": "kristapsdz", + "repo": "lowdown", + "type": "github" + } + }, + "nix": { + "inputs": { + "lowdown-src": "lowdown-src", + "nixpkgs": [ + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1676545802, + "narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=", + "owner": "domenkozar", + "repo": "nix", + "rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "relaxed-flakes", + "repo": "nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1678875422, + "narHash": "sha256-T3o6NcQPwXjxJMn2shz86Chch4ljXgZn746c2caGxd8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "126f49a01de5b7e35a43fd43f891ecf6d3a51459", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-python": { + "inputs": { + "flake-compat": "flake-compat_2", + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709875392, + "narHash": "sha256-ZC/8TNR2q8Q+j4vzaW3B8jLS9ZDvss61brFW4VtWr0A=", + "owner": "cachix", + "repo": "nixpkgs-python", + "rev": "7296d316153575b8db614ff02dac5b7501a92071", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "nixpkgs-python", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1685801374, + "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1710272261, + "narHash": "sha256-g0bDwXFmTE7uGDOs9HcJsfLFhH7fOsASbAuOzDC+fhQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0ad13a6833440b8e238947e47bea7f11071dc2b2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": [ + "devenv", + "flake-compat" + ], + "flake-utils": "flake-utils", + "gitignore": "gitignore", + "nixpkgs": [ + "devenv", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1704725188, + "narHash": "sha256-qq8NbkhRZF1vVYQFt1s8Mbgo8knj+83+QlL5LBnYGpI=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "ea96f0c05924341c551a797aaba8126334c505d2", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "nixpkgs": "nixpkgs_2", + "nixpkgs-python": "nixpkgs-python", + "systems": "systems_3" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..a664df7 --- /dev/null +++ b/flake.nix @@ -0,0 +1,61 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + systems.url = "github:nix-systems/default"; + devenv.url = "github:cachix/devenv"; + nixpkgs-python = { + url = "github:cachix/nixpkgs-python"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { + self, + nixpkgs, + devenv, + systems, + ... + } @ inputs: let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + in { + # packages = forEachSystem (system: { + # default = + # nixpkgs.legacyPackages.${system}.poetry2nix.mkPoetryApplication + # { + # projectDir = self; + # preferWheels = true; + # }; + # }); + + devShells = + forEachSystem + (system: let + pkgs = nixpkgs.legacyPackages.${system}; + in { + default = devenv.lib.mkShell { + inherit inputs pkgs; + + modules = [ + { + packages = with pkgs; [pre-commit poethepoet stdenv.cc.cc.lib]; + + languages.python = { + enable = true; + poetry = { + enable = true; + install.enable = true; + install.groups = ["dev" "analysis" "tests"]; + }; + version = "3.11"; + }; + } + ]; + }; + }); + }; + + nixConfig = { + extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw="; + extra-substituters = "https://devenv.cachix.org"; + }; +} diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..bbee0b8 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,3944 @@ +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. + +[[package]] +name = "alabaster" +version = "0.7.16" +description = "A light, configurable Sphinx theme" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, +] + +[[package]] +name = "alembic" +version = "1.18.4" +description = "A database migration tool for SQLAlchemy." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "alembic-1.18.4-py3-none-any.whl", hash = "sha256:a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a"}, + {file = "alembic-1.18.4.tar.gz", hash = "sha256:cb6e1fd84b6174ab8dbb2329f86d631ba9559dd78df550b57804d607672cedbc"}, +] + +[package.dependencies] +Mako = "*" +SQLAlchemy = ">=1.4.23" +typing-extensions = ">=4.12" + +[package.extras] +tz = ["tzdata"] + +[[package]] +name = "antlr4-python3-runtime" +version = "4.13.2" +description = "ANTLR 4.13.2 runtime for Python 3" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "antlr4_python3_runtime-4.13.2-py3-none-any.whl", hash = "sha256:fe3835eb8d33daece0e799090eda89719dbccee7aa39ef94eed3818cafa5a7e8"}, + {file = "antlr4_python3_runtime-4.13.2.tar.gz", hash = "sha256:909b647e1d2fc2b70180ac586df3933e38919c85f98ccc656a96cd3f25ef3916"}, +] + +[[package]] +name = "astroid" +version = "3.3.11" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.9.0" +groups = ["analysis"] +files = [ + {file = "astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec"}, + {file = "astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce"}, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a"}, + {file = "asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7"}, +] + +[package.extras] +astroid = ["astroid (>=2,<5)"] +test = ["astroid (>=2,<5)", "pytest (<9.0)", "pytest-cov", "pytest-xdist"] + +[[package]] +name = "autoray" +version = "0.8.10" +description = "Abstract your array operations." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "autoray-0.8.10-py3-none-any.whl", hash = "sha256:033f4ba37e2278ece9c50be4a42abe0d91d5c611194d90904c4e6d980300454a"}, + {file = "autoray-0.8.10.tar.gz", hash = "sha256:a411c87fe5c0c12120c56478ddf64172d584705e582ef86ef12f81f5769f697f"}, +] + +[package.extras] +docs = ["furo", "ipython", "myst-nb", "setuptools-scm", "sphinx", "sphinx-autoapi", "sphinx-copybutton"] +tests = ["coverage", "numpy", "pytest", "pytest-cov"] + +[[package]] +name = "babel" +version = "2.18.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35"}, + {file = "babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d"}, +] + +[package.extras] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.7.0" +groups = ["docs"] +files = [ + {file = "beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb"}, + {file = "beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86"}, +] + +[package.dependencies] +soupsieve = ">=1.6.1" +typing-extensions = ">=4.0.0" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "certifi" +version = "2026.2.25" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["docs"] +files = [ + {file = "certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa"}, + {file = "certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +groups = ["docs"] +files = [ + {file = "charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_armv7l.whl", hash = "sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-win32.whl", hash = "sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win32.whl", hash = "sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c"}, + {file = "charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d"}, + {file = "charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5"}, +] + +[[package]] +name = "cma" +version = "3.4.0" +description = "CMA-ES, Covariance Matrix Adaptation Evolution Strategy for non-linear numerical optimization in Python" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "cma-3.4.0-py3-none-any.whl", hash = "sha256:4140e490cc4e68cf8c7b1114e079c0561c9b78b1bf9ec69362c20865636ae5ca"}, + {file = "cma-3.4.0.tar.gz", hash = "sha256:a1ebd969b99871be3715d5a24b7bf54cf04ea94e80d6b8536d7147620dd10f6c"}, +] + +[package.dependencies] +numpy = "*" + +[package.extras] +constrained-solution-tracking = ["moarchiving"] +plotting = ["matplotlib"] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "analysis", "dev", "docs", "tests"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] +markers = {main = "sys_platform == \"win32\" or platform_system == \"Windows\"", analysis = "sys_platform == \"win32\"", dev = "sys_platform == \"win32\"", docs = "sys_platform == \"win32\"", tests = "sys_platform == \"win32\""} + +[[package]] +name = "colorlog" +version = "6.10.1" +description = "Add colours to the output of Python's logging module." +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c"}, + {file = "colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +development = ["black", "flake8", "mypy", "pytest", "types-colorama"] + +[[package]] +name = "contourpy" +version = "1.3.3" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = true +python-versions = ">=3.11" +groups = ["main"] +files = [ + {file = "contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1"}, + {file = "contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381"}, + {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7"}, + {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1"}, + {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a"}, + {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db"}, + {file = "contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620"}, + {file = "contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f"}, + {file = "contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff"}, + {file = "contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42"}, + {file = "contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470"}, + {file = "contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb"}, + {file = "contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6"}, + {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7"}, + {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8"}, + {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea"}, + {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1"}, + {file = "contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7"}, + {file = "contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411"}, + {file = "contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69"}, + {file = "contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b"}, + {file = "contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc"}, + {file = "contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5"}, + {file = "contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1"}, + {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286"}, + {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5"}, + {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67"}, + {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9"}, + {file = "contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659"}, + {file = "contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7"}, + {file = "contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d"}, + {file = "contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263"}, + {file = "contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9"}, + {file = "contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d"}, + {file = "contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216"}, + {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae"}, + {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20"}, + {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99"}, + {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b"}, + {file = "contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a"}, + {file = "contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e"}, + {file = "contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3"}, + {file = "contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8"}, + {file = "contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301"}, + {file = "contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a"}, + {file = "contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77"}, + {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5"}, + {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4"}, + {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36"}, + {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3"}, + {file = "contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b"}, + {file = "contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36"}, + {file = "contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d"}, + {file = "contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd"}, + {file = "contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339"}, + {file = "contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772"}, + {file = "contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77"}, + {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13"}, + {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe"}, + {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f"}, + {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0"}, + {file = "contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4"}, + {file = "contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f"}, + {file = "contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae"}, + {file = "contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc"}, + {file = "contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77"}, + {file = "contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880"}, +] + +[package.dependencies] +numpy = ">=1.25" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.17.0)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] + +[[package]] +name = "cotengra" +version = "0.7.5" +description = "Hyper optimized contraction trees for large tensor networks and einsums." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "cotengra-0.7.5-py3-none-any.whl", hash = "sha256:0d269883ee87e4a08ce6c91ca38aafbd3d56e177a3b3b54d61e3fe314fe67e8b"}, + {file = "cotengra-0.7.5.tar.gz", hash = "sha256:f3cee6c0cd29fd239a1e9868c3b719c574cc56204dbf7e658ba10f3fd93dce98"}, +] + +[package.dependencies] +autoray = "*" + +[package.extras] +docs = ["astroid (<3.0.0)", "furo", "ipython (!=8.7.0)", "myst-nb", "setuptools-scm", "sphinx (>=2.0)", "sphinx-autoapi", "sphinx-copybutton", "sphinx-design"] +recommended = ["cmaes", "cotengrust (>=0.1.3)", "cytoolz", "kahypar", "networkx", "numpy", "opt-einsum", "optuna", "ray", "tqdm"] +test = ["altair", "baytune", "chocolate", "cmaes", "dask", "distributed", "kahypar", "matplotlib", "networkx", "nevergrad", "numpy", "opt-einsum", "pytest", "scikit-optimize", "seaborn"] + +[[package]] +name = "coverage" +version = "7.13.5" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.10" +groups = ["tests"] +files = [ + {file = "coverage-7.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0723d2c96324561b9aa76fb982406e11d93cdb388a7a7da2b16e04719cf7ca5"}, + {file = "coverage-7.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52f444e86475992506b32d4e5ca55c24fc88d73bcbda0e9745095b28ef4dc0cf"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:704de6328e3d612a8f6c07000a878ff38181ec3263d5a11da1db294fa6a9bdf8"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a1a6d79a14e1ec1832cabc833898636ad5f3754a678ef8bb4908515208bf84f4"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79060214983769c7ba3f0cee10b54c97609dca4d478fa1aa32b914480fd5738d"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:356e76b46783a98c2a2fe81ec79df4883a1e62895ea952968fb253c114e7f930"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0cef0cdec915d11254a7f549c1170afecce708d30610c6abdded1f74e581666d"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dc022073d063b25a402454e5712ef9e007113e3a676b96c5f29b2bda29352f40"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9b74db26dfea4f4e50d48a4602207cd1e78be33182bc9cbf22da94f332f99878"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ad146744ca4fd09b50c482650e3c1b1f4dfa1d4792e0a04a369c7f23336f0400"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c555b48be1853fe3997c11c4bd521cdd9a9612352de01fa4508f16ec341e6fe0"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7034b5c56a58ae5e85f23949d52c14aca2cfc6848a31764995b7de88f13a1ea0"}, + {file = "coverage-7.13.5-cp310-cp310-win32.whl", hash = "sha256:eb7fdf1ef130660e7415e0253a01a7d5a88c9c4d158bcf75cbbd922fd65a5b58"}, + {file = "coverage-7.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:3e1bb5f6c78feeb1be3475789b14a0f0a5b47d505bfc7267126ccbd50289999e"}, + {file = "coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d"}, + {file = "coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8"}, + {file = "coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf"}, + {file = "coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9"}, + {file = "coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028"}, + {file = "coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01"}, + {file = "coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c"}, + {file = "coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf"}, + {file = "coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810"}, + {file = "coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de"}, + {file = "coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1"}, + {file = "coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17"}, + {file = "coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85"}, + {file = "coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b"}, + {file = "coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664"}, + {file = "coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d"}, + {file = "coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2"}, + {file = "coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a"}, + {file = "coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819"}, + {file = "coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911"}, + {file = "coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f"}, + {file = "coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0"}, + {file = "coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc"}, + {file = "coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633"}, + {file = "coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8"}, + {file = "coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b"}, + {file = "coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a"}, + {file = "coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215"}, + {file = "coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43"}, + {file = "coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45"}, + {file = "coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61"}, + {file = "coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179"}, +] + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + +[[package]] +name = "cuda-bindings" +version = "12.9.6" +description = "Python bindings for CUDA" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cuda_bindings-12.9.6-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bb2f1eedc8f65902b34e807c21a3b7c922dc8de1f51d0829ecbb5c6a5e9c5ff1"}, + {file = "cuda_bindings-12.9.6-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9f9031e7a265e74f1517668139987253552d1677d995da4b0d990aa19b9b9b0"}, + {file = "cuda_bindings-12.9.6-cp310-cp310-win_amd64.whl", hash = "sha256:69e820e72af29bac65cf821a0a7b2546ef4cca5685640739a828c00ef91fdbef"}, + {file = "cuda_bindings-12.9.6-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2662f59db67d9aeaf8959c593c91f600792c2970cf02cae2814387fc687b115a"}, + {file = "cuda_bindings-12.9.6-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8519707644ea630a365b101703a9136f4cb144760cc2c73281c38a05e07d08d"}, + {file = "cuda_bindings-12.9.6-cp311-cp311-win_amd64.whl", hash = "sha256:e0ac0a4facdb9a6563984ae4917c7a658cbc6a5d0feb858e5a79ba4047c36397"}, + {file = "cuda_bindings-12.9.6-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea331bc47d9988cc61f0ecc5fa8df9dd188b4493ae1c6688bb1ee8ce8ba1af4"}, + {file = "cuda_bindings-12.9.6-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b2b54b95a47104eff56b5155818ab5790e3ccdba8dd51e2928ae56782aaf5b02"}, + {file = "cuda_bindings-12.9.6-cp312-cp312-win_amd64.whl", hash = "sha256:407b85671c363a5ddf77cd4bdeb05355340a88ac2cd0c6adc1a0f4b4d11c13c2"}, + {file = "cuda_bindings-12.9.6-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da30d89db8188b9beb5a6467d72b2f11d1b667ab901d2d373bcde51b97765b21"}, + {file = "cuda_bindings-12.9.6-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3d1be8bd80b34f51dcbaf138dafd817e888cf2d12c47833019fd933beb32d7ef"}, + {file = "cuda_bindings-12.9.6-cp313-cp313-win_amd64.whl", hash = "sha256:ee82fd3588ad28ec9887503bf81b329b89ea9ac0df726e0e50fb377abd57d2a0"}, + {file = "cuda_bindings-12.9.6-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48666e666f083a4c4387ffe20594b05e092b535a4453d1e4817d71237d02aa13"}, + {file = "cuda_bindings-12.9.6-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b4f82f8f8061f3a39446bf854c4edd9bcc2d0da3f58d8f6f54541b3e4d5c933d"}, + {file = "cuda_bindings-12.9.6-cp313-cp313t-win_amd64.whl", hash = "sha256:b1731d651fe05e795295bf011e98bae0ad5cc29759da7ccb6ff946cc541b50c1"}, + {file = "cuda_bindings-12.9.6-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f00290f9468d2cfeee92aaad2275be32dfd2f4967a97ac0f12314b7e6281ad78"}, + {file = "cuda_bindings-12.9.6-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3bc6e28cf5d133f72050c515db72876870fb009f1431bcbf45b54a179be2284"}, + {file = "cuda_bindings-12.9.6-cp314-cp314-win_amd64.whl", hash = "sha256:2b23ac88152b2b09f9c12fb70d5e07c25f17e915ab2e1b1dec7b702b25ae5dc6"}, + {file = "cuda_bindings-12.9.6-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e88d38fdf07cc777dec1afaba8139c2eedb3819063f6b42f1e2ea8516bdd6806"}, + {file = "cuda_bindings-12.9.6-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4df01e34cefd3275170b2ac0426d325271ab435e85f59a69300eacd8ff23d34c"}, + {file = "cuda_bindings-12.9.6-cp314-cp314t-win_amd64.whl", hash = "sha256:7f0a08eba6e807d041bf6f2ba66d84db1ddf54787399dfac716497ef40fb5fc3"}, +] + +[package.dependencies] +cuda-pathfinder = ">=1.1,<2.0" + +[package.extras] +all = ["nvidia-cuda-nvcc-cu12", "nvidia-cuda-nvrtc-cu12", "nvidia-cufile-cu12 ; sys_platform == \"linux\"", "nvidia-nvfatbin-cu12", "nvidia-nvjitlink-cu12 (>=12.3)"] +test = ["cython (>=3.2,<3.3)", "numpy (>=1.21.1)", "pyglet (>=2.1.9)", "pytest (>=6.2.4)", "pytest-benchmark (>=3.4.1)", "setuptools (>=77.0.0)"] + +[[package]] +name = "cuda-core" +version = "0.3.2" +description = "cuda.core: (experimental) pythonic CUDA module" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cuda_core-0.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a2a1f7e96e68c0bbc710592e78ca09c951afc10238c739482e265da1e6ea102"}, + {file = "cuda_core-0.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1058402b41320516d5022a1cdfc7063909bf620e91126f851d859302b77d02d1"}, + {file = "cuda_core-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e843a3058fc74640e5d629e87d864ad3f7e763bc89d6c2b83b55a829603ee5a3"}, + {file = "cuda_core-0.3.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffd99410f648d3bcd26f464da70d2b5ef9b5eaab79b744960d3dd66780dd1ac1"}, + {file = "cuda_core-0.3.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d339c874905e00ddc36556d56cf7eaa9dae62d4bc4f2db774f15a9b41ca634a"}, + {file = "cuda_core-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:c8c438b2e3c08ba0f3f36a9067e2092f5dfb8e40084206fc2722a7a26745fa70"}, + {file = "cuda_core-0.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d5e635d60209478d7fcb26d96e9182e6f7407c983147f488b98130c1ba31df12"}, + {file = "cuda_core-0.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1338ab324d29b3afcde623c4a12571cd6e74e76fa0d5533db1e36df978899e4e"}, + {file = "cuda_core-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:b4afafbc3809244dfe764898c8a49abaccb1cc4cd41bbb9a61e89c31dd1f2a18"}, + {file = "cuda_core-0.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:89017fa01d65f355155e85e40362f10a16224650743a929bc447090236733e5c"}, + {file = "cuda_core-0.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5c048a9d788028d2a268101001d40210812d6dcf178e6869f49e855606ed2605"}, + {file = "cuda_core-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:2fcd38ceb9934e58b830b9aa4c30db7a22d65d328155454f5801eda45ac10f42"}, + {file = "cuda_core-0.3.2-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad4e8a3b05525e877e0b3e5d626bdbc05b68c0b5d7da843d8c0366ab2bc3421f"}, + {file = "cuda_core-0.3.2-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e6ba1ff9721825992a03191a50140a89468763fe0a7055397b731622dca4a50"}, + {file = "cuda_core-0.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:6106c159bfebce4c05ad4b1dbb6006e52ceea1c60f642df270e559e714a19962"}, +] + +[package.dependencies] +numpy = "*" + +[package.extras] +cu11 = ["cuda-bindings[all] (==11.8.*)"] +cu12 = ["cuda-bindings[all] (==12.*)"] +cu13 = ["cuda-bindings[all] (==13.*)"] +test = ["cython (>=3.0)", "pytest (>=6.2.4)", "setuptools"] +test-cu11 = ["cuda-core[test]", "cupy-cuda11x", "nvidia-cuda-runtime-cu11"] +test-cu12 = ["cuda-core[test]", "cupy-cuda12x", "nvidia-cuda-runtime-cu12"] + +[[package]] +name = "cuda-pathfinder" +version = "1.5.2" +description = "Pathfinder for CUDA components" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cuda_pathfinder-1.5.2-py3-none-any.whl", hash = "sha256:0c5f160a7756c5b072723cbbd6d861e38917ef956c68150b02f0b6e9271c71fa"}, +] + +[[package]] +name = "cuda-toolkit" +version = "12.9.1" +description = "CUDA Toolkit meta-package" +optional = false +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cuda_toolkit-12.9.1-py2.py3-none-any.whl", hash = "sha256:0c8636dfacbecfe9867a949a211864f080a805bc54023ce4a361aa4e1fd8738b"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = {version = "==12.9.1.4.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cuda-cccl-cu12 = {version = "==12.9.27.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cuda-cupti-cu12 = {version = "==12.9.79.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cuda-cuxxfilt-cu12 = {version = "==12.9.82.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cuda-nvcc-cu12 = {version = "==12.9.86.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cuda-nvrtc-cu12 = {version = "==12.9.86.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cuda-opencl-cu12 = {version = "==12.9.19.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cuda-profiler-api-cu12 = {version = "==12.9.79.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cuda-runtime-cu12 = {version = "==12.9.79.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cuda-sanitizer-api-cu12 = {version = "==12.9.79.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cufft-cu12 = {version = "==11.4.1.4.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cufile-cu12 = {version = "==1.14.1.1.*", optional = true, markers = "sys_platform == \"linux\" and extra == \"all\""} +nvidia-curand-cu12 = {version = "==10.3.10.19.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cusolver-cu12 = {version = "==11.7.5.82.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-cusparse-cu12 = {version = "==12.5.10.65.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-npp-cu12 = {version = "==12.4.1.87.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-nvfatbin-cu12 = {version = "==12.9.82.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-nvjitlink-cu12 = {version = "==12.9.86.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-nvjpeg-cu12 = {version = "==12.4.0.76.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-nvml-dev-cu12 = {version = "==12.9.79.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} +nvidia-nvtx-cu12 = {version = "==12.9.79.*", optional = true, markers = "(sys_platform == \"win32\" or sys_platform == \"linux\") and extra == \"all\""} + +[package.extras] +all = ["nvidia-cublas-cu12 (==12.9.1.4.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cuda-cccl-cu12 (==12.9.27.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cuda-cupti-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cuda-cuxxfilt-cu12 (==12.9.82.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cuda-nvcc-cu12 (==12.9.86.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cuda-nvrtc-cu12 (==12.9.86.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cuda-opencl-cu12 (==12.9.19.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cuda-profiler-api-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cuda-runtime-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cuda-sanitizer-api-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cufft-cu12 (==11.4.1.4.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cufile-cu12 (==1.14.1.1.*) ; sys_platform == \"linux\"", "nvidia-curand-cu12 (==10.3.10.19.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cusolver-cu12 (==11.7.5.82.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-cusparse-cu12 (==12.5.10.65.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-npp-cu12 (==12.4.1.87.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-nvfatbin-cu12 (==12.9.82.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-nvjitlink-cu12 (==12.9.86.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-nvjpeg-cu12 (==12.4.0.76.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-nvml-dev-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\"", "nvidia-nvtx-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +cccl = ["nvidia-cuda-cccl-cu12 (==12.9.27.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +cublas = ["nvidia-cublas-cu12 (==12.9.1.4.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +cudart = ["nvidia-cuda-runtime-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +cufft = ["nvidia-cufft-cu12 (==11.4.1.4.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +cufile = ["nvidia-cufile-cu12 (==1.14.1.1.*) ; sys_platform == \"linux\""] +cupti = ["nvidia-cuda-cupti-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +curand = ["nvidia-curand-cu12 (==10.3.10.19.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +cusolver = ["nvidia-cusolver-cu12 (==11.7.5.82.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +cusparse = ["nvidia-cusparse-cu12 (==12.5.10.65.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +cuxxfilt = ["nvidia-cuda-cuxxfilt-cu12 (==12.9.82.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +npp = ["nvidia-npp-cu12 (==12.4.1.87.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +nvcc = ["nvidia-cuda-nvcc-cu12 (==12.9.86.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +nvfatbin = ["nvidia-nvfatbin-cu12 (==12.9.82.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +nvjitlink = ["nvidia-nvjitlink-cu12 (==12.9.86.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +nvjpeg = ["nvidia-nvjpeg-cu12 (==12.4.0.76.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +nvml = ["nvidia-nvml-dev-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +nvrtc = ["nvidia-cuda-nvrtc-cu12 (==12.9.86.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +nvtx = ["nvidia-nvtx-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +opencl = ["nvidia-cuda-opencl-cu12 (==12.9.19.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +profiler = ["nvidia-cuda-profiler-api-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] +sanitizer = ["nvidia-cuda-sanitizer-api-cu12 (==12.9.79.*) ; sys_platform == \"win32\" or sys_platform == \"linux\""] + +[[package]] +name = "cudensitymat-cu12" +version = "0.3.2" +description = "cuDensityMat - a component of NVIDIA cuQuantum SDK" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cudensitymat_cu12-0.3.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0f04e3006c73848a6e955ac7be697b2e65fd9cfc2b27b0e05d53a61968dc2dc3"}, + {file = "cudensitymat_cu12-0.3.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:dfe85b4f0bef34c087f7625995b11d370c135e7a3bf64e7d09ee2fd41f2aa237"}, +] + +[package.dependencies] +cutensor-cu12 = ">=2.3.1,<3" +cutensornet-cu12 = ">=2.9.1,<3" + +[[package]] +name = "cupauliprop-cu12" +version = "0.1.0" +description = "cuPauliProp - a component of NVIDIA cuQuantum SDK" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cupauliprop_cu12-0.1.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9090cb0302c588628e990be7532f8a199e1b75d5225768bcdf2d659264217fde"}, + {file = "cupauliprop_cu12-0.1.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:874e5a0d0e0d238bf2c2c511d61c590fe47d889e01963b5e6439a213a0a05bb4"}, +] + +[[package]] +name = "cupy-cuda12x" +version = "13.6.0" +description = "CuPy: NumPy & SciPy for GPU" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cupy_cuda12x-13.6.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:9e37f60f27ff9625dfdccc4688a09852707ec613e32ea9404f425dd22a386d14"}, + {file = "cupy_cuda12x-13.6.0-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:e78409ea72f5ac7d6b6f3d33d99426a94005254fa57e10617f430f9fd7c3a0a1"}, + {file = "cupy_cuda12x-13.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:f33c9c975782ef7a42c79b6b4fb3d5b043498f9b947126d792592372b432d393"}, + {file = "cupy_cuda12x-13.6.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:c790d012fd4d86872b9c89af9f5f15d91c30b8e3a4aa4dd04c2610f45f06ac44"}, + {file = "cupy_cuda12x-13.6.0-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:77ba6745a130d880c962e687e4e146ebbb9014f290b0a80dbc4e4634eb5c3b48"}, + {file = "cupy_cuda12x-13.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:a20b7acdc583643a623c8d8e3efbe0db616fbcf5916e9c99eedf73859b6133af"}, + {file = "cupy_cuda12x-13.6.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:a6970ceefe40f9acbede41d7fe17416bd277b1bd2093adcde457b23b578c5a59"}, + {file = "cupy_cuda12x-13.6.0-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:79b0cacb5e8b190ef409f9e03f06ac8de1b021b0c0dda47674d446f5557e0eb1"}, + {file = "cupy_cuda12x-13.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca06fede7b8b83ca9ad80062544ef2e5bb8d4762d1c4fc3ac8349376de9c8a5e"}, + {file = "cupy_cuda12x-13.6.0-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e5426ae3b1b9cf59927481e457a89e3f0b50a35b114a8034ec9110e7a833434c"}, + {file = "cupy_cuda12x-13.6.0-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:52d9e7f83d920da7d81ec2e791c2c2c747fdaa1d7b811971b34865ce6371e98a"}, + {file = "cupy_cuda12x-13.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:297b4268f839de67ef7865c2202d3f5a0fb8d20bd43360bc51b6e60cb4406447"}, + {file = "cupy_cuda12x-13.6.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:6ccd2fc75b0e0e24493531b8f8d8f978efecddb45f8479a48890c40d3805eb87"}, + {file = "cupy_cuda12x-13.6.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:771f3135861b68199c18b49345210180d4fcdce4681b51c28224db389c4aac5d"}, + {file = "cupy_cuda12x-13.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:4d2dfd9bb4705d446f542739a3616b4c9eea98d674fce247402cc9bcec89a1e4"}, +] + +[package.dependencies] +fastrlock = ">=0.5" +numpy = ">=1.22,<2.6" + +[package.extras] +all = ["Cython (>=3)", "optuna (>=2.0)", "scipy (>=1.7,<1.17)"] +test = ["hypothesis (>=6.37.2,<6.55.0)", "mpmath", "packaging", "pytest (>=7.2)"] + +[[package]] +name = "cuquantum-python-cu12" +version = "25.11.1" +description = "NVIDIA cuQuantum Python" +optional = true +python-versions = ">=3.11" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cuquantum_python_cu12-25.11.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:cd429691283507b2f4b078d96a97d1cde8bccdbab51c3acc1911845ec1bc97fd"}, + {file = "cuquantum_python_cu12-25.11.1-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:543b93a80f5526fc043a50d455c83f984d477d9d6ce2426a576a2b086030bb25"}, + {file = "cuquantum_python_cu12-25.11.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:637d08b5ab724c70d6b4a2a70fba80d76b516e3b36dd1f0b4cd87d3b631cfb6a"}, + {file = "cuquantum_python_cu12-25.11.1-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:1bf8f2e827c473ab4780a1743895d807101b0a2cb1c1aa639e91baaa785f1864"}, + {file = "cuquantum_python_cu12-25.11.1-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:56d41f1ad2eb3d1ea6d4db2ba85dde430c037d3629b396a19f1c12ebd17f4efb"}, + {file = "cuquantum_python_cu12-25.11.1-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:3701ed37ebab6c8bc09fefd34cac59ebc2d9d18f2c73cff5b48febdb4e3debbb"}, +] + +[package.dependencies] +cuda-bindings = ">=12.9.2,<13.0.0" +cudensitymat-cu12 = ">=0.3.2,<0.4" +cupauliprop-cu12 = ">=0.1.0,<0.2" +cupy-cuda12x = ">=13.0" +custabilizer-cu12 = ">=0.1.0,<0.2" +custatevec-cu12 = ">=1.11,<2.0" +cutensornet-cu12 = ">=2.10.1,<3" +numpy = ">=1.21,<3.0" +nvmath-python = "0.6.0" + +[package.extras] +jax = ["cuquantum-python-jax"] +test = ["cffi (>=1.0.0)", "cirq-core", "jsonschema (==4.17.3)", "mpi4py", "nbconvert", "nbformat", "networkx", "opt_einsum", "pylatexenc", "pytest (>=6.2)", "pytest-xdist", "qiskit (>=1.4.2,<3)", "qiskit-aer", "stim (==1.15.0)"] + +[[package]] +name = "custabilizer-cu12" +version = "0.1.0" +description = "cuStabilizer - a component of NVIDIA cuQuantum SDK" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "custabilizer_cu12-0.1.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:a64d754c8290427f93a22109af32f834c9b99e93afae711cb604eab47d8980bb"}, + {file = "custabilizer_cu12-0.1.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:af4b056604ce6186445732040d36fcd6568b4554a561e665dd0c619f8d811204"}, +] + +[[package]] +name = "custatevec-cu12" +version = "1.13.0" +description = "cuStateVec - a component of NVIDIA cuQuantum SDK" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "custatevec_cu12-1.13.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:ed1ba8b9d23242f91fc6cef8b4e6487b007d6061251479a1bf87e3dbcb3db0be"}, + {file = "custatevec_cu12-1.13.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:0019b0e945247d62dcf5829be89dd90e584bcd59b9a7c85d54e3f9e4acf8fd96"}, +] + +[[package]] +name = "cutensor-cu12" +version = "2.6.0" +description = "NVIDIA cuTENSOR" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cutensor_cu12-2.6.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:99c3f29b4061d097371786cb00d4ca127a731b7568a962d1e069ce11baa8d344"}, + {file = "cutensor_cu12-2.6.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c0baefa562c60e39989c5aed3e3f2d2e655d396b2e4788f6fe1b5410e20fef70"}, + {file = "cutensor_cu12-2.6.0-py3-none-win_amd64.whl", hash = "sha256:a3a0930362cb4b3ff784163e956b1a557535a2cd6d3f1a1612ad427a988f46e3"}, +] + +[[package]] +name = "cutensornet-cu12" +version = "2.12.0" +description = "cuTensorNet - a component of NVIDIA cuQuantum SDK" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "cutensornet_cu12-2.12.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4d363a2d746461cebe00da86c84401f59699b55c2a8f45f893a9cab930d1b5e6"}, + {file = "cutensornet_cu12-2.12.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:14c8a91d3918aee6f6219b3b2cf85077c6c443d1e3f38af6a57712098b301f37"}, +] + +[package.dependencies] +cutensor-cu12 = ">=2.5,<3" + +[[package]] +name = "cycler" +version = "0.12.1" +description = "Composable style cycles" +optional = true +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + +[[package]] +name = "cytoolz" +version = "1.1.0" +description = "Cython implementation of Toolz: High performance functional utilities" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "cytoolz-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:72d7043a88ea5e61ba9d17ea0d1c1eff10f645d7edfcc4e56a31ef78be287644"}, + {file = "cytoolz-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d759e9ed421bacfeb456d47af8d734c057b9912b5f2441f95b27ca35e5efab07"}, + {file = "cytoolz-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fdb5be8fbcc0396141189022724155a4c1c93712ac4aef8c03829af0c2a816d7"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c8c0a513dc89bc05cc72893609118815bced5ef201f1a317b4cc3423b3a0e750"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce94db4f8ebe842c30c0ece42ff5de977c47859088c2c363dede5a68f6906484"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b622d4f54e370c853ded94a668f94fe72c6d70e06ac102f17a2746661c27ab52"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:375a65baa5a5b4ff6a0c5ff17e170cf23312e4c710755771ca966144c24216b5"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c0d51bcdb3203a062a78f66bbe33db5e3123048e24a5f0e1402422d79df8ee2d"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1010869529bb05dc9802b6d776a34ca1b6d48b9deec70ad5e2918ae175be5c2f"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:11a8f2e83295bdb33f35454d6bafcb7845b03b5881dcaed66ecbd726c7f16772"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0499c5e0a8e688ed367a2e51cc13792ae8f08226c15f7d168589fc44b9b9cada"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:87d44e6033d4c5e95a7d39ba59b8e105ba1c29b1ccd1d215f26477cc1d64be39"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a68cef396a7de237f7b97422a6a450dfb111722296ba217ba5b34551832f1f6e"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:06ad4c95b258141f138a93ebfdc1d76ac087afc1a82f1401100a1f44b44ba656"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ada59a4b3c59d4ac7162e0ed08667ffa78abf48e975c8a9f9d5b9bc50720f4fd"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a8957bcaea1ba01327a9b219d2adb84144377684f51444253890dab500ca171f"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6d8cdc299d67eb0f3b9ecdafeeb55eb3b7b7470e2d950ac34b05ed4c7a5572b8"}, + {file = "cytoolz-1.1.0-cp310-cp310-win32.whl", hash = "sha256:d8e08464c5cdea4f6df31e84b11ed6bfd79cedb99fbcbfdc15eb9361a6053c5a"}, + {file = "cytoolz-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:7e49922a7ed54262d41960bf3b835a7700327bf79cff1e9bfc73d79021132ff8"}, + {file = "cytoolz-1.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:943a662d2e72ffc4438d43ab5a1de8d852237775a423236594a3b3e381b8032c"}, + {file = "cytoolz-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dba8e5a8c6e3c789d27b0eb5e7ce5ed7d032a7a9aae17ca4ba5147b871f6e327"}, + {file = "cytoolz-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:44b31c05addb0889167a720123b3b497b28dd86f8a0aeaf3ae4ffa11e2c85d55"}, + {file = "cytoolz-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:653cb18c4fc5d8a8cfce2bce650aabcbe82957cd0536827367d10810566d5294"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:853a5b4806915020c890e1ce70cc056bbc1dd8bc44f2d74d555cccfd7aefba7d"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7b44e9de86bea013fe84fd8c399d6016bbb96c37c5290769e5c99460b9c53e5"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:098d628a801dc142e9740126be5624eb7aef1d732bc7a5719f60a2095547b485"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:779ee4096ed7a82cffab89372ffc339631c285079dbf33dbe7aff1f6174985df"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f2ce18dd99533d077e9712f9faa852f389f560351b1efd2f2bdb193a95eddde2"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac266a34437812cf841cecbfe19f355ab9c3dd1ef231afc60415d40ff12a76e4"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1920b9b9c13d60d0bb6cd14594b3bce0870022eccb430618c37156da5f2b7a55"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47caa376dafd2bdc29f8a250acf59c810ec9105cd6f7680b9a9d070aae8490ec"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5ab2c97d8aaa522b038cca9187b1153347af22309e7c998b14750c6fdec7b1cb"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4bce006121b120e8b359244ee140bb0b1093908efc8b739db8dbaa3f8fb42139"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fc0f1e4e9bb384d26e73c6657bbc26abdae4ff66a95933c00f3d578be89181b"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:dd3f894ff972da1994d06ac6157d74e40dda19eb31fe5e9b7863ca4278c3a167"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0846f49cf8a4496bd42659040e68bd0484ce6af819709cae234938e039203ba0"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:16a3af394ade1973226d64bb2f9eb3336adbdea03ed5b134c1bbec5a3b20028e"}, + {file = "cytoolz-1.1.0-cp311-cp311-win32.whl", hash = "sha256:b786c9c8aeab76cc2f76011e986f7321a23a56d985b77d14f155d5e5514ea781"}, + {file = "cytoolz-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:ebf06d1c5344fb22fee71bf664234733e55db72d74988f2ecb7294b05e4db30c"}, + {file = "cytoolz-1.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:b63f5f025fac893393b186e132e3e242de8ee7265d0cd3f5bdd4dda93f6616c9"}, + {file = "cytoolz-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:99f8e134c9be11649342853ec8c90837af4089fc8ff1e8f9a024a57d1fa08514"}, + {file = "cytoolz-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0a6f44cf9319c30feb9a50aa513d777ef51efec16f31c404409e7deb8063df64"}, + {file = "cytoolz-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:945580dc158c557172fca899a35a99a16fbcebf6db0c77cb6621084bc82189f9"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:257905ec050d04f2f856854620d1e25556fd735064cebd81b460f54939b9f9d5"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82779049f352fb3ab5e8c993ab45edbb6e02efb1f17f0b50f4972c706cc51d76"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7d3e405e435320e08c5a1633afaf285a392e2d9cef35c925d91e2a31dfd7a688"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:923df8f5591e0d20543060c29909c149ab1963a7267037b39eee03a83dbc50a8"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:25db9e4862f22ea0ae2e56c8bec9fc9fd756b655ae13e8c7b5625d7ed1c582d4"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7a98deb11ccd8e5d9f9441ef2ff3352aab52226a2b7d04756caaa53cd612363"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dce4ee9fc99104bc77efdea80f32ca5a650cd653bcc8a1d984a931153d3d9b58"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80d6da158f7d20c15819701bbda1c041f0944ede2f564f5c739b1bc80a9ffb8b"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3b5c5a192abda123ad45ef716ec9082b4cf7d95e9ada8291c5c2cc5558be858b"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5b399ce7d967b1cb6280250818b786be652aa8ddffd3c0bb5c48c6220d945ab5"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e7e29a1a03f00b4322196cfe8e2c38da9a6c8d573566052c586df83aacc5663c"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5291b117d71652a817ec164e7011f18e6a51f8a352cc9a70ed5b976c51102fda"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8caef62f846a9011676c51bda9189ae394cdd6bb17f2946ecaedc23243268320"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:de425c5a8e3be7bb3a195e19191d28d9eb3c2038046064a92edc4505033ec9cb"}, + {file = "cytoolz-1.1.0-cp312-cp312-win32.whl", hash = "sha256:296440a870e8d1f2e1d1edf98f60f1532b9d3ab8dfbd4b25ec08cd76311e79e5"}, + {file = "cytoolz-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:07156987f224c6dac59aa18fb8bf91e1412f5463961862716a3381bf429c8699"}, + {file = "cytoolz-1.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:23e616b38f5b3160c7bb45b0f84a8f3deb4bd26b29fb2dfc716f241c738e27b8"}, + {file = "cytoolz-1.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:76c9b58555300be6dde87a41faf1f97966d79b9a678b7a526fcff75d28ef4945"}, + {file = "cytoolz-1.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d1d638b10d3144795655e9395566ce35807df09219fd7cacd9e6acbdef67946a"}, + {file = "cytoolz-1.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:26801c1a165e84786a99e03c9c9973356caaca002d66727b761fb1042878ef06"}, + {file = "cytoolz-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2a9a464542912d3272f6dccc5142df057c71c6a5cbd30439389a732df401afb7"}, + {file = "cytoolz-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ed6104fa942aa5784bf54f339563de637557e3443b105760bc4de8f16a7fc79b"}, + {file = "cytoolz-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56161f0ab60dc4159ec343509abaf809dc88e85c7e420e354442c62e3e7cbb77"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:832bd36cc9123535f1945acf6921f8a2a15acc19cfe4065b1c9b985a28671886"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1842636b6e034f229bf084c2bcdcfd36c8437e752eefd2c74ce9e2f10415cb6e"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:823df012ab90d2f2a0f92fea453528539bf71ac1879e518524cd0c86aa6df7b9"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f1fcf9e7e7b3487883ff3f815abc35b89dcc45c4cf81c72b7ee457aa72d197b"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4cdb3fa1772116827f263f25b0cdd44c663b6701346a56411960534a06c082de"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1b5c95041741b81430454db65183e133976f45ac3c03454cfa8147952568529"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b2079fd9f1a65f4c61e6278c8a6d4f85edf30c606df8d5b32f1add88cbbe2286"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a92a320d72bef1c7e2d4c6d875125cf57fc38be45feb3fac1bfa64ea401f54a4"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06d1c79aa51e6a92a90b0e456ebce2288f03dd6a76c7f582bfaa3eda7692e8a5"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e1d7be25f6971e986a52b6d3a0da28e1941850985417c35528f6823aef2cfec5"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:964b248edc31efc50a65e9eaa0c845718503823439d2fa5f8d2c7e974c2b5409"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c9ff2b3c57c79b65cb5be14a18c6fd4a06d5036fb3f33e973a9f70e9ac13ca28"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:22290b73086af600042d99f5ce52a43d4ad9872c382610413176e19fc1d4fd2d"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a2ade74fccd080ea793382968913ee38d7a35c921df435bbf0a6aeecf0d17574"}, + {file = "cytoolz-1.1.0-cp313-cp313-win32.whl", hash = "sha256:db5dbcfda1c00e937426cbf9bdc63c24ebbc358c3263bfcbc1ab4a88dc52aa8e"}, + {file = "cytoolz-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9e2d3fe3b45c3eb7233746f7aca37789be3dceec3e07dcc406d3e045ea0f7bdc"}, + {file = "cytoolz-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:32c559f95ff44a9ebcbd934acaa1e6dc8f3e6ffce4762a79a88528064873d6d5"}, + {file = "cytoolz-1.1.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9e2cd93b28f667c5870a070ab2b8bb4397470a85c4b204f2454b0ad001cd1ca3"}, + {file = "cytoolz-1.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f494124e141a9361f31d79875fe7ea459a3be2b9dadd90480427c0c52a0943d4"}, + {file = "cytoolz-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53a3262bf221f19437ed544bf8c0e1980c81ac8e2a53d87a9bc075dba943d36f"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:47663e57d3f3f124921f38055e86a1022d0844c444ede2e8f090d3bbf80deb65"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5a8755c4104ee4e3d5ba434c543b5f85fdee6a1f1df33d93f518294da793a60"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4d96ff3d381423af1b105295f97de86d1db51732c9566eb37378bab6670c5010"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0ec96b3d537cdf47d4e76ded199f7440715f4c71029b45445cff92c1248808c2"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:208e2f2ef90a32b0acbff3303d90d89b13570a228d491d2e622a7883a3c68148"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d416a81bb0bd517558668e49d30a7475b5445f9bbafaab7dcf066f1e9adba36"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f32e94c91ffe49af04835ee713ebd8e005c85ebe83e7e1fdcc00f27164c2d636"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15d0c6405efc040499c46df44056a5c382f551a7624a41cf3e4c84a96b988a15"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:bf069c5381d757debae891401b88b3a346ba3a28ca45ba9251103b282463fad8"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d5cf15892e63411ec1bd67deff0e84317d974e6ab2cdfefdd4a7cea2989df66"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3e3872c21170f8341656f8692f8939e8800dcee6549ad2474d4c817bdefd62cd"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b9ddeff8e8fd65eb1fcefa61018100b2b627e759ea6ad275d2e2a93ffac147bf"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:02feeeda93e1fa3b33414eb57c2b0aefd1db8f558dd33fdfcce664a0f86056e4"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d08154ad45349162b6c37f12d5d1b2e6eef338e657b85e1621e4e6a4a69d64cb"}, + {file = "cytoolz-1.1.0-cp313-cp313t-win32.whl", hash = "sha256:10ae4718a056948d73ca3e1bb9ab1f95f897ec1e362f829b9d37cc29ab566c60"}, + {file = "cytoolz-1.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:1bb77bc6197e5cb19784b6a42bb0f8427e81737a630d9d7dda62ed31733f9e6c"}, + {file = "cytoolz-1.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:563dda652c6ff52d215704fbe6b491879b78d7bbbb3a9524ec8e763483cb459f"}, + {file = "cytoolz-1.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d542cee7c7882d2a914a33dec4d3600416fb336734df979473249d4c53d207a1"}, + {file = "cytoolz-1.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:31922849b701b0f24bb62e56eb2488dcd3aa6ae3057694bd6b3b7c4c2bc27c2f"}, + {file = "cytoolz-1.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e68308d32afd31943314735c1335e4ab5696110e96b405f6bdb8f2a8dc771a16"}, + {file = "cytoolz-1.1.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fc4bb48b3b866e1867f7c6411a4229e5b44be3989060663713e10efc24c9bd5f"}, + {file = "cytoolz-1.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:456f77207d1445025d7ef262b8370a05492dcb1490cb428b0f3bf1bd744a89b0"}, + {file = "cytoolz-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:174ebc71ebb20a9baeffce6ee07ee2cd913754325c93f99d767380d8317930f7"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8b3604fef602bcd53415055a4f68468339192fd17be39e687ae24f476d23d56e"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3604b959a01f64c366e7d10ec7634d5f5cfe10301e27a8f090f6eb3b2a628a18"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6db2127a3c1bc2f59f08010d2ae53a760771a9de2f67423ad8d400e9ba4276e8"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56584745ac647993a016a21bc76399113b7595e312f8d0a1b140c9fcf9b58a27"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db2c4c3a7f7bd7e03bb1a236a125c8feb86c75802f4ecda6ecfaf946610b2930"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48cb8a692111a285d2b9acd16d185428176bfbffa8a7c274308525fccd01dd42"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d2f344ba5eb17dcf38ee37fdde726f69053f54927db8f8a1bed6ac61e5b1890d"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:abf76b1c1abd031f098f293b6d90ee08bdaa45f8b5678430e331d991b82684b1"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ddf9a38a5b686091265ff45b53d142e44a538cd6c2e70610d3bc6be094219032"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:946786755274f07bb2be0400f28adb31d7d85a7c7001873c0a8e24a503428fb3"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b8f78b9fed79cf185ad4ddec099abeef45951bdcb416c5835ba05f0a1242c7"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fccde6efefdbc02e676ccb352a2ccc8a8e929f59a1c6d3d60bb78e923a49ca44"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:717b7775313da5f51b0fbf50d865aa9c39cb241bd4cb605df3cf2246d6567397"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5158744a09d0e0e4a4f82225e3a3c4ebf38f9ae74467aaa905467270e52f2794"}, + {file = "cytoolz-1.1.0-cp314-cp314-win32.whl", hash = "sha256:1ed534bdbbf063b2bb28fca7d0f6723a3e5a72b086e7c7fe6d74ae8c3e4d00e2"}, + {file = "cytoolz-1.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:472c1c9a085f5ad973ec0ad7f0b9ba0969faea6f96c9e397f6293d386f3a25ec"}, + {file = "cytoolz-1.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:a7ad7ca3386fa86bd301be3fa36e7f0acb024f412f665937955acfc8eb42deff"}, + {file = "cytoolz-1.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:64b63ed4b71b1ba813300ad0f06b8aff19a12cf51116e0e4f1ed837cea4debcf"}, + {file = "cytoolz-1.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a60ba6f2ed9eb0003a737e1ee1e9fa2258e749da6477946008d4324efa25149f"}, + {file = "cytoolz-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1aa58e2434d732241f7f051e6f17657e969a89971025e24578b5cbc6f1346485"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6965af3fc7214645970e312deb9bd35a213a1eaabcfef4f39115e60bf2f76867"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ddd2863f321d67527d3b67a93000a378ad6f967056f68c06467fe011278a6d0e"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4e6b428e9eb5126053c2ae0efa62512ff4b38ed3951f4d0888ca7005d63e56f5"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d758e5ef311d2671e0ae8c214c52e44617cf1e58bef8f022b547b9802a5a7f30"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a95416eca473e6c1179b48d86adcf528b59c63ce78f4cb9934f2e413afa9b56b"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36c8ede93525cf11e2cc787b7156e5cecd7340193ef800b816a16f1404a8dc6d"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c949755b6d8a649c5fbc888bc30915926f1b09fe42fea9f289e297c2f6ddd3"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e1b6d37545816905a76d9ed59fa4e332f929e879f062a39ea0f6f620405cdc27"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:05332112d4087904842b36954cd1d3fc0e463a2f4a7ef9477bd241427c593c3b"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:31538ca2fad2d688cbd962ccc3f1da847329e2258a52940f10a2ac0719e526be"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:747562aa70abf219ea16f07d50ac0157db856d447f7f498f592e097cbc77df0b"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:3dc15c48b20c0f467e15e341e102896c8422dccf8efc6322def5c1b02f074629"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3c03137ee6103ba92d5d6ad6a510e86fded69cd67050bd8a1843f15283be17ac"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:be8e298d88f88bd172b59912240558be3b7a04959375646e7fd4996401452941"}, + {file = "cytoolz-1.1.0-cp314-cp314t-win32.whl", hash = "sha256:3d407140f5604a89578285d4aac7b18b8eafa055cf776e781aabb89c48738fad"}, + {file = "cytoolz-1.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:56e5afb69eb6e1b3ffc34716ee5f92ffbdb5cb003b3a5ca4d4b0fe700e217162"}, + {file = "cytoolz-1.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:27b19b4a286b3ff52040efa42dbe403730aebe5fdfd2def704eb285e2125c63e"}, + {file = "cytoolz-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:08a63935c66488511b7b29b06233be0be5f4123622fc8fd488f28dc1b7e4c164"}, + {file = "cytoolz-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:93bd0afcc4cc05794507084afaefb161c3639f283ee629bd0e8654b5c0327ba8"}, + {file = "cytoolz-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f3d4da470cfd5cf44f6d682c6eb01363066e0af53ebe111225e44a618f9453d"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ba6c12d0e6a67399f4102b4980f4f1bebdbf226ed0a68e84617709d4009b4e71"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b557071405b4aeeaa7cbec1a95d15d6c8f37622fe3f4b595311e0e226ce772c"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cdb406001474726a47fbe903f3aba0de86f5c0b9c9861f55c09c366368225ae0"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b6072876ba56446d9ac29d349983677d6f44c6d1c6c1c6be44e66e377c57c767"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c3784c965c9a6822d315d099c3a85b0884ac648952815891c667b469116f1d0"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cc537ad78981df1a827773069fd3b7774f4478db43f518b1616efaf87d7d8f9"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:574ee9dfdc632db8bf9237f27f2a687d1a0b90d29d5e96cab2b21fd2b419c17d"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6594efbaea72dc58b368b53e745ad902c8d8cc41286f00b3743ceac464d5ef3f"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7c849f9ddaf3c7faba938440f9c849235a2908b303063d49da3092a93acd695b"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1fef0296fb3577d0a08ad9b70344ee418f728f1ec21a768ffe774437d67ac859"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:1dce1e66fdf72cc474367bd7a7f2b90ec67bb8197dc3fe8ecd08f4ce3ab950a1"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:202fe9975efaec0085cab14a6a6050418bc041f5316f2cf098c0cd2aced4c50e"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:528349434601b9d55e65c6a495494de0001c9a06b431547fea4c60b5edc7d5b3"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3e248cdbf2a54bafdadf4486ddd32e8352f816d3caa2014e44de99f8c525d4a8"}, + {file = "cytoolz-1.1.0-cp39-cp39-win32.whl", hash = "sha256:e63f2b70f4654648a5c6a176ae80897c0de6401f385540dce8e365019e800cfe"}, + {file = "cytoolz-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:f731c53ed29959f105ae622b62e39603c207ed8e8cb2a40cd4accb63d9f92901"}, + {file = "cytoolz-1.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:5a2120bf9e6e8f25e1b32748424a5571e319ef03a995a8fde663fd2feec1a696"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f32e93a55681d782fc6af939f6df36509d65122423cbc930be39b141064adff8"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:5d9bc596751cbda8073e65be02ca11706f00029768fbbbc81e11a8c290bb41aa"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b16660d01c3931951fab49db422c627897c38c1a1f0393a97582004019a4887"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b7de5718e2113d4efccea3f06055758cdbc17388ecc3341ba4d1d812837d7c1a"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a12a2a1a6bc44099491c05a12039efa08cc33a3d0f8c7b0566185e085e139283"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:047defa7f5f9a32f82373dbc3957289562e8a3fa58ae02ec8e4dca4f43a33a21"}, + {file = "cytoolz-1.1.0.tar.gz", hash = "sha256:13a7bf254c3c0d28b12e2290b82aed0f0977a4c2a2bf84854fcdc7796a29f3b0"}, +] + +[package.dependencies] +toolz = ">=0.8.0" + +[package.extras] +cython = ["cython (>=0.29)"] +test = ["pytest"] + +[[package]] +name = "decorator" +version = "5.2.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, + {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, +] + +[[package]] +name = "dill" +version = "0.4.1" +description = "serialize all of Python" +optional = false +python-versions = ">=3.9" +groups = ["main", "analysis"] +files = [ + {file = "dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d"}, + {file = "dill-0.4.1.tar.gz", hash = "sha256:423092df4182177d4d8ba8290c8a5b640c66ab35ec7da59ccfa00f6fa3eea5fa"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + +[[package]] +name = "docutils" +version = "0.17.1" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["docs"] +files = [ + {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, + {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, +] + +[[package]] +name = "executing" +version = "2.2.1" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017"}, + {file = "executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] + +[[package]] +name = "fastrlock" +version = "0.8.3" +description = "Fast, re-entrant optimistic lock implemented in Cython" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "fastrlock-0.8.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bbbe31cb60ec32672969651bf68333680dacaebe1a1ec7952b8f5e6e23a70aa5"}, + {file = "fastrlock-0.8.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:45055702fe9bff719cdc62caa849aa7dbe9e3968306025f639ec62ef03c65e88"}, + {file = "fastrlock-0.8.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac4fcc9b43160f7f64b49bd7ecfd129faf0793c1c8c6f0f56788c3bacae7f54a"}, + {file = "fastrlock-0.8.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d3ebb29de71bf9e330c2769c34a6b5e69d560126f02994e6c09635a2784f6de3"}, + {file = "fastrlock-0.8.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:cc5fa9166e05409f64a804d5b6d01af670979cdb12cd2594f555cb33cdc155bd"}, + {file = "fastrlock-0.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7a77ebb0a24535ef4f167da2c5ee35d9be1e96ae192137e9dc3ff75b8dfc08a5"}, + {file = "fastrlock-0.8.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:d51f7fb0db8dab341b7f03a39a3031678cf4a98b18533b176c533c122bfce47d"}, + {file = "fastrlock-0.8.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:767ec79b7f6ed9b9a00eb9ff62f2a51f56fdb221c5092ab2dadec34a9ccbfc6e"}, + {file = "fastrlock-0.8.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d6a77b3f396f7d41094ef09606f65ae57feeb713f4285e8e417f4021617ca62"}, + {file = "fastrlock-0.8.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:92577ff82ef4a94c5667d6d2841f017820932bc59f31ffd83e4a2c56c1738f90"}, + {file = "fastrlock-0.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3df8514086e16bb7c66169156a8066dc152f3be892c7817e85bf09a27fa2ada2"}, + {file = "fastrlock-0.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:001fd86bcac78c79658bac496e8a17472d64d558cd2227fdc768aa77f877fe40"}, + {file = "fastrlock-0.8.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:f68c551cf8a34b6460a3a0eba44bd7897ebfc820854e19970c52a76bf064a59f"}, + {file = "fastrlock-0.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:55d42f6286b9d867370af4c27bc70d04ce2d342fe450c4a4fcce14440514e695"}, + {file = "fastrlock-0.8.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:bbc3bf96dcbd68392366c477f78c9d5c47e5d9290cb115feea19f20a43ef6d05"}, + {file = "fastrlock-0.8.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:77ab8a98417a1f467dafcd2226718f7ca0cf18d4b64732f838b8c2b3e4b55cb5"}, + {file = "fastrlock-0.8.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:04bb5eef8f460d13b8c0084ea5a9d3aab2c0573991c880c0a34a56bb14951d30"}, + {file = "fastrlock-0.8.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c9d459ce344c21ff03268212a1845aa37feab634d242131bc16c2a2355d5f65"}, + {file = "fastrlock-0.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33e6fa4af4f3af3e9c747ec72d1eadc0b7ba2035456c2afb51c24d9e8a56f8fd"}, + {file = "fastrlock-0.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:5e5f1665d8e70f4c5b4a67f2db202f354abc80a321ce5a26ac1493f055e3ae2c"}, + {file = "fastrlock-0.8.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:8cb2cf04352ea8575d496f31b3b88c42c7976e8e58cdd7d1550dfba80ca039da"}, + {file = "fastrlock-0.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:85a49a1f1e020097d087e1963e42cea6f307897d5ebe2cb6daf4af47ffdd3eed"}, + {file = "fastrlock-0.8.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5f13ec08f1adb1aa916c384b05ecb7dbebb8df9ea81abd045f60941c6283a670"}, + {file = "fastrlock-0.8.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0ea4e53a04980d646def0f5e4b5e8bd8c7884288464acab0b37ca0c65c482bfe"}, + {file = "fastrlock-0.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:38340f6635bd4ee2a4fb02a3a725759fe921f2ca846cb9ca44531ba739cc17b4"}, + {file = "fastrlock-0.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:da06d43e1625e2ffddd303edcd6d2cd068e1c486f5fd0102b3f079c44eb13e2c"}, + {file = "fastrlock-0.8.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:5264088185ca8e6bc83181dff521eee94d078c269c7d557cc8d9ed5952b7be45"}, + {file = "fastrlock-0.8.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a98ba46b3e14927550c4baa36b752d0d2f7387b8534864a8767f83cce75c160"}, + {file = "fastrlock-0.8.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dbdea6deeccea1917c6017d353987231c4e46c93d5338ca3e66d6cd88fbce259"}, + {file = "fastrlock-0.8.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c6e5bfecbc0d72ff07e43fed81671747914d6794e0926700677ed26d894d4f4f"}, + {file = "fastrlock-0.8.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:2a83d558470c520ed21462d304e77a12639859b205759221c8144dd2896b958a"}, + {file = "fastrlock-0.8.3-cp313-cp313-win_amd64.whl", hash = "sha256:8d1d6a28291b4ace2a66bd7b49a9ed9c762467617febdd9ab356b867ed901af8"}, + {file = "fastrlock-0.8.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a0eadc772353cfa464b34c814b2a97c4f3c0ba0ed7b8e1c2e0ad3ebba84bf8e0"}, + {file = "fastrlock-0.8.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:350f517a7d22d383f8ef76652b0609dc79de6693880a99bafc8a05c100e8c5e7"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:924abbf21eba69c1b35c04278f3ca081e8de1ef5933355756e86e05499123238"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fd6727c1e0952ba93fdc5975753781039772be6c1a3911a3afc87b53460dc0"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9c2c24856d2adc60ab398780f7b7cd8a091e4bd0c0e3bb3e67f12bef2800f377"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f2b84b2fe858e64946e54e0e918b8a0e77fc7b09ca960ae1e50a130e8fbc9af8"}, + {file = "fastrlock-0.8.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:963123bafc41c9fba72e57145917a3f23086b5d631b6cda9cf858c428a606ff9"}, + {file = "fastrlock-0.8.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:314e787532ce555a7362d3c438f0a680cd88a82c69b655e7181a4dd5e67712f5"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:494fc374afd0b6c7281c87f2ded9607c2731fc0057ec63bd3ba4451e7b7cb642"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:da53350b90a67d5431df726816b041f1f96fd558ad6e2fc64948e13be3c7c29a"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cdee8c02c20a0b17dbc52f54c48ede3bd421985e5d9cef5cd2136b14da967996"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:558b538221e9c5502bb8725a1f51157ec38467a20498212838e385807e4d1b89"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6ac082d670e195ad53ec8d0c5d2e87648f8838b0d48f7d44a6e696b8a9528e2"}, + {file = "fastrlock-0.8.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d7edaf0071a6a98340fc2ec45b0ba37b7a16ed7761479aab577e41e09b3565e1"}, + {file = "fastrlock-0.8.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9c4068f21fddc47393a3526ce95b180a2f4e1ac286db8d9e59e56771da50c815"}, + {file = "fastrlock-0.8.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d7f359bb989c01a5875e8dbde9acab37b9da0943b60ef97ba9887c4598eb3009"}, + {file = "fastrlock-0.8.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:239e85cbebda16f14be92468ce648d0bc25e2442a3d11818deca59a7c43a4416"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:5eef1d32d7614e0ceb6db198cf53df2a5830685cccbcf141a3e116faca967384"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:80876d9e04e8e35abbdb3e1a81a56558f4d5cf90c8592e428d4d12efce048347"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24522689f4b5311afad0c8f998daec84a3dbe3a70cf821a615a763f843903030"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:de8c90c1a23fbe929d8a9628a6c1f0f1d8af6019e786354a682a26fa22ea21be"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e0ceefadde046a5f6a261bfeaf25de9e0eba3ee790a9795b1fa9634111d3220e"}, + {file = "fastrlock-0.8.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1dd7f1520f7424793c812e1a4090570f8ff312725dbaf10a925b688aef7425f1"}, + {file = "fastrlock-0.8.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:15e13a8b01a3bbf25f1615a6ac1d6ed40ad3bcb8db134ee5ffa7360214a8bc5c"}, + {file = "fastrlock-0.8.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcb50e195ec981c92d0211a201704aecbd9e4f9451aea3a6f71ac5b1ec2c98cf"}, + {file = "fastrlock-0.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:3e77a3d0ca5b29695d86b7d03ea88029c0ed8905cfee658eb36052df3861855a"}, + {file = "fastrlock-0.8.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:668fad1c8322badbc8543673892f80ee563f3da9113e60e256ae9ddd5b23daa4"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:40b328369005a0b32de14b699192aed32f549c2d2b27a5e1f614fb7ac4cec4e9"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:6cbfb6f7731b5a280851c93883624424068fa5b22c2f546d8ae6f1fd9311e36d"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1fced4cb0b3f1616be68092b70a56e9173713a4a943d02e90eb9c7897a7b5e07"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:387b2ac642938a20170a50f528817026c561882ea33306c5cbe750ae10d0a7c2"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a0d31840a28d66573047d2df410eb971135a2461fb952894bf51c9533cbfea5"}, + {file = "fastrlock-0.8.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0a9dc6fa73174f974dfb22778d05a44445b611a41d5d3776b0d5daa9e50225c6"}, + {file = "fastrlock-0.8.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9842b7722e4923fe76b08d8c58a9415a9a50d4c29b80673cffeae4874ea6626a"}, + {file = "fastrlock-0.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:05029d7080c0c61a81d5fee78e842c9a1bf22552cd56129451a252655290dcef"}, + {file = "fastrlock-0.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:accd897ab2799024bb87b489c0f087d6000b89af1f184a66e996d3d96a025a3b"}, + {file = "fastrlock-0.8.3.tar.gz", hash = "sha256:4af6734d92eaa3ab4373e6c9a1dd0d5ad1304e172b1521733c6c3b3d73c8fa5d"}, +] + +[[package]] +name = "fonttools" +version = "4.62.1" +description = "Tools to manipulate font files" +optional = true +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "fonttools-4.62.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ad5cca75776cd453b1b035b530e943334957ae152a36a88a320e779d61fc980c"}, + {file = "fonttools-4.62.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b3ae47e8636156a9accff64c02c0924cbebad62854c4a6dbdc110cd5b4b341a"}, + {file = "fonttools-4.62.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b9e288b4da2f64fd6180644221749de651703e8d0c16bd4b719533a3a7d6e3"}, + {file = "fonttools-4.62.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7bca7a1c1faf235ffe25d4f2e555246b4750220b38de8261d94ebc5ce8a23c23"}, + {file = "fonttools-4.62.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4e0fcf265ad26e487c56cb12a42dffe7162de708762db951e1b3f755319507d"}, + {file = "fonttools-4.62.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2d850f66830a27b0d498ee05adb13a3781637b1826982cd7e2b3789ef0cc71ae"}, + {file = "fonttools-4.62.1-cp310-cp310-win32.whl", hash = "sha256:486f32c8047ccd05652aba17e4a8819a3a9d78570eb8a0e3b4503142947880ed"}, + {file = "fonttools-4.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:5a648bde915fba9da05ae98856987ca91ba832949a9e2888b48c47ef8b96c5a9"}, + {file = "fonttools-4.62.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40975849bac44fb0b9253d77420c6d8b523ac4dcdcefeff6e4d706838a5b80f7"}, + {file = "fonttools-4.62.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9dde91633f77fa576879a0c76b1d89de373cae751a98ddf0109d54e173b40f14"}, + {file = "fonttools-4.62.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6acb4109f8bee00fec985c8c7afb02299e35e9c94b57287f3ea542f28bd0b0a7"}, + {file = "fonttools-4.62.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1c5c25671ce8805e0d080e2ffdeca7f1e86778c5cbfbeae86d7f866d8830517b"}, + {file = "fonttools-4.62.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a5d8825e1140f04e6c99bb7d37a9e31c172f3bc208afbe02175339e699c710e1"}, + {file = "fonttools-4.62.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:268abb1cb221e66c014acc234e872b7870d8b5d4657a83a8f4205094c32d2416"}, + {file = "fonttools-4.62.1-cp311-cp311-win32.whl", hash = "sha256:942b03094d7edbb99bdf1ae7e9090898cad7bf9030b3d21f33d7072dbcb51a53"}, + {file = "fonttools-4.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:e8514f4924375f77084e81467e63238b095abda5107620f49421c368a6017ed2"}, + {file = "fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974"}, + {file = "fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9"}, + {file = "fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936"}, + {file = "fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392"}, + {file = "fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04"}, + {file = "fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d"}, + {file = "fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c"}, + {file = "fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42"}, + {file = "fonttools-4.62.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c22b1014017111c401469e3acc5433e6acf6ebcc6aa9efb538a533c800971c79"}, + {file = "fonttools-4.62.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68959f5fc58ed4599b44aad161c2837477d7f35f5f79402d97439974faebfebe"}, + {file = "fonttools-4.62.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef46db46c9447103b8f3ff91e8ba009d5fe181b1920a83757a5762551e32bb68"}, + {file = "fonttools-4.62.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6706d1cb1d5e6251a97ad3c1b9347505c5615c112e66047abbef0f8545fa30d1"}, + {file = "fonttools-4.62.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2e7abd2b1e11736f58c1de27819e1955a53267c21732e78243fa2fa2e5c1e069"}, + {file = "fonttools-4.62.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:403d28ce06ebfc547fbcb0cb8b7f7cc2f7a2d3e1a67ba9a34b14632df9e080f9"}, + {file = "fonttools-4.62.1-cp313-cp313-win32.whl", hash = "sha256:93c316e0f5301b2adbe6a5f658634307c096fd5aae60a5b3412e4f3e1728ab24"}, + {file = "fonttools-4.62.1-cp313-cp313-win_amd64.whl", hash = "sha256:7aa21ff53e28a9c2157acbc44e5b401149d3c9178107130e82d74ceb500e5056"}, + {file = "fonttools-4.62.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fa1d16210b6b10a826d71bed68dd9ec24a9e218d5a5e2797f37c573e7ec215ca"}, + {file = "fonttools-4.62.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:aa69d10ed420d8121118e628ad47d86e4caa79ba37f968597b958f6cceab7eca"}, + {file = "fonttools-4.62.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd13b7999d59c5eb1c2b442eb2d0c427cb517a0b7a1f5798fc5c9e003f5ff782"}, + {file = "fonttools-4.62.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8d337fdd49a79b0d51c4da87bc38169d21c3abbf0c1aa9367eff5c6656fb6dae"}, + {file = "fonttools-4.62.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d241cdc4a67b5431c6d7f115fdf63335222414995e3a1df1a41e1182acd4bcc7"}, + {file = "fonttools-4.62.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c05557a78f8fa514da0f869556eeda40887a8abc77c76ee3f74cf241778afd5a"}, + {file = "fonttools-4.62.1-cp314-cp314-win32.whl", hash = "sha256:49a445d2f544ce4a69338694cad575ba97b9a75fff02720da0882d1a73f12800"}, + {file = "fonttools-4.62.1-cp314-cp314-win_amd64.whl", hash = "sha256:1eecc128c86c552fb963fe846ca4e011b1be053728f798185a1687502f6d398e"}, + {file = "fonttools-4.62.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1596aeaddf7f78e21e68293c011316a25267b3effdaccaf4d59bc9159d681b82"}, + {file = "fonttools-4.62.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8f8fca95d3bb3208f59626a4b0ea6e526ee51f5a8ad5d91821c165903e8d9260"}, + {file = "fonttools-4.62.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee91628c08e76f77b533d65feb3fbe6d9dad699f95be51cf0d022db94089cdc4"}, + {file = "fonttools-4.62.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f37df1cac61d906e7b836abe356bc2f34c99d4477467755c216b72aa3dc748b"}, + {file = "fonttools-4.62.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:92bb00a947e666169c99b43753c4305fc95a890a60ef3aeb2a6963e07902cc87"}, + {file = "fonttools-4.62.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bdfe592802ef939a0e33106ea4a318eeb17822c7ee168c290273cbd5fabd746c"}, + {file = "fonttools-4.62.1-cp314-cp314t-win32.whl", hash = "sha256:b820fcb92d4655513d8402d5b219f94481c4443d825b4372c75a2072aa4b357a"}, + {file = "fonttools-4.62.1-cp314-cp314t-win_amd64.whl", hash = "sha256:59b372b4f0e113d3746b88985f1c796e7bf830dd54b28374cd85c2b8acd7583e"}, + {file = "fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd"}, + {file = "fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d"}, +] + +[package.extras] +all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.45.0)", "unicodedata2 (>=17.0.0) ; python_version <= \"3.14\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""] +lxml = ["lxml (>=4.0)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.45.0)"] +symfont = ["sympy"] +type1 = ["xattr ; sys_platform == \"darwin\""] +unicode = ["unicodedata2 (>=17.0.0) ; python_version <= \"3.14\""] +woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"] + +[[package]] +name = "furo" +version = "2023.3.27" +description = "A clean customisable Sphinx documentation theme." +optional = false +python-versions = ">=3.7" +groups = ["docs"] +files = [ + {file = "furo-2023.3.27-py3-none-any.whl", hash = "sha256:4ab2be254a2d5e52792d0ca793a12c35582dd09897228a6dd47885dabd5c9521"}, + {file = "furo-2023.3.27.tar.gz", hash = "sha256:b99e7867a5cc833b2b34d7230631dd6558c7a29f93071fdbb5709634bb33c5a5"}, +] + +[package.dependencies] +beautifulsoup4 = "*" +pygments = ">=2.7" +sphinx = ">=5.0,<7.0" +sphinx-basic-ng = "*" + +[[package]] +name = "greenlet" +version = "3.3.2" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\"" +files = [ + {file = "greenlet-3.3.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d"}, + {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13"}, + {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e"}, + {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508c7f01f1791fbc8e011bd508f6794cb95397fdb198a46cb6635eb5b78d85a7"}, + {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f"}, + {file = "greenlet-3.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef"}, + {file = "greenlet-3.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca"}, + {file = "greenlet-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:5d0e35379f93a6d0222de929a25ab47b5eb35b5ef4721c2b9cbcc4036129ff1f"}, + {file = "greenlet-3.3.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:c56692189a7d1c7606cb794be0a8381470d95c57ce5be03fb3d0ef57c7853b86"}, + {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ebd458fa8285960f382841da585e02201b53a5ec2bac6b156fc623b5ce4499f"}, + {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a443358b33c4ec7b05b79a7c8b466f5d275025e750298be7340f8fc63dff2a55"}, + {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4375a58e49522698d3e70cc0b801c19433021b5c37686f7ce9c65b0d5c8677d2"}, + {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e2cd90d413acbf5e77ae41e5d3c9b3ac1d011a756d7284d7f3f2b806bbd6358"}, + {file = "greenlet-3.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:442b6057453c8cb29b4fb36a2ac689382fc71112273726e2423f7f17dc73bf99"}, + {file = "greenlet-3.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45abe8eb6339518180d5a7fa47fa01945414d7cca5ecb745346fc6a87d2750be"}, + {file = "greenlet-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e692b2dae4cc7077cbb11b47d258533b48c8fde69a33d0d8a82e2fe8d8531d5"}, + {file = "greenlet-3.3.2-cp311-cp311-win_arm64.whl", hash = "sha256:02b0a8682aecd4d3c6c18edf52bc8e51eacdd75c8eac52a790a210b06aa295fd"}, + {file = "greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd"}, + {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd"}, + {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac"}, + {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9e21c84035c490506c17002f5c8ab25f980205c3e61ddb3a2a2a2e6c411fcb"}, + {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070"}, + {file = "greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79"}, + {file = "greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395"}, + {file = "greenlet-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:34308836d8370bddadb41f5a7ce96879b72e2fdfb4e87729330c6ab52376409f"}, + {file = "greenlet-3.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:d3a62fa76a32b462a97198e4c9e99afb9ab375115e74e9a83ce180e7a496f643"}, + {file = "greenlet-3.3.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4"}, + {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986"}, + {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92"}, + {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccd21bb86944ca9be6d967cf7691e658e43417782bce90b5d2faeda0ff78a7dd"}, + {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab"}, + {file = "greenlet-3.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a"}, + {file = "greenlet-3.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b"}, + {file = "greenlet-3.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:a7945dd0eab63ded0a48e4dcade82939783c172290a7903ebde9e184333ca124"}, + {file = "greenlet-3.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:394ead29063ee3515b4e775216cb756b2e3b4a7e55ae8fd884f17fa579e6b327"}, + {file = "greenlet-3.3.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab"}, + {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082"}, + {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9"}, + {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e3cb43ce200f59483eb82949bf1835a99cf43d7571e900d7c8d5c62cdf25d2f9"}, + {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63d10328839d1973e5ba35e98cccbca71b232b14051fd957b6f8b6e8e80d0506"}, + {file = "greenlet-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e4ab3cfb02993c8cc248ea73d7dae6cec0253e9afa311c9b37e603ca9fad2ce"}, + {file = "greenlet-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94ad81f0fd3c0c0681a018a976e5c2bd2ca2d9d94895f23e7bb1af4e8af4e2d5"}, + {file = "greenlet-3.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:8c4dd0f3997cf2512f7601563cc90dfb8957c0cff1e3a1b23991d4ea1776c492"}, + {file = "greenlet-3.3.2-cp314-cp314-win_arm64.whl", hash = "sha256:cd6f9e2bbd46321ba3bbb4c8a15794d32960e3b0ae2cc4d49a1a53d314805d71"}, + {file = "greenlet-3.3.2-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:e26e72bec7ab387ac80caa7496e0f908ff954f31065b0ffc1f8ecb1338b11b54"}, + {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b466dff7a4ffda6ca975979bab80bdadde979e29fc947ac3be4451428d8b0e4"}, + {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8bddc5b73c9720bea487b3bffdb1840fe4e3656fba3bd40aa1489e9f37877ff"}, + {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:59b3e2c40f6706b05a9cd299c836c6aa2378cabe25d021acd80f13abf81181cf"}, + {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b26b0f4428b871a751968285a1ac9648944cea09807177ac639b030bddebcea4"}, + {file = "greenlet-3.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fb39a11ee2e4d94be9a76671482be9398560955c9e568550de0224e41104727"}, + {file = "greenlet-3.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:20154044d9085151bc309e7689d6f7ba10027f8f5a8c0676ad398b951913d89e"}, + {file = "greenlet-3.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c04c5e06ec3e022cbfe2cd4a846e1d4e50087444f875ff6d2c2ad8445495cf1a"}, + {file = "greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil", "setuptools"] + +[[package]] +name = "h5py" +version = "3.16.0" +description = "Read and write HDF5 files from Python" +optional = true +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "h5py-3.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e06f864bedb2c8e7c1358e6c73af48519e317457c444d6f3d332bb4e8fa6d7d9"}, + {file = "h5py-3.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec86d4fffd87a0f4cb3d5796ceb5a50123a2a6d99b43e616e5504e66a953eca3"}, + {file = "h5py-3.16.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:86385ea895508220b8a7e45efa428aeafaa586bd737c7af9ee04661d8d84a10d"}, + {file = "h5py-3.16.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:8975273c2c5921c25700193b408e28d6bdd0111c37468b2d4e25dcec4cd1d84d"}, + {file = "h5py-3.16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1677ad48b703f44efc9ea0c3ab284527f81bc4f318386aaaebc5fede6bbae56f"}, + {file = "h5py-3.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c4dd4cf5f0a4e36083f73172f6cfc25a5710789269547f132a20975bfe2434c"}, + {file = "h5py-3.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:bdef06507725b455fccba9c16529121a5e1fbf56aa375f7d9713d9e8ff42454d"}, + {file = "h5py-3.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:719439d14b83f74eeb080e9650a6c7aa6d0d9ea0ca7f804347b05fac6fbf18af"}, + {file = "h5py-3.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3f0a0e136f2e95dd0b67146abb6668af4f1a69c81ef8651a2d316e8e01de447"}, + {file = "h5py-3.16.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a6fbc5367d4046801f9b7db9191b31895f22f1c6df1f9987d667854cac493538"}, + {file = "h5py-3.16.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:fb1720028d99040792bb2fb31facb8da44a6f29df7697e0b84f0d79aff2e9bd3"}, + {file = "h5py-3.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:314b6054fe0b1051c2b0cb2df5cbdab15622fb05e80f202e3b6a5eee0d6fe365"}, + {file = "h5py-3.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ffbab2fedd6581f6aa31cf1639ca2cb86e02779de525667892ebf4cc9fd26434"}, + {file = "h5py-3.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d1f1630f92ad74494a9a7392ab25982ce2b469fc62da6074c0ce48366a2999"}, + {file = "h5py-3.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:85b9c49dd58dc44cf70af944784e2c2038b6f799665d0dcbbc812a26e0faa859"}, + {file = "h5py-3.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c5313566f4643121a78503a473f0fb1e6dcc541d5115c44f05e037609c565c4d"}, + {file = "h5py-3.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:42b012933a83e1a558c673176676a10ce2fd3759976a0fedee1e672d1e04fc9d"}, + {file = "h5py-3.16.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ff24039e2573297787c3063df64b60aab0591980ac898329a08b0320e0cf2527"}, + {file = "h5py-3.16.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:dfc21898ff025f1e8e67e194965a95a8d4754f452f83454538f98f8a3fcb207e"}, + {file = "h5py-3.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:698dd69291272642ffda44a0ecd6cd3bda5faf9621452d255f57ce91487b9794"}, + {file = "h5py-3.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2b2c02b0a160faed5fb33f1ba8a264a37ee240b22e049ecc827345d0d9043074"}, + {file = "h5py-3.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:96b422019a1c8975c2d5dadcf61d4ba6f01c31f92bbde6e4649607885fe502d6"}, + {file = "h5py-3.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:39c2838fb1e8d97bcf1755e60ad1f3dd76a7b2a475928dc321672752678b96db"}, + {file = "h5py-3.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:370a845f432c2c9619db8eed334d1e610c6015796122b0e57aa46312c22617d9"}, + {file = "h5py-3.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42108e93326c50c2810025aade9eac9d6827524cdccc7d4b75a546e5ab308edb"}, + {file = "h5py-3.16.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:099f2525c9dcf28de366970a5fb34879aab20491589fa89ce2863a84218bb524"}, + {file = "h5py-3.16.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:9300ad32dea9dfc5171f94d5f6948e159ed93e4701280b0f508773b3f582f402"}, + {file = "h5py-3.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:171038f23bccddfc23f344cadabdfc9917ff554db6a0d417180d2747fe4c75a7"}, + {file = "h5py-3.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7e420b539fb6023a259a1b14d4c9f6df8cf50d7268f48e161169987a57b737ff"}, + {file = "h5py-3.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:18f2bbcd545e6991412253b98727374c356d67caa920e68dc79eab36bf5fedad"}, + {file = "h5py-3.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:656f00e4d903199a1d58df06b711cf3ca632b874b4207b7dbec86185b5c8c7d4"}, + {file = "h5py-3.16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9c9d307c0ef862d1cd5714f72ecfafe0a5d7529c44845afa8de9f46e5ba8bd65"}, + {file = "h5py-3.16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8c1eff849cdd53cbc73c214c30ebdb6f1bb8b64790b4b4fc36acdb5e43570210"}, + {file = "h5py-3.16.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:e2c04d129f180019e216ee5f9c40b78a418634091c8782e1f723a6ca3658b965"}, + {file = "h5py-3.16.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:e4360f15875a532bc7b98196c7592ed4fc92672a57c0a621355961cafb17a6dd"}, + {file = "h5py-3.16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3fae9197390c325e62e0a1aa977f2f62d994aa87aab182abbea85479b791197c"}, + {file = "h5py-3.16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:43259303989ac8adacc9986695b31e35dba6fd1e297ff9c6a04b7da5542139cc"}, + {file = "h5py-3.16.0-cp314-cp314-win_amd64.whl", hash = "sha256:fa48993a0b799737ba7fd21e2350fa0a60701e58180fae9f2de834bc39a147ab"}, + {file = "h5py-3.16.0-cp314-cp314-win_arm64.whl", hash = "sha256:1897a771a7f40d05c262fc8f37376ec37873218544b70216872876c627640f63"}, + {file = "h5py-3.16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:15922e485844f77c0b9d275396d435db3baa58292a9c2176a386e072e0cf2491"}, + {file = "h5py-3.16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:df02dd29bd247f98674634dfe41f89fd7c16ba3d7de8695ec958f58404a4e618"}, + {file = "h5py-3.16.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0f456f556e4e2cebeebd9d66adf8dc321770a42593494a0b6f0af54a7567b242"}, + {file = "h5py-3.16.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:3e6cb3387c756de6a9492d601553dffea3fe11b5f22b443aac708c69f3f55e16"}, + {file = "h5py-3.16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8389e13a1fd745ad2856873e8187fd10268b2d9677877bb667b41aebd771d8b7"}, + {file = "h5py-3.16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:346df559a0f7dcb31cf8e44805319e2ab24b8957c45e7708ce503b2ec79ba725"}, + {file = "h5py-3.16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4c6ab014ab704b4feaa719ae783b86522ed0bf1f82184704ed3c9e4e3228796e"}, + {file = "h5py-3.16.0-cp314-cp314t-win_arm64.whl", hash = "sha256:faca8fb4e4319c09d83337adc80b2ca7d5c5a343c2d6f1b6388f32cfecca13c1"}, + {file = "h5py-3.16.0.tar.gz", hash = "sha256:a0dbaad796840ccaa67a4c144a0d0c8080073c34c76d5a6941d6818678ef2738"}, +] + +[package.dependencies] +numpy = ">=1.21.2" + +[[package]] +name = "idna" +version = "3.11" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, + {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "imagesize" +version = "2.0.0" +description = "Get image size from headers (BMP/PNG/JPEG/JPEG2000/GIF/TIFF/SVG/Netpbm/WebP/AVIF/HEIC/HEIF)" +optional = false +python-versions = "<3.15,>=3.10" +groups = ["docs"] +files = [ + {file = "imagesize-2.0.0-py2.py3-none-any.whl", hash = "sha256:5667c5bbb57ab3f1fa4bc366f4fbc971db3d5ed011fd2715fd8001f782718d96"}, + {file = "imagesize-2.0.0.tar.gz", hash = "sha256:8e8358c4a05c304f1fccf7ff96f036e7243a189e9e42e90851993c558cfe9ee3"}, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.10" +groups = ["tests"] +files = [ + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, +] + +[[package]] +name = "ipython" +version = "8.39.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "ipython-8.39.0-py3-none-any.whl", hash = "sha256:bb3c51c4fa8148ab1dea07a79584d1c854e234ea44aa1283bcb37bc75054651f"}, + {file = "ipython-8.39.0.tar.gz", hash = "sha256:4110ae96012c379b8b6db898a07e186c40a2a1ef5d57a7fa83166047d9da7624"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} +prompt_toolkit = ">=3.0.41,<3.1.0" +pygments = ">=2.4.0" +stack_data = "*" +traitlets = ">=5.13.0" +typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} + +[package.extras] +all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing_extensions"] +kernel = ["ipykernel"] +matplotlib = ["matplotlib"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] + +[[package]] +name = "isort" +version = "6.1.0" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.9.0" +groups = ["analysis"] +files = [ + {file = "isort-6.1.0-py3-none-any.whl", hash = "sha256:58d8927ecce74e5087aef019f778d4081a3b6c98f15a80ba35782ca8a2097784"}, + {file = "isort-6.1.0.tar.gz", hash = "sha256:9b8f96a14cfee0677e78e941ff62f03769a06d412aabb9e2a90487b3b7e8d481"}, +] + +[package.extras] +colors = ["colorama"] +plugins = ["setuptools"] + +[[package]] +name = "jedi" +version = "0.19.2" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, + {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, +] + +[package.dependencies] +parso = ">=0.8.4,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] + +[[package]] +name = "jinja2" +version = "3.1.6" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +groups = ["docs"] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "joblib" +version = "1.5.3" +description = "Lightweight pipelining with Python functions" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713"}, + {file = "joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3"}, +] + +[[package]] +name = "kiwisolver" +version = "1.5.0" +description = "A fast implementation of the Cassowary constraint solver" +optional = true +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "kiwisolver-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32cc0a5365239a6ea0c6ed461e8838d053b57e397443c0ca894dcc8e388d4374"}, + {file = "kiwisolver-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc0b66c1eec9021353a4b4483afb12dfd50e3669ffbb9152d6842eb34c7e29fd"}, + {file = "kiwisolver-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86e0287879f75621ae85197b0877ed2f8b7aa57b511c7331dce2eb6f4de7d476"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:62f59da443c4f4849f73a51a193b1d9d258dcad0c41bc4d1b8fb2bcc04bfeb22"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9190426b7aa26c5229501fa297b8d0653cfd3f5a36f7990c264e157cbf886b3b"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c8277104ded0a51e699c8c3aff63ce2c56d4ed5519a5f73e0fd7057f959a2b9e"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8f9baf6f0a6e7571c45c8863010b45e837c3ee1c2c77fcd6ef423be91b21fedb"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cff8e5383db4989311f99e814feeb90c4723eb4edca425b9d5d9c3fefcdd9537"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ebae99ed6764f2b5771c522477b311be313e8841d2e0376db2b10922daebbba4"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d5cd5189fc2b6a538b75ae45433140c4823463918f7b1617c31e68b085c0022c"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f42c23db5d1521218a3276bb08666dcb662896a0be7347cba864eca45ff64ede"}, + {file = "kiwisolver-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:94eff26096eb5395136634622515b234ecb6c9979824c1f5004c6e3c3c85ccd2"}, + {file = "kiwisolver-1.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:dd952e03bfbb096cfe2dd35cd9e00f269969b67536cb4370994afc20ff2d0875"}, + {file = "kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c"}, + {file = "kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb"}, + {file = "kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4"}, + {file = "kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b"}, + {file = "kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac"}, + {file = "kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9"}, + {file = "kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588"}, + {file = "kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9"}, + {file = "kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384"}, + {file = "kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7"}, + {file = "kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09"}, + {file = "kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3"}, + {file = "kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0"}, + {file = "kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276"}, + {file = "kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53"}, + {file = "kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615"}, + {file = "kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02"}, + {file = "kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796"}, + {file = "kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e"}, + {file = "kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:295d9ffe712caa9f8a3081de8d32fc60191b4b51c76f02f951fd8407253528f4"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:51e8c4084897de9f05898c2c2a39af6318044ae969d46ff7a34ed3f96274adca"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b83af57bdddef03c01a9138034c6ff03181a3028d9a1003b301eb1a55e161a3f"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf4679a3d71012a7c2bf360e5cd878fbd5e4fcac0896b56393dec239d81529ed"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:41024ed50e44ab1a60d3fe0a9d15a4ccc9f5f2b1d814ff283c8d01134d5b81bc"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1"}, + {file = "kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a"}, +] + +[[package]] +name = "latexcodec" +version = "3.0.1" +description = "A lexer and codec to work with LaTeX code in Python." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "latexcodec-3.0.1-py3-none-any.whl", hash = "sha256:a9eb8200bff693f0437a69581f7579eb6bca25c4193515c09900ce76451e452e"}, + {file = "latexcodec-3.0.1.tar.gz", hash = "sha256:e78a6911cd72f9dec35031c6ec23584de6842bfbc4610a9678868d14cdfb0357"}, +] + +[[package]] +name = "llvmlite" +version = "0.44.0" +description = "lightweight wrapper around basic LLVM functionality" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "llvmlite-0.44.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:9fbadbfba8422123bab5535b293da1cf72f9f478a65645ecd73e781f962ca614"}, + {file = "llvmlite-0.44.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cccf8eb28f24840f2689fb1a45f9c0f7e582dd24e088dcf96e424834af11f791"}, + {file = "llvmlite-0.44.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7202b678cdf904823c764ee0fe2dfe38a76981f4c1e51715b4cb5abb6cf1d9e8"}, + {file = "llvmlite-0.44.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40526fb5e313d7b96bda4cbb2c85cd5374e04d80732dd36a282d72a560bb6408"}, + {file = "llvmlite-0.44.0-cp310-cp310-win_amd64.whl", hash = "sha256:41e3839150db4330e1b2716c0be3b5c4672525b4c9005e17c7597f835f351ce2"}, + {file = "llvmlite-0.44.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:eed7d5f29136bda63b6d7804c279e2b72e08c952b7c5df61f45db408e0ee52f3"}, + {file = "llvmlite-0.44.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ace564d9fa44bb91eb6e6d8e7754977783c68e90a471ea7ce913bff30bd62427"}, + {file = "llvmlite-0.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5d22c3bfc842668168a786af4205ec8e3ad29fb1bc03fd11fd48460d0df64c1"}, + {file = "llvmlite-0.44.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f01a394e9c9b7b1d4e63c327b096d10f6f0ed149ef53d38a09b3749dcf8c9610"}, + {file = "llvmlite-0.44.0-cp311-cp311-win_amd64.whl", hash = "sha256:d8489634d43c20cd0ad71330dde1d5bc7b9966937a263ff1ec1cebb90dc50955"}, + {file = "llvmlite-0.44.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:1d671a56acf725bf1b531d5ef76b86660a5ab8ef19bb6a46064a705c6ca80aad"}, + {file = "llvmlite-0.44.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f79a728e0435493611c9f405168682bb75ffd1fbe6fc360733b850c80a026db"}, + {file = "llvmlite-0.44.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0143a5ef336da14deaa8ec26c5449ad5b6a2b564df82fcef4be040b9cacfea9"}, + {file = "llvmlite-0.44.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d752f89e31b66db6f8da06df8b39f9b91e78c5feea1bf9e8c1fba1d1c24c065d"}, + {file = "llvmlite-0.44.0-cp312-cp312-win_amd64.whl", hash = "sha256:eae7e2d4ca8f88f89d315b48c6b741dcb925d6a1042da694aa16ab3dd4cbd3a1"}, + {file = "llvmlite-0.44.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:319bddd44e5f71ae2689859b7203080716448a3cd1128fb144fe5c055219d516"}, + {file = "llvmlite-0.44.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c58867118bad04a0bb22a2e0068c693719658105e40009ffe95c7000fcde88e"}, + {file = "llvmlite-0.44.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46224058b13c96af1365290bdfebe9a6264ae62fb79b2b55693deed11657a8bf"}, + {file = "llvmlite-0.44.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0097052c32bf721a4efc03bd109d335dfa57d9bffb3d4c24cc680711b8b4fc"}, + {file = "llvmlite-0.44.0-cp313-cp313-win_amd64.whl", hash = "sha256:2fb7c4f2fb86cbae6dca3db9ab203eeea0e22d73b99bc2341cdf9de93612e930"}, + {file = "llvmlite-0.44.0.tar.gz", hash = "sha256:07667d66a5d150abed9157ab6c0b9393c9356f229784a4385c02f99e94fc94d4"}, +] + +[[package]] +name = "mako" +version = "1.3.10" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59"}, + {file = "mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28"}, +] + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["Babel"] +lingua = ["lingua"] +testing = ["pytest"] + +[[package]] +name = "markupsafe" +version = "3.0.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +groups = ["main", "docs"] +files = [ + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, +] + +[[package]] +name = "matplotlib" +version = "3.10.8" +description = "Python plotting package" +optional = true +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "matplotlib-3.10.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:00270d217d6b20d14b584c521f810d60c5c78406dc289859776550df837dcda7"}, + {file = "matplotlib-3.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b3c1cc42aa184b3f738cfa18c1c1d72fd496d85467a6cf7b807936d39aa656"}, + {file = "matplotlib-3.10.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee40c27c795bda6a5292e9cff9890189d32f7e3a0bf04e0e3c9430c4a00c37df"}, + {file = "matplotlib-3.10.8-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a48f2b74020919552ea25d222d5cc6af9ca3f4eb43a93e14d068457f545c2a17"}, + {file = "matplotlib-3.10.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f254d118d14a7f99d616271d6c3c27922c092dac11112670b157798b89bf4933"}, + {file = "matplotlib-3.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:f9b587c9c7274c1613a30afabf65a272114cd6cdbe67b3406f818c79d7ab2e2a"}, + {file = "matplotlib-3.10.8-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6be43b667360fef5c754dda5d25a32e6307a03c204f3c0fc5468b78fa87b4160"}, + {file = "matplotlib-3.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2b336e2d91a3d7006864e0990c83b216fcdca64b5a6484912902cef87313d78"}, + {file = "matplotlib-3.10.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efb30e3baaea72ce5928e32bab719ab4770099079d66726a62b11b1ef7273be4"}, + {file = "matplotlib-3.10.8-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d56a1efd5bfd61486c8bc968fa18734464556f0fb8e51690f4ac25d85cbbbbc2"}, + {file = "matplotlib-3.10.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238b7ce5717600615c895050239ec955d91f321c209dd110db988500558e70d6"}, + {file = "matplotlib-3.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:18821ace09c763ec93aef5eeff087ee493a24051936d7b9ebcad9662f66501f9"}, + {file = "matplotlib-3.10.8-cp311-cp311-win_arm64.whl", hash = "sha256:bab485bcf8b1c7d2060b4fcb6fc368a9e6f4cd754c9c2fea281f4be21df394a2"}, + {file = "matplotlib-3.10.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:64fcc24778ca0404ce0cb7b6b77ae1f4c7231cdd60e6778f999ee05cbd581b9a"}, + {file = "matplotlib-3.10.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9a5ca4ac220a0cdd1ba6bcba3608547117d30468fefce49bb26f55c1a3d5c58"}, + {file = "matplotlib-3.10.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3ab4aabc72de4ff77b3ec33a6d78a68227bf1123465887f9905ba79184a1cc04"}, + {file = "matplotlib-3.10.8-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24d50994d8c5816ddc35411e50a86ab05f575e2530c02752e02538122613371f"}, + {file = "matplotlib-3.10.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:99eefd13c0dc3b3c1b4d561c1169e65fe47aab7b8158754d7c084088e2329466"}, + {file = "matplotlib-3.10.8-cp312-cp312-win_amd64.whl", hash = "sha256:dd80ecb295460a5d9d260df63c43f4afbdd832d725a531f008dad1664f458adf"}, + {file = "matplotlib-3.10.8-cp312-cp312-win_arm64.whl", hash = "sha256:3c624e43ed56313651bc18a47f838b60d7b8032ed348911c54906b130b20071b"}, + {file = "matplotlib-3.10.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3f2e409836d7f5ac2f1c013110a4d50b9f7edc26328c108915f9075d7d7a91b6"}, + {file = "matplotlib-3.10.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56271f3dac49a88d7fca5060f004d9d22b865f743a12a23b1e937a0be4818ee1"}, + {file = "matplotlib-3.10.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a0a7f52498f72f13d4a25ea70f35f4cb60642b466cbb0a9be951b5bc3f45a486"}, + {file = "matplotlib-3.10.8-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:646d95230efb9ca614a7a594d4fcacde0ac61d25e37dd51710b36477594963ce"}, + {file = "matplotlib-3.10.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f89c151aab2e2e23cb3fe0acad1e8b82841fd265379c4cecd0f3fcb34c15e0f6"}, + {file = "matplotlib-3.10.8-cp313-cp313-win_amd64.whl", hash = "sha256:e8ea3e2d4066083e264e75c829078f9e149fa119d27e19acd503de65e0b13149"}, + {file = "matplotlib-3.10.8-cp313-cp313-win_arm64.whl", hash = "sha256:c108a1d6fa78a50646029cb6d49808ff0fc1330fda87fa6f6250c6b5369b6645"}, + {file = "matplotlib-3.10.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ad3d9833a64cf48cc4300f2b406c3d0f4f4724a91c0bd5640678a6ba7c102077"}, + {file = "matplotlib-3.10.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:eb3823f11823deade26ce3b9f40dcb4a213da7a670013929f31d5f5ed1055b22"}, + {file = "matplotlib-3.10.8-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d9050fee89a89ed57b4fb2c1bfac9a3d0c57a0d55aed95949eedbc42070fea39"}, + {file = "matplotlib-3.10.8-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b44d07310e404ba95f8c25aa5536f154c0a8ec473303535949e52eb71d0a1565"}, + {file = "matplotlib-3.10.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0a33deb84c15ede243aead39f77e990469fff93ad1521163305095b77b72ce4a"}, + {file = "matplotlib-3.10.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3a48a78d2786784cc2413e57397981fb45c79e968d99656706018d6e62e57958"}, + {file = "matplotlib-3.10.8-cp313-cp313t-win_arm64.whl", hash = "sha256:15d30132718972c2c074cd14638c7f4592bd98719e2308bccea40e0538bc0cb5"}, + {file = "matplotlib-3.10.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b53285e65d4fa4c86399979e956235deb900be5baa7fc1218ea67fbfaeaadd6f"}, + {file = "matplotlib-3.10.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32f8dce744be5569bebe789e46727946041199030db8aeb2954d26013a0eb26b"}, + {file = "matplotlib-3.10.8-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf267add95b1c88300d96ca837833d4112756045364f5c734a2276038dae27d"}, + {file = "matplotlib-3.10.8-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2cf5bd12cecf46908f286d7838b2abc6c91cda506c0445b8223a7c19a00df008"}, + {file = "matplotlib-3.10.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:41703cc95688f2516b480f7f339d8851a6035f18e100ee6a32bc0b8536a12a9c"}, + {file = "matplotlib-3.10.8-cp314-cp314-win_amd64.whl", hash = "sha256:83d282364ea9f3e52363da262ce32a09dfe241e4080dcedda3c0db059d3c1f11"}, + {file = "matplotlib-3.10.8-cp314-cp314-win_arm64.whl", hash = "sha256:2c1998e92cd5999e295a731bcb2911c75f597d937341f3030cc24ef2733d78a8"}, + {file = "matplotlib-3.10.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b5a2b97dbdc7d4f353ebf343744f1d1f1cca8aa8bfddb4262fcf4306c3761d50"}, + {file = "matplotlib-3.10.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3f5c3e4da343bba819f0234186b9004faba952cc420fbc522dc4e103c1985908"}, + {file = "matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f62550b9a30afde8c1c3ae450e5eb547d579dd69b25c2fc7a1c67f934c1717a"}, + {file = "matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:495672de149445ec1b772ff2c9ede9b769e3cb4f0d0aa7fa730d7f59e2d4e1c1"}, + {file = "matplotlib-3.10.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:595ba4d8fe983b88f0eec8c26a241e16d6376fe1979086232f481f8f3f67494c"}, + {file = "matplotlib-3.10.8-cp314-cp314t-win_amd64.whl", hash = "sha256:25d380fe8b1dc32cf8f0b1b448470a77afb195438bafdf1d858bfb876f3edf7b"}, + {file = "matplotlib-3.10.8-cp314-cp314t-win_arm64.whl", hash = "sha256:113bb52413ea508ce954a02c10ffd0d565f9c3bc7f2eddc27dfe1731e71c7b5f"}, + {file = "matplotlib-3.10.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f97aeb209c3d2511443f8797e3e5a569aebb040d4f8bc79aa3ee78a8fb9e3dd8"}, + {file = "matplotlib-3.10.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb061f596dad3a0f52b60dc6a5dec4a0c300dec41e058a7efe09256188d170b7"}, + {file = "matplotlib-3.10.8-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12d90df9183093fcd479f4172ac26b322b1248b15729cb57f42f71f24c7e37a3"}, + {file = "matplotlib-3.10.8-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6da7c2ce169267d0d066adcf63758f0604aa6c3eebf67458930f9d9b79ad1db1"}, + {file = "matplotlib-3.10.8-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9153c3292705be9f9c64498a8872118540c3f4123d1a1c840172edf262c8be4a"}, + {file = "matplotlib-3.10.8-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ae029229a57cd1e8fe542485f27e7ca7b23aa9e8944ddb4985d0bc444f1eca2"}, + {file = "matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.3.1" +numpy = ">=1.23" +packaging = ">=20.0" +pillow = ">=8" +pyparsing = ">=3" +python-dateutil = ">=2.7" + +[package.extras] +dev = ["meson-python (>=0.13.1,<0.17.0)", "pybind11 (>=2.13.2,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7)"] + +[[package]] +name = "matplotlib-inline" +version = "0.2.1" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76"}, + {file = "matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe"}, +] + +[package.dependencies] +traitlets = "*" + +[package.extras] +test = ["flake8", "nbdime", "nbval", "notebook", "pytest"] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +groups = ["analysis"] +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +description = "Python library for arbitrary-precision floating-point arithmetic" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, + {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, +] + +[package.extras] +develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] +docs = ["sphinx"] +gmpy = ["gmpy2 (>=2.1.0a4) ; platform_python_implementation != \"PyPy\""] +tests = ["pytest (>=4.6)"] + +[[package]] +name = "networkx" +version = "3.6.1" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = "!=3.14.1,>=3.11" +groups = ["main"] +files = [ + {file = "networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762"}, + {file = "networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509"}, +] + +[package.extras] +benchmarking = ["asv", "virtualenv"] +default = ["matplotlib (>=3.8)", "numpy (>=1.25)", "pandas (>=2.0)", "scipy (>=1.11.2)"] +developer = ["mypy (>=1.15)", "pre-commit (>=4.1)"] +doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=10)", "pydata-sphinx-theme (>=0.16)", "sphinx (>=8.0)", "sphinx-gallery (>=0.18)", "texext (>=0.6.7)"] +example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "iplotx (>=0.9.0)", "momepy (>=0.7.2)", "osmnx (>=2.0.0)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] +extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] +release = ["build (>=0.10)", "changelist (==0.5)", "twine (>=4.0)", "wheel (>=0.40)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)", "pytest-xdist (>=3.0)"] +test-extras = ["pytest-mpl", "pytest-randomly"] + +[[package]] +name = "numba" +version = "0.61.2" +description = "compiling Python code using LLVM" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "numba-0.61.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:cf9f9fc00d6eca0c23fc840817ce9f439b9f03c8f03d6246c0e7f0cb15b7162a"}, + {file = "numba-0.61.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ea0247617edcb5dd61f6106a56255baab031acc4257bddaeddb3a1003b4ca3fd"}, + {file = "numba-0.61.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae8c7a522c26215d5f62ebec436e3d341f7f590079245a2f1008dfd498cc1642"}, + {file = "numba-0.61.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bd1e74609855aa43661edffca37346e4e8462f6903889917e9f41db40907daa2"}, + {file = "numba-0.61.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae45830b129c6137294093b269ef0a22998ccc27bf7cf096ab8dcf7bca8946f9"}, + {file = "numba-0.61.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:efd3db391df53aaa5cfbee189b6c910a5b471488749fd6606c3f33fc984c2ae2"}, + {file = "numba-0.61.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:49c980e4171948ffebf6b9a2520ea81feed113c1f4890747ba7f59e74be84b1b"}, + {file = "numba-0.61.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3945615cd73c2c7eba2a85ccc9c1730c21cd3958bfcf5a44302abae0fb07bb60"}, + {file = "numba-0.61.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbfdf4eca202cebade0b7d43896978e146f39398909a42941c9303f82f403a18"}, + {file = "numba-0.61.2-cp311-cp311-win_amd64.whl", hash = "sha256:76bcec9f46259cedf888041b9886e257ae101c6268261b19fda8cfbc52bec9d1"}, + {file = "numba-0.61.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:34fba9406078bac7ab052efbf0d13939426c753ad72946baaa5bf9ae0ebb8dd2"}, + {file = "numba-0.61.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ddce10009bc097b080fc96876d14c051cc0c7679e99de3e0af59014dab7dfe8"}, + {file = "numba-0.61.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b1bb509d01f23d70325d3a5a0e237cbc9544dd50e50588bc581ba860c213546"}, + {file = "numba-0.61.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48a53a3de8f8793526cbe330f2a39fe9a6638efcbf11bd63f3d2f9757ae345cd"}, + {file = "numba-0.61.2-cp312-cp312-win_amd64.whl", hash = "sha256:97cf4f12c728cf77c9c1d7c23707e4d8fb4632b46275f8f3397de33e5877af18"}, + {file = "numba-0.61.2-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:3a10a8fc9afac40b1eac55717cece1b8b1ac0b946f5065c89e00bde646b5b154"}, + {file = "numba-0.61.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d3bcada3c9afba3bed413fba45845f2fb9cd0d2b27dd58a1be90257e293d140"}, + {file = "numba-0.61.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bdbca73ad81fa196bd53dc12e3aaf1564ae036e0c125f237c7644fe64a4928ab"}, + {file = "numba-0.61.2-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:5f154aaea625fb32cfbe3b80c5456d514d416fcdf79733dd69c0df3a11348e9e"}, + {file = "numba-0.61.2-cp313-cp313-win_amd64.whl", hash = "sha256:59321215e2e0ac5fa928a8020ab00b8e57cda8a97384963ac0dfa4d4e6aa54e7"}, + {file = "numba-0.61.2.tar.gz", hash = "sha256:8750ee147940a6637b80ecf7f95062185ad8726c8c28a2295b8ec1160a196f7d"}, +] + +[package.dependencies] +llvmlite = "==0.44.*" +numpy = ">=1.24,<2.3" + +[[package]] +name = "numpy" +version = "2.1.3" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "numpy-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c894b4305373b9c5576d7a12b473702afdf48ce5369c074ba304cc5ad8730dff"}, + {file = "numpy-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b47fbb433d3260adcd51eb54f92a2ffbc90a4595f8970ee00e064c644ac788f5"}, + {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:825656d0743699c529c5943554d223c021ff0494ff1442152ce887ef4f7561a1"}, + {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a4825252fcc430a182ac4dee5a505053d262c807f8a924603d411f6718b88fd"}, + {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e711e02f49e176a01d0349d82cb5f05ba4db7d5e7e0defd026328e5cfb3226d3"}, + {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098"}, + {file = "numpy-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c7662f0e3673fe4e832fe07b65c50342ea27d989f92c80355658c7f888fcc83c"}, + {file = "numpy-2.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fa2d1337dc61c8dc417fbccf20f6d1e139896a30721b7f1e832b2bb6ef4eb6c4"}, + {file = "numpy-2.1.3-cp310-cp310-win32.whl", hash = "sha256:72dcc4a35a8515d83e76b58fdf8113a5c969ccd505c8a946759b24e3182d1f23"}, + {file = "numpy-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:ecc76a9ba2911d8d37ac01de72834d8849e55473457558e12995f4cd53e778e0"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09"}, + {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a"}, + {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b"}, + {file = "numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee"}, + {file = "numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0"}, + {file = "numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9"}, + {file = "numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564"}, + {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512"}, + {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b"}, + {file = "numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc"}, + {file = "numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0"}, + {file = "numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9"}, + {file = "numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe"}, + {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43"}, + {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56"}, + {file = "numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a"}, + {file = "numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef"}, + {file = "numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f"}, + {file = "numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0"}, + {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408"}, + {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6"}, + {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f"}, + {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17"}, + {file = "numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48"}, + {file = "numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4f2015dfe437dfebbfce7c85c7b53d81ba49e71ba7eadbf1df40c915af75979f"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3522b0dfe983a575e6a9ab3a4a4dfe156c3e428468ff08ce582b9bb6bd1d71d4"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006b607a865b07cd981ccb218a04fc86b600411d83d6fc261357f1c0966755d"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e14e26956e6f1696070788252dcdff11b4aca4c3e8bd166e0df1bb8f315a67cb"}, + {file = "numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761"}, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.9.1.4" +description = "CUBLAS native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cublas_cu12-12.9.1.4-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:7a950dae01add3b415a5a5cdc4ec818fb5858263e9cca59004bb99fdbbd3a5d6"}, + {file = "nvidia_cublas_cu12-12.9.1.4-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:453611eb21a7c1f2c2156ed9f3a45b691deda0440ec550860290dc901af5b4c2"}, + {file = "nvidia_cublas_cu12-12.9.1.4-py3-none-win_amd64.whl", hash = "sha256:1e5fee10662e6e52bd71dec533fbbd4971bb70a5f24f3bc3793e5c2e9dc640bf"}, +] + +[[package]] +name = "nvidia-cuda-cccl-cu12" +version = "12.9.27" +description = "CUDA CCCL" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cuda_cccl_cu12-12.9.27-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7898b38aa68beaa234d48f0868273702342a196d6e2e9d0ef058dca2390ebea"}, + {file = "nvidia_cuda_cccl_cu12-12.9.27-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:37869e17ce2e1ecec6eddf1927cca0f8c34e64fd848d40453df559091e2d7117"}, + {file = "nvidia_cuda_cccl_cu12-12.9.27-py3-none-win_amd64.whl", hash = "sha256:72106f95a9bb3be18472806b4f663ebf0f9248a86d14b4ae3305725b855d9d92"}, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.9.79" +description = "CUDA profiling tools runtime libs." +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cuda_cupti_cu12-12.9.79-py3-none-manylinux_2_25_aarch64.whl", hash = "sha256:791853b030602c6a11d08b5578edfb957cadea06e9d3b26adbf8d036135a4afe"}, + {file = "nvidia_cuda_cupti_cu12-12.9.79-py3-none-manylinux_2_25_x86_64.whl", hash = "sha256:096bcf334f13e1984ba36685ad4c1d6347db214de03dbb6eebb237b41d9d934f"}, + {file = "nvidia_cuda_cupti_cu12-12.9.79-py3-none-win_amd64.whl", hash = "sha256:1848a9380067560d5bee10ed240eecc22991713e672c0515f9c3d9396adf93c8"}, +] + +[[package]] +name = "nvidia-cuda-cuxxfilt-cu12" +version = "12.9.82" +description = "CUDA cuxxfilt" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cuda_cuxxfilt_cu12-12.9.82-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:472cfaced1068d3d73a3e7e36bdca30fc4f5e61503b2d1dd2c6bbfff58aabf46"}, + {file = "nvidia_cuda_cuxxfilt_cu12-12.9.82-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ccef4629a8d5d74d0370c6f34c329a4781abcfaf390a9fff89d4fe21ec1b950c"}, + {file = "nvidia_cuda_cuxxfilt_cu12-12.9.82-py3-none-win_amd64.whl", hash = "sha256:b6d696985f83982502100c7bff1e3931227966cab47772ee70bdcd3503955207"}, +] + +[[package]] +name = "nvidia-cuda-nvcc-cu12" +version = "12.9.86" +description = "CUDA nvcc" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cuda_nvcc_cu12-12.9.86-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:5d6a0d32fdc7ea39917c20065614ae93add6f577d840233237ff08e9a38f58f0"}, + {file = "nvidia_cuda_nvcc_cu12-12.9.86-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44e1eca4d08926193a558d2434b1bf83d57b4d5743e0c431c0c83d51da1df62b"}, + {file = "nvidia_cuda_nvcc_cu12-12.9.86-py3-none-win_amd64.whl", hash = "sha256:8ed7f0b17dea662755395be029376db3b94fed5cbb17c2d35cc866c5b1b84099"}, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.9.86" +description = "NVRTC native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cuda_nvrtc_cu12-12.9.86-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:210cf05005a447e29214e9ce50851e83fc5f4358df8b453155d5e1918094dcb4"}, + {file = "nvidia_cuda_nvrtc_cu12-12.9.86-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:096d4de6bda726415dfaf3198d4f5c522b8e70139c97feef5cd2ca6d4cd9cead"}, + {file = "nvidia_cuda_nvrtc_cu12-12.9.86-py3-none-win_amd64.whl", hash = "sha256:72972ebdcf504d69462d3bcd67e7b81edd25d0fb85a2c46d3ea3517666636349"}, +] + +[[package]] +name = "nvidia-cuda-opencl-cu12" +version = "12.9.19" +description = "CUDA OpenCL" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cuda_opencl_cu12-12.9.19-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:16897b9fe8e5849a7550ddd9e1d104bf3950531eb39a9c90a02453f19aa57a68"}, + {file = "nvidia_cuda_opencl_cu12-12.9.19-py3-none-win_amd64.whl", hash = "sha256:970edb7ad8e6b3f77271fefffaa4147f35d4f752389b159a1330f271e919178f"}, +] + +[[package]] +name = "nvidia-cuda-profiler-api-cu12" +version = "12.9.79" +description = "CUDA Profiler API" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cuda_profiler_api_cu12-12.9.79-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8d79c445609d53a3b461832690cab0105a3f71fd9f17d4a6ed9ae102f4217108"}, + {file = "nvidia_cuda_profiler_api_cu12-12.9.79-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b3d5877b016450beb4d8935299bb86368f234d8789b64e844043b9a65ce31b39"}, + {file = "nvidia_cuda_profiler_api_cu12-12.9.79-py3-none-win_amd64.whl", hash = "sha256:e22e5bf44c5b966e03baa3e0bf30455a2e59bdb3e787538fe66db324fdb078d2"}, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.9.79" +description = "CUDA Runtime native Libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cuda_runtime_cu12-12.9.79-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83469a846206f2a733db0c42e223589ab62fd2fabac4432d2f8802de4bded0a4"}, + {file = "nvidia_cuda_runtime_cu12-12.9.79-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25bba2dfb01d48a9b59ca474a1ac43c6ebf7011f1b0b8cc44f54eb6ac48a96c3"}, + {file = "nvidia_cuda_runtime_cu12-12.9.79-py3-none-win_amd64.whl", hash = "sha256:8e018af8fa02363876860388bd10ccb89eb9ab8fb0aa749aaf58430a9f7c4891"}, +] + +[[package]] +name = "nvidia-cuda-sanitizer-api-cu12" +version = "12.9.79" +description = "CUDA Sanitizer" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cuda_sanitizer_api_cu12-12.9.79-py3-none-manylinux_2_25_aarch64.whl", hash = "sha256:b456fbc21b4246143cf1d37af9d90401098096bbe610b9bf6b1a41c05600d44e"}, + {file = "nvidia_cuda_sanitizer_api_cu12-12.9.79-py3-none-manylinux_2_25_x86_64.whl", hash = "sha256:61e6bb66755cd13b89a32f5bda090022ef50c310eec404cc440fae4a3a405ee7"}, + {file = "nvidia_cuda_sanitizer_api_cu12-12.9.79-py3-none-win_amd64.whl", hash = "sha256:7536fff811aa997239571c601b4a98c26e29209d76f1d3343645d9e5cb320cdc"}, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.4.1.4" +description = "CUFFT native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cufft_cu12-11.4.1.4-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1a28c9b12260a1aa7a8fd12f5ebd82d027963d635ba82ff39a1acfa7c4c0fbcf"}, + {file = "nvidia_cufft_cu12-11.4.1.4-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c67884f2a7d276b4b80eb56a79322a95df592ae5e765cf1243693365ccab4e28"}, + {file = "nvidia_cufft_cu12-11.4.1.4-py3-none-win_amd64.whl", hash = "sha256:8e5bfaac795e93f80611f807d42844e8e27e340e0cde270dcb6c65386d795b80"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.14.1.1" +description = "cuFile GPUDirect libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and sys_platform == \"linux\"" +files = [ + {file = "nvidia_cufile_cu12-1.14.1.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9552e2231792e94b1ff17bc99e958cc0e6bbbaa4a9d91fa2dbeed97716628fe6"}, + {file = "nvidia_cufile_cu12-1.14.1.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:8dea77590761e02cb6dd955a57cb6414c58aa3cb1b7adbf9919869a11509cf65"}, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.10.19" +description = "CURAND native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_curand_cu12-10.3.10.19-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:de663377feb1697e1d30ed587b07d5721fdd6d2015c738d7528a6002a6134d37"}, + {file = "nvidia_curand_cu12-10.3.10.19-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:49b274db4780d421bd2ccd362e1415c13887c53c214f0d4b761752b8f9f6aa1e"}, + {file = "nvidia_curand_cu12-10.3.10.19-py3-none-win_amd64.whl", hash = "sha256:e8129e6ac40dc123bd948e33d3e11b4aa617d87a583fa2f21b3210e90c743cde"}, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.5.82" +description = "CUDA solver native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cusolver_cu12-11.7.5.82-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:62efa83e4ace59a4c734d052bb72158e888aa7b770e1a5f601682f16fe5b4fd2"}, + {file = "nvidia_cusolver_cu12-11.7.5.82-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:15da72d1340d29b5b3cf3fd100e3cd53421dde36002eda6ed93811af63c40d88"}, + {file = "nvidia_cusolver_cu12-11.7.5.82-py3-none-win_amd64.whl", hash = "sha256:77666337237716783c6269a658dea310195cddbd80a5b2919b1ba8735cec8efd"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" +nvidia-cusparse-cu12 = "*" +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.10.65" +description = "CUSPARSE native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_cusparse_cu12-12.5.10.65-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:221c73e7482dd93eda44e65ce567c031c07e2f93f6fa0ecd3ba876a195023e83"}, + {file = "nvidia_cusparse_cu12-12.5.10.65-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:73060ce019ac064a057267c585bf1fd5a353734151f87472ff02b2c5c9984e78"}, + {file = "nvidia_cusparse_cu12-12.5.10.65-py3-none-win_amd64.whl", hash = "sha256:9e487468a22a1eaf1fbd1d2035936a905feb79c4ce5c2f67626764ee4f90227c"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.29.7" +description = "NVIDIA Collective Communication Library (NCCL) Runtime" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "nvidia_nccl_cu12-2.29.7-py3-none-manylinux_2_18_aarch64.whl", hash = "sha256:0cf032ee22b560447daf0456108a75e32bd74a4de6c6b64725637a359fa48cd8"}, + {file = "nvidia_nccl_cu12-2.29.7-py3-none-manylinux_2_18_x86_64.whl", hash = "sha256:ecd0a012051abc20c1aa87328841efa8cade3ced65803046e38c2f03c0891fea"}, +] + +[[package]] +name = "nvidia-npp-cu12" +version = "12.4.1.87" +description = "NPP native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_npp_cu12-12.4.1.87-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:e6680d2a12beca9ce91e61dd2e6121e8e77e820b09c29a419aa36b84aa7fec3a"}, + {file = "nvidia_npp_cu12-12.4.1.87-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:a586435420f08a804ebe83c09f2757d53fdee65364f2129e36d7476ab66c6197"}, + {file = "nvidia_npp_cu12-12.4.1.87-py3-none-win_amd64.whl", hash = "sha256:7c425c400b610eecfb1a08cfc92ecfa4a1927c2ecb691bc26406444c605d30a9"}, +] + +[[package]] +name = "nvidia-nvfatbin-cu12" +version = "12.9.82" +description = "NVIDIA compiler library for fatbin interaction" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_nvfatbin_cu12-12.9.82-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:16cbfbd12287508212f22f42dff6ff51cf9b528b906f57f615b080da16dea1ea"}, + {file = "nvidia_nvfatbin_cu12-12.9.82-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:92d516bdb9287970cecbf855a0fd39d09599db806148038e1ed2cf0eaef92af2"}, + {file = "nvidia_nvfatbin_cu12-12.9.82-py3-none-win_amd64.whl", hash = "sha256:b673b13edcecdec18d87e6b1a1dc3d4ec9a6dbd1012ab9dc8df4873bc0595b12"}, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.9.86" +description = "Nvidia JIT LTO Library" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_nvjitlink_cu12-12.9.86-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:e3f1171dbdc83c5932a45f0f4c99180a70de9bd2718c1ab77d14104f6d7147f9"}, + {file = "nvidia_nvjitlink_cu12-12.9.86-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:994a05ef08ef4b0b299829cde613a424382aff7efb08a7172c1fa616cc3af2ca"}, + {file = "nvidia_nvjitlink_cu12-12.9.86-py3-none-win_amd64.whl", hash = "sha256:cc6fcec260ca843c10e34c936921a1c426b351753587fdd638e8cff7b16bb9db"}, +] + +[[package]] +name = "nvidia-nvjpeg-cu12" +version = "12.4.0.76" +description = "NVJPEG native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_nvjpeg_cu12-12.4.0.76-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f52c5ef7cf56e8bffac8903a59f14494017a52e4fe89d5a1d16c1e88d7bbf194"}, + {file = "nvidia_nvjpeg_cu12-12.4.0.76-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3888f10b32fbd58e80166c48e01073732d752fa5f167b7cb5b9615f1c6375a20"}, + {file = "nvidia_nvjpeg_cu12-12.4.0.76-py3-none-win_amd64.whl", hash = "sha256:21923726db667bd53050d0de88320983ff423322b7f376057dd943e487c40abc"}, +] + +[[package]] +name = "nvidia-nvml-dev-cu12" +version = "12.9.79" +description = "NVML native dev links, headers" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_nvml_dev_cu12-12.9.79-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:311f14749b67467cd05e8077c961841a05f6d25357d1ce11c20f94950e071f3e"}, + {file = "nvidia_nvml_dev_cu12-12.9.79-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bb367913c62cb65be9ae386c58dbf573f1f9e2f01cae54abb87bf5f63c6069e"}, + {file = "nvidia_nvml_dev_cu12-12.9.79-py3-none-win_amd64.whl", hash = "sha256:ff591d178bd6527277e143afe7ab8d94b7535edd6a46746223babff26dd14194"}, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.9.79" +description = "NVIDIA Tools Extension" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "extra == \"cuda\" and (sys_platform == \"win32\" or sys_platform == \"linux\")" +files = [ + {file = "nvidia_nvtx_cu12-12.9.79-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fec150986817f2b4e7eed72ed059f2dcb9ba3856b9a96134e448eac946a6952f"}, + {file = "nvidia_nvtx_cu12-12.9.79-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d1f258e752294acdb4f61c3d31fee87bd0f60e459f1e2f624376369b524cd15d"}, + {file = "nvidia_nvtx_cu12-12.9.79-py3-none-win_amd64.whl", hash = "sha256:1f504e573b3a955e55aae6c747e2ae561b63fdcafcd591e43d18dae9875504f8"}, +] + +[[package]] +name = "nvmath-python" +version = "0.6.0" +description = "NVIDIA Math Python libraries" +optional = true +python-versions = "<3.14,>=3.10" +groups = ["main"] +markers = "extra == \"cuda\"" +files = [ + {file = "nvmath_python-0.6.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:27849b7791394c64b7aec768510e64715cc5bc138498cf35e2db944190931d72"}, + {file = "nvmath_python-0.6.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3a9385a7eea66cd0a5544331a0212a28ae2841cc957fa44409c5ecdd6683eeee"}, + {file = "nvmath_python-0.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd2f557ee2b3b8a741bf3339ec4ce5fa9f668aa83e0ac036e7891626649629d7"}, + {file = "nvmath_python-0.6.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:7117d3dde52401517e71d40c81dc0c21b066beb5878302ce921e04ef2d531bef"}, + {file = "nvmath_python-0.6.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:fd1e4814545e495970342027506382b58fa958624ddf40e4523c9e3a6a91c269"}, + {file = "nvmath_python-0.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:cba4147fecbd568c9acab2d03edb4b8ddf3030b49982c572be478060d06aebf7"}, + {file = "nvmath_python-0.6.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:374c48f92c7aef721e4acade78c731f892e39d3c63611a2d459a058a0dfbef21"}, + {file = "nvmath_python-0.6.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e51230e8a0ddb1c7f767e9299bd5b30f8b80c2eff028278a2dc0394d27303961"}, + {file = "nvmath_python-0.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:dd668762921879303851a9694d1b65fb66f36ad22d010b498bf239110221640f"}, + {file = "nvmath_python-0.6.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2d800543e2dc008e2e22463c66d7908e32ea57b52c081d8584f8d7fffa7896c8"}, + {file = "nvmath_python-0.6.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8b3595175d59b7b4aee5466d5b9c90a3e2e22448b1df0eebf8d4bae85b337f4c"}, + {file = "nvmath_python-0.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:a86215413c7ddd39e7b5d5d0b2a815ec00f56188b2e718af737f0190b58af288"}, +] + +[package.dependencies] +cuda-bindings = "*" +cuda-core = ">=0.3.2,<0.4" +cuda-pathfinder = ">=1.2.1,<2.0" +numpy = ">=1.25,<3" +pywin32 = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +cpu = ["cuda-core (>=0.3.2,<0.4)", "mkl ; platform_machine == \"x86_64\"", "nvpl-fft (>=0.3,<1.0) ; platform_system == \"Linux\" and platform_machine == \"aarch64\""] +cu11 = ["cuda-bindings (>=11.8.7,<12)", "cuda-core[cu11] (==0.3.2)", "cupy-cuda11x", "nvidia-cublas-cu11", "nvidia-cuda-nvrtc-cu11", "nvidia-cufft-cu11", "nvidia-curand-cu11", "nvidia-cusolver-cu11", "nvidia-cusparse-cu11"] +cu12 = ["cuda-bindings (>=12.9.1,<13)", "cuda-core[cu12] (>=0.3.2,<0.4)", "cupy-cuda12x", "nvidia-cublas-cu12", "nvidia-cuda-nvrtc-cu12", "nvidia-cuda-runtime-cu12", "nvidia-cudss-cu12 (==0.5.0.16)", "nvidia-cufft-cu12", "nvidia-curand-cu12", "nvidia-cusolver-cu12", "nvidia-cusparse-cu12"] +cu12-distributed = ["cuda-bindings (>=12.9.1,<13)", "cuda-core[cu12] (>=0.3.2,<0.4)", "cupy-cuda12x", "mpi4py", "nvidia-cublas-cu12", "nvidia-cublasmp-cu12 (>=0.4.0)", "nvidia-cuda-nvrtc-cu12", "nvidia-cuda-runtime-cu12", "nvidia-cudss-cu12 (==0.5.0.16)", "nvidia-cufft-cu12", "nvidia-cufftmp-cu12", "nvidia-curand-cu12", "nvidia-cusolver-cu12", "nvidia-cusparse-cu12", "nvidia-nvshmem-cu12 (>=3.2.5)"] +dx = ["cuda-bindings (>=12.9.1,<13)", "cuda-core[cu12] (>=0.3.2,<0.4)", "cupy-cuda12x", "numba", "numba-cuda (>=0.18.1)", "nvidia-cuda-cccl-cu12 (>12.4.127)", "nvidia-cuda-nvcc-cu12", "nvidia-cuda-nvrtc-cu12 (<12.4.dev0 || >12.5.0)", "nvidia-libmathdx-cu12 (>=0.2.3,<0.3)"] +sysctk11 = ["cuda-bindings (>=11.8.7,<12)", "cuda-core (==0.3.2)", "cupy-cuda11x"] +sysctk12 = ["cuda-bindings (>=12.9.1,<13)", "cuda-core (>=0.3.2,<0.4)", "cupy-cuda12x"] +sysctk12-dx = ["cuda-bindings (>=12.9.1,<13)", "cuda-core (>=0.3.2,<0.4)", "cupy-cuda12x", "numba", "numba-cuda (>=0.18.1)"] + +[[package]] +name = "openqasm3" +version = "1.0.1" +description = "Reference OpenQASM AST in Python" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "openqasm3-1.0.1-py3-none-any.whl", hash = "sha256:0d3a1ebe3465e3ea619bcaa369858bba8944cbb0c49604b24f94662d3ec41d41"}, + {file = "openqasm3-1.0.1.tar.gz", hash = "sha256:c589dc05d4ced50ca24167d14e0f2c916e717499ba0442e0ff2a3030ef312d0a"}, +] + +[package.dependencies] +antlr4_python3_runtime = {version = ">=4.7,<4.14", optional = true, markers = "extra == \"parser\""} + +[package.extras] +all = ["antlr4_python3_runtime (>=4.7,<4.14)", "importlib_metadata ; python_version < \"3.10\"", "pytest (>=6.0)", "pyyaml"] +parser = ["antlr4_python3_runtime (>=4.7,<4.14)", "importlib_metadata ; python_version < \"3.10\""] +tests = ["pytest (>=6.0)", "pyyaml"] + +[[package]] +name = "optuna" +version = "4.8.0" +description = "A hyperparameter optimization framework" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "optuna-4.8.0-py3-none-any.whl", hash = "sha256:c57a7682679c36bfc9bca0da430698179e513874074b71bebedb0334964ab930"}, + {file = "optuna-4.8.0.tar.gz", hash = "sha256:6f7043e9f8ecb5e607af86a7eb00fb5ec2be26c3b08c201209a73d36aff37a38"}, +] + +[package.dependencies] +alembic = ">=1.5.0" +colorlog = "*" +numpy = "*" +packaging = ">=20.0" +PyYAML = "*" +sqlalchemy = ">=1.4.2" +tqdm = "*" + +[package.extras] +checking = ["mypy", "mypy_boto3_s3", "ruff", "scipy-stubs ; python_version >= \"3.10\"", "types-PyYAML", "types-redis", "types-setuptools", "types-tqdm", "typing_extensions (>=3.10.0.0)"] +document = ["ase", "cmaes (>=0.12.0)", "fvcore", "kaleido (<0.4)", "lightgbm", "matplotlib (!=3.6.0)", "pandas", "pillow", "plotly (>=4.9.0)", "scikit-learn", "sphinx", "sphinx-copybutton", "sphinx-gallery", "sphinx-notfound-page", "sphinx_rtd_theme (>=1.2.0)", "torch", "torchvision"] +optional = ["boto3", "cmaes (>=0.12.0)", "google-cloud-storage", "greenlet", "grpcio", "matplotlib (!=3.6.0)", "pandas", "plotly (>=4.9.0)", "protobuf (>=5.28.1)", "redis", "scikit-learn (>=0.24.2)", "scipy", "torch"] +test = ["fakeredis[lua]", "greenlet", "grpcio", "kaleido (<0.4)", "moto", "protobuf (>=5.28.1)", "pytest", "pytest-xdist", "scipy (>=1.9.2)", "torch"] + +[[package]] +name = "packaging" +version = "26.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main", "docs", "tests"] +files = [ + {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, + {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, +] + +[[package]] +name = "parso" +version = "0.8.6" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff"}, + {file = "parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd"}, +] + +[package.extras] +qa = ["flake8 (==5.0.4)", "types-setuptools (==67.2.0.1)", "zuban (==0.5.1)"] +testing = ["docopt", "pytest"] + +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +groups = ["dev"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pillow" +version = "12.2.0" +description = "Python Imaging Library (fork)" +optional = true +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "pillow-12.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:a4e8f36e677d3336f35089648c8955c51c6d386a13cf6ee9c189c5f5bd713a9f"}, + {file = "pillow-12.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e589959f10d9824d39b350472b92f0ce3b443c0a3442ebf41c40cb8361c5b97"}, + {file = "pillow-12.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a52edc8bfff4429aaabdf4d9ee0daadbbf8562364f940937b941f87a4290f5ff"}, + {file = "pillow-12.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:975385f4776fafde056abb318f612ef6285b10a1f12b8570f3647ad0d74b48ec"}, + {file = "pillow-12.2.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd9c0c7a0c681a347b3194c500cb1e6ca9cab053ea4d82a5cf45b6b754560136"}, + {file = "pillow-12.2.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:88d387ff40b3ff7c274947ed3125dedf5262ec6919d83946753b5f3d7c67ea4c"}, + {file = "pillow-12.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:51c4167c34b0d8ba05b547a3bb23578d0ba17b80a5593f93bd8ecb123dd336a3"}, + {file = "pillow-12.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:34c0d99ecccea270c04882cb3b86e7b57296079c9a4aff88cb3b33563d95afaa"}, + {file = "pillow-12.2.0-cp310-cp310-win32.whl", hash = "sha256:b85f66ae9eb53e860a873b858b789217ba505e5e405a24b85c0464822fe88032"}, + {file = "pillow-12.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:673aa32138f3e7531ccdbca7b3901dba9b70940a19ccecc6a37c77d5fdeb05b5"}, + {file = "pillow-12.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:3e080565d8d7c671db5802eedfb438e5565ffa40115216eabb8cd52d0ecce024"}, + {file = "pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab"}, + {file = "pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65"}, + {file = "pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7"}, + {file = "pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e"}, + {file = "pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705"}, + {file = "pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176"}, + {file = "pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b"}, + {file = "pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909"}, + {file = "pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808"}, + {file = "pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60"}, + {file = "pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe"}, + {file = "pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5"}, + {file = "pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421"}, + {file = "pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987"}, + {file = "pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76"}, + {file = "pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005"}, + {file = "pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780"}, + {file = "pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5"}, + {file = "pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5"}, + {file = "pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940"}, + {file = "pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5"}, + {file = "pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414"}, + {file = "pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c"}, + {file = "pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2"}, + {file = "pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c"}, + {file = "pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795"}, + {file = "pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f"}, + {file = "pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed"}, + {file = "pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9"}, + {file = "pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed"}, + {file = "pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3"}, + {file = "pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9"}, + {file = "pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795"}, + {file = "pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e"}, + {file = "pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b"}, + {file = "pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06"}, + {file = "pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b"}, + {file = "pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f"}, + {file = "pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612"}, + {file = "pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c"}, + {file = "pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea"}, + {file = "pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4"}, + {file = "pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4"}, + {file = "pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea"}, + {file = "pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24"}, + {file = "pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98"}, + {file = "pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453"}, + {file = "pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8"}, + {file = "pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b"}, + {file = "pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295"}, + {file = "pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed"}, + {file = "pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae"}, + {file = "pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601"}, + {file = "pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be"}, + {file = "pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f"}, + {file = "pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286"}, + {file = "pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50"}, + {file = "pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104"}, + {file = "pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7"}, + {file = "pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150"}, + {file = "pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1"}, + {file = "pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463"}, + {file = "pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3"}, + {file = "pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166"}, + {file = "pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe"}, + {file = "pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd"}, + {file = "pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e"}, + {file = "pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06"}, + {file = "pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43"}, + {file = "pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354"}, + {file = "pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1"}, + {file = "pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb"}, + {file = "pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f"}, + {file = "pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d"}, + {file = "pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f"}, + {file = "pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e"}, + {file = "pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0"}, + {file = "pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1"}, + {file = "pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e"}, + {file = "pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] +test-arrow = ["arro3-compute", "arro3-core", "nanoarrow", "pyarrow"] +tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma (>=5)", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] +xmp = ["defusedxml"] + +[[package]] +name = "platformdirs" +version = "4.9.4" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.10" +groups = ["analysis"] +files = [ + {file = "platformdirs-4.9.4-py3-none-any.whl", hash = "sha256:68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868"}, + {file = "platformdirs-4.9.4.tar.gz", hash = "sha256:1ec356301b7dc906d83f371c8f487070e99d3ccf9e501686456394622a01a934"}, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +groups = ["tests"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, + {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "psutil" +version = "5.9.8" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +groups = ["main"] +files = [ + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, +] + +[package.extras] +test = ["enum34 ; python_version <= \"3.4\"", "ipaddress ; python_version < \"3.0\"", "mock ; python_version < \"3.0\"", "pywin32 ; sys_platform == \"win32\"", "wmi ; sys_platform == \"win32\""] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +groups = ["dev"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, + {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "pybtex" +version = "0.26.1" +description = "A BibTeX-compatible bibliography processor in Python" +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "pybtex-0.26.1-py3-none-any.whl", hash = "sha256:e26c0412cc54f5f21b2a6d9d175762a2d2af9ccf3a8f651cdb89ec035db77aa1"}, + {file = "pybtex-0.26.1.tar.gz", hash = "sha256:2e5543bea424e60e9e42eef70bff597be48649d8f68ba061a7a092b2477d5464"}, +] + +[package.dependencies] +latexcodec = ">=1.0.4" +pyyaml = ">=3.01" + +[[package]] +name = "pybtex-docutils" +version = "1.0.3" +description = "A docutils backend for pybtex." +optional = false +python-versions = ">=3.7" +groups = ["docs"] +files = [ + {file = "pybtex-docutils-1.0.3.tar.gz", hash = "sha256:3a7ebdf92b593e00e8c1c538aa9a20bca5d92d84231124715acc964d51d93c6b"}, + {file = "pybtex_docutils-1.0.3-py3-none-any.whl", hash = "sha256:8fd290d2ae48e32fcb54d86b0efb8d573198653c7e2447d5bec5847095f430b9"}, +] + +[package.dependencies] +docutils = ">=0.14" +pybtex = ">=0.16" + +[[package]] +name = "pygments" +version = "2.20.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.9" +groups = ["dev", "docs", "tests"] +files = [ + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pylint" +version = "3.3.9" +description = "python code static checker" +optional = false +python-versions = ">=3.9.0" +groups = ["analysis"] +files = [ + {file = "pylint-3.3.9-py3-none-any.whl", hash = "sha256:01f9b0462c7730f94786c283f3e52a1fbdf0494bbe0971a78d7277ef46a751e7"}, + {file = "pylint-3.3.9.tar.gz", hash = "sha256:d312737d7b25ccf6b01cc4ac629b5dcd14a0fcf3ec392735ac70f137a9d5f83a"}, +] + +[package.dependencies] +astroid = ">=3.3.8,<=3.4.0.dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.3.6", markers = "python_version == \"3.11\""}, +] +isort = ">=4.2.5,<5.13 || >5.13,<7" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2" +tomlkit = ">=0.10.1" + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pyparsing" +version = "3.3.2" +description = "pyparsing - Classes and methods to define and execute parsing grammars" +optional = true +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, + {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pytest" +version = "9.0.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.10" +groups = ["tests"] +files = [ + {file = "pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9"}, + {file = "pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +iniconfig = ">=1.0.1" +packaging = ">=22" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "4.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.7" +groups = ["tests"] +files = [ + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "pytest-env" +version = "1.2.0" +description = "pytest plugin that allows you to add environment variables." +optional = false +python-versions = ">=3.10" +groups = ["tests"] +files = [ + {file = "pytest_env-1.2.0-py3-none-any.whl", hash = "sha256:d7e5b7198f9b83c795377c09feefa45d56083834e60d04767efd64819fc9da00"}, + {file = "pytest_env-1.2.0.tar.gz", hash = "sha256:475e2ebe8626cee01f491f304a74b12137742397d6c784ea4bc258f069232b80"}, +] + +[package.dependencies] +pytest = ">=8.4.2" + +[package.extras] +testing = ["covdefaults (>=2.3)", "coverage (>=7.10.7)", "pytest-mock (>=3.15.1)"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pywin32" +version = "311" +description = "Python for Window Extensions" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"cuda\" and platform_system == \"Windows\"" +files = [ + {file = "pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3"}, + {file = "pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b"}, + {file = "pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b"}, + {file = "pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151"}, + {file = "pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503"}, + {file = "pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2"}, + {file = "pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31"}, + {file = "pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067"}, + {file = "pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852"}, + {file = "pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d"}, + {file = "pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d"}, + {file = "pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a"}, + {file = "pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee"}, + {file = "pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87"}, + {file = "pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42"}, + {file = "pywin32-311-cp38-cp38-win32.whl", hash = "sha256:6c6f2969607b5023b0d9ce2541f8d2cbb01c4f46bc87456017cf63b73f1e2d8c"}, + {file = "pywin32-311-cp38-cp38-win_amd64.whl", hash = "sha256:c8015b09fb9a5e188f83b7b04de91ddca4658cee2ae6f3bc483f0b21a77ef6cd"}, + {file = "pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b"}, + {file = "pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91"}, + {file = "pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "docs"] +files = [ + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, +] + +[[package]] +name = "qibo" +version = "0.3.2" +description = "A framework for quantum computing with hardware acceleration." +optional = false +python-versions = "<3.14,>=3.10" +groups = ["main"] +files = [ + {file = "qibo-0.3.2-py3-none-any.whl", hash = "sha256:c6883daa7fe664f916e069fe345156631daf5e598e55044e6891b8200aaf6400"}, + {file = "qibo-0.3.2.tar.gz", hash = "sha256:8f21d98ebee9d8575b5ee6bcd6d9cebbb37ebb34960eebd79037b622f34ff798"}, +] + +[package.dependencies] +cma = ">=3.4.0,<4.0.0" +joblib = ">=1.4.2,<2.0.0" +networkx = ">=3.2.1,<4.0.0" +numpy = ">=2.0.0,<3.0.0" +openqasm3 = {version = ">=1.0.1,<2.0.0", extras = ["parser"]} +optuna = ">=4.2.1,<5.0.0" +scipy = ">=1.15.2,<2.0.0" +sympy = ">=1.13.1,<2.0.0" +tabulate = ">=0.9.0,<0.10.0" + +[package.extras] +cudaq = ["qbraid[cudaq,qir] (>=0.10.0,<0.11.0)", "qbraid[cudaq] (>=0.10.0,<0.11.0)"] +qir = ["qbraid[cudaq,qir] (>=0.10.0,<0.11.0)", "qbraid[qir] (>=0.10.0,<0.11.0)"] +qulacs = ["qulacs (>=0.6.4,<0.7.0) ; python_version < \"3.13\""] + +[[package]] +name = "qibojit" +version = "0.1.15" +description = "Simulation tools based on numba and cupy." +optional = false +python-versions = "<3.14,>=3.10" +groups = ["main"] +files = [ + {file = "qibojit-0.1.15-py3-none-any.whl", hash = "sha256:211ad0d9ae5c06623b0efffcbd87917231eef2fe1c343f1b57788d6e0c3d7b14"}, + {file = "qibojit-0.1.15.tar.gz", hash = "sha256:c9f82aaac988f778e6e8eb989184e54875b181314ea718ab017b1786688e63a5"}, +] + +[package.dependencies] +numba = ">=0.61.0,<0.62.0" +psutil = ">=5.9.5,<6.0.0" +qibo = ">=0.3.2,<0.4.0" +scipy = ">=1.10.1,<2.0.0" + +[[package]] +name = "qiskit" +version = "1.4.5" +description = "An open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives." +optional = true +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "qiskit-1.4.5-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3b2e12192778942ff1c7ace26be7fa05bdb96cb3b61e932682a62c40ef026aa2"}, + {file = "qiskit-1.4.5-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:595eca31dc09b53eaf811ffadd328b98b03e6dfe025c94d62ccae9ef845a5cd9"}, + {file = "qiskit-1.4.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bed7c45486e624e6b0c7416b0bc46d34d43b1fe0698fdd1f5a820af1dcb2e6f2"}, + {file = "qiskit-1.4.5-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da16929ace8e12cc08b395838420ff2dad5963a9d06c6a038c023aa572196531"}, + {file = "qiskit-1.4.5-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fd77df822ad3e0cfb4f9523d2943d3e672bb7049a4f6c2a448f6962759808ad"}, + {file = "qiskit-1.4.5-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:629eb135738b4b3c59900626c285ea8e919f82e104fde6a76f6fccd199169063"}, + {file = "qiskit-1.4.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58fbe190e21c3e2e8a92895766b07b795ad261de0fd0e50fd367f442dbd94475"}, + {file = "qiskit-1.4.5-cp39-abi3-win32.whl", hash = "sha256:c27b8783d726f06185a1e7b7c8719427cca7016014c876e06579090509a3d380"}, + {file = "qiskit-1.4.5-cp39-abi3-win_amd64.whl", hash = "sha256:3b4f5e520834a6636aadaf4241eed5350b95dae4dd4989a0761cee18518f19c4"}, + {file = "qiskit-1.4.5.tar.gz", hash = "sha256:b7e8734e4d5abae59e500e92bde73cc7e5f69c1de47a12cd367e59fcfa29402f"}, +] + +[package.dependencies] +dill = ">=0.3" +numpy = ">=1.17,<3" +python-dateutil = ">=2.8.0" +rustworkx = ">=0.15.0" +scipy = ">=1.5" +stevedore = ">=3.0.0" +symengine = ">=0.11,<0.14" +sympy = ">=1.3" +typing-extensions = "*" + +[package.extras] +all = ["qiskit[crosstalk-pass,csp-layout-pass,qasm3-import,visualization]"] +crosstalk-pass = ["z3-solver (>=4.7)"] +csp-layout-pass = ["python-constraint (>=1.4)"] +qasm3-import = ["qiskit-qasm3-import (>=0.1.0)"] +visualization = ["Pillow (>=4.2.1)", "matplotlib (>=3.3)", "pydot", "pylatexenc (>=1.4)", "seaborn (>=0.9.0)"] + +[[package]] +name = "qmatchatea" +version = "1.5.7" +description = "Quantum matcha TEA python library for tensor network emulation of quantum circuits." +optional = true +python-versions = ">=3.11" +groups = ["main"] +markers = "extra == \"qmatchatea\"" +files = [ + {file = "qmatchatea-1.5.7-py3-none-any.whl", hash = "sha256:675cdeba60c6a7dc2993e5f11238a8090fb87152b41b4922d25408bb569acd56"}, + {file = "qmatchatea-1.5.7.tar.gz", hash = "sha256:24f9caa785becc54e103b3a0bc98dd5c8cae7160ffc1bb2e315344c57c9bd2bb"}, +] + +[package.dependencies] +joblib = "*" +matplotlib = ">=3.1.3" +numpy = ">=1.26.0" +psutil = "*" +qiskit = ">=1.0.0,<2.0.0" +qredtea = ">=0.3.13,<0.4.0" +qtealeaves = ">=1.7.21,<1.8.0" +scipy = ">=1.4.1" + +[package.extras] +cqa = ["black (==24.4.2)", "isort (==5.13.2)", "pre-commit", "pylint (==3.2.4)"] +dev = ["qmatchatea[cqa]", "qmatchatea[tests]"] +docs = ["sphinx", "sphinx-gallery", "sphinx_rtd_theme"] +tests = ["pytest", "pytest-cov", "pytest-subtests"] + +[[package]] +name = "qredtea" +version = "0.3.15" +description = "Quantum TEA's python tensor library beyond numpy/cupy" +optional = true +python-versions = ">=3.11" +groups = ["main"] +markers = "extra == \"qmatchatea\"" +files = [ + {file = "qredtea-0.3.15-py3-none-any.whl", hash = "sha256:71a9c56ec8d8d00689694a8d10e7a7eda44cf949f3692f4545e14382ef16d2f2"}, + {file = "qredtea-0.3.15.tar.gz", hash = "sha256:9b7ef77cc48d130b21face3d9c68ff2c7be0f7d0b5841178fa3c95d5d99c7140"}, +] + +[package.dependencies] +matplotlib = "*" +numpy = ">=1.26.0,<2.1.4" +qtealeaves = ">=1.7.18,<1.8.0" +scipy = "*" + +[package.extras] +all-backends = ["qredtea[jax]", "qredtea[qtorch]", "qredtea[tensorflow]", "qredtea[torch]"] +all-backends-cpu = ["qredtea[jax-cpu]", "qredtea[qtorch]", "qredtea[tensorflow-cpu]", "qredtea[torch]"] +cqa = ["black (==24.4.2)", "isort (==5.13.2)", "pre-commit", "pylint (==3.2.4)"] +dev = ["qredtea[cqa]", "qredtea[tests]"] +docs = ["sphinx", "sphinx-gallery", "sphinx_rtd_theme"] +jax = ["jax[cuda12-local] (>=0.5.0,<0.6.0)"] +jax-cpu = ["jax (>=0.5.0,<0.6.0)"] +qtorch = ["ninja", "qtorch"] +tensorflow = ["tensorflow[and-cuda] (>=2.19.0,<2.21.0)"] +tensorflow-cpu = ["tensorflow (>=2.19.0,<2.21.0)"] +tests = ["pytest", "pytest-cov", "pytest-subtests"] +torch = ["torch (>=2.5.0,<2.11)"] + +[[package]] +name = "qtealeaves" +version = "1.7.32" +description = "Quantum TEA's python tensor network library" +optional = true +python-versions = ">=3.11" +groups = ["main"] +files = [ + {file = "qtealeaves-1.7.32-py3-none-any.whl", hash = "sha256:13705b2857377079517993c78cc5bfb6f6cf140e5191a8577a79aa5d14ce3ddf"}, + {file = "qtealeaves-1.7.32.tar.gz", hash = "sha256:9c8a22f81cc4f8a6ae79f81233b9812522492a86c15595880ea1f8c4f7aaddd7"}, +] + +[package.dependencies] +h5py = "*" +joblib = "*" +matplotlib = "*" +mpmath = "*" +numpy = ">=1.26.0" +scipy = "*" + +[package.extras] +cqa = ["black (==24.4.2)", "isort (==5.13.2)", "pre-commit", "pylint (==3.2.4)"] +dev = ["qtealeaves[cqa]", "qtealeaves[tests]"] +docs = ["sphinx", "sphinx-gallery", "sphinx_rtd_theme"] +gpu = ["cupy-cuda12x"] +tests = ["pytest", "pytest-cov", "pytest-subtests", "pytest-xdist"] + +[[package]] +name = "quimb" +version = "1.13.0" +description = "Quantum information and many-body library." +optional = false +python-versions = ">=3.11" +groups = ["main"] +files = [ + {file = "quimb-1.13.0-py3-none-any.whl", hash = "sha256:861862ca9a03c91476ca9e013f9da6df80fa2d53783a6a6f206e8862fd87f358"}, + {file = "quimb-1.13.0.tar.gz", hash = "sha256:efc9aa5f32b69ada50b5950d1eb0d104100903aecbf8a6615e95fa1073aa9f68"}, +] + +[package.dependencies] +autoray = ">=0.8" +cotengra = ">=0.7.1" +cytoolz = ">=0.8.0" +numba = ">=0.39" +numpy = ">=1.17" +psutil = ">=4.3.1" +scipy = ">=1.16.0" +tqdm = ">=4" + +[package.extras] +advanced-solvers = ["mpi4py", "petsc4py", "slepc4py"] +docs = ["astroid", "doc2dash (>=2.4.1)", "furo", "ipython (!=8.7.0)", "myst-nb", "setuptools-scm", "sphinx (>=2.0)", "sphinx-autoapi", "sphinx-copybutton", "sphinx-design"] +recommended = ["autograd", "cmaes", "cotengrust", "kahypar", "matplotlib", "networkx", "plotly", "pygraphviz"] +tests = ["coverage", "pytest", "pytest-cov"] + +[[package]] +name = "requests" +version = "2.33.1" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.10" +groups = ["docs"] +files = [ + {file = "requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a"}, + {file = "requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517"}, +] + +[package.dependencies] +certifi = ">=2023.5.7" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.26,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<8)"] + +[[package]] +name = "rustworkx" +version = "0.17.1" +description = "A High-Performance Graph Library for Python" +optional = true +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "rustworkx-0.17.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c08fb8db041db052da404839b064ebfb47dcce04ba9a3e2eb79d0c65ab011da4"}, + {file = "rustworkx-0.17.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:4ef8e327dadf6500edd76fedb83f6d888b9266c58bcdbffd5a40c33835c9dd26"}, + {file = "rustworkx-0.17.1-cp39-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b809e0aa2927c68574b196f993233e269980918101b0dd235289c4f3ddb2115"}, + {file = "rustworkx-0.17.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7e82c46a92fb0fd478b7372e15ca524c287485fdecaed37b8bb68f4df2720f2"}, + {file = "rustworkx-0.17.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42170075d8a7319e89ff63062c2f1d1116ced37b6f044f3bf36d10b60a107aa4"}, + {file = "rustworkx-0.17.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65cba97fa95470239e2d65eb4db1613f78e4396af9f790ff771b0e5476bfd887"}, + {file = "rustworkx-0.17.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246cc252053f89e36209535b9c58755960197e6ae08d48d3973760141c62ac95"}, + {file = "rustworkx-0.17.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c10d25e9f0e87d6a273d1ea390b636b4fb3fede2094bf0cb3fe565d696a91b48"}, + {file = "rustworkx-0.17.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:48784a673cf8d04f3cd246fa6b53fd1ccc4d83304503463bd561c153517bccc1"}, + {file = "rustworkx-0.17.1-cp39-abi3-win32.whl", hash = "sha256:5dbc567833ff0a8ad4580a4fe4bde92c186d36b4c45fca755fb1792e4fafe9b5"}, + {file = "rustworkx-0.17.1-cp39-abi3-win_amd64.whl", hash = "sha256:d0a48fb62adabd549f9f02927c3a159b51bf654c7388a12fc16d45452d5703ea"}, + {file = "rustworkx-0.17.1.tar.gz", hash = "sha256:59ea01b4e603daffa4e8827316c1641eef18ae9032f0b1b14aa0181687e3108e"}, +] + +[package.dependencies] +numpy = ">=1.16.0,<3" + +[package.extras] +all = ["matplotlib (>=3.0)", "pillow (>=5.4)"] +graphviz = ["pillow (>=5.4)"] +mpl = ["matplotlib (>=3.0)"] + +[[package]] +name = "scipy" +version = "1.17.1" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.11" +groups = ["main"] +files = [ + {file = "scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec"}, + {file = "scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696"}, + {file = "scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee"}, + {file = "scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd"}, + {file = "scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c"}, + {file = "scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4"}, + {file = "scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444"}, + {file = "scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082"}, + {file = "scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff"}, + {file = "scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d"}, + {file = "scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8"}, + {file = "scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76"}, + {file = "scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086"}, + {file = "scipy-1.17.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:c80be5ede8f3f8eded4eff73cc99a25c388ce98e555b17d31da05287015ffa5b"}, + {file = "scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e19ebea31758fac5893a2ac360fedd00116cbb7628e650842a6691ba7ca28a21"}, + {file = "scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02ae3b274fde71c5e92ac4d54bc06c42d80e399fec704383dcd99b301df37458"}, + {file = "scipy-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a604bae87c6195d8b1045eddece0514d041604b14f2727bbc2b3020172045eb"}, + {file = "scipy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f590cd684941912d10becc07325a3eeb77886fe981415660d9265c4c418d0bea"}, + {file = "scipy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:41b71f4a3a4cab9d366cd9065b288efc4d4f3c0b37a91a8e0947fb5bd7f31d87"}, + {file = "scipy-1.17.1-cp312-cp312-win_arm64.whl", hash = "sha256:f4115102802df98b2b0db3cce5cb9b92572633a1197c77b7553e5203f284a5b3"}, + {file = "scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c"}, + {file = "scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f"}, + {file = "scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d"}, + {file = "scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b"}, + {file = "scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6"}, + {file = "scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464"}, + {file = "scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950"}, + {file = "scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369"}, + {file = "scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448"}, + {file = "scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87"}, + {file = "scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a"}, + {file = "scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0"}, + {file = "scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce"}, + {file = "scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6"}, + {file = "scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e"}, + {file = "scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475"}, + {file = "scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50"}, + {file = "scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca"}, + {file = "scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c"}, + {file = "scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49"}, + {file = "scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717"}, + {file = "scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9"}, + {file = "scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b"}, + {file = "scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866"}, + {file = "scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350"}, + {file = "scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118"}, + {file = "scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068"}, + {file = "scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118"}, + {file = "scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19"}, + {file = "scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293"}, + {file = "scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6"}, + {file = "scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1"}, + {file = "scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39"}, + {file = "scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca"}, + {file = "scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad"}, + {file = "scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a"}, + {file = "scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4"}, + {file = "scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2"}, + {file = "scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484"}, + {file = "scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21"}, + {file = "scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0"}, +] + +[package.dependencies] +numpy = ">=1.26.4,<2.7" + +[package.extras] +dev = ["click (<8.3.0)", "cython-lint (>=0.12.2)", "mypy (==1.10.0)", "pycodestyle", "ruff (>=0.12.0)", "spin", "types-psutil", "typing_extensions"] +doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "linkify-it-py", "matplotlib (>=3.5)", "myst-nb (>=1.2.0)", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.2.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)", "tabulate"] +test = ["Cython", "array-api-strict (>=2.3.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest (>=8.0.0)", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" +groups = ["docs"] +files = [ + {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, + {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, +] + +[[package]] +name = "soupsieve" +version = "2.8.3" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95"}, + {file = "soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349"}, +] + +[[package]] +name = "sphinx" +version = "5.3.0" +description = "Python documentation generator" +optional = false +python-versions = ">=3.6" +groups = ["docs"] +files = [ + {file = "Sphinx-5.3.0.tar.gz", hash = "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5"}, + {file = "sphinx-5.3.0-py3-none-any.whl", hash = "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d"}, +] + +[package.dependencies] +alabaster = ">=0.7,<0.8" +babel = ">=2.9" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.14,<0.20" +imagesize = ">=1.3" +Jinja2 = ">=3.0" +packaging = ">=21.0" +Pygments = ">=2.12" +requests = ">=2.5.0" +snowballstemmer = ">=2.0" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "types-requests", "types-typed-ast"] +test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast ; python_version < \"3.8\""] + +[[package]] +name = "sphinx-basic-ng" +version = "1.0.0b2" +description = "A modern skeleton for Sphinx themes." +optional = false +python-versions = ">=3.7" +groups = ["docs"] +files = [ + {file = "sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b"}, + {file = "sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9"}, +] + +[package.dependencies] +sphinx = ">=4.0" + +[package.extras] +docs = ["furo", "ipython", "myst-parser", "sphinx-copybutton", "sphinx-inline-tabs"] + +[[package]] +name = "sphinx-copybutton" +version = "0.5.2" +description = "Add a copy button to each of your code cells." +optional = false +python-versions = ">=3.7" +groups = ["docs"] +files = [ + {file = "sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd"}, + {file = "sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e"}, +] + +[package.dependencies] +sphinx = ">=1.8" + +[package.extras] +code-style = ["pre-commit (==2.12.1)"] +rtd = ["ipython", "myst-nb", "sphinx", "sphinx-book-theme", "sphinx-examples"] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-bibtex" +version = "2.6.5" +description = "Sphinx extension for BibTeX style citations." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_bibtex-2.6.5-py3-none-any.whl", hash = "sha256:455ea4509642ea0b28ede3721550273626f85af65af01f161bfd8e19dc1edd7d"}, + {file = "sphinxcontrib_bibtex-2.6.5.tar.gz", hash = "sha256:9b3224dd6fece9268ebd8c905dc0a83ff2f6c54148a9235fe70e9d1e9ff149c0"}, +] + +[package.dependencies] +docutils = ">=0.8,<0.18.dev0 || >=0.20.dev0" +pybtex = ">=0.25" +pybtex-docutils = ">=1.0.0" +Sphinx = ">=3.5" + +[package.extras] +test = ["pytest", "pytest-cov", "sphinx-autoapi"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["html5lib", "pytest"] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +optional = false +python-versions = ">=3.5" +groups = ["docs"] +files = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] + +[package.extras] +test = ["flake8", "mypy", "pytest"] + +[[package]] +name = "sphinxcontrib-katex" +version = "0.9.11" +description = "A Sphinx extension for rendering math in HTML pages" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_katex-0.9.11-py3-none-any.whl", hash = "sha256:b0a318d86b8f43314ccdd481ce0db90283ac51f51afd9479969f36a0c291f44e"}, + {file = "sphinxcontrib_katex-0.9.11.tar.gz", hash = "sha256:2d32b210d20bbee451a51d19645f6fef5f5568b9a54e2813affb96efa661238a"}, +] + +[package.dependencies] +sphinx = ">=1.6" + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["defusedxml (>=0.7.1)", "pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["pytest"] + +[[package]] +name = "sqlalchemy" +version = "2.0.49" +description = "Database Abstraction Library" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "sqlalchemy-2.0.49-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:42e8804962f9e6f4be2cbaedc0c3718f08f60a16910fa3d86da5a1e3b1bfe60f"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc992c6ed024c8c3c592c5fc9846a03dd68a425674900c70122c77ea16c5fb0b"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6eb188b84269f357669b62cb576b5b918de10fb7c728a005fa0ebb0b758adce1"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:62557958002b69699bdb7f5137c6714ca1133f045f97b3903964f47db97ea339"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da9b91bca419dc9b9267ffadde24eae9b1a6bffcd09d0a207e5e3af99a03ce0d"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-win32.whl", hash = "sha256:5e61abbec255be7b122aa461021daa7c3f310f3e743411a67079f9b3cc91ece3"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-win_amd64.whl", hash = "sha256:0c98c59075b890df8abfcc6ad632879540f5791c68baebacb4f833713b510e75"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5070135e1b7409c4161133aa525419b0062088ed77c92b1da95366ec5cbebbe"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9ac7a3e245fd0310fd31495eb61af772e637bdf7d88ee81e7f10a3f271bff014"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d4e5a0ceba319942fa6b585cf82539288a61e314ef006c1209f734551ab9536"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ddcb27fb39171de36e207600116ac9dfd4ae46f86c82a9bf3934043e80ebb88"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:32fe6a41ad97302db2931f05bb91abbcc65b5ce4c675cd44b972428dd2947700"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-win32.whl", hash = "sha256:46d51518d53edfbe0563662c96954dc8fcace9832332b914375f45a99b77cc9a"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-win_amd64.whl", hash = "sha256:951d4a210744813be63019f3df343bf233b7432aadf0db54c75802247330d3af"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4bbccb45260e4ff1b7db0be80a9025bb1e6698bdb808b83fff0000f7a90b2c0b"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb37f15714ec2652d574f021d479e78cd4eb9d04396dca36568fdfffb3487982"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb9ec6436a820a4c006aad1ac351f12de2f2dbdaad171692ee457a02429b672"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8d6efc136f44a7e8bc8088507eaabbb8c2b55b3dbb63fe102c690da0ddebe55e"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e06e617e3d4fd9e51d385dfe45b077a41e9d1b033a7702551e3278ac597dc750"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-win32.whl", hash = "sha256:83101a6930332b87653886c01d1ee7e294b1fe46a07dd9a2d2b4f91bcc88eec0"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-win_amd64.whl", hash = "sha256:618a308215b6cececb6240b9abde545e3acdabac7ae3e1d4e666896bf5ba44b4"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df2d441bacf97022e81ad047e1597552eb3f83ca8a8f1a1fdd43cd7fe3898120"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e20e511dc15265fb433571391ba313e10dd8ea7e509d51686a51313b4ac01a2"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47604cb2159f8bbd5a1ab48a714557156320f20871ee64d550d8bf2683d980d3"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:22d8798819f86720bc646ab015baff5ea4c971d68121cb36e2ebc2ee43ead2b7"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b1c058c171b739e7c330760044803099c7fff11511e3ab3573e5327116a9c33"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-win32.whl", hash = "sha256:a143af2ea6672f2af3f44ed8f9cd020e9cc34c56f0e8db12019d5d9ecf41cb3b"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-win_amd64.whl", hash = "sha256:12b04d1db2663b421fe072d638a138460a51d5a862403295671c4f3987fb9148"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24bd94bb301ec672d8f0623eba9226cc90d775d25a0c92b5f8e4965d7f3a1518"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a51d3db74ba489266ef55c7a4534eb0b8db9a326553df481c11e5d7660c8364d"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:55250fe61d6ebfd6934a272ee16ef1244e0f16b7af6cd18ab5b1fc9f08631db0"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:46796877b47034b559a593d7e4b549aba151dae73f9e78212a3478161c12ab08"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-win32.whl", hash = "sha256:9c4969a86e41454f2858256c39bdfb966a20961e9b58bf8749b65abf447e9a8d"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-win_amd64.whl", hash = "sha256:b9870d15ef00e4d0559ae10ee5bc71b654d1f20076dbe8bc7ed19b4c0625ceba"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:233088b4b99ebcbc5258c755a097aa52fbf90727a03a5a80781c4b9c54347a2e"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57ca426a48eb2c682dae8204cd89ea8ab7031e2675120a47924fabc7caacbc2a"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:685e93e9c8f399b0c96a624799820176312f5ceef958c0f88215af4013d29066"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e0400fa22f79acc334d9a6b185dc00a44a8e6578aa7e12d0ddcd8434152b187"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a05977bffe9bffd2229f477fa75eabe3192b1b05f408961d1bebff8d1cd4d401"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-win32.whl", hash = "sha256:0f2fa354ba106eafff2c14b0cc51f22801d1e8b2e4149342023bd6f0955de5f5"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-win_amd64.whl", hash = "sha256:77641d299179c37b89cf2343ca9972c88bb6eef0d5fc504a2f86afd15cd5adf5"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c1dc3368794d522f43914e03312202523cc89692f5389c32bea0233924f8d977"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c821c47ecfe05cc32140dcf8dc6fd5d21971c86dbd56eabfe5ba07a64910c01"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9c04bff9a5335eb95c6ecf1c117576a0aa560def274876fd156cfe5510fccc61"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7f605a456948c35260e7b2a39f8952a26f077fd25653c37740ed186b90aaa68a"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-win32.whl", hash = "sha256:6270d717b11c5476b0cbb21eedc8d4dbb7d1a956fd6c15a23e96f197a6193158"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-win_amd64.whl", hash = "sha256:275424295f4256fd301744b8f335cff367825d270f155d522b30c7bf49903ee7"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8a97ac839c2c6672c4865e48f3cbad7152cee85f4233fb4ca6291d775b9b954a"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c338ec6ec01c0bc8e735c58b9f5d51e75bacb6ff23296658826d7cfdfdb8678a"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:566df36fd0e901625523a5a1835032f1ebdd7f7886c54584143fa6c668b4df3b"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d99945830a6f3e9638d89a28ed130b1eb24c91255e4f24366fbe699b983f29e4"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:01146546d84185f12721a1d2ce0c6673451a7894d1460b592d378ca4871a0c72"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-win32.whl", hash = "sha256:69469ce8ce7a8df4d37620e3163b71238719e1e2e5048d114a1b6ce0fbf8c662"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-win_amd64.whl", hash = "sha256:b95b2f470c1b2683febd2e7eab1d3f0e078c91dbdd0b00e9c645d07a413bb99f"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43d044780732d9e0381ac8d5316f95d7f02ef04d6e4ef6dc82379f09795d993f"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d6be30b2a75362325176c036d7fb8d19e8846c77e87683ffaa8177b35135613"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d898cc2c76c135ef65517f4ddd7a3512fb41f23087b0650efb3418b8389a3cd1"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:059d7151fff513c53a4638da8778be7fce81a0c4854c7348ebd0c4078ddf28fe"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:334edbcff10514ad1d66e3a70b339c0a29886394892490119dbb669627b17717"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-win32.whl", hash = "sha256:74ab4ee7794d7ed1b0c37e7333640e0f0a626fc7b398c07a7aef52f484fddde3"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-win_amd64.whl", hash = "sha256:88690f4e1f0fbf5339bedbb127e240fec1fd3070e9934c0b7bef83432f779d2f"}, + {file = "sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0"}, + {file = "sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f"}, +] + +[package.dependencies] +greenlet = {version = ">=1", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +typing-extensions = ">=4.6.0" + +[package.extras] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (>=1)"] +aioodbc = ["aioodbc", "greenlet (>=1)"] +aiosqlite = ["aiosqlite", "greenlet (>=1)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (>=1)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (>=1)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx_oracle (>=8)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (>=1)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] +sqlcipher = ["sqlcipher3_binary"] + +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "stevedore" +version = "5.7.0" +description = "Manage dynamic plugins for Python applications" +optional = true +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "stevedore-5.7.0-py3-none-any.whl", hash = "sha256:fd25efbb32f1abb4c9e502f385f0018632baac11f9ee5d1b70f88cc5e22ad4ed"}, + {file = "stevedore-5.7.0.tar.gz", hash = "sha256:31dd6fe6b3cbe921e21dcefabc9a5f1cf848cf538a1f27543721b8ca09948aa3"}, +] + +[[package]] +name = "symengine" +version = "0.13.0" +description = "Python library providing wrappers to SymEngine" +optional = true +python-versions = "<4,>=3.8" +groups = ["main"] +files = [ + {file = "symengine-0.13.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:259fd4111c7a70c72bdff5686de1949e8132baeb612eacdaf8837720c6fe449b"}, + {file = "symengine-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:44f2eb28a1e36db0bbd6679435412f79da9743bf9c1cb3eff25e0c343b7ddd48"}, + {file = "symengine-0.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d141712fa14d9138bd19e64b10392f850c68d88cd7db29f1bda33e32d1095559"}, + {file = "symengine-0.13.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:830226d933bfcdb93546e4062541627d9a3bc7a178a63fb16c002eb5c5221938"}, + {file = "symengine-0.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a08090163819a0bbfa97d64bd2d8dac2c5268147ed9c242799d7f7e8728a6f4e"}, + {file = "symengine-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1e435dcd8ed25e4c7c21ab1c0376be910efc7f35da76d532367df27b359f0358"}, + {file = "symengine-0.13.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:da0eba7e106095cdce88eb275c8a9d7c4586ad88f229394c53e1184155c00745"}, + {file = "symengine-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b0c175f4f895a73a925508af03faf7efd6cad8593256bbdb5346bd996d3ec5c8"}, + {file = "symengine-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e58d1e2abd08381aa0cf24c88c0e8b7f592df92619b51e32d36835fbd2dd6ae8"}, + {file = "symengine-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db745f2c7a3c5e83510cf4decb43201f43552dfb05ad8af9787c89708be9ede"}, + {file = "symengine-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2572c98b09ac284db6ecff63f6170461194dc94c4209afd34c092ec67873d85"}, + {file = "symengine-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:12727f02a2919f005aee48e68e0cbb70cf857b19385857b4d985d1c9b075f620"}, + {file = "symengine-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cf91d24f1bfd6d53228593c7804dd106b71b19674d5afc4fa322d516e1793bdd"}, + {file = "symengine-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5615b7eb68890917abd390ebb10434a949165f6064741c1a8cc345fee14e855"}, + {file = "symengine-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb92bdf0890de264abaeacbfbdbd4dd7444b94057bd47958d913b662e549ad8a"}, + {file = "symengine-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b3bce486fbc0b87970ed1b10ca9d5cafb1fd6b66382fe631261d83592851d7e"}, + {file = "symengine-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7e6bae9cfcdde2775d92fbb0abe3ef04e32f65ebc4c2d164ca33f4da202d4a7"}, + {file = "symengine-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:bced0a1dbdb94737c299384c85ddbad6944ce8dadc334f7bb8dbbd8f6c965807"}, + {file = "symengine-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d34df77971538e4c29f2d8e5ef7f459c2179465e6cdb7dfd48b79b87ecd8f4d"}, + {file = "symengine-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ab2661d9b18867e7c6edbfa7a74b8b0a2a694bd24aa08003dc3214f77cb9d6f2"}, + {file = "symengine-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53f27b9013878ee4419d8e853664d8ae4b68419e3f4b9b5b7f503d32bf904755"}, + {file = "symengine-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27987f75ce08c64f453e2b9b74fec6ffc5ca418c4deca0b75580979d4a4e242a"}, + {file = "symengine-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9ea9410330ea15ed4137d7a0a3c43caccacb71490e18036ce5182d08c93baf8"}, + {file = "symengine-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:5031eb7a5c6675d5195bb57f93cc7d9ac5a7a9a826d4ad6f6b2927746ed7e6e6"}, + {file = "symengine-0.13.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ce0e5dfb19943bcf3e44a4485bcac4c5533ba3705c63083494eed0b3bf246076"}, + {file = "symengine-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c3b77dc54bf1181f6bd3b3338c4e6e5973a8b0fa20a189d15563ef5626e57b04"}, + {file = "symengine-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca7c3f6c168f6f5b06b421833c3d3baae56067a94b671bdffbe09b8e4fefd9be"}, + {file = "symengine-0.13.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:847523de682416811bacb3ad11507e663b3522fbb35cd27184757e9956d0eaf0"}, + {file = "symengine-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2fc1b7d96426463f0c9011e9fb88459d906477c1baa8a996dde6fb2bfa99d4"}, + {file = "symengine-0.13.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:6e371bb2da3867085779c1c21bbb1c85f9634c76c8a76c08562ea113e3dfcd85"}, + {file = "symengine-0.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cf7c62478b19683d54e4d93faa5b89303beae25db0c503a105a70d266dc99fa9"}, + {file = "symengine-0.13.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdb21158cf3e2ba87e441f21ecc7724f108b8db17c0fd1880f9f531602bab1f3"}, + {file = "symengine-0.13.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1848d366b359ff69ef5dac148b30ca04c7339a7d3bcab28419d411e68c0cc011"}, + {file = "symengine-0.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242f817e890a0a50d52ed6b2bfd1aad19636a58db700c7995bbe1ceeaebd9d08"}, + {file = "symengine-0.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:af79cf2b9645fb55216850185987b2e9347db71e42e87b6402e4bbd41710b316"}, + {file = "symengine-0.13.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:17ae9d1c781a60ac48d07fa30f39a2d237f9da95e9e81f6a24b1c16908e9cad2"}, + {file = "symengine-0.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5264157a95f6d09dd044cee6abcbc176e649c487638b7f32199f387f37ad82a5"}, + {file = "symengine-0.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01a6d0829b4881d5f831ae7848eb0d82b80d8b46b5689f1bf27069672370f75"}, + {file = "symengine-0.13.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35ec68b11c2df2be1a236d0c028edb5b331909b16666d7a9fe99a4a5810afec7"}, + {file = "symengine-0.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4357fed87083e8719fcffd8bd0e7ddd16172e319343362512f681e472ac5668"}, + {file = "symengine-0.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a41be31816e5e51e9063bf26de07faf3751de7a133dbbec149632de702a28e18"}, + {file = "symengine-0.13.0.tar.gz", hash = "sha256:ab83a08897ebf12579702c2b71ba73d4732fb706cc4291d810aedf39c690c14c"}, +] + +[[package]] +name = "sympy" +version = "1.14.0" +description = "Computer algebra system (CAS) in Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5"}, + {file = "sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517"}, +] + +[package.dependencies] +mpmath = ">=1.1.0,<1.4" + +[package.extras] +dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"] + +[[package]] +name = "tabulate" +version = "0.9.0" +description = "Pretty-print tabular data" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[package.extras] +widechars = ["wcwidth"] + +[[package]] +name = "tomlkit" +version = "0.14.0" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.9" +groups = ["analysis"] +files = [ + {file = "tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680"}, + {file = "tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064"}, +] + +[[package]] +name = "toolz" +version = "1.1.0" +description = "List processing tools and functional utilities" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8"}, + {file = "toolz-1.1.0.tar.gz", hash = "sha256:27a5c770d068c110d9ed9323f24f1543e83b2f300a687b7891c1a6d56b697b5b"}, +] + +[[package]] +name = "tqdm" +version = "4.67.3" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf"}, + {file = "tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "traitlets" +version = "5.14.3" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev", "docs"] +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] +markers = {dev = "python_version == \"3.11\""} + +[[package]] +name = "urllib3" +version = "2.6.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, + {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, +] + +[package.extras] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] + +[[package]] +name = "wcwidth" +version = "0.6.0" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad"}, + {file = "wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159"}, +] + +[extras] +cuda = ["cuda-toolkit", "cupy-cuda12x", "cuquantum-python-cu12", "nvidia-nccl-cu12"] +qmatchatea = ["qmatchatea"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.11,<3.14" +content-hash = "c481f345e729c8a67b6869092ce73b465f6ae8ad9594be8b8ff7590fdeeba60b" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f631f18 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,84 @@ +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +name = "qibotn" +version = "0.0.7" +description = "A tensor-network translation module for Qibo" +authors = ["The Qibo team"] +license = "Apache License 2.0" +readme = "README.md" +homepage = "https://qibo.science/" +repository = "https://github.com/qiboteam/qibotn/" +documentation = "https://qibo.science/docs/qibotn/stable" +keywords = [] +classifiers = [ + "Programming Language :: Python :: 3", + "Topic :: Scientific/Engineering :: Physics", +] +packages = [{ include = "qibotn", from = "src" }] + +[tool.poetry.dependencies] +python = ">=3.11,<3.14" +qibo = "^0.3.0" +qibojit = "^0.1.13" +quimb = { version = "^1.10.0", extras = ["tensor"] } +cupy-cuda12x = { version = "^13.6.0", optional = true } +cuda-toolkit = {extras = ["all"], version = "^12.9.1"} +nvidia-nccl-cu12 = { version = "^2.16.5", optional = true } +cuquantum-python-cu12 = { version = "^25.9.1", optional = true } +qmatchatea = { version = "^1.4.3", optional = true } +qiskit = { version = "^1.4.0", optional = true } +qtealeaves = { version = "^1.5.20", optional = true } + + +[tool.poetry.extras] +cuda = ["cupy-cuda12x", "cuda-toolkit", "nvidia-nccl-cu12", "cuquantum-python-cu12", "mpi4py"] +qmatchatea = ["qmatchatea"] + +[tool.poetry.group.docs] +optional = true + +[tool.poetry.group.docs.dependencies] +Sphinx = "^5.3.0" +furo = "^2023.3.27" +sphinxcontrib-bibtex = "^2.5.0" +sphinx-copybutton = "^0.5.2" +sphinxcontrib-katex = "^0.9.9" + +[tool.poetry.group.dev.dependencies] +ipython = "^8.34.0" + +[tool.poetry.group.tests] +optional = true + +[tool.poetry.group.tests.dependencies] +pytest = ">=8,<10" +pytest-cov = "^4.1.0" +pytest-env = "^1.1.3" + +[tool.poetry.group.analysis] +optional = true + +[tool.poetry.group.analysis.dependencies] +pylint = "^3.0.3" + +[tool.poe.tasks] +test = "pytest" +lint = "pylint src --errors-only" +lint-warnings = "pylint src --exit-zero" +docs = "make -C doc html" +docs-clean = "make -C doc clean" +test-docs = "make -C doc doctest" + +[tool.pylint.main] +ignored-modules = ["cupy", "cuquantum", "mpi4py"] + +[tool.pylint.reports] +output-format = "colorized" + +[tool.pytest.ini_options] +testpaths = ["tests/"] +addopts = ["--cov=qibotn", "--cov-report=xml"] +env = ["D:NUMBA_DISABLE_JIT=1"] diff --git a/src/qibotn/__init__.py b/src/qibotn/__init__.py new file mode 100644 index 0000000..4942a45 --- /dev/null +++ b/src/qibotn/__init__.py @@ -0,0 +1,5 @@ +import importlib.metadata as im + +from qibotn.backends import MetaBackend + +__version__ = im.version(__package__) diff --git a/src/qibotn/backends/__init__.py b/src/qibotn/backends/__init__.py new file mode 100644 index 0000000..c330d1f --- /dev/null +++ b/src/qibotn/backends/__init__.py @@ -0,0 +1,55 @@ +from typing import Union + +from qibo.config import raise_error + +from qibotn.backends.abstract import QibotnBackend +from qibotn.backends.cutensornet import CuTensorNet # pylint: disable=E0401 + +PLATFORMS = ("cutensornet", "quimb", "qmatchatea") + + +class MetaBackend: + """Meta-backend class which takes care of loading the qibotn backends.""" + + @staticmethod + def load(platform: str, runcard: dict = None, **kwargs) -> QibotnBackend: + """Loads the backend. + + Args: + platform (str): Name of the backend to load: either `cutensornet` or `qutensornet`. + runcard (dict): Dictionary containing the simulation settings. + Returns: + qibo.backends.abstract.Backend: The loaded backend. + """ + + if platform == "cutensornet": # pragma: no cover + return CuTensorNet(runcard) + elif platform == "quimb": # pragma: no cover + import qibotn.backends.quimb as qmb + + quimb_backend = kwargs.get("quimb_backend", "numpy") + contraction_optimizer = kwargs.get("contraction_optimizer", "auto-hq") + return qmb.BACKENDS[quimb_backend]( + quimb_backend=quimb_backend, contraction_optimizer=contraction_optimizer + ) + elif platform == "qmatchatea": # pragma: no cover + from qibotn.backends.qmatchatea import QMatchaTeaBackend + + return QMatchaTeaBackend() + else: + raise_error( + NotImplementedError, + f"Unsupported platform {platform}, please pick one in {PLATFORMS}", + ) + + def list_available(self) -> dict: + """Lists all the available qibotn backends.""" + available_backends = {} + for platform in PLATFORMS: + try: + MetaBackend.load(platform=platform) + available = True + except: + available = False + available_backends[platform] = available + return available_backends diff --git a/src/qibotn/backends/abstract.py b/src/qibotn/backends/abstract.py new file mode 100644 index 0000000..24e87f6 --- /dev/null +++ b/src/qibotn/backends/abstract.py @@ -0,0 +1,35 @@ +from abc import ABC + +from qibo.config import raise_error + + +class QibotnBackend(ABC): + + def __init__(self): + super().__init__() + + def apply_gate(self, gate, state, nqubits): # pragma: no cover + raise_error(NotImplementedError, "QiboTN cannot apply gates directly.") + + def apply_gate_density_matrix(self, gate, state, nqubits): # pragma: no cover + raise_error(NotImplementedError, "QiboTN cannot apply gates directly.") + + def assign_measurements(self, measurement_map, circuit_result): + raise_error(NotImplementedError, "Not implemented in QiboTN.") + + def set_precision(self, precision): + if precision != self.precision: + super().set_precision(precision) + self._setup_backend_specifics() + + def set_device(self, device): + self.device = device + self._setup_backend_specifics() + + def configure_tn_simulation(self, **config): + """Configure the TN simulation that will be performed.""" + pass + + def _setup_backend_specifics(self): + """Configure the backend specific according to the used package.""" + pass diff --git a/src/qibotn/backends/cutensornet.py b/src/qibotn/backends/cutensornet.py new file mode 100644 index 0000000..616cda9 --- /dev/null +++ b/src/qibotn/backends/cutensornet.py @@ -0,0 +1,169 @@ +import numpy as np +from qibo import hamiltonians +from qibo.backends import NumpyBackend +from qibo.config import raise_error + +from qibotn.backends.abstract import QibotnBackend +from qibotn.result import TensorNetworkResult + + +class CuTensorNet(QibotnBackend, NumpyBackend): # pragma: no cover + # CI does not test for GPU + """Creates CuQuantum backend for QiboTN.""" + + def __init__(self, runcard=None): + super().__init__() + from cuquantum import __version__ # pylint: disable=import-error + + self.name = "qibotn" + self.platform = "cutensornet" + self.versions["cuquantum"] = __version__ + self.supports_multigpu = True + self.configure_tn_simulation(runcard) + + def configure_tn_simulation(self, runcard): + self.rank = None + if runcard is not None: + self.MPI_enabled = runcard.get("MPI_enabled", False) + self.NCCL_enabled = runcard.get("NCCL_enabled", False) + + expectation_enabled_value = runcard.get("expectation_enabled") + if expectation_enabled_value is True: + self.expectation_enabled = True + self.observable = None + elif expectation_enabled_value is False: + self.expectation_enabled = False + elif isinstance(expectation_enabled_value, dict): + self.expectation_enabled = True + self.observable = runcard.get("expectation_enabled", {}) + elif isinstance( + expectation_enabled_value, hamiltonians.SymbolicHamiltonian + ): + self.expectation_enabled = True + self.observable = expectation_enabled_value + else: + raise TypeError("expectation_enabled has an unexpected type") + + mps_enabled_value = runcard.get("MPS_enabled") + if mps_enabled_value is True: + self.MPS_enabled = True + self.gate_algo = { + "qr_method": False, + "svd_method": { + "partition": "UV", + "abs_cutoff": 1e-12, + }, + } + elif mps_enabled_value is False: + self.MPS_enabled = False + elif isinstance(mps_enabled_value, dict): + self.MPS_enabled = True + self.gate_algo = mps_enabled_value + else: + raise TypeError("MPS_enabled has an unexpected type") + + else: + self.MPI_enabled = False + self.MPS_enabled = False + self.NCCL_enabled = False + self.expectation_enabled = False + + def execute_circuit( + self, circuit, initial_state=None, nshots=None, return_array=False + ): # pragma: no cover + """Executes a quantum circuit using selected TN backend. + + Parameters: + circuit (:class:`qibo.models.circuit.Circuit`): Circuit to execute. + initial_state (:class:`qibo.models.circuit.Circuit`): Circuit to prepare the initial state. + If ``None`` the default ``|00...0>`` state is used. + + Returns: + QuantumState or numpy.ndarray: If `return_array` is False, returns a QuantumState object representing the quantum state. If `return_array` is True, returns a numpy array representing the quantum state. + """ + + import qibotn.eval as eval + + if initial_state is not None: + raise_error(NotImplementedError, "QiboTN cannot support initial state.") + + if ( + self.MPI_enabled == False + and self.MPS_enabled == False + and self.NCCL_enabled == False + and self.expectation_enabled == False + ): + state = eval.dense_vector_tn(circuit, self.dtype) + elif ( + self.MPI_enabled == False + and self.MPS_enabled == True + and self.NCCL_enabled == False + and self.expectation_enabled == False + ): + state = eval.dense_vector_mps(circuit, self.gate_algo, self.dtype) + elif ( + self.MPI_enabled == True + and self.MPS_enabled == False + and self.NCCL_enabled == False + and self.expectation_enabled == False + ): + state, self.rank = eval.dense_vector_tn_MPI(circuit, self.dtype, 32) + if self.rank > 0: + state = np.array(0) + elif ( + self.MPI_enabled == False + and self.MPS_enabled == False + and self.NCCL_enabled == True + and self.expectation_enabled == False + ): + state, self.rank = eval.dense_vector_tn_nccl(circuit, self.dtype, 32) + if self.rank > 0: + state = np.array(0) + elif ( + self.MPI_enabled == False + and self.MPS_enabled == False + and self.NCCL_enabled == False + and self.expectation_enabled == True + ): + state = eval.expectation_tn(circuit, self.dtype, self.observable) + elif ( + self.MPI_enabled == True + and self.MPS_enabled == False + and self.NCCL_enabled == False + and self.expectation_enabled == True + ): + state, self.rank = eval.expectation_tn_MPI( + circuit, self.dtype, self.observable, 32 + ) + if self.rank > 0: + state = np.array(0) + elif ( + self.MPI_enabled == False + and self.MPS_enabled == False + and self.NCCL_enabled == True + and self.expectation_enabled == True + ): + state, self.rank = eval.expectation_tn_nccl( + circuit, self.dtype, self.observable, 32 + ) + if self.rank > 0: + state = np.array(0) + else: + raise_error(NotImplementedError, "Compute type not supported.") + + if self.expectation_enabled: + return state.flatten().real + else: + if return_array: + statevector = state.flatten() + else: + statevector = state + + return TensorNetworkResult( + nqubits=circuit.nqubits, + backend=self, + measures=None, + measured_probabilities=None, + prob_type=None, + statevector=statevector, + ) diff --git a/src/qibotn/backends/qmatchatea.py b/src/qibotn/backends/qmatchatea.py new file mode 100644 index 0000000..a5261f4 --- /dev/null +++ b/src/qibotn/backends/qmatchatea.py @@ -0,0 +1,317 @@ +"""Implementation of Quantum Matcha Tea backend.""" + +import re +from dataclasses import dataclass + +import numpy as np +import qiskit +import qmatchatea +import qtealeaves +from qibo.backends import NumpyBackend +from qibo.config import raise_error + +from qibotn.backends.abstract import QibotnBackend +from qibotn.result import TensorNetworkResult + + +@dataclass +class QMatchaTeaBackend(QibotnBackend, NumpyBackend): + + def __init__(self): + super().__init__() + + self.name = "qibotn" + self.platform = "qmatchatea" + + # Default precision + self.precision = "double" + + # Set default configurations + self.configure_tn_simulation() + self._setup_backend_specifics() + + def configure_tn_simulation( + self, + ansatz: str = "MPS", + max_bond_dimension: int = 10, + cut_ratio: float = 1e-9, + trunc_tracking_mode: str = "C", + svd_control: str = "A", + ini_bond_dimension: int = 1, + ): + """Configure TN simulation given Quantum Matcha Tea interface. + + Args: + ansatz (str): tensor network ansatz. It can be tree tensor network "TTN" + or Matrix Product States "MPS" (default). + max_bond_dimension : int, optional Maximum bond dimension of the problem. Default to 10. + cut_ratio : float, optional + Cut ratio for singular values. If :math:`\\lambda_n/\\lambda_1 <` cut_ratio then + :math:`\\lambda_n` is neglected. Default to 1e-9. + trunc_tracking_mode : str, optional + Modus for storing truncation, 'M' for maximum, 'C' for + cumulated (default). + svd_ctrl : character, optional + Control for the SVD algorithm. Available: + - "A" : automatic. Some heuristic is run to choose the best mode for the algorithm. + - "V" : gesvd. Safe but slow method. + - "D" : gesdd. Fast iterative method. It might fail. Resort to gesvd if it fails + - "E" : eigenvalue decomposition method. Faster on GPU. Available only when + contracting the singular value to left or right + - "X" : sparse eigenvalue decomposition method. Used when you reach the maximum + bond dimension. + - "R" : random svd method. Used when you reach the maximum bond dimension. + Default to 'A'. + ini_bond_dimension: int, optional + Initial bond dimension of the simulation. It is used if the initial state is random. + Default to 1. + """ + + self.convergence_params = qmatchatea.QCConvergenceParameters( + max_bond_dimension=max_bond_dimension, + cut_ratio=cut_ratio, + trunc_tracking_mode=trunc_tracking_mode, + svd_ctrl=svd_control, + ini_bond_dimension=ini_bond_dimension, + ) + self.ansatz = ansatz + + def _setup_backend_specifics(self): + """Configure qmatchatea QCBackend object.""" + + qmatchatea_device = ( + "cpu" if "CPU" in self.device else "gpu" if "GPU" in self.device else None + ) + qmatchatea_precision = ( + "C" + if self.precision == "single" + else "Z" if self.precision == "double" else "A" + ) + + # TODO: once MPI is available for Python, integrate it here + self.qmatchatea_backend = qmatchatea.QCBackend( + precision=qmatchatea_precision, + device=qmatchatea_device, + ansatz=self.ansatz, + ) + + def execute_circuit( + self, + circuit, + initial_state=None, + nshots=None, + prob_type=None, + return_array=False, + **prob_kwargs, + ): + """Execute a Qibo quantum circuit using tensor network simulation. + + This method returns a ``TensorNetworkResult`` object, which provides: + - Reconstruction of the system state (if the system size is < 20). + - Frequencies (if the number of shots is specified). + - Probabilities computed using various methods. + + The following probability computation methods are available, as implemented + in Quantum Matcha Tea: + - **"E" (Even):** Probabilities are computed by evenly descending the probability tree, + pruning branches (states) with probabilities below a threshold. + - **"G" (Greedy):** Probabilities are computed by following the most probable states + in descending order until reaching a given coverage (sum of probabilities). + - **"U" (Unbiased):** An optimal probability measure that is unbiased and designed + for best performance. See https://arxiv.org/abs/2401.10330 for details. + + Args: + circuit: A Qibo circuit to execute. + initial_state: The initial state of the system (default is the vacuum state + for tensor network simulations). + nshots: The number of shots for shot-noise simulation (optional). + prob_type: The probability computation method. Must be one of: + - "E" (Even) + - "G" (Greedy) + - "U" (Unbiased) [default]. + prob_kwargs: Additional parameters required for probability computation: + - For "U", requires ``num_samples``. + - For "E" and "G", requires ``prob_threshold``. + + Returns: + TensorNetworkResult: An object with methods to reconstruct the state, + compute probabilities, and generate frequencies. + """ + + # TODO: verify if the QCIO mechanism of matcha is supported by Fortran only + # as written in the docstrings or by Python too (see ``io_info`` argument of + # ``qmatchatea.interface.run_simulation`` function) + if initial_state is not None: + raise_error( + NotImplementedError, + f"Backend {self} currently does not support initial state.", + ) + + if prob_type == None: + prob_type = "U" + prob_kwargs = {"num_samples": 500} + + # TODO: check + circuit = self._qibocirc_to_qiskitcirc(circuit) + run_qk_params = qmatchatea.preprocessing.qk_transpilation_params(False) + + # Initialize the TNObservable object + observables = qtealeaves.observables.TNObservables() + + # Shots + if nshots is not None: + observables += qtealeaves.observables.TNObsProjective(num_shots=nshots) + + # Probabilities + observables += qtealeaves.observables.TNObsProbabilities( + prob_type=prob_type, + **prob_kwargs, + ) + + # State + observables += qtealeaves.observables.TNState2File(name="temp", formatting="U") + + results = qmatchatea.run_simulation( + circ=circuit, + convergence_parameters=self.convergence_params, + transpilation_parameters=run_qk_params, + backend=self.qmatchatea_backend, + observables=observables, + ) + + if circuit.num_qubits < 20 and return_array: + statevector = results.statevector + else: + statevector = None + + return TensorNetworkResult( + nqubits=circuit.num_qubits, + backend=self, + measures=results.measures, + measured_probabilities=results.measure_probabilities, + prob_type=prob_type, + statevector=statevector, + ) + + def expectation(self, circuit, observable): + """Compute the expectation value of a Qibo-friendly ``observable`` on + the Tensor Network constructed from a Qibo ``circuit``. + + This method takes a Qibo-style symbolic Hamiltonian (e.g., `X(0)*Z(1) + 2.0*Y(2)*Z(0)`) + as the observable, converts it into a Quantum Matcha Tea (qmatchatea) observable + (using `TNObsTensorProduct` and `TNObsWeightedSum`), and computes its expectation + value using the provided circuit. + + Args: + circuit: A Qibo quantum circuit object on which the expectation value + is computed. The circuit should be compatible with the qmatchatea + Tensor Network backend. + observable: The observable whose expectation value we want to compute. + This must be provided in the symbolic Hamiltonian form supported by Qibo + (e.g., `X(0)*Y(1)` or `Z(0)*Z(1) + 1.5*Y(2)`). + + Returns: + qibotn.TensorNetworkResult class, providing methods to retrieve + probabilities, frequencies and state always according to the chosen + simulation setup. + """ + + # From Qibo to Qiskit + circuit = self._qibocirc_to_qiskitcirc(circuit) + run_qk_params = qmatchatea.preprocessing.qk_transpilation_params(False) + + operators = qmatchatea.QCOperators() + observables = qtealeaves.observables.TNObservables() + # Add custom observable + observables += self._qiboobs_to_qmatchaobs(hamiltonian=observable) + + results = qmatchatea.run_simulation( + circ=circuit, + convergence_parameters=self.convergence_params, + transpilation_parameters=run_qk_params, + backend=self.qmatchatea_backend, + observables=observables, + operators=operators, + ) + + return np.real(results.observables["custom_hamiltonian"]) + + def _qibocirc_to_qiskitcirc(self, qibo_circuit) -> qiskit.QuantumCircuit: + """Convert a Qibo Circuit into a Qiskit Circuit.""" + # Convert the circuit to QASM 2.0 to qiskit + qasm_circuit = qibo_circuit.to_qasm() + qiskit_circuit = qiskit.QuantumCircuit.from_qasm_str(qasm_circuit) + + # Transpile the circuit to adapt it to the linear structure of the MPS, + # with the constraint of having only the gates basis_gates + qiskit_circuit = qmatchatea.preprocessing.preprocess( + qiskit_circuit, + qk_params=qmatchatea.preprocessing.qk_transpilation_params(), + ) + return qiskit_circuit + + def _qiboobs_to_qmatchaobs(self, hamiltonian, observable_name="custom_hamiltonian"): + """ + Convert a Qibo SymbolicHamiltonian into a qmatchatea TNObsWeightedSum observable. + + The SymbolicHamiltonian is expected to have a collection of terms, where each term has: + - `coefficient`: A numeric value. + - `factors`: A list of factors, each a string such as "X2" or "Z0", representing an operator + and the qubit it acts on. + + Args: + hamiltonian (qibo.SymbolicHamiltonian): The symbolic Hamiltonian containing the terms. + observable_name (str): The name for the resulting TNObsWeightedSum observable. + + Returns: + TNObsWeightedSum: An observable suitable for use with qmatchatea. + """ + coeff_list = [] + tensor_product_obs = None + + # Regex to split an operator factor (e.g., "X2" -> operator "X", qubit 2) + factor_pattern = re.compile(r"([^\d]+)(\d+)") + + # Iterate over each term in the symbolic Hamiltonian + for i, term in enumerate(hamiltonian.terms): + # Store the term's coefficient + coeff_list.append(term.coefficient) + + operator_names = [] + acting_on_qubits = [] + + # Process each factor in the term + for factor in term.factors: + # Assume each factor is a string like "Y2" or "Z0" + match = factor_pattern.match(str(factor)) + if match: + operator_name = match.group(1) + qubit_index = int(match.group(2)) + operator_names.append(operator_name) + acting_on_qubits.append([qubit_index]) + else: + raise ValueError( + f"Factor '{str(factor)}' does not match the expected format." + ) + + # Create a TNObsTensorProduct for this term. + term_tensor_prod = qtealeaves.observables.TNObsTensorProduct( + name=f"term_{i}", + operators=operator_names, + sites=acting_on_qubits, + ) + + # Combine tensor products from each term + if tensor_product_obs is None: + tensor_product_obs = term_tensor_prod + else: + tensor_product_obs += term_tensor_prod + + # Combine all terms into a weighted sum observable + obs_sum = qtealeaves.observables.TNObsWeightedSum( + name=observable_name, + tp_operators=tensor_product_obs, + coeffs=coeff_list, + use_itpo=False, + ) + return obs_sum diff --git a/src/qibotn/backends/quimb.py b/src/qibotn/backends/quimb.py new file mode 100644 index 0000000..3ee200d --- /dev/null +++ b/src/qibotn/backends/quimb.py @@ -0,0 +1,387 @@ +from collections import Counter +from typing import Optional + +import quimb as qu +import quimb.tensor as qtn +from qibo.config import raise_error +from qibo.gates.abstract import ParametrizedGate +from qibo.models import Circuit + +from qibotn.backends.abstract import QibotnBackend +from qibotn.result import TensorNetworkResult + +GATE_MAP = { + "h": "H", + "x": "X", + "y": "Y", + "z": "Z", + "s": "S", + "t": "T", + "rx": "RX", + "ry": "RY", + "rz": "RZ", + "u3": "U3", + "cx": "CX", + "cnot": "CNOT", + "cy": "CY", + "cz": "CZ", + "iswap": "ISWAP", + "swap": "SWAP", + "ccx": "CCX", + "ccy": "CCY", + "ccz": "CCZ", + "toffoli": "TOFFOLI", + "cswap": "CSWAP", + "fredkin": "FREDKIN", + "fsim": "fsim", + "measure": "measure", +} + + +def __init__(self, quimb_backend="numpy", contraction_optimizer="auto-hq"): + super(self.__class__, self).__init__() + + self.name = "qibotn" + self.platform = "quimb" + self.backend = quimb_backend + + self.ansatz = None + self.max_bond_dimension = None + self.svd_cutoff = None + self.n_most_frequent_states = None + + self.configure_tn_simulation() + self.setup_backend_specifics( + quimb_backend=quimb_backend, contractions_optimizer=contraction_optimizer + ) + + +def configure_tn_simulation( + self, + ansatz: str = "mps", + max_bond_dimension: Optional[int] = None, + svd_cutoff: Optional[float] = 1e-10, + n_most_frequent_states: int = 100, +): + """ + Configure tensor network simulation. + + Args: + ansatz : str, optional + The tensor network ansatz to use. Default is `None` and, in this case, a + generic Circuit Quimb class is used. + max_bond_dimension : int, optional + The maximum bond dimension for the MPS ansatz. Default is 10. + + Notes: + - The ansatz determines the tensor network structure used for simulation. Currently, only "MPS" is supported. + - The `max_bond_dimension` parameter controls the maximum allowed bond dimension for the MPS ansatz. + """ + self.ansatz = ansatz + self.max_bond_dimension = max_bond_dimension + self.svd_cutoff = svd_cutoff + self.n_most_frequent_states = n_most_frequent_states + + +@property +def circuit_ansatz(self): + if self.ansatz == "mps": + return qtn.CircuitMPS + return qtn.Circuit + + +def setup_backend_specifics( + self, quimb_backend="numpy", contractions_optimizer="auto-hq" +): + """Setup backend specifics. + Args: + quimb_backend: str + The backend to use for the quimb tensor network simulation. + contractions_optimizer: str, optional + The contractions_optimizer to use for the quimb tensor network simulation. + """ + # this is not really working because it does not change the inheritance + if quimb_backend == "jax": + import jax.numpy as jnp + + self.engine = jnp + elif quimb_backend == "numpy": + import numpy as np + + self.engine = np + elif quimb_backend == "torch": + import torch + + self.engine = torch + else: + raise_error(ValueError, f"Unsupported quimb backend: {quimb_backend}") + + self.backend = quimb_backend + self.contractions_optimizer = contractions_optimizer + + +def execute_circuit( + self, + circuit: Circuit, + initial_state=None, + nshots=None, + return_array=False, +): + """ + Execute a quantum circuit using the specified tensor network ansatz and initial state. + + Args: + circuit : QuantumCircuit + The quantum circuit to be executed. + initial_state : array-like, optional + The initial state of the quantum system. Only supported for Matrix Product States (MPS) ansatz. + nshots : int, optional + The number of shots for sampling the circuit. If None, no sampling is performed, and the full statevector is used. + return_array : bool, optional + If True, returns the statevector as a dense array. Default is False. + + Returns: + TensorNetworkResult + An object containing the results of the circuit execution, including: + - nqubits: Number of qubits in the circuit. + - backend: The backend used for execution. + - measures: The measurement frequencies if nshots is specified, otherwise None. + - measured_probabilities: A dictionary of computational basis states and their probabilities. + - prob_type: The type of probability computation used (currently "default"). + - statevector: The final statevector as a dense array if return_array is True, otherwise None. + + Raises: + ValueError + If an initial state is provided but the ansatz is not "MPS". + + Notes: + - The ansatz determines the tensor network structure used for simulation. Currently, only "MPS" is supported. + - If `initial_state` is provided, it must be compatible with the MPS ansatz. + - The `nshots` parameter enables sampling from the circuit's output distribution. If not specified, the full statevector is computed. + """ + if initial_state is not None and self.ansatz == "MPS": + initial_state = qtn.tensor_1d.MatrixProductState.from_dense( + initial_state, 2 + ) # 2 is the physical dimension + elif initial_state is not None: + raise_error(ValueError, "Initial state not None supported only for MPS ansatz.") + + circ_quimb = self.circuit_ansatz.from_openqasm2_str( + circuit.to_qasm(), psi0=initial_state + ) + + if nshots: + frequencies = Counter(circ_quimb.sample(nshots)) + main_frequencies = { + state: count + for state, count in frequencies.most_common(self.n_most_frequent_states) + } + computational_states = list(main_frequencies.keys()) + amplitudes = { + state: circ_quimb.amplitude(state) for state in computational_states + } + measured_probabilities = { + state: abs(amplitude) ** 2 for state, amplitude in amplitudes.items() + } + else: + frequencies = None + measured_probabilities = None + + statevector = ( + circ_quimb.to_dense(backend=self.backend, optimize=self.contractions_optimizer) + if return_array + else None + ) + return TensorNetworkResult( + nqubits=circuit.nqubits, + backend=self, + measures=frequencies, + measured_probabilities=measured_probabilities, + prob_type="default", + statevector=statevector, + ) + + +def exp_value_observable_symbolic( + self, circuit, operators_list, sites_list, coeffs_list, nqubits +): + """ + Compute the expectation value of a symbolic Hamiltonian on a quantum circuit using tensor network contraction. + This method takes a Qibo circuit, converts it to a Quimb tensor network circuit, and evaluates the expectation value + of a Hamiltonian specified by three lists of strings: operators, sites, and coefficients. + The expectation value is computed by summing the contributions from each term in the Hamiltonian, where each term's + expectation is calculated using Quimb's `local_expectation` function. + Each operator string must act on all different qubits, i.e., for each term, the corresponding sites tuple must contain unique qubit indices. + Example: operators_list = ['xyz', 'xyz'], sites_list = [(1,2,3), (1,2,3)], coeffs_list = [1, 2] + + + Parameters + ---------- + circuit : qibo.models.Circuit + The quantum circuit to evaluate, provided as a Qibo circuit object. + operators_list : list of str + List of operator strings representing the symbolic Hamiltonian terms. + sites_list : list of tuple of int + Tuples each specifying the qubits (sites) the corresponding operator acts on. + coeffs_list : list of real/complex + The coefficients for each Hamiltonian term. + Returns + ------- + float + The real part of the expectation value of the Hamiltonian on the given circuit state. + """ + # Validate that no term acts multiple times on the same qubit (no repeated indices in a sites tuple) + for sites in sites_list: + if len(sites) != len(set(sites)): + raise_error( + ValueError, + f"Invalid Hamiltonian term sites {sites}: repeated qubit indices are not allowed " + "within a single term (e.g. (0,0,0) is invalid).", + ) + quimb_circuit = self._qibo_circuit_to_quimb( + circuit, + quimb_circuit_type=self.circuit_ansatz, + gate_opts={"max_bond": self.max_bond_dimension, "cutoff": self.svd_cutoff}, + ) + + expectation_value = 0.0 + for opstr, sites, coeff in zip(operators_list, sites_list, coeffs_list): + + ops = self._string_to_quimb_operator(opstr) + coeff = coeff.real + + exp_values = quimb_circuit.local_expectation( + ops, + where=sites, + backend=self.backend, + optimize=self.contractions_optimizer, + simplify_sequence="R", + ) + + expectation_value = expectation_value + coeff * exp_values + + return self.real(expectation_value) + + +def _qibo_circuit_to_quimb( + self, qibo_circ, quimb_circuit_type=qtn.Circuit, **circuit_kwargs +): + """ + Convert a Qibo Circuit to a Quimb Circuit. Measurement gates are ignored. If are given gates not supported by Quimb, an error is raised. + + Parameters + ---------- + qibo_circ : qibo.models.circuit.Circuit + The circuit to convert. + quimb_circuit_type : type + The Quimb circuit class to use (Circuit, CircuitMPS, etc). + circuit_kwargs : dict + Extra arguments to pass to the Quimb circuit constructor. + + Returns + ------- + circ : quimb.tensor.circuit.Circuit + The converted circuit. + """ + nqubits = qibo_circ.nqubits + circ = quimb_circuit_type(nqubits, **circuit_kwargs) + + for gate in qibo_circ.queue: + gate_name = getattr(gate, "name", None) + quimb_gate_name = GATE_MAP.get(gate_name, None) + if quimb_gate_name == "measure": + continue + if quimb_gate_name is None: + raise_error(ValueError, f"Gate {gate_name} not supported in Quimb backend.") + + params = getattr(gate, "parameters", ()) + qubits = getattr(gate, "qubits", ()) + + is_parametrized = isinstance(gate, ParametrizedGate) and getattr( + gate, "trainable", True + ) + if is_parametrized: + circ.apply_gate( + quimb_gate_name, *params, *qubits, parametrized=is_parametrized + ) + else: + circ.apply_gate( + quimb_gate_name, + *params, + *qubits, + ) + return circ + + +def _string_to_quimb_operator(self, op_str): + """ + Convert a Pauli string (e.g. 'xzy') to a Quimb operator using '&' chaining. + + Parameters + ---------- + op_str : str + A string like 'xzy', where each character is one of 'x', 'y', 'z', 'i'. + + Returns + ------- + qu_op : quimb.Qarray + The corresponding Quimb operator. + """ + op_str = op_str.lower() + op = qu.pauli(op_str[0]) + for c in op_str[1:]: + op = op & qu.pauli(c) + return op + + +CLASSES_ROOTS = {"numpy": "Numpy", "torch": "PyTorch", "jax": "Jax"} + +METHODS = { + "__init__": __init__, + "configure_tn_simulation": configure_tn_simulation, + "setup_backend_specifics": setup_backend_specifics, + "execute_circuit": execute_circuit, + "exp_value_observable_symbolic": exp_value_observable_symbolic, + "_qibo_circuit_to_quimb": _qibo_circuit_to_quimb, + "_string_to_quimb_operator": _string_to_quimb_operator, + "circuit_ansatz": circuit_ansatz, +} + + +def _generate_backend(quimb_backend: str = "numpy"): + bases = (QibotnBackend,) + + if quimb_backend == "numpy": + from qibo.backends import NumpyBackend + + bases += (NumpyBackend,) + elif quimb_backend == "torch": + from qiboml.backends import PyTorchBackend + + bases += (PyTorchBackend,) + elif quimb_backend == "jax": + from qiboml.backends import JaxBackend + + bases += (JaxBackend,) + else: + raise_error(ValueError, f"Unsupported quimb backend: {quimb_backend}") + + return type(f"Quimb{CLASSES_ROOTS[quimb_backend]}Backend", bases, METHODS) + + +BACKENDS = {} +for k, v in CLASSES_ROOTS.items(): + backend_name = f"Quimb{v}Backend" + try: + backend = _generate_backend(k) + BACKENDS[k] = backend + globals()[backend_name] = backend + except ImportError: + continue + + +def __getattr__(name): + try: + return BACKENDS[name] + except KeyError: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None diff --git a/src/qibotn/circuit_convertor.py b/src/qibotn/circuit_convertor.py new file mode 100644 index 0000000..1c8b3ee --- /dev/null +++ b/src/qibotn/circuit_convertor.py @@ -0,0 +1,246 @@ +import cupy as cp +import numpy as np + +# Reference: https://github.com/NVIDIA/cuQuantum/tree/main/python/samples/cutensornet/circuit_converter + + +class QiboCircuitToEinsum: + """Convert a circuit to a Tensor Network (TN) representation. + + The circuit is first processed to an intermediate form by grouping each gate matrix + with its corresponding qubit it is acting on to a list. It is then converted to an + equivalent TN expression through the class function state_vector_operands() + following the Einstein summation convention in the interleave format. + + See document for detail of the format: https://docs.nvidia.com/cuda/cuquantum/python/api/generated/cuquantum.contract.html + + The output is to be used by cuQuantum's contract() for computation of the + state vectors of the circuit. + """ + + def __init__(self, circuit, dtype="complex128"): + self.backend = cp + self.dtype = getattr(self.backend, dtype) + self.init_basis_map(self.backend, dtype) + self.init_intermediate_circuit(circuit) + self.circuit = circuit + + def state_vector_operands(self): + """Create the operands for dense vector computation in the interleave + format. + + Returns: + Operands for the contraction in the interleave format. + """ + input_bitstring = "0" * len(self.active_qubits) + + input_operands = self._get_bitstring_tensors(input_bitstring) + + ( + mode_labels, + qubits_frontier, + next_frontier, + ) = self._init_mode_labels_from_qubits(self.active_qubits) + + gate_mode_labels, gate_operands = self._parse_gates_to_mode_labels_operands( + self.gate_tensors, qubits_frontier, next_frontier + ) + + operands = input_operands + gate_operands + mode_labels += gate_mode_labels + + out_list = [] + for key in qubits_frontier: + out_list.append(qubits_frontier[key]) + + operand_exp_interleave = [x for y in zip(operands, mode_labels) for x in y] + operand_exp_interleave.append(out_list) + return operand_exp_interleave + + def _init_mode_labels_from_qubits(self, qubits): + n = len(qubits) + frontier_dict = {q: i for i, q in enumerate(qubits)} + mode_labels = [[i] for i in range(n)] + return mode_labels, frontier_dict, n + + def _get_bitstring_tensors(self, bitstring): + return [self.basis_map[ibit] for ibit in bitstring] + + def _parse_gates_to_mode_labels_operands( + self, gates, qubits_frontier, next_frontier + ): + mode_labels = [] + operands = [] + + for tensor, gate_qubits in gates: + operands.append(tensor) + input_mode_labels = [] + output_mode_labels = [] + for q in gate_qubits: + input_mode_labels.append(qubits_frontier[q]) + output_mode_labels.append(next_frontier) + qubits_frontier[q] = next_frontier + next_frontier += 1 + mode_labels.append(output_mode_labels + input_mode_labels) + return mode_labels, operands + + def op_shape_from_qubits(self, nqubits): + """Modify tensor to cuQuantum shape. + + Parameters: + nqubits (int): The number of qubits in quantum circuit. + + Returns: + (qubit_states,input_output) * nqubits + """ + return (2, 2) * nqubits + + def init_intermediate_circuit(self, circuit): + """Initialize the intermediate circuit representation. + + This method initializes the intermediate circuit representation by extracting gate matrices and qubit IDs + from the given quantum circuit. + + Parameters: + circuit (object): The quantum circuit object. + """ + self.gate_tensors = [] + gates_qubits = [] + + for gate in circuit.queue: + gate_qubits = gate.control_qubits + gate.target_qubits + gates_qubits.extend(gate_qubits) + + # self.gate_tensors is to extract into a list the gate matrix together with the qubit id that it is acting on + # https://github.com/NVIDIA/cuQuantum/blob/6b6339358f859ea930907b79854b90b2db71ab92/python/cuquantum/cutensornet/_internal/circuit_parser_utils_cirq.py#L32 + required_shape = self.op_shape_from_qubits(len(gate_qubits)) + self.gate_tensors.append( + ( + cp.asarray(gate.matrix(), dtype=self.dtype).reshape(required_shape), + gate_qubits, + ) + ) + + # self.active_qubits is to identify qubits with at least 1 gate acting on it in the whole circuit. + self.active_qubits = np.unique(gates_qubits) + + def init_basis_map(self, backend, dtype): + """Initialize the basis map for the quantum circuit. + + This method initializes a basis map for the quantum circuit, which maps binary + strings representing qubit states to their corresponding quantum state vectors. + + Parameters: + backend (object): The backend object providing the array conversion method. + dtype (object): The data type for the quantum state vectors. + """ + asarray = backend.asarray + state_0 = asarray([1, 0], dtype=dtype) + state_1 = asarray([0, 1], dtype=dtype) + + self.basis_map = {"0": state_0, "1": state_1} + + def init_inverse_circuit(self, circuit): + """Initialize the inverse circuit representation. + + This method initializes the inverse circuit representation by extracting gate matrices and qubit IDs + from the given quantum circuit. + + Parameters: + circuit (object): The quantum circuit object. + """ + self.gate_tensors_inverse = [] + gates_qubits_inverse = [] + + for gate in circuit.queue: + gate_qubits = gate.control_qubits + gate.target_qubits + gates_qubits_inverse.extend(gate_qubits) + + # self.gate_tensors is to extract into a list the gate matrix together with the qubit id that it is acting on + # https://github.com/NVIDIA/cuQuantum/blob/6b6339358f859ea930907b79854b90b2db71ab92/python/cuquantum/cutensornet/_internal/circuit_parser_utils_cirq.py#L32 + required_shape = self.op_shape_from_qubits(len(gate_qubits)) + self.gate_tensors_inverse.append( + ( + cp.asarray(gate.matrix()).reshape(required_shape), + gate_qubits, + ) + ) + + # self.active_qubits is to identify qubits with at least 1 gate acting on it in the whole circuit. + self.active_qubits_inverse = np.unique(gates_qubits_inverse) + + def get_pauli_gates(self, pauli_map, dtype="complex128", backend=cp): + """Populate the gates for all pauli operators. + + Parameters: + pauli_map: A dictionary mapping qubits to pauli operators. + dtype: Data type for the tensor operands. + backend: The package the tensor operands belong to. + + Returns: + A sequence of pauli gates. + """ + asarray = backend.asarray + pauli_i = asarray([[1, 0], [0, 1]], dtype=dtype) + pauli_x = asarray([[0, 1], [1, 0]], dtype=dtype) + pauli_y = asarray([[0, -1j], [1j, 0]], dtype=dtype) + pauli_z = asarray([[1, 0], [0, -1]], dtype=dtype) + + operand_map = {"I": pauli_i, "X": pauli_x, "Y": pauli_y, "Z": pauli_z} + gates = [] + for qubit, pauli_char in pauli_map.items(): + operand = operand_map.get(pauli_char) + if operand is None: + raise ValueError("pauli string character must be one of I/X/Y/Z") + gates.append((operand, (qubit,))) + return gates + + def expectation_operands(self, ham_gates): + """Create the operands for pauli string expectation computation in the + interleave format. + + Parameters: + ham_gates: A list of gates derived from Qibo hamiltonian object. + + Returns: + Operands for the contraction in the interleave format. + """ + input_bitstring = "0" * self.circuit.nqubits + + input_operands = self._get_bitstring_tensors(input_bitstring) + + ( + mode_labels, + qubits_frontier, + next_frontier, + ) = self._init_mode_labels_from_qubits(range(self.circuit.nqubits)) + + gate_mode_labels, gate_operands = self._parse_gates_to_mode_labels_operands( + self.gate_tensors, qubits_frontier, next_frontier + ) + + operands = input_operands + gate_operands + mode_labels += gate_mode_labels + + self.init_inverse_circuit(self.circuit.invert()) + + next_frontier = max(qubits_frontier.values()) + 1 + + gates_inverse = ham_gates + self.gate_tensors_inverse + + ( + gate_mode_labels_inverse, + gate_operands_inverse, + ) = self._parse_gates_to_mode_labels_operands( + gates_inverse, qubits_frontier, next_frontier + ) + mode_labels = ( + mode_labels + + gate_mode_labels_inverse + + [[qubits_frontier[ix]] for ix in range(self.circuit.nqubits)] + ) + operands = operands + gate_operands_inverse + operands[: self.circuit.nqubits] + + operand_exp_interleave = [x for y in zip(operands, mode_labels) for x in y] + + return operand_exp_interleave diff --git a/src/qibotn/circuit_to_mps.py b/src/qibotn/circuit_to_mps.py new file mode 100644 index 0000000..680ef9b --- /dev/null +++ b/src/qibotn/circuit_to_mps.py @@ -0,0 +1,47 @@ +import cupy as cp +import cuquantum.bindings.cutensornet as cutn +import numpy as np + +from qibotn.circuit_convertor import QiboCircuitToEinsum +from qibotn.mps_utils import apply_gate, initial + + +class QiboCircuitToMPS: + """A helper class to convert Qibo circuit to MPS. + + Parameters: + circ_qibo: The quantum circuit object. + gate_algo(dict): Dictionary for SVD and QR settings. + datatype (str): Either single ("complex64") or double (complex128) precision. + rand_seed(int): Seed for random number generator. + """ + + def __init__( + self, + circ_qibo, + gate_algo, + dtype="complex128", + rand_seed=0, + ): + np.random.seed(rand_seed) + cp.random.seed(rand_seed) + + self.num_qubits = circ_qibo.nqubits + self.handle = cutn.create() + self.dtype = dtype + self.mps_tensors = initial(self.num_qubits, dtype=dtype) + circuitconvertor = QiboCircuitToEinsum(circ_qibo, dtype=dtype) + + for gate, qubits in circuitconvertor.gate_tensors: + # mapping from qubits to qubit indices + # apply the gate in-place + apply_gate( + self.mps_tensors, + gate, + qubits, + algorithm=gate_algo, + options={"handle": self.handle}, + ) + + def __del__(self): + cutn.destroy(self.handle) diff --git a/src/qibotn/eval.py b/src/qibotn/eval.py new file mode 100644 index 0000000..680c817 --- /dev/null +++ b/src/qibotn/eval.py @@ -0,0 +1,497 @@ +import cupy as cp +import cuquantum.bindings.cutensornet as cutn +from cupy.cuda import nccl +from cupy.cuda.runtime import getDeviceCount +from cuquantum.tensornet import Network, contract +from mpi4py import MPI +from qibo import hamiltonians +from qibo.symbols import I, X, Y, Z + +from qibotn.circuit_convertor import QiboCircuitToEinsum +from qibotn.circuit_to_mps import QiboCircuitToMPS +from qibotn.mps_contraction_helper import MPSContractionHelper + + +def check_observable(observable, circuit_nqubit): + """Checks the type of observable and returns the appropriate Hamiltonian.""" + if observable is None: + return build_observable(circuit_nqubit) + elif isinstance(observable, dict): + return create_hamiltonian_from_dict(observable, circuit_nqubit) + elif isinstance(observable, hamiltonians.SymbolicHamiltonian): + # TODO: check if the observable is compatible with the circuit + return observable + else: + raise TypeError("Invalid observable type.") + + +def build_observable(circuit_nqubit): + """Helper function to construct a target observable.""" + hamiltonian_form = 0 + for i in range(circuit_nqubit): + hamiltonian_form += 0.5 * X(i % circuit_nqubit) * Z((i + 1) % circuit_nqubit) + + hamiltonian = hamiltonians.SymbolicHamiltonian(form=hamiltonian_form) + return hamiltonian + + +def create_hamiltonian_from_dict(data, circuit_nqubit): + """Create a Qibo SymbolicHamiltonian from a dictionary representation. + + Ensures that each Hamiltonian term explicitly acts on all circuit qubits + by adding identity (`I`) gates where needed. + + Args: + data (dict): Dictionary containing Hamiltonian terms. + circuit_nqubit (int): Total number of qubits in the quantum circuit. + + Returns: + hamiltonians.SymbolicHamiltonian: The constructed Hamiltonian. + """ + PAULI_GATES = {"X": X, "Y": Y, "Z": Z} + + terms = [] + + for term in data["terms"]: + coeff = term["coefficient"] + operators = term["operators"] # List of tuples like [("Z", 0), ("X", 1)] + + # Convert the operator list into a dictionary {qubit_index: gate} + operator_dict = {q: PAULI_GATES[g] for g, q in operators} + + # Build the full term ensuring all qubits are covered + full_term_expr = [ + operator_dict[q](q) if q in operator_dict else I(q) + for q in range(circuit_nqubit) + ] + + # Multiply all operators together to form a single term + term_expr = full_term_expr[0] + for op in full_term_expr[1:]: + term_expr *= op + + # Scale by the coefficient + final_term = coeff * term_expr + terms.append(final_term) + + if not terms: + raise ValueError("No valid Hamiltonian terms were added.") + + # Combine all terms + hamiltonian_form = sum(terms) + + return hamiltonians.SymbolicHamiltonian(hamiltonian_form) + + +def get_ham_gates(pauli_map, dtype="complex128", backend=cp): + """Populate the gates for all pauli operators. + + Parameters: + pauli_map: A dictionary mapping qubits to pauli operators. + dtype: Data type for the tensor operands. + backend: The package the tensor operands belong to. + + Returns: + A sequence of pauli gates. + """ + asarray = backend.asarray + pauli_i = asarray([[1, 0], [0, 1]], dtype=dtype) + pauli_x = asarray([[0, 1], [1, 0]], dtype=dtype) + pauli_y = asarray([[0, -1j], [1j, 0]], dtype=dtype) + pauli_z = asarray([[1, 0], [0, -1]], dtype=dtype) + + operand_map = {"I": pauli_i, "X": pauli_x, "Y": pauli_y, "Z": pauli_z} + gates = [] + for qubit, pauli_char, coeff in pauli_map: + operand = operand_map.get(pauli_char) + if operand is None: + raise ValueError("pauli string character must be one of I/X/Y/Z") + operand = coeff * operand + gates.append((operand, (qubit,))) + return gates + + +def extract_gates_and_qubits(hamiltonian): + """ + Extracts the gates and their corresponding qubits from a Qibo Hamiltonian. + + Parameters: + hamiltonian (qibo.hamiltonians.Hamiltonian or qibo.hamiltonians.SymbolicHamiltonian): + A Qibo Hamiltonian object. + + Returns: + list of tuples: [(coefficient, [(gate, qubit), ...]), ...] + - coefficient: The prefactor of the term. + - list of (gate, qubit): Each term's gates and the qubits they act on. + """ + extracted_terms = [] + + if isinstance(hamiltonian, hamiltonians.SymbolicHamiltonian): + for term in hamiltonian.terms: + coeff = term.coefficient # Extract coefficient + gate_qubit_list = [] + + # Extract gate and qubit information + for factor in term.factors: + gate_name = str(factor)[ + 0 + ] # Extract the gate type (X, Y, Z) from 'X0', 'Z1' + qubit = int(str(factor)[1:]) # Extract the qubit index + gate_qubit_list.append((qubit, gate_name, coeff)) + coeff = 1.0 + + extracted_terms.append(gate_qubit_list) + + else: + raise ValueError( + "Unsupported Hamiltonian type. Must be SymbolicHamiltonian or Hamiltonian." + ) + + return extracted_terms + + +def initialize_mpi(): + """Initialize MPI communication and device selection.""" + comm = MPI.COMM_WORLD + rank = comm.Get_rank() + size = comm.Get_size() + device_id = rank % getDeviceCount() + cp.cuda.Device(device_id).use() + return comm, rank, size, device_id + + +def initialize_nccl(comm_mpi, rank, size): + """Initialize NCCL communication.""" + nccl_id = nccl.get_unique_id() if rank == 0 else None + nccl_id = comm_mpi.bcast(nccl_id, root=0) + return nccl.NcclCommunicator(size, nccl_id, rank) + + +def get_operands(qibo_circ, datatype, rank, comm): + """Perform circuit conversion and broadcast operands.""" + if rank == 0: + myconvertor = QiboCircuitToEinsum(qibo_circ, dtype=datatype) + operands = myconvertor.state_vector_operands() + else: + operands = None + return comm.bcast(operands, root=0) + + +def compute_optimal_path(network, n_samples, size, comm): + """Compute contraction path and broadcast optimal selection.""" + path, info = network.contract_path( + optimize={ + "samples": n_samples, + "slicing": { + "min_slices": max(32, size), + "memory_model": cutn.MemoryModel.CUTENSOR, + }, + } + ) + opt_cost, sender = comm.allreduce( + sendobj=(info.opt_cost, comm.Get_rank()), op=MPI.MINLOC + ) + return comm.bcast(info, sender) + + +def compute_slices(info, rank, size): + """Determine the slice range each process should compute.""" + num_slices = info.num_slices + chunk, extra = num_slices // size, num_slices % size + slice_begin = rank * chunk + min(rank, extra) + slice_end = ( + num_slices if rank == size - 1 else (rank + 1) * chunk + min(rank + 1, extra) + ) + return range(slice_begin, slice_end) + + +def reduce_result(result, comm, method="MPI", root=0): + """Reduce results across processes.""" + if method == "MPI": + return comm.reduce(sendobj=result, op=MPI.SUM, root=root) + + elif method == "NCCL": + stream_ptr = cp.cuda.get_current_stream().ptr + if result.dtype == cp.complex128: + count = result.size * 2 # complex128 has 2 float64 numbers + nccl_type = nccl.NCCL_FLOAT64 + elif result.dtype == cp.complex64: + count = result.size * 2 # complex64 has 2 float32 numbers + nccl_type = nccl.NCCL_FLOAT32 + else: + raise TypeError(f"Unsupported dtype for NCCL reduce: {result.dtype}") + + comm.reduce( + result.data.ptr, + result.data.ptr, + count, + nccl_type, + nccl.NCCL_SUM, + root, + stream_ptr, + ) + return result + else: + raise ValueError(f"Unknown reduce method: {method}") + + +def dense_vector_tn_MPI(qibo_circ, datatype, n_samples=8): + """Convert qibo circuit to tensornet (TN) format and perform contraction + using multi node and multi GPU through MPI. + + The conversion is performed by QiboCircuitToEinsum(), after which it + goes through 2 steps: pathfinder and execution. The pathfinder looks + at user defined number of samples (n_samples) iteratively to select + the least costly contraction path. This is sped up with multi + thread. After pathfinding the optimal path is used in the actual + contraction to give a dense vector representation of the TN. + + Parameters: + qibo_circ: The quantum circuit object. + datatype (str): Either single ("complex64") or double (complex128) precision. + n_samples(int): Number of samples for pathfinding. + + Returns: + Dense vector of quantum circuit. + """ + comm, rank, size, device_id = initialize_mpi() + operands = get_operands(qibo_circ, datatype, rank, comm) + network = Network(*operands, options={"device_id": device_id}) + info = compute_optimal_path(network, n_samples, size, comm) + path, info = network.contract_path( + optimize={"path": info.path, "slicing": info.slices} + ) + slices = compute_slices(info, rank, size) + result = network.contract(slices=slices) + return reduce_result(result, comm, method="MPI"), rank + + +def dense_vector_tn_nccl(qibo_circ, datatype, n_samples=8): + """Convert qibo circuit to tensornet (TN) format and perform contraction + using multi node and multi GPU through NCCL. + + The conversion is performed by QiboCircuitToEinsum(), after which it + goes through 2 steps: pathfinder and execution. The pathfinder looks + at user defined number of samples (n_samples) iteratively to select + the least costly contraction path. This is sped up with multi + thread. After pathfinding the optimal path is used in the actual + contraction to give a dense vector representation of the TN. + + Parameters: + qibo_circ: The quantum circuit object. + datatype (str): Either single ("complex64") or double (complex128) precision. + n_samples(int): Number of samples for pathfinding. + + Returns: + Dense vector of quantum circuit. + """ + comm_mpi, rank, size, device_id = initialize_mpi() + comm_nccl = initialize_nccl(comm_mpi, rank, size) + operands = get_operands(qibo_circ, datatype, rank, comm_mpi) + network = Network(*operands) + info = compute_optimal_path(network, n_samples, size, comm_mpi) + path, info = network.contract_path( + optimize={"path": info.path, "slicing": info.slices} + ) + slices = compute_slices(info, rank, size) + result = network.contract(slices=slices) + return reduce_result(result, comm_nccl, method="NCCL"), rank + + +def dense_vector_tn(qibo_circ, datatype): + """Convert qibo circuit to tensornet (TN) format and perform contraction to + dense vector. + + Parameters: + qibo_circ: The quantum circuit object. + datatype (str): Either single ("complex64") or double (complex128) precision. + + Returns: + Dense vector of quantum circuit. + """ + myconvertor = QiboCircuitToEinsum(qibo_circ, dtype=datatype) + return contract(*myconvertor.state_vector_operands()) + + +def expectation_tn_nccl(qibo_circ, datatype, observable, n_samples=8): + """Convert qibo circuit to tensornet (TN) format and perform contraction to + expectation of given Pauli string using multi node and multi GPU through + NCCL. + + The conversion is performed by QiboCircuitToEinsum(), after which it + goes through 2 steps: pathfinder and execution. The + pauli_string_pattern is used to generate the pauli string + corresponding to the number of qubits of the system. The pathfinder + looks at user defined number of samples (n_samples) iteratively to + select the least costly contraction path. This is sped up with multi + thread. After pathfinding the optimal path is used in the actual + contraction to give an expectation value. + + Parameters: + qibo_circ: The quantum circuit object. + datatype (str): Either single ("complex64") or double (complex128) precision. + pauli_string_pattern(str): pauli string pattern. + n_samples(int): Number of samples for pathfinding. + + Returns: + Expectation of quantum circuit due to pauli string. + """ + + comm_mpi, rank, size, device_id = initialize_mpi() + + comm_nccl = initialize_nccl(comm_mpi, rank, size) + + observable = check_observable(observable, qibo_circ.nqubits) + + ham_gate_map = extract_gates_and_qubits(observable) + + if rank == 0: + myconvertor = QiboCircuitToEinsum(qibo_circ, dtype=datatype) + + exp = 0 + for each_ham in ham_gate_map: + ham_gates = get_ham_gates(each_ham) + # Perform circuit conversion + if rank == 0: + operands = myconvertor.expectation_operands(ham_gates) + else: + operands = None + + operands = comm_mpi.bcast(operands, root=0) + + network = Network(*operands) + + # Compute the path on all ranks with 8 samples for hyperoptimization. Force slicing to enable parallel contraction. + info = compute_optimal_path(network, n_samples, size, comm_mpi) + + # Recompute path with the selected optimal settings + path, info = network.contract_path( + optimize={"path": info.path, "slicing": info.slices} + ) + + slices = compute_slices(info, rank, size) + + # Contract the group of slices the process is responsible for. + result = network.contract(slices=slices) + + # Sum the partial contribution from each process on root. + result = reduce_result(result, comm_nccl, method="NCCL", root=0) + + exp += result + + return exp, rank + + +def expectation_tn_MPI(qibo_circ, datatype, observable, n_samples=8): + """Convert qibo circuit to tensornet (TN) format and perform contraction to + expectation of given Pauli string using multi node and multi GPU through + MPI. + + The conversion is performed by QiboCircuitToEinsum(), after which it + goes through 2 steps: pathfinder and execution. The + pauli_string_pattern is used to generate the pauli string + corresponding to the number of qubits of the system. The pathfinder + looks at user defined number of samples (n_samples) iteratively to + select the least costly contraction path. This is sped up with multi + thread. After pathfinding the optimal path is used in the actual + contraction to give an expectation value. + + Parameters: + qibo_circ: The quantum circuit object. + datatype (str): Either single ("complex64") or double (complex128) precision. + pauli_string_pattern(str): pauli string pattern. + n_samples(int): Number of samples for pathfinding. + + Returns: + Expectation of quantum circuit due to pauli string. + """ + # Initialize MPI and device + comm, rank, size, device_id = initialize_mpi() + + observable = check_observable(observable, qibo_circ.nqubits) + + ham_gate_map = extract_gates_and_qubits(observable) + + if rank == 0: + myconvertor = QiboCircuitToEinsum(qibo_circ, dtype=datatype) + exp = 0 + for each_ham in ham_gate_map: + ham_gates = get_ham_gates(each_ham) + # Perform circuit conversion + # Perform circuit conversion + if rank == 0: + operands = myconvertor.expectation_operands(ham_gates) + else: + operands = None + + operands = comm.bcast(operands, root=0) + + # Create network object. + network = Network(*operands, options={"device_id": device_id}) + + # Compute optimal contraction path + info = compute_optimal_path(network, n_samples, size, comm) + + # Set path and slices. + path, info = network.contract_path( + optimize={"path": info.path, "slicing": info.slices} + ) + + # Compute slice range for each rank + slices = compute_slices(info, rank, size) + + # Perform contraction + result = network.contract(slices=slices) + + # Sum the partial contribution from each process on root. + result = reduce_result(result, comm, method="MPI", root=0) + + if rank == 0: + exp += result + + return exp, rank + + +def expectation_tn(qibo_circ, datatype, observable): + """Convert qibo circuit to tensornet (TN) format and perform contraction to + expectation of given Pauli string. + + Parameters: + qibo_circ: The quantum circuit object. + datatype (str): Either single ("complex64") or double (complex128) precision. + pauli_string_pattern(str): pauli string pattern. + + Returns: + Expectation of quantum circuit due to pauli string. + """ + myconvertor = QiboCircuitToEinsum(qibo_circ, dtype=datatype) + + observable = check_observable(observable, qibo_circ.nqubits) + + ham_gate_map = extract_gates_and_qubits(observable) + exp = 0 + for each_ham in ham_gate_map: + ham_gates = get_ham_gates(each_ham) + expectation_operands = myconvertor.expectation_operands(ham_gates) + exp += contract(*expectation_operands) + return exp + + +def dense_vector_mps(qibo_circ, gate_algo, datatype): + """Convert qibo circuit to matrix product state (MPS) format and perform + contraction to dense vector. + + Parameters: + qibo_circ: The quantum circuit object. + gate_algo(dict): Dictionary for SVD and QR settings. + datatype (str): Either single ("complex64") or double (complex128) precision. + + Returns: + Dense vector of quantum circuit. + """ + myconvertor = QiboCircuitToMPS(qibo_circ, gate_algo, dtype=datatype) + mps_helper = MPSContractionHelper(myconvertor.num_qubits) + + return mps_helper.contract_state_vector( + myconvertor.mps_tensors, {"handle": myconvertor.handle} + ) diff --git a/src/qibotn/eval_qu.py b/src/qibotn/eval_qu.py new file mode 100644 index 0000000..6cb9f39 --- /dev/null +++ b/src/qibotn/eval_qu.py @@ -0,0 +1,46 @@ +import numpy as np +import quimb.tensor as qtn + + +def init_state_tn(nqubits, init_state_sv): + """Create a matrix product state directly from a dense vector. + + Args: + nqubits (int): Total number of qubits in the circuit. + init_state_sv (list): Initial state in the dense vector form. + + Returns: + list: Matrix product state representation of the dense vector. + """ + + dims = tuple(2 * np.ones(nqubits, dtype=int)) + + return qtn.tensor_1d.MatrixProductState.from_dense(init_state_sv, dims) + + +def dense_vector_tn_qu(qasm: str, initial_state, mps_opts, backend="numpy"): + """Evaluate circuit in QASM format with Quimb. + + Args: + qasm (str): QASM program. + initial_state (list): Initial state in the dense vector form. If ``None`` the default ``|00...0>`` state is used. + mps_opts (dict): Parameters to tune the gate_opts for mps settings in ``class quimb.tensor.circuit.CircuitMPS``. + backend (str): Backend to perform the contraction with, e.g. ``numpy``, ``cupy``, ``jax``. Passed to ``opt_einsum``. + + Returns: + list: Amplitudes of final state after the simulation of the circuit. + """ + + if initial_state is not None: + nqubits = int(np.log2(len(initial_state))) + initial_state = init_state_tn(nqubits, initial_state) + + circ_cls = qtn.circuit.CircuitMPS if mps_opts else qtn.circuit.Circuit + circ_quimb = circ_cls.from_openqasm2_str( + qasm, psi0=initial_state, gate_opts=mps_opts + ) + + interim = circ_quimb.psi.full_simplify(seq="DRC") + amplitudes = interim.to_dense(backend=backend) + + return amplitudes diff --git a/src/qibotn/mps_contraction_helper.py b/src/qibotn/mps_contraction_helper.py new file mode 100644 index 0000000..fcb4441 --- /dev/null +++ b/src/qibotn/mps_contraction_helper.py @@ -0,0 +1,118 @@ +from cuquantum.tensornet import contract, contract_path + +# Reference: https://github.com/NVIDIA/cuQuantum/blob/main/python/samples/cutensornet/tn_algorithms/mps_algorithms.ipynb + + +class MPSContractionHelper: + """A helper class to compute various quantities for a given MPS. + + Interleaved format is used to construct the input args for `cuquantum.contract`. + + Reference: https://github.com/NVIDIA/cuQuantum/blob/main/python/samples/cutensornet/tn_algorithms/mps_algorithms.ipynb + + The following compute quantities are supported: + + - the norm of the MPS. + - the equivalent state vector from the MPS. + - the expectation value for a given operator. + - the equivalent state vector after multiplying an MPO to an MPS. + + Parameters: + num_qubits: The number of qubits for the MPS. + """ + + def __init__(self, num_qubits): + self.num_qubits = num_qubits + self.bra_modes = [(2 * i, 2 * i + 1, 2 * i + 2) for i in range(num_qubits)] + offset = 2 * num_qubits + 1 + self.ket_modes = [ + (i + offset, 2 * i + 1, i + 1 + offset) for i in range(num_qubits) + ] + + def contract_norm(self, mps_tensors, options=None): + """Contract the corresponding tensor network to form the norm of the + MPS. + + Parameters: + mps_tensors: A list of rank-3 ndarray-like tensor objects. + The indices of the ith tensor are expected to be bonding index to the i-1 tensor, + the physical mode, and then the bonding index to the i+1th tensor. + options: Specify the contract and decompose options. + + Returns: + The norm of the MPS. + """ + interleaved_inputs = [] + for i, o in enumerate(mps_tensors): + interleaved_inputs.extend( + [o, self.bra_modes[i], o.conj(), self.ket_modes[i]] + ) + interleaved_inputs.append([]) # output + return self._contract(interleaved_inputs, options=options).real + + def contract_state_vector(self, mps_tensors, options=None): + """Contract the corresponding tensor network to form the state vector + representation of the MPS. + + Parameters: + mps_tensors: A list of rank-3 ndarray-like tensor objects. + The indices of the ith tensor are expected to be bonding index to the i-1 tensor, + the physical mode, and then the bonding index to the i+1th tensor. + options: Specify the contract and decompose options. + + Returns: + An ndarray-like object as the state vector. + """ + interleaved_inputs = [] + for i, o in enumerate(mps_tensors): + interleaved_inputs.extend([o, self.bra_modes[i]]) + output_modes = tuple([bra_modes[1] for bra_modes in self.bra_modes]) + interleaved_inputs.append(output_modes) # output + return self._contract(interleaved_inputs, options=options) + + def contract_expectation( + self, mps_tensors, operator, qubits, options=None, normalize=False + ): + """Contract the corresponding tensor network to form the expectation of + the MPS. + + Parameters: + mps_tensors: A list of rank-3 ndarray-like tensor objects. + The indices of the ith tensor are expected to be bonding index to the i-1 tensor, + the physical mode, and then the bonding index to the i+1th tensor. + operator: A ndarray-like tensor object. + The modes of the operator are expected to be output qubits followed by input qubits, e.g, + ``A, B, a, b`` where `a, b` denotes the inputs and `A, B'` denotes the outputs. + qubits: A sequence of integers specifying the qubits that the operator is acting on. + options: Specify the contract and decompose options. + normalize: Whether to scale the expectation value by the normalization factor. + + Returns: + An ndarray-like object as the state vector. + """ + + interleaved_inputs = [] + extra_mode = 3 * self.num_qubits + 2 + operator_modes = [None] * len(qubits) + [self.bra_modes[q][1] for q in qubits] + qubits = list(qubits) + for i, o in enumerate(mps_tensors): + interleaved_inputs.extend([o, self.bra_modes[i]]) + k_modes = self.ket_modes[i] + if i in qubits: + k_modes = (k_modes[0], extra_mode, k_modes[2]) + q = qubits.index(i) + operator_modes[q] = extra_mode # output modes + extra_mode += 1 + interleaved_inputs.extend([o.conj(), k_modes]) + interleaved_inputs.extend([operator, tuple(operator_modes)]) + interleaved_inputs.append([]) # output + if normalize: + norm = self.contract_norm(mps_tensors, options=options) + else: + norm = 1 + return self._contract(interleaved_inputs, options=options) / norm + + def _contract(self, interleaved_inputs, options=None): + path = contract_path(*interleaved_inputs, options=options)[0] + + return contract(*interleaved_inputs, options=options, optimize={"path": path}) diff --git a/src/qibotn/mps_utils.py b/src/qibotn/mps_utils.py new file mode 100644 index 0000000..1450837 --- /dev/null +++ b/src/qibotn/mps_utils.py @@ -0,0 +1,95 @@ +import cupy as cp +from cuquantum.tensornet import contract +from cuquantum.tensornet.experimental import contract_decompose + + +def initial(num_qubits, dtype): + r"""Generate the MPS with an initial state of :math:`\ket{00...00}` + + Parameters: + num_qubits: Number of qubits in the Quantum Circuit. + dtype: Either single ("complex64") or double (complex128) precision. + + Returns: + The initial MPS tensors. + """ + state_tensor = cp.asarray([1, 0], dtype=dtype).reshape(1, 2, 1) + mps_tensors = [state_tensor] * num_qubits + return mps_tensors + + +def mps_site_right_swap(mps_tensors, i, **kwargs): + """Perform the swap operation between the ith and i+1th MPS tensors. + + Parameters: + mps_tensors: Tensors representing MPS + i (int): index of the tensor to swap + + Returns: + The updated MPS tensors. + """ + # contraction followed by QR decomposition + a, _, b = contract_decompose( + "ipj,jqk->iqj,jpk", + *mps_tensors[i : i + 2], + algorithm=kwargs.get("algorithm", None), + options=kwargs.get("options", None), + ) + mps_tensors[i : i + 2] = (a, b) + return mps_tensors + + +def apply_gate(mps_tensors, gate, qubits, **kwargs): + """Apply the gate operand to the MPS tensors in-place. + + # Reference: https://github.com/NVIDIA/cuQuantum/blob/main/python/samples/cutensornet/tn_algorithms/mps_algorithms.ipynb + + Parameters: + mps_tensors: A list of rank-3 ndarray-like tensor objects. + The indices of the ith tensor are expected to be the bonding index to the i-1 tensor, + the physical mode, and then the bonding index to the i+1th tensor. + gate: A ndarray-like tensor object representing the gate operand. + The modes of the gate is expected to be output qubits followed by input qubits, e.g, + ``A, B, a, b`` where ``a, b`` denotes the inputs and ``A, B`` denotes the outputs. + qubits: A sequence of integers denoting the qubits that the gate is applied onto. + algorithm: The contract and decompose algorithm to use for gate application. + Can be either a `dict` or a `ContractDecomposeAlgorithm`. + options: Specify the contract and decompose options. + + Returns: + The updated MPS tensors. + """ + + n_qubits = len(qubits) + if n_qubits == 1: + # single-qubit gate + i = qubits[0] + mps_tensors[i] = contract( + "ipj,qp->iqj", mps_tensors[i], gate, options=kwargs.get("options", None) + ) # in-place update + elif n_qubits == 2: + # two-qubit gate + i, j = qubits + if i > j: + # swap qubits order + return apply_gate(mps_tensors, gate.transpose(1, 0, 3, 2), (j, i), **kwargs) + elif i + 1 == j: + # two adjacent qubits + a, _, b = contract_decompose( + "ipj,jqk,rspq->irj,jsk", + *mps_tensors[i : i + 2], + gate, + algorithm=kwargs.get("algorithm", None), + options=kwargs.get("options", None), + ) + mps_tensors[i : i + 2] = (a, b) # in-place update + else: + # non-adjacent two-qubit gate + # step 1: swap i with i+1 + mps_site_right_swap(mps_tensors, i, **kwargs) + # step 2: apply gate to (i+1, j) pair. This amounts to a recursive swap until the two qubits are adjacent + apply_gate(mps_tensors, gate, (i + 1, j), **kwargs) + # step 3: swap back i and i+1 + mps_site_right_swap(mps_tensors, i, **kwargs) + else: + raise NotImplementedError("Only one- and two-qubit gates supported") diff --git a/src/qibotn/result.py b/src/qibotn/result.py new file mode 100644 index 0000000..33be61c --- /dev/null +++ b/src/qibotn/result.py @@ -0,0 +1,66 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import Union + +from numpy import ndarray +from qibo.config import raise_error + +from qibotn.backends.abstract import QibotnBackend + + +@dataclass +class TensorNetworkResult: + """ + Object to store and process the output of a Tensor Network simulation of a quantum circuit. + + Args: + nqubits (int): number of qubits involved in the simulation; + backend (QibotnBackend): specific backend on which the simulation has been performed; + measures (dict): measures (if performed) during the tensor network simulation; + measured_probabilities (Union[dict, ndarray]): probabilities of the final state + according to the simulation; + prob_type (str): string identifying the method used to compute the probabilities. + Especially useful in case the `QmatchateaBackend` is selected. + statevector (ndarray): if computed, the reconstructed statevector. + """ + + nqubits: int + backend: QibotnBackend + measures: dict + measured_probabilities: Union[dict, ndarray] + prob_type: str + statevector: ndarray + + def __post_init__(self): + # TODO: define the general convention when using backends different from qmatchatea + if self.measured_probabilities is None: + self.measured_probabilities = {"default": self.measured_probabilities} + + def probabilities(self): + """Return calculated probabilities according to the given method.""" + if self.prob_type == "U": + measured_probabilities = deepcopy(self.measured_probabilities) + for bitstring, prob in self.measured_probabilities[self.prob_type].items(): + measured_probabilities[self.prob_type][bitstring] = prob[1] - prob[0] + probabilities = measured_probabilities[self.prob_type] + else: + probabilities = self.measured_probabilities + return probabilities + + def frequencies(self): + """Return frequencies if a certain number of shots has been set.""" + if self.measures is None: + raise_error( + ValueError, + f"To access frequencies, circuit has to be executed with a given number of shots != None", + ) + return self.measures + + def state(self): + """Return the statevector if the number of qubits is less than 20.""" + if self.nqubits < 20: + return self.statevector + raise_error( + NotImplementedError, + f"Tensor network simulation cannot be used to reconstruct statevector for >= 20 .", + ) diff --git a/tests/config.py b/tests/config.py new file mode 100644 index 0000000..7403673 --- /dev/null +++ b/tests/config.py @@ -0,0 +1,12 @@ +from dataclasses import dataclass +from typing import Optional + + +@dataclass +class Executor: + backend: str + platform: Optional[str] = None + + +qibo = Executor(backend="qibojit", platform="numpy") +quimb = Executor(backend="numpy") diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..c5e9ed4 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,66 @@ +"""conftest.py. + +Pytest fixtures. +""" + +import sys + +import pytest + +# backends to be tested +# TODO: add cutensornet and quimb here as well +BACKENDS = ["cutensornet"] +# BACKENDS = ["qmatchatea"] + + +def get_backend(backend_name): + + from qibotn.backends.cutensornet import CuTensorNet + from qibotn.backends.qmatchatea import QMatchaTeaBackend + + NAME2BACKEND = {"qmatchatea": QMatchaTeaBackend, "cutensornet": CuTensorNet} + + return NAME2BACKEND[backend_name]() + + +AVAILABLE_BACKENDS = [] +for backend_name in BACKENDS: + try: + _backend = get_backend(backend_name) + AVAILABLE_BACKENDS.append(backend_name) + except (ModuleNotFoundError, ImportError): + pass + + +def pytest_runtest_setup(item): + ALL = {"darwin", "linux"} + supported_platforms = ALL.intersection(mark.name for mark in item.iter_markers()) + plat = sys.platform + if supported_platforms and plat not in supported_platforms: # pragma: no cover + # case not covered by workflows + pytest.skip(f"Cannot run test on platform {plat}.") + + +@pytest.fixture +def backend(backend_name): + yield get_backend(backend_name) + + +def pytest_runtest_setup(item): + ALL = {"darwin", "linux"} + supported_platforms = ALL.intersection(mark.name for mark in item.iter_markers()) + plat = sys.platform + if supported_platforms and plat not in supported_platforms: # pragma: no cover + # case not covered by workflows + pytest.skip(f"Cannot run test on platform {plat}.") + + +def pytest_configure(config): + config.addinivalue_line("markers", "linux: mark test to run only on linux") + + +def pytest_generate_tests(metafunc): + module_name = metafunc.module.__name__ + + if "backend_name" in metafunc.fixturenames: + metafunc.parametrize("backend_name", AVAILABLE_BACKENDS) diff --git a/tests/test_circuit_execution.py b/tests/test_circuit_execution.py new file mode 100644 index 0000000..c5dfc86 --- /dev/null +++ b/tests/test_circuit_execution.py @@ -0,0 +1,91 @@ +import math + +import pytest +from qibo import Circuit, gates, hamiltonians +from qibo.symbols import X, Z + +from qibotn.backends.qmatchatea import QMatchaTeaBackend + + +def build_observable(nqubits): + """Helper function to construct a target observable.""" + hamiltonian_form = 0 + for i in range(nqubits): + hamiltonian_form += 0.5 * X(i % nqubits) * Z((i + 1) % nqubits) + + hamiltonian = hamiltonians.SymbolicHamiltonian(form=hamiltonian_form) + return hamiltonian, hamiltonian_form + + +def build_GHZ(nqubits): + """Helper function to construct a layered quantum circuit.""" + circ = Circuit(nqubits) + circ.add(gates.H(0)) + [circ.add(gates.CNOT(q, q + 1)) for q in range(nqubits - 1)] + return circ + + +def construct_targets(nqubits): + """Construct strings of 1s and 0s of size `nqubits`.""" + ones = "1" * nqubits + zeros = "0" * nqubits + return ones, zeros + + +@pytest.mark.parametrize("nqubits", [2, 10, 40]) +def test_probabilities(backend, nqubits): + + circ = build_GHZ(nqubits=nqubits) + + if isinstance(backend, QMatchaTeaBackend): + # unbiased prob + out_u = backend.execute_circuit( + circuit=circ, + prob_type="U", + num_samples=1000, + ).probabilities() + + math.isclose(out_u[0], 0.5, abs_tol=1e-7) + math.isclose(out_u[1], 0.5, abs_tol=1e-7) + + out_g = backend.execute_circuit( + circuit=circ, + prob_type="G", + prob_threshold=1.0, + ).probabilities() + + math.isclose(out_g[0], 0.5, abs_tol=1e-7) + math.isclose(out_g[1], 0.5, abs_tol=1e-7) + + out_e = backend.execute_circuit( + circuit=circ, + prob_type="E", + prob_threshold=0.2, + ).probabilities() + + math.isclose(out_e[0], 0.5, abs_tol=1e-7) + math.isclose(out_e[1], 0.5, abs_tol=1e-7) + + +@pytest.mark.parametrize("nqubits", [2, 10, 40]) +@pytest.mark.parametrize("nshots", [100, 1000]) +def test_shots(backend, nqubits, nshots): + circ = build_GHZ(nqubits=nqubits) + ones, zeros = construct_targets(nqubits) + + # For p = 0.5, sigma = sqrt(nshots * 0.5 * 0.5) = sqrt(nshots)/2. + sigma_threshold = 3 * (math.sqrt(nshots) / 2) + + outcome = backend.execute_circuit(circ, nshots=nshots) + frequencies = outcome.frequencies() + + shots_ones = frequencies.get(ones, 0) + shots_zeros = frequencies.get(zeros, 0) + + # Check that the counts for both outcomes are within the 3-sigma threshold of nshots/2. + assert ( + abs(shots_ones - (nshots / 2)) < sigma_threshold + ), f"Count for {ones} deviates too much: {shots_ones} vs expected {nshots/2}" + assert ( + abs(shots_zeros - (nshots / 2)) < sigma_threshold + ), f"Count for {zeros} deviates too much: {shots_zeros} vs expected {nshots/2}" diff --git a/tests/test_cuquantum_cutensor_backend.py b/tests/test_cuquantum_cutensor_backend.py new file mode 100644 index 0000000..2bd4c26 --- /dev/null +++ b/tests/test_cuquantum_cutensor_backend.py @@ -0,0 +1,199 @@ +import math + +import cupy as cp +import pytest +import qibo +from qibo import construct_backend, hamiltonians +from qibo.models import QFT +from qibo.symbols import X, Z + +ABS_TOL = 1e-7 + + +def qibo_qft(nqubits, swaps): + circ_qibo = QFT(nqubits, swaps) + state_vec = circ_qibo().state(numpy=True) + return circ_qibo, state_vec + + +def build_observable(nqubits): + """Helper function to construct a target observable.""" + hamiltonian_form = 0 + for i in range(nqubits): + hamiltonian_form += 0.5 * X(i % nqubits) * Z((i + 1) % nqubits) + + hamiltonian = hamiltonians.SymbolicHamiltonian(form=hamiltonian_form) + return hamiltonian, hamiltonian_form + + +def build_observable_dict(nqubits): + """Construct a target observable as a dictionary representation. + + Returns a dictionary suitable for `create_hamiltonian_from_dict`. + """ + terms = [] + + for i in range(nqubits): + term = { + "coefficient": 0.5, + "operators": [("X", i % nqubits), ("Z", (i + 1) % nqubits)], + } + terms.append(term) + + return {"terms": terms} + + +@pytest.mark.gpu +@pytest.mark.parametrize("nqubits", [1, 2, 5, 10]) +def test_eval(nqubits: int, dtype="complex128"): + """ + Args: + nqubits (int): Total number of qubits in the system. + dtype (str): The data type for precision, 'complex64' for single, + 'complex128' for double. + """ + # Test qibo + qibo.set_backend(backend="numpy") + qibo_circ, result_sv = qibo_qft(nqubits, swaps=True) + result_sv_cp = cp.asarray(result_sv) + + # Test cutensornet + backend = construct_backend(backend="qibotn", platform="cutensornet") + # Test with no settings specified. Default is dense vector calculation without MPI or NCCL. + result_tn = backend.execute_circuit(circuit=qibo_circ) + print( + f"State vector difference: {abs(result_tn.statevector.flatten() - result_sv_cp).max():0.3e}" + ) + assert cp.allclose( + result_sv_cp, result_tn.statevector.flatten() + ), "Resulting dense vectors do not match" + + # Test with explicit settings specified. + comp_set_w_bool = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": False, + } + backend.configure_tn_simulation(comp_set_w_bool) + result_tn = backend.execute_circuit(circuit=qibo_circ) + print( + f"State vector difference: {abs(result_tn.statevector.flatten() - result_sv_cp).max():0.3e}" + ) + assert cp.allclose( + result_sv_cp, result_tn.statevector.flatten() + ), "Resulting dense vectors do not match" + + +@pytest.mark.gpu +@pytest.mark.parametrize("nqubits", [2, 5, 10]) +def test_mps(nqubits: int, dtype="complex128"): + """Evaluate MPS with cuQuantum. + + Args: + nqubits (int): Total number of qubits in the system. + dtype (str): The data type for precision, 'complex64' for single, + 'complex128' for double. + """ + + # Test qibo + qibo.set_backend(backend="numpy") + qibo_circ, result_sv = qibo_qft(nqubits, swaps=True) + result_sv_cp = cp.asarray(result_sv) + + # Test cutensornet + backend = construct_backend(backend="qibotn", platform="cutensornet") + # Test with simple MPS settings specified using bool. Uses the default MPS parameters. + comp_set_w_bool = { + "MPI_enabled": False, + "MPS_enabled": True, + "NCCL_enabled": False, + "expectation_enabled": False, + } + backend.configure_tn_simulation(comp_set_w_bool) + result_tn = backend.execute_circuit(circuit=qibo_circ) + print( + f"State vector difference: {abs(result_tn.statevector.flatten() - result_sv_cp).max():0.3e}" + ) + assert cp.allclose( + result_tn.statevector.flatten(), result_sv_cp + ), "Resulting dense vectors do not match" + + # Test with explicit MPS computation settings specified using Dict. Users able to specify parameters like qr_method etc. + comp_set_w_MPS_config_para = { + "MPI_enabled": False, + "MPS_enabled": { + "qr_method": False, + "svd_method": { + "partition": "UV", + "abs_cutoff": 1e-12, + }, + }, + "NCCL_enabled": False, + "expectation_enabled": False, + } + backend.configure_tn_simulation(comp_set_w_MPS_config_para) + result_tn = backend.execute_circuit(circuit=qibo_circ) + print( + f"State vector difference: {abs(result_tn.statevector.flatten() - result_sv_cp).max():0.3e}" + ) + assert cp.allclose( + result_tn.statevector.flatten(), result_sv_cp + ), "Resulting dense vectors do not match" + + +@pytest.mark.parametrize("nqubits", [2, 5, 10]) +def test_expectation(nqubits: int, dtype="complex128"): + + # Test qibo + qibo_circ, state_vec_qibo = qibo_qft(nqubits, swaps=True) + ham, ham_form = build_observable(nqubits) + numpy_backend = construct_backend("numpy") + exact_expval = numpy_backend.calculate_expectation_state( + hamiltonian=ham, + state=state_vec_qibo, + normalize=False, + ) + + # Test cutensornet + backend = construct_backend(backend="qibotn", platform="cutensornet") + + # Test with simple settings using bool. Uses default Hamilitonian for expectation calculation. + comp_set_w_bool = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": True, + } + backend.configure_tn_simulation(comp_set_w_bool) + result_tn = backend.execute_circuit(circuit=qibo_circ) + assert math.isclose( + exact_expval.item(), result_tn.real.get().item(), abs_tol=ABS_TOL + ) + + # Test with user defined hamiltonian using "hamiltonians.SymbolicHamiltonian" object. + comp_set_w_hamiltonian_obj = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": ham, + } + backend.configure_tn_simulation(comp_set_w_hamiltonian_obj) + result_tn = backend.execute_circuit(circuit=qibo_circ) + assert math.isclose( + exact_expval.item(), result_tn.real.get().item(), abs_tol=ABS_TOL + ) + + # Test with user defined hamiltonian using Dictionary object form of hamiltonian. + ham_dict = build_observable_dict(nqubits) + comp_set_w_hamiltonian_dict = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": ham_dict, + } + backend.configure_tn_simulation(comp_set_w_hamiltonian_dict) + result_tn = backend.execute_circuit(circuit=qibo_circ) + assert math.isclose( + exact_expval.item(), result_tn.real.get().item(), abs_tol=ABS_TOL + ) diff --git a/tests/test_cuquantum_cutensor_mpi_backend.py b/tests/test_cuquantum_cutensor_mpi_backend.py new file mode 100644 index 0000000..0645800 --- /dev/null +++ b/tests/test_cuquantum_cutensor_mpi_backend.py @@ -0,0 +1,315 @@ +# mpirun --allow-run-as-root -np 2 python -m pytest --with-mpi test_cuquantum_cutensor_mpi_backend.py + +import math + +import cupy as cp +import numpy as np +import pytest +import qibo +from qibo import construct_backend, hamiltonians +from qibo.models import QFT +from qibo.symbols import X, Z + +ABS_TOL = 1e-7 + + +def qibo_qft(nqubits, swaps): + circ_qibo = QFT(nqubits, swaps) + state_vec = circ_qibo().state(numpy=True) + return circ_qibo, state_vec + + +def build_observable(nqubits): + """Helper function to construct a target observable.""" + hamiltonian_form = 0 + for i in range(nqubits): + hamiltonian_form += 0.5 * X(i % nqubits) * Z((i + 1) % nqubits) + + hamiltonian = hamiltonians.SymbolicHamiltonian(form=hamiltonian_form) + return hamiltonian, hamiltonian_form + + +def build_observable_dict(nqubits): + """Construct a target observable as a dictionary representation. + + Returns a dictionary suitable for `create_hamiltonian_from_dict`. + """ + terms = [] + + for i in range(nqubits): + term = { + "coefficient": 0.5, + "operators": [("X", i % nqubits), ("Z", (i + 1) % nqubits)], + } + terms.append(term) + + return {"terms": terms} + + +@pytest.mark.gpu +@pytest.mark.mpi +@pytest.mark.parametrize("nqubits", [1, 2, 5, 7, 10]) +def test_eval_mpi(nqubits: int, dtype="complex128"): + """ + Args: + nqubits (int): Total number of qubits in the system. + dtype (str): The data type for precision, 'complex64' for single, + 'complex128' for double. + """ + # Test qibo + qibo.set_backend(backend="numpy") + qibo_circ, result_sv = qibo_qft(nqubits, swaps=True) + result_sv_cp = cp.asarray(result_sv) + + # Test cutensornet + backend = construct_backend(backend="qibotn", platform="cutensornet") + + # Test with explicit settings specified. + comp_set_w_bool = { + "MPI_enabled": True, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": False, + } + backend.configure_tn_simulation(comp_set_w_bool) + result_tn = backend.execute_circuit(circuit=qibo_circ) + result_tn_cp = cp.asarray(result_tn.statevector.flatten()) + + print(f"State vector difference: {abs(result_tn_cp - result_sv_cp).max():0.3e}") + + if backend.rank == 0: + + assert cp.allclose( + result_sv_cp, result_tn_cp + ), "Resulting dense vectors do not match" + else: + assert ( + isinstance(result_tn_cp, cp.ndarray) + and result_tn_cp.size == 1 + and result_tn_cp.item() == 0 + ), f"Rank {backend.rank}: result_tn_cp should be scalar/array with 0, got {result_tn_cp}" + + +@pytest.mark.gpu +@pytest.mark.mpi +@pytest.mark.parametrize("nqubits", [1, 2, 5, 7, 10]) +def test_expectation_mpi(nqubits: int, dtype="complex128"): + + # Test qibo + qibo_circ, state_vec_qibo = qibo_qft(nqubits, swaps=True) + ham, ham_form = build_observable(nqubits) + numpy_backend = construct_backend("numpy") + exact_expval = numpy_backend.calculate_expectation_state( + hamiltonian=ham, + state=state_vec_qibo, + normalize=False, + ) + + # Test cutensornet + backend = construct_backend(backend="qibotn", platform="cutensornet") + + # Test with simple settings using bool. Uses default Hamilitonian for expectation calculation. + comp_set_w_bool = { + "MPI_enabled": True, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": True, + } + backend.configure_tn_simulation(comp_set_w_bool) + result_tn = backend.execute_circuit(circuit=qibo_circ) + if backend.rank == 0: + # Compare numerical values + assert math.isclose( + exact_expval.item(), float(result_tn[0]), abs_tol=ABS_TOL + ), f"Rank {backend.rank}: mismatch, expected {exact_expval}, got {result_tn}" + + else: + # Rank > 0: must be hardcoded [0] (int) + assert ( + isinstance(result_tn, (np.ndarray, cp.ndarray)) + and result_tn.size == 1 + and np.issubdtype(result_tn.dtype, np.integer) + and result_tn.item() == 0 + ), f"Rank {backend.rank}: expected int array [0], got {result_tn}" + + # Test with user defined hamiltonian using "hamiltonians.SymbolicHamiltonian" object. + comp_set_w_hamiltonian_obj = { + "MPI_enabled": True, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": ham, + } + backend.configure_tn_simulation(comp_set_w_hamiltonian_obj) + result_tn = backend.execute_circuit(circuit=qibo_circ) + if backend.rank == 0: + # Compare numerical values + assert math.isclose( + exact_expval.item(), float(result_tn[0]), abs_tol=ABS_TOL + ), f"Rank {backend.rank}: mismatch, expected {exact_expval}, got {result_tn}" + + else: + # Rank > 0: must be hardcoded [0] (int) + assert ( + isinstance(result_tn, (np.ndarray, cp.ndarray)) + and result_tn.size == 1 + and np.issubdtype(result_tn.dtype, np.integer) + and result_tn.item() == 0 + ), f"Rank {backend.rank}: expected int array [0], got {result_tn}" + + # Test with user defined hamiltonian using Dictionary object form of hamiltonian. + ham_dict = build_observable_dict(nqubits) + comp_set_w_hamiltonian_dict = { + "MPI_enabled": True, + "MPS_enabled": False, + "NCCL_enabled": False, + "expectation_enabled": ham_dict, + } + backend.configure_tn_simulation(comp_set_w_hamiltonian_dict) + result_tn = backend.execute_circuit(circuit=qibo_circ) + if backend.rank == 0: + # Compare numerical values + assert math.isclose( + exact_expval.item(), float(result_tn[0]), abs_tol=ABS_TOL + ), f"Rank {backend.rank}: mismatch, expected {exact_expval}, got {result_tn}" + + else: + # Rank > 0: must be hardcoded [0] (int) + assert ( + isinstance(result_tn, (np.ndarray, cp.ndarray)) + and result_tn.size == 1 + and np.issubdtype(result_tn.dtype, np.integer) + and result_tn.item() == 0 + ), f"Rank {backend.rank}: expected int array [0], got {result_tn}" + + +@pytest.mark.gpu +@pytest.mark.mpi +@pytest.mark.parametrize("nqubits", [1, 2, 5, 7, 10]) +def test_eval_nccl(nqubits: int, dtype="complex128"): + """ + Args: + nqubits (int): Total number of qubits in the system. + dtype (str): The data type for precision, 'complex64' for single, + 'complex128' for double. + """ + # Test qibo + qibo.set_backend(backend="numpy") + qibo_circ, result_sv = qibo_qft(nqubits, swaps=True) + result_sv_cp = cp.asarray(result_sv) + + # Test cutensornet + backend = construct_backend(backend="qibotn", platform="cutensornet") + + # Test with explicit settings specified. + comp_set_w_bool = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": True, + "expectation_enabled": False, + } + backend.configure_tn_simulation(comp_set_w_bool) + result_tn = backend.execute_circuit(circuit=qibo_circ) + result_tn_cp = cp.asarray(result_tn.statevector.flatten()) + + if backend.rank == 0: + assert cp.allclose( + result_sv_cp, result_tn_cp + ), "Resulting dense vectors do not match" + else: + assert ( + isinstance(result_tn_cp, cp.ndarray) + and result_tn_cp.size == 1 + and result_tn_cp.item() == 0 + ), f"Rank {backend.rank}: result_tn_cp should be scalar/array with 0, got {result_tn_cp}" + + +@pytest.mark.gpu +@pytest.mark.mpi +@pytest.mark.parametrize("nqubits", [1, 2, 5, 7, 10]) +def test_expectation_NCCL(nqubits: int, dtype="complex128"): + + # Test qibo + qibo_circ, state_vec_qibo = qibo_qft(nqubits, swaps=True) + ham, ham_form = build_observable(nqubits) + numpy_backend = construct_backend("numpy") + exact_expval = numpy_backend.calculate_expectation_state( + hamiltonian=ham, + state=state_vec_qibo, + normalize=False, + ) + + # Test cutensornet + backend = construct_backend(backend="qibotn", platform="cutensornet") + + # Test with simple settings using bool. Uses default Hamilitonian for expectation calculation. + comp_set_w_bool = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": True, + "expectation_enabled": True, + } + backend.configure_tn_simulation(comp_set_w_bool) + result_tn = backend.execute_circuit(circuit=qibo_circ) + if backend.rank == 0: + # Compare numerical values + assert math.isclose( + exact_expval.item(), float(result_tn[0]), abs_tol=ABS_TOL + ), f"Rank {backend.rank}: mismatch, expected {exact_expval}, got {result_tn}" + + else: + # Rank > 0: must be hardcoded [0] (int) + assert ( + isinstance(result_tn, (np.ndarray, cp.ndarray)) + and result_tn.size == 1 + and np.issubdtype(result_tn.dtype, np.integer) + and result_tn.item() == 0 + ), f"Rank {backend.rank}: expected int array [0], got {result_tn}" + + # Test with user defined hamiltonian using "hamiltonians.SymbolicHamiltonian" object. + comp_set_w_hamiltonian_obj = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": True, + "expectation_enabled": ham, + } + backend.configure_tn_simulation(comp_set_w_hamiltonian_obj) + result_tn = backend.execute_circuit(circuit=qibo_circ) + if backend.rank == 0: + # Compare numerical values + assert math.isclose( + exact_expval.item(), float(result_tn[0]), abs_tol=ABS_TOL + ), f"Rank {backend.rank}: mismatch, expected {exact_expval}, got {result_tn}" + + else: + # Rank > 0: must be hardcoded [0] (int) + assert ( + isinstance(result_tn, (np.ndarray, cp.ndarray)) + and result_tn.size == 1 + and np.issubdtype(result_tn.dtype, np.integer) + and result_tn.item() == 0 + ), f"Rank {backend.rank}: expected int array [0], got {result_tn}" + + # Test with user defined hamiltonian using Dictionary object form of hamiltonian. + ham_dict = build_observable_dict(nqubits) + comp_set_w_hamiltonian_dict = { + "MPI_enabled": False, + "MPS_enabled": False, + "NCCL_enabled": True, + "expectation_enabled": ham_dict, + } + backend.configure_tn_simulation(comp_set_w_hamiltonian_dict) + result_tn = backend.execute_circuit(circuit=qibo_circ) + if backend.rank == 0: + # Compare numerical values + assert math.isclose( + exact_expval.item(), float(result_tn[0]), abs_tol=ABS_TOL + ), f"Rank {backend.rank}: mismatch, expected {exact_expval}, got {result_tn}" + + else: + # Rank > 0: must be hardcoded [0] (int) + assert ( + isinstance(result_tn, (np.ndarray, cp.ndarray)) + and result_tn.size == 1 + and np.issubdtype(result_tn.dtype, np.integer) + and result_tn.item() == 0 + ), f"Rank {backend.rank}: expected int array [0], got {result_tn}" diff --git a/tests/test_expectation.py b/tests/test_expectation.py new file mode 100644 index 0000000..d89c6f9 --- /dev/null +++ b/tests/test_expectation.py @@ -0,0 +1,47 @@ +import math +import random + +import pytest +from qibo import Circuit, construct_backend, gates, hamiltonians +from qibo.symbols import X, Z + + +def build_observable(nqubits): + """Helper function to construct a target observable.""" + hamiltonian_form = 0 + for i in range(nqubits): + hamiltonian_form += 0.5 * X(i % nqubits) * Z((i + 1) % nqubits) + + hamiltonian = hamiltonians.SymbolicHamiltonian(form=hamiltonian_form) + return hamiltonian, hamiltonian_form + + +def build_circuit(nqubits, nlayers, seed=42): + """Helper function to construct a layered quantum circuit.""" + random.seed(seed) + + circ = Circuit(nqubits) + for _ in range(nlayers): + for q in range(nqubits): + circ.add(gates.RY(q=q, theta=random.uniform(-math.pi, math.pi))) + circ.add(gates.RZ(q=q, theta=random.uniform(-math.pi, math.pi))) + [circ.add(gates.CNOT(q % nqubits, (q + 1) % nqubits) for q in range(nqubits))] + circ.add(gates.M(*range(nqubits))) + return circ + + +@pytest.mark.parametrize("nqubits", [2, 5, 10]) +def test_observable_expval(backend, nqubits): + numpy_backend = construct_backend("numpy") + ham, ham_form = build_observable(nqubits) + circ = build_circuit(nqubits=nqubits, nlayers=1) + + exact_expval = numpy_backend.calculate_expectation_state( + hamiltonian=ham, + state=circ().state(), + normalize=False, + ) + + tn_expval = backend.expectation(circuit=circ, observable=ham_form) + + assert math.isclose(exact_expval, tn_expval, abs_tol=1e-7) diff --git a/tests/test_quimb_backend.py b/tests/test_quimb_backend.py new file mode 100644 index 0000000..e32aefe --- /dev/null +++ b/tests/test_quimb_backend.py @@ -0,0 +1,66 @@ +import copy +import os + +import config +import numpy as np +import pytest +import qibo +from qibo.models import QFT + + +def create_init_state(nqubits): + init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits) + init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) + return init_state + + +def qibo_qft(nqubits, init_state, swaps): + circ_qibo = QFT(nqubits, swaps) + state_vec = circ_qibo(init_state).state(numpy=True) + return circ_qibo, state_vec + + +@pytest.mark.parametrize( + "nqubits, tolerance, is_mps", + [(1, 1e-6, True), (2, 1e-6, False), (5, 1e-3, True), (10, 1e-3, False)], +) +def test_eval(nqubits: int, tolerance: float, is_mps: bool): + """Evaluate circuit with Quimb backend. + + Args: + nqubits (int): Total number of qubits in the system. + tolerance (float): Maximum limit allowed for difference in results + is_mps (bool): True if state is MPS and False for tensor network structure + """ + # hack quimb to use the correct number of processes + # TODO: remove completely, or at least delegate to the backend + # implementation + os.environ["QUIMB_NUM_PROCS"] = str(os.cpu_count()) + import qibotn.eval_qu + + init_state = create_init_state(nqubits=nqubits) + init_state_tn = copy.deepcopy(init_state) + + # Test qibo + qibo.set_backend(backend=config.qibo.backend, platform=config.qibo.platform) + + qibo_circ, result_sv = qibo_qft(nqubits, init_state, swaps=True) + + # Convert to qasm for other backends + qasm_circ = qibo_circ.to_qasm() + + # Test quimb + if is_mps: + gate_opt = {} + gate_opt["method"] = "svd" + gate_opt["cutoff"] = 1e-6 + gate_opt["cutoff_mode"] = "abs" + else: + gate_opt = None + result_tn = qibotn.eval_qu.dense_vector_tn_qu( + qasm_circ, init_state_tn, gate_opt, backend=config.quimb.backend + ).flatten() + + assert np.allclose( + result_sv, result_tn, atol=tolerance + ), "Resulting dense vectors do not match"