diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 023134c..2b0b6e0 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -29,7 +29,7 @@ jobs: - name: Install documentation dependencies run: uv sync --locked --group docs --no-dev - name: Build site - run: uv run mkdocs build + run: uv run mkdocs build --strict - uses: actions/upload-pages-artifact@v3 with: path: site diff --git a/docs/index.md b/docs/index.md index efaee1c..bdf320e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,7 +10,7 @@ hide: --- - Narrative guides and API reference will land here as the library stabilizes. + Start with the [API reference](reference/utils.md) for standalone utilities. - :material-github:{ .lg .middle } __Source__ diff --git a/docs/javascript/mathjax.js b/docs/javascript/mathjax.js new file mode 100644 index 0000000..117b046 --- /dev/null +++ b/docs/javascript/mathjax.js @@ -0,0 +1,16 @@ +window.MathJax = { + tex: { + inlineMath: [["\\(", "\\)"]], + displayMath: [["\\[", "\\]"]], + processEscapes: true, + processEnvironments: true, + }, + options: { + ignoreHtmlClass: ".*|", + processHtmlClass: "arithmatex", + }, +}; + +document$.subscribe(() => { + MathJax.typesetPromise(); +}); diff --git a/docs/reference/combined_hamiltonian_matrix.md b/docs/reference/combined_hamiltonian_matrix.md new file mode 100644 index 0000000..8a38ecd --- /dev/null +++ b/docs/reference/combined_hamiltonian_matrix.md @@ -0,0 +1,5 @@ +# Combined Hamiltonian matrix + +Build a full-system Hamiltonian matrix from local and global terms. + +::: shadowsim.core.combined_hamiltonian_matrix.combined_hamiltonian_matrix diff --git a/docs/reference/utils.md b/docs/reference/utils.md new file mode 100644 index 0000000..3d63545 --- /dev/null +++ b/docs/reference/utils.md @@ -0,0 +1,23 @@ +# Utils + +Standalone matrix and helper utilities. + +::: shadowsim.utils.hermitian.hermitian + +::: shadowsim.utils.unitary.unitary + +::: shadowsim.utils.positive_definite.positive_definite + +::: shadowsim.utils.positive_semidefinite.positive_semidefinite + +::: shadowsim.utils.negative_definite.negative_definite + +::: shadowsim.utils.negative_semidefinite.negative_semidefinite + +::: shadowsim.utils.indefinite.indefinite + +::: shadowsim.utils.tensor.tensor + +::: shadowsim.utils.flip_dict.flip_dict + +::: shadowsim.utils.next_power_of_two.next_power_of_two diff --git a/mkdocs.yml b/mkdocs.yml index 43e96d1..860b8c8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -40,12 +40,16 @@ theme: markdown_extensions: - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true - pymdownx.inlinehilite - pymdownx.snippets - admonition - pymdownx.details - attr_list - md_in_html + - pymdownx.arithmatex: + generic: true - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg @@ -54,10 +58,36 @@ markdown_extensions: nav: - Home: index.md + - API Reference: + - Utils: reference/utils.md + - Combined Hamiltonian matrix: reference/combined_hamiltonian_matrix.md plugins: - meta - search + - markdown-exec + - mkdocstrings: + handlers: + python: + paths: + - . + options: + show_root_heading: true + show_root_full_path: false + show_source: true + show_symbol_type_heading: true + show_symbol_type_toc: true + heading_level: 2 + signature_crossrefs: true + separate_signature: true + docstring_style: google + docstring_section_style: list + show_signature_annotations: true + members_order: source + +extra_javascript: + - javascript/mathjax.js + - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js extra: social: diff --git a/pyproject.toml b/pyproject.toml index 20bbbcc..4993310 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,10 @@ dev = [ docs = [ "mkdocs>=1.6", "mkdocs-material>=9.5", + "mkdocstrings[python]>=0.24", + "markdown-exec[ansi]>=1.7", + # Needed so mkdocstrings can format signatures during the docs build. + "ruff==0.16.0", ] lint = [ "ruff==0.16.0", @@ -101,6 +105,9 @@ ignore = ["D407", "D203", "D213", "D416", "PLR0912", "PLR0911", "PLR0915", "PLR2 # E203 -- Whitespace before ':'. This rule conflicts with Black's formatting style. # It was removing definitions with the same name creating conflicts in test_is_stochastic.py +[tool.ruff.lint.pydocstyle] +convention = "google" + [tool.ruff.lint.pylint] # Simulator constructors take many positional model parameters (default limit is 5). max-positional-args = 15 diff --git a/shadowsim/core/combined_hamiltonian_matrix.py b/shadowsim/core/combined_hamiltonian_matrix.py index a1f073c..6e6533a 100644 --- a/shadowsim/core/combined_hamiltonian_matrix.py +++ b/shadowsim/core/combined_hamiltonian_matrix.py @@ -10,18 +10,40 @@ def combined_hamiltonian_matrix( hamiltonians: list[Hamiltonian], num_qubits: int, ) -> np.ndarray: - """Sum Hamiltonian terms on the full ``num_qubits``-site tensor space. + r"""Sum Hamiltonian terms on the full ``num_qubits``-site tensor space. ``LocalHamiltonian`` terms are embedded with identities on the remaining sites; full-domain ``Hamiltonian`` matrices are added as-is. All terms must match a common Hilbert-space dimension (``local_dim ** num_qubits`` for locals, or the matrix size of bare terms). - Parameter hamiltonians: The list of Hamiltonians to sum. - Precondition: hamiltonians is a list of Hamiltonian objects. + Args: + hamiltonians: Non-empty list of ``Hamiltonian`` objects to sum. + num_qubits: Positive number of sites in the full system. + + Returns: + Complex matrix of shape ``(d, d)`` equal to the sum of the (embedded) + terms, where ``d`` is the shared Hilbert-space dimension. + + Raises: + ValueError: If ``LocalHamiltonian`` terms use mixed ``local_dim`` values, + or if term dimensions disagree for the requested ``num_qubits``. + AssertionError: If ``hamiltonians`` / ``num_qubits`` fail basic type and + positivity checks. + + Examples: + Embed a single-site \(Z\) into a three-qubit chain and inspect the shape: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.core import LocalHamiltonian + from shadowsim.core.combined_hamiltonian_matrix import combined_hamiltonian_matrix + + local = LocalHamiltonian(np.diag([1.0, -1.0]), sites=[1], local_dim=2) + out = combined_hamiltonian_matrix([local], num_qubits=3) + print(out.shape) + ``` - Parameter num_qubits: The number of qubits in the full system. - Precondition: num_qubits is a positive integer. """ assert isinstance(hamiltonians, list), "hamiltonians must be a list" assert all(isinstance(h, Hamiltonian) for h in hamiltonians), "all hamiltonians must be Hamiltonian objects" diff --git a/shadowsim/utils/flip_dict.py b/shadowsim/utils/flip_dict.py index 754f471..762b296 100644 --- a/shadowsim/utils/flip_dict.py +++ b/shadowsim/utils/flip_dict.py @@ -1,9 +1,29 @@ """Helpers for reversing dictionary keys (bitstring endianness).""" +from typing import Any -def flip_dict(d): + +def flip_dict(d: dict[str, Any]) -> dict[str, Any]: """Return a new dictionary with each string key reversed. - This is used to switch the endianness of measurement results. + Measurement outcomes are often labeled by bitstrings whose endianness + differs between frameworks; reversing the keys converts between those + conventions. + + Args: + d: Mapping whose keys are strings (typically measurement bitstrings). + + Returns: + A new dictionary with the same values and each key reversed. + + Examples: + Flip Qiskit-style bitstring keys: + + ```python exec="1" source="above" result="text" + from shadowsim.utils.flip_dict import flip_dict + + print(flip_dict({"01": 3, "10": 5})) + ``` + """ return {k[::-1]: v for k, v in d.items()} diff --git a/shadowsim/utils/hermitian.py b/shadowsim/utils/hermitian.py index ef43687..e8bd041 100644 --- a/shadowsim/utils/hermitian.py +++ b/shadowsim/utils/hermitian.py @@ -3,6 +3,37 @@ import numpy as np -def hermitian(H): - """Return whether the NumPy matrix ``H`` is Hermitian.""" +def hermitian(H: np.ndarray) -> bool: + r"""Return whether the NumPy matrix ``H`` is Hermitian. + + A square matrix \(H\) is Hermitian when it equals its conjugate transpose, + \(H = H^\dagger\). + + Args: + H: Square complex matrix. + + Returns: + ``True`` if ``H`` is Hermitian up to numerical tolerance, else ``False``. + + Examples: + The Pauli \(Y\) matrix is Hermitian: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.hermitian import hermitian + + Y = np.array([[0.0, -1j], [1j, 0.0]]) + print(hermitian(Y)) + ``` + + A non-symmetric complex matrix is not: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.hermitian import hermitian + + print(hermitian(np.array([[1.0 + 2j, 0.0], [0.0, 0.0]]))) + ``` + + """ return np.allclose(H, H.conjugate().T) diff --git a/shadowsim/utils/indefinite.py b/shadowsim/utils/indefinite.py index 18a5388..ba1461a 100644 --- a/shadowsim/utils/indefinite.py +++ b/shadowsim/utils/indefinite.py @@ -5,7 +5,30 @@ from shadowsim.utils._real_parts_of_eigenvalues import _real_parts_of_eigenvalues -def indefinite(matrix): - """Return whether a matrix has both positive and negative eigenvalues.""" +def indefinite(matrix: np.ndarray) -> bool: + r"""Return whether a matrix is indefinite. + + A matrix is indefinite when it has at least one eigenvalue with positive real + part and at least one with negative real part. + + Args: + matrix: Square matrix to check. + + Returns: + ``True`` if the matrix has both positive and negative eigenvalue real + parts, else ``False``. + + Examples: + Pauli \(Z\) is indefinite: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.indefinite import indefinite + + Z = np.array([[1.0, 0.0], [0.0, -1.0]]) + print(indefinite(Z)) + ``` + + """ eigvals = _real_parts_of_eigenvalues(matrix) return np.any(eigvals > 0) and np.any(eigvals < 0) diff --git a/shadowsim/utils/negative_definite.py b/shadowsim/utils/negative_definite.py index 49456a5..66d3f13 100644 --- a/shadowsim/utils/negative_definite.py +++ b/shadowsim/utils/negative_definite.py @@ -5,6 +5,27 @@ from shadowsim.utils._real_parts_of_eigenvalues import _real_parts_of_eigenvalues -def negative_definite(matrix): - """Return whether a matrix is negative definite.""" +def negative_definite(matrix: np.ndarray) -> bool: + r"""Return whether a matrix is negative definite. + + A matrix is negative definite when every eigenvalue has strictly negative + real part. + + Args: + matrix: Square matrix to check. + + Returns: + ``True`` if all real parts of the eigenvalues are negative, else ``False``. + + Examples: + A negative multiple of the identity is negative definite: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.negative_definite import negative_definite + + print(negative_definite(-np.eye(2))) + ``` + + """ return np.all(_real_parts_of_eigenvalues(matrix) < 0) diff --git a/shadowsim/utils/negative_semidefinite.py b/shadowsim/utils/negative_semidefinite.py index 502c650..4ac67f9 100644 --- a/shadowsim/utils/negative_semidefinite.py +++ b/shadowsim/utils/negative_semidefinite.py @@ -5,6 +5,28 @@ from shadowsim.utils._real_parts_of_eigenvalues import _real_parts_of_eigenvalues -def negative_semidefinite(matrix): - """Return whether a matrix is negative semidefinite.""" +def negative_semidefinite(matrix: np.ndarray) -> bool: + r"""Return whether a matrix is negative semidefinite. + + A matrix is negative semidefinite when every eigenvalue has non-positive real + part. + + Args: + matrix: Square matrix to check. + + Returns: + ``True`` if all real parts of the eigenvalues are non-positive, else ``False``. + + Examples: + A diagonal matrix with a zero and a negative entry is negative + semidefinite: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.negative_semidefinite import negative_semidefinite + + print(negative_semidefinite(np.diag([0.0, -1.0]))) + ``` + + """ return np.all(_real_parts_of_eigenvalues(matrix) <= 0) diff --git a/shadowsim/utils/next_power_of_two.py b/shadowsim/utils/next_power_of_two.py index de7c030..4bda170 100644 --- a/shadowsim/utils/next_power_of_two.py +++ b/shadowsim/utils/next_power_of_two.py @@ -1,10 +1,30 @@ """Helpers for rounding up to a power of two.""" -def next_power_of_two(n): +def next_power_of_two(n: int) -> int: """Return the first power of two greater than or equal to ``n``. - ``next_power_of_two(5)`` returns 8 and ``next_power_of_two(8)`` returns 8. + Useful when allocating padded Hilbert-space dimensions or buffer sizes that + must be a power of two. + + Args: + n: Non-negative integer. + + Returns: + The smallest power of two that is at least ``n``. For ``n <= 1`` the + result is ``1``. + + Raises: + AssertionError: If ``n`` is not a non-negative integer. + + Examples: + ```python exec="1" source="above" result="text" + from shadowsim.utils.next_power_of_two import next_power_of_two + + print(next_power_of_two(5)) + print(next_power_of_two(8)) + ``` + """ assert isinstance(n, int), "n must be an integer" assert n >= 0, "n must be non-negative" diff --git a/shadowsim/utils/positive_definite.py b/shadowsim/utils/positive_definite.py index 438fd9c..45636aa 100644 --- a/shadowsim/utils/positive_definite.py +++ b/shadowsim/utils/positive_definite.py @@ -5,6 +5,36 @@ from shadowsim.utils._real_parts_of_eigenvalues import _real_parts_of_eigenvalues -def positive_definite(matrix): - """Return whether a matrix is positive definite.""" +def positive_definite(matrix: np.ndarray) -> bool: + r"""Return whether a matrix is positive definite. + + A matrix is positive definite when every eigenvalue has strictly positive + real part. + + Args: + matrix: Square matrix to check. + + Returns: + ``True`` if all real parts of the eigenvalues are positive, else ``False``. + + Examples: + The identity is positive definite: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.positive_definite import positive_definite + + print(positive_definite(np.eye(3))) + ``` + + A zero eigenvalue makes the matrix fail the strict test: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.positive_definite import positive_definite + + print(positive_definite(np.diag([0.0, 1.0, 2.0]))) + ``` + + """ return np.all(_real_parts_of_eigenvalues(matrix) > 0) diff --git a/shadowsim/utils/positive_semidefinite.py b/shadowsim/utils/positive_semidefinite.py index 131c87f..79d3b37 100644 --- a/shadowsim/utils/positive_semidefinite.py +++ b/shadowsim/utils/positive_semidefinite.py @@ -5,6 +5,28 @@ from shadowsim.utils._real_parts_of_eigenvalues import _real_parts_of_eigenvalues -def positive_semidefinite(matrix): - """Return whether a matrix is positive semidefinite.""" +def positive_semidefinite(matrix: np.ndarray) -> bool: + r"""Return whether a matrix is positive semidefinite. + + A matrix is positive semidefinite when every eigenvalue has non-negative real + part. + + Args: + matrix: Square matrix to check. + + Returns: + ``True`` if all real parts of the eigenvalues are non-negative, else ``False``. + + Examples: + A diagonal matrix with a zero eigenvalue is positive semidefinite but + not positive definite: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.positive_semidefinite import positive_semidefinite + + print(positive_semidefinite(np.diag([0.0, 1.0, 2.0]))) + ``` + + """ return np.all(_real_parts_of_eigenvalues(matrix) >= 0) diff --git a/shadowsim/utils/tensor.py b/shadowsim/utils/tensor.py index cfa7ad6..e115ec6 100644 --- a/shadowsim/utils/tensor.py +++ b/shadowsim/utils/tensor.py @@ -3,8 +3,36 @@ import numpy as np -def tensor(lst): - """Return the tensor product of the arrays in ``lst``.""" +def tensor(lst: list[np.ndarray]) -> np.ndarray: + r"""Return the Kronecker tensor product of the arrays in ``lst``. + + Given matrices or vectors \(A_1, A_2, \ldots, A_n\), computes + + \[ + A_1 \otimes A_2 \otimes \cdots \otimes A_n + \] + + via successive applications of :func:`numpy.kron`. + + Args: + lst: Non-empty sequence of NumPy arrays to tensor together. + + Returns: + The Kronecker product of the entries of ``lst``. + + Examples: + Tensor Pauli \(Z\) with Pauli \(X\): + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.tensor import tensor + + Z = np.array([[1.0, 0.0], [0.0, -1.0]]) + X = np.array([[0.0, 1.0], [1.0, 0.0]]) + print(tensor([Z, X])) + ``` + + """ result = lst[0] for i in range(1, len(lst)): result = np.kron(result, lst[i]) diff --git a/shadowsim/utils/unitary.py b/shadowsim/utils/unitary.py index 4a3617a..66920ea 100644 --- a/shadowsim/utils/unitary.py +++ b/shadowsim/utils/unitary.py @@ -3,6 +3,36 @@ import numpy as np -def unitary(U): - """Return whether the NumPy matrix ``U`` is unitary.""" +def unitary(U: np.ndarray) -> bool: + r"""Return whether the NumPy matrix ``U`` is unitary. + + A square matrix \(U\) is unitary when \(U U^\dagger = I\). + + Args: + U: Square complex matrix. + + Returns: + ``True`` if ``U`` is unitary up to numerical tolerance, else ``False``. + + Examples: + The 2-qubit Hadamard gate is unitary: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.unitary import unitary + + H = np.array([[1.0, 1.0], [1.0, -1.0]]) / np.sqrt(2) + print(unitary(H)) + ``` + + A shear matrix is not: + + ```python exec="1" source="above" result="text" + import numpy as np + from shadowsim.utils.unitary import unitary + + print(unitary(np.array([[1.0, 2.0], [0.0, 1.0]]))) + ``` + + """ return np.allclose(np.eye(U.shape[0]), np.dot(U, U.conjugate().T)) diff --git a/uv.lock b/uv.lock index ac3583b..0d1fce2 100644 --- a/uv.lock +++ b/uv.lock @@ -321,6 +321,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, ] +[[package]] +name = "griffelib" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/e4/8d187ea29c2e30b3a09505c567513077d6117861bde1fbd997a167f262ec/griffelib-2.1.0.tar.gz", hash = "sha256:762a186d2c6fd6794d4ea20d428d597ffb857cb56b66421651cbba15bdd5e813", size = 216234, upload-time = "2026-06-19T12:05:42.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/d3/5268aeabf2ad82658c4e2ff3a060648d0f02f3926cb53247c0e4d0dab49e/griffelib-2.1.0-py3-none-any.whl", hash = "sha256:cc7b3d2d2865ad0b909fcc38086e3f554b5ea7acbaa7bbb7ecaa3f5dfb7d9f00", size = 142560, upload-time = "2026-06-19T12:05:38.742Z" }, +] + [[package]] name = "idna" version = "3.18" @@ -446,6 +455,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, ] +[[package]] +name = "markdown-exec" +version = "1.12.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/76/c47da8edb6a12b066728432fb3724109d9d91de5331df5073d12d272493f/markdown_exec-1.12.3.tar.gz", hash = "sha256:006b9cac46470a9499797bc9c579305ae4719e0a8e495e5401dfbf1e66ce7fb4", size = 77841, upload-time = "2026-07-07T09:53:13.838Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/a7/0279016386d611183ccc508c5688eb1e2133e8182164d7a2c6213b176f69/markdown_exec-1.12.3-py3-none-any.whl", hash = "sha256:48ac12a565f3f4331b1acd9efc48a0773e717eb7ca7c38e23c1d72ee61660de6", size = 37995, upload-time = "2026-07-07T09:53:12.619Z" }, +] + +[package.optional-dependencies] +ansi = [ + { name = "pygments-ansi-color" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -596,6 +622,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, ] +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/c0/f641843de3f612a6b48253f39244165acff36657a91cc903633d456ae1ac/mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197", size = 56588, upload-time = "2026-02-10T15:23:55.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/de/a3e710469772c6a89595fc52816da05c1e164b4c866a89e3cb82fb1b67c5/mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089", size = 25530, upload-time = "2026-02-10T15:23:53.817Z" }, +] + [[package]] name = "mkdocs-get-deps" version = "0.2.2" @@ -641,6 +681,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, ] +[[package]] +name = "mkdocstrings" +version = "1.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/71/f85bdf13355073ae15a7375f09879375a830553552e58c1c4b7e0bbc5c8b/mkdocstrings-1.0.6.tar.gz", hash = "sha256:a0b8c2bdd29a6416c80d717aa369bbf7831946bd9f23c2a66db1b1dbe7693dbd", size = 100649, upload-time = "2026-07-11T19:38:05.732Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/5b/4c1902e8bdd5c4db63284e9d101dece4038d4025d6d88850ffe0a1578980/mkdocstrings-1.0.6-py3-none-any.whl", hash = "sha256:2703708697487d1b6d6d7b412e176fa436edf120c1bf81dc9e126b12d00893c7", size = 35787, upload-time = "2026-07-11T19:38:04.417Z" }, +] + +[package.optional-dependencies] +python = [ + { name = "mkdocstrings-python" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "2.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffelib" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/b6/e858701499d57eee8b3fd8e78168083956c6683ddbe727b46758b19e1119/mkdocstrings_python-2.0.5.tar.gz", hash = "sha256:3a4d92556ad39637e88af94a5374213af9a8e3040c3824ceaed04b486c017594", size = 199578, upload-time = "2026-06-19T10:41:08.868Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/fc/10ab7e80650a9c9e8f4f1105f8c8e73567f88ed0c06ada589ab81d38687c/mkdocstrings_python-2.0.5-py3-none-any.whl", hash = "sha256:30c837bbff016549f659fcba6539ac351303f0fd7e713c89a040611072236e9d", size = 104951, upload-time = "2026-06-19T10:41:07.378Z" }, +] + [[package]] name = "numpy" version = "2.5.1" @@ -845,6 +921,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] +[[package]] +name = "pygments-ansi-color" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/f9/7f417aaee98a74b4f757f2b72971245181fcf25d824d2e7a190345669eaf/pygments-ansi-color-0.3.0.tar.gz", hash = "sha256:7018954cf5b11d1e734383a1bafab5af613213f246109417fee3f76da26d5431", size = 7317, upload-time = "2023-05-18T22:44:35.792Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/17/8306a0bcd8c88d7761c2e73e831b0be026cd6873ce1f12beb3b4c9a03ffa/pygments_ansi_color-0.3.0-py3-none-any.whl", hash = "sha256:7eb063feaecadad9d4d1fd3474cbfeadf3486b64f760a8f2a00fc25392180aba", size = 10242, upload-time = "2023-05-18T22:44:34.287Z" }, +] + [[package]] name = "pymdown-extensions" version = "11.0.1" @@ -1193,8 +1281,11 @@ dev = [ { name = "pytest-cov" }, ] docs = [ + { name = "markdown-exec", extra = ["ansi"] }, { name = "mkdocs" }, { name = "mkdocs-material" }, + { name = "mkdocstrings", extra = ["python"] }, + { name = "ruff" }, ] lint = [ { name = "ruff" }, @@ -1217,8 +1308,11 @@ dev = [ { name = "pytest-cov" }, ] docs = [ + { name = "markdown-exec", extras = ["ansi"], specifier = ">=1.7" }, { name = "mkdocs", specifier = ">=1.6" }, { name = "mkdocs-material", specifier = ">=9.5" }, + { name = "mkdocstrings", extras = ["python"], specifier = ">=0.24" }, + { name = "ruff", specifier = "==0.16.0" }, ] lint = [{ name = "ruff", specifier = "==0.16.0" }]