def mpc_psi(m, z, prec, rnd=round_fast): """ Computation of the polygamma function of arbitrary integer order m >= 0, for a complex argument z. """ if m == 0: return mpc_psi0(z, prec, rnd) re, im = z wp = prec + 20 sign, man, exp, bc = re if not man: if re == finf and im == fzero: return (fzero, fzero) if re == fnan: return fnan # Recurrence w = to_int(re) n = int(0.4*wp + 4*m) s = mpc_zero if w < n: for k in xrange(w, n): t = mpc_pow_int(z, -m-1, wp) s = mpc_add(s, t, wp) z = mpc_add_mpf(z, fone, wp) zm = mpc_pow_int(z, -m, wp) z2 = mpc_pow_int(z, -2, wp) # 1/m*(z+N)^m integral_term = mpc_div_mpf(zm, from_int(m), wp) s = mpc_add(s, integral_term, wp) # 1/2*(z+N)^(-(m+1)) s = mpc_add(s, mpc_mul_mpf(mpc_div(zm, z, wp), fhalf, wp), wp) a = m + 1 b = 2 k = 1 # Important: we want to sum up to the *relative* error, # not the absolute error, because psi^(m)(z) might be tiny magn = mpc_abs(s, 10) magn = magn[2]+magn[3] eps = mpf_shift(fone, magn-wp+2) while 1: zm = mpc_mul(zm, z2, wp) bern = mpf_bernoulli(2*k, wp) scal = mpf_mul_int(bern, a, wp) scal = mpf_div(scal, from_int(b), wp) term = mpc_mul_mpf(zm, scal, wp) s = mpc_add(s, term, wp) szterm = mpc_abs(term, 10) if k > 2 and mpf_le(szterm, eps): break #print k, to_str(szterm, 10), to_str(eps, 10) a *= (m+2*k)*(m+2*k+1) b *= (2*k+1)*(2*k+2) k += 1 # Scale and sign factor v = mpc_mul_mpf(s, mpf_gamma(from_int(m+1), wp), prec, rnd) if not (m & 1): v = mpf_neg(v[0]), mpf_neg(v[1]) return v
def mpc_psi(m, z, prec, rnd=round_fast): """ Computation of the polygamma function of arbitrary integer order m >= 0, for a complex argument z. """ if m == 0: return mpc_psi0(z, prec, rnd) re, im = z wp = prec + 20 sign, man, exp, bc = re if not man: if re == finf and im == fzero: return (fzero, fzero) if re == fnan: return fnan # Recurrence w = to_int(re) n = int(0.4 * wp + 4 * m) s = mpc_zero if w < n: for k in xrange(w, n): t = mpc_pow_int(z, -m - 1, wp) s = mpc_add(s, t, wp) z = mpc_add_mpf(z, fone, wp) zm = mpc_pow_int(z, -m, wp) z2 = mpc_pow_int(z, -2, wp) # 1/m*(z+N)^m integral_term = mpc_div_mpf(zm, from_int(m), wp) s = mpc_add(s, integral_term, wp) # 1/2*(z+N)^(-(m+1)) s = mpc_add(s, mpc_mul_mpf(mpc_div(zm, z, wp), fhalf, wp), wp) a = m + 1 b = 2 k = 1 # Important: we want to sum up to the *relative* error, # not the absolute error, because psi^(m)(z) might be tiny magn = mpc_abs(s, 10) magn = magn[2] + magn[3] eps = mpf_shift(fone, magn - wp + 2) while 1: zm = mpc_mul(zm, z2, wp) bern = mpf_bernoulli(2 * k, wp) scal = mpf_mul_int(bern, a, wp) scal = mpf_div(scal, from_int(b), wp) term = mpc_mul_mpf(zm, scal, wp) s = mpc_add(s, term, wp) szterm = mpc_abs(term, 10) if k > 2 and mpf_le(szterm, eps): break #print k, to_str(szterm, 10), to_str(eps, 10) a *= (m + 2 * k) * (m + 2 * k + 1) b *= (2 * k + 1) * (2 * k + 2) k += 1 # Scale and sign factor v = mpc_mul_mpf(s, mpf_gamma(from_int(m + 1), wp), prec, rnd) if not (m & 1): v = mpf_neg(v[0]), mpf_neg(v[1]) return v
def mpc_psi0(z, prec, rnd=round_fast): """ Computation of the digamma function (psi function of order 0) of a complex argument. """ re, im = z # Fall back to the real case if im == fzero: return (mpf_psi0(re, prec, rnd), fzero) wp = prec + 20 sign, man, exp, bc = re # Reflection formula if sign and exp+bc > 3: c = mpc_cos_pi(z, wp) s = mpc_sin_pi(z, wp) q = mpc_mul_mpf(mpc_div(c, s, wp), mpf_pi(wp), wp) p = mpc_psi0(mpc_sub(mpc_one, z, wp), wp) return mpc_sub(p, q, prec, rnd) # Just the logarithmic term if (not sign) and bc + exp > wp: return mpc_log(mpc_sub(z, mpc_one, wp), prec, rnd) # Initial recurrence to obtain a large enough z w = to_int(re) n = int(0.11*wp) + 2 s = mpc_zero if w < n: for k in xrange(w, n): s = mpc_sub(s, mpc_reciprocal(z, wp), wp) z = mpc_add_mpf(z, fone, wp) z = mpc_sub(z, mpc_one, wp) # Logarithmic and endpoint term s = mpc_add(s, mpc_log(z, wp), wp) s = mpc_add(s, mpc_div(mpc_half, z, wp), wp) # Euler-Maclaurin remainder sum z2 = mpc_square(z, wp) t = mpc_one prev = mpc_zero k = 1 eps = mpf_shift(fone, -wp+2) while 1: t = mpc_mul(t, z2, wp) bern = mpf_bernoulli(2*k, wp) term = mpc_mpf_div(bern, mpc_mul_int(t, 2*k, wp), wp) s = mpc_sub(s, term, wp) szterm = mpc_abs(term, 10) if k > 2 and mpf_le(szterm, eps): break prev = term k += 1 return s
def mpc_psi0(z, prec, rnd=round_fast): """ Computation of the digamma function (psi function of order 0) of a complex argument. """ re, im = z # Fall back to the real case if im == fzero: return (mpf_psi0(re, prec, rnd), fzero) wp = prec + 20 sign, man, exp, bc = re # Reflection formula if sign and exp + bc > 3: c = mpc_cos_pi(z, wp) s = mpc_sin_pi(z, wp) q = mpc_mul(mpc_div(c, s, wp), (mpf_pi(wp), fzero), wp) p = mpc_psi0(mpc_sub(mpc_one, z, wp), wp) return mpc_sub(p, q, prec, rnd) # Just the logarithmic term if (not sign) and bc + exp > wp: return mpc_log(mpc_sub(z, mpc_one, wp), prec, rnd) # Initial recurrence to obtain a large enough z w = to_int(re) n = int(0.11 * wp) + 2 s = mpc_zero if w < n: for k in xrange(w, n): s = mpc_sub(s, mpc_div(mpc_one, z, wp), wp) z = mpc_add_mpf(z, fone, wp) z = mpc_sub(z, mpc_one, wp) # Logarithmic and endpoint term s = mpc_add(s, mpc_log(z, wp), wp) s = mpc_add(s, mpc_div(mpc_half, z, wp), wp) # Euler-Maclaurin remainder sum z2 = mpc_mul(z, z, wp) t = mpc_one prev = mpc_zero k = 1 eps = mpf_shift(fone, -wp + 2) while 1: t = mpc_mul(t, z2, wp) bern = mpf_bernoulli(2 * k, wp) term = mpc_div((bern, fzero), mpc_mul_int(t, 2 * k, wp), wp) s = mpc_sub(s, term, wp) szterm = mpc_abs(term, 10) if k > 2 and mpf_le(szterm, eps): break prev = term k += 1 return s
def mpc_agm(a, b, prec, rnd=round_fast): """ Complex AGM. TODO: * check that convergence works as intended * optimize * select a nonarbitrary branch """ if mpc_is_infnan(a) or mpc_is_infnan(b): return fnan, fnan if mpc_zero in (a, b): return fzero, fzero if mpc_neg(a) == b: return fzero, fzero wp = prec+20 eps = mpf_shift(fone, -wp+10) while 1: a1 = mpc_shift(mpc_add(a, b, wp), -1) b1 = mpc_sqrt(mpc_mul(a, b, wp), wp) a, b = a1, b1 size = mpf_min_max([mpc_abs(a,10), mpc_abs(b,10)])[1] err = mpc_abs(mpc_sub(a, b, 10), 10) if size == fzero or mpf_lt(err, mpf_mul(eps, size)): return a
def mpc_agm(a, b, prec, rnd=round_fast): """ Complex AGM. TODO: * check that convergence works as intended * optimize * select a nonarbitrary branch """ if mpc_is_infnan(a) or mpc_is_infnan(b): return fnan, fnan if mpc_zero in (a, b): return fzero, fzero if mpc_neg(a) == b: return fzero, fzero wp = prec + 20 eps = mpf_shift(fone, -wp + 10) while 1: a1 = mpc_shift(mpc_add(a, b, wp), -1) b1 = mpc_sqrt(mpc_mul(a, b, wp), wp) a, b = a1, b1 size = sorted([mpc_abs(a, 10), mpc_abs(a, 10)], cmp=mpf_cmp)[1] err = mpc_abs(mpc_sub(a, b, 10), 10) if size == fzero or mpf_lt(err, mpf_mul(eps, size)): return a
def __add__(s, t): prec, rounding = prec_rounding if not isinstance(t, mpc): t = mpc_convert_lhs(t) if t is NotImplemented: return t if isinstance(t, mpf): return make_mpc(mpc_add_mpf(s._mpc_, t._mpf_, prec, rounding)) return make_mpc(mpc_add(s._mpc_, t._mpc_, prec, rounding))
def mpc_ci(z, prec, rnd=round_fast): re, im = z if im == fzero: ci = mpf_ci_si(re, prec, rnd, 0)[0] if mpf_sign(re) < 0: return (ci, mpf_pi(prec, rnd)) return (ci, fzero) wp = prec + 20 cre, cim = mpc_ci_si_taylor(re, im, wp, 0) cre = mpf_add(cre, mpf_euler(wp), wp) ci = mpc_add((cre, cim), mpc_log(z, wp), prec, rnd) return ci
def mpc_ellipe(z, prec, rnd=round_fast): re, im = z if im == fzero: if re == finf: return (fzero, finf) if mpf_le(re, fone): return mpf_ellipe(re, prec, rnd), fzero wp = prec + 15 mag = mpc_abs(z, 1) p = max(mag[2]+mag[3], 0) - wp h = mpf_shift(fone, p) K = mpc_ellipk(z, 2*wp) Kh = mpc_ellipk(mpc_add_mpf(z, h, 2*wp), 2*wp) Kdiff = mpc_shift(mpc_sub(Kh, K, wp), -p) t = mpc_sub(mpc_one, z, wp) b = mpc_mul(Kdiff, mpc_shift(z,1), wp) return mpc_mul(t, mpc_add(K, b, wp), prec, rnd)
def mpc_ellipe(z, prec, rnd=round_fast): re, im = z if im == fzero: if re == finf: return (fzero, finf) if mpf_le(re, fone): return mpf_ellipe(re, prec, rnd), fzero wp = prec + 15 mag = mpc_abs(z, 1) p = max(mag[2] + mag[3], 0) - wp h = mpf_shift(fone, p) K = mpc_ellipk(z, 2 * wp) Kh = mpc_ellipk(mpc_add_mpf(z, h, 2 * wp), 2 * wp) Kdiff = mpc_shift(mpc_sub(Kh, K, wp), -p) t = mpc_sub(mpc_one, z, wp) b = mpc_mul(Kdiff, mpc_shift(z, 1), wp) return mpc_mul(t, mpc_add(K, b, wp), prec, rnd)
def mpc_ei(z, prec, rnd=round_fast, e1=False): if e1: z = mpc_neg(z) a, b = z asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b if b == fzero: if e1: x = mpf_neg(mpf_ei(a, prec, rnd)) if not asign: y = mpf_neg(mpf_pi(prec, rnd)) else: y = fzero return x, y else: return mpf_ei(a, prec, rnd), fzero if a != fzero: if not aman or not bman: return (fnan, fnan) wp = prec + 40 amag = aexp+abc bmag = bexp+bbc zmag = max(amag, bmag) can_use_asymp = zmag > wp if not can_use_asymp: zabsint = abs(to_int(a)) + abs(to_int(b)) can_use_asymp = zabsint > int(wp*0.693) + 20 try: if can_use_asymp: if zmag > wp: v = fone, fzero else: zre = to_fixed(a, wp) zim = to_fixed(b, wp) vre, vim = complex_ei_asymptotic(zre, zim, wp) v = from_man_exp(vre, -wp), from_man_exp(vim, -wp) v = mpc_mul(v, mpc_exp(z, wp), wp) v = mpc_div(v, z, wp) if e1: v = mpc_neg(v, prec, rnd) else: x, y = v if bsign: v = mpf_pos(x, prec, rnd), mpf_sub(y, mpf_pi(wp), prec, rnd) else: v = mpf_pos(x, prec, rnd), mpf_add(y, mpf_pi(wp), prec, rnd) return v except NoConvergence: pass #wp += 2*max(0,zmag) wp += 2*int(to_int(mpc_abs(z, 5))) zre = to_fixed(a, wp) zim = to_fixed(b, wp) vre, vim = complex_ei_taylor(zre, zim, wp) vre += euler_fixed(wp) v = from_man_exp(vre,-wp), from_man_exp(vim,-wp) if e1: u = mpc_log(mpc_neg(z),wp) else: u = mpc_log(z,wp) v = mpc_add(v, u, prec, rnd) if e1: v = mpc_neg(v) return v
def mpc_ei(z, prec, rnd=round_fast, e1=False): if e1: z = mpc_neg(z) a, b = z asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b if b == fzero: if e1: x = mpf_neg(mpf_ei(a, prec, rnd)) if not asign: y = mpf_neg(mpf_pi(prec, rnd)) else: y = fzero return x, y else: return mpf_ei(a, prec, rnd), fzero if a != fzero: if not aman or not bman: return (fnan, fnan) wp = prec + 40 amag = aexp + abc bmag = bexp + bbc zmag = max(amag, bmag) can_use_asymp = zmag > wp if not can_use_asymp: zabsint = abs(to_int(a)) + abs(to_int(b)) can_use_asymp = zabsint > int(wp * 0.693) + 20 try: if can_use_asymp: if zmag > wp: v = fone, fzero else: zre = to_fixed(a, wp) zim = to_fixed(b, wp) vre, vim = complex_ei_asymptotic(zre, zim, wp) v = from_man_exp(vre, -wp), from_man_exp(vim, -wp) v = mpc_mul(v, mpc_exp(z, wp), wp) v = mpc_div(v, z, wp) if e1: v = mpc_neg(v, prec, rnd) else: x, y = v if bsign: v = mpf_pos(x, prec, rnd), mpf_sub(y, mpf_pi(wp), prec, rnd) else: v = mpf_pos(x, prec, rnd), mpf_add(y, mpf_pi(wp), prec, rnd) return v except NoConvergence: pass #wp += 2*max(0,zmag) wp += 2 * int(to_int(mpc_abs(z, 5))) zre = to_fixed(a, wp) zim = to_fixed(b, wp) vre, vim = complex_ei_taylor(zre, zim, wp) vre += euler_fixed(wp) v = from_man_exp(vre, -wp), from_man_exp(vim, -wp) if e1: u = mpc_log(mpc_neg(z), wp) else: u = mpc_log(z, wp) v = mpc_add(v, u, prec, rnd) if e1: v = mpc_neg(v) return v