Skip to content

Commit

Permalink
FEAT: simplify Hankel polynomial internally
Browse files Browse the repository at this point in the history
  • Loading branch information
redeboer committed May 16, 2024
1 parent 125d6e6 commit c4a253c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 24 deletions.
34 changes: 29 additions & 5 deletions src/ampform/dynamics/form_factor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from functools import lru_cache
from typing import Any

import sympy as sp
Expand Down Expand Up @@ -37,12 +38,16 @@ class BlattWeisskopfSquared(sp.Expr):
_latex_repr_ = R"B_{{{angular_momentum}}}^2\left({z}\right)"

def evaluate(self) -> sp.Expr:
z, angular_momentum = self.args
return (
sp.Abs(SphericalHankel1(angular_momentum, 1)) ** 2
/ sp.Abs(SphericalHankel1(angular_momentum, sp.sqrt(z))) ** 2
ell = self.angular_momentum
z = sp.Dummy("z", nonnegative=True, real=True)
expr = (
sp.Abs(SphericalHankel1(ell, 1)) ** 2
/ sp.Abs(SphericalHankel1(ell, sp.sqrt(z))) ** 2
/ z
)
if not ell.free_symbols:
expr = expr.doit().simplify()
return expr.xreplace({z: self.z})


@unevaluated(implement_doit=False)
Expand Down Expand Up @@ -75,10 +80,29 @@ def evaluate(self) -> sp.Expr:
return (
(-sp.I) ** (1 + l) # type:ignore[operator]
* (sp.exp(z * sp.I) / z)
* sp.Sum(
* _SymbolicSum(
sp.factorial(l + k)
/ (sp.factorial(l - k) * sp.factorial(k))
* (sp.I / (2 * z)) ** k, # type:ignore[operator]
(k, 0, l),
)
)


class _SymbolicSum(sp.Sum):
"""See [TR-029](https://compwa.github.io/report/029.html) for why this class is needed."""

def doit(self, deep: bool = True, **kwargs) -> sp.Expr:
if _get_indices(self):
expression = self.args[0]
indices = self.args[1:]
return _SymbolicSum(expression.doit(deep=deep, **kwargs), *indices)
return super().doit(deep=deep, **kwargs)


@lru_cache(maxsize=None)
def _get_indices(expr: sp.Sum) -> set[sp.Basic]:
free_symbols = set()
for index in expr.args[1:]:
free_symbols.update(index.free_symbols)
return {s for s in free_symbols if not isinstance(s, sp.Dummy)}
20 changes: 1 addition & 19 deletions tests/dynamics/test_dynamics.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,14 @@


class TestBlattWeisskopfSquared:
def test_max_angular_momentum(self):
def test_factorials(self):
z = sp.Symbol("z")
angular_momentum = sp.Symbol("L", integer=True)
form_factor = BlattWeisskopfSquared(z, angular_momentum)
form_factor_9 = form_factor.subs(angular_momentum, 8).evaluate()
factor, z_power, _ = form_factor_9.args
assert factor == 4392846440677
assert z_power == z**8
assert BlattWeisskopfSquared.max_angular_momentum is None
BlattWeisskopfSquared.max_angular_momentum = 1
assert form_factor.evaluate() == sp.Piecewise(
(1, sp.Eq(angular_momentum, 0)),
(2 * z / (z + 1), sp.Eq(angular_momentum, 1)),
)
BlattWeisskopfSquared.max_angular_momentum = None

def test_unevaluated_expression(self):
z = sp.Symbol("z")
ff1 = BlattWeisskopfSquared(z, angular_momentum=1)
ff2 = BlattWeisskopfSquared(z, angular_momentum=2)
assert ff1.max_angular_momentum is None
assert ff2.max_angular_momentum is None
BlattWeisskopfSquared.max_angular_momentum = 3
assert ff1.max_angular_momentum is 3 # noqa: F632
assert ff2.max_angular_momentum is 3 # noqa: F632
BlattWeisskopfSquared.max_angular_momentum = None


class TestEnergyDependentWidth:
Expand Down

0 comments on commit c4a253c

Please sign in to comment.