From 2844bc124aada79a072cacba6fa278890a965b01 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Tue, 2 Jun 2026 07:44:43 -0400 Subject: [PATCH 01/15] docstring update --- haarpy/circular_ensembles.py | 12 +++++++----- haarpy/orthogonal.py | 14 ++++++++------ haarpy/partition.py | 4 ++-- haarpy/permutation.py | 20 +++++++++++--------- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/haarpy/circular_ensembles.py b/haarpy/circular_ensembles.py index be906bf..a8ac4c8 100644 --- a/haarpy/circular_ensembles.py +++ b/haarpy/circular_ensembles.py @@ -39,7 +39,7 @@ @lru_cache def weingarten_circular_orthogonal( - permutation: Union[Permutation, tuple[int]], + permutation: Union[Permutation, tuple[int, ...]], coe_dimension: Symbol, ) -> Expr: """Returns the circular orthogonal ensemble's Weingarten functions @@ -113,7 +113,7 @@ def weingarten_circular_symplectic(permutation: Permutation, cse_dimension: Symb @lru_cache def haar_integral_circular_orthogonal( - sequences: tuple[tuple[int]], group_dimension: Symbol + sequences: tuple[tuple[int, ...], ...], group_dimension: Symbol ) -> Expr: """Returns integral over circular orthogonal ensemble polynomial sampled at random from the Haar measure @@ -168,14 +168,16 @@ def haar_integral_circular_orthogonal( @lru_cache -def haar_integral_circular_symplectic(sequences: tuple[tuple[Expr]], half_dimension: Expr) -> Expr: +def haar_integral_circular_symplectic( + sequences: tuple[tuple[Expr, ...], ...], half_dimension: Expr +) -> Expr: """Returns integral over circular symplectic ensemble polynomial sampled at random from the Haar measure Parameters ---------- - sequences (tuple[tuple[int]]) : Indices of matrix elements - half_dimension (Symbol) : Half the dimension of the unitary group + sequences (tuple[tuple[Expr]]) : Indices of matrix elements + half_dimension (Expr) : Half the dimension of the unitary group Returns ------- diff --git a/haarpy/orthogonal.py b/haarpy/orthogonal.py index db57fe3..042212a 100644 --- a/haarpy/orthogonal.py +++ b/haarpy/orthogonal.py @@ -45,7 +45,7 @@ @lru_cache -def zonal_spherical_function(permutation: Permutation, partition: tuple[int]) -> Fraction: +def zonal_spherical_function(permutation: Permutation, partition: tuple[int, ...]) -> Fraction: """Returns the zonal spherical function of the Gelfand pair (S_2k, H_k) Parameters @@ -97,18 +97,18 @@ def zonal_spherical_function(permutation: Permutation, partition: tuple[int]) -> @lru_cache def weingarten_orthogonal( - permutation: Union[Permutation, tuple[int]], orthogonal_dimension: Symbol + permutation: Union[Permutation, tuple[int, ...]], orthogonal_dimension: Symbol ) -> Expr: """Returns the orthogonal Weingarten function Parameters ---------- permutation (Permutation, tuple[int]) : a permutation of S_2k or its coset-type - orthogonal_dimension (int): dimension of the orthogonal group + orthogonal_dimension (Symbol): dimension of the orthogonal group Returns ------- - Symbol : the Weingarten function + Expr : the Weingarten function Raise ----- @@ -200,13 +200,15 @@ def weingarten_orthogonal( @lru_cache -def haar_integral_orthogonal(sequences: tuple[tuple[int]], orthogonal_dimension: Symbol) -> Expr: +def haar_integral_orthogonal( + sequences: tuple[tuple[int, ...], ...], orthogonal_dimension: Symbol +) -> Expr: """Returns the integral over orthogonal group polynomial sampled at random from the Haar measure Parameters ---------- sequences (tuple[tuple[int]]) : indices of matrix elements - orthogonal_dimension (int) : dimension of the orthogonal group + orthogonal_dimension (Symbol) : dimension of the orthogonal group Returns ------- diff --git a/haarpy/partition.py b/haarpy/partition.py index 80c9804..abb260b 100644 --- a/haarpy/partition.py +++ b/haarpy/partition.py @@ -40,7 +40,7 @@ def set_partitions(collection: tuple) -> Iterator[tuple[tuple, ...]]: Returns ------- - generator(tuple[tuple]) : all partitions of the input collection + Iterator(tuple[tuple]) : all partitions of the input collection Raise ----- @@ -83,7 +83,7 @@ def pair_partitions( Returns ------- - generator : all the single-double partitions of the tuple + Iterator[tuple[tuple[int]]] : all the single-double partitions of the tuple Raise ----- diff --git a/haarpy/permutation.py b/haarpy/permutation.py index 0f9bd21..f967ba8 100644 --- a/haarpy/permutation.py +++ b/haarpy/permutation.py @@ -31,7 +31,9 @@ @lru_cache -def mobius_function(partition_1: tuple[tuple[int]], partition_2: tuple[tuple[int]]) -> int: +def mobius_function( + partition_1: tuple[tuple[int, ...], ...], partition_2: tuple[tuple[int, ...], ...] +) -> int: """Returns the Möbius function of two given partitions Parameters @@ -66,8 +68,8 @@ def mobius_function(partition_1: tuple[tuple[int]], partition_2: tuple[tuple[int @lru_cache def weingarten_permutation( - first_partition: tuple[tuple[int]], - second_partition: tuple[tuple[int]], + first_partition: tuple[tuple[int, ...], ...], + second_partition: tuple[tuple[int, ...], ...], dimension: Symbol, ) -> Symbol: """Returns the Weingarten function for random permutation matrices @@ -131,8 +133,8 @@ def weingarten_permutation( @lru_cache def weingarten_centered_permutation( - first_partition: tuple[tuple[int]], - second_partition: tuple[tuple[int]], + first_partition: tuple[tuple[int, ...], ...], + second_partition: tuple[tuple[int, ...], ...], dimension: Symbol, ) -> Symbol: """Returns the Weingarten function for centered random permutation matrices @@ -212,8 +214,8 @@ def weingarten_centered_permutation( @lru_cache def haar_integral_permutation( - row_indices: tuple[int], - column_indices: tuple[int], + row_indices: tuple[int, ...], + column_indices: tuple[int, ...], dimension: Symbol, ) -> Symbol: """Returns the integral over Haar random permutation matrices @@ -272,8 +274,8 @@ def sequence_to_partition(sequence: tuple) -> tuple[tuple[int]]: @lru_cache def haar_integral_centered_permutation( - row_indices: tuple[int], - column_indices: tuple[int], + row_indices: tuple[int, ...], + column_indices: tuple[int, ...], dimension: Symbol, ) -> Symbol: """Returns the integral over Haar random centered permutation matrices From 6e26180d456279501f59708d7550f291e358f3cf Mon Sep 17 00:00:00 2001 From: yaniccd Date: Tue, 2 Jun 2026 09:13:03 -0400 Subject: [PATCH 02/15] docstring update --- haarpy/symmetric.py | 34 ++++++++++++++++++---------------- haarpy/symplectic.py | 4 ++-- haarpy/unitary.py | 10 +++++++--- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/haarpy/symmetric.py b/haarpy/symmetric.py index af407f5..4465f95 100644 --- a/haarpy/symmetric.py +++ b/haarpy/symmetric.py @@ -26,7 +26,7 @@ from math import factorial, prod from functools import lru_cache -from typing import Generator +from collections.abc import Iterator from fractions import Fraction from sympy.combinatorics import ( Permutation, @@ -87,8 +87,8 @@ def get_conjugacy_class(permutation: Permutation) -> tuple[int, ...]: def derivative_tableaux( - tableau: tuple[tuple[int]], increment: int, partition: tuple[int] -) -> Generator[tuple[tuple[int]], None, None]: + tableau: tuple[tuple[int, ...], ...], increment: int, partition: tuple[int, ...] +) -> Iterator[tuple[tuple[int, ...], ...]]: """Takes a single tableau and adds the selected number to its contents in a way that keeps it semi-standard. All possible tableaux are yielded @@ -133,8 +133,8 @@ def derivative_tableaux( @lru_cache def semi_standard_young_tableaux( - partition: tuple[int], conjugacy_class: tuple[int] -) -> set[tuple[tuple[int]]]: + partition: tuple[int, ...], conjugacy_class: tuple[int, ...] +) -> set[tuple[tuple[int, ...], ...]]: """all eligible semi-standard young tableaux based of the partition Parameters @@ -167,7 +167,9 @@ def semi_standard_young_tableaux( @lru_cache -def proper_border_strip(tableau: tuple[tuple[int]], conjugacy_class: tuple[int]) -> bool: +def proper_border_strip( + tableau: tuple[tuple[int, ...], ...], conjugacy_class: tuple[int, ...] +) -> bool: """Returns True if input Young tableau is a valid border-strip tableau Parameters @@ -215,7 +217,7 @@ def proper_border_strip(tableau: tuple[tuple[int]], conjugacy_class: tuple[int]) @lru_cache -def murn_naka_rule(partition: tuple[int], conjugacy_class: tuple[int]) -> int: +def murn_naka_rule(partition: tuple[int, ...], conjugacy_class: tuple[int, ...]) -> int: """Implementation of the Murnaghan-Nakayama rule for the characters irreducible representations of the symmetric group Sp @@ -257,7 +259,7 @@ def murn_naka_rule(partition: tuple[int], conjugacy_class: tuple[int]) -> int: @lru_cache -def irrep_dimension(partition: tuple[int]) -> int: +def irrep_dimension(partition: tuple[int, ...]) -> int: """Returns the dimension of the irrep of the symmetric group Sp labelled by the input partition Parameters @@ -286,7 +288,7 @@ def irrep_dimension(partition: tuple[int]) -> int: @lru_cache -def sorting_permutation(*sequence: tuple[int]) -> Permutation: +def sorting_permutation(*sequence: tuple[int, ...]) -> Permutation: """Returns the sorting permutation of a given sequence If two sequences, sequence_1 and sequence_2, are given as parameters, @@ -329,7 +331,7 @@ def sorting_permutation(*sequence: tuple[int]) -> Permutation: # pylint: disable=invalid-name -def YoungSubgroup(partition: tuple[int]) -> PermutationGroup: +def YoungSubgroup(partition: tuple[int, ...]) -> PermutationGroup: """Returns the Young subgroup of a given input partition Parameters @@ -363,7 +365,7 @@ def YoungSubgroup(partition: tuple[int]) -> PermutationGroup: return DirectProduct(*[SymmetricGroup(part) for part in partition]) -def stabilizer_coset(*sequence: tuple) -> Generator[Permutation, None, None]: +def stabilizer_coset(*sequence: tuple) -> Iterator[Permutation]: """Returns all permutations that, when acting on sequence[0], return sequence[1] For a single input, the function returns the stabilizer group with respect to the sequence. @@ -376,7 +378,7 @@ def stabilizer_coset(*sequence: tuple) -> Generator[Permutation, None, None]: Returns ------- - Generator[Permutation] : permutations that, when acting on sequence[0], return sequence[1] + Iterator[Permutation] : permutations that, when acting on sequence[0], return sequence[1] Raise ----- @@ -450,7 +452,7 @@ def HyperoctahedralGroup(degree: int) -> PermutationGroup: return PermutationGroup(transpositions + double_transpositions) -def hyperoctahedral_transversal(degree: int) -> Generator[Permutation, None, None]: +def hyperoctahedral_transversal(degree: int) -> Iterator[Permutation]: """Returns a generator with the permutations of M_2k, the complete set of coset representatives of S_2k/H_k @@ -460,7 +462,7 @@ def hyperoctahedral_transversal(degree: int) -> Generator[Permutation, None, Non Returns ------- - Generator[Permutation] : the permutations of M_2k + Iterator[Permutation] : the permutations of M_2k Examples -------- @@ -484,7 +486,7 @@ def hyperoctahedral_transversal(degree: int) -> Generator[Permutation, None, Non @lru_cache -def coset_type(permutation: Permutation) -> tuple[int]: +def coset_type(permutation: Permutation) -> tuple[int, ...]: """Returns the coset-type of a given permutation of S_2k Parameters @@ -532,7 +534,7 @@ def coset_type(permutation: Permutation) -> tuple[int]: @lru_cache -def coset_type_representative(partition: tuple[int]) -> Permutation: +def coset_type_representative(partition: tuple[int, ...]) -> Permutation: """Returns a representative permutation of S_2k for a given input coset-type (partition of k) diff --git a/haarpy/symplectic.py b/haarpy/symplectic.py index a8bd7f2..8782c8d 100644 --- a/haarpy/symplectic.py +++ b/haarpy/symplectic.py @@ -42,7 +42,7 @@ @lru_cache -def twisted_spherical_function(permutation: Permutation, partition: tuple[int]) -> Fraction: +def twisted_spherical_function(permutation: Permutation, partition: tuple[int, ...]) -> Fraction: """Returns the twisted spherical function of the Gelfand pair (S_2k, H_k) Parameters @@ -182,7 +182,7 @@ def weingarten_symplectic(permutation: Permutation, half_dimension: Symbol) -> E @lru_cache def haar_integral_symplectic( - sequences: tuple[tuple[Expr]], + sequences: tuple[tuple[Expr, ...], ...], half_dimension: Symbol, ) -> Expr: """Returns integral over symplectic group polynomial sampled at random from the Haar measure diff --git a/haarpy/unitary.py b/haarpy/unitary.py index 7a80900..08673f6 100644 --- a/haarpy/unitary.py +++ b/haarpy/unitary.py @@ -42,7 +42,7 @@ @lru_cache -def representation_dimension(partition: tuple[int], unitary_dimension: Symbol) -> Expr: +def representation_dimension(partition: tuple[int, ...], unitary_dimension: Symbol) -> Expr: """Returns the dimension of the unitary group U(d) labelled by the input partition Parameters @@ -89,7 +89,9 @@ def representation_dimension(partition: tuple[int], unitary_dimension: Symbol) - @lru_cache -def weingarten_unitary(cycle: Union[Permutation, tuple[int]], unitary_dimension: Symbol) -> Expr: +def weingarten_unitary( + cycle: Union[Permutation, tuple[int, ...]], unitary_dimension: Symbol +) -> Expr: """Returns the Weingarten function The function works with both a permutation or a conjugacy class as a partition @@ -164,7 +166,9 @@ def weingarten_unitary(cycle: Union[Permutation, tuple[int]], unitary_dimension: @lru_cache -def haar_integral_unitary(sequences: tuple[tuple[int]], unitary_dimension: Symbol) -> Expr: +def haar_integral_unitary( + sequences: tuple[tuple[int, ...], ...], unitary_dimension: Symbol +) -> Expr: """Returns integral over unitary group polynomial sampled at random from the Haar measure Parameters From f1b22f0aa227f0cac912941c1fdece8213c26f4a Mon Sep 17 00:00:00 2001 From: yaniccd Date: Tue, 2 Jun 2026 20:51:49 -0400 Subject: [PATCH 03/15] docstring format update --- haarpy/unitary.py | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/haarpy/unitary.py b/haarpy/unitary.py index 08673f6..94a56ea 100644 --- a/haarpy/unitary.py +++ b/haarpy/unitary.py @@ -19,6 +19,7 @@ [1] Collins, B. (2003). Moments and cumulants of polynomial random variables on unitarygroups, the Itzykson-Zuber integral, and free probability. International Mathematics Research Notices, 2003(17), 953-982. + [2] Matsumoto, S. (2013). Weingarten calculus for matrix ensembles associated with compact symmetric spaces. arXiv preprint arXiv:1301.5401. """ @@ -43,26 +44,34 @@ @lru_cache def representation_dimension(partition: tuple[int, ...], unitary_dimension: Symbol) -> Expr: - """Returns the dimension of the unitary group U(d) labelled by the input partition + """Returns the dimension of the unitary group's representation labelled by the input partition Parameters ---------- - partition (tuple[int]) : a partition labelling a representation of U(d) - unitary_dimension (Symbol) : dimension d of the unitary matrix U + partition : tuple[int, ...] + A partition labelling a representation of the unitary group :math:`U(d)` + + unitary_dimension : Symbol + The dimension :math:`d` of the unitary group Returns ------- - Expr : the dimension of the representation of U(d) labeled by the partition + Expr + The dimension of the unitary group's representation labelled by the input partition + + Notes + ----- + LINK TO THEORY AND ALGORITHMS Examples -------- - >>> from sympy import Symbol - >>> from haarpy import representation_dimension - >>> d = Symbol("d") - >>> representation_dimension((2,1,1), 4) - 15 - >>> representation_dimension((2,1,1), d) - d*(d/2 - 1/2)*(d - 2)*(d + 1)/4 + >>> from sympy import Symbol + >>> from haarpy import representation_dimension + >>> d = Symbol("d") + >>> representation_dimension((2,1,1), 4) + 15 + >>> representation_dimension((2,1,1), d) + d*(d/2 - 1/2)*(d - 2)*(d + 1)/4 """ conjugate_partition = tuple( sum(1 for part in partition if i < part) for i in range(partition[0]) @@ -105,10 +114,12 @@ def weingarten_unitary( ------- Expr : the Weingarten function - Raise + Raises ----- - TypeError : if unitary_dimension has the wrong type - TypeError : if cycle has the wrong type + TypeError + if unitary_dimension has the wrong type + TypeError + if cycle has the wrong type Examples -------- @@ -180,10 +191,12 @@ def haar_integral_unitary( ------- Expr : integral under the Haar measure - Raise + Raises ----- - ValueError : if sequences do not contain 4 tuples - ValueError : if tuples i and j are of different length + ValueError + if sequences do not contain 4 tuples + ValueError + if tuples i and j are of different length Examples -------- From 9a1daebf1c49b9363ec66957c0f084a896b5675c Mon Sep 17 00:00:00 2001 From: yaniccd Date: Tue, 2 Jun 2026 20:53:12 -0400 Subject: [PATCH 04/15] docs first draft --- docs/Makefile | 20 +++++++++++++++++++ docs/code/unitary.rst | 10 ++++++++++ docs/conf.py | 43 +++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 23 ++++++++++++++++++++++ docs/references.bib | 0 docs/theory/unitary.rst | 5 +++++ 6 files changed, 101 insertions(+) create mode 100644 docs/Makefile create mode 100644 docs/code/unitary.rst create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/references.bib create mode 100644 docs/theory/unitary.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/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 = . +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/docs/code/unitary.rst b/docs/code/unitary.rst new file mode 100644 index 0000000..fb7d19d --- /dev/null +++ b/docs/code/unitary.rst @@ -0,0 +1,10 @@ +Unitary group API +================== + +This module provides tools for computations on the unitary group. + +Functions +--------- + +.. automodule:: haarpy.unitary + :members: \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..4af6367 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,43 @@ +# 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 + +import sys, os +import haarpy + +sys.path.insert(0, os.path.abspath("..")) + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'Haarpy' +copyright = '2026, Yanic Cardin, Hubert de Guise, Nicolás Quesada' +author = 'Yanic Cardin, Hubert de Guise, Nicolás Quesada' +release = haarpy.version() + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx.ext.mathjax", + "sphinx.ext.viewcode", + "sphinx.ext.autosummary", + "sphinx_autodoc_typehints", + "myst_parser", +] + +bibtex_bibfiles = ["references.bib"] + +autosummary_generate = True + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'pydata_sphinx_theme' +html_static_path = ['_static'] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..e33864b --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,23 @@ +.. Haarpy documentation master file, created by + sphinx-quickstart on Tue Jun 2 16:04:12 2026. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Haarpy documentation +==================== + +Add your content using ``reStructuredText`` syntax. See the +`reStructuredText `_ +documentation for details. + +.. toctree:: + :maxdepth: 2 + :caption: Background + + theory/unitary + +.. toctree:: + :maxdepth: 2 + :caption: Haarpy API + + code/unitary \ No newline at end of file diff --git a/docs/references.bib b/docs/references.bib new file mode 100644 index 0000000..e69de29 diff --git a/docs/theory/unitary.rst b/docs/theory/unitary.rst new file mode 100644 index 0000000..69fc394 --- /dev/null +++ b/docs/theory/unitary.rst @@ -0,0 +1,5 @@ +The Unitary group +================= + +.. math:: + \text{Wg}^U = \sum\delta, From a03118a4da011e5536cacfc7766d5deac275e38b Mon Sep 17 00:00:00 2001 From: yaniccd Date: Tue, 2 Jun 2026 20:58:24 -0400 Subject: [PATCH 05/15] docs first draft --- docs/make.bat | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 docs/make.bat diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..32bb245 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +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 From bb8f72339458a3c781bdaa8d83809a58975e30e6 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Wed, 3 Jun 2026 08:01:19 -0400 Subject: [PATCH 06/15] docstring update --- docs/code/symmetric.rst | 7 +++++ docs/code/unitary.rst | 10 +++----- docs/index.rst | 31 +++++++++++++++------- haarpy/unitary.py | 57 +++++++++++++++++++++++------------------ 4 files changed, 65 insertions(+), 40 deletions(-) create mode 100644 docs/code/symmetric.rst diff --git a/docs/code/symmetric.rst b/docs/code/symmetric.rst new file mode 100644 index 0000000..0472f48 --- /dev/null +++ b/docs/code/symmetric.rst @@ -0,0 +1,7 @@ +The symmetric group +================== + +Description + +.. automodule:: haarpy.symmetric + :members: \ No newline at end of file diff --git a/docs/code/unitary.rst b/docs/code/unitary.rst index fb7d19d..a23b307 100644 --- a/docs/code/unitary.rst +++ b/docs/code/unitary.rst @@ -1,10 +1,8 @@ -Unitary group API +The unitary group ================== -This module provides tools for computations on the unitary group. - -Functions ---------- +This module provides tools for computations of integrals of polynomials on the unitary group. .. automodule:: haarpy.unitary - :members: \ No newline at end of file + :members: + :member-order: bysource \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index e33864b..d0aa65a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,21 +3,34 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Haarpy documentation +Haarpy Documentation ==================== -Add your content using ``reStructuredText`` syntax. See the -`reStructuredText `_ -documentation for details. +A Python library for Weingarten calculus and integration of groups and ensembles equipped with the Haar measure. .. toctree:: - :maxdepth: 2 - :caption: Background + :maxdepth: 1 + :caption: Background on Weingarten calculus - theory/unitary + .. theory/weingarten + theory/compact + theory/circular + theorry/quantum + theory/permutation .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + :caption: Tutorials and examples + +.. toctree:: + :maxdepth: 1 :caption: Haarpy API - code/unitary \ No newline at end of file + code/symmetric + .. code/partition + code/permutation + code/unitary + code/orthogonal + code/symplectic + code/circular_ensembles + code/quantum \ No newline at end of file diff --git a/haarpy/unitary.py b/haarpy/unitary.py index 94a56ea..f12d5cd 100644 --- a/haarpy/unitary.py +++ b/haarpy/unitary.py @@ -19,14 +19,13 @@ [1] Collins, B. (2003). Moments and cumulants of polynomial random variables on unitarygroups, the Itzykson-Zuber integral, and free probability. International Mathematics Research Notices, 2003(17), 953-982. - + [2] Matsumoto, S. (2013). Weingarten calculus for matrix ensembles associated with compact symmetric spaces. arXiv preprint arXiv:1301.5401. """ from math import factorial, prod from functools import lru_cache -from typing import Union from itertools import product from collections import Counter from fractions import Fraction @@ -50,7 +49,7 @@ def representation_dimension(partition: tuple[int, ...], unitary_dimension: Symb ---------- partition : tuple[int, ...] A partition labelling a representation of the unitary group :math:`U(d)` - + unitary_dimension : Symbol The dimension :math:`d` of the unitary group @@ -59,10 +58,6 @@ def representation_dimension(partition: tuple[int, ...], unitary_dimension: Symb Expr The dimension of the unitary group's representation labelled by the input partition - Notes - ----- - LINK TO THEORY AND ALGORITHMS - Examples -------- >>> from sympy import Symbol @@ -98,44 +93,56 @@ def representation_dimension(partition: tuple[int, ...], unitary_dimension: Symb @lru_cache -def weingarten_unitary( - cycle: Union[Permutation, tuple[int, ...]], unitary_dimension: Symbol -) -> Expr: +def weingarten_unitary(cycle: Permutation | tuple[int, ...], unitary_dimension: Symbol) -> Expr: """Returns the Weingarten function The function works with both a permutation or a conjugacy class as a partition Parameters ---------- - cycle (Permutation, tuple[int]) : permutation from the symmetric group or its cycle-type - unitary_dimension (Symbol) : dimension d of the unitary matrix U + cycle : Permutation | tuple[int, ...] + A permutation from the symmetric group or a partition reprensenting its cycle-type + + unitary_dimension : Symbol + The dimension :math:`d` of the unitary matrix :math:`U(d)` Returns ------- - Expr : the Weingarten function + Expr + The Weingarten function Raises ----- TypeError - if unitary_dimension has the wrong type + If unitary_dimension has the wrong type TypeError - if cycle has the wrong type + If cycle has the wrong type + + Notes + ----- + Since the unitary Weingarten function is a class function on the symmetric group, the argument + may be given either as a permutation or as its cycle type Examples -------- - >>> from sympy import Symbol - >>> from haarpy import weingarten_unitary - >>> d = Symbol("d") - >>> weingarten_unitary(Permutation(2)(0, 1), 4) - Fraction(-1, 180) - >>> weingarten_unitary(Permutation(2)(0, 1), d) - -1/((d - 2)*(d - 1)*(d + 1)*(d + 2)) - >>> weingarten_unitary((2, 1), d) - -1/((d - 2)*(d - 1)*(d + 1)*(d + 2)) + >>> from sympy import Symbol + >>> from haarpy import weingarten_unitary + >>> d = Symbol("d") + >>> weingarten_unitary(Permutation(2)(0, 1), 4) + Fraction(-1, 180) + >>> weingarten_unitary(Permutation(2)(0, 1), d) + -1/((d - 2)*(d - 1)*(d + 1)*(d + 2)) + >>> weingarten_unitary((2, 1), d) + -1/((d - 2)*(d - 1)*(d + 1)*(d + 2)) See Also -------- - murn_naka_rule, representation_dimension, sympy.utilities.iterables.partitions + :func:`haarpy.symmetric.murn_naka_rule` + Implementation of the Murnaghan-Nakayama rule for the characters irreducible + representations of the symmetric group :math:`S_p` + :func:`haarpy.unitary.representation_dimension` + Computes the dimension of the unitary group's representation labelled by a + given partition """ if not isinstance(unitary_dimension, (Expr, int)): raise TypeError("unitary_dimension must be an instance of int or sympy.Expr") From 6a6f2c38a0aabd78c704c08288922df99c8266cf Mon Sep 17 00:00:00 2001 From: yaniccd Date: Wed, 3 Jun 2026 10:20:39 -0400 Subject: [PATCH 07/15] docstring update --- docs/code/symmetric.rst | 3 +- haarpy/symmetric.py | 333 ++++++++++++++++++++++------------------ 2 files changed, 186 insertions(+), 150 deletions(-) diff --git a/docs/code/symmetric.rst b/docs/code/symmetric.rst index 0472f48..591b33a 100644 --- a/docs/code/symmetric.rst +++ b/docs/code/symmetric.rst @@ -4,4 +4,5 @@ The symmetric group Description .. automodule:: haarpy.symmetric - :members: \ No newline at end of file + :members: + :member-order: bysource \ No newline at end of file diff --git a/haarpy/symmetric.py b/haarpy/symmetric.py index 4465f95..d7d6c3e 100644 --- a/haarpy/symmetric.py +++ b/haarpy/symmetric.py @@ -19,8 +19,10 @@ [1] Collins, B. (2003). Moments and cumulants of polynomial random variables on unitarygroups, the Itzykson-Zuber integral, and free probability. International Mathematics Research Notices, 2003(17), 953-982. + [2] Matsumoto, S. (2013). Weingarten calculus for matrix ensembles associated with compact symmetric spaces. arXiv preprint arXiv:1301.5401. + [3] Macdonald, I. G. (1998). Symmetric functions and Hall polynomials. Oxford university press. """ @@ -39,26 +41,29 @@ @lru_cache def get_conjugacy_class(permutation: Permutation) -> tuple[int, ...]: - """Returns the conjugacy class of an element of the symmetric group Sp + """Returns the conjugacy class of an element of the symmetric group :math:`S_p` Parameters ---------- - permutation (Permutation) : permutation of the symmetric group + permutation : Permutation + A permutation of the symmetric group Returns ------- - tuple[int] : the conjugacy class (cycle-type) of the permutation + tuple[int, ...] + The conjugacy class (cycle-type) of the permutation - Raise - ----- - TypeError : cycle must be of type sympy.combinatorics.Permutation + Raises + ------ + TypeError + The cycle must be of type `sympy.combinatorics.Permutation` Examples -------- - >>> from sympy.combinatorics import Permutation - >>> from haarpy import get_conjugacy_class - >>> get_conjugacy_class(Permutation(5)(0,1,3)) - (3, 1, 1, 1) + >>> from sympy.combinatorics import Permutation + >>> from haarpy import get_conjugacy_class + >>> get_conjugacy_class(Permutation(5)(0,1,3)) + (3, 1, 1, 1) """ if not isinstance(permutation, Permutation): raise TypeError("Permutation must be of type sympy.combinatorics.Permutation") @@ -89,18 +94,25 @@ def get_conjugacy_class(permutation: Permutation) -> tuple[int, ...]: def derivative_tableaux( tableau: tuple[tuple[int, ...], ...], increment: int, partition: tuple[int, ...] ) -> Iterator[tuple[tuple[int, ...], ...]]: - """Takes a single tableau and adds the selected number to its contents - in a way that keeps it semi-standard. All possible tableaux are yielded + """ + Takes a single tableau and adds the selected number to its contents + in a way that keeps it semi-standard. All possible tableaux are yielded. Parameters ---------- - tableau (tuple[tuple[int]]) : an incomplete Young tableau - increment (int) : selected number to be added - partition (tuple[int]) : partition characterizing an irrep of Sp + tableau : tuple[tuple[int, ...], ...] + An incomplete Young tableau - Yields - ------ - tuple[tuple[int]] : modified tableaux + increment : int + Integer to be added to the tableaux + + partition : tuple[int, ...] + A partition characterizing an irrep of the symmetric group + + Returns + ------- + iterator of tuple[tuple[int, ...], ...] + Yielded modified tableaux """ # empty tableau if not tableau[0]: @@ -135,24 +147,28 @@ def derivative_tableaux( def semi_standard_young_tableaux( partition: tuple[int, ...], conjugacy_class: tuple[int, ...] ) -> set[tuple[tuple[int, ...], ...]]: - """all eligible semi-standard young tableaux based of the partition + """All eligible semi-standard young tableaux based of the partition Parameters ---------- - partition (tuple[int]) : partition characterizing an irrep of Sp - conjugacy_class (tuple[int]) : a conjugacy class, in partition form, of Sp + partition : tuple[int, ...] + A partition characterizing an irrep of the symmetric group + + conjugacy_class : tuple[int, ...] + A conjugacy class, in partition form, of the symmetric group Returns ------- - set[tuple[tuple[int]]] : all eligible semi-standard young tableaux + set[tuple[tuple[int, ...], ...]] + All eligible semi-standard young tableaux Examples -------- - >>> from haarpy import semi_standard_young_tableaux - >>> semi_standard_young_tableaux((3, 1), (2, 1, 1)) - {((0, 1, 2), (0,)), ((0, 0, 2), (1,)), ((0, 0, 1), (2,))} - >>> semi_standard_young_tableaux((3,2),(4,1)) - {((0, 0, 1), (0, 0)), ((0, 0, 0), (0, 1))} + >>> from haarpy import semi_standard_young_tableaux + >>> semi_standard_young_tableaux((3, 1), (2, 1, 1)) + {((0, 1, 2), (0,)), ((0, 0, 2), (1,)), ((0, 0, 1), (2,))} + >>> semi_standard_young_tableaux((3,2),(4,1)) + {((0, 0, 1), (0, 0)), ((0, 0, 0), (0, 1))} """ tableaux = (tuple(() for _ in partition),) cell_values = (i for i, m in enumerate(conjugacy_class) for _ in range(m)) @@ -174,20 +190,24 @@ def proper_border_strip( Parameters ---------- - tableau (tuple[tuple[int]]) : a semi-standard Young tableau - conjugacy_class (tuple[int]) : a conjugacy class, in partition form, of Sp + tableau : tuple[tuple[int, ...], ...] + A semi-standard Young tableau + + conjugacy_class : tuple[int, ...] + A conjugacy class, in partition form, of the symmetric group Returns ------- - bool : True if the tableau is a border-strip + bool + True if the tableau is a border-strip Examples -------- - >>> from haarpy import proper_border_strip - >>> ap.proper_border_strip(((0, 0, 0), (0, 1)), (4,1)) - True - >>> ap.proper_border_strip(((0, 0, 1), (0, 0)), (4,1)) - False + >>> from haarpy import proper_border_strip + >>> ap.proper_border_strip(((0, 0, 0), (0, 1)), (4,1)) + True + >>> ap.proper_border_strip(((0, 0, 1), (0, 0)), (4,1)) + False """ if len(tableau) == 1: return True @@ -219,28 +239,32 @@ def proper_border_strip( @lru_cache def murn_naka_rule(partition: tuple[int, ...], conjugacy_class: tuple[int, ...]) -> int: """Implementation of the Murnaghan-Nakayama rule for the characters irreducible - representations of the symmetric group Sp + representations of the symmetric group Parameters ---------- - partition (tuple[int]) : partition characterizing an irrep of Sp - conjugacy_class (tuple[int]) : a conjugacy class, in partition form, of Sp + partition : tuple[int, ...] + A partition characterizing an irrep of the symmetric group + conjugacy_class : tuple[int, ...] + A conjugacy class, in partition form, of the symmetric group Returns ------- - int : character of the elements in class mu of the irrep of the symmetric group + int + The character of the input permutation in the given irrep of the symmetric group Examples -------- - >>> from haarpy import murn_naka_rule - >>> murn_naka_rule((4, 1, 1), (3, 2, 1)) - -1 - >>> murn_naka_rule((3, 1), (1, 1, 1, 1)) - 3 + >>> from haarpy import murn_naka_rule + >>> murn_naka_rule((4, 1, 1), (3, 2, 1)) + -1 + >>> murn_naka_rule((3, 1), (1, 1, 1, 1)) + 3 See Also -------- - semi_standard_young_tableaux, proper_border_strip + :func:`haarpy.symmetric.semi_standard_young_tableaux` + Returns all eligible semi-standard young tableaux based of the partition """ if sum(partition) != sum(conjugacy_class): return 0 @@ -260,21 +284,23 @@ def murn_naka_rule(partition: tuple[int, ...], conjugacy_class: tuple[int, ...]) @lru_cache def irrep_dimension(partition: tuple[int, ...]) -> int: - """Returns the dimension of the irrep of the symmetric group Sp labelled by the input partition + """Returns the dimension of the irrep of the symmetric group labelled by the input partition Parameters ---------- - partition (tuple[int]) : a partition labelling an irrep of Sp + partition : tuple[int] + A partition labelling an irrep of the symmetric group Returns ------- - int : the dimension of the irrep + int + The dimension of the irrep Examples -------- - >>> from haarpy import irrep_dimension - >>> irrep_dimension((2, 1, 1)) - 3 + >>> from haarpy import irrep_dimension + >>> irrep_dimension((2, 1, 1)) + 3 """ numerator = prod( part_i - part_j + j + 1 @@ -289,36 +315,38 @@ def irrep_dimension(partition: tuple[int, ...]) -> int: @lru_cache def sorting_permutation(*sequence: tuple[int, ...]) -> Permutation: - """Returns the sorting permutation of a given sequence - - If two sequences, sequence_1 and sequence_2, are given as parameters, - the function returns the permutation such that - permutation(sequence_1) = sequence_2 - - Note that the function return the first permutation found if the sequences - contain multiplicity + """Returns the sorting permutation of a given sequence. If two sequences are given + as parameters, the function returns the permutation sending the first sequence to the second. Parameters ---------- - *sequence (tuple[int]) : one or two sequences of unorderd elements + *sequence : tuple[int]) + One or two unorderd sequences Returns ------- - Permutation : the sorting permutation + Permutation + Tthe sorting permutation - Raise + Raises + ------ + ValueError + If the two sequences are incompatible + TypeError + If more than two sequences are passed as arguments + + Notes ----- - ValueError : for incompatible sequence inputs - TypeError : if more than two sequences are passed as arguments + If the sorting permutation is not unique, the function returns the first permutation obtained. Examples -------- - >>> from haarpy import sorting_permutation - >>> sequence_1, sequence_2 = (2, 1, 2, 1, 3), (3, 2, 2, 1, 1) - >>> sorting_permutation(sequence_1) - Permutation(4)(0, 1, 3, 2) - >>> sorting_permutation(sequence_1, sequence_2) - Permutation(0, 4, 3, 1) + >>> from haarpy import sorting_permutation + >>> sequence_1, sequence_2 = (2, 1, 2, 1, 3), (3, 2, 2, 1, 1) + >>> sorting_permutation(sequence_1) + Permutation(4)(0, 1, 3, 2) + >>> sorting_permutation(sequence_1, sequence_2) + Permutation(0, 4, 3, 1) """ if len(sequence) == 1: return Permutation(sorted(range(len(sequence[0])), key=lambda k: sequence[0][k])) @@ -336,27 +364,27 @@ def YoungSubgroup(partition: tuple[int, ...]) -> PermutationGroup: Parameters ---------- - partition (tuple[int]) : a partition + partition : tuple[int, ...] + A partition Returns ------- - PermutationGroup : the associated Young subgroup + PermutationGroup + The associated Young subgroup - Raise - ----- - TypeError : if partition is not a tuple or a list - TypeError : if partition is not made of positive integers + Raises + ------ + TypeError + If the partition is neither a tuple or a list + TypeError + If the partition is not made of positive integers Examples -------- - >>> from haarpy import YoungSubgroup - >>> young = YoungSubgroup((2, 2)) - >>> list(young.generate()) - [Permutation(3), Permutation(3)(0, 1), Permutation(2, 3), Permutation(0, 1)(2, 3)] - - See Also - -------- - sympy.combinatorics.DirectProduct, sympy.combinatorics.SymmetricGroup + >>> from haarpy import YoungSubgroup + >>> young = YoungSubgroup((2, 2)) + >>> list(young.generate()) + [Permutation(3), Permutation(3)(0, 1), Permutation(2, 3), Permutation(0, 1)(2, 3)] """ if not isinstance(partition, (tuple, list)): raise TypeError @@ -366,36 +394,38 @@ def YoungSubgroup(partition: tuple[int, ...]) -> PermutationGroup: def stabilizer_coset(*sequence: tuple) -> Iterator[Permutation]: - """Returns all permutations that, when acting on sequence[0], return sequence[1] - - For a single input, the function returns the stabilizer group with respect to the sequence. - For two inputs, it returns the stabilizer of the first sequence with respect to the second, - that is, all permutations such that permutation(sequence[0]) == sequence[1]. + """Returns all permutations that sends the first sequences to the second. For a single input, + the function returns the stabilizer group with respect to the sequence. For two inputs, + it returns the stabilizer of the first sequence with respect to the second. Parameters ---------- - *sequence (tuple) : the sequences acted upon + *sequence : tuple + The sequences acted upon Returns ------- - Iterator[Permutation] : permutations that, when acting on sequence[0], return sequence[1] + Iterator[Permutation] + The stabilizer group - Raise - ----- - TypeError : if the sequence argument contains more than two sequences + Raises + ------ + TypeError + If the sequence argument contains more than two sequences Examples -------- - >>> from haarpy import stabilizer_coset - >>> sequence_1, sequence_2 = (2, 2, 1, 3), (3, 2, 2, 1) - >>> list(stabilizer_coset(sequence_1)) - [Permutation(3), Permutation(3)(0, 1)] - >>> list(stabilizer_coset(sequence_1, sequence_2)) - [Permutation(0, 3, 2, 1), Permutation(0, 3, 2)] + >>> from haarpy import stabilizer_coset + >>> sequence_1, sequence_2 = (2, 2, 1, 3), (3, 2, 2, 1) + >>> list(stabilizer_coset(sequence_1)) + [Permutation(3), Permutation(3)(0, 1)] + >>> list(stabilizer_coset(sequence_1, sequence_2)) + [Permutation(0, 3, 2, 1), Permutation(0, 3, 2)] See Also -------- - sorting_permutation, YoungSubgroup + :func:`haarpy.symmetric.YoungSubgroup` + The Young subgroup of a given input partition """ if len(sequence) == 1: sequence = tuple(sequence[0] for _ in range(2)) @@ -416,30 +446,29 @@ def stabilizer_coset(*sequence: tuple) -> Iterator[Permutation]: # pylint: disable=invalid-name @lru_cache def HyperoctahedralGroup(degree: int) -> PermutationGroup: - """Return the hyperoctahedral group + """Returns the hyperoctahedral group :math:`H_p` Parameters ---------- - degree (int) : the degree k of the hyperoctahedral group H_k + degree : int + The degree :math:`p` of the hyperoctahedral group :math:`H_p` Returns ------- - PermutationGroup : the hyperoctahedral group + PermutationGroup + The hyperoctahedral group - Raise - ----- - TypeError : if degree is not of type int + Raises + ------ + TypeError + If the degree is not an integer Examples -------- - >>> from haarpy import HyperoctahedralGroup - >>> hyperoctahedral = ap.HyperoctahedralGroup(3) - >>> hyperoctahedral.order() - 48 - - See Also - -------- - sympy.combinatorics.PermutationGroup + >>> from haarpy import HyperoctahedralGroup + >>> hyperoctahedral = ap.HyperoctahedralGroup(3) + >>> hyperoctahedral.order() + 48 """ if not isinstance(degree, int): raise TypeError @@ -453,27 +482,30 @@ def HyperoctahedralGroup(degree: int) -> PermutationGroup: def hyperoctahedral_transversal(degree: int) -> Iterator[Permutation]: - """Returns a generator with the permutations of M_2k, the complete set of coset - representatives of S_2k/H_k + """Yields the permutations of :math:`M_{2p}`, the complete set of coset + representatives of the quotient group :math:`S_{2p}/H_p` Parameters ---------- - degree (int) : degree 2k of the set M_2k + degree : int + The degree :math:`2p` of the associated symmetric group :math:`S_{2p}` Returns ------- - Iterator[Permutation] : the permutations of M_2k + Iterator[Permutation] + The permutations of :math:`M_{2p}` Examples -------- - >>> from haarpy import hyperoctahedral_transversal - >>> transversal = ap.hyperoctahedral_transversal(4) - >>> list(transversal) - [Permutation(3), Permutation(3)(1, 2), Permutation(1, 3, 2)] + >>> from haarpy import hyperoctahedral_transversal + >>> transversal = ap.hyperoctahedral_transversal(4) + >>> list(transversal) + [Permutation(3), Permutation(3)(1, 2), Permutation(1, 3, 2)] See Also -------- - pair_partitions + :func:`haarpy.partition.pair_partitions` + Yields the pairings of a given set """ if degree % 2: raise ValueError("degree should be a factor of 2") @@ -487,31 +519,31 @@ def hyperoctahedral_transversal(degree: int) -> Iterator[Permutation]: @lru_cache def coset_type(permutation: Permutation) -> tuple[int, ...]: - """Returns the coset-type of a given permutation of S_2k + """Returns the coset-type of a given permutation of the symmetric group Parameters ---------- - permutation (Permutation) : a permutation of the symmetric group S_2k + permutation : Permutation + A permutation of the symmetric group :math:`S_{2p}` Returns ------- - tuple[int] : the associated coset-type as a partition of k + tuple[int] + The coset-type as a partition of :math:`p` - Raise - ----- - TypeError : if partition is not a Permutation - ValueError : if the symmetric group is of odd degree + Raises + ------ + TypeError + If the permutation is of incorrect type + ValueError + If the symmetric group is of odd degree Examples -------- - >>> from sympy.combinatorics import Permutation - >>> from haarpy import coset_type - >>> coset_type(Permutation(0, 5, 4, 2, 1, 3)) - (2, 1) - - See Also - -------- - join_operation + >>> from sympy.combinatorics import Permutation + >>> from haarpy import coset_type + >>> coset_type(Permutation(0, 5, 4, 2, 1, 3)) + (2, 1) """ if not isinstance(permutation, Permutation): raise TypeError @@ -535,26 +567,29 @@ def coset_type(permutation: Permutation) -> tuple[int, ...]: @lru_cache def coset_type_representative(partition: tuple[int, ...]) -> Permutation: - """Returns a representative permutation of S_2k for a given - input coset-type (partition of k) + """Returns a representative permutation of the symmetric group :math:`S_{2p}` + for a given input coset-type Parameters ---------- - partition (tuple[int]) : the coset-type (partition of k) + partition : tuple[int, ...] + The coset-type as a partition of :math:`p` Returns ------- - Permutation : the associated permutation of S_2k + Permutation + The representative - Raise - ----- - TypeError : if partition is not a tuple + Raises + ------ + TypeError + If the input partition is of incorrect type Examples -------- - >>> from haarpy import coset_type_representative - >>> coset_type_representative((2, 1)) - Permutation(5)(1, 3, 2) + >>> from haarpy import coset_type_representative + >>> coset_type_representative((2, 1)) + Permutation(5)(1, 3, 2) """ if not isinstance(partition, tuple): raise TypeError From 98a469f0093af3021d46eddea1016ee32de1a1ab Mon Sep 17 00:00:00 2001 From: yaniccd Date: Wed, 3 Jun 2026 11:47:32 -0400 Subject: [PATCH 08/15] docstring update --- docs/code/partition.rst | 8 ++++++++ docs/code/symmetric.rst | 4 ++-- docs/code/unitary.rst | 4 ++-- docs/index.rst | 4 ++-- haarpy/partition.py | 20 +++++++++++--------- 5 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 docs/code/partition.rst diff --git a/docs/code/partition.rst b/docs/code/partition.rst new file mode 100644 index 0000000..724a743 --- /dev/null +++ b/docs/code/partition.rst @@ -0,0 +1,8 @@ +Partition Python API +========================== + +Description + +.. automodule:: haarpy.partition + :members: + :member-order: bysource \ No newline at end of file diff --git a/docs/code/symmetric.rst b/docs/code/symmetric.rst index 591b33a..7b35949 100644 --- a/docs/code/symmetric.rst +++ b/docs/code/symmetric.rst @@ -1,5 +1,5 @@ -The symmetric group -================== +Symmetric group Python API +========================== Description diff --git a/docs/code/unitary.rst b/docs/code/unitary.rst index a23b307..e03162f 100644 --- a/docs/code/unitary.rst +++ b/docs/code/unitary.rst @@ -1,5 +1,5 @@ -The unitary group -================== +Unitary group Python API +======================== This module provides tools for computations of integrals of polynomials on the unitary group. diff --git a/docs/index.rst b/docs/index.rst index d0aa65a..dcbb202 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,8 +27,8 @@ A Python library for Weingarten calculus and integration of groups and ensembles :caption: Haarpy API code/symmetric - .. code/partition - code/permutation + code/partition + .. code/permutation code/unitary code/orthogonal code/symplectic diff --git a/haarpy/partition.py b/haarpy/partition.py index abb260b..a5fd938 100644 --- a/haarpy/partition.py +++ b/haarpy/partition.py @@ -18,8 +18,10 @@ ---------- [1] Collins, B., & Nagatsu, M. (2025). Weingarten calculus for centered random permutation matrices. arXiv preprint arXiv:2503.18453. + [2] Matsumoto, S. (2013). Weingarten calculus for matrix ensembles associated with compact symmetric spaces. arXiv preprint arXiv:1301.5401. + [3] Nica, A., & Speicher, R. (2006). Lectures on the combinatorics of free probability (Vol. 13). Cambridge University Press. """ @@ -32,7 +34,7 @@ def set_partitions(collection: tuple) -> Iterator[tuple[tuple, ...]]: """Returns the partitionning of a given collection (set) of objects - into non-empty subsets. + into non-empty subsets Parameters ---------- @@ -42,8 +44,8 @@ def set_partitions(collection: tuple) -> Iterator[tuple[tuple, ...]]: ------- Iterator(tuple[tuple]) : all partitions of the input collection - Raise - ----- + Raises + ------ ValueError : if the collection is not a tuple Examples @@ -85,8 +87,8 @@ def pair_partitions( ------- Iterator[tuple[tuple[int]]] : all the single-double partitions of the tuple - Raise - ----- + Raises + ------ TypeError : if the seed is not a tuple Examples @@ -252,8 +254,8 @@ def non_crossing_partitions(n: int, pair: bool = False) -> Iterator[tuple[tuple[ ------- Iterator : yields the non-crossing partitions - Raise - ----- + Raises + ------ TypeError : if n is not int ValueError : if n < 0 or if pair is True and n is odd @@ -373,8 +375,8 @@ def gram_matrix( ------- Matrix : the symbolic Gram matrix - Raise - ----- + Raises + ------ TypeError : group_dimension is neither a symbol or an integer Examples From bd838380acb92ba968942d734450587c6735e0e1 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Wed, 3 Jun 2026 16:15:38 -0400 Subject: [PATCH 09/15] update docstrings --- haarpy/partition.py | 249 +++++++++++++++++++++++++------------------- 1 file changed, 143 insertions(+), 106 deletions(-) diff --git a/haarpy/partition.py b/haarpy/partition.py index a5fd938..769b846 100644 --- a/haarpy/partition.py +++ b/haarpy/partition.py @@ -38,26 +38,29 @@ def set_partitions(collection: tuple) -> Iterator[tuple[tuple, ...]]: Parameters ---------- - collection (tuple) : an indexable iterable to be partitionned + collection :tuple + An indexable iterable to be partitionned Returns ------- - Iterator(tuple[tuple]) : all partitions of the input collection + Iterator : tuple[tuple] + All partitions of the input collection Raises ------ - ValueError : if the collection is not a tuple + ValueError + If the collection is not a tuple Examples -------- - >>> from haarpy import set_partitions - >>> for partition in set_partitions((0,1,2)): - >>> print(partition) - ((0, 1, 2),) - ((0,), (1, 2)) - ((0, 1), (2,)) - ((0, 2), (1,)) - ((0,), (1,), (2,)) + >>> from haarpy import set_partitions + >>> for partition in set_partitions((0,1,2)): + >>> print(partition) + ((0, 1, 2),) + ((0,), (1, 2)) + ((0, 1), (2,)) + ((0, 2), (1,)) + ((0,), (1,), (2,)) """ if not isinstance(collection, tuple): raise TypeError("collection must be a tuple") @@ -76,29 +79,32 @@ def set_partitions(collection: tuple) -> Iterator[tuple[tuple, ...]]: def pair_partitions( seed: tuple[int, ...], ) -> Iterator[tuple[tuple[int, ...], ...]]: - """Returns the pair partitions of a given set. + """Returns the pair partitions of a given set Parameters ---------- - seed (tuple[int]) : a tuple representing the (multi-)set that will be partitioned. - Note that it must hold that ``len(s) >= 2`` + seed : tuple[int] + A tuple representing the (multi-)set that will be partitioned. + Note that it must hold that ``len(s) >= 2`` Returns ------- - Iterator[tuple[tuple[int]]] : all the single-double partitions of the tuple + Iterator[tuple[tuple[int]]] + All the single-double partitions of the tuple Raises ------ - TypeError : if the seed is not a tuple + TypeError + If the seed is not a tuple Examples -------- - >>> from haarpy import pair_partitions - >>> for matching in pair_partitions((0,1,2,3)): - >>> print(matching) - ((0, 1), (2, 3)) - ((0, 2), (1, 3)) - ((0, 3), (1, 2)) + >>> from haarpy import pair_partitions + >>> for matching in pair_partitions((0,1,2,3)): + >>> print(matching) + ((0, 1), (2, 3)) + ((0, 2), (1, 3)) + ((0, 3), (1, 2)) """ if not isinstance(seed, tuple): raise TypeError("seed must be a tuple") @@ -118,31 +124,37 @@ def pair_partitions( def partial_order( partition_1: tuple[tuple[int, ...], ...], partition_2: tuple[tuple[int, ...], ...] ) -> bool: - """Checks if parition_1 <= partition_2 in terms of partial order - - For parition_1 and partition_2, two partitions of the same set, we call - partition_1 <= partition_2 if and only if each block of partition_1 is - contained in some block of partition_2 + """Checks if ``parition_1 <= partition_2`` in terms of partial order Parameters ---------- - partition_1 (tuple[tuple[int]]) : the partition of lower order - partition_2 (tuple[tuple[int]]) : the partition of higher order + partition_1 : tuple[tuple[int]] + The partition of lower order + + partition_2 : tuple[tuple[int]] + The partition of higher order Returns ------- - bool : True if partition_1 <= partition_2 + bool + ``True`` if ``partition_1 <= partition_2`` + + Notes + ----- + For ``parition_1`` and ``partition_2``, two partitions of the same set, we call + ``partition_1 <= partition_2`` if and only if each block of ``partition_1`` is + contained in some block of ``partition_2`` Examples -------- - >>> from haarpy import partial_order - >>> partition_1 = ((0, 1), (2, 3), (4,)) - >>> partition_2 = ((0, 1), (2, 3, 4)) - >>> partition_3 = ((0, 4), (1, 2, 3)) - >>> partial_order(partition_1, partition_2) - True - >>> partial_order(partition_1, partition_3) - False + >>> from haarpy import partial_order + >>> partition_1 = ((0, 1), (2, 3), (4,)) + >>> partition_2 = ((0, 1), (2, 3, 4)) + >>> partition_3 = ((0, 4), (1, 2, 3)) + >>> partial_order(partition_1, partition_2) + True + >>> partial_order(partition_1, partition_3) + False """ for part in partition_1: if all(not set(part).issubset(bigger_part) for bigger_part in partition_2): @@ -157,28 +169,34 @@ def meet_operation( ) -> tuple[tuple[int, ...], ...]: """Returns the greatest lower bound of the two input partitions - For parition_1 and partition_2, two partitions of the same set, - the meet operation yields the greatest lower bound of both partitions - - The meet operation symbol is ∧, for instance - ((0, 1), (2, 3), (4,)) ∧ ((0, 1, 2), (3, 4)) = ((0, 1), (2,), (3,), (4,)) - Parameters ---------- - partition_1 (tuple[tuple[int]]) : partition of a set - partition_2 (tuple[tuple[int]]) : partition of a set + partition_1 : tuple[tuple[int]] + The partition of a set + + partition_2 : tuple[tuple[int]] + A second partition of the same set Returns ------- - tuple[tuple] : greatest lower bound + tuple[tuple] + The greatest lower bound + + Notes + ----- + For ``parition_1`` and ``partition_2``, two partitions of the same set, + the meet operation yields the greatest lower bound of both partitions + + The meet operation symbol is ``∧``, for instance + ``((0, 1), (2, 3), (4,)) ∧ ((0, 1, 2), (3, 4)) = ((0, 1), (2,), (3,), (4,))`` Examples -------- - >>> from haarpy import meet_operation - >>> partition_1 = ((0, 1), (2, 3), (4,)) - >>> partition_2 = ((0, 1, 2), (3, 4)) - >>> meet_operation(partition_1, partition_2) - ((0, 1), (2,), (3,), (4,)) + >>> from haarpy import meet_operation + >>> partition_1 = ((0, 1), (2, 3), (4,)) + >>> partition_2 = ((0, 1, 2), (3, 4)) + >>> meet_operation(partition_1, partition_2) + ((0, 1), (2,), (3,), (4,)) """ partition_1 = tuple(set(part) for part in partition_1) partition_2 = tuple(set(part) for part in partition_2) @@ -198,28 +216,34 @@ def join_operation( ) -> tuple[tuple[int, ...], ...]: """Returns the least upper bound of the two input partitions - For parition_1 and partition_2, two partitions of the same set, - the join operation yields the least upper bound of both partitions - - The join operation symbol is ∨, for instance - ((0, 1), (2,), (3, 4)) ∨ ((0, 2), (1,), (3,), (4,)) = ((0, 1, 2), (3, 4)) - Parameters ---------- - partition_1 (tuple[tuple[int]]) : partition of a set - partition_2 (tuple[tuple[int]]) : partition of a set + partition_1 : tuple[tuple[int]] + The partition of a set + + partition_2 : tuple[tuple[int]] + A second partition of the same set Returns ------ - tuple[tuple[int]] : least upper bound + tuple[tuple[int]] + The least upper bound + + Notes + ----- + For ``parition_1`` and ``partition_2``, two partitions of the same set, + the join operation yields the least upper bound of both partitions + + The join operation symbol is ``∨``, for instance + ``((0, 1), (2,), (3, 4)) ∨ ((0, 2), (1,), (3,), (4,)) = ((0, 1, 2), (3, 4))`` Examples -------- - >>> from haarpy import join_operation - >>> partition_1 = ((0, 1), (2,), (3, 4)) - >>> partition_2 = ((0, 2), (1,), (3,), (4,)) - >>> join_operation(partition_1, partition_2) - ((0, 1, 2), (3, 4)) + >>> from haarpy import join_operation + >>> partition_1 = ((0, 1), (2,), (3, 4)) + >>> partition_2 = ((0, 2), (1,), (3,), (4,)) + >>> join_operation(partition_1, partition_2) + ((0, 1, 2), (3, 4)) """ parent = [ {index for value in block1 for index, block2 in enumerate(partition_2) if value in block2} @@ -243,39 +267,45 @@ def join_operation( def non_crossing_partitions(n: int, pair: bool = False) -> Iterator[tuple[tuple[int, ...], ...]]: - """Yields non crossing partitions of [n] = {1,2,...,n} + """Yields non crossing partitions of the set :math:`[n] = \{1,2,...,n\}` Parameters ---------- - n (int) : the size of the partitioned set [n] - pair (bool) : True if limited to pair partitions + n : int + The size of the partitioned set :math:`[n]` + + pair : bool + ``True`` to yield only pair partitions Returns ------- - Iterator : yields the non-crossing partitions + Iterator[tuple[tuple[int, ...], ...]] + Yields the non-crossing partitions Raises ------ - TypeError : if n is not int - ValueError : if n < 0 or if pair is True and n is odd + TypeError + If parameter ``n`` is not of type ``int`` + ValueError + If ``n < 0`` or if pair is ``True`` and ``n`` is odd Examples -------- - >>> from haarpy import non_crossing_partitions - >>> for partition in non_crossing_partitions(3): - >>> print(partition) - ((0,), (1,), (2,)) - ((0,), (1, 2)) - ((0, 2), (1,)) - ((0, 1), (2,)) - ((0, 1, 2),) - >>> for partition in non_crossing_partitions(6, pair = True): - >>> print(partition) - ((0, 5), (1, 4), (2, 3)) - ((0, 5), (1, 2), (3, 4)) - ((0, 3), (1, 2), (4, 5)) - ((0, 1), (2, 5), (3, 4)) - ((0, 1), (2, 3), (4, 5)) + >>> from haarpy import non_crossing_partitions + >>> for partition in non_crossing_partitions(3): + >>> print(partition) + ((0,), (1,), (2,)) + ((0,), (1, 2)) + ((0, 2), (1,)) + ((0, 1), (2,)) + ((0, 1, 2),) + >>> for partition in non_crossing_partitions(6, pair = True): + >>> print(partition) + ((0, 5), (1, 4), (2, 3)) + ((0, 5), (1, 2), (3, 4)) + ((0, 3), (1, 2), (4, 5)) + ((0, 1), (2, 5), (3, 4)) + ((0, 1), (2, 3), (4, 5)) """ if not isinstance(n, int): raise TypeError @@ -330,19 +360,21 @@ def is_crossing_partition(partition: tuple[tuple[int, ...], ...]) -> bool: Parameters ---------- - partition (tuple[tuple[int]])) : partition of a set + partition : tuple[tuple[int, ...], ...] + The partition of a set Returns ------- - bool : True if the partition is crossing, False otherwise + bool + ``True`` if the partition is crossing, ``False`` otherwise Examples -------- - >>> from haarpy import is_crossing_partition - >>> is_crossing_partition(((0,2,4), (1,3))) - True - >>> is_crossing_partition(((0,3,4), (1,2))) - False + >>> from haarpy import is_crossing_partition + >>> is_crossing_partition(((0,2,4), (1,3))) + True + >>> is_crossing_partition(((0,3,4), (1,2))) + False """ filtered_partition = tuple( block for block in partition if len(block) != 1 and block[0] + 1 != block[-1] @@ -368,27 +400,32 @@ def gram_matrix( Parameters ---------- - partition_tuple (tuple[tuple[tuple[int]])) : set of partitions - group_dimension (Symbol) : the dimension of the underlying group + partition_tuple : tuple[tuple[tuple[int, ...], ...], ...] + A set of partitions + + group_dimension : Symbol + The dimension of the underlying group Returns ------- - Matrix : the symbolic Gram matrix + Matrix + The symbolic Gram matrix Raises ------ - TypeError : group_dimension is neither a symbol or an integer + TypeError + If the parameter ``group_dimension`` is neither a symbol or an integer Examples -------- - >>> from haarpy import gram_matrix - >>> from sympy import Symbol - >>> n = Symbol('n') - >>> pair_partition_tuple = (((0, 1), (2, 3)), ((0, 3), (1, 2))) - >>> gram_matrix(pair_partition_tuple, n) - Matrix([ - [n**2, n], - [ n, n**2]]) + >>> from haarpy import gram_matrix + >>> from sympy import Symbol + >>> n = Symbol('n') + >>> pair_partition_tuple = (((0, 1), (2, 3)), ((0, 3), (1, 2))) + >>> gram_matrix(pair_partition_tuple, n) + Matrix([ + [n**2, n], + [ n, n**2]]) """ if not isinstance(group_dimension, (Expr, int)): raise TypeError From b57de7b57d5170a719eb2aba9182df0186f8888b Mon Sep 17 00:00:00 2001 From: yaniccd Date: Thu, 4 Jun 2026 10:15:57 -0400 Subject: [PATCH 10/15] docstrings updates --- docs/code/orthogonal.rst | 8 ++ docs/code/permutation.rst | 8 ++ docs/index.rst | 4 +- haarpy/orthogonal.py | 142 +++++++++++++++++---------- haarpy/permutation.py | 197 +++++++++++++++++++++++--------------- haarpy/unitary.py | 47 +++++---- 6 files changed, 256 insertions(+), 150 deletions(-) create mode 100644 docs/code/orthogonal.rst create mode 100644 docs/code/permutation.rst diff --git a/docs/code/orthogonal.rst b/docs/code/orthogonal.rst new file mode 100644 index 0000000..6f9939b --- /dev/null +++ b/docs/code/orthogonal.rst @@ -0,0 +1,8 @@ +orthogonal group Python API +======================== + +This module provides tools for computations of integrals of polynomials on the orthogonal group. + +.. automodule:: haarpy.orthogonal + :members: + :member-order: bysource \ No newline at end of file diff --git a/docs/code/permutation.rst b/docs/code/permutation.rst new file mode 100644 index 0000000..fc302c5 --- /dev/null +++ b/docs/code/permutation.rst @@ -0,0 +1,8 @@ +Permutation matrices Python API +========================== + +Description + +.. automodule:: haarpy.permutation + :members: + :member-order: bysource \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index dcbb202..905c491 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -28,9 +28,9 @@ A Python library for Weingarten calculus and integration of groups and ensembles code/symmetric code/partition - .. code/permutation + code/permutation code/unitary code/orthogonal - code/symplectic + .. code/symplectic code/circular_ensembles code/quantum \ No newline at end of file diff --git a/haarpy/orthogonal.py b/haarpy/orthogonal.py index 042212a..bda09bc 100644 --- a/haarpy/orthogonal.py +++ b/haarpy/orthogonal.py @@ -18,8 +18,10 @@ ---------- [1] Collins, B., & Śniady, P. (2006). Integration with respect to the Haar measure on unitary, orthogonal and symplectic group. Communications in Mathematical Physics, 264(3), 773-795. + [2] Matsumoto, S. (2013). Weingarten calculus for matrix ensembles associated with compact symmetric spaces. arXiv preprint arXiv:1301.5401. + [3] Macdonald, I. G. (1998). Symmetric functions and Hall polynomials. Oxford university press. """ @@ -27,7 +29,6 @@ from fractions import Fraction from itertools import product from functools import lru_cache -from typing import Union from collections import Counter from sympy import Symbol, Expr, factorial from sympy.combinatorics import Permutation @@ -46,32 +47,42 @@ @lru_cache def zonal_spherical_function(permutation: Permutation, partition: tuple[int, ...]) -> Fraction: - """Returns the zonal spherical function of the Gelfand pair (S_2k, H_k) + """Returns the zonal spherical function of the Gelfand pair :math:`(S_{2p}, H_p)` Parameters ---------- - permutation (Permutation) : a permutation of the symmetric group S_2k - partition (tuple[int]) : a partition of k + permutation : Permutation + A permutation of the symmetric group :math:`S_{2p}` + + partition : tuple[int, ...] + An integer partition of :math:`p` Returns ------- - Fraction : the zonal spherical function of the given permutation + Fraction + The zonal spherical function of the given permutation - Raise - ----- - TypeError : if partition argument is not a tuple - TypeError : if permutation argument is not a permutation + Raises + ------ + TypeError + If ``partition`` is not a tuple + TypeError + If ``permutation`` is not a permutation Examples -------- - >>> from sympy.combinatorics import Permutation - >>> from haarpy import zonal_spherical_function - >>> zonal_spherical_function(Permutation(5)(0,1,2), (2,1)) - Fraction(1, 6) + >>> from sympy.combinatorics import Permutation + >>> from haarpy import zonal_spherical_function + >>> zonal_spherical_function(Permutation(5)(0,1,2), (2,1)) + Fraction(1, 6) See Also -------- - HyperoctahedralGroup, murn_naka_rule + :func:`haarpy.symmetric.HyperoctahedralGroup` + Returns the hyperoctahedral group :math:`H_p` + :func:`haarpy.symmetric.murn_naka_rule` + Implementation of the Murnaghan-Nakayama rule for the characters irreducible + representations of the symmetric group """ if not isinstance(partition, tuple): raise TypeError @@ -97,43 +108,59 @@ def zonal_spherical_function(permutation: Permutation, partition: tuple[int, ... @lru_cache def weingarten_orthogonal( - permutation: Union[Permutation, tuple[int, ...]], orthogonal_dimension: Symbol + permutation: Permutation | tuple[int, ...], orthogonal_dimension: Symbol ) -> Expr: """Returns the orthogonal Weingarten function Parameters ---------- - permutation (Permutation, tuple[int]) : a permutation of S_2k or its coset-type - orthogonal_dimension (Symbol): dimension of the orthogonal group + permutation : Permutation | tuple[int, ...] + A permutation of the symmetric group or its coset-type + + orthogonal_dimension : Symbol + The dimension of the orthogonal group Returns ------- - Expr : the Weingarten function - - Raise + Expr + The Weingarten function + + Raises + ------ + TypeError + If unitary_dimension has the wrong type + TypeError + If ``permutation`` has the wrong type + ValueError + If the degree :math:`2p` of the symmetric group :math:`S_{2p}` is not even + + Notes ----- - TypeError : if unitary_dimension has the wrong type - TypeError : if permutation has the wrong type - ValueError : if the degree 2k of the symmetric group S_2k is not a factor of 2 + Since the orthogonal Weingarten function is invariant over coset-types, the argument + may be given either as a permutation or as its coset-type Examples -------- - >>> from sympy import Symbol - >>> from sympy.combinatorics import Permutation - >>> from haarpy import weingarten_orthogonal - >>> d = Symbol("d") - >>> weingarten_orthogonal(Permutation(5)(0,1,2), 6) - Fraction(-1, 1200) - >>> weingarten_orthogonal(Permutation(5)(0,1,2), d) - -1/(d*(d - 2)*(d - 1)*(d + 4)) - >>> weingarten_orthogonal((2,1), d) - -1/(d*(d - 2)*(d - 1)*(d + 4)) - - Where (2,1) is the coset-type of Permutation(5)(0,1,2) + >>> from sympy import Symbol + >>> from sympy.combinatorics import Permutation + >>> from haarpy import weingarten_orthogonal + >>> d = Symbol("d") + >>> weingarten_orthogonal(Permutation(5)(0,1,2), 6) + Fraction(-1, 1200) + >>> weingarten_orthogonal(Permutation(5)(0,1,2), d) + -1/(d*(d - 2)*(d - 1)*(d + 4)) + >>> weingarten_orthogonal((2,1), d) + -1/(d*(d - 2)*(d - 1)*(d + 4)) See Also -------- - zonal_spherical_function, coset_type_representative + :func:`haarpy.orthogonal.zonal_spherical_function` + Returns the zonal spherical function of the Gelfand pair :math:`(S_{2p}, H_p)` + :func:`haarpy.symmetric.coset_type` + Returns the coset-type of a given permutation of the symmetric group + :func:`haarpy.symmetric.coset_type_representative` + Returns a representative permutation of the symmetric group :math:`S_{2p}` + for a given input coset-type """ if not isinstance(orthogonal_dimension, (Expr, int)): raise TypeError("orthogonal_dimension must be an instance of int or sympy.Symbol") @@ -207,32 +234,43 @@ def haar_integral_orthogonal( Parameters ---------- - sequences (tuple[tuple[int]]) : indices of matrix elements - orthogonal_dimension (Symbol) : dimension of the orthogonal group + sequences : tuple[tuple[int, ...], ...] + Sequences of matrix elements + orthogonal_dimension : Symbol + The dimension of the orthogonal group Returns ------- - Expr : integral under the Haar measure + Expr + The integral under the Haar measure - Raise - ----- - ValueError : if sequences do not contain 2 tuples - ValueError : if tuples i and j are of different length + Raises + ------ + ValueError + If the argument ``sequences`` does not contain 2 tuples + ValueError + If the sequences are of different lengths Examples -------- - >>> from sympy import Symbol - >>> from haarpy import haar_integral_orthogonal - >>> d = Symbol("d") - >>> row_indices, column_indices = (0, 0, 1, 1, 2, 2), (0, 2, 2, 1, 1, 0) - >>> haar_integral_orthogonal((row_indices, column_indices), 4) - Fraction(1, 576) - >>> haar_integral_orthogonal((row_indices, column_indices), d) - 2/(d*(d - 2)*(d - 1)*(d + 2)*(d + 4)) + >>> from sympy import Symbol + >>> from haarpy import haar_integral_orthogonal + >>> d = Symbol("d") + >>> row_indices, column_indices = (0, 0, 1, 1, 2, 2), (0, 2, 2, 1, 1, 0) + >>> haar_integral_orthogonal((row_indices, column_indices), 4) + Fraction(1, 576) + >>> haar_integral_orthogonal((row_indices, column_indices), d) + 2/(d*(d - 2)*(d - 1)*(d + 2)*(d + 4)) See Also -------- - hyperoctahedral_transversal, coset_type, weingarten_orthogonal + :func:`haarpy.symmetric.coset_type` + Returns the coset-type of a given permutation of the symmetric group + :func:`haarpy.symmetric.hyperoctahedral_transversal` + Yields the permutations of :math:`M_{2p}`, the complete set of coset + representatives of the quotient group :math:`S_{2p}/H_p` + :func:`haarpy.orthogonal.weingarten_orthogonal` + Computes the orthogonal Weingarten function """ if len(sequences) != 2: raise ValueError("Wrong tuple format") diff --git a/haarpy/permutation.py b/haarpy/permutation.py index f967ba8..be6c0de 100644 --- a/haarpy/permutation.py +++ b/haarpy/permutation.py @@ -25,7 +25,7 @@ from itertools import product from collections.abc import Sequence from fractions import Fraction -from sympy import Symbol, binomial +from sympy import Expr, Symbol, binomial from haarpy import set_partitions, meet_operation, join_operation, partial_order from ._utils import _simplify @@ -38,20 +38,24 @@ def mobius_function( Parameters ---------- - partition_1 (tuple[tuple[int]) : the intersected partition - partition_2 (tuple[tuple[int]]) : the partition summed over + partition_1 : tuple[tuple[int] + The intersected partition + + partition_2 : tuple[tuple[int]] + The partition summed over Returns ------- - int : the value of the Möbius function + int + The value of the Möbius function Examples -------- - >>> from haarpy import mobius_function - >>> partition_1 = ((0, 3), (1, 2), (4,), (5,)) - >>> partition_2 = ((0, 1, 2), (3, 4, 5)) - >>> mobius_function(partition_1, partition_2) - -2 + >>> from haarpy import mobius_function + >>> partition_1 = ((0, 3), (1, 2), (4,), (5,)) + >>> partition_2 = ((0, 1, 2), (3, 4, 5)) + >>> mobius_function(partition_1, partition_2) + -2 """ partition_set_1 = tuple(set(block) for block in partition_1) partition_set_2 = tuple(set(block) for block in partition_2) @@ -71,34 +75,43 @@ def weingarten_permutation( first_partition: tuple[tuple[int, ...], ...], second_partition: tuple[tuple[int, ...], ...], dimension: Symbol, -) -> Symbol: +) -> Expr: """Returns the Weingarten function for random permutation matrices Parameters ---------- - first_partition (tuple(tuple(int))) : a set partition of integer k - second_partition (tuple(tuple(int))) : a set partition of integer k - dimension (Symbol) : the dimension of the random permutation matrices + first_partition : tuple[tuple[int, ...], ...] + A partition of the set of :math:`k` integers :math:`[k] = \{1,2,\dots, k\}` + + second_partition : tuple[tuple[int, ...], ...] + A second partition of the same set + + dimension : Symbol + The dimension of the random permutation matrices Returns ------- - Symbol : the Weingarten function + Expr + The Weingarten function Example ------- - >>> from sympy import Symbol - >>> from haarpy import weingarten_permutation - >>> d = Symbol('d') - >>> partition_1 = ((0, 1, 2), (3,)) - >>> partition_2 = ((0,), (1, 2, 3)) - >>> weingarten_permutation(partition_1, partition_2, 4) - Fraction(5, 24) - >>> weingarten_permutation(partition_1, partition_2, d) - (d + 1)/(d*(d - 3)*(d - 2)*(d - 1)) + >>> from sympy import Symbol + >>> from haarpy import weingarten_permutation + >>> d = Symbol('d') + >>> partition_1 = ((0, 1, 2), (3,)) + >>> partition_2 = ((0,), (1, 2, 3)) + >>> weingarten_permutation(partition_1, partition_2, 4) + Fraction(5, 24) + >>> weingarten_permutation(partition_1, partition_2, d) + (d + 1)/(d*(d - 3)*(d - 2)*(d - 1)) See Also -------- - meet_operation, mobius_function + :func:`haarpy.partition.meet_operation` + Returns the greatest lower bound of the two input partitions + :func:`haarpy.permutation.mobius_function` + Returns the Möbius function of two given partitions """ disjoint_partition_tuple = tuple( (partition for partition in set_partitions(block)) @@ -136,34 +149,45 @@ def weingarten_centered_permutation( first_partition: tuple[tuple[int, ...], ...], second_partition: tuple[tuple[int, ...], ...], dimension: Symbol, -) -> Symbol: +) -> Expr: """Returns the Weingarten function for centered random permutation matrices Parameters ---------- - first_partition (tuple(tuple(int))) : a set partition of integer k - second_partition (tuple(tuple(int))) : a set partition of integer k - dimension (Symbol) : the dimension of the centered random permutation matrices + first_partition : tuple[tuple[int, ...], ...] + A partition of the set of :math:`k` integers :math:`[k] = \{1,2,\dots, k\}` + + second_partition : tuple[tuple[int, ...], ...] + A second partition of the same set + + dimension : Symbol + The dimension of the random permutation matrices Returns ------- - Symbol : the Weingarten function + Expr + The Weingarten function Example ------- - >>> from sympy import Symbol - >>> from haarpy import weingarten_centered_permutation - >>> d = Symbol('d') - >>> partition_1 = ((0,), (1,), (2,)) - >>> partition_2 = ((0, 2), (1,)) - >>> weingarten_centered_permutation(partition_1, partition_2, 3) - Fraction(-1, 9) - >>> weingarten_centered_permutation(partition_1, partition_2, d) - -2/(d**2*(d - 2)*(d - 1)) + >>> from sympy import Symbol + >>> from haarpy import weingarten_centered_permutation + >>> d = Symbol('d') + >>> partition_1 = ((0,), (1,), (2,)) + >>> partition_2 = ((0, 2), (1,)) + >>> weingarten_centered_permutation(partition_1, partition_2, 3) + Fraction(-1, 9) + >>> weingarten_centered_permutation(partition_1, partition_2, d) + -2/(d**2*(d - 2)*(d - 1)) See Also -------- - join_operation, meet_operation, mobius_function + :func:`haarpy.partition.meet_operation` + Returns the greatest lower bound of the two input partitions + :func:`haarpy.partition.join_operation` + Returns the least upper bound of the two input partitions + :func:`haarpy.permutation.mobius_function` + Returns the Möbius function of two given partitions """ singleton_set_size = sum( 1 for block in join_operation(first_partition, second_partition) if len(block) == 1 @@ -217,34 +241,45 @@ def haar_integral_permutation( row_indices: tuple[int, ...], column_indices: tuple[int, ...], dimension: Symbol, -) -> Symbol: +) -> Expr: """Returns the integral over Haar random permutation matrices Parameters ---------- - row_indices (tuple(int)) : sequence of row indices - column_indices (tuple(int)) : sequence of column indices + row_indices : tuple[int, ...] + A sequence of row indices + + column_indices : tuple[int, ...] + A sequence of column indices Returns ------- - Symbol : integral under the Haar measure + Expr + The integral under the Haar measure - Raise - ----- - TypeError : if row_indices and column_indices are not Sequence - ValueError : if row_indices and column_indices are of different length + Raises + ------ + TypeError + If the input parameters are not of type ``Sequence`` + ValueError + If the input sequences are of different length Examples -------- - >>> from sympy import Symbol - >>> from haarpy import haar_integral_permutation - >>> d = Symbol('d') - >>> row_indices = (0, 1, 2, 2) - >>> column_indices = (1, 0, 2, 2) - >>> haar_integral_permutation(row_indices, column_indices, 3) - Fraction(1, 6) - >>> haar_integral_permutation(row_indices, column_indices, d) - 1/(d*(d - 2)*(d - 1)) + >>> from sympy import Symbol + >>> from haarpy import haar_integral_permutation + >>> d = Symbol('d') + >>> row_indices = (0, 1, 2, 2) + >>> column_indices = (1, 0, 2, 2) + >>> haar_integral_permutation(row_indices, column_indices, 3) + Fraction(1, 6) + >>> haar_integral_permutation(row_indices, column_indices, d) + 1/(d*(d - 2)*(d - 1)) + + See Also + -------- + :func:`haarpy.permutation.weingarten_permutation` + Returns the Weingarten function for random permutation matrices """ if not (isinstance(row_indices, Sequence) and isinstance(column_indices, Sequence)): raise TypeError @@ -277,35 +312,47 @@ def haar_integral_centered_permutation( row_indices: tuple[int, ...], column_indices: tuple[int, ...], dimension: Symbol, -) -> Symbol: +) -> Expr: """Returns the integral over Haar random centered permutation matrices - Args: - row_indices (tuple(int)) : sequence of row indices - column_indices (tuple(int)) : sequence of column indices + Parameters + ---------- + row_indices : tuple[int, ...] + A sequence of row indices - Returns: - Symbol : integral under the Haar measure + column_indices : tuple[int, ...] + A sequence of column indices + + Returns + ------- + Expr + The integral under the Haar measure - Raise: - TypeError : if row_indices and column_indices are not Sequence - ValueError : if row_indices and column_indices are of different length + Raises + ------ + TypeError + If the input parameters are not of type ``Sequence`` + ValueError + If the input sequences are of different length Examples -------- - >>> from sympy import Symbol - >>> from haarpy import haar_integral_centered_permutation - >>> d = Symbol('d') - >>> row_indices = (0, 1, 2) - >>> column_indices = (0, 1, 1) - >>> haar_integral_centered_permutation(row_indices, column_indices, 3) - Fraction(-1, 27) - >>> haar_integral_centered_permutation(row_indices, column_indices, d) - -2/(d**3*(d - 1)) + >>> from sympy import Symbol + >>> from haarpy import haar_integral_centered_permutation + >>> d = Symbol('d') + >>> row_indices = (0, 1, 2) + >>> column_indices = (0, 1, 1) + >>> haar_integral_centered_permutation(row_indices, column_indices, 3) + Fraction(-1, 27) + >>> haar_integral_centered_permutation(row_indices, column_indices, d) + -2/(d**3*(d - 1)) See Also -------- - partial_order, weingarten_centered_permutation + :func:`haarpy.partition.partial_order` + Compares two partitions in terms of partial order + :func:`haarpy.permutation.weingarten_centered_permutation` + Returns the Weingarten function for centered random permutation matrices """ if not (isinstance(row_indices, Sequence) and isinstance(column_indices, Sequence)): raise TypeError diff --git a/haarpy/unitary.py b/haarpy/unitary.py index f12d5cd..18a5d05 100644 --- a/haarpy/unitary.py +++ b/haarpy/unitary.py @@ -94,9 +94,7 @@ def representation_dimension(partition: tuple[int, ...], unitary_dimension: Symb @lru_cache def weingarten_unitary(cycle: Permutation | tuple[int, ...], unitary_dimension: Symbol) -> Expr: - """Returns the Weingarten function - - The function works with both a permutation or a conjugacy class as a partition + """Returns the unitary Weingarten function Parameters ---------- @@ -112,7 +110,7 @@ def weingarten_unitary(cycle: Permutation | tuple[int, ...], unitary_dimension: The Weingarten function Raises - ----- + ------ TypeError If unitary_dimension has the wrong type TypeError @@ -121,7 +119,7 @@ def weingarten_unitary(cycle: Permutation | tuple[int, ...], unitary_dimension: Notes ----- Since the unitary Weingarten function is a class function on the symmetric group, the argument - may be given either as a permutation or as its cycle type + may be given either as a permutation or as its cycle-type Examples -------- @@ -187,39 +185,46 @@ def weingarten_unitary(cycle: Permutation | tuple[int, ...], unitary_dimension: def haar_integral_unitary( sequences: tuple[tuple[int, ...], ...], unitary_dimension: Symbol ) -> Expr: - """Returns integral over unitary group polynomial sampled at random from the Haar measure + """Returns the integral of a monomial over the unitary group Parameters ---------- - sequences (tuple[tuple[int]]) : indices of matrix elements - unitary_dimension (Symbol) : dimension of the unitary group + sequences : tuple[tuple[int, ...], ...] + Sequences of matrix elements + + unitary_dimension : Symbol + The dimension of the unitary group Returns ------- - Expr : integral under the Haar measure + Expr + The integral under the Haar measure Raises - ----- + ------ ValueError if sequences do not contain 4 tuples ValueError - if tuples i and j are of different length + if the input sequences are of different lengths Examples -------- - >>> from sympy import Symbol - >>> from haarpy import haar_integral_unitary - >>> d = Symbol("d") - >>> seq_i, seq_j = (0, 1, 2), (0, 0, 1) - >>> seq_i_prime, seq_j_prime = (0, 1, 2), (0, 1, 0) - >>> haar_integral_unitary((seq_i, seq_j, seq_i_prime, seq_j_prime), 5) - Fraction(-1, 840) - >>> haar_integral_unitary((seq_i, seq_j, seq_i_prime, seq_j_prime), d) - -1/(d*(d - 1)*(d + 1)*(d + 2)) + >>> from sympy import Symbol + >>> from haarpy import haar_integral_unitary + >>> d = Symbol("d") + >>> seq_i, seq_j = (0, 1, 2), (0, 0, 1) + >>> seq_i_prime, seq_j_prime = (0, 1, 2), (0, 1, 0) + >>> haar_integral_unitary((seq_i, seq_j, seq_i_prime, seq_j_prime), 5) + Fraction(-1, 840) + >>> haar_integral_unitary((seq_i, seq_j, seq_i_prime, seq_j_prime), d) + -1/(d*(d - 1)*(d + 1)*(d + 2)) See Also -------- - stabilizer_coset, weingarten_unitary + :func:`haarpy.symmetric.stabilizer_coset` + Returns all permutations sending a first sequence to a second sequence + :func:`haarpy.unitary.weingarten_unitary` + Returns the unitary Weingarten function """ if len(sequences) != 4: raise ValueError("Wrong tuple format") From 819bfd5081afeb8e4c49d694950c83ba547dfebb Mon Sep 17 00:00:00 2001 From: yaniccd Date: Thu, 4 Jun 2026 12:50:21 -0400 Subject: [PATCH 11/15] docstring updates --- docs/code/circular_ensembles.rst | 8 ++ docs/code/quantum.rst | 8 ++ docs/code/symplectic.rst | 8 ++ docs/index.rst | 2 +- haarpy/circular_ensembles.py | 177 ++++++++++++++++++------------- haarpy/orthogonal.py | 2 +- haarpy/quantum.py | 90 ++++++++++------ haarpy/symplectic.py | 142 +++++++++++++++---------- 8 files changed, 275 insertions(+), 162 deletions(-) create mode 100644 docs/code/circular_ensembles.rst create mode 100644 docs/code/quantum.rst create mode 100644 docs/code/symplectic.rst diff --git a/docs/code/circular_ensembles.rst b/docs/code/circular_ensembles.rst new file mode 100644 index 0000000..1c636f6 --- /dev/null +++ b/docs/code/circular_ensembles.rst @@ -0,0 +1,8 @@ +Circular ensembles Python API +======================== + +This module provides tools for computations of integrals of polynomials on the circular ensembles. + +.. automodule:: haarpy.circular_ensembles + :members: + :member-order: bysource \ No newline at end of file diff --git a/docs/code/quantum.rst b/docs/code/quantum.rst new file mode 100644 index 0000000..756f7ce --- /dev/null +++ b/docs/code/quantum.rst @@ -0,0 +1,8 @@ +Quantum groups Python API +======================== + +This module provides tools for computations of integrals of polynomials on the quantum groups. + +.. automodule:: haarpy.quantum + :members: + :member-order: bysource \ No newline at end of file diff --git a/docs/code/symplectic.rst b/docs/code/symplectic.rst new file mode 100644 index 0000000..b310da0 --- /dev/null +++ b/docs/code/symplectic.rst @@ -0,0 +1,8 @@ +Symplectic group Python API +======================== + +This module provides tools for computations of integrals of polynomials on the symplectic group. + +.. automodule:: haarpy.symplectic + :members: + :member-order: bysource \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 905c491..e975a71 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -31,6 +31,6 @@ A Python library for Weingarten calculus and integration of groups and ensembles code/permutation code/unitary code/orthogonal - .. code/symplectic + code/symplectic code/circular_ensembles code/quantum \ No newline at end of file diff --git a/haarpy/circular_ensembles.py b/haarpy/circular_ensembles.py index a8ac4c8..4ea1249 100644 --- a/haarpy/circular_ensembles.py +++ b/haarpy/circular_ensembles.py @@ -17,13 +17,12 @@ References ---------- [1] Matsumoto, S. (2013). Weingarten calculus for matrix ensembles associated with compact - symmetric spaces. arXiv preprint arXiv:1301.5401. + symmetric spaces. arXiv preprint arXiv:1301.5401. """ from math import prod from fractions import Fraction from functools import lru_cache -from typing import Union from collections import Counter from sympy import Symbol, Expr from sympy.combinatorics import Permutation, SymmetricGroup @@ -39,38 +38,43 @@ @lru_cache def weingarten_circular_orthogonal( - permutation: Union[Permutation, tuple[int, ...]], + permutation: Permutation | tuple[int, ...], coe_dimension: Symbol, ) -> Expr: """Returns the circular orthogonal ensemble's Weingarten functions Parameters ---------- - permutation (Permutation) : A permutation of S_2k or its coset-type - coe_dimension (Symbol) : The dimension of the COE + permutation : Permutation) : | tuple[int, ...] + A permutation of the symmetric group :math:`S_{2p}` or its coset-type + + coe_dimension : Symbol + The dimension of the circular orthogonal ensemble Returns ------- - Expr : The Weingarten function + Expr + The Weingarten function Examples -------- - >>> from sympy import Symbol - >>> from sympy.combinatorics import Permutation - >>> from haarpy import weingarten_circular_orthogonal - >>> d = Symbol("d") - >>> weingarten_circular_orthogonal(Permutation(3)(0,1), 4) - Fraction(3, 70) - >>> weingarten_circular_orthogonal(Permutation(3)(0,1), d) - (d + 2)/(d*(d + 1)*(d + 3)) - >>> weingarten_circular_orthogonal((1,1), d) - (d + 2)/(d*(d + 1)*(d + 3)) - - Where (1,1) is the coset-type of Permutation(3)(0,1) + >>> from sympy import Symbol + >>> from sympy.combinatorics import Permutation + >>> from haarpy import weingarten_circular_orthogonal + >>> d = Symbol("d") + >>> weingarten_circular_orthogonal(Permutation(3)(0,1), 4) + Fraction(3, 70) + >>> weingarten_circular_orthogonal(Permutation(3)(0,1), d) + (d + 2)/(d*(d + 1)*(d + 3)) + >>> weingarten_circular_orthogonal((1,1), d) + (d + 2)/(d*(d + 1)*(d + 3)) See Also -------- - coset_type, weingarten_orthogonal + :func:`haarpy.symmetric.coset_type` + Returns the coset-type of a given permutation of the symmetric group + :func:`haarpy.orthogonal.weingarten_orthogonal` + Returns the orthogonal Weingarten function """ return weingarten_orthogonal(permutation, coe_dimension + 1) @@ -81,27 +85,32 @@ def weingarten_circular_symplectic(permutation: Permutation, cse_dimension: Symb Parameters ---------- - permutation (Permutation) : A permutation of the symmetric group S_2k - cse_dimension (int) : The dimension of the CSE + permutation : Permutation + A permutation of the symmetric group :math:`S_{2p} + + cse_dimension : int + The dimension of the circular symplectic ensemble Returns ------- - Expr : The Weingarten function + Expr + The Weingarten function Examples -------- - >>> from sympy import Symbol - >>> from sympy.combinatorics import Permutation - >>> from haarpy import weingarten_circular_symplectic - >>> d = Symbol("d") - >>> weingarten_circular_symplectic(Permutation(3)(0,1), 4) - Fraction(-3, 140) - >>> weingarten_circular_symplectic(Permutation(3)(0,1), d) - (1 - d)/(d*(2*d - 3)*(2*d - 1)) + >>> from sympy import Symbol + >>> from sympy.combinatorics import Permutation + >>> from haarpy import weingarten_circular_symplectic + >>> d = Symbol("d") + >>> weingarten_circular_symplectic(Permutation(3)(0,1), 4) + Fraction(-3, 140) + >>> weingarten_circular_symplectic(Permutation(3)(0,1), d) + (1 - d)/(d*(2*d - 3)*(2*d - 1)) See Also -------- - weingarten_symplectic + :func:`haarpy.symplectic.weingarten_symplectic` + Returns the symplectic Weingarten function """ symplectic_dimension = ( (2 * cse_dimension - 1) / 2 @@ -115,37 +124,49 @@ def weingarten_circular_symplectic(permutation: Permutation, cse_dimension: Symb def haar_integral_circular_orthogonal( sequences: tuple[tuple[int, ...], ...], group_dimension: Symbol ) -> Expr: - """Returns integral over circular orthogonal ensemble polynomial + """Returns the integral over the circular orthogonal ensemble of a monomial sampled at random from the Haar measure Parameters ---------- - sequences (tuple[tuple[int]]) : Indices of matrix elements - group_dimension (Symbol) : Dimension of the orthogonal group + sequences : tuple[tuple[int, ...], ...] + Sequences of matrix elements + + group_dimension : Symbol + The dimension of the circular orthogonal ensemble Returns ------- - Expr : Integral under the Haar measure + Expr + The integral under the Haar measure - Raise - ----- - ValueError : if sequences do not contain 2 tuples - ValueError : if tuples i and j are of odd size + Raises + ------ + ValueError + If ``sequences`` do not contain precisely two sequences + ValueError + If the sequences are of odd length Examples -------- - >>> from sympy import Symbol - >>> from haarpy import haar_integral_circular_orthogonal - >>> d = Symbol("d") - >>> seq_i, seq_j = (0, 0, 1, 2), (1, 0, 0, 2) - >>> haar_integral_circular_orthogonal((seq_i, seq_j), 7) - Fraction(-1, 280) - >>> haar_integral_circular_orthogonal((seq_i, seq_j), d) - -2/(d*(d + 1)*(d + 3)) + >>> from sympy import Symbol + >>> from haarpy import haar_integral_circular_orthogonal + >>> d = Symbol("d") + >>> seq_i, seq_j = (0, 0, 1, 2), (1, 0, 0, 2) + >>> haar_integral_circular_orthogonal((seq_i, seq_j), 7) + Fraction(-1, 280) + >>> haar_integral_circular_orthogonal((seq_i, seq_j), d) + -2/(d*(d + 1)*(d + 3)) See Also -------- - coset_type, stabilizer_coset, weingarten_circular_orthogonal + :func:`haarpy.symmetric.coset_type` + Returns the coset-type of a given permutation of the symmetric group + :func:`haarpy.symmetric.stabilizer_coset` + Returns all permutations that sends the first sequences to the second. For a single input, + the function returns the stabilizer group with respect to the sequence + :func:`haarpy.circular_ensembles.weingarten_circular_orthogonal` + Returns the circular orthogonal ensemble's Weingarten functions """ if len(sequences) != 2: raise ValueError("Wrong tuple format") @@ -171,43 +192,55 @@ def haar_integral_circular_orthogonal( def haar_integral_circular_symplectic( sequences: tuple[tuple[Expr, ...], ...], half_dimension: Expr ) -> Expr: - """Returns integral over circular symplectic ensemble polynomial + """Returns the integral over the circular symplectic ensemble of a monomial sampled at random from the Haar measure Parameters ---------- - sequences (tuple[tuple[Expr]]) : Indices of matrix elements - half_dimension (Expr) : Half the dimension of the unitary group + sequences : tuple[tuple[Expr, ...], ...] + Indices of matrix elements + + half_dimension : Expr + Half the dimension of the unitary group Returns ------- - Expr : Integral under the Haar measure - - Raise - ----- - ValueError : if sequences do not contain 2 tuples - ValueError : if tuples i and j are of odd size - TypeError : if dimension is int and sequence is not - TypeError : if the half_dimension is neither int nor Symbol - ValueError : if all sequence indices are not between 0 and 2*dimension - 1 - TypeError : if sequence contains something other than Expr - TypeError : if symbolic sequences have the wrong format + Expr + The integral under the Haar measure + + Raises + ------ + ValueError + If parameter ``sequences`` do not contain precisely two sequences + ValueError + If either sequence is of odd length + TypeError + If parameter ``half_dimension`` is of type ``int`` while the sequences contain symbols + TypeError + If the parameter ``half_dimension`` is neither ``int`` nor ``Symbol`` + ValueError + If not all sequence indices are between ``0`` and ``2*half_dimension - 1`` + TypeError + If ``sequences`` contains something other than ``Expr`` or ``int`` + TypeError + If the symbolic sequences have the wrong format Examples -------- - >>> from sympy import Symbol - >>> from haarpy import haar_integral_circular_symplectic - >>> d = Symbol("d") - >>> seq_i_num, seq_j_num = (0, 3, 2, 1), (0, 1, 2, 3) - >>> haar_integral_circular_symplectic((seq_i_num, seq_j_num), 2) - Fraction(1, 6) - >>> seq_i_symb, seq_j_symb = (0, d+1, d, 1), (0, 1, d, d + 1) - >>> haar_integral_circular_symplectic((seq_i_symb, seq_j_symb), d) - -1/(2*d*(2*d - 3)*(2*d - 1)) + >>> from sympy import Symbol + >>> from haarpy import haar_integral_circular_symplectic + >>> d = Symbol("d") + >>> seq_i_num, seq_j_num = (0, 3, 2, 1), (0, 1, 2, 3) + >>> haar_integral_circular_symplectic((seq_i_num, seq_j_num), 2) + Fraction(1, 6) + >>> seq_i_symb, seq_j_symb = (0, d+1, d, 1), (0, 1, d, d + 1) + >>> haar_integral_circular_symplectic((seq_i_symb, seq_j_symb), d) + -1/(2*d*(2*d - 3)*(2*d - 1)) See Also -------- - weingarten_circular_symplectic + :func:`haarpy.circular_ensembles.weingarten_circular_symplectic` + Returns the circular symplectic ensemble's Weingarten functions """ if len(sequences) != 2: raise ValueError("Wrong sequence format") diff --git a/haarpy/orthogonal.py b/haarpy/orthogonal.py index bda09bc..d1b6cbf 100644 --- a/haarpy/orthogonal.py +++ b/haarpy/orthogonal.py @@ -53,7 +53,7 @@ def zonal_spherical_function(permutation: Permutation, partition: tuple[int, ... ---------- permutation : Permutation A permutation of the symmetric group :math:`S_{2p}` - + partition : tuple[int, ...] An integer partition of :math:`p` diff --git a/haarpy/quantum.py b/haarpy/quantum.py index 8c214fa..6ff8f15 100644 --- a/haarpy/quantum.py +++ b/haarpy/quantum.py @@ -38,22 +38,32 @@ def _haar_integral_quantum( Parameters ---------- - sequences (tuple[tuple[int]]) : indices of matrix elements - group_dimension (Symbol) : dimension of the quantum group - pair (bool) : True for free orthogonal group, False for free symmetric group + sequences : tuple[tuple[int, ...], ...] + The indices of matrix elements + + group_dimension : Symbol + The dimension of the quantum group + + pair : bool + ``True`` for free orthogonal group, ``False`` for free symmetric group Returns ------- - Expr : integral under the Haar measure + Expr + The integral under the Haar measure - Raise - ----- - TypeError : if the dimension is neither int nor Symbol - ValueError : if sequences do not contain 2 tuples or if they are of different length + Raises + ------ + TypeError + If the dimension is neither ``int`` nor ``Symbol`` + ValueError : if sequences do not contain 2 tuples or if they are of different length See Also -------- - gram_matrix + :func:`haarpy.partition.gram_matrix` + Generates the Gram matrix of a given input set of partitions + :func:`haarpy.partition.non_crossing_partitions` + Yields non crossing partitions of the set :math:`[n] = \{1,2,...,n\}` """ if not isinstance(group_dimension, (Expr, int)): raise TypeError @@ -101,27 +111,34 @@ def haar_integral_free_symmetric( Parameters ---------- - sequences (tuple[tuple[int]]) : indices of matrix elements - group_dimension (Symbol) : dimension of the quantum group + sequences : tuple[tuple[int, ...], ...] + Sequences of matrix elements + + group_dimension : Symbol + The dimension of the free symmetric group Returns ------- - Expr : integral under the Haar measure + Expr + The integral under the Haar measure Examples -------- - >>> from sympy import Symbol - >>> from haarpy import haar_integral_free_symmetric - >>> d = Symbol("d") - >>> sequences = ((0, 1, 2), (2, 1, 0)) - >>> haar_integral_free_symmetric(sequences, d) - 1/(d*(d - 2)*(d - 1)) - >>> haar_integral_free_symmetric(sequences, 4) - 1/24 + >>> from sympy import Symbol + >>> from haarpy import haar_integral_free_symmetric + >>> d = Symbol("d") + >>> sequences = ((0, 1, 2), (2, 1, 0)) + >>> haar_integral_free_symmetric(sequences, d) + 1/(d*(d - 2)*(d - 1)) + >>> haar_integral_free_symmetric(sequences, 4) + 1/24 See Also -------- - _haar_integral_quantum + :func:`haarpy.partition.gram_matrix` + Generates the Gram matrix of a given input set of partitions + :func:`haarpy.partition.non_crossing_partitions` + Yields non crossing partitions of the set :math:`[n] = \{1,2,...,n\}` """ return _haar_integral_quantum(sequences, group_dimension, False) @@ -135,26 +152,33 @@ def haar_integral_free_orthogonal( Parameters ---------- - sequences (tuple[tuple[int]]) : indices of matrix elements - group_dimension (Symbol) : dimension of the quantum group + sequences : tuple[tuple[int, ...], ...] + Sequences of matrix elements + + group_dimension : Symbol + The dimension of the free orthogonal group Returns ------- - Expr : integral under the Haar measure + Expr + The integral under the Haar measure Examples -------- - >>> from sympy import Symbol - >>> from haarpy import haar_integral_free_symmetric - >>> d = Symbol("d") - >>> sequences = ((0, 1, 1, 0), (0, 0, 1, 1)) - >>> haar_integral_free_symmetric(sequences, d) - -1/(d*(d - 1)*(d + 1)) - >>> haar_integral_free_symmetric(sequences, 4) - -1/60 + >>> from sympy import Symbol + >>> from haarpy import haar_integral_free_symmetric + >>> d = Symbol("d") + >>> sequences = ((0, 1, 1, 0), (0, 0, 1, 1)) + >>> haar_integral_free_symmetric(sequences, d) + -1/(d*(d - 1)*(d + 1)) + >>> haar_integral_free_symmetric(sequences, 4) + -1/60 See Also -------- - _haar_integral_quantum + :func:`haarpy.partition.gram_matrix` + Generates the Gram matrix of a given input set of partitions + :func:`haarpy.partition.non_crossing_partitions` + Yields non crossing partitions of the set :math:`[n] = \{1,2,...,n\}` """ return _haar_integral_quantum(sequences, group_dimension, True) diff --git a/haarpy/symplectic.py b/haarpy/symplectic.py index 8782c8d..46467a8 100644 --- a/haarpy/symplectic.py +++ b/haarpy/symplectic.py @@ -18,8 +18,10 @@ ---------- [1] Collins, B., & Śniady, P. (2006). Integration with respect to the Haar measure on unitary, orthogonal and symplectic group. Communications in Mathematical Physics, 264(3), 773-795. + [2] Matsumoto, S. (2013). Weingarten calculus for matrix ensembles associated with compact symmetric spaces. arXiv preprint arXiv:1301.5401. + [3] Macdonald, I. G. (1998). Symmetric functions and Hall polynomials. Oxford university press. """ @@ -43,34 +45,44 @@ @lru_cache def twisted_spherical_function(permutation: Permutation, partition: tuple[int, ...]) -> Fraction: - """Returns the twisted spherical function of the Gelfand pair (S_2k, H_k) + """Returns the twisted spherical function of the Gelfand pair :math:`(S_{2p}, H_p)` Parameters ---------- - permutation (Permutation) : a permutation of the symmetric group S_2k - partition (tuple[int]) : a partition of k + permutation : Permutation + A permutation of the symmetric group :math:`S_{2p}` + + partition : tuple[int, ...] + An integer partition of :math:`p` Returns ------- - Fraction : the twisted spherical function of the given permutation - - Raise - ----- - TypeError : if partition is not a tuple - TypeError : if permutation argument is not a permutation. - ValueError : if the degree of the permutation is not a factor of 2 - ValueError : if the degree of the partition and the permutation are incompatible + Fraction + The twisted spherical function of the given permutation + + Raises + ------ + TypeError + If ``partition`` is not of type ``tuple`` + TypeError + If ``permutation`` of type ``Permutation`` + ValueError + If the degree of the permutation is odd + ValueError + If the partition and the permutation are incompatible Examples -------- - >>> from sympy.combinatorics import Permutation - >>> from haarpy import twisted_spherical_function - >>> twisted_spherical_function(Permutation(5, 0, 1, 2), (2, 1)) - Fraction(1, 4) + >>> from sympy.combinatorics import Permutation + >>> from haarpy import twisted_spherical_function + >>> twisted_spherical_function(Permutation(5, 0, 1, 2), (2, 1)) + Fraction(1, 4) See Also -------- - murn_naka_rule + :func:`haarpy.symmetric.murn_naka_rule` + Implementation of the Murnaghan-Nakayama rule for the characters irreducible + representations of the symmetric group """ if not isinstance(partition, tuple): raise TypeError @@ -101,31 +113,36 @@ def weingarten_symplectic(permutation: Permutation, half_dimension: Symbol) -> E Parameters ---------- - permutation (Permutation) : a permutation of the symmetric group S_2k - half_dimension (Symbol) : half the dimension of the symplectic group + permutation : Permutation + A permutation of the symmetric group :math:`S_{2p}` + half_dimension : Symbol + Half the dimension of the symplectic group Returns ------- - Expr : the Weingarten function + Expr + The Weingarten function - Raise - ----- - ValueError : if the degree 2k of the symmetric group S_2k is not a factor of 2 + Raises + ------ + ValueError + If the degree :math:`2p` of the symmetric group :math:`S_{2p}` is odd Examples -------- - >>> from sympy import Symbol - >>> from sympy.combinatorics import Permutation - >>> from haarpy import weingarten_symplectic - >>> d = Symbol("d") - >>> weingarten_symplectic(Permutation(0, 1, 2, 3, 4, 5), 7) - Fraction(-1, 201600) - >>> weingarten_symplectic(Permutation(0, 1, 2, 3, 4, 5), d) - -1/(8*d*(d - 2)*(d - 1)*(d + 1)*(2*d + 1)) + >>> from sympy import Symbol + >>> from sympy.combinatorics import Permutation + >>> from haarpy import weingarten_symplectic + >>> d = Symbol("d") + >>> weingarten_symplectic(Permutation(0, 1, 2, 3, 4, 5), 7) + Fraction(-1, 201600) + >>> weingarten_symplectic(Permutation(0, 1, 2, 3, 4, 5), d) + -1/(8*d*(d - 2)*(d - 1)*(d + 1)*(2*d + 1)) See Also -------- - twisted_spherical_function, sympy.utilities.iterables.partitions + :func:`haarpy.symplectic.twisted_spherical_function` + Computes the twisted spherical function of the Gelfand pair :math:`(S_{2p}, H_p)` """ degree = permutation.size if degree % 2: @@ -189,41 +206,56 @@ def haar_integral_symplectic( Parameters ---------- - sequences (tuple[tuple[Expr]]) : indices of matrix elements - half_dimension (Symbol) : half the dimension of the symplectic group + sequences : tuple[tuple[Expr, ...], ...] + Indices of matrix elements + + half_dimension : Symbol + Half the dimension of the symplectic group Returns ------- - Expr : integral under the Haar measure - - Raise - ----- - ValueError : if sequences do not contain 2 tuples - ValueError : if tuples i and j are of different length - TypeError : if the half_dimension is not int nor Symbol - TypeError : if dimension is int and sequence is not - ValueError : if all sequence indices are not between 0 and 2*dimension - 1 - TypeError : if sequence containt something else than Expr - TypeError : if symbolic sequences have the wrong format + Expr + Integral under the Haar measure + + Raises + ------ + ValueError + If ``sequences`` do not contain 2 tuples + ValueError + If the sequences are of different lengths + TypeError + If ``half_dimension`` is neither ``int`` or ``Symbol`` + TypeError + If ``half_dimension`` is an ``int`` but ``sequences`` contain a ``Symbol`` + ValueError + If not all sequence indices are between ``0`` and ``2*half_dimension - 1`` + TypeError + If ``sequences`` containt something else than ``Expr`` and ``int`` + TypeError + If symbolic sequences have the wrong format Examples -------- - >>> from sympy import Symbol - >>> from haarpy import haar_integral_symplectic + >>> from sympy import Symbol + >>> from haarpy import haar_integral_symplectic - >>> d = Symbol("d") - >>> sequence_1, sequence_2 = (0, 1, 2, d, d+1, d+2), (0, 0, 0, d, d, d) - >>> haar_integral_symplectic((sequence_1, sequence_2), d) - 1/(4*d*(d + 1)*(2*d + 1)) + >>> d = Symbol("d") + >>> sequence_1, sequence_2 = (0, 1, 2, d, d+1, d+2), (0, 0, 0, d, d, d) + >>> haar_integral_symplectic((sequence_1, sequence_2), d) + 1/(4*d*(d + 1)*(2*d + 1)) - >>> d = 4 - >>> sequence_1, sequence_2 = (0, 1, 2, d, d+1, d+2), (0, 0, 0, d, d, d) - >>> haar_integral_symplectic((sequence_1, sequence_2), d) - Fraction(1, 720) + >>> d = 4 + >>> sequence_1, sequence_2 = (0, 1, 2, d, d+1, d+2), (0, 0, 0, d, d, d) + >>> haar_integral_symplectic((sequence_1, sequence_2), d) + Fraction(1, 720) See Also -------- - hyperoctahedral_transversal, weingarten_symplectic + :func:`haarpy.symmetric.hyperoctahedral_transversal` + Yields the permutations of :math:`M_{2p}`, the complete set of coset + representatives of the quotient group :math:`S_{2p}/H_p` + :func:`haarpy.symplectic.weingarten_symplectic` + Returns the symplectic Weingarten function """ if len(sequences) != 2: raise ValueError("Wrong sequence format") From 4302e4ff3f3d6e79e10b04d54e86cea0f3cf5218 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Wed, 10 Jun 2026 16:53:36 -0400 Subject: [PATCH 12/15] documentation added in PR #59 --- .readthedocs.yml | 21 +++++++++++++++++++++ docs/code/circular_ensembles.rst | 4 ++-- docs/code/orthogonal.rst | 4 ++-- docs/code/partition.rst | 4 ++-- docs/code/permutation.rst | 6 +++--- docs/code/quantum.rst | 4 ++-- docs/code/symmetric.rst | 6 +++--- docs/code/symplectic.rst | 4 ++-- docs/code/unitary.rst | 4 ++-- docs/index.rst | 17 ++++++++++++----- docs/requirements.txt | 8 ++++++++ 11 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 .readthedocs.yml create mode 100644 docs/requirements.txt diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..d51a0b8 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,21 @@ +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-24.04 + tools: + python: "3.12" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Set the requirements required to build your docs +python: + install: + - requirements: docs/requirements.txt \ No newline at end of file diff --git a/docs/code/circular_ensembles.rst b/docs/code/circular_ensembles.rst index 1c636f6..a0426be 100644 --- a/docs/code/circular_ensembles.rst +++ b/docs/code/circular_ensembles.rst @@ -1,5 +1,5 @@ -Circular ensembles Python API -======================== +Circular ensembles +================== This module provides tools for computations of integrals of polynomials on the circular ensembles. diff --git a/docs/code/orthogonal.rst b/docs/code/orthogonal.rst index 6f9939b..c2b9f45 100644 --- a/docs/code/orthogonal.rst +++ b/docs/code/orthogonal.rst @@ -1,5 +1,5 @@ -orthogonal group Python API -======================== +Orthogonal group +================ This module provides tools for computations of integrals of polynomials on the orthogonal group. diff --git a/docs/code/partition.rst b/docs/code/partition.rst index 724a743..2d439b2 100644 --- a/docs/code/partition.rst +++ b/docs/code/partition.rst @@ -1,5 +1,5 @@ -Partition Python API -========================== +Partition +========= Description diff --git a/docs/code/permutation.rst b/docs/code/permutation.rst index fc302c5..d207761 100644 --- a/docs/code/permutation.rst +++ b/docs/code/permutation.rst @@ -1,7 +1,7 @@ -Permutation matrices Python API -========================== +Permutation matrices +==================== -Description +This module provides tools for computations of integrals of Haar random permutation matrices. .. automodule:: haarpy.permutation :members: diff --git a/docs/code/quantum.rst b/docs/code/quantum.rst index 756f7ce..482dde9 100644 --- a/docs/code/quantum.rst +++ b/docs/code/quantum.rst @@ -1,5 +1,5 @@ -Quantum groups Python API -======================== +Quantum groups +============== This module provides tools for computations of integrals of polynomials on the quantum groups. diff --git a/docs/code/symmetric.rst b/docs/code/symmetric.rst index 7b35949..75f4b28 100644 --- a/docs/code/symmetric.rst +++ b/docs/code/symmetric.rst @@ -1,7 +1,7 @@ -Symmetric group Python API -========================== +Symmetric group +=============== -Description +This module provides tools to work with the symmetric group in the context of Weingarten calculus. .. automodule:: haarpy.symmetric :members: diff --git a/docs/code/symplectic.rst b/docs/code/symplectic.rst index b310da0..9530035 100644 --- a/docs/code/symplectic.rst +++ b/docs/code/symplectic.rst @@ -1,5 +1,5 @@ -Symplectic group Python API -======================== +Symplectic group +================ This module provides tools for computations of integrals of polynomials on the symplectic group. diff --git a/docs/code/unitary.rst b/docs/code/unitary.rst index e03162f..bfd6ba6 100644 --- a/docs/code/unitary.rst +++ b/docs/code/unitary.rst @@ -1,5 +1,5 @@ -Unitary group Python API -======================== +Unitary group +============= This module provides tools for computations of integrals of polynomials on the unitary group. diff --git a/docs/index.rst b/docs/index.rst index e975a71..97ec733 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,7 +8,18 @@ Haarpy Documentation A Python library for Weingarten calculus and integration of groups and ensembles equipped with the Haar measure. -.. toctree:: +.. + toctree:: + :maxdepth: 1 + :caption: Getting started + + .. /installation + .. /quickstart + .. /tutorials + .. /examples + +.. + toctree:: :maxdepth: 1 :caption: Background on Weingarten calculus @@ -18,10 +29,6 @@ A Python library for Weingarten calculus and integration of groups and ensembles theorry/quantum theory/permutation -.. toctree:: - :maxdepth: 1 - :caption: Tutorials and examples - .. toctree:: :maxdepth: 1 :caption: Haarpy API diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..7dd4bee --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,8 @@ +sphinx +pydata-sphinx-theme +myst-parser +sphinx-autodoc-typehints +sphinx-copybutton +sphinx-autobuild +sympy>=1.14 +ipykernel \ No newline at end of file From 7d5dda1d7401a4289c1e99eff4cd8d44fac4fbe0 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Wed, 10 Jun 2026 16:55:53 -0400 Subject: [PATCH 13/15] documentation added in PR #59 --- .github/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index f8f7b74..0c429df 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -24,6 +24,7 @@ * Added references and examples to the docstrings. Slight modification to the docstring format [(#47)](https://github.com/polyquantique/haarpy/pull/47). * `get_conjugacy_class()` has been sped up [(#51)](https://github.com/polyquantique/haarpy/pull/51). * `weingarten_...()` and `haar_integral_...()` have been sped up by building logic to simplify rational functions in `utils._simplify` [(#53)](https://github.com/polyquantique/haarpy/pull/53). +* Added documentation [(#59)](https://github.com/polyquantique/haarpy/pull/59). ### Bug fixes From 17f10cdb2695b99b29250767baa22ceda8e70bf7 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Wed, 10 Jun 2026 17:05:23 -0400 Subject: [PATCH 14/15] documentation added in PR #59 --- .github/workflows/python-publish.yml | 2 +- .github/workflows/tests.yml | 2 +- README.md | 2 +- setup.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 2e18ed8..eb768f2 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -25,7 +25,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1d933dd..5f8f566 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,7 +22,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.9' + python-version: '3.10' - name: Install dependencies shell: bash diff --git a/README.md b/README.md index 26617af..e270a59 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ pip install haarpy ## Compiling from source Haarpy has the following dependencies: -* [Python](https://www.python.org/) >= 3.9 +* [Python](https://www.python.org/) >= 3.10 * [SymPy](https://www.sympy.org) >= 1.14 diff --git a/setup.py b/setup.py index 3132d05..92cc71e 100644 --- a/setup.py +++ b/setup.py @@ -33,10 +33,10 @@ "Operating System :: Microsoft :: Windows", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3 :: Only", "Topic :: Scientific/Engineering :: Physics", ] From 3a72bcaa943961c034916d8e7667f333ccee3f9f Mon Sep 17 00:00:00 2001 From: yaniccd Date: Thu, 11 Jun 2026 12:40:34 -0400 Subject: [PATCH 15/15] documentation in PR #59 --- docs/conf.py | 2 + docs/index.rst | 9 +- docs/requirements.txt | 3 + docs/tutorials/guide.ipynb | 180 ++++++++++++++++++++++++++++++++ docs/tutorials/installation.rst | 26 +++++ 5 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 docs/tutorials/guide.ipynb create mode 100644 docs/tutorials/installation.rst diff --git a/docs/conf.py b/docs/conf.py index 4af6367..45baff2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,6 +27,8 @@ "sphinx.ext.autosummary", "sphinx_autodoc_typehints", "myst_parser", + "nbsphinx", + "sphinx_copybutton", ] bibtex_bibfiles = ["references.bib"] diff --git a/docs/index.rst b/docs/index.rst index 97ec733..04ad083 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,15 +8,12 @@ Haarpy Documentation A Python library for Weingarten calculus and integration of groups and ensembles equipped with the Haar measure. -.. - toctree:: +.. toctree:: :maxdepth: 1 :caption: Getting started - .. /installation - .. /quickstart - .. /tutorials - .. /examples + tutorials/installation + tutorials/guide.ipynb .. toctree:: diff --git a/docs/requirements.txt b/docs/requirements.txt index 7dd4bee..b15d6d0 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,7 @@ +docutils sphinx +sphinx_copybutton +nbsphinx pydata-sphinx-theme myst-parser sphinx-autodoc-typehints diff --git a/docs/tutorials/guide.ipynb b/docs/tutorials/guide.ipynb new file mode 100644 index 0000000..395bb89 --- /dev/null +++ b/docs/tutorials/guide.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quick Guide\n", + "To introduce the main functionality of Haarpy consider the following problem: imagine that you can generate unitary matrices at random (from the Haar measure); you would like to estimate the average of $|U_{i,j}|^2$ which we write mathematically as $\\int dU |U_{i,j}|^2 = \\int dU U_{i,j} U_{i,j}^*$. We could obtain this average by using the random matrix functionality of SciPy as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from scipy.stats import unitary_group" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.4964599 , 0.32742463, 0.25429793])" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.random.seed(137)\n", + "shots = 1000\n", + "\n", + "# For unitary matrices of size between 2 and 4 produce 1000 shots and calculate the average\n", + "# of the absolute value squared of the 0,1 entry\n", + "np.array(\n", + " [\n", + " np.mean([np.abs(unitary_group.rvs(dim=dim)[0, 1]) ** 2 for _ in range(shots)])\n", + " for dim in range(2, 5)\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Haarpy allows you to obtain this average (and many others!) analytically. We first recall that the expression we are trying to calculate is $\\int dU \\left|U_{i,j}\\right|^2 = \\int dU U_{i,j} U_{i,j}^*$. With this expression in mind we can use Sympy to create a symbolic variable $d$ for the dimension of the unitary and write" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from sympy import Symbol\n", + "from haarpy import haar_integral_unitary" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{1}{d}$" + ], + "text/plain": [ + "1/d" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d = Symbol(\"d\")\n", + "haar_integral_unitary((\"i\", \"j\", \"i\", \"j\"), d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also put integers" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Fraction(1, 3)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "haar_integral_unitary((\"i\", \"j\", \"i\", \"j\"), 3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice the order of the indices! The first `\"i\"` and `\"j\"` are the indices of $U$ while the second pair of `\"i\"` and `\"j\"` are the indices of $U^*$.\n", + "\n", + "Imagine that now we want to calculate something like $\\int dU U_{i,m} U_{j,n} U_{k,o} U_{i,m}^* U_{j,n}^* U_{k,p}^*$ $= \\int dU \\left|U_{i,m} U_{j,n} U_{k,o}\\right|^2$ we simply do" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle \\frac{d^{2} - 2}{d \\left(d - 2\\right) \\left(d - 1\\right) \\left(d + 1\\right) \\left(d + 2\\right)}$" + ], + "text/plain": [ + "(d**2 - 2)/(d*(d - 2)*(d - 1)*(d + 1)*(d + 2))" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "haar_integral_unitary((\"ijk\", \"mno\", \"ijk\", \"mno\"), d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The averages we are calculating are obtained by using so-called [Weingarten calculus](https://doi.org/10.1155/S107379280320917X)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "mtl", + "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.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/tutorials/installation.rst b/docs/tutorials/installation.rst new file mode 100644 index 0000000..ebc07f1 --- /dev/null +++ b/docs/tutorials/installation.rst @@ -0,0 +1,26 @@ + +Installation +============ + +Haarpy requires Python version 3.10 or later. Installation of Haarpy and its dependencies can be done using pip: + +.. code-block:: bash + + $ pip install haarpy + + +Compiling from source +--------------------- + +The Walrus has the following dependencies: + +* `Python `_ >= 3.10 +* `SymPy `_ >=1.14.0 + +You can compile the latest development version by cloning the git repository, and installing using +pip in development mode. + +.. code-block:: console + + $ git clone https://github.com/polyquantique/haarpy.git + $ cd haarpy && python -m pip install -e . \ No newline at end of file