Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions haarpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,7 @@ def about():
import sympy

# a QuTiP-style infobox
print(
"\nHaarpy: a Python library for the symbolic calculation of Weingarten functions."
)
print("\nHaarpy: a Python library for the symbolic calculation of Weingarten functions.")
# print("Copyright 2018-2021 Polyquantique\n")

print("Python version: {}.{}.{}".format(*sys.version_info[0:3]))
Expand Down
16 changes: 4 additions & 12 deletions haarpy/circular_ensembles.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ def weingarten_circular_orthogonal(


@lru_cache
def weingarten_circular_symplectic(
permutation: Permutation, cse_dimension: Symbol
) -> Expr:
def weingarten_circular_symplectic(permutation: Permutation, cse_dimension: Symbol) -> Expr:
"""Returns the circular symplectic ensembles Weingarten functions

Args:
Expand Down Expand Up @@ -112,9 +110,7 @@ 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

Expand Down Expand Up @@ -151,9 +147,7 @@ def haar_integral_circular_symplectic(
raise ValueError("The matrix indices are outside the dimension range")
if degree != len(seq_j):
return 0
coefficient = prod(
-1 if i < half_dimension else 1 for i in (seq_i + seq_j)[::2]
)
coefficient = prod(-1 if i < half_dimension else 1 for i in (seq_i + seq_j)[::2])
shifted_i = [
(
i + half_dimension
Expand Down Expand Up @@ -189,9 +183,7 @@ def haar_integral_circular_symplectic(
raise TypeError
if degree != len(seq_j):
return 0
coefficient = prod(
-1 if isinstance(i, int) else 1 for i in (seq_i + seq_j)[::2]
)
coefficient = prod(-1 if isinstance(i, int) else 1 for i in (seq_i + seq_j)[::2])
shifted_i = [
(
i + half_dimension
Expand Down
25 changes: 7 additions & 18 deletions haarpy/orthogonal.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,7 @@ def zonal_spherical_function(permutation: Permutation, partition: tuple[int]) ->
double_partition = tuple(2 * part for part in partition)
hyperocta = HyperoctahedralGroup(degree // 2)
numerator = sum(
murn_naka_rule(
double_partition, get_conjugacy_class(permutation * zeta, degree)
)
murn_naka_rule(double_partition, get_conjugacy_class(permutation * zeta, degree))
for zeta in hyperocta.generate()
)
return Fraction(numerator, hyperocta.order())
Expand All @@ -94,9 +92,7 @@ def weingarten_orthogonal(
ValueError: if the degree 2k of the symmetric group S_2k is not a factor of 2
"""
if not isinstance(orthogonal_dimension, (Expr, int)):
raise TypeError(
"orthogonal_dimension must be an instance of int or sympy.Symbol"
)
raise TypeError("orthogonal_dimension must be an instance of int or sympy.Symbol")

if isinstance(permutation, (tuple, list)) and all(
isinstance(value, int) for value in permutation
Expand All @@ -112,18 +108,14 @@ def weingarten_orthogonal(
half_degree = degree // 2

partition_tuple = tuple(
sum((value * (key,) for key, value in part.items()), ())
for part in partitions(half_degree)
sum((value * (key,) for key, value in part.items()), ()) for part in partitions(half_degree)
)
double_partition_tuple = tuple(
tuple(2 * part for part in partition) for partition in partition_tuple
)
irrep_dimension_gen = (
irrep_dimension(partition) for partition in double_partition_tuple
)
irrep_dimension_gen = (irrep_dimension(partition) for partition in double_partition_tuple)
zonal_spherical_gen = (
zonal_spherical_function(permutation, partition)
for partition in partition_tuple
zonal_spherical_function(permutation, partition) for partition in partition_tuple
)
coefficient_gen = (
prod(
Expand Down Expand Up @@ -168,9 +160,7 @@ 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 integral over orthogonal group polynomial sampled at random from the Haar measure

Args:
Expand Down Expand Up @@ -209,8 +199,7 @@ def haar_integral_orthogonal(
)

coset_mapping = Counter(
coset_type(cycle_j * ~cycle_i)
for cycle_i, cycle_j in product(permutation_i, permutation_j)
coset_type(cycle_j * ~cycle_i) for cycle_i, cycle_j in product(permutation_i, permutation_j)
)

integral = sum(
Expand Down
19 changes: 4 additions & 15 deletions haarpy/partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,7 @@ def perfect_matchings(


@lru_cache
def partial_order(
partition_1: tuple[tuple[int]], partition_2: tuple[tuple[int]]
) -> bool:
def partial_order(partition_1: tuple[tuple[int]], partition_2: tuple[tuple[int]]) -> bool:
"""Returns True if parition_1 <= partition_2 in terms of partial order

For parition_1 and partition_2, two partitions of the same set, we call
Expand All @@ -105,9 +103,7 @@ def partial_order(


@lru_cache
def meet_operation(
partition_1: tuple[tuple[int]], partition_2: tuple[tuple[int]]
) -> tuple[tuple]:
def meet_operation(partition_1: tuple[tuple[int]], partition_2: tuple[tuple[int]]) -> tuple[tuple]:
"""Returns the greatest lower bound of the two input partitions

For parition_1 and partition_2, two partitions of the same set,
Expand Down Expand Up @@ -136,9 +132,7 @@ def meet_operation(


@lru_cache
def join_operation(
partition_1: tuple[tuple[int]], partition_2: tuple[tuple[int]]
) -> tuple[tuple]:
def join_operation(partition_1: tuple[tuple[int]], partition_2: tuple[tuple[int]]) -> tuple[tuple]:
"""Returns the least upper bound of the two input partitions

For parition_1 and partition_2, two partitions of the same set,
Expand All @@ -155,12 +149,7 @@ def join_operation(
tuple[tuple[int]]: Least upper bound
"""
parent = [
{
index
for value in block1
for index, block2 in enumerate(partition_2)
if value in block2
}
{index for value in block1 for index, block2 in enumerate(partition_2) if value in block2}
for block1 in partition_1
]

Expand Down
11 changes: 3 additions & 8 deletions haarpy/permutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@


@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:
"""Return the Möbius function
as seen in `Collins and Nagatsu. Weingarten Calculus for Centered Random
Permutation Matrices <https://arxiv.org/abs/2503.18453>`_
Expand All @@ -42,8 +40,7 @@ def mobius_function(
partition_set_2 = tuple(set(block) for block in partition_2)

partition_intersection = tuple(
sum(1 for block_1 in partition_set_1 if block_1 & block_2)
for block_2 in partition_set_2
sum(1 for block_1 in partition_set_1 if block_1 & block_2) for block_2 in partition_set_2
)

return prod(
Expand Down Expand Up @@ -109,9 +106,7 @@ def weingarten_centered_permutation(
Symbol : The Weingarten function
"""
singleton_set_size = sum(
1
for block in join_operation(first_partition, second_partition)
if len(block) == 1
1 for block in join_operation(first_partition, second_partition) if len(block) == 1
)

disjoint_partition_tuple = tuple(
Expand Down
52 changes: 13 additions & 39 deletions haarpy/symmetric.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ def get_conjugacy_class(perm: Permutation, degree: int) -> tuple:
"The degree you have provided is too low. It must be an integer greater than 0."
)
if not isinstance(perm, Permutation):
raise TypeError(
"Permutation must be of type sympy.combinatorics.permutations.Permutation"
)
raise TypeError("Permutation must be of type sympy.combinatorics.permutations.Permutation")

if perm.size > degree:
raise ValueError("Incompatible degree and permutation cycle")
Expand Down Expand Up @@ -101,17 +99,15 @@ def derivative_tableaux(
if not current_row_length:
if tableau[index][0] <= increment:
yield tuple(
row if i != index + 1 else row + (increment,)
for i, row in enumerate(tableau)
row if i != index + 1 else row + (increment,) for i, row in enumerate(tableau)
)
return
if (
current_row_length < min(part, previous_row__length)
and tableau[index][current_row_length] <= increment
):
yield tuple(
row if i != index + 1 else row + (increment,)
for i, row in enumerate(tableau)
row if i != index + 1 else row + (increment,) for i, row in enumerate(tableau)
)


Expand Down Expand Up @@ -141,9 +137,7 @@ 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

Args:
Expand Down Expand Up @@ -174,12 +168,7 @@ def proper_border_strip(
# 2x2 square condition
for i in range(1, len(tableau)):
for j in range(1, len(tableau[i])):
if (
tableau[i][j]
== tableau[i][j - 1]
== tableau[i - 1][j]
== tableau[i - 1][j - 1]
):
if tableau[i][j] == tableau[i][j - 1] == tableau[i - 1][j] == tableau[i - 1][j - 1]:
return False

return True
Expand All @@ -201,15 +190,12 @@ def murn_naka_rule(partition: tuple[int], conjugacy_class: tuple[int]) -> int:
return 0

tableaux = semi_standard_young_tableaux(partition, conjugacy_class)
tableaux = (
tableau for tableau in tableaux if proper_border_strip(tableau, conjugacy_class)
)
tableaux = (tableau for tableau in tableaux if proper_border_strip(tableau, conjugacy_class))

tableaux_set = ((set(row) for row in tableau) for tableau in tableaux)
heights = (tuple(i for row in tableau for i in row) for tableau in tableaux_set)
heights = (
sum(height.count(unit) - 1 for unit in range(len(conjugacy_class)))
for height in heights
sum(height.count(unit) - 1 for unit in range(len(conjugacy_class))) for height in heights
)

character = sum((-1) ** height for height in heights)
Expand All @@ -231,9 +217,7 @@ def irrep_dimension(partition: tuple[int]) -> int:
for i, part_i in enumerate(partition)
for j, part_j in enumerate(partition[i + 1 :])
)
denominator = prod(
factorial(part + len(partition) - i - 1) for i, part in enumerate(partition)
)
denominator = prod(factorial(part + len(partition) - i - 1) for i, part in enumerate(partition))
dimension = Fraction(numerator, denominator) * factorial(sum(partition))

return dimension.numerator
Expand All @@ -254,9 +238,7 @@ def sorting_permutation(*sequence: tuple[int]) -> Permutation:
TypeError: if more than two sequences are passed as arguments
"""
if len(sequence) == 1:
return Permutation(
sorted(range(len(sequence[0])), key=lambda k: sequence[0][k])
)
return Permutation(sorted(range(len(sequence[0])), key=lambda k: sequence[0][k]))
if len(sequence) == 2:
if sorted(sequence[0]) != sorted(sequence[1]):
raise ValueError("Incompatible sequences")
Expand Down Expand Up @@ -309,9 +291,7 @@ def stabilizer_coset(*sequence: tuple) -> Generator[Permutation, None, None]:
young_partition = tuple(sequence[0].count(i) for i in sorted(set(sequence[0])))

return (
~sorting_permutation(sequence[1])
* permutation
* sorting_permutation(sequence[0])
~sorting_permutation(sequence[1]) * permutation * sorting_permutation(sequence[0])
for permutation in YoungSubgroup(young_partition).generate()
)

Expand All @@ -331,9 +311,7 @@ def HyperoctahedralGroup(degree: int) -> PermutationGroup:
"""
if not isinstance(degree, int):
raise TypeError
transpositions = tuple(
Permutation(2 * degree - 1)(2 * i, 2 * i + 1) for i in range(degree)
)
transpositions = tuple(Permutation(2 * degree - 1)(2 * i, 2 * i + 1) for i in range(degree))
double_transpositions = tuple(
Permutation(2 * degree - 1)(2 * i, 2 * j)(2 * i + 1, 2 * j + 1)
for i in range(degree)
Expand All @@ -358,8 +336,7 @@ def hyperoctahedral_transversal(degree: int) -> Generator[Permutation, None, Non
if degree == 2:
return (Permutation(1),)
flatten_pmp = (
tuple(i for pair in pmp for i in pair)
for pmp in perfect_matchings(tuple(range(degree)))
tuple(i for pair in pmp for i in pair) for pmp in perfect_matchings(tuple(range(degree)))
)
return (Permutation(pmp) for pmp in flatten_pmp)

Expand Down Expand Up @@ -394,10 +371,7 @@ def coset_type(permutation: Permutation) -> tuple[int]:
)
return tuple(
sorted(
(
len(block) // 2
for block in join_operation(base_partition, matching_partition)
),
(len(block) // 2 for block in join_operation(base_partition, matching_partition)),
reverse=True,
)
)
Expand Down
Loading