1"""
2This module implements computation of hypergeometric and related
3functions. In particular, it provides code for generic summation
4of hypergeometric series. Optimized versions for various special
5cases are also provided.
6"""
7
8import operator
9import math
10
11from .backend import MPZ_ZERO, MPZ_ONE, BACKEND, xrange, exec_
12
13from .libintmath import gcd
14
15from .libmpf import (\
16    ComplexResult, round_fast, round_nearest,
17    negative_rnd, bitcount, to_fixed, from_man_exp, from_int, to_int,
18    from_rational,
19    fzero, fone, fnone, ftwo, finf, fninf, fnan,
20    mpf_sign, mpf_add, mpf_abs, mpf_pos,
21    mpf_cmp, mpf_lt, mpf_le, mpf_gt, mpf_min_max,
22    mpf_perturb, mpf_neg, mpf_shift, mpf_sub, mpf_mul, mpf_div,
23    sqrt_fixed, mpf_sqrt, mpf_rdiv_int, mpf_pow_int,
24    to_rational,
25)
26
27from .libelefun import (\
28    mpf_pi, mpf_exp, mpf_log, pi_fixed, mpf_cos_sin, mpf_cos, mpf_sin,
29    mpf_sqrt, agm_fixed,
30)
31
32from .libmpc import (\
33    mpc_one, mpc_sub, mpc_mul_mpf, mpc_mul, mpc_neg, complex_int_pow,
34    mpc_div, mpc_add_mpf, mpc_sub_mpf,
35    mpc_log, mpc_add, mpc_pos, mpc_shift,
36    mpc_is_infnan, mpc_zero, mpc_sqrt, mpc_abs,
37    mpc_mpf_div, mpc_square, mpc_exp
38)
39
40from .libintmath import ifac
41from .gammazeta import mpf_gamma_int, mpf_euler, euler_fixed
42
43class NoConvergence(Exception):
44    pass
45
46
47#-----------------------------------------------------------------------#
48#                                                                       #
49#                     Generic hypergeometric series                     #
50#                                                                       #
51#-----------------------------------------------------------------------#
52
53"""
54TODO:
55
561. proper mpq parsing
572. imaginary z special-cased (also: rational, integer?)
583. more clever handling of series that don't converge because of stupid
59   upwards rounding
604. checking for cancellation
61
62"""
63
64def make_hyp_summator(key):
65    """
66    Returns a function that sums a generalized hypergeometric series,
67    for given parameter types (integer, rational, real, complex).
68
69    """
70    p, q, param_types, ztype = key
71
72    pstring = "".join(param_types)
73    fname = "hypsum_%i_%i_%s_%s_%s" % (p, q, pstring[:p], pstring[p:], ztype)
74    #print "generating hypsum", fname
75
76    have_complex_param = 'C' in param_types
77    have_complex_arg = ztype == 'C'
78    have_complex = have_complex_param or have_complex_arg
79
80    source = []
81    add = source.append
82
83    aint = []
84    arat = []
85    bint = []
86    brat = []
87    areal = []
88    breal = []
89    acomplex = []
90    bcomplex = []
91
92    #add("wp = prec + 40")
93    add("MAX = kwargs.get('maxterms', wp*100)")
94    add("HIGH = MPZ_ONE<<epsshift")
95    add("LOW = -HIGH")
96
97    # Setup code
98    add("SRE = PRE = one = (MPZ_ONE << wp)")
99    if have_complex:
100        add("SIM = PIM = MPZ_ZERO")
101
102    if have_complex_arg:
103        add("xsign, xm, xe, xbc = z[0]")
104        add("if xsign: xm = -xm")
105        add("ysign, ym, ye, ybc = z[1]")
106        add("if ysign: ym = -ym")
107    else:
108        add("xsign, xm, xe, xbc = z")
109        add("if xsign: xm = -xm")
110
111    add("offset = xe + wp")
112    add("if offset >= 0:")
113    add("    ZRE = xm << offset")
114    add("else:")
115    add("    ZRE = xm >> (-offset)")
116    if have_complex_arg:
117        add("offset = ye + wp")
118        add("if offset >= 0:")
119        add("    ZIM = ym << offset")
120        add("else:")
121        add("    ZIM = ym >> (-offset)")
122
123    for i, flag in enumerate(param_types):
124        W = ["A", "B"][i >= p]
125        if flag == 'Z':
126            ([aint,bint][i >= p]).append(i)
127            add("%sINT_%i = coeffs[%i]" % (W, i, i))
128        elif flag == 'Q':
129            ([arat,brat][i >= p]).append(i)
130            add("%sP_%i, %sQ_%i = coeffs[%i]._mpq_" % (W, i, W, i, i))
131        elif flag == 'R':
132            ([areal,breal][i >= p]).append(i)
133            add("xsign, xm, xe, xbc = coeffs[%i]._mpf_" % i)
134            add("if xsign: xm = -xm")
135            add("offset = xe + wp")
136            add("if offset >= 0:")
137            add("    %sREAL_%i = xm << offset" % (W, i))
138            add("else:")
139            add("    %sREAL_%i = xm >> (-offset)" % (W, i))
140        elif flag == 'C':
141            ([acomplex,bcomplex][i >= p]).append(i)
142            add("__re, __im = coeffs[%i]._mpc_" % i)
143            add("xsign, xm, xe, xbc = __re")
144            add("if xsign: xm = -xm")
145            add("ysign, ym, ye, ybc = __im")
146            add("if ysign: ym = -ym")
147
148            add("offset = xe + wp")
149            add("if offset >= 0:")
150            add("    %sCRE_%i = xm << offset" % (W, i))
151            add("else:")
152            add("    %sCRE_%i = xm >> (-offset)" % (W, i))
153            add("offset = ye + wp")
154            add("if offset >= 0:")
155            add("    %sCIM_%i = ym << offset" % (W, i))
156            add("else:")
157            add("    %sCIM_%i = ym >> (-offset)" % (W, i))
158        else:
159            raise ValueError
160
161    l_areal = len(areal)
162    l_breal = len(breal)
163    cancellable_real = min(l_areal, l_breal)
164    noncancellable_real_num = areal[cancellable_real:]
165    noncancellable_real_den = breal[cancellable_real:]
166
167    # LOOP
168    add("for n in xrange(1,10**8):")
169
170    add("    if n in magnitude_check:")
171    add("        p_mag = bitcount(abs(PRE))")
172    if have_complex:
173        add("        p_mag = max(p_mag, bitcount(abs(PIM)))")
174    add("        magnitude_check[n] = wp-p_mag")
175
176    # Real factors
177    multiplier = " * ".join(["AINT_#".replace("#", str(i)) for i in aint] + \
178                            ["AP_#".replace("#", str(i)) for i in arat] + \
179                            ["BQ_#".replace("#", str(i)) for i in brat])
180
181    divisor    = " * ".join(["BINT_#".replace("#", str(i)) for i in bint] + \
182                            ["BP_#".replace("#", str(i)) for i in brat] + \
183                            ["AQ_#".replace("#", str(i)) for i in arat] + ["n"])
184
185    if multiplier:
186        add("    mul = " + multiplier)
187    add("    div = " + divisor)
188
189    # Check for singular terms
190    add("    if not div:")
191    if multiplier:
192        add("        if not mul:")
193        add("            break")
194    add("        raise ZeroDivisionError")
195
196    # Update product
197    if have_complex:
198
199        # TODO: when there are several real parameters and just a few complex
200        # (maybe just the complex argument), we only need to do about
201        # half as many ops if we accumulate the real factor in a single real variable
202        for k in range(cancellable_real): add("    PRE = PRE * AREAL_%i // BREAL_%i" % (areal[k], breal[k]))
203        for i in noncancellable_real_num: add("    PRE = (PRE * AREAL_#) >> wp".replace("#", str(i)))
204        for i in noncancellable_real_den: add("    PRE = (PRE << wp) // BREAL_#".replace("#", str(i)))
205        for k in range(cancellable_real): add("    PIM = PIM * AREAL_%i // BREAL_%i" % (areal[k], breal[k]))
206        for i in noncancellable_real_num: add("    PIM = (PIM * AREAL_#) >> wp".replace("#", str(i)))
207        for i in noncancellable_real_den: add("    PIM = (PIM << wp) // BREAL_#".replace("#", str(i)))
208
209        if multiplier:
210            if have_complex_arg:
211                add("    PRE, PIM = (mul*(PRE*ZRE-PIM*ZIM))//div, (mul*(PIM*ZRE+PRE*ZIM))//div")
212                add("    PRE >>= wp")
213                add("    PIM >>= wp")
214            else:
215                add("    PRE = ((mul * PRE * ZRE) >> wp) // div")
216                add("    PIM = ((mul * PIM * ZRE) >> wp) // div")
217        else:
218            if have_complex_arg:
219                add("    PRE, PIM = (PRE*ZRE-PIM*ZIM)//div, (PIM*ZRE+PRE*ZIM)//div")
220                add("    PRE >>= wp")
221                add("    PIM >>= wp")
222            else:
223                add("    PRE = ((PRE * ZRE) >> wp) // div")
224                add("    PIM = ((PIM * ZRE) >> wp) // div")
225
226        for i in acomplex:
227            add("    PRE, PIM = PRE*ACRE_#-PIM*ACIM_#, PIM*ACRE_#+PRE*ACIM_#".replace("#", str(i)))
228            add("    PRE >>= wp")
229            add("    PIM >>= wp")
230
231        for i in bcomplex:
232            add("    mag = BCRE_#*BCRE_#+BCIM_#*BCIM_#".replace("#", str(i)))
233            add("    re = PRE*BCRE_# + PIM*BCIM_#".replace("#", str(i)))
234            add("    im = PIM*BCRE_# - PRE*BCIM_#".replace("#", str(i)))
235            add("    PRE = (re << wp) // mag".replace("#", str(i)))
236            add("    PIM = (im << wp) // mag".replace("#", str(i)))
237
238    else:
239        for k in range(cancellable_real): add("    PRE = PRE * AREAL_%i // BREAL_%i" % (areal[k], breal[k]))
240        for i in noncancellable_real_num: add("    PRE = (PRE * AREAL_#) >> wp".replace("#", str(i)))
241        for i in noncancellable_real_den: add("    PRE = (PRE << wp) // BREAL_#".replace("#", str(i)))
242        if multiplier:
243            add("    PRE = ((PRE * mul * ZRE) >> wp) // div")
244        else:
245            add("    PRE = ((PRE * ZRE) >> wp) // div")
246
247    # Add product to sum
248    if have_complex:
249        add("    SRE += PRE")
250        add("    SIM += PIM")
251        add("    if (HIGH > PRE > LOW) and (HIGH > PIM > LOW):")
252        add("        break")
253    else:
254        add("    SRE += PRE")
255        add("    if HIGH > PRE > LOW:")
256        add("        break")
257
258    #add("    from mpmath import nprint, log, ldexp")
259    #add("    nprint([n, log(abs(PRE),2), ldexp(PRE,-wp)])")
260
261    add("    if n > MAX:")
262    add("        raise NoConvergence('Hypergeometric series converges too slowly. Try increasing maxterms.')")
263
264    # +1 all parameters for next loop
265    for i in aint:     add("    AINT_# += 1".replace("#", str(i)))
266    for i in bint:     add("    BINT_# += 1".replace("#", str(i)))
267    for i in arat:     add("    AP_# += AQ_#".replace("#", str(i)))
268    for i in brat:     add("    BP_# += BQ_#".replace("#", str(i)))
269    for i in areal:    add("    AREAL_# += one".replace("#", str(i)))
270    for i in breal:    add("    BREAL_# += one".replace("#", str(i)))
271    for i in acomplex: add("    ACRE_# += one".replace("#", str(i)))
272    for i in bcomplex: add("    BCRE_# += one".replace("#", str(i)))
273
274    if have_complex:
275        add("a = from_man_exp(SRE, -wp, prec, 'n')")
276        add("b = from_man_exp(SIM, -wp, prec, 'n')")
277
278        add("if SRE:")
279        add("    if SIM:")
280        add("        magn = max(a[2]+a[3], b[2]+b[3])")
281        add("    else:")
282        add("        magn = a[2]+a[3]")
283        add("elif SIM:")
284        add("    magn = b[2]+b[3]")
285        add("else:")
286        add("    magn = -wp+1")
287
288        add("return (a, b), True, magn")
289    else:
290        add("a = from_man_exp(SRE, -wp, prec, 'n')")
291
292        add("if SRE:")
293        add("    magn = a[2]+a[3]")
294        add("else:")
295        add("    magn = -wp+1")
296
297        add("return a, False, magn")
298
299    source = "\n".join(("    " + line) for line in source)
300    source = ("def %s(coeffs, z, prec, wp, epsshift, magnitude_check, **kwargs):\n" % fname) + source
301
302    namespace = {}
303
304    exec_(source, globals(), namespace)
305
306    #print source
307    return source, namespace[fname]
308
309
310if BACKEND == 'sage':
311
312    def make_hyp_summator(key):
313        """
314        Returns a function that sums a generalized hypergeometric series,
315        for given parameter types (integer, rational, real, complex).
316        """
317        from sage.libs.mpmath.ext_main import hypsum_internal
318        p, q, param_types, ztype = key
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
324
325
326#-----------------------------------------------------------------------#
327#                                                                       #
328#                              Error functions                          #
329#                                                                       #
330#-----------------------------------------------------------------------#
331
332# TODO: mpf_erf should call mpf_erfc when appropriate (currently
333#    only the converse delegation is implemented)
334
335def mpf_erf(x, prec, rnd=round_fast):
336    sign, man, exp, bc = x
337    if not man:
338        if x == fzero: return fzero
339        if x == finf: return fone
340        if x== fninf: return fnone
341        return fnan
342    size = exp + bc
343    lg = math.log
344    # The approximation erf(x) = 1 is accurate to > x^2 * log(e,2) bits
345    if size > 3 and 2*(size-1) + 0.528766 > lg(prec,2):
346        if sign:
347            return mpf_perturb(fnone, 0, prec, rnd)
348        else:
349            return mpf_perturb(fone, 1, prec, rnd)
350    # erf(x) ~ 2*x/sqrt(pi) close to 0
351    if size < -prec:
352        # 2*x
353        x = mpf_shift(x,1)
354        c = mpf_sqrt(mpf_pi(prec+20), prec+20)
355        # TODO: interval rounding
356        return mpf_div(x, c, prec, rnd)
357    wp = prec + abs(size) + 25
358    # Taylor series for erf, fixed-point summation
359    t = abs(to_fixed(x, wp))
360    t2 = (t*t) >> wp
361    s, term, k = t, 12345, 1
362    while term:
363        t = ((t * t2) >> wp) // k
364        term = t // (2*k+1)
365        if k & 1:
366            s -= term
367        else:
368            s += term
369        k += 1
370    s = (s << (wp+1)) // sqrt_fixed(pi_fixed(wp), wp)
371    if sign:
372        s = -s
373    return from_man_exp(s, -wp, prec, rnd)
374
375# If possible, we use the asymptotic series for erfc.
376# This is an alternating divergent asymptotic series, so
377# the error is at most equal to the first omitted term.
378# Here we check if the smallest term is small enough
379# for a given x and precision
380def erfc_check_series(x, prec):
381    n = to_int(x)
382    if n**2 * 1.44 > prec:
383        return True
384    return False
385
386def mpf_erfc(x, prec, rnd=round_fast):
387    sign, man, exp, bc = x
388    if not man:
389        if x == fzero: return fone
390        if x == finf: return fzero
391        if x == fninf: return ftwo
392        return fnan
393    wp = prec + 20
394    mag = bc+exp
395    # Preserve full accuracy when exponent grows huge
396    wp += max(0, 2*mag)
397    regular_erf = sign or mag < 2
398    if regular_erf or not erfc_check_series(x, wp):
399        if regular_erf:
400            return mpf_sub(fone, mpf_erf(x, prec+10, negative_rnd[rnd]), prec, rnd)
401        # 1-erf(x) ~ exp(-x^2), increase prec to deal with cancellation
402        n = to_int(x)+1
403        return mpf_sub(fone, mpf_erf(x, prec + int(n**2*1.44) + 10), prec, rnd)
404    s = term = MPZ_ONE << wp
405    term_prev = 0
406    t = (2 * to_fixed(x, wp) ** 2) >> wp
407    k = 1
408    while 1:
409        term = ((term * (2*k - 1)) << wp) // t
410        if k > 4 and term > term_prev or not term:
411            break
412        if k & 1:
413            s -= term
414        else:
415            s += term
416        term_prev = term
417        #print k, to_str(from_man_exp(term, -wp, 50), 10)
418        k += 1
419    s = (s << wp) // sqrt_fixed(pi_fixed(wp), wp)
420    s = from_man_exp(s, -wp, wp)
421    z = mpf_exp(mpf_neg(mpf_mul(x,x,wp),wp),wp)
422    y = mpf_div(mpf_mul(z, s, wp), x, prec, rnd)
423    return y
424
425
426#-----------------------------------------------------------------------#
427#                                                                       #
428#                         Exponential integrals                         #
429#                                                                       #
430#-----------------------------------------------------------------------#
431
432def ei_taylor(x, prec):
433    s = t = x
434    k = 2
435    while t:
436        t = ((t*x) >> prec) // k
437        s += t // k
438        k += 1
439    return s
440
441def complex_ei_taylor(zre, zim, prec):
442    _abs = abs
443    sre = tre = zre
444    sim = tim = zim
445    k = 2
446    while _abs(tre) + _abs(tim) > 5:
447        tre, tim = ((tre*zre-tim*zim)//k)>>prec, ((tre*zim+tim*zre)//k)>>prec
448        sre += tre // k
449        sim += tim // k
450        k += 1
451    return sre, sim
452
453def ei_asymptotic(x, prec):
454    one = MPZ_ONE << prec
455    x = t = ((one << prec) // x)
456    s = one + x
457    k = 2
458    while t:
459        t = (k*t*x) >> prec
460        s += t
461        k += 1
462    return s
463
464def complex_ei_asymptotic(zre, zim, prec):
465    _abs = abs
466    one = MPZ_ONE << prec
467    M = (zim*zim + zre*zre) >> prec
468    # 1 / z
469    xre = tre = (zre << prec) // M
470    xim = tim = ((-zim) << prec) // M
471    sre = one + xre
472    sim = xim
473    k = 2
474    while _abs(tre) + _abs(tim) > 1000:
475        #print tre, tim
476        tre, tim = ((tre*xre-tim*xim)*k)>>prec, ((tre*xim+tim*xre)*k)>>prec
477        sre += tre
478        sim += tim
479        k += 1
480        if k > prec:
481            raise NoConvergence
482    return sre, sim
483
484def mpf_ei(x, prec, rnd=round_fast, e1=False):
485    if e1:
486        x = mpf_neg(x)
487    sign, man, exp, bc = x
488    if e1 and not sign:
489        if x == fzero:
490            return finf
491        raise ComplexResult("E1(x) for x < 0")
492    if man:
493        xabs = 0, man, exp, bc
494        xmag = exp+bc
495        wp = prec + 20
496        can_use_asymp = xmag > wp
497        if not can_use_asymp:
498            if exp >= 0:
499                xabsint = man << exp
500            else:
501                xabsint = man >> (-exp)
502            can_use_asymp = xabsint > int(wp*0.693) + 10
503        if can_use_asymp:
504            if xmag > wp:
505                v = fone
506            else:
507                v = from_man_exp(ei_asymptotic(to_fixed(x, wp), wp), -wp)
508            v = mpf_mul(v, mpf_exp(x, wp), wp)
509            v = mpf_div(v, x, prec, rnd)
510        else:
511            wp += 2*int(to_int(xabs))
512            u = to_fixed(x, wp)
513            v = ei_taylor(u, wp) + euler_fixed(wp)
514            t1 = from_man_exp(v,-wp)
515            t2 = mpf_log(xabs,wp)
516            v = mpf_add(t1, t2, prec, rnd)
517    else:
518        if x == fzero: v = fninf
519        elif x == finf: v = finf
520        elif x == fninf: v = fzero
521        else: v = fnan
522    if e1:
523        v = mpf_neg(v)
524    return v
525
526def mpc_ei(z, prec, rnd=round_fast, e1=False):
527    if e1:
528        z = mpc_neg(z)
529    a, b = z
530    asign, aman, aexp, abc = a
531    bsign, bman, bexp, bbc = b
532    if b == fzero:
533        if e1:
534            x = mpf_neg(mpf_ei(a, prec, rnd))
535            if not asign:
536                y = mpf_neg(mpf_pi(prec, rnd))
537            else:
538                y = fzero
539            return x, y
540        else:
541            return mpf_ei(a, prec, rnd), fzero
542    if a != fzero:
543        if not aman or not bman:
544            return (fnan, fnan)
545    wp = prec + 40
546    amag = aexp+abc
547    bmag = bexp+bbc
548    zmag = max(amag, bmag)
549    can_use_asymp = zmag > wp
550    if not can_use_asymp:
551        zabsint = abs(to_int(a)) + abs(to_int(b))
552        can_use_asymp = zabsint > int(wp*0.693) + 20
553    try:
554        if can_use_asymp:
555            if zmag > wp:
556                v = fone, fzero
557            else:
558                zre = to_fixed(a, wp)
559                zim = to_fixed(b, wp)
560                vre, vim = complex_ei_asymptotic(zre, zim, wp)
561                v = from_man_exp(vre, -wp), from_man_exp(vim, -wp)
562            v = mpc_mul(v, mpc_exp(z, wp), wp)
563            v = mpc_div(v, z, wp)
564            if e1:
565                v = mpc_neg(v, prec, rnd)
566            else:
567                x, y = v
568                if bsign:
569                    v = mpf_pos(x, prec, rnd), mpf_sub(y, mpf_pi(wp), prec, rnd)
570                else:
571                    v = mpf_pos(x, prec, rnd), mpf_add(y, mpf_pi(wp), prec, rnd)
572            return v
573    except NoConvergence:
574        pass
575    #wp += 2*max(0,zmag)
576    wp += 2*int(to_int(mpc_abs(z, 5)))
577    zre = to_fixed(a, wp)
578    zim = to_fixed(b, wp)
579    vre, vim = complex_ei_taylor(zre, zim, wp)
580    vre += euler_fixed(wp)
581    v = from_man_exp(vre,-wp), from_man_exp(vim,-wp)
582    if e1:
583        u = mpc_log(mpc_neg(z),wp)
584    else:
585        u = mpc_log(z,wp)
586    v = mpc_add(v, u, prec, rnd)
587    if e1:
588        v = mpc_neg(v)
589    return v
590
591def mpf_e1(x, prec, rnd=round_fast):
592    return mpf_ei(x, prec, rnd, True)
593
594def mpc_e1(x, prec, rnd=round_fast):
595    return mpc_ei(x, prec, rnd, True)
596
597def mpf_expint(n, x, prec, rnd=round_fast, gamma=False):
598    """
599    E_n(x), n an integer, x real
600
601    With gamma=True, computes Gamma(n,x)   (upper incomplete gamma function)
602
603    Returns (real, None) if real, otherwise (real, imag)
604    The imaginary part is an optional branch cut term
605
606    """
607    sign, man, exp, bc = x
608    if not man:
609        if gamma:
610            if x == fzero:
611                # Actually gamma function pole
612                if n <= 0:
613                    return finf, None
614                return mpf_gamma_int(n, prec, rnd), None
615            if x == finf:
616                return fzero, None
617            # TODO: could return finite imaginary value at -inf
618            return fnan, fnan
619        else:
620            if x == fzero:
621                if n > 1:
622                    return from_rational(1, n-1, prec, rnd), None
623                else:
624                    return finf, None
625            if x == finf:
626                return fzero, None
627            return fnan, fnan
628    n_orig = n
629    if gamma:
630        n = 1-n
631    wp = prec + 20
632    xmag = exp + bc
633    # Beware of near-poles
634    if xmag < -10:
635        raise NotImplementedError
636    nmag = bitcount(abs(n))
637    have_imag = n > 0 and sign
638    negx = mpf_neg(x)
639    # Skip series if direct convergence
640    if n == 0 or 2*nmag - xmag < -wp:
641        if gamma:
642            v = mpf_exp(negx, wp)
643            re = mpf_mul(v, mpf_pow_int(x, n_orig-1, wp), prec, rnd)
644        else:
645            v = mpf_exp(negx, wp)
646            re = mpf_div(v, x, prec, rnd)
647    else:
648        # Finite number of terms, or...
649        can_use_asymptotic_series = -3*wp < n <= 0
650        # ...large enough?
651        if not can_use_asymptotic_series:
652            xi = abs(to_int(x))
653            m = min(max(1, xi-n), 2*wp)
654            siz = -n*nmag + (m+n)*bitcount(abs(m+n)) - m*xmag - (144*m//100)
655            tol = -wp-10
656            can_use_asymptotic_series = siz < tol
657        if can_use_asymptotic_series:
658            r = ((-MPZ_ONE) << (wp+wp)) // to_fixed(x, wp)
659            m = n
660            t = r*m
661            s = MPZ_ONE << wp
662            while m and t:
663                s += t
664                m += 1
665                t = (m*r*t) >> wp
666            v = mpf_exp(negx, wp)
667            if gamma:
668                # ~ exp(-x) * x^(n-1) * (1 + ...)
669                v = mpf_mul(v, mpf_pow_int(x, n_orig-1, wp), wp)
670            else:
671                # ~ exp(-x)/x * (1 + ...)
672                v = mpf_div(v, x, wp)
673            re = mpf_mul(v, from_man_exp(s, -wp), prec, rnd)
674        elif n == 1:
675            re = mpf_neg(mpf_ei(negx, prec, rnd))
676        elif n > 0 and n < 3*wp:
677            T1 = mpf_neg(mpf_ei(negx, wp))
678            if gamma:
679                if n_orig & 1:
680                    T1 = mpf_neg(T1)
681            else:
682                T1 = mpf_mul(T1, mpf_pow_int(negx, n-1, wp), wp)
683            r = t = to_fixed(x, wp)
684            facs = [1] * (n-1)
685            for k in range(1,n-1):
686                facs[k] = facs[k-1] * k
687            facs = facs[::-1]
688            s = facs[0] << wp
689            for k in range(1, n-1):
690                if k & 1:
691                    s -= facs[k] * t
692                else:
693                    s += facs[k] * t
694                t = (t*r) >> wp
695            T2 = from_man_exp(s, -wp, wp)
696            T2 = mpf_mul(T2, mpf_exp(negx, wp))
697            if gamma:
698                T2 = mpf_mul(T2, mpf_pow_int(x, n_orig, wp), wp)
699            R = mpf_add(T1, T2)
700            re = mpf_div(R, from_int(ifac(n-1)), prec, rnd)
701        else:
702            raise NotImplementedError
703    if have_imag:
704        M = from_int(-ifac(n-1))
705        if gamma:
706            im = mpf_div(mpf_pi(wp), M, prec, rnd)
707            if n_orig & 1:
708                im = mpf_neg(im)
709        else:
710            im = mpf_div(mpf_mul(mpf_pi(wp), mpf_pow_int(negx, n_orig-1, wp), wp), M, prec, rnd)
711        return re, im
712    else:
713        return re, None
714
715def mpf_ci_si_taylor(x, wp, which=0):
716    """
717    0 - Ci(x) - (euler+log(x))
718    1 - Si(x)
719    """
720    x = to_fixed(x, wp)
721    x2 = -(x*x) >> wp
722    if which == 0:
723        s, t, k = 0, (MPZ_ONE<<wp), 2
724    else:
725        s, t, k = x, x, 3
726    while t:
727        t = (t*x2//(k*(k-1)))>>wp
728        s += t//k
729        k += 2
730    return from_man_exp(s, -wp)
731
732def mpc_ci_si_taylor(re, im, wp, which=0):
733    # The following code is only designed for small arguments,
734    # and not too small arguments (for relative accuracy)
735    if re[1]:
736        mag = re[2]+re[3]
737    elif im[1]:
738        mag = im[2]+im[3]
739    if im[1]:
740        mag = max(mag, im[2]+im[3])
741    if mag > 2 or mag < -wp:
742        raise NotImplementedError
743    wp += (2-mag)
744    zre = to_fixed(re, wp)
745    zim = to_fixed(im, wp)
746    z2re = (zim*zim-zre*zre)>>wp
747    z2im = (-2*zre*zim)>>wp
748    tre = zre
749    tim = zim
750    one = MPZ_ONE<<wp
751    if which == 0:
752        sre, sim, tre, tim, k = 0, 0, (MPZ_ONE<<wp), 0, 2
753    else:
754        sre, sim, tre, tim, k = zre, zim, zre, zim, 3
755    while max(abs(tre), abs(tim)) > 2:
756        f = k*(k-1)
757        tre, tim = ((tre*z2re-tim*z2im)//f)>>wp, ((tre*z2im+tim*z2re)//f)>>wp
758        sre += tre//k
759        sim += tim//k
760        k += 2
761    return from_man_exp(sre, -wp), from_man_exp(sim, -wp)
762
763def mpf_ci_si(x, prec, rnd=round_fast, which=2):
764    """
765    Calculation of Ci(x), Si(x) for real x.
766
767    which = 0 -- returns (Ci(x), -)
768    which = 1 -- returns (Si(x), -)
769    which = 2 -- returns (Ci(x), Si(x))
770
771    Note: if x < 0, Ci(x) needs an additional imaginary term, pi*i.
772    """
773    wp = prec + 20
774    sign, man, exp, bc = x
775    ci, si = None, None
776    if not man:
777        if x == fzero:
778            return (fninf, fzero)
779        if x == fnan:
780            return (x, x)
781        ci = fzero
782        if which != 0:
783            if x == finf:
784                si = mpf_shift(mpf_pi(prec, rnd), -1)
785            if x == fninf:
786                si = mpf_neg(mpf_shift(mpf_pi(prec, negative_rnd[rnd]), -1))
787        return (ci, si)
788    # For small x: Ci(x) ~ euler + log(x), Si(x) ~ x
789    mag = exp+bc
790    if mag < -wp:
791        if which != 0:
792            si = mpf_perturb(x, 1-sign, prec, rnd)
793        if which != 1:
794            y = mpf_euler(wp)
795            xabs = mpf_abs(x)
796            ci = mpf_add(y, mpf_log(xabs, wp), prec, rnd)
797        return ci, si
798    # For huge x: Ci(x) ~ sin(x)/x, Si(x) ~ pi/2
799    elif mag > wp:
800        if which != 0:
801            if sign:
802                si = mpf_neg(mpf_pi(prec, negative_rnd[rnd]))
803            else:
804                si = mpf_pi(prec, rnd)
805            si = mpf_shift(si, -1)
806        if which != 1:
807            ci = mpf_div(mpf_sin(x, wp), x, prec, rnd)
808        return ci, si
809    else:
810        wp += abs(mag)
811    # Use an asymptotic series? The smallest value of n!/x^n
812    # occurs for n ~ x, where the magnitude is ~ exp(-x).
813    asymptotic = mag-1 > math.log(wp, 2)
814    # Case 1: convergent series near 0
815    if not asymptotic:
816        if which != 0:
817            si = mpf_pos(mpf_ci_si_taylor(x, wp, 1), prec, rnd)
818        if which != 1:
819            ci = mpf_ci_si_taylor(x, wp, 0)
820            ci = mpf_add(ci, mpf_euler(wp), wp)
821            ci = mpf_add(ci, mpf_log(mpf_abs(x), wp), prec, rnd)
822        return ci, si
823    x = mpf_abs(x)
824    # Case 2: asymptotic series for x >> 1
825    xf = to_fixed(x, wp)
826    xr = (MPZ_ONE<<(2*wp)) // xf   # 1/x
827    s1 = (MPZ_ONE << wp)
828    s2 = xr
829    t = xr
830    k = 2
831    while t:
832        t = -t
833        t = (t*xr*k)>>wp
834        k += 1
835        s1 += t
836        t = (t*xr*k)>>wp
837        k += 1
838        s2 += t
839    s1 = from_man_exp(s1, -wp)
840    s2 = from_man_exp(s2, -wp)
841    s1 = mpf_div(s1, x, wp)
842    s2 = mpf_div(s2, x, wp)
843    cos, sin = mpf_cos_sin(x, wp)
844    # Ci(x) = sin(x)*s1-cos(x)*s2
845    # Si(x) = pi/2-cos(x)*s1-sin(x)*s2
846    if which != 0:
847        si = mpf_add(mpf_mul(cos, s1), mpf_mul(sin, s2), wp)
848        si = mpf_sub(mpf_shift(mpf_pi(wp), -1), si, wp)
849        if sign:
850            si = mpf_neg(si)
851        si = mpf_pos(si, prec, rnd)
852    if which != 1:
853        ci = mpf_sub(mpf_mul(sin, s1), mpf_mul(cos, s2), prec, rnd)
854    return ci, si
855
856def mpf_ci(x, prec, rnd=round_fast):
857    if mpf_sign(x) < 0:
858        raise ComplexResult
859    return mpf_ci_si(x, prec, rnd, 0)[0]
860
861def mpf_si(x, prec, rnd=round_fast):
862    return mpf_ci_si(x, prec, rnd, 1)[1]
863
864def mpc_ci(z, prec, rnd=round_fast):
865    re, im = z
866    if im == fzero:
867        ci = mpf_ci_si(re, prec, rnd, 0)[0]
868        if mpf_sign(re) < 0:
869            return (ci, mpf_pi(prec, rnd))
870        return (ci, fzero)
871    wp = prec + 20
872    cre, cim = mpc_ci_si_taylor(re, im, wp, 0)
873    cre = mpf_add(cre, mpf_euler(wp), wp)
874    ci = mpc_add((cre, cim), mpc_log(z, wp), prec, rnd)
875    return ci
876
877def mpc_si(z, prec, rnd=round_fast):
878    re, im = z
879    if im == fzero:
880        return (mpf_ci_si(re, prec, rnd, 1)[1], fzero)
881    wp = prec + 20
882    z = mpc_ci_si_taylor(re, im, wp, 1)
883    return mpc_pos(z, prec, rnd)
884
885
886#-----------------------------------------------------------------------#
887#                                                                       #
888#                             Bessel functions                          #
889#                                                                       #
890#-----------------------------------------------------------------------#
891
892# A Bessel function of the first kind of integer order, J_n(x), is
893# given by the power series
894
895#             oo
896#             ___         k         2 k + n
897#            \        (-1)     / x \
898#    J_n(x) = )    ----------- | - |
899#            /___  k! (k + n)! \ 2 /
900#            k = 0
901
902# Simplifying the quotient between two successive terms gives the
903# ratio x^2 / (-4*k*(k+n)). Hence, we only need one full-precision
904# multiplication and one division by a small integer per term.
905# The complex version is very similar, the only difference being
906# that the multiplication is actually 4 multiplies.
907
908# In the general case, we have
909# J_v(x) = (x/2)**v / v! * 0F1(v+1, (-1/4)*z**2)
910
911# TODO: for extremely large x, we could use an asymptotic
912# trigonometric approximation.
913
914# TODO: recompute at higher precision if the fixed-point mantissa
915# is very small
916
917def mpf_besseljn(n, x, prec, rounding=round_fast):
918    prec += 50
919    negate = n < 0 and n & 1
920    mag = x[2]+x[3]
921    n = abs(n)
922    wp = prec + 20 + n*bitcount(n)
923    if mag < 0:
924        wp -= n * mag
925    x = to_fixed(x, wp)
926    x2 = (x**2) >> wp
927    if not n:
928        s = t = MPZ_ONE << wp
929    else:
930        s = t = (x**n // ifac(n)) >> ((n-1)*wp + n)
931    k = 1
932    while t:
933        t = ((t * x2) // (-4*k*(k+n))) >> wp
934        s += t
935        k += 1
936    if negate:
937        s = -s
938    return from_man_exp(s, -wp, prec, rounding)
939
940def mpc_besseljn(n, z, prec, rounding=round_fast):
941    negate = n < 0 and n & 1
942    n = abs(n)
943    origprec = prec
944    zre, zim = z
945    mag = max(zre[2]+zre[3], zim[2]+zim[3])
946    prec += 20 + n*bitcount(n) + abs(mag)
947    if mag < 0:
948        prec -= n * mag
949    zre = to_fixed(zre, prec)
950    zim = to_fixed(zim, prec)
951    z2re = (zre**2 - zim**2) >> prec
952    z2im = (zre*zim) >> (prec-1)
953    if not n:
954        sre = tre = MPZ_ONE << prec
955        sim = tim = MPZ_ZERO
956    else:
957        re, im = complex_int_pow(zre, zim, n)
958        sre = tre = (re // ifac(n)) >> ((n-1)*prec + n)
959        sim = tim = (im // ifac(n)) >> ((n-1)*prec + n)
960    k = 1
961    while abs(tre) + abs(tim) > 3:
962        p = -4*k*(k+n)
963        tre, tim = tre*z2re - tim*z2im, tim*z2re + tre*z2im
964        tre = (tre // p) >> prec
965        tim = (tim // p) >> prec
966        sre += tre
967        sim += tim
968        k += 1
969    if negate:
970        sre = -sre
971        sim = -sim
972    re = from_man_exp(sre, -prec, origprec, rounding)
973    im = from_man_exp(sim, -prec, origprec, rounding)
974    return (re, im)
975
976def mpf_agm(a, b, prec, rnd=round_fast):
977    """
978    Computes the arithmetic-geometric mean agm(a,b) for
979    nonnegative mpf values a, b.
980    """
981    asign, aman, aexp, abc = a
982    bsign, bman, bexp, bbc = b
983    if asign or bsign:
984        raise ComplexResult("agm of a negative number")
985    # Handle inf, nan or zero in either operand
986    if not (aman and bman):
987        if a == fnan or b == fnan:
988            return fnan
989        if a == finf:
990            if b == fzero:
991                return fnan
992            return finf
993        if b == finf:
994            if a == fzero:
995                return fnan
996            return finf
997        # agm(0,x) = agm(x,0) = 0
998        return fzero
999    wp = prec + 20
1000    amag = aexp+abc
1001    bmag = bexp+bbc
1002    mag_delta = amag - bmag
1003    # Reduce to roughly the same magnitude using floating-point AGM
1004    abs_mag_delta = abs(mag_delta)
1005    if abs_mag_delta > 10:
1006        while abs_mag_delta > 10:
1007            a, b = mpf_shift(mpf_add(a,b,wp),-1), \
1008                mpf_sqrt(mpf_mul(a,b,wp),wp)
1009            abs_mag_delta //= 2
1010        asign, aman, aexp, abc = a
1011        bsign, bman, bexp, bbc = b
1012        amag = aexp+abc
1013        bmag = bexp+bbc
1014        mag_delta = amag - bmag
1015    #print to_float(a), to_float(b)
1016    # Use agm(a,b) = agm(x*a,x*b)/x to obtain a, b ~= 1
1017    min_mag = min(amag,bmag)
1018    max_mag = max(amag,bmag)
1019    n = 0
1020    # If too small, we lose precision when going to fixed-point
1021    if min_mag < -8:
1022        n = -min_mag
1023    # If too large, we waste time using fixed-point with large numbers
1024    elif max_mag > 20:
1025        n = -max_mag
1026    if n:
1027        a = mpf_shift(a, n)
1028        b = mpf_shift(b, n)
1029    #print to_float(a), to_float(b)
1030    af = to_fixed(a, wp)
1031    bf = to_fixed(b, wp)
1032    g = agm_fixed(af, bf, wp)
1033    return from_man_exp(g, -wp-n, prec, rnd)
1034
1035def mpf_agm1(a, prec, rnd=round_fast):
1036    """
1037    Computes the arithmetic-geometric mean agm(1,a) for a nonnegative
1038    mpf value a.
1039    """
1040    return mpf_agm(fone, a, prec, rnd)
1041
1042def mpc_agm(a, b, prec, rnd=round_fast):
1043    """
1044    Complex AGM.
1045
1046    TODO:
1047    * check that convergence works as intended
1048    * optimize
1049    * select a nonarbitrary branch
1050    """
1051    if mpc_is_infnan(a) or mpc_is_infnan(b):
1052        return fnan, fnan
1053    if mpc_zero in (a, b):
1054        return fzero, fzero
1055    if mpc_neg(a) == b:
1056        return fzero, fzero
1057    wp = prec+20
1058    eps = mpf_shift(fone, -wp+10)
1059    while 1:
1060        a1 = mpc_shift(mpc_add(a, b, wp), -1)
1061        b1 = mpc_sqrt(mpc_mul(a, b, wp), wp)
1062        a, b = a1, b1
1063        size = mpf_min_max([mpc_abs(a,10), mpc_abs(b,10)])[1]
1064        err = mpc_abs(mpc_sub(a, b, 10), 10)
1065        if size == fzero or mpf_lt(err, mpf_mul(eps, size)):
1066            return a
1067
1068def mpc_agm1(a, prec, rnd=round_fast):
1069    return mpc_agm(mpc_one, a, prec, rnd)
1070
1071def mpf_ellipk(x, prec, rnd=round_fast):
1072    if not x[1]:
1073        if x == fzero:
1074            return mpf_shift(mpf_pi(prec, rnd), -1)
1075        if x == fninf:
1076            return fzero
1077        if x == fnan:
1078            return x
1079    if x == fone:
1080        return finf
1081    # TODO: for |x| << 1/2, one could use fall back to
1082    # pi/2 * hyp2f1_rat((1,2),(1,2),(1,1), x)
1083    wp = prec + 15
1084    # Use K(x) = pi/2/agm(1,a) where a = sqrt(1-x)
1085    # The sqrt raises ComplexResult if x > 0
1086    a = mpf_sqrt(mpf_sub(fone, x, wp), wp)
1087    v = mpf_agm1(a, wp)
1088    r = mpf_div(mpf_pi(wp), v, prec, rnd)
1089    return mpf_shift(r, -1)
1090
1091def mpc_ellipk(z, prec, rnd=round_fast):
1092    re, im = z
1093    if im == fzero:
1094        if re == finf:
1095            return mpc_zero
1096        if mpf_le(re, fone):
1097            return mpf_ellipk(re, prec, rnd), fzero
1098    wp = prec + 15
1099    a = mpc_sqrt(mpc_sub(mpc_one, z, wp), wp)
1100    v = mpc_agm1(a, wp)
1101    r = mpc_mpf_div(mpf_pi(wp), v, prec, rnd)
1102    return mpc_shift(r, -1)
1103
1104def mpf_ellipe(x, prec, rnd=round_fast):
1105    # http://functions.wolfram.com/EllipticIntegrals/
1106    # EllipticK/20/01/0001/
1107    # E = (1-m)*(K'(m)*2*m + K(m))
1108    sign, man, exp, bc = x
1109    if not man:
1110        if x == fzero:
1111            return mpf_shift(mpf_pi(prec, rnd), -1)
1112        if x == fninf:
1113            return finf
1114        if x == fnan:
1115            return x
1116        if x == finf:
1117            raise ComplexResult
1118    if x == fone:
1119        return fone
1120    wp = prec+20
1121    mag = exp+bc
1122    if mag < -wp:
1123        return mpf_shift(mpf_pi(prec, rnd), -1)
1124    # Compute a finite difference for K'
1125    p = max(mag, 0) - wp
1126    h = mpf_shift(fone, p)
1127    K = mpf_ellipk(x, 2*wp)
1128    Kh = mpf_ellipk(mpf_sub(x, h), 2*wp)
1129    Kdiff = mpf_shift(mpf_sub(K, Kh), -p)
1130    t = mpf_sub(fone, x)
1131    b = mpf_mul(Kdiff, mpf_shift(x,1), wp)
1132    return mpf_mul(t, mpf_add(K, b), prec, rnd)
1133
1134def mpc_ellipe(z, prec, rnd=round_fast):
1135    re, im = z
1136    if im == fzero:
1137        if re == finf:
1138            return (fzero, finf)
1139        if mpf_le(re, fone):
1140            return mpf_ellipe(re, prec, rnd), fzero
1141    wp = prec + 15
1142    mag = mpc_abs(z, 1)
1143    p = max(mag[2]+mag[3], 0) - wp
1144    h = mpf_shift(fone, p)
1145    K = mpc_ellipk(z, 2*wp)
1146    Kh = mpc_ellipk(mpc_add_mpf(z, h, 2*wp), 2*wp)
1147    Kdiff = mpc_shift(mpc_sub(Kh, K, wp), -p)
1148    t = mpc_sub(mpc_one, z, wp)
1149    b = mpc_mul(Kdiff, mpc_shift(z,1), wp)
1150    return mpc_mul(t, mpc_add(K, b, wp), prec, rnd)
1151