From 0677dd7271ceddee55ce059c41d4a95017e62576 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Thu, 26 Mar 2026 17:19:27 +0900 Subject: [PATCH 1/7] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 08777d4..5baaaa3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ __pycache__/ _build/ +notebooks/ .coverage* coverage.xml From 3050aed3392b6ade96dec2e91b6143c841b63a42 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Thu, 26 Mar 2026 17:40:32 +0900 Subject: [PATCH 2/7] update changelog --- .github/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index a3dcac2..33b8dd2 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -22,6 +22,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 in [(#53)](https://github.com/polyquantique/haarpy/pull/53). +* Replace `haar_integral...()` and `weingarten...()` functions have been sped up [(#54)](https://github.com/polyquantique/haarpy/pull/54). ### Bug fixes From c050875bfe75538503041957a1d6a2f95e330523 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Fri, 27 Mar 2026 16:56:45 +0900 Subject: [PATCH 3/7] new simplify function in PR #53 --- haarpy/_utils.py | 62 ++++++++++++++++++++++++++++++++ haarpy/circular_ensembles.py | 2 +- haarpy/orthogonal.py | 31 +++++++--------- haarpy/permutation.py | 4 +-- haarpy/symplectic.py | 21 +++++------ haarpy/tests/test_orthogonal.py | 6 ++-- haarpy/tests/test_permutation.py | 6 ++-- haarpy/tests/test_symplectic.py | 10 +++--- haarpy/unitary.py | 30 ++++++---------- 9 files changed, 108 insertions(+), 64 deletions(-) create mode 100644 haarpy/_utils.py diff --git a/haarpy/_utils.py b/haarpy/_utils.py new file mode 100644 index 0000000..c70a092 --- /dev/null +++ b/haarpy/_utils.py @@ -0,0 +1,62 @@ +# 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. +""" +Utility Python interface +""" + +from collections.abc import Iterable +from fractions import Fraction +from sympy import Add, Mul, together, fraction, factor, factor_list, Expr, PolificationFailed + + +def _simplify(expr_iter: Iterable[Expr], constant: Fraction = Fraction(1, 1)) -> Expr: + """Factorizes a sum of rational fraction into a + single factorized, simplified fraction + + Parameters + ---------- + expr (Expr) : the expression to be simplified + constant (Fraction) : A constant fraction multiplying the simplification result + + Returns + ------- + Expr : the simplified fraction + """ + equation = together(Add(*expr_iter)) + #automatically factorises the denominator + num, denum = fraction(constant * equation) + + # Error occurs if numerator is a constant + try: + num_factor_list = factor_list(num) + except PolificationFailed: + return factor(num) / denum + + denum_factor_list = factor_list(denum) + + # gets rid of common factors + num_factor_dict, denum_factor_dict = dict(num_factor_list[1]), dict(denum_factor_list[1]) + for fact in num_factor_dict: + if fact in denum_factor_dict: + common = min(num_factor_dict[fact], denum_factor_dict[fact]) + num_factor_dict[fact] -= common + denum_factor_dict[fact] -= common + + num_simplified = Mul(*(fact**power for fact, power in num_factor_dict.items())) + denum_simplified = Mul(*(fact**power for fact, power in denum_factor_dict.items())) + constant_simplified = Fraction(num_factor_list[0], denum_factor_list[0]) + + return Mul(constant_simplified.numerator, num_simplified, evaluate=False) / Mul( + constant_simplified.denominator, denum_simplified, evaluate=False + ) diff --git a/haarpy/circular_ensembles.py b/haarpy/circular_ensembles.py index c36918b..74781a1 100644 --- a/haarpy/circular_ensembles.py +++ b/haarpy/circular_ensembles.py @@ -164,7 +164,7 @@ def haar_integral_circular_orthogonal( ) if isinstance(group_dimension, Expr): - numerator, denominator = fraction(cancel(together(integral))) + numerator, denominator = fraction(together(integral)) integral = factor(numerator) / factor(denominator) return integral diff --git a/haarpy/orthogonal.py b/haarpy/orthogonal.py index a8a0cc6..db57fe3 100644 --- a/haarpy/orthogonal.py +++ b/haarpy/orthogonal.py @@ -29,7 +29,7 @@ from functools import lru_cache from typing import Union from collections import Counter -from sympy import Symbol, Expr, factorial, factor, fraction, cancel, together +from sympy import Symbol, Expr, factorial from sympy.combinatorics import Permutation from sympy.utilities.iterables import partitions from haarpy import ( @@ -41,6 +41,7 @@ coset_type, coset_type_representative, ) +from ._utils import _simplify @lru_cache @@ -184,20 +185,16 @@ def weingarten_orthogonal( factorial(degree), ) else: - weingarten = ( - sum( - irrep_dim * zonal_spherical / coefficient - for irrep_dim, zonal_spherical, coefficient in zip( - irrep_dimension_gen, zonal_spherical_gen, coefficient_gen - ) - if coefficient + weingarten_gen = ( + irrep_dim * zonal_spherical / coefficient + for irrep_dim, zonal_spherical, coefficient in zip( + irrep_dimension_gen, zonal_spherical_gen, coefficient_gen ) - * 2**half_degree - * factorial(half_degree) - / factorial(degree) + if coefficient + ) + weingarten = _simplify( + weingarten_gen, Fraction(2**half_degree * factorial(half_degree), factorial(degree)) ) - numerator, denominator = fraction(cancel(together(weingarten))) - weingarten = factor(numerator) / factor(denominator) return weingarten @@ -263,13 +260,9 @@ def haar_integral_orthogonal(sequences: tuple[tuple[int]], orthogonal_dimension: coset_type(cycle_j * ~cycle_i) for cycle_i, cycle_j in product(permutation_i, permutation_j) ) - integral = sum( + integral_gen = ( count * weingarten_orthogonal(coset, orthogonal_dimension) for coset, count in coset_mapping.items() ) - if isinstance(orthogonal_dimension, Expr): - numerator, denominator = fraction(cancel(together(integral))) - integral = factor(numerator) / factor(denominator) - - return integral + return sum(integral_gen) if isinstance(orthogonal_dimension, int) else _simplify(integral_gen) diff --git a/haarpy/permutation.py b/haarpy/permutation.py index ba4c0cb..9a098ae 100644 --- a/haarpy/permutation.py +++ b/haarpy/permutation.py @@ -123,7 +123,7 @@ def weingarten_permutation( / prod(dimension - i for i, _ in enumerate(partition)) for partition in inferieur_partition_tuple ) - numerator, denominator = fraction(cancel(together(weingarten))) + numerator, denominator = fraction(together(weingarten)) weingarten = factor(numerator) / factor(denominator) return weingarten @@ -205,7 +205,7 @@ def weingarten_centered_permutation( for i in range(singleton_set_size + 1) ) - num, denum = fraction(cancel(together(weingarten))) + num, denum = fraction(together(weingarten)) weingarten = factor(num) / factor(denum) return weingarten diff --git a/haarpy/symplectic.py b/haarpy/symplectic.py index 008840c..4b371bd 100644 --- a/haarpy/symplectic.py +++ b/haarpy/symplectic.py @@ -38,6 +38,7 @@ irrep_dimension, hyperoctahedral_transversal, ) +from ._utils import _simplify @lru_cache @@ -165,20 +166,16 @@ def weingarten_symplectic(permutation: Permutation, half_dimension: Symbol) -> E factorial(degree), ) else: - weingarten = ( - sum( - irrep_dim * zonal_spherical / coefficient - for irrep_dim, zonal_spherical, coefficient in zip( - irrep_dimension_gen, twisted_spherical_gen, coefficient_gen - ) - if coefficient + weingarten_gen = ( + irrep_dim * zonal_spherical / coefficient + for irrep_dim, zonal_spherical, coefficient in zip( + irrep_dimension_gen, twisted_spherical_gen, coefficient_gen ) - * 2**half_degree - * factorial(half_degree) - / factorial(degree) + if coefficient + ) + weingarten = ( + _simplify(weingarten_gen) * 2**half_degree * factorial(half_degree) / factorial(degree) ) - numerator, denominator = fraction(cancel(together(weingarten))) - weingarten = factor(numerator) / factor(denominator) return weingarten diff --git a/haarpy/tests/test_orthogonal.py b/haarpy/tests/test_orthogonal.py index e56a366..73ad06e 100644 --- a/haarpy/tests/test_orthogonal.py +++ b/haarpy/tests/test_orthogonal.py @@ -223,7 +223,7 @@ def test_zonal_spherical_type_error(permutation, partition): (Permutation(0, 1, 2, 3, 4, 5), 2, d * (d - 1) * (d - 2) * (d + 2) * (d + 4)), ( Permutation(0, 1, 2, 3, 4, 5, 6, 7), - -5 * d - 6, + -(5 * d + 6), d * (d - 1) * (d - 2) * (d - 3) * (d + 1) * (d + 2) * (d + 4) * (d + 6), ), ( @@ -238,7 +238,7 @@ def test_zonal_spherical_type_error(permutation, partition): ), ( Permutation(4, 5, 6, 7), - -(d**3) - 6 * d**2 - 3 * d + 6, + -(d**3 + 6 * d**2 + 3 * d - 6), d * (d - 1) * (d - 2) * (d - 3) * (d + 1) * (d + 2) * (d + 4) * (d + 6), ), ( @@ -253,7 +253,7 @@ def test_weingarten_orthogonal_literature(permutation, num, denum): `Collins et al. Integration with Respect to the Haar Measure on Unitary, Orthogonal and Symplectic Group: `_ """ - assert ap.weingarten_orthogonal(permutation, d) == num / denum + assert ap.weingarten_orthogonal(permutation, d).equals(num / denum) @pytest.mark.parametrize("degree", range(2, 10, 2)) diff --git a/haarpy/tests/test_permutation.py b/haarpy/tests/test_permutation.py index a435efc..557c5c1 100644 --- a/haarpy/tests/test_permutation.py +++ b/haarpy/tests/test_permutation.py @@ -271,9 +271,9 @@ def test_haar_integral_centered_permutation_weingarten(row_indices, column_indic sum(value * hand_calculated_weingarten[key] for key, value in result_dict.items()) ) num, denum = fraction(result) - assert ap.haar_integral_centered_permutation(row_indices, column_indices, d) == factor( - num - ) / factor(denum) + assert ap.haar_integral_centered_permutation(row_indices, column_indices, d).equals( + factor(num) / factor(denum) + ) @pytest.mark.parametrize( diff --git a/haarpy/tests/test_symplectic.py b/haarpy/tests/test_symplectic.py index 1860017..409152c 100644 --- a/haarpy/tests/test_symplectic.py +++ b/haarpy/tests/test_symplectic.py @@ -186,12 +186,12 @@ def test_weingarten_symplectic_hyperoctahedral_symbolic(half_degree): """ if half_degree == 1: for permutation in SymmetricGroup(2 * half_degree).generate(): - assert ap.weingarten_symplectic(permutation, d) == (permutation.signature() / (2 * d)) + assert ap.weingarten_symplectic(permutation, d).equals((permutation.signature() / (2 * d))) else: for permutation in SymmetricGroup(2 * half_degree).generate(): hyperoctahedral = ap.HyperoctahedralGroup(half_degree) coefficient = permutation.signature() / (4 * d * (d - 1) * (2 * d + 1)) - assert ap.weingarten_symplectic(permutation, d) == ( + assert ap.weingarten_symplectic(permutation, d).equals( simplify((2 * d - 1) * coefficient) if permutation in hyperoctahedral else coefficient @@ -240,11 +240,11 @@ def test_weingarten_symplectic_orthogonal_relation(permutation): `Matsumoto. Weingarten calculus for matrix ensembles associated with compact symmetric spaces: `_ """ - assert ap.weingarten_symplectic(permutation, d) == simplify( + assert ap.weingarten_symplectic(permutation, d).equals(simplify( (-1) ** (permutation.size // 2) * permutation.signature() * ap.weingarten_orthogonal(permutation, -2 * d) - ) + )) @pytest.mark.parametrize( @@ -408,4 +408,4 @@ def test_haar_integral_symplectic_weingarten_reconciliation(half_degree): assert ap.haar_integral_symplectic( (sequence, perm_sequence), d - ) == ap.weingarten_symplectic(perm, d) + ).equals(ap.weingarten_symplectic(perm, d)) diff --git a/haarpy/unitary.py b/haarpy/unitary.py index 7b43500..7a80900 100644 --- a/haarpy/unitary.py +++ b/haarpy/unitary.py @@ -29,7 +29,7 @@ from itertools import product from collections import Counter from fractions import Fraction -from sympy import Symbol, Expr, fraction, together, cancel, factor +from sympy import Symbol, Expr from sympy.combinatorics import Permutation from sympy.utilities.iterables import partitions from haarpy import ( @@ -38,6 +38,7 @@ irrep_dimension, stabilizer_coset, ) +from ._utils import _simplify @lru_cache @@ -150,17 +151,14 @@ def weingarten_unitary(cycle: Union[Permutation, tuple[int]], unitary_dimension: for part, irrep_dimension in zip(partition_tuple, irrep_dimension_tuple) ) * Fraction(1, factorial(degree) ** 2) else: - weingarten = ( - sum( - irrep_dimension**2 - * murn_naka_rule(partition, conjugacy_class) - / representation_dimension(partition, unitary_dimension) - for partition, irrep_dimension in zip(partition_tuple, irrep_dimension_tuple) - ) - / factorial(degree) ** 2 + weingarten_gen = ( + irrep_dimension**2 + * murn_naka_rule(partition, conjugacy_class) + / representation_dimension(partition, unitary_dimension) + for partition, irrep_dimension in zip(partition_tuple, irrep_dimension_tuple) ) - numerator, denominator = fraction(cancel(together(weingarten))) - weingarten = factor(numerator) / factor(denominator) + + weingarten = _simplify(weingarten_gen, Fraction(1, factorial(degree) ** 2)) return weingarten @@ -207,8 +205,6 @@ def haar_integral_unitary(sequences: tuple[tuple[int]], unitary_dimension: Symbo if len(seq_i) != len(seq_j) or len(seq_i_prime) != len(seq_j_prime): raise ValueError("Wrong tuple format") - degree = len(seq_i) - class_mapping = Counter( get_conjugacy_class(cycle_i * ~cycle_j) for cycle_i, cycle_j in product( @@ -217,13 +213,9 @@ def haar_integral_unitary(sequences: tuple[tuple[int]], unitary_dimension: Symbo ) ) - integral = sum( + integral_gen = ( count * weingarten_unitary(conjugacy, unitary_dimension) for conjugacy, count in class_mapping.items() ) - if isinstance(unitary_dimension, Expr): - numerator, denominator = fraction(cancel(together(integral))) - integral = factor(numerator) / factor(denominator) - - return integral + return sum(integral_gen) if isinstance(unitary_dimension, int) else _simplify(integral_gen) From acdc2f404b85b0de8a2d06e29d9b84ab6f2845f0 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Fri, 27 Mar 2026 18:22:09 +0900 Subject: [PATCH 4/7] new simplify function in PR #53 --- haarpy/circular_ensembles.py | 23 ++++++++++------------- haarpy/permutation.py | 21 ++++++++------------- haarpy/tests/test_circular_ensembles.py | 4 ++-- haarpy/tests/test_permutation.py | 2 +- 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/haarpy/circular_ensembles.py b/haarpy/circular_ensembles.py index 74781a1..be906bf 100644 --- a/haarpy/circular_ensembles.py +++ b/haarpy/circular_ensembles.py @@ -25,7 +25,7 @@ from functools import lru_cache from typing import Union from collections import Counter -from sympy import Symbol, Expr, fraction, factor, cancel, together +from sympy import Symbol, Expr from sympy.combinatorics import Permutation, SymmetricGroup from sympy.core.numbers import Integer from haarpy import ( @@ -34,6 +34,7 @@ coset_type, stabilizer_coset, ) +from ._utils import _simplify @lru_cache @@ -158,16 +159,12 @@ def haar_integral_circular_orthogonal( coset_type(permutation) for permutation in stabilizer_coset(seq_i, seq_j) ) - integral = sum( + integral_gen = ( count * weingarten_circular_orthogonal(coset, group_dimension) for coset, count in coset_mapping.items() ) - if isinstance(group_dimension, Expr): - numerator, denominator = fraction(together(integral)) - integral = factor(numerator) / factor(denominator) - - return integral + return sum(integral_gen) if isinstance(group_dimension, int) else _simplify(integral_gen) @lru_cache @@ -298,13 +295,13 @@ def haar_integral_circular_symplectic(sequences: tuple[tuple[Expr]], half_dimens if permutation(shifted_i) == shifted_j ) - integral = coefficient * sum( + integral_gen = ( weingarten_circular_symplectic(permutation, half_dimension) for permutation in permutation_tuple ) - if isinstance(half_dimension, Expr): - numerator, denominator = fraction(cancel(together(integral))) - integral = factor(numerator) / factor(denominator) - - return integral + return ( + coefficient * sum(integral_gen) + if isinstance(half_dimension, int) + else _simplify(integral_gen, Fraction(coefficient, 1)) + ) diff --git a/haarpy/permutation.py b/haarpy/permutation.py index 9a098ae..0f9bd21 100644 --- a/haarpy/permutation.py +++ b/haarpy/permutation.py @@ -25,8 +25,9 @@ from itertools import product from collections.abc import Sequence from fractions import Fraction -from sympy import Symbol, binomial, factor, fraction, cancel, together +from sympy import Symbol, binomial from haarpy import set_partitions, meet_operation, join_operation, partial_order +from ._utils import _simplify @lru_cache @@ -117,14 +118,13 @@ def weingarten_permutation( for partition in inferieur_partition_tuple ) else: - weingarten = sum( + weingarten_gen = ( mobius_function(partition, first_partition) * mobius_function(partition, second_partition) / prod(dimension - i for i, _ in enumerate(partition)) for partition in inferieur_partition_tuple ) - numerator, denominator = fraction(together(weingarten)) - weingarten = factor(numerator) / factor(denominator) + weingarten = _simplify(weingarten_gen) return weingarten @@ -192,7 +192,7 @@ def weingarten_centered_permutation( for i in range(singleton_set_size + 1) ) else: - weingarten = sum( + weingarten_gen = ( (-1) ** i * binomial(singleton_set_size, i) * sum( @@ -205,8 +205,7 @@ def weingarten_centered_permutation( for i in range(singleton_set_size + 1) ) - num, denum = fraction(together(weingarten)) - weingarten = factor(num) / factor(denum) + weingarten = _simplify(weingarten_gen) return weingarten @@ -321,7 +320,7 @@ def haar_integral_centered_permutation( for unique in set(column_indices) ) - integral = sum( + integral_gen = ( weingarten_centered_permutation( partition_sigma, partition_tau, @@ -335,8 +334,4 @@ def haar_integral_centered_permutation( and partial_order(partition_tau, column_partition) ) - if isinstance(dimension, Symbol): - num, denum = fraction(cancel(together(integral))) - integral = factor(num) / factor(denum) - - return integral + return sum(integral_gen) if isinstance(dimension, int) else _simplify(integral_gen) diff --git a/haarpy/tests/test_circular_ensembles.py b/haarpy/tests/test_circular_ensembles.py index 75cda0f..f455d04 100644 --- a/haarpy/tests/test_circular_ensembles.py +++ b/haarpy/tests/test_circular_ensembles.py @@ -56,7 +56,7 @@ def test_weingarten_circular_orthogonal_hyperoctahedral_symbolic(half_degree): for permutation in SymmetricGroup(2 * half_degree).generate(): hyperoctahedral = ap.HyperoctahedralGroup(half_degree) coefficient = 1 / (d * (d + 1) * (d + 3)) - assert ap.weingarten_circular_orthogonal(permutation, d) == ( + assert ap.weingarten_circular_orthogonal(permutation, d).equals( simplify((d + 2) * coefficient) if permutation in hyperoctahedral else -coefficient ) @@ -94,7 +94,7 @@ def test_weingarten_circular_symplectic_hyperoctahedral_symbolic(half_degree): for permutation in SymmetricGroup(2 * half_degree).generate(): hyperoctahedral = ap.HyperoctahedralGroup(half_degree) coefficient = permutation.signature() / (d * (2 * d - 1) * (2 * d - 3)) - assert ap.weingarten_circular_symplectic(permutation, d) == ( + assert ap.weingarten_circular_symplectic(permutation, d).equals( simplify((d - 1) * coefficient) if permutation in hyperoctahedral else coefficient / 2 diff --git a/haarpy/tests/test_permutation.py b/haarpy/tests/test_permutation.py index 557c5c1..2b01e10 100644 --- a/haarpy/tests/test_permutation.py +++ b/haarpy/tests/test_permutation.py @@ -136,7 +136,7 @@ def test_weingarten_centered_permutation_hand_calculated(partition1, partition2, dimension = randint(10, 99) assert ap.weingarten_centered_permutation( partition1, partition2, d - ) == hand_calculated_weingarten[result_key] and ap.weingarten_centered_permutation( + ).equals(hand_calculated_weingarten[result_key]) and ap.weingarten_centered_permutation( partition1, partition2, dimension ) == Fraction( hand_calculated_weingarten[result_key].subs(d, dimension) From 81f41e00b3cf1c73ef67bbac4544a12152820d57 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Fri, 27 Mar 2026 18:30:12 +0900 Subject: [PATCH 5/7] new simplify function in PR #53 --- .github/CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 33b8dd2..a3dcac2 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -22,7 +22,6 @@ * 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 in [(#53)](https://github.com/polyquantique/haarpy/pull/53). -* Replace `haar_integral...()` and `weingarten...()` functions have been sped up [(#54)](https://github.com/polyquantique/haarpy/pull/54). ### Bug fixes From 94874172feb66d5f0c502cc3ebad7e6bfa0da4c4 Mon Sep 17 00:00:00 2001 From: yaniccd Date: Fri, 27 Mar 2026 19:01:21 +0900 Subject: [PATCH 6/7] new simplify function in PR #53 --- haarpy/symplectic.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/haarpy/symplectic.py b/haarpy/symplectic.py index 4b371bd..a8bd7f2 100644 --- a/haarpy/symplectic.py +++ b/haarpy/symplectic.py @@ -27,7 +27,7 @@ from fractions import Fraction from functools import lru_cache from itertools import product -from sympy import Symbol, factorial, factor, fraction, cancel, together, Expr +from sympy import Symbol, factorial, Expr from sympy.combinatorics import Permutation from sympy.utilities.iterables import partitions from sympy.core.numbers import Integer @@ -293,14 +293,10 @@ def twisted_delta(seq_value, seq_pos, perm): for perm in hyperoctahedral_transversal(degree) ) - integral = sum( + integral_gen = ( perm_i[1] * perm_j[1] * weingarten_symplectic(perm_j[0] * ~perm_i[0], half_dimension) for perm_i, perm_j in product(permutation_i_tuple, permutation_j_tuple) if perm_i[1] * perm_j[1] ) - if isinstance(half_dimension, Expr): - numerator, denominator = fraction(cancel(together(integral))) - integral = factor(numerator) / factor(denominator) - - return integral + return sum(integral_gen) if isinstance(half_dimension, int) else _simplify(integral_gen) From cbdf8493d8aed6d7fb1f3a2c21ce6afe02461dd0 Mon Sep 17 00:00:00 2001 From: Yanic Cardin Date: Fri, 27 Mar 2026 21:11:00 +0900 Subject: [PATCH 7/7] Update CHANGELOG #53 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nicolás Quesada <991946+nquesada@users.noreply.github.com> --- .github/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index a3dcac2..f4b4832 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -21,7 +21,7 @@ * 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). -* `weingarten_...()` and `haar_integral_...()` have been sped up in [(#53)](https://github.com/polyquantique/haarpy/pull/53). +* `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). ### Bug fixes