| | from ..libmp.backend import xrange |
| | from .functions import defun, defun_wrapped |
| |
|
| | def _check_need_perturb(ctx, terms, prec, discard_known_zeros): |
| | perturb = recompute = False |
| | extraprec = 0 |
| | discard = [] |
| | for term_index, term in enumerate(terms): |
| | w_s, c_s, alpha_s, beta_s, a_s, b_s, z = term |
| | have_singular_nongamma_weight = False |
| | |
| | |
| | for k, w in enumerate(w_s): |
| | if not w: |
| | if ctx.re(c_s[k]) <= 0 and c_s[k]: |
| | perturb = recompute = True |
| | have_singular_nongamma_weight = True |
| | pole_count = [0, 0, 0] |
| | |
| | for data_index, data in enumerate([alpha_s, beta_s, b_s]): |
| | for i, x in enumerate(data): |
| | n, d = ctx.nint_distance(x) |
| | |
| | if n > 0: |
| | continue |
| | if d == ctx.ninf: |
| | |
| | |
| | ok = False |
| | if data_index == 2: |
| | for u in a_s: |
| | if ctx.isnpint(u) and u >= int(n): |
| | ok = True |
| | break |
| | if ok: |
| | continue |
| | pole_count[data_index] += 1 |
| | |
| | |
| | |
| | elif d < -4: |
| | extraprec += -d |
| | recompute = True |
| | if discard_known_zeros and pole_count[1] > pole_count[0] + pole_count[2] \ |
| | and not have_singular_nongamma_weight: |
| | discard.append(term_index) |
| | elif sum(pole_count): |
| | perturb = recompute = True |
| | return perturb, recompute, extraprec, discard |
| |
|
| | _hypercomb_msg = """ |
| | hypercomb() failed to converge to the requested %i bits of accuracy |
| | using a working precision of %i bits. The function value may be zero or |
| | infinite; try passing zeroprec=N or infprec=M to bound finite values between |
| | 2^(-N) and 2^M. Otherwise try a higher maxprec or maxterms. |
| | """ |
| |
|
| | @defun |
| | def hypercomb(ctx, function, params=[], discard_known_zeros=True, **kwargs): |
| | orig = ctx.prec |
| | sumvalue = ctx.zero |
| | dist = ctx.nint_distance |
| | ninf = ctx.ninf |
| | orig_params = params[:] |
| | verbose = kwargs.get('verbose', False) |
| | maxprec = kwargs.get('maxprec', ctx._default_hyper_maxprec(orig)) |
| | kwargs['maxprec'] = maxprec |
| | zeroprec = kwargs.get('zeroprec') |
| | infprec = kwargs.get('infprec') |
| | perturbed_reference_value = None |
| | hextra = 0 |
| | try: |
| | while 1: |
| | ctx.prec += 10 |
| | if ctx.prec > maxprec: |
| | raise ValueError(_hypercomb_msg % (orig, ctx.prec)) |
| | orig2 = ctx.prec |
| | params = orig_params[:] |
| | terms = function(*params) |
| | if verbose: |
| | print() |
| | print("ENTERING hypercomb main loop") |
| | print("prec =", ctx.prec) |
| | print("hextra", hextra) |
| | perturb, recompute, extraprec, discard = \ |
| | _check_need_perturb(ctx, terms, orig, discard_known_zeros) |
| | ctx.prec += extraprec |
| | if perturb: |
| | if "hmag" in kwargs: |
| | hmag = kwargs["hmag"] |
| | elif ctx._fixed_precision: |
| | hmag = int(ctx.prec*0.3) |
| | else: |
| | hmag = orig + 10 + hextra |
| | h = ctx.ldexp(ctx.one, -hmag) |
| | ctx.prec = orig2 + 10 + hmag + 10 |
| | for k in range(len(params)): |
| | params[k] += h |
| | |
| | |
| | |
| | |
| | h += h/(k+1) |
| | if recompute: |
| | terms = function(*params) |
| | if discard_known_zeros: |
| | terms = [term for (i, term) in enumerate(terms) if i not in discard] |
| | if not terms: |
| | return ctx.zero |
| | evaluated_terms = [] |
| | for term_index, term_data in enumerate(terms): |
| | w_s, c_s, alpha_s, beta_s, a_s, b_s, z = term_data |
| | if verbose: |
| | print() |
| | print(" Evaluating term %i/%i : %iF%i" % \ |
| | (term_index+1, len(terms), len(a_s), len(b_s))) |
| | print(" powers", ctx.nstr(w_s), ctx.nstr(c_s)) |
| | print(" gamma", ctx.nstr(alpha_s), ctx.nstr(beta_s)) |
| | print(" hyper", ctx.nstr(a_s), ctx.nstr(b_s)) |
| | print(" z", ctx.nstr(z)) |
| | |
| | |
| | |
| | |
| | v = ctx.fprod([ctx.hyper(a_s, b_s, z, **kwargs)] + \ |
| | [ctx.gamma(a) for a in alpha_s] + \ |
| | [ctx.rgamma(b) for b in beta_s] + \ |
| | [ctx.power(w,c) for (w,c) in zip(w_s,c_s)]) |
| | if verbose: |
| | print(" Value:", v) |
| | evaluated_terms.append(v) |
| |
|
| | if len(terms) == 1 and (not perturb): |
| | sumvalue = evaluated_terms[0] |
| | break |
| |
|
| | if ctx._fixed_precision: |
| | sumvalue = ctx.fsum(evaluated_terms) |
| | break |
| |
|
| | sumvalue = ctx.fsum(evaluated_terms) |
| | term_magnitudes = [ctx.mag(x) for x in evaluated_terms] |
| | max_magnitude = max(term_magnitudes) |
| | sum_magnitude = ctx.mag(sumvalue) |
| | cancellation = max_magnitude - sum_magnitude |
| | if verbose: |
| | print() |
| | print(" Cancellation:", cancellation, "bits") |
| | print(" Increased precision:", ctx.prec - orig, "bits") |
| |
|
| | precision_ok = cancellation < ctx.prec - orig |
| |
|
| | if zeroprec is None: |
| | zero_ok = False |
| | else: |
| | zero_ok = max_magnitude - ctx.prec < -zeroprec |
| | if infprec is None: |
| | inf_ok = False |
| | else: |
| | inf_ok = max_magnitude > infprec |
| |
|
| | if precision_ok and (not perturb) or ctx.isnan(cancellation): |
| | break |
| | elif precision_ok: |
| | if perturbed_reference_value is None: |
| | hextra += 20 |
| | perturbed_reference_value = sumvalue |
| | continue |
| | elif ctx.mag(sumvalue - perturbed_reference_value) <= \ |
| | ctx.mag(sumvalue) - orig: |
| | break |
| | elif zero_ok: |
| | sumvalue = ctx.zero |
| | break |
| | elif inf_ok: |
| | sumvalue = ctx.inf |
| | break |
| | elif 'hmag' in kwargs: |
| | break |
| | else: |
| | hextra *= 2 |
| | perturbed_reference_value = sumvalue |
| | |
| | else: |
| | increment = min(max(cancellation, orig//2), max(extraprec,orig)) |
| | ctx.prec += increment |
| | if verbose: |
| | print(" Must start over with increased precision") |
| | continue |
| | finally: |
| | ctx.prec = orig |
| | return +sumvalue |
| |
|
| | @defun |
| | def hyper(ctx, a_s, b_s, z, **kwargs): |
| | """ |
| | Hypergeometric function, general case. |
| | """ |
| | z = ctx.convert(z) |
| | p = len(a_s) |
| | q = len(b_s) |
| | a_s = [ctx._convert_param(a) for a in a_s] |
| | b_s = [ctx._convert_param(b) for b in b_s] |
| | |
| | if kwargs.get('eliminate', True): |
| | elim_nonpositive = kwargs.get('eliminate_all', False) |
| | i = 0 |
| | while i < q and a_s: |
| | b = b_s[i] |
| | if b in a_s and (elim_nonpositive or not ctx.isnpint(b[0])): |
| | a_s.remove(b) |
| | b_s.remove(b) |
| | p -= 1 |
| | q -= 1 |
| | else: |
| | i += 1 |
| | |
| | if p == 0: |
| | if q == 1: return ctx._hyp0f1(b_s, z, **kwargs) |
| | elif q == 0: return ctx.exp(z) |
| | elif p == 1: |
| | if q == 1: return ctx._hyp1f1(a_s, b_s, z, **kwargs) |
| | elif q == 2: return ctx._hyp1f2(a_s, b_s, z, **kwargs) |
| | elif q == 0: return ctx._hyp1f0(a_s[0][0], z) |
| | elif p == 2: |
| | if q == 1: return ctx._hyp2f1(a_s, b_s, z, **kwargs) |
| | elif q == 2: return ctx._hyp2f2(a_s, b_s, z, **kwargs) |
| | elif q == 3: return ctx._hyp2f3(a_s, b_s, z, **kwargs) |
| | elif q == 0: return ctx._hyp2f0(a_s, b_s, z, **kwargs) |
| | elif p == q+1: |
| | return ctx._hypq1fq(p, q, a_s, b_s, z, **kwargs) |
| | elif p > q+1 and not kwargs.get('force_series'): |
| | return ctx._hyp_borel(p, q, a_s, b_s, z, **kwargs) |
| | coeffs, types = zip(*(a_s+b_s)) |
| | return ctx.hypsum(p, q, types, coeffs, z, **kwargs) |
| |
|
| | @defun |
| | def hyp0f1(ctx,b,z,**kwargs): |
| | return ctx.hyper([],[b],z,**kwargs) |
| |
|
| | @defun |
| | def hyp1f1(ctx,a,b,z,**kwargs): |
| | return ctx.hyper([a],[b],z,**kwargs) |
| |
|
| | @defun |
| | def hyp1f2(ctx,a1,b1,b2,z,**kwargs): |
| | return ctx.hyper([a1],[b1,b2],z,**kwargs) |
| |
|
| | @defun |
| | def hyp2f1(ctx,a,b,c,z,**kwargs): |
| | return ctx.hyper([a,b],[c],z,**kwargs) |
| |
|
| | @defun |
| | def hyp2f2(ctx,a1,a2,b1,b2,z,**kwargs): |
| | return ctx.hyper([a1,a2],[b1,b2],z,**kwargs) |
| |
|
| | @defun |
| | def hyp2f3(ctx,a1,a2,b1,b2,b3,z,**kwargs): |
| | return ctx.hyper([a1,a2],[b1,b2,b3],z,**kwargs) |
| |
|
| | @defun |
| | def hyp2f0(ctx,a,b,z,**kwargs): |
| | return ctx.hyper([a,b],[],z,**kwargs) |
| |
|
| | @defun |
| | def hyp3f2(ctx,a1,a2,a3,b1,b2,z,**kwargs): |
| | return ctx.hyper([a1,a2,a3],[b1,b2],z,**kwargs) |
| |
|
| | @defun_wrapped |
| | def _hyp1f0(ctx, a, z): |
| | return (1-z) ** (-a) |
| |
|
| | @defun |
| | def _hyp0f1(ctx, b_s, z, **kwargs): |
| | (b, btype), = b_s |
| | if z: |
| | magz = ctx.mag(z) |
| | else: |
| | magz = 0 |
| | if magz >= 8 and not kwargs.get('force_series'): |
| | try: |
| | |
| | |
| | |
| | |
| | orig = ctx.prec |
| | try: |
| | ctx.prec += 12 + magz//2 |
| | def h(): |
| | w = ctx.sqrt(-z) |
| | jw = ctx.j*w |
| | u = 1/(4*jw) |
| | c = ctx.mpq_1_2 - b |
| | E = ctx.exp(2*jw) |
| | T1 = ([-jw,E], [c,-1], [], [], [b-ctx.mpq_1_2, ctx.mpq_3_2-b], [], -u) |
| | T2 = ([jw,E], [c,1], [], [], [b-ctx.mpq_1_2, ctx.mpq_3_2-b], [], u) |
| | return T1, T2 |
| | v = ctx.hypercomb(h, [], force_series=True) |
| | v = ctx.gamma(b)/(2*ctx.sqrt(ctx.pi))*v |
| | finally: |
| | ctx.prec = orig |
| | if ctx._is_real_type(b) and ctx._is_real_type(z): |
| | v = ctx._re(v) |
| | return +v |
| | except ctx.NoConvergence: |
| | pass |
| | return ctx.hypsum(0, 1, (btype,), [b], z, **kwargs) |
| |
|
| | @defun |
| | def _hyp1f1(ctx, a_s, b_s, z, **kwargs): |
| | (a, atype), = a_s |
| | (b, btype), = b_s |
| | if not z: |
| | return ctx.one+z |
| | magz = ctx.mag(z) |
| | if magz >= 7 and not (ctx.isint(a) and ctx.re(a) <= 0): |
| | if ctx.isinf(z): |
| | if ctx.sign(a) == ctx.sign(b) == ctx.sign(z) == 1: |
| | return ctx.inf |
| | return ctx.nan * z |
| | try: |
| | try: |
| | ctx.prec += magz |
| | sector = ctx._im(z) < 0 |
| | def h(a,b): |
| | if sector: |
| | E = ctx.expjpi(ctx.fneg(a, exact=True)) |
| | else: |
| | E = ctx.expjpi(a) |
| | rz = 1/z |
| | T1 = ([E,z], [1,-a], [b], [b-a], [a, 1+a-b], [], -rz) |
| | T2 = ([ctx.exp(z),z], [1,a-b], [b], [a], [b-a, 1-a], [], rz) |
| | return T1, T2 |
| | v = ctx.hypercomb(h, [a,b], force_series=True) |
| | if ctx._is_real_type(a) and ctx._is_real_type(b) and ctx._is_real_type(z): |
| | v = ctx._re(v) |
| | return +v |
| | except ctx.NoConvergence: |
| | pass |
| | finally: |
| | ctx.prec -= magz |
| | v = ctx.hypsum(1, 1, (atype, btype), [a, b], z, **kwargs) |
| | return v |
| |
|
| | def _hyp2f1_gosper(ctx,a,b,c,z,**kwargs): |
| | |
| | |
| | _a,_b,_c,_z = a, b, c, z |
| | orig = ctx.prec |
| | maxprec = kwargs.get('maxprec', 100*orig) |
| | extra = 10 |
| | while 1: |
| | ctx.prec = orig + extra |
| | |
| | |
| | |
| | z = ctx.convert(_z) |
| | d = ctx.mpf(0) |
| | e = ctx.mpf(1) |
| | f = ctx.mpf(0) |
| | k = 0 |
| | |
| | |
| | |
| | abz = a*b*z |
| | ch = c * ctx.mpq_1_2 |
| | c1h = (c+1) * ctx.mpq_1_2 |
| | nz = 1-z |
| | g = z/nz |
| | abg = a*b*g |
| | cba = c-b-a |
| | z2 = z-2 |
| | tol = -ctx.prec - 10 |
| | nstr = ctx.nstr |
| | nprint = ctx.nprint |
| | mag = ctx.mag |
| | maxmag = ctx.ninf |
| | while 1: |
| | kch = k+ch |
| | kakbz = (k+a)*(k+b)*z / (4*(k+1)*kch*(k+c1h)) |
| | d1 = kakbz*(e-(k+cba)*d*g) |
| | e1 = kakbz*(d*abg+(k+c)*e) |
| | ft = d*(k*(cba*z+k*z2-c)-abz)/(2*kch*nz) |
| | f1 = f + e - ft |
| | maxmag = max(maxmag, mag(f1)) |
| | if mag(f1-f) < tol: |
| | break |
| | d, e, f = d1, e1, f1 |
| | k += 1 |
| | cancellation = maxmag - mag(f1) |
| | if cancellation < extra: |
| | break |
| | else: |
| | extra += cancellation |
| | if extra > maxprec: |
| | raise ctx.NoConvergence |
| | return f1 |
| |
|
| | @defun |
| | def _hyp2f1(ctx, a_s, b_s, z, **kwargs): |
| | (a, atype), (b, btype) = a_s |
| | (c, ctype), = b_s |
| | if z == 1: |
| | |
| | convergent = ctx.re(c-a-b) > 0 |
| | finite = (ctx.isint(a) and a <= 0) or (ctx.isint(b) and b <= 0) |
| | zerodiv = ctx.isint(c) and c <= 0 and not \ |
| | ((ctx.isint(a) and c <= a <= 0) or (ctx.isint(b) and c <= b <= 0)) |
| | |
| | |
| | if (convergent or finite) and not zerodiv: |
| | return ctx.gammaprod([c, c-a-b], [c-a, c-b], _infsign=True) |
| | |
| | |
| | |
| | return ctx.hyp2f1(a,b,c,1-ctx.eps*2) * ctx.inf |
| |
|
| | |
| | |
| | if not z: |
| | |
| | |
| | if c or a == 0 or b == 0: |
| | return 1+z |
| | |
| | return ctx.nan |
| |
|
| | |
| | if ctx.isint(c) and c <= 0: |
| | if (ctx.isint(a) and c <= a <= 0) or \ |
| | (ctx.isint(b) and c <= b <= 0): |
| | pass |
| | else: |
| | |
| | return ctx.inf |
| |
|
| | absz = abs(z) |
| |
|
| | |
| | |
| | if absz <= 0.8 or (ctx.isint(a) and a <= 0 and a >= -1000) or \ |
| | (ctx.isint(b) and b <= 0 and b >= -1000): |
| | return ctx.hypsum(2, 1, (atype, btype, ctype), [a, b, c], z, **kwargs) |
| |
|
| | orig = ctx.prec |
| | try: |
| | ctx.prec += 10 |
| |
|
| | |
| | if absz >= 1.3: |
| | def h(a,b): |
| | t = ctx.mpq_1-c; ab = a-b; rz = 1/z |
| | T1 = ([-z],[-a], [c,-ab],[b,c-a], [a,t+a],[ctx.mpq_1+ab], rz) |
| | T2 = ([-z],[-b], [c,ab],[a,c-b], [b,t+b],[ctx.mpq_1-ab], rz) |
| | return T1, T2 |
| | v = ctx.hypercomb(h, [a,b], **kwargs) |
| |
|
| | |
| | elif abs(1-z) <= 0.75: |
| | def h(a,b): |
| | t = c-a-b; ca = c-a; cb = c-b; rz = 1-z |
| | T1 = [], [], [c,t], [ca,cb], [a,b], [1-t], rz |
| | T2 = [rz], [t], [c,a+b-c], [a,b], [ca,cb], [1+t], rz |
| | return T1, T2 |
| | v = ctx.hypercomb(h, [a,b], **kwargs) |
| |
|
| | |
| | elif abs(z/(z-1)) <= 0.75: |
| | v = ctx.hyp2f1(a, c-b, c, z/(z-1)) / (1-z)**a |
| |
|
| | |
| | else: |
| | v = _hyp2f1_gosper(ctx,a,b,c,z,**kwargs) |
| |
|
| | finally: |
| | ctx.prec = orig |
| | return +v |
| |
|
| | @defun |
| | def _hypq1fq(ctx, p, q, a_s, b_s, z, **kwargs): |
| | r""" |
| | Evaluates 3F2, 4F3, 5F4, ... |
| | """ |
| | a_s, a_types = zip(*a_s) |
| | b_s, b_types = zip(*b_s) |
| | a_s = list(a_s) |
| | b_s = list(b_s) |
| | absz = abs(z) |
| | ispoly = False |
| | for a in a_s: |
| | if ctx.isint(a) and a <= 0: |
| | ispoly = True |
| | break |
| | |
| | if absz < 1 or ispoly: |
| | try: |
| | return ctx.hypsum(p, q, a_types+b_types, a_s+b_s, z, **kwargs) |
| | except ctx.NoConvergence: |
| | if absz > 1.1 or ispoly: |
| | raise |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if z == 1: |
| | |
| | |
| | S = ctx.re(sum(b_s)-sum(a_s)) |
| | if S <= 0: |
| | |
| | return ctx.hyper(a_s, b_s, 0.9, **kwargs) * ctx.inf |
| | if (p,q) == (3,2) and abs(z-1) < 0.05: |
| | |
| | a1,a2,a3 = a_s |
| | b1,b2 = b_s |
| | u = b1+b2-a3 |
| | initial = ctx.gammaprod([b2-a3,b1-a3,a1,a2],[b2-a3,b1-a3,1,u]) |
| | def term(k, _cache={0:initial}): |
| | u = b1+b2-a3+k |
| | if k in _cache: |
| | t = _cache[k] |
| | else: |
| | t = _cache[k-1] |
| | t *= (b1+k-a3-1)*(b2+k-a3-1) |
| | t /= k*(u-1) |
| | _cache[k] = t |
| | return t * ctx.hyp2f1(a1,a2,u,z) |
| | try: |
| | S = ctx.nsum(term, [0,ctx.inf], verbose=kwargs.get('verbose'), |
| | strict=kwargs.get('strict', True)) |
| | return S * ctx.gammaprod([b1,b2],[a1,a2,a3]) |
| | except ctx.NoConvergence: |
| | pass |
| | |
| | |
| | |
| | |
| | if absz < 1.1 and ctx._re(z) <= 1: |
| |
|
| | def term(kk, _cache={0:ctx.one}): |
| | k = int(kk) |
| | if k != kk: |
| | t = z ** ctx.mpf(kk) / ctx.fac(kk) |
| | for a in a_s: t *= ctx.rf(a,kk) |
| | for b in b_s: t /= ctx.rf(b,kk) |
| | return t |
| | if k in _cache: |
| | return _cache[k] |
| | t = term(k-1) |
| | m = k-1 |
| | for j in xrange(p): t *= (a_s[j]+m) |
| | for j in xrange(q): t /= (b_s[j]+m) |
| | t *= z |
| | t /= k |
| | _cache[k] = t |
| | return t |
| |
|
| | sum_method = kwargs.get('sum_method', 'r+s+e') |
| |
|
| | try: |
| | return ctx.nsum(term, [0,ctx.inf], verbose=kwargs.get('verbose'), |
| | strict=kwargs.get('strict', True), |
| | method=sum_method.replace('e','')) |
| | except ctx.NoConvergence: |
| | if 'e' not in sum_method: |
| | raise |
| | pass |
| |
|
| | if kwargs.get('verbose'): |
| | print("Attempting Euler-Maclaurin summation") |
| |
|
| |
|
| | """ |
| | Somewhat slower version (one diffs_exp for each factor). |
| | However, this would be faster with fast direct derivatives |
| | of the gamma function. |
| | |
| | def power_diffs(k0): |
| | r = 0 |
| | l = ctx.log(z) |
| | while 1: |
| | yield z**ctx.mpf(k0) * l**r |
| | r += 1 |
| | |
| | def loggamma_diffs(x, reciprocal=False): |
| | sign = (-1) ** reciprocal |
| | yield sign * ctx.loggamma(x) |
| | i = 0 |
| | while 1: |
| | yield sign * ctx.psi(i,x) |
| | i += 1 |
| | |
| | def hyper_diffs(k0): |
| | b2 = b_s + [1] |
| | A = [ctx.diffs_exp(loggamma_diffs(a+k0)) for a in a_s] |
| | B = [ctx.diffs_exp(loggamma_diffs(b+k0,True)) for b in b2] |
| | Z = [power_diffs(k0)] |
| | C = ctx.gammaprod([b for b in b2], [a for a in a_s]) |
| | for d in ctx.diffs_prod(A + B + Z): |
| | v = C * d |
| | yield v |
| | """ |
| |
|
| | def log_diffs(k0): |
| | b2 = b_s + [1] |
| | yield sum(ctx.loggamma(a+k0) for a in a_s) - \ |
| | sum(ctx.loggamma(b+k0) for b in b2) + k0*ctx.log(z) |
| | i = 0 |
| | while 1: |
| | v = sum(ctx.psi(i,a+k0) for a in a_s) - \ |
| | sum(ctx.psi(i,b+k0) for b in b2) |
| | if i == 0: |
| | v += ctx.log(z) |
| | yield v |
| | i += 1 |
| |
|
| | def hyper_diffs(k0): |
| | C = ctx.gammaprod([b for b in b_s], [a for a in a_s]) |
| | for d in ctx.diffs_exp(log_diffs(k0)): |
| | v = C * d |
| | yield v |
| |
|
| | tol = ctx.eps / 1024 |
| | prec = ctx.prec |
| | try: |
| | trunc = 50 * ctx.dps |
| | ctx.prec += 20 |
| | for i in xrange(5): |
| | head = ctx.fsum(term(k) for k in xrange(trunc)) |
| | tail, err = ctx.sumem(term, [trunc, ctx.inf], tol=tol, |
| | adiffs=hyper_diffs(trunc), |
| | verbose=kwargs.get('verbose'), |
| | error=True, |
| | _fast_abort=True) |
| | if err < tol: |
| | v = head + tail |
| | break |
| | trunc *= 2 |
| | |
| | |
| | ctx.prec += ctx.prec//2 |
| | if i == 4: |
| | raise ctx.NoConvergence(\ |
| | "Euler-Maclaurin summation did not converge") |
| | finally: |
| | ctx.prec = prec |
| | return +v |
| |
|
| | |
| | |
| | |
| | def h(*args): |
| | a_s = list(args[:p]) |
| | b_s = list(args[p:]) |
| | Ts = [] |
| | recz = ctx.one/z |
| | negz = ctx.fneg(z, exact=True) |
| | for k in range(q+1): |
| | ak = a_s[k] |
| | C = [negz] |
| | Cp = [-ak] |
| | Gn = b_s + [ak] + [a_s[j]-ak for j in range(q+1) if j != k] |
| | Gd = a_s + [b_s[j]-ak for j in range(q)] |
| | Fn = [ak] + [ak-b_s[j]+1 for j in range(q)] |
| | Fd = [1-a_s[j]+ak for j in range(q+1) if j != k] |
| | Ts.append((C, Cp, Gn, Gd, Fn, Fd, recz)) |
| | return Ts |
| | return ctx.hypercomb(h, a_s+b_s, **kwargs) |
| |
|
| | @defun |
| | def _hyp_borel(ctx, p, q, a_s, b_s, z, **kwargs): |
| | if a_s: |
| | a_s, a_types = zip(*a_s) |
| | a_s = list(a_s) |
| | else: |
| | a_s, a_types = [], () |
| | if b_s: |
| | b_s, b_types = zip(*b_s) |
| | b_s = list(b_s) |
| | else: |
| | b_s, b_types = [], () |
| | kwargs['maxterms'] = kwargs.get('maxterms', ctx.prec) |
| | try: |
| | return ctx.hypsum(p, q, a_types+b_types, a_s+b_s, z, **kwargs) |
| | except ctx.NoConvergence: |
| | pass |
| | prec = ctx.prec |
| | try: |
| | tol = kwargs.get('asymp_tol', ctx.eps/4) |
| | ctx.prec += 10 |
| | |
| | def term(k, cache={0:ctx.one}): |
| | if k in cache: |
| | return cache[k] |
| | t = term(k-1) |
| | for a in a_s: t *= (a+(k-1)) |
| | for b in b_s: t /= (b+(k-1)) |
| | t *= z |
| | t /= k |
| | cache[k] = t |
| | return t |
| | s = ctx.one |
| | for k in xrange(1, ctx.prec): |
| | t = term(k) |
| | s += t |
| | if abs(t) <= tol: |
| | return s |
| | finally: |
| | ctx.prec = prec |
| | if p <= q+3: |
| | contour = kwargs.get('contour') |
| | if not contour: |
| | if ctx.arg(z) < 0.25: |
| | u = z / max(1, abs(z)) |
| | if ctx.arg(z) >= 0: |
| | contour = [0, 2j, (2j+2)/u, 2/u, ctx.inf] |
| | else: |
| | contour = [0, -2j, (-2j+2)/u, 2/u, ctx.inf] |
| | |
| | |
| | |
| | else: |
| | contour = [0, ctx.inf] |
| | quad_kwargs = kwargs.get('quad_kwargs', {}) |
| | def g(t): |
| | return ctx.exp(-t)*ctx.hyper(a_s, b_s+[1], t*z) |
| | I, err = ctx.quad(g, contour, error=True, **quad_kwargs) |
| | if err <= abs(I)*ctx.eps*8: |
| | return I |
| | raise ctx.NoConvergence |
| |
|
| |
|
| | @defun |
| | def _hyp2f2(ctx, a_s, b_s, z, **kwargs): |
| | (a1, a1type), (a2, a2type) = a_s |
| | (b1, b1type), (b2, b2type) = b_s |
| |
|
| | absz = abs(z) |
| | magz = ctx.mag(z) |
| | orig = ctx.prec |
| |
|
| | |
| | asymp_extraprec = magz |
| |
|
| | |
| | can_use_asymptotic = (not kwargs.get('force_series')) and \ |
| | (ctx.mag(absz) > 3) |
| |
|
| | |
| | |
| | if can_use_asymptotic: |
| | |
| | try: |
| | try: |
| | ctx.prec += asymp_extraprec |
| | |
| | |
| | def h(a1,a2,b1,b2): |
| | X = a1+a2-b1-b2 |
| | A2 = a1+a2 |
| | B2 = b1+b2 |
| | c = {} |
| | c[0] = ctx.one |
| | c[1] = (A2-1)*X+b1*b2-a1*a2 |
| | s1 = 0 |
| | k = 0 |
| | tprev = 0 |
| | while 1: |
| | if k not in c: |
| | uu1 = 1-B2+2*a1+a1**2+2*a2+a2**2-A2*B2+a1*a2+b1*b2+(2*B2-3*(A2+1))*k+2*k**2 |
| | uu2 = (k-A2+b1-1)*(k-A2+b2-1)*(k-X-2) |
| | c[k] = ctx.one/k * (uu1*c[k-1]-uu2*c[k-2]) |
| | t1 = c[k] * z**(-k) |
| | if abs(t1) < 0.1*ctx.eps: |
| | |
| | break |
| | |
| | if k > 5 and abs(tprev) / abs(t1) < 1.5: |
| | |
| | raise ctx.NoConvergence |
| | s1 += t1 |
| | tprev = t1 |
| | k += 1 |
| | S = ctx.exp(z)*s1 |
| | T1 = [z,S], [X,1], [b1,b2],[a1,a2],[],[],0 |
| | T2 = [-z],[-a1],[b1,b2,a2-a1],[a2,b1-a1,b2-a1],[a1,a1-b1+1,a1-b2+1],[a1-a2+1],-1/z |
| | T3 = [-z],[-a2],[b1,b2,a1-a2],[a1,b1-a2,b2-a2],[a2,a2-b1+1,a2-b2+1],[-a1+a2+1],-1/z |
| | return T1, T2, T3 |
| | v = ctx.hypercomb(h, [a1,a2,b1,b2], force_series=True, maxterms=4*ctx.prec) |
| | if sum(ctx._is_real_type(u) for u in [a1,a2,b1,b2,z]) == 5: |
| | v = ctx.re(v) |
| | return v |
| | except ctx.NoConvergence: |
| | pass |
| | finally: |
| | ctx.prec = orig |
| |
|
| | return ctx.hypsum(2, 2, (a1type, a2type, b1type, b2type), [a1, a2, b1, b2], z, **kwargs) |
| |
|
| |
|
| |
|
| | @defun |
| | def _hyp1f2(ctx, a_s, b_s, z, **kwargs): |
| | (a1, a1type), = a_s |
| | (b1, b1type), (b2, b2type) = b_s |
| |
|
| | absz = abs(z) |
| | magz = ctx.mag(z) |
| | orig = ctx.prec |
| |
|
| | |
| | asymp_extraprec = z and magz//2 |
| |
|
| | |
| | can_use_asymptotic = (not kwargs.get('force_series')) and \ |
| | (ctx.mag(absz) > 19) and \ |
| | (ctx.sqrt(absz) > 1.5*orig) |
| | |
| | |
| |
|
| | |
| | |
| | if can_use_asymptotic: |
| | |
| | try: |
| | try: |
| | ctx.prec += asymp_extraprec |
| | |
| | |
| | def h(a1,b1,b2): |
| | X = ctx.mpq_1_2*(a1-b1-b2+ctx.mpq_1_2) |
| | c = {} |
| | c[0] = ctx.one |
| | c[1] = 2*(ctx.mpq_1_4*(3*a1+b1+b2-2)*(a1-b1-b2)+b1*b2-ctx.mpq_3_16) |
| | c[2] = 2*(b1*b2+ctx.mpq_1_4*(a1-b1-b2)*(3*a1+b1+b2-2)-ctx.mpq_3_16)**2+\ |
| | ctx.mpq_1_16*(-16*(2*a1-3)*b1*b2 + \ |
| | 4*(a1-b1-b2)*(-8*a1**2+11*a1+b1+b2-2)-3) |
| | s1 = 0 |
| | s2 = 0 |
| | k = 0 |
| | tprev = 0 |
| | while 1: |
| | if k not in c: |
| | uu1 = (3*k**2+(-6*a1+2*b1+2*b2-4)*k + 3*a1**2 - \ |
| | (b1-b2)**2 - 2*a1*(b1+b2-2) + ctx.mpq_1_4) |
| | uu2 = (k-a1+b1-b2-ctx.mpq_1_2)*(k-a1-b1+b2-ctx.mpq_1_2)*\ |
| | (k-a1+b1+b2-ctx.mpq_5_2) |
| | c[k] = ctx.one/(2*k)*(uu1*c[k-1]-uu2*c[k-2]) |
| | w = c[k] * (-z)**(-0.5*k) |
| | t1 = (-ctx.j)**k * ctx.mpf(2)**(-k) * w |
| | t2 = ctx.j**k * ctx.mpf(2)**(-k) * w |
| | if abs(t1) < 0.1*ctx.eps: |
| | |
| | break |
| | |
| | if k > 5 and abs(tprev) / abs(t1) < 1.5: |
| | |
| | raise ctx.NoConvergence |
| | s1 += t1 |
| | s2 += t2 |
| | tprev = t1 |
| | k += 1 |
| | S = ctx.expj(ctx.pi*X+2*ctx.sqrt(-z))*s1 + \ |
| | ctx.expj(-(ctx.pi*X+2*ctx.sqrt(-z)))*s2 |
| | T1 = [0.5*S, ctx.pi, -z], [1, -0.5, X], [b1, b2], [a1],\ |
| | [], [], 0 |
| | T2 = [-z], [-a1], [b1,b2],[b1-a1,b2-a1], \ |
| | [a1,a1-b1+1,a1-b2+1], [], 1/z |
| | return T1, T2 |
| | v = ctx.hypercomb(h, [a1,b1,b2], force_series=True, maxterms=4*ctx.prec) |
| | if sum(ctx._is_real_type(u) for u in [a1,b1,b2,z]) == 4: |
| | v = ctx.re(v) |
| | return v |
| | except ctx.NoConvergence: |
| | pass |
| | finally: |
| | ctx.prec = orig |
| |
|
| | |
| | return ctx.hypsum(1, 2, (a1type, b1type, b2type), [a1, b1, b2], z, **kwargs) |
| |
|
| |
|
| |
|
| | @defun |
| | def _hyp2f3(ctx, a_s, b_s, z, **kwargs): |
| | (a1, a1type), (a2, a2type) = a_s |
| | (b1, b1type), (b2, b2type), (b3, b3type) = b_s |
| |
|
| | absz = abs(z) |
| | magz = ctx.mag(z) |
| |
|
| | |
| | asymp_extraprec = z and magz//2 |
| | orig = ctx.prec |
| |
|
| | |
| | |
| | |
| | can_use_asymptotic = (not kwargs.get('force_series')) and \ |
| | (ctx.mag(absz) > 19) and (ctx.sqrt(absz) > 1.5*orig) |
| |
|
| | if can_use_asymptotic: |
| | |
| | try: |
| | try: |
| | ctx.prec += asymp_extraprec |
| | |
| | |
| | def h(a1,a2,b1,b2,b3): |
| | X = ctx.mpq_1_2*(a1+a2-b1-b2-b3+ctx.mpq_1_2) |
| | A2 = a1+a2 |
| | B3 = b1+b2+b3 |
| | A = a1*a2 |
| | B = b1*b2+b3*b2+b1*b3 |
| | R = b1*b2*b3 |
| | c = {} |
| | c[0] = ctx.one |
| | c[1] = 2*(B - A + ctx.mpq_1_4*(3*A2+B3-2)*(A2-B3) - ctx.mpq_3_16) |
| | c[2] = ctx.mpq_1_2*c[1]**2 + ctx.mpq_1_16*(-16*(2*A2-3)*(B-A) + 32*R +\ |
| | 4*(-8*A2**2 + 11*A2 + 8*A + B3 - 2)*(A2-B3)-3) |
| | s1 = 0 |
| | s2 = 0 |
| | k = 0 |
| | tprev = 0 |
| | while 1: |
| | if k not in c: |
| | uu1 = (k-2*X-3)*(k-2*X-2*b1-1)*(k-2*X-2*b2-1)*\ |
| | (k-2*X-2*b3-1) |
| | uu2 = (4*(k-1)**3 - 6*(4*X+B3)*(k-1)**2 + \ |
| | 2*(24*X**2+12*B3*X+4*B+B3-1)*(k-1) - 32*X**3 - \ |
| | 24*B3*X**2 - 4*B - 8*R - 4*(4*B+B3-1)*X + 2*B3-1) |
| | uu3 = (5*(k-1)**2+2*(-10*X+A2-3*B3+3)*(k-1)+2*c[1]) |
| | c[k] = ctx.one/(2*k)*(uu1*c[k-3]-uu2*c[k-2]+uu3*c[k-1]) |
| | w = c[k] * ctx.power(-z, -0.5*k) |
| | t1 = (-ctx.j)**k * ctx.mpf(2)**(-k) * w |
| | t2 = ctx.j**k * ctx.mpf(2)**(-k) * w |
| | if abs(t1) < 0.1*ctx.eps: |
| | break |
| | |
| | if k > 5 and abs(tprev) / abs(t1) < 1.5: |
| | raise ctx.NoConvergence |
| | s1 += t1 |
| | s2 += t2 |
| | tprev = t1 |
| | k += 1 |
| | S = ctx.expj(ctx.pi*X+2*ctx.sqrt(-z))*s1 + \ |
| | ctx.expj(-(ctx.pi*X+2*ctx.sqrt(-z)))*s2 |
| | T1 = [0.5*S, ctx.pi, -z], [1, -0.5, X], [b1, b2, b3], [a1, a2],\ |
| | [], [], 0 |
| | T2 = [-z], [-a1], [b1,b2,b3,a2-a1],[a2,b1-a1,b2-a1,b3-a1], \ |
| | [a1,a1-b1+1,a1-b2+1,a1-b3+1], [a1-a2+1], 1/z |
| | T3 = [-z], [-a2], [b1,b2,b3,a1-a2],[a1,b1-a2,b2-a2,b3-a2], \ |
| | [a2,a2-b1+1,a2-b2+1,a2-b3+1],[-a1+a2+1], 1/z |
| | return T1, T2, T3 |
| | v = ctx.hypercomb(h, [a1,a2,b1,b2,b3], force_series=True, maxterms=4*ctx.prec) |
| | if sum(ctx._is_real_type(u) for u in [a1,a2,b1,b2,b3,z]) == 6: |
| | v = ctx.re(v) |
| | return v |
| | except ctx.NoConvergence: |
| | pass |
| | finally: |
| | ctx.prec = orig |
| |
|
| | return ctx.hypsum(2, 3, (a1type, a2type, b1type, b2type, b3type), [a1, a2, b1, b2, b3], z, **kwargs) |
| |
|
| | @defun |
| | def _hyp2f0(ctx, a_s, b_s, z, **kwargs): |
| | (a, atype), (b, btype) = a_s |
| | |
| | |
| | try: |
| | kwargsb = kwargs.copy() |
| | kwargsb['maxterms'] = kwargsb.get('maxterms', ctx.prec) |
| | return ctx.hypsum(2, 0, (atype,btype), [a,b], z, **kwargsb) |
| | except ctx.NoConvergence: |
| | if kwargs.get('force_series'): |
| | raise |
| | pass |
| | def h(a, b): |
| | w = ctx.sinpi(b) |
| | rz = -1/z |
| | T1 = ([ctx.pi,w,rz],[1,-1,a],[],[a-b+1,b],[a],[b],rz) |
| | T2 = ([-ctx.pi,w,rz],[1,-1,1+a-b],[],[a,2-b],[a-b+1],[2-b],rz) |
| | return T1, T2 |
| | return ctx.hypercomb(h, [a, 1+a-b], **kwargs) |
| |
|
| | @defun |
| | def meijerg(ctx, a_s, b_s, z, r=1, series=None, **kwargs): |
| | an, ap = a_s |
| | bm, bq = b_s |
| | n = len(an) |
| | p = n + len(ap) |
| | m = len(bm) |
| | q = m + len(bq) |
| | a = an+ap |
| | b = bm+bq |
| | a = [ctx.convert(_) for _ in a] |
| | b = [ctx.convert(_) for _ in b] |
| | z = ctx.convert(z) |
| | if series is None: |
| | if p < q: series = 1 |
| | if p > q: series = 2 |
| | if p == q: |
| | if m+n == p and abs(z) > 1: |
| | series = 2 |
| | else: |
| | series = 1 |
| | if kwargs.get('verbose'): |
| | print("Meijer G m,n,p,q,series =", m,n,p,q,series) |
| | if series == 1: |
| | def h(*args): |
| | a = args[:p] |
| | b = args[p:] |
| | terms = [] |
| | for k in range(m): |
| | bases = [z] |
| | expts = [b[k]/r] |
| | gn = [b[j]-b[k] for j in range(m) if j != k] |
| | gn += [1-a[j]+b[k] for j in range(n)] |
| | gd = [a[j]-b[k] for j in range(n,p)] |
| | gd += [1-b[j]+b[k] for j in range(m,q)] |
| | hn = [1-a[j]+b[k] for j in range(p)] |
| | hd = [1-b[j]+b[k] for j in range(q) if j != k] |
| | hz = (-ctx.one)**(p-m-n) * z**(ctx.one/r) |
| | terms.append((bases, expts, gn, gd, hn, hd, hz)) |
| | return terms |
| | else: |
| | def h(*args): |
| | a = args[:p] |
| | b = args[p:] |
| | terms = [] |
| | for k in range(n): |
| | bases = [z] |
| | if r == 1: |
| | expts = [a[k]-1] |
| | else: |
| | expts = [(a[k]-1)/ctx.convert(r)] |
| | gn = [a[k]-a[j] for j in range(n) if j != k] |
| | gn += [1-a[k]+b[j] for j in range(m)] |
| | gd = [a[k]-b[j] for j in range(m,q)] |
| | gd += [1-a[k]+a[j] for j in range(n,p)] |
| | hn = [1-a[k]+b[j] for j in range(q)] |
| | hd = [1+a[j]-a[k] for j in range(p) if j != k] |
| | hz = (-ctx.one)**(q-m-n) / z**(ctx.one/r) |
| | terms.append((bases, expts, gn, gd, hn, hd, hz)) |
| | return terms |
| | return ctx.hypercomb(h, a+b, **kwargs) |
| |
|
| | @defun_wrapped |
| | def appellf1(ctx,a,b1,b2,c,x,y,**kwargs): |
| | |
| | |
| | if abs(x) > abs(y): |
| | x, y = y, x |
| | b1, b2 = b2, b1 |
| | def ok(x): |
| | return abs(x) < 0.99 |
| | |
| | if ctx.isnpint(a): |
| | pass |
| | elif ctx.isnpint(b1): |
| | pass |
| | elif ctx.isnpint(b2): |
| | x, y, b1, b2 = y, x, b2, b1 |
| | else: |
| | |
| | |
| | |
| | if not ok(x): |
| | u1 = (x-y)/(x-1) |
| | if not ok(u1): |
| | raise ValueError("Analytic continuation not implemented") |
| | |
| | return (1-x)**(-b1)*(1-y)**(c-a-b2)*\ |
| | ctx.appellf1(c-a,b1,c-b1-b2,c,u1,y,**kwargs) |
| | return ctx.hyper2d({'m+n':[a],'m':[b1],'n':[b2]}, {'m+n':[c]}, x,y, **kwargs) |
| |
|
| | @defun |
| | def appellf2(ctx,a,b1,b2,c1,c2,x,y,**kwargs): |
| | |
| | return ctx.hyper2d({'m+n':[a],'m':[b1],'n':[b2]}, |
| | {'m':[c1],'n':[c2]}, x,y, **kwargs) |
| |
|
| | @defun |
| | def appellf3(ctx,a1,a2,b1,b2,c,x,y,**kwargs): |
| | outer_polynomial = ctx.isnpint(a1) or ctx.isnpint(b1) |
| | inner_polynomial = ctx.isnpint(a2) or ctx.isnpint(b2) |
| | if not outer_polynomial: |
| | if inner_polynomial or abs(x) > abs(y): |
| | x, y = y, x |
| | a1,a2,b1,b2 = a2,a1,b2,b1 |
| | return ctx.hyper2d({'m':[a1,b1],'n':[a2,b2]}, {'m+n':[c]},x,y,**kwargs) |
| |
|
| | @defun |
| | def appellf4(ctx,a,b,c1,c2,x,y,**kwargs): |
| | |
| | return ctx.hyper2d({'m+n':[a,b]}, {'m':[c1],'n':[c2]},x,y,**kwargs) |
| |
|
| | @defun |
| | def hyper2d(ctx, a, b, x, y, **kwargs): |
| | r""" |
| | Sums the generalized 2D hypergeometric series |
| | |
| | .. math :: |
| | |
| | \sum_{m=0}^{\infty} \sum_{n=0}^{\infty} |
| | \frac{P((a),m,n)}{Q((b),m,n)} |
| | \frac{x^m y^n} {m! n!} |
| | |
| | where `(a) = (a_1,\ldots,a_r)`, `(b) = (b_1,\ldots,b_s)` and where |
| | `P` and `Q` are products of rising factorials such as `(a_j)_n` or |
| | `(a_j)_{m+n}`. `P` and `Q` are specified in the form of dicts, with |
| | the `m` and `n` dependence as keys and parameter lists as values. |
| | The supported rising factorials are given in the following table |
| | (note that only a few are supported in `Q`): |
| | |
| | +------------+-------------------+--------+ |
| | | Key | Rising factorial | `Q` | |
| | +============+===================+========+ |
| | | ``'m'`` | `(a_j)_m` | Yes | |
| | +------------+-------------------+--------+ |
| | | ``'n'`` | `(a_j)_n` | Yes | |
| | +------------+-------------------+--------+ |
| | | ``'m+n'`` | `(a_j)_{m+n}` | Yes | |
| | +------------+-------------------+--------+ |
| | | ``'m-n'`` | `(a_j)_{m-n}` | No | |
| | +------------+-------------------+--------+ |
| | | ``'n-m'`` | `(a_j)_{n-m}` | No | |
| | +------------+-------------------+--------+ |
| | | ``'2m+n'`` | `(a_j)_{2m+n}` | No | |
| | +------------+-------------------+--------+ |
| | | ``'2m-n'`` | `(a_j)_{2m-n}` | No | |
| | +------------+-------------------+--------+ |
| | | ``'2n-m'`` | `(a_j)_{2n-m}` | No | |
| | +------------+-------------------+--------+ |
| | |
| | For example, the Appell F1 and F4 functions |
| | |
| | .. math :: |
| | |
| | F_1 = \sum_{m=0}^{\infty} \sum_{n=0}^{\infty} |
| | \frac{(a)_{m+n} (b)_m (c)_n}{(d)_{m+n}} |
| | \frac{x^m y^n}{m! n!} |
| | |
| | F_4 = \sum_{m=0}^{\infty} \sum_{n=0}^{\infty} |
| | \frac{(a)_{m+n} (b)_{m+n}}{(c)_m (d)_{n}} |
| | \frac{x^m y^n}{m! n!} |
| | |
| | can be represented respectively as |
| | |
| | ``hyper2d({'m+n':[a], 'm':[b], 'n':[c]}, {'m+n':[d]}, x, y)`` |
| | |
| | ``hyper2d({'m+n':[a,b]}, {'m':[c], 'n':[d]}, x, y)`` |
| | |
| | More generally, :func:`~mpmath.hyper2d` can evaluate any of the 34 distinct |
| | convergent second-order (generalized Gaussian) hypergeometric |
| | series enumerated by Horn, as well as the Kampe de Feriet |
| | function. |
| | |
| | The series is computed by rewriting it so that the inner |
| | series (i.e. the series containing `n` and `y`) has the form of an |
| | ordinary generalized hypergeometric series and thereby can be |
| | evaluated efficiently using :func:`~mpmath.hyper`. If possible, |
| | manually swapping `x` and `y` and the corresponding parameters |
| | can sometimes give better results. |
| | |
| | **Examples** |
| | |
| | Two separable cases: a product of two geometric series, and a |
| | product of two Gaussian hypergeometric functions:: |
| | |
| | >>> from mpmath import * |
| | >>> mp.dps = 25; mp.pretty = True |
| | >>> x, y = mpf(0.25), mpf(0.5) |
| | >>> hyper2d({'m':1,'n':1}, {}, x,y) |
| | 2.666666666666666666666667 |
| | >>> 1/(1-x)/(1-y) |
| | 2.666666666666666666666667 |
| | >>> hyper2d({'m':[1,2],'n':[3,4]}, {'m':[5],'n':[6]}, x,y) |
| | 4.164358531238938319669856 |
| | >>> hyp2f1(1,2,5,x)*hyp2f1(3,4,6,y) |
| | 4.164358531238938319669856 |
| | |
| | Some more series that can be done in closed form:: |
| | |
| | >>> hyper2d({'m':1,'n':1},{'m+n':1},x,y) |
| | 2.013417124712514809623881 |
| | >>> (exp(x)*x-exp(y)*y)/(x-y) |
| | 2.013417124712514809623881 |
| | |
| | Six of the 34 Horn functions, G1-G3 and H1-H3:: |
| | |
| | >>> from mpmath import * |
| | >>> mp.dps = 10; mp.pretty = True |
| | >>> x, y = 0.0625, 0.125 |
| | >>> a1,a2,b1,b2,c1,c2,d = 1.1,-1.2,-1.3,-1.4,1.5,-1.6,1.7 |
| | >>> hyper2d({'m+n':a1,'n-m':b1,'m-n':b2},{},x,y) # G1 |
| | 1.139090746 |
| | >>> nsum(lambda m,n: rf(a1,m+n)*rf(b1,n-m)*rf(b2,m-n)*\ |
| | ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf]) |
| | 1.139090746 |
| | >>> hyper2d({'m':a1,'n':a2,'n-m':b1,'m-n':b2},{},x,y) # G2 |
| | 0.9503682696 |
| | >>> nsum(lambda m,n: rf(a1,m)*rf(a2,n)*rf(b1,n-m)*rf(b2,m-n)*\ |
| | ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf]) |
| | 0.9503682696 |
| | >>> hyper2d({'2n-m':a1,'2m-n':a2},{},x,y) # G3 |
| | 1.029372029 |
| | >>> nsum(lambda m,n: rf(a1,2*n-m)*rf(a2,2*m-n)*\ |
| | ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf]) |
| | 1.029372029 |
| | >>> hyper2d({'m-n':a1,'m+n':b1,'n':c1},{'m':d},x,y) # H1 |
| | -1.605331256 |
| | >>> nsum(lambda m,n: rf(a1,m-n)*rf(b1,m+n)*rf(c1,n)/rf(d,m)*\ |
| | ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf]) |
| | -1.605331256 |
| | >>> hyper2d({'m-n':a1,'m':b1,'n':[c1,c2]},{'m':d},x,y) # H2 |
| | -2.35405404 |
| | >>> nsum(lambda m,n: rf(a1,m-n)*rf(b1,m)*rf(c1,n)*rf(c2,n)/rf(d,m)*\ |
| | ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf]) |
| | -2.35405404 |
| | >>> hyper2d({'2m+n':a1,'n':b1},{'m+n':c1},x,y) # H3 |
| | 0.974479074 |
| | >>> nsum(lambda m,n: rf(a1,2*m+n)*rf(b1,n)/rf(c1,m+n)*\ |
| | ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf]) |
| | 0.974479074 |
| | |
| | **References** |
| | |
| | 1. [SrivastavaKarlsson]_ |
| | 2. [Weisstein]_ http://mathworld.wolfram.com/HornFunction.html |
| | 3. [Weisstein]_ http://mathworld.wolfram.com/AppellHypergeometricFunction.html |
| | |
| | """ |
| | x = ctx.convert(x) |
| | y = ctx.convert(y) |
| | def parse(dct, key): |
| | args = dct.pop(key, []) |
| | try: |
| | args = list(args) |
| | except TypeError: |
| | args = [args] |
| | return [ctx.convert(arg) for arg in args] |
| | a_s = dict(a) |
| | b_s = dict(b) |
| | a_m = parse(a, 'm') |
| | a_n = parse(a, 'n') |
| | a_m_add_n = parse(a, 'm+n') |
| | a_m_sub_n = parse(a, 'm-n') |
| | a_n_sub_m = parse(a, 'n-m') |
| | a_2m_add_n = parse(a, '2m+n') |
| | a_2m_sub_n = parse(a, '2m-n') |
| | a_2n_sub_m = parse(a, '2n-m') |
| | b_m = parse(b, 'm') |
| | b_n = parse(b, 'n') |
| | b_m_add_n = parse(b, 'm+n') |
| | if a: raise ValueError("unsupported key: %r" % a.keys()[0]) |
| | if b: raise ValueError("unsupported key: %r" % b.keys()[0]) |
| | s = 0 |
| | outer = ctx.one |
| | m = ctx.mpf(0) |
| | ok_count = 0 |
| | prec = ctx.prec |
| | maxterms = kwargs.get('maxterms', 20*prec) |
| | try: |
| | ctx.prec += 10 |
| | tol = +ctx.eps |
| | while 1: |
| | inner_sign = 1 |
| | outer_sign = 1 |
| | inner_a = list(a_n) |
| | inner_b = list(b_n) |
| | outer_a = [a+m for a in a_m] |
| | outer_b = [b+m for b in b_m] |
| | |
| | for a in a_m_add_n: |
| | a = a+m |
| | inner_a.append(a) |
| | outer_a.append(a) |
| | |
| | for b in b_m_add_n: |
| | b = b+m |
| | inner_b.append(b) |
| | outer_b.append(b) |
| | |
| | for a in a_n_sub_m: |
| | inner_a.append(a-m) |
| | outer_b.append(a-m-1) |
| | |
| | for a in a_m_sub_n: |
| | inner_sign *= (-1) |
| | outer_sign *= (-1)**(m) |
| | inner_b.append(1-a-m) |
| | outer_a.append(-a-m) |
| | |
| | for a in a_2m_add_n: |
| | inner_a.append(a+2*m) |
| | outer_a.append((a+2*m)*(1+a+2*m)) |
| | |
| | for a in a_2m_sub_n: |
| | inner_sign *= (-1) |
| | inner_b.append(1-a-2*m) |
| | outer_a.append((a+2*m)*(1+a+2*m)) |
| | |
| | for a in a_2n_sub_m: |
| | inner_sign *= 4 |
| | inner_a.append(0.5*(a-m)) |
| | inner_a.append(0.5*(a-m+1)) |
| | outer_b.append(a-m-1) |
| | inner = ctx.hyper(inner_a, inner_b, inner_sign*y, |
| | zeroprec=ctx.prec, **kwargs) |
| | term = outer * inner * outer_sign |
| | if abs(term) < tol: |
| | ok_count += 1 |
| | else: |
| | ok_count = 0 |
| | if ok_count >= 3 or not outer: |
| | break |
| | s += term |
| | for a in outer_a: outer *= a |
| | for b in outer_b: outer /= b |
| | m += 1 |
| | outer = outer * x / m |
| | if m > maxterms: |
| | raise ctx.NoConvergence("maxterms exceeded in hyper2d") |
| | finally: |
| | ctx.prec = prec |
| | return +s |
| |
|
| | """ |
| | @defun |
| | def kampe_de_feriet(ctx,a,b,c,d,e,f,x,y,**kwargs): |
| | return ctx.hyper2d({'m+n':a,'m':b,'n':c}, |
| | {'m+n':d,'m':e,'n':f}, x,y, **kwargs) |
| | """ |
| |
|
| | @defun |
| | def bihyper(ctx, a_s, b_s, z, **kwargs): |
| | r""" |
| | Evaluates the bilateral hypergeometric series |
| | |
| | .. math :: |
| | |
| | \,_AH_B(a_1, \ldots, a_k; b_1, \ldots, b_B; z) = |
| | \sum_{n=-\infty}^{\infty} |
| | \frac{(a_1)_n \ldots (a_A)_n} |
| | {(b_1)_n \ldots (b_B)_n} \, z^n |
| | |
| | where, for direct convergence, `A = B` and `|z| = 1`, although a |
| | regularized sum exists more generally by considering the |
| | bilateral series as a sum of two ordinary hypergeometric |
| | functions. In order for the series to make sense, none of the |
| | parameters may be integers. |
| | |
| | **Examples** |
| | |
| | The value of `\,_2H_2` at `z = 1` is given by Dougall's formula:: |
| | |
| | >>> from mpmath import * |
| | >>> mp.dps = 25; mp.pretty = True |
| | >>> a,b,c,d = 0.5, 1.5, 2.25, 3.25 |
| | >>> bihyper([a,b],[c,d],1) |
| | -14.49118026212345786148847 |
| | >>> gammaprod([c,d,1-a,1-b,c+d-a-b-1],[c-a,d-a,c-b,d-b]) |
| | -14.49118026212345786148847 |
| | |
| | The regularized function `\,_1H_0` can be expressed as the |
| | sum of one `\,_2F_0` function and one `\,_1F_1` function:: |
| | |
| | >>> a = mpf(0.25) |
| | >>> z = mpf(0.75) |
| | >>> bihyper([a], [], z) |
| | (0.2454393389657273841385582 + 0.2454393389657273841385582j) |
| | >>> hyper([a,1],[],z) + (hyper([1],[1-a],-1/z)-1) |
| | (0.2454393389657273841385582 + 0.2454393389657273841385582j) |
| | >>> hyper([a,1],[],z) + hyper([1],[2-a],-1/z)/z/(a-1) |
| | (0.2454393389657273841385582 + 0.2454393389657273841385582j) |
| | |
| | **References** |
| | |
| | 1. [Slater]_ (chapter 6: "Bilateral Series", pp. 180-189) |
| | 2. [Wikipedia]_ http://en.wikipedia.org/wiki/Bilateral_hypergeometric_series |
| | |
| | """ |
| | z = ctx.convert(z) |
| | c_s = a_s + b_s |
| | p = len(a_s) |
| | q = len(b_s) |
| | if (p, q) == (0,0) or (p, q) == (1,1): |
| | return ctx.zero * z |
| | neg = (p-q) % 2 |
| | def h(*c_s): |
| | a_s = list(c_s[:p]) |
| | b_s = list(c_s[p:]) |
| | aa_s = [2-b for b in b_s] |
| | bb_s = [2-a for a in a_s] |
| | rp = [(-1)**neg * z] + [1-b for b in b_s] + [1-a for a in a_s] |
| | rc = [-1] + [1]*len(b_s) + [-1]*len(a_s) |
| | T1 = [], [], [], [], a_s + [1], b_s, z |
| | T2 = rp, rc, [], [], aa_s + [1], bb_s, (-1)**neg / z |
| | return T1, T2 |
| | return ctx.hypercomb(h, c_s, **kwargs) |
| |
|