Complex Infinity for negative k in symbol pys binomial
brandhoff opened this issue · comments
There is an unwanted behaviour using the binomial function of sympy, resulting in a nan return:
sum(sy.Pow(-1, k) * sy.binomial(self.n - k, k) * sy.binomial(self.n - 2 * k, (self.n - self.m) / 2 - k) * sy.Pow(rho, self.n - 2 * k) for k in range(0, int((self.n - self.m) / 2)+1))
will break for j= 15, 21, 28, 29, 36, 37.... also resulting in a wrong gradient:
if m == -5 and n == 5 and wrt == "x": if isinstance(x, ndarray): return 0 * ones(x.shape) return 0 if m == -5 and n == 5 and wrt == "y": if isinstance(x, ndarray): return 0 * ones(x.shape) return 0
an easy fix would be adopting the function from sympy and changing the return of elif n_nonneg is False and n_isint: # a special case when binomial evaluates to complex infinity return S.ComplexInfinity
to return 1 and then the function behaves as expected.
Hi @brandhoff, thanks a lot for taking the time to report this issue! 🙂 Do you want to create a PR yourself, or should I try to fix it? If I understand correctly, it should be sufficient to wrap sympy's binomial
function like this:
def binomial_(n: int, k: int) -> int:
result = sy.binomial(n, k)
if result == S.ComplexInfinity:
return 1
return result
and then replace the sy.binomial
calls with this wrapper?
Hey, yes this is sufficient as a fix. You can just add this function to the zernike module and call this one instead of sympys (S should be imported as from sympy.core import S
) :)
I finally had time to look at this again in a bit more detail. Turns out that the problem was pretty subtle and essentially boils down to sympy.binomial()
giving unexpected results when the type of the input is not integer:
>>> sympy.binomial(-1, 3)
-1
>>> sympy.binomial(-1, 3.0)
zoo
>>> sympy.binomial(-1.0, 3)
-1.00000000000000
>>> sympy.binomial(-1.0, 3.0)
nan
I've opened a sympy issue about this behavior.
For hswfs, this means that the above binomial_()
function is not really needed, and that the issue can be resolved simply by ensuring all inputs to sympy.binomial()
are cast to integer. I have already updated the code accordingly and pushed the changes 🙂 (see c5782f7 and subsequent commits)
@brandhoff Feel free to let me know if this is working for you!