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
5 changes: 3 additions & 2 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
### New features
* Added a new module `orthogonal` allowing the calculation of the orthogonal Weingarten function and its moments [(#28)](https://github.com/polyquantique/haarpy/pull/28).
* Added a new module `symplectic` allowing the calculation of the symplectic Weingarten function [(#31)](https://github.com/polyquantique/haarpy/pull/31).
* Added a new module `circular_ensembles` allowing the calculation of the circular orthogonal ensembles and circular symplectic ensembles Weingarten functions [(#32)](https://github.com/polyquantique/haarpy/pull/32).
* Added a new module `circular_ensembles` allowing the calculation of the circular orthogonal ensembles and circular symplectic ensembles Weingarten functions [(#32)](https://github.com/polyquantique/haarpy/pull/32) and moments [(#43)](https://github.com/polyquantique/haarpy/pull/43).
* Added a new module `permutation` allowing the calculation of the permutation matrices and centered permuation matrices' Weingarten functions as well as their moments [(#36)](https://github.com/polyquantique/haarpy/pull/36).
* Added a new module `partition` allowing to generate partitions of a set as well as implementing some operations on them such as the meet and the join operations [(#36)](https://github.com/polyquantique/haarpy/pull/36).
* Added moment calculation for Haar random symplectic matrices and circular symplectic ensemble [(#43)](https://github.com/polyquantique/haarpy/pull/43).

### Breaking changes

Expand All @@ -15,11 +14,13 @@
* `weingarten_class()` -> `weingarten_unitary()`
* `weingarten_element()` -> `weingarten_unitary()` The argument `degree` has been removed for the degree of the symmetric group is already contained in both the permutation and the conjugacy class.
* `coset_type()` -> `coset_type_representative()`
* `get_conjugacy_class()` : `degree` has been removed from the arguments since it is already contained in `permutation` [(#51)](https://github.com/polyquantique/haarpy/pull/51).

### Improvements

* The `README` has been improved to describe the expanding capabilities of `haarpy` [(#39)](https://github.com/polyquantique/haarpy/pull/39).
* 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).

### Bug fixes

Expand Down
2 changes: 1 addition & 1 deletion haarpy/orthogonal.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,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))
for zeta in hyperocta.generate()
)
return Fraction(numerator, hyperocta.order())
Expand Down
51 changes: 25 additions & 26 deletions haarpy/symmetric.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,53 +38,52 @@


@lru_cache
def get_conjugacy_class(perm: Permutation, degree: int) -> tuple:
def get_conjugacy_class(permutation: Permutation) -> tuple[int, ...]:
"""Returns the conjugacy class of an element of the symmetric group Sp

Parameters
----------
perm (Permutation) : permutation cycle from the symmetric group
degree (integer) : order of the symmetric group
permutation (Permutation) : permutation of the symmetric group

Returns
-------
tuple[int] : the conjugacy class in partition form
tuple[int] : the conjugacy class (cycle-type) of the permutation

Raise
-----
TypeError : order must be of type int
ValueError : if order is not an integer greaten than 1
TypeError : cycle must be of type sympy.combinatorics.permutations.Permutation
ValueError : incompatible degree and permutation cycle
TypeError : 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), 6)
>>> get_conjugacy_class(Permutation(5)(0,1,3))
(3, 1, 1, 1)
"""
if not isinstance(degree, int):
raise TypeError("degree must be of type int")
if not isinstance(permutation, Permutation):
raise TypeError("Permutation must be of type sympy.combinatorics.Permutation")
perm_array = permutation.array_form
degree = len(perm_array)

if degree < 1:
raise ValueError(
"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")
visited = [False] * degree
cycle_type = []

if perm.size > degree:
raise ValueError("Incompatible degree and permutation cycle")
for i in range(degree):
if not visited[i]:
j = i
cycle_len = 0

perm = perm * Permutation(degree - 1)
for _ in range(degree):
visited[j] = True
j = perm_array[j]
cycle_len += 1
if visited[j]:
break

return tuple(
sorted(
(key for key, value in perm.cycle_structure.items() for _ in range(value)),
reverse=True,
)
)
cycle_type.append(cycle_len)

cycle_type.sort(reverse=True)
return tuple(cycle_type)


def derivative_tableaux(
Expand Down
2 changes: 1 addition & 1 deletion haarpy/symplectic.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def twisted_spherical_function(permutation: Permutation, partition: tuple[int])
duplicate_partition = tuple(part for part in partition for _ in range(2))
hyperocta = HyperoctahedralGroup(degree // 2)
numerator = sum(
murn_naka_rule(duplicate_partition, get_conjugacy_class(~zeta * permutation, degree))
murn_naka_rule(duplicate_partition, get_conjugacy_class(~zeta * permutation))
* zeta.signature()
for zeta in hyperocta.generate()
)
Expand Down
84 changes: 22 additions & 62 deletions haarpy/tests/test_symmetric.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,82 +27,42 @@


@pytest.mark.parametrize(
"degree, cycle, conjugacy",
"cycle, conjugacy",
[
(3, Permutation(0, 1, 2), (3,)),
(3, Permutation(2)(0, 1), (2, 1)),
(4, Permutation(0, 1, 2, 3), (4,)),
(4, Permutation(0, 1, 2), (3, 1)),
(4, Permutation(0, 1)(2, 3), (2, 2)),
(5, Permutation(0, 1, 2), (3, 1, 1)),
(5, Permutation(1, 2, 4), (3, 1, 1)),
(5, Permutation(3)(0, 1, 2), (3, 1, 1)),
(6, Permutation(2)(3, 4, 5)(0, 1), (3, 2, 1)),
(6, Permutation(2, 3, 4, 0, 1, 5), (6,)),
(7, Permutation(2, 3, 4, 0, 1, 6), (6, 1)),
(1, Permutation(0), (1,)),
(Permutation(0, 1, 2), (3,)),
(Permutation(2)(0, 1), (2, 1)),
(Permutation(0, 1, 2, 3), (4,)),
(Permutation(3)(0, 1, 2), (3, 1)),
(Permutation(0, 1)(2, 3), (2, 2)),
(Permutation(4)(0, 1, 2), (3, 1, 1)),
(Permutation(1, 2, 4), (3, 1, 1)),
(Permutation(4)(0, 1, 2), (3, 1, 1)),
(Permutation(2)(3, 4, 5)(0, 1), (3, 2, 1)),
(Permutation(2, 3, 4, 0, 1, 5), (6,)),
(Permutation(2, 3, 4, 0, 1, 6), (6, 1)),
(Permutation(0), (1,)),
],
)
def test_get_conjugacy_class(degree, cycle, conjugacy):
def test_get_conjugacy_class(cycle, conjugacy):
"Test the normal usage of get_conjugacy_class"
assert ap.get_conjugacy_class(cycle, degree) == conjugacy
assert ap.get_conjugacy_class(cycle) == conjugacy


@pytest.mark.parametrize(
"degree, cycle",
"cycle",
[
("a", Permutation(0, 1, 2)),
(0.1, Permutation(2)(0, 1)),
((1,), Permutation(0, 1, 2, 3)),
((5,), Permutation(0, 1, 2)),
((1, 2, 3)),
("a"),
(2.0),
],
)
def test_get_conjugacy_class_degree_type_error(degree, cycle):
"Test the degree parameter TypeError"
with pytest.raises(TypeError, match=".*degree must be of type int.*"):
ap.get_conjugacy_class(cycle, degree)


@pytest.mark.parametrize("degree", range(-3, 1))
def test_get_conjugacy_class_degree_value_error(degree):
"Test the degree parameter ValueError"
with pytest.raises(
ValueError,
match=".*The degree you have provided is too low. It must be an integer greater than 0.*",
):
ap.get_conjugacy_class(Permutation(0, 1, 2), degree)


@pytest.mark.parametrize(
"degree, cycle",
[
(3, (1, 2, 3)),
(4, "a"),
(7, 2.0),
],
)
def test_get_conjugacy_class_cycle_type_error(degree, cycle):
def test_get_conjugacy_class_cycle_type_error(cycle):
"Test the cycle parameter TypeError"
with pytest.raises(
TypeError,
match=".*Permutation must be of type sympy.combinatorics.permutations.Permutation.*",
match=".*Permutation must be of type sympy.combinatorics.Permutation.*",
):
ap.get_conjugacy_class(cycle, degree)


@pytest.mark.parametrize(
"degree, cycle",
[
(3, Permutation(0, 1, 2, 3)),
(3, Permutation(2, 3)(0, 1)),
(4, Permutation(0, 1, 2, 3, 5)),
(4, Permutation(4, 1)),
],
)
def test_get_conjugacy_class_cycle_value_error(degree, cycle):
"Test the cycle parameter ValueError if permutation maximum value is greater than the degree"
with pytest.raises(ValueError, match=".*Incompatible degree and permutation cycle.*"):
ap.get_conjugacy_class(cycle, degree)
ap.get_conjugacy_class(cycle)


@pytest.mark.parametrize(
Expand Down
6 changes: 3 additions & 3 deletions haarpy/tests/test_unitary.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def test_weingarten_unitary_element(cycle, dimension, num, denum):
def test_weingarten_reconciliation_numeric(cycle):
"Numeric reconciliation of permutation and conjugacy class input"
assert ap.weingarten_unitary(cycle, 9) == ap.weingarten_unitary(
ap.get_conjugacy_class(cycle, cycle.size), 9
ap.get_conjugacy_class(cycle), 9
)


Expand All @@ -147,7 +147,7 @@ def test_weingarten_reconciliation_symbolic(cycle):
"Symbolic reconciliation of permutation and conjugacy class input"
d = Symbol("d")
assert ap.weingarten_unitary(cycle, d) == ap.weingarten_unitary(
ap.get_conjugacy_class(cycle, cycle.size), d
ap.get_conjugacy_class(cycle), d
)


Expand Down Expand Up @@ -216,7 +216,7 @@ def test_gram_orthogonality_elements(n):
def test_gram_orthogonality_classes(n):
"Test the orthogonality relation between Weingarten matrix and Graham matrix"
d = Symbol("d")
weight = lambda g: d ** (g.cycles) * ap.weingarten_unitary(ap.get_conjugacy_class(g, n), d)
weight = lambda g: d ** (g.cycles) * ap.weingarten_unitary(ap.get_conjugacy_class(g), d)
orthogonality = sum(len(c) * weight(c.pop()) for c in SymmetricGroup(n).conjugacy_classes())
assert simplify(orthogonality) == 1

Expand Down
7 changes: 4 additions & 3 deletions haarpy/unitary.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,16 @@ def weingarten_unitary(cycle: Union[Permutation, tuple[int]], unitary_dimension:

if isinstance(cycle, Permutation):
degree = cycle.size
conjugacy_class = get_conjugacy_class(cycle, degree)
conjugacy_class = get_conjugacy_class(cycle)
elif isinstance(cycle, (tuple, list)) and all(isinstance(value, int) for value in cycle):
degree = sum(cycle)
conjugacy_class = tuple(cycle)
else:
raise TypeError

partition_tuple = tuple(
sum((value * (key,) for key, value in part.items()), ()) for part in partitions(degree)
tuple(summand for summand, mult in partition.items() for _ in range(mult))
for partition in partitions(degree)
)
irrep_dimension_tuple = (irrep_dimension(part) for part in partition_tuple)

Expand Down Expand Up @@ -209,7 +210,7 @@ def haar_integral_unitary(sequences: tuple[tuple[int]], unitary_dimension: Symbo
degree = len(seq_i)

class_mapping = Counter(
get_conjugacy_class(cycle_i * ~cycle_j, degree)
get_conjugacy_class(cycle_i * ~cycle_j)
for cycle_i, cycle_j in product(
stabilizer_coset(seq_i, seq_i_prime),
stabilizer_coset(seq_j, seq_j_prime),
Expand Down
Loading