Source code for haarpy.quantum

# Copyright 2026 Polyquantique

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#    http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Quantum groups Python interface

References
----------
    [1] Banica, T., & Collins, B. (2007). Integration over compact quantum groups.
    Publications of the Research Institute for Mathematical Sciences, 43(2), 277-302.
"""

from functools import lru_cache
from itertools import product
from sympy import Expr, Symbol
from haarpy import non_crossing_partitions, gram_matrix
from ._utils import _simplify


@lru_cache
def _haar_integral_quantum(
    sequences: tuple[tuple[int, ...], ...],
    group_dimension: Symbol,
    pair: bool,
) -> Expr:
    """Returns the integral of a quantum group, either the free symmetric group or
    the free orthogonal group

    Parameters
    ----------
    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
        The integral under the Haar measure

    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
    --------
    :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
    if len(sequences) != 2 or len(sequences[0]) != len(sequences[1]):
        raise ValueError("Wrong tuple format")

    degree = len(sequences[0])
    partition_tuple = tuple(partition for partition in non_crossing_partitions(degree, pair))

    weingarten_matrix = gram_matrix(partition_tuple, group_dimension).inv()

    def is_elligible_partition(partition, sequence):
        block_values = tuple(sequence[block[0]] for block in partition)
        return all(
            sequence[i] == block_values[index]
            for index, block in enumerate(partition)
            for i in block
        )

    elligible_row_indices = (
        idx
        for idx, partition in enumerate(partition_tuple)
        if is_elligible_partition(partition, sequences[0])
    )
    elligible_col_indices = (
        idx
        for idx, partition in enumerate(partition_tuple)
        if is_elligible_partition(partition, sequences[1])
    )

    integral_gen = (
        weingarten_matrix[row_index, col_index]
        for row_index, col_index in product(elligible_row_indices, elligible_col_indices)
    )

    return sum(integral_gen) if isinstance(group_dimension, int) else _simplify(integral_gen)


[docs] @lru_cache def haar_integral_free_symmetric( sequences: tuple[tuple[int, ...], ...], group_dimension: Symbol, ) -> Expr: """Returns the integral of the free symmetric group under the Haar measure Parameters ---------- sequences : tuple[tuple[int, ...], ...] Sequences of matrix elements group_dimension : Symbol The dimension of the free symmetric group Returns ------- 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 See Also -------- :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)
[docs] @lru_cache def haar_integral_free_orthogonal( sequences: tuple[tuple[int, ...], ...], group_dimension: Symbol, ) -> Expr: """Returns the integral of the free orthogonal group under the Haar measure Parameters ---------- sequences : tuple[tuple[int, ...], ...] Sequences of matrix elements group_dimension : Symbol The dimension of the free orthogonal group Returns ------- 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 See Also -------- :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)