Opened 2 years ago

Last modified 2 years ago

#27785 new defect

hypergeometric function drops keyword arguments when evaluated with mpmath

Reported by: embray Owned by:
Priority: major Milestone:
Component: symbolics Keywords:
Cc: Merged in:
Authors: Reviewers:
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Status badges

Description

As demonstrated by this ask.sagemath.org question, when trying to evaluate hypergeometric numerically, if it does not appear to be converging after the default number of iterations it raises an exception:

NoConvergence: Hypergeometric series converges too slowly. Try increasing maxterms.

For example:

sage: hypergeometric([4.14 + 15*I, -3.14 + 15*I],[1. - 1.12e7*I], -500000)
....:
---------------------------------------------------------------------------
NoConvergence                             Traceback (most recent call last)
<ipython-input-1-77676b9ed860> in <module>()
----> 1 hypergeometric([RealNumber('4.14') + Integer(15)*I, -RealNumber('3.14') + Integer(15)*I],[RealNumber('1.') - RealNumber('1.12e7')*I], -Integer(500000))

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/functions/hypergeometric.py in __call__(self, a, b, z, **kwargs)
    275                                         SR._force_pyobject(a),
    276                                         SR._force_pyobject(b),
--> 277                                         z, **kwargs)
    278
    279     def _print_latex_(self, a, b, z):

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/symbolic/function.pyx in sage.symbolic.function.BuiltinFunction.__call__ (build/cythonized/sage/symbolic/function.cpp:11840)()
    996             res = self._evalf_try_(*args)
    997             if res is None:
--> 998                 res = super(BuiltinFunction, self).__call__(
    999                         *args, coerce=coerce, hold=hold)
   1000

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/symbolic/function.pyx in sage.symbolic.function.Function.__call__ (build/cythonized/sage/symbolic/function.cpp:6979)()
    493                     (<Expression>args[1])._gobj, hold)
    494         elif self._nargs == 3:
--> 495             res = g_function_eval3(self._serial,
    496                     (<Expression>args[0])._gobj, (<Expression>args[1])._gobj,
    497                     (<Expression>args[2])._gobj, hold)

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/symbolic/function.pyx in sage.symbolic.function.BuiltinFunction._evalf_or_eval_ (build/cythonized/sage/symbolic/function.cpp:12952)()
   1082         original version of :meth:`_eval_` saved in :meth:`__init__`.
   1083         """
-> 1084         res = self._evalf_try_(*args)
   1085         if res is None:
   1086             return self._eval0_(*args)

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/functions/hypergeometric.py in _evalf_try_(self, a, b, z)
    336             if not any(isinstance(x, Expression) for x in args):
    337                 p = get_coercion_model().common_parent(*args)
--> 338                 return self._evalf_(a, b, z, parent=p)
    339
    340     def _evalf_(self, a, b, z, parent, algorithm=None):

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/functions/hypergeometric.py in _evalf_(self, a, b, z, parent, algorithm)
    353         aa = [rational_param_as_tuple(c) for c in a]
    354         bb = [rational_param_as_tuple(c) for c in b]
--> 355         return mpmath_utils.call(hyper, aa, bb, z, parent=parent)
    356
    357     def _tderivative_(self, a, b, z, *args, **kwargs):

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/libs/mpmath/utils.pyx in sage.libs.mpmath.utils.call (build/cythonized/sage/libs/mpmath/utils.c:6947)()
    435     try:
    436         mp.prec = prec
--> 437         y = func(*args, **kwargs)
    438     finally:
    439         mp.prec = orig

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/mpmath/functions/hypergeometric.py in hyper(ctx, a_s, b_s, z, **kwargs)
    224         elif q == 0: return ctx._hyp1f0(a_s[0][0], z)
    225     elif p == 2:
--> 226         if   q == 1: return ctx._hyp2f1(a_s, b_s, z, **kwargs)
    227         elif q == 2: return ctx._hyp2f2(a_s, b_s, z, **kwargs)
    228         elif q == 3: return ctx._hyp2f3(a_s, b_s, z, **kwargs)

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/mpmath/functions/hypergeometric.py in _hyp2f1(ctx, a_s, b_s, z, **kwargs)
    454                 T2 = ([-z],[-b], [c,ab],[a,c-b], [b,t+b],[ctx.mpq_1-ab],  rz)
    455                 return T1, T2
--> 456             v = ctx.hypercomb(h, [a,b], **kwargs)
    457
    458         # Use 1-z transformation

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/mpmath/functions/hypergeometric.py in hypercomb(ctx, function, params, discard_known_zeros, **kwargs)
    125                 v = ctx.fprod([ctx.hyper(a_s, b_s, z, **kwargs)] + \
    126                     [ctx.gamma(a) for a in alpha_s] + \
--> 127                     [ctx.rgamma(b) for b in beta_s] + \
    128                     [ctx.power(w,c) for (w,c) in zip(w_s,c_s)])
    129                 if verbose:

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/mpmath/functions/hypergeometric.py in hyper(ctx, a_s, b_s, z, **kwargs)
    224         elif q == 0: return ctx._hyp1f0(a_s[0][0], z)
    225     elif p == 2:
--> 226         if   q == 1: return ctx._hyp2f1(a_s, b_s, z, **kwargs)
    227         elif q == 2: return ctx._hyp2f2(a_s, b_s, z, **kwargs)
    228         elif q == 3: return ctx._hyp2f3(a_s, b_s, z, **kwargs)

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/mpmath/functions/hypergeometric.py in _hyp2f1(ctx, a_s, b_s, z, **kwargs)
    441     if absz <= 0.8 or (ctx.isint(a) and a <= 0 and a >= -1000) or \
    442                       (ctx.isint(b) and b <= 0 and b >= -1000):
--> 443         return ctx.hypsum(2, 1, (atype, btype, ctype), [a, b, c], z, **kwargs)
    444
    445     orig = ctx.prec

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/mpmath/ctx_mp.py in hypsum(ctx, p, q, flags, coeffs, z, accurate_small, **kwargs)
    713                 mag_dict = {}
    714             zv, have_complex, magnitude = summator(coeffs, v, prec, wp, \
--> 715                 epsshift, mag_dict, **kwargs)
    716             cancel = -magnitude
    717             jumps_resolved = True

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/mpmath/libmp/libhyper.py in _hypsum(coeffs, z, prec, wp, epsshift, magnitude_check, **kwargs)
    319         def _hypsum(coeffs, z, prec, wp, epsshift, magnitude_check, **kwargs):
    320             return hypsum_internal(p, q, param_types, ztype, coeffs, z,
--> 321                 prec, wp, epsshift, magnitude_check, kwargs)
    322
    323         return "(none)", _hypsum

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/libs/mpmath/ext_main.pyx in sage.libs.mpmath.ext_main.hypsum_internal (build/cythonized/sage/libs/mpmath/ext_main.c:28408)()
   2646     cdef mpc c
   2647     c = mpc.__new__(mpc)
-> 2648     have_complex, magn = MPF_hypsum(&c.re, &c.im, p, q, param_types, \
   2649         ztype, coeffs, z, prec, wp, epsshift, magnitude_check, kwargs)
   2650     if have_complex:

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/libs/mpmath/ext_impl.pyx in sage.libs.mpmath.ext_impl.MPF_hypsum (build/cythonized/sage/libs/mpmath/ext_impl.c:23878)()
   2212         if n > MAX:
   2213             from mpmath.libmp import NoConvergence
-> 2214             raise NoConvergence('Hypergeometric series converges too slowly. Try increasing maxterms.')
   2215
   2216         # +1 all parameters for next iteration

NoConvergence: Hypergeometric series converges too slowly. Try increasing maxterms.

However, when trying to call it like:

sage: hypergeometric([4.14 + 15*I, -3.14 + 15*I],[1. - 1.12e7*I], -500000, maxterms=1e6)

it just gives

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-29457394b902> in <module>()
----> 1 hypergeometric([RealNumber('4.14') + Integer(15)*I, -RealNumber('3.14') + Integer(15)*I],[RealNumber('1.') - RealNumber('1.12e7')*I], -Integer(500000), maxterms=RealNumber('1e6'))
      2

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/functions/hypergeometric.py in __call__(self, a, b, z, **kwargs)
    275                                         SR._force_pyobject(a),
    276                                         SR._force_pyobject(b),
--> 277                                         z, **kwargs)
    278
    279     def _print_latex_(self, a, b, z):

/home/embray/src/sagemath/sage-python3/local/lib/python3.7/site-packages/sage/symbolic/function.pyx in sage.symbolic.function.BuiltinFunction.__call__ (build/cythonized/sage/symbolic/function.cpp:10399)()
    895                 evalf_params_first, alt_name = alt_name)
    896
--> 897     def __call__(self, *args, bint coerce=True, bint hold=False,
    898             bint dont_call_method_on_arg=False):
    899         r"""

TypeError: __call__() got an unexpected keyword argument 'maxterms'

So, somewhere in the symbolic function interface it refuses to pass through keywords that are understood only by the underlying numerical implementation.

Change History (1)

comment:1 Changed 2 years ago by embray

  • Milestone sage-8.8 deleted

As the Sage-8.8 release milestone is pending, we should delete the sage-8.8 milestone for tickets that are not actively being worked on or that still require significant work to move forward. If you feel that this ticket should be included in the next Sage release at the soonest please set its milestone to the next release milestone (sage-8.9).

Note: See TracTickets for help on using tickets.