hypergeometric.py 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413
  1. from ..libmp.backend import xrange
  2. from .functions import defun, defun_wrapped
  3. def _check_need_perturb(ctx, terms, prec, discard_known_zeros):
  4. perturb = recompute = False
  5. extraprec = 0
  6. discard = []
  7. for term_index, term in enumerate(terms):
  8. w_s, c_s, alpha_s, beta_s, a_s, b_s, z = term
  9. have_singular_nongamma_weight = False
  10. # Avoid division by zero in leading factors (TODO:
  11. # also check for near division by zero?)
  12. for k, w in enumerate(w_s):
  13. if not w:
  14. if ctx.re(c_s[k]) <= 0 and c_s[k]:
  15. perturb = recompute = True
  16. have_singular_nongamma_weight = True
  17. pole_count = [0, 0, 0]
  18. # Check for gamma and series poles and near-poles
  19. for data_index, data in enumerate([alpha_s, beta_s, b_s]):
  20. for i, x in enumerate(data):
  21. n, d = ctx.nint_distance(x)
  22. # Poles
  23. if n > 0:
  24. continue
  25. if d == ctx.ninf:
  26. # OK if we have a polynomial
  27. # ------------------------------
  28. ok = False
  29. if data_index == 2:
  30. for u in a_s:
  31. if ctx.isnpint(u) and u >= int(n):
  32. ok = True
  33. break
  34. if ok:
  35. continue
  36. pole_count[data_index] += 1
  37. # ------------------------------
  38. #perturb = recompute = True
  39. #return perturb, recompute, extraprec
  40. elif d < -4:
  41. extraprec += -d
  42. recompute = True
  43. if discard_known_zeros and pole_count[1] > pole_count[0] + pole_count[2] \
  44. and not have_singular_nongamma_weight:
  45. discard.append(term_index)
  46. elif sum(pole_count):
  47. perturb = recompute = True
  48. return perturb, recompute, extraprec, discard
  49. _hypercomb_msg = """
  50. hypercomb() failed to converge to the requested %i bits of accuracy
  51. using a working precision of %i bits. The function value may be zero or
  52. infinite; try passing zeroprec=N or infprec=M to bound finite values between
  53. 2^(-N) and 2^M. Otherwise try a higher maxprec or maxterms.
  54. """
  55. @defun
  56. def hypercomb(ctx, function, params=[], discard_known_zeros=True, **kwargs):
  57. orig = ctx.prec
  58. sumvalue = ctx.zero
  59. dist = ctx.nint_distance
  60. ninf = ctx.ninf
  61. orig_params = params[:]
  62. verbose = kwargs.get('verbose', False)
  63. maxprec = kwargs.get('maxprec', ctx._default_hyper_maxprec(orig))
  64. kwargs['maxprec'] = maxprec # For calls to hypsum
  65. zeroprec = kwargs.get('zeroprec')
  66. infprec = kwargs.get('infprec')
  67. perturbed_reference_value = None
  68. hextra = 0
  69. try:
  70. while 1:
  71. ctx.prec += 10
  72. if ctx.prec > maxprec:
  73. raise ValueError(_hypercomb_msg % (orig, ctx.prec))
  74. orig2 = ctx.prec
  75. params = orig_params[:]
  76. terms = function(*params)
  77. if verbose:
  78. print()
  79. print("ENTERING hypercomb main loop")
  80. print("prec =", ctx.prec)
  81. print("hextra", hextra)
  82. perturb, recompute, extraprec, discard = \
  83. _check_need_perturb(ctx, terms, orig, discard_known_zeros)
  84. ctx.prec += extraprec
  85. if perturb:
  86. if "hmag" in kwargs:
  87. hmag = kwargs["hmag"]
  88. elif ctx._fixed_precision:
  89. hmag = int(ctx.prec*0.3)
  90. else:
  91. hmag = orig + 10 + hextra
  92. h = ctx.ldexp(ctx.one, -hmag)
  93. ctx.prec = orig2 + 10 + hmag + 10
  94. for k in range(len(params)):
  95. params[k] += h
  96. # Heuristically ensure that the perturbations
  97. # are "independent" so that two perturbations
  98. # don't accidentally cancel each other out
  99. # in a subtraction.
  100. h += h/(k+1)
  101. if recompute:
  102. terms = function(*params)
  103. if discard_known_zeros:
  104. terms = [term for (i, term) in enumerate(terms) if i not in discard]
  105. if not terms:
  106. return ctx.zero
  107. evaluated_terms = []
  108. for term_index, term_data in enumerate(terms):
  109. w_s, c_s, alpha_s, beta_s, a_s, b_s, z = term_data
  110. if verbose:
  111. print()
  112. print(" Evaluating term %i/%i : %iF%i" % \
  113. (term_index+1, len(terms), len(a_s), len(b_s)))
  114. print(" powers", ctx.nstr(w_s), ctx.nstr(c_s))
  115. print(" gamma", ctx.nstr(alpha_s), ctx.nstr(beta_s))
  116. print(" hyper", ctx.nstr(a_s), ctx.nstr(b_s))
  117. print(" z", ctx.nstr(z))
  118. #v = ctx.hyper(a_s, b_s, z, **kwargs)
  119. #for a in alpha_s: v *= ctx.gamma(a)
  120. #for b in beta_s: v *= ctx.rgamma(b)
  121. #for w, c in zip(w_s, c_s): v *= ctx.power(w, c)
  122. v = ctx.fprod([ctx.hyper(a_s, b_s, z, **kwargs)] + \
  123. [ctx.gamma(a) for a in alpha_s] + \
  124. [ctx.rgamma(b) for b in beta_s] + \
  125. [ctx.power(w,c) for (w,c) in zip(w_s,c_s)])
  126. if verbose:
  127. print(" Value:", v)
  128. evaluated_terms.append(v)
  129. if len(terms) == 1 and (not perturb):
  130. sumvalue = evaluated_terms[0]
  131. break
  132. if ctx._fixed_precision:
  133. sumvalue = ctx.fsum(evaluated_terms)
  134. break
  135. sumvalue = ctx.fsum(evaluated_terms)
  136. term_magnitudes = [ctx.mag(x) for x in evaluated_terms]
  137. max_magnitude = max(term_magnitudes)
  138. sum_magnitude = ctx.mag(sumvalue)
  139. cancellation = max_magnitude - sum_magnitude
  140. if verbose:
  141. print()
  142. print(" Cancellation:", cancellation, "bits")
  143. print(" Increased precision:", ctx.prec - orig, "bits")
  144. precision_ok = cancellation < ctx.prec - orig
  145. if zeroprec is None:
  146. zero_ok = False
  147. else:
  148. zero_ok = max_magnitude - ctx.prec < -zeroprec
  149. if infprec is None:
  150. inf_ok = False
  151. else:
  152. inf_ok = max_magnitude > infprec
  153. if precision_ok and (not perturb) or ctx.isnan(cancellation):
  154. break
  155. elif precision_ok:
  156. if perturbed_reference_value is None:
  157. hextra += 20
  158. perturbed_reference_value = sumvalue
  159. continue
  160. elif ctx.mag(sumvalue - perturbed_reference_value) <= \
  161. ctx.mag(sumvalue) - orig:
  162. break
  163. elif zero_ok:
  164. sumvalue = ctx.zero
  165. break
  166. elif inf_ok:
  167. sumvalue = ctx.inf
  168. break
  169. elif 'hmag' in kwargs:
  170. break
  171. else:
  172. hextra *= 2
  173. perturbed_reference_value = sumvalue
  174. # Increase precision
  175. else:
  176. increment = min(max(cancellation, orig//2), max(extraprec,orig))
  177. ctx.prec += increment
  178. if verbose:
  179. print(" Must start over with increased precision")
  180. continue
  181. finally:
  182. ctx.prec = orig
  183. return +sumvalue
  184. @defun
  185. def hyper(ctx, a_s, b_s, z, **kwargs):
  186. """
  187. Hypergeometric function, general case.
  188. """
  189. z = ctx.convert(z)
  190. p = len(a_s)
  191. q = len(b_s)
  192. a_s = [ctx._convert_param(a) for a in a_s]
  193. b_s = [ctx._convert_param(b) for b in b_s]
  194. # Reduce degree by eliminating common parameters
  195. if kwargs.get('eliminate', True):
  196. elim_nonpositive = kwargs.get('eliminate_all', False)
  197. i = 0
  198. while i < q and a_s:
  199. b = b_s[i]
  200. if b in a_s and (elim_nonpositive or not ctx.isnpint(b[0])):
  201. a_s.remove(b)
  202. b_s.remove(b)
  203. p -= 1
  204. q -= 1
  205. else:
  206. i += 1
  207. # Handle special cases
  208. if p == 0:
  209. if q == 1: return ctx._hyp0f1(b_s, z, **kwargs)
  210. elif q == 0: return ctx.exp(z)
  211. elif p == 1:
  212. if q == 1: return ctx._hyp1f1(a_s, b_s, z, **kwargs)
  213. elif q == 2: return ctx._hyp1f2(a_s, b_s, z, **kwargs)
  214. elif q == 0: return ctx._hyp1f0(a_s[0][0], z)
  215. elif p == 2:
  216. if q == 1: return ctx._hyp2f1(a_s, b_s, z, **kwargs)
  217. elif q == 2: return ctx._hyp2f2(a_s, b_s, z, **kwargs)
  218. elif q == 3: return ctx._hyp2f3(a_s, b_s, z, **kwargs)
  219. elif q == 0: return ctx._hyp2f0(a_s, b_s, z, **kwargs)
  220. elif p == q+1:
  221. return ctx._hypq1fq(p, q, a_s, b_s, z, **kwargs)
  222. elif p > q+1 and not kwargs.get('force_series'):
  223. return ctx._hyp_borel(p, q, a_s, b_s, z, **kwargs)
  224. coeffs, types = zip(*(a_s+b_s))
  225. return ctx.hypsum(p, q, types, coeffs, z, **kwargs)
  226. @defun
  227. def hyp0f1(ctx,b,z,**kwargs):
  228. return ctx.hyper([],[b],z,**kwargs)
  229. @defun
  230. def hyp1f1(ctx,a,b,z,**kwargs):
  231. return ctx.hyper([a],[b],z,**kwargs)
  232. @defun
  233. def hyp1f2(ctx,a1,b1,b2,z,**kwargs):
  234. return ctx.hyper([a1],[b1,b2],z,**kwargs)
  235. @defun
  236. def hyp2f1(ctx,a,b,c,z,**kwargs):
  237. return ctx.hyper([a,b],[c],z,**kwargs)
  238. @defun
  239. def hyp2f2(ctx,a1,a2,b1,b2,z,**kwargs):
  240. return ctx.hyper([a1,a2],[b1,b2],z,**kwargs)
  241. @defun
  242. def hyp2f3(ctx,a1,a2,b1,b2,b3,z,**kwargs):
  243. return ctx.hyper([a1,a2],[b1,b2,b3],z,**kwargs)
  244. @defun
  245. def hyp2f0(ctx,a,b,z,**kwargs):
  246. return ctx.hyper([a,b],[],z,**kwargs)
  247. @defun
  248. def hyp3f2(ctx,a1,a2,a3,b1,b2,z,**kwargs):
  249. return ctx.hyper([a1,a2,a3],[b1,b2],z,**kwargs)
  250. @defun_wrapped
  251. def _hyp1f0(ctx, a, z):
  252. return (1-z) ** (-a)
  253. @defun
  254. def _hyp0f1(ctx, b_s, z, **kwargs):
  255. (b, btype), = b_s
  256. if z:
  257. magz = ctx.mag(z)
  258. else:
  259. magz = 0
  260. if magz >= 8 and not kwargs.get('force_series'):
  261. try:
  262. # http://functions.wolfram.com/HypergeometricFunctions/
  263. # Hypergeometric0F1/06/02/03/0004/
  264. # TODO: handle the all-real case more efficiently!
  265. # TODO: figure out how much precision is needed (exponential growth)
  266. orig = ctx.prec
  267. try:
  268. ctx.prec += 12 + magz//2
  269. def h():
  270. w = ctx.sqrt(-z)
  271. jw = ctx.j*w
  272. u = 1/(4*jw)
  273. c = ctx.mpq_1_2 - b
  274. E = ctx.exp(2*jw)
  275. T1 = ([-jw,E], [c,-1], [], [], [b-ctx.mpq_1_2, ctx.mpq_3_2-b], [], -u)
  276. T2 = ([jw,E], [c,1], [], [], [b-ctx.mpq_1_2, ctx.mpq_3_2-b], [], u)
  277. return T1, T2
  278. v = ctx.hypercomb(h, [], force_series=True)
  279. v = ctx.gamma(b)/(2*ctx.sqrt(ctx.pi))*v
  280. finally:
  281. ctx.prec = orig
  282. if ctx._is_real_type(b) and ctx._is_real_type(z):
  283. v = ctx._re(v)
  284. return +v
  285. except ctx.NoConvergence:
  286. pass
  287. return ctx.hypsum(0, 1, (btype,), [b], z, **kwargs)
  288. @defun
  289. def _hyp1f1(ctx, a_s, b_s, z, **kwargs):
  290. (a, atype), = a_s
  291. (b, btype), = b_s
  292. if not z:
  293. return ctx.one+z
  294. magz = ctx.mag(z)
  295. if magz >= 7 and not (ctx.isint(a) and ctx.re(a) <= 0):
  296. if ctx.isinf(z):
  297. if ctx.sign(a) == ctx.sign(b) == ctx.sign(z) == 1:
  298. return ctx.inf
  299. return ctx.nan * z
  300. try:
  301. try:
  302. ctx.prec += magz
  303. sector = ctx._im(z) < 0
  304. def h(a,b):
  305. if sector:
  306. E = ctx.expjpi(ctx.fneg(a, exact=True))
  307. else:
  308. E = ctx.expjpi(a)
  309. rz = 1/z
  310. T1 = ([E,z], [1,-a], [b], [b-a], [a, 1+a-b], [], -rz)
  311. T2 = ([ctx.exp(z),z], [1,a-b], [b], [a], [b-a, 1-a], [], rz)
  312. return T1, T2
  313. v = ctx.hypercomb(h, [a,b], force_series=True)
  314. if ctx._is_real_type(a) and ctx._is_real_type(b) and ctx._is_real_type(z):
  315. v = ctx._re(v)
  316. return +v
  317. except ctx.NoConvergence:
  318. pass
  319. finally:
  320. ctx.prec -= magz
  321. v = ctx.hypsum(1, 1, (atype, btype), [a, b], z, **kwargs)
  322. return v
  323. def _hyp2f1_gosper(ctx,a,b,c,z,**kwargs):
  324. # Use Gosper's recurrence
  325. # See http://www.math.utexas.edu/pipermail/maxima/2006/000126.html
  326. _a,_b,_c,_z = a, b, c, z
  327. orig = ctx.prec
  328. maxprec = kwargs.get('maxprec', 100*orig)
  329. extra = 10
  330. while 1:
  331. ctx.prec = orig + extra
  332. #a = ctx.convert(_a)
  333. #b = ctx.convert(_b)
  334. #c = ctx.convert(_c)
  335. z = ctx.convert(_z)
  336. d = ctx.mpf(0)
  337. e = ctx.mpf(1)
  338. f = ctx.mpf(0)
  339. k = 0
  340. # Common subexpression elimination, unfortunately making
  341. # things a bit unreadable. The formula is quite messy to begin
  342. # with, though...
  343. abz = a*b*z
  344. ch = c * ctx.mpq_1_2
  345. c1h = (c+1) * ctx.mpq_1_2
  346. nz = 1-z
  347. g = z/nz
  348. abg = a*b*g
  349. cba = c-b-a
  350. z2 = z-2
  351. tol = -ctx.prec - 10
  352. nstr = ctx.nstr
  353. nprint = ctx.nprint
  354. mag = ctx.mag
  355. maxmag = ctx.ninf
  356. while 1:
  357. kch = k+ch
  358. kakbz = (k+a)*(k+b)*z / (4*(k+1)*kch*(k+c1h))
  359. d1 = kakbz*(e-(k+cba)*d*g)
  360. e1 = kakbz*(d*abg+(k+c)*e)
  361. ft = d*(k*(cba*z+k*z2-c)-abz)/(2*kch*nz)
  362. f1 = f + e - ft
  363. maxmag = max(maxmag, mag(f1))
  364. if mag(f1-f) < tol:
  365. break
  366. d, e, f = d1, e1, f1
  367. k += 1
  368. cancellation = maxmag - mag(f1)
  369. if cancellation < extra:
  370. break
  371. else:
  372. extra += cancellation
  373. if extra > maxprec:
  374. raise ctx.NoConvergence
  375. return f1
  376. @defun
  377. def _hyp2f1(ctx, a_s, b_s, z, **kwargs):
  378. (a, atype), (b, btype) = a_s
  379. (c, ctype), = b_s
  380. if z == 1:
  381. # TODO: the following logic can be simplified
  382. convergent = ctx.re(c-a-b) > 0
  383. finite = (ctx.isint(a) and a <= 0) or (ctx.isint(b) and b <= 0)
  384. zerodiv = ctx.isint(c) and c <= 0 and not \
  385. ((ctx.isint(a) and c <= a <= 0) or (ctx.isint(b) and c <= b <= 0))
  386. #print "bz", a, b, c, z, convergent, finite, zerodiv
  387. # Gauss's theorem gives the value if convergent
  388. if (convergent or finite) and not zerodiv:
  389. return ctx.gammaprod([c, c-a-b], [c-a, c-b], _infsign=True)
  390. # Otherwise, there is a pole and we take the
  391. # sign to be that when approaching from below
  392. # XXX: this evaluation is not necessarily correct in all cases
  393. return ctx.hyp2f1(a,b,c,1-ctx.eps*2) * ctx.inf
  394. # Equal to 1 (first term), unless there is a subsequent
  395. # division by zero
  396. if not z:
  397. # Division by zero but power of z is higher than
  398. # first order so cancels
  399. if c or a == 0 or b == 0:
  400. return 1+z
  401. # Indeterminate
  402. return ctx.nan
  403. # Hit zero denominator unless numerator goes to 0 first
  404. if ctx.isint(c) and c <= 0:
  405. if (ctx.isint(a) and c <= a <= 0) or \
  406. (ctx.isint(b) and c <= b <= 0):
  407. pass
  408. else:
  409. # Pole in series
  410. return ctx.inf
  411. absz = abs(z)
  412. # Fast case: standard series converges rapidly,
  413. # possibly in finitely many terms
  414. if absz <= 0.8 or (ctx.isint(a) and a <= 0 and a >= -1000) or \
  415. (ctx.isint(b) and b <= 0 and b >= -1000):
  416. return ctx.hypsum(2, 1, (atype, btype, ctype), [a, b, c], z, **kwargs)
  417. orig = ctx.prec
  418. try:
  419. ctx.prec += 10
  420. # Use 1/z transformation
  421. if absz >= 1.3:
  422. def h(a,b):
  423. t = ctx.mpq_1-c; ab = a-b; rz = 1/z
  424. T1 = ([-z],[-a], [c,-ab],[b,c-a], [a,t+a],[ctx.mpq_1+ab], rz)
  425. T2 = ([-z],[-b], [c,ab],[a,c-b], [b,t+b],[ctx.mpq_1-ab], rz)
  426. return T1, T2
  427. v = ctx.hypercomb(h, [a,b], **kwargs)
  428. # Use 1-z transformation
  429. elif abs(1-z) <= 0.75:
  430. def h(a,b):
  431. t = c-a-b; ca = c-a; cb = c-b; rz = 1-z
  432. T1 = [], [], [c,t], [ca,cb], [a,b], [1-t], rz
  433. T2 = [rz], [t], [c,a+b-c], [a,b], [ca,cb], [1+t], rz
  434. return T1, T2
  435. v = ctx.hypercomb(h, [a,b], **kwargs)
  436. # Use z/(z-1) transformation
  437. elif abs(z/(z-1)) <= 0.75:
  438. v = ctx.hyp2f1(a, c-b, c, z/(z-1)) / (1-z)**a
  439. # Remaining part of unit circle
  440. else:
  441. v = _hyp2f1_gosper(ctx,a,b,c,z,**kwargs)
  442. finally:
  443. ctx.prec = orig
  444. return +v
  445. @defun
  446. def _hypq1fq(ctx, p, q, a_s, b_s, z, **kwargs):
  447. r"""
  448. Evaluates 3F2, 4F3, 5F4, ...
  449. """
  450. a_s, a_types = zip(*a_s)
  451. b_s, b_types = zip(*b_s)
  452. a_s = list(a_s)
  453. b_s = list(b_s)
  454. absz = abs(z)
  455. ispoly = False
  456. for a in a_s:
  457. if ctx.isint(a) and a <= 0:
  458. ispoly = True
  459. break
  460. # Direct summation
  461. if absz < 1 or ispoly:
  462. try:
  463. return ctx.hypsum(p, q, a_types+b_types, a_s+b_s, z, **kwargs)
  464. except ctx.NoConvergence:
  465. if absz > 1.1 or ispoly:
  466. raise
  467. # Use expansion at |z-1| -> 0.
  468. # Reference: Wolfgang Buhring, "Generalized Hypergeometric Functions at
  469. # Unit Argument", Proc. Amer. Math. Soc., Vol. 114, No. 1 (Jan. 1992),
  470. # pp.145-153
  471. # The current implementation has several problems:
  472. # 1. We only implement it for 3F2. The expansion coefficients are
  473. # given by extremely messy nested sums in the higher degree cases
  474. # (see reference). Is efficient sequential generation of the coefficients
  475. # possible in the > 3F2 case?
  476. # 2. Although the series converges, it may do so slowly, so we need
  477. # convergence acceleration. The acceleration implemented by
  478. # nsum does not always help, so results returned are sometimes
  479. # inaccurate! Can we do better?
  480. # 3. We should check conditions for convergence, and possibly
  481. # do a better job of cancelling out gamma poles if possible.
  482. if z == 1:
  483. # XXX: should also check for division by zero in the
  484. # denominator of the series (cf. hyp2f1)
  485. S = ctx.re(sum(b_s)-sum(a_s))
  486. if S <= 0:
  487. #return ctx.hyper(a_s, b_s, 1-ctx.eps*2, **kwargs) * ctx.inf
  488. return ctx.hyper(a_s, b_s, 0.9, **kwargs) * ctx.inf
  489. if (p,q) == (3,2) and abs(z-1) < 0.05: # and kwargs.get('sum1')
  490. #print "Using alternate summation (experimental)"
  491. a1,a2,a3 = a_s
  492. b1,b2 = b_s
  493. u = b1+b2-a3
  494. initial = ctx.gammaprod([b2-a3,b1-a3,a1,a2],[b2-a3,b1-a3,1,u])
  495. def term(k, _cache={0:initial}):
  496. u = b1+b2-a3+k
  497. if k in _cache:
  498. t = _cache[k]
  499. else:
  500. t = _cache[k-1]
  501. t *= (b1+k-a3-1)*(b2+k-a3-1)
  502. t /= k*(u-1)
  503. _cache[k] = t
  504. return t * ctx.hyp2f1(a1,a2,u,z)
  505. try:
  506. S = ctx.nsum(term, [0,ctx.inf], verbose=kwargs.get('verbose'),
  507. strict=kwargs.get('strict', True))
  508. return S * ctx.gammaprod([b1,b2],[a1,a2,a3])
  509. except ctx.NoConvergence:
  510. pass
  511. # Try to use convergence acceleration on and close to the unit circle.
  512. # Problem: the convergence acceleration degenerates as |z-1| -> 0,
  513. # except for special cases. Everywhere else, the Shanks transformation
  514. # is very efficient.
  515. if absz < 1.1 and ctx._re(z) <= 1:
  516. def term(kk, _cache={0:ctx.one}):
  517. k = int(kk)
  518. if k != kk:
  519. t = z ** ctx.mpf(kk) / ctx.fac(kk)
  520. for a in a_s: t *= ctx.rf(a,kk)
  521. for b in b_s: t /= ctx.rf(b,kk)
  522. return t
  523. if k in _cache:
  524. return _cache[k]
  525. t = term(k-1)
  526. m = k-1
  527. for j in xrange(p): t *= (a_s[j]+m)
  528. for j in xrange(q): t /= (b_s[j]+m)
  529. t *= z
  530. t /= k
  531. _cache[k] = t
  532. return t
  533. sum_method = kwargs.get('sum_method', 'r+s+e')
  534. try:
  535. return ctx.nsum(term, [0,ctx.inf], verbose=kwargs.get('verbose'),
  536. strict=kwargs.get('strict', True),
  537. method=sum_method.replace('e',''))
  538. except ctx.NoConvergence:
  539. if 'e' not in sum_method:
  540. raise
  541. pass
  542. if kwargs.get('verbose'):
  543. print("Attempting Euler-Maclaurin summation")
  544. """
  545. Somewhat slower version (one diffs_exp for each factor).
  546. However, this would be faster with fast direct derivatives
  547. of the gamma function.
  548. def power_diffs(k0):
  549. r = 0
  550. l = ctx.log(z)
  551. while 1:
  552. yield z**ctx.mpf(k0) * l**r
  553. r += 1
  554. def loggamma_diffs(x, reciprocal=False):
  555. sign = (-1) ** reciprocal
  556. yield sign * ctx.loggamma(x)
  557. i = 0
  558. while 1:
  559. yield sign * ctx.psi(i,x)
  560. i += 1
  561. def hyper_diffs(k0):
  562. b2 = b_s + [1]
  563. A = [ctx.diffs_exp(loggamma_diffs(a+k0)) for a in a_s]
  564. B = [ctx.diffs_exp(loggamma_diffs(b+k0,True)) for b in b2]
  565. Z = [power_diffs(k0)]
  566. C = ctx.gammaprod([b for b in b2], [a for a in a_s])
  567. for d in ctx.diffs_prod(A + B + Z):
  568. v = C * d
  569. yield v
  570. """
  571. def log_diffs(k0):
  572. b2 = b_s + [1]
  573. yield sum(ctx.loggamma(a+k0) for a in a_s) - \
  574. sum(ctx.loggamma(b+k0) for b in b2) + k0*ctx.log(z)
  575. i = 0
  576. while 1:
  577. v = sum(ctx.psi(i,a+k0) for a in a_s) - \
  578. sum(ctx.psi(i,b+k0) for b in b2)
  579. if i == 0:
  580. v += ctx.log(z)
  581. yield v
  582. i += 1
  583. def hyper_diffs(k0):
  584. C = ctx.gammaprod([b for b in b_s], [a for a in a_s])
  585. for d in ctx.diffs_exp(log_diffs(k0)):
  586. v = C * d
  587. yield v
  588. tol = ctx.eps / 1024
  589. prec = ctx.prec
  590. try:
  591. trunc = 50 * ctx.dps
  592. ctx.prec += 20
  593. for i in xrange(5):
  594. head = ctx.fsum(term(k) for k in xrange(trunc))
  595. tail, err = ctx.sumem(term, [trunc, ctx.inf], tol=tol,
  596. adiffs=hyper_diffs(trunc),
  597. verbose=kwargs.get('verbose'),
  598. error=True,
  599. _fast_abort=True)
  600. if err < tol:
  601. v = head + tail
  602. break
  603. trunc *= 2
  604. # Need to increase precision because calculation of
  605. # derivatives may be inaccurate
  606. ctx.prec += ctx.prec//2
  607. if i == 4:
  608. raise ctx.NoConvergence(\
  609. "Euler-Maclaurin summation did not converge")
  610. finally:
  611. ctx.prec = prec
  612. return +v
  613. # Use 1/z transformation
  614. # http://functions.wolfram.com/HypergeometricFunctions/
  615. # HypergeometricPFQ/06/01/05/02/0004/
  616. def h(*args):
  617. a_s = list(args[:p])
  618. b_s = list(args[p:])
  619. Ts = []
  620. recz = ctx.one/z
  621. negz = ctx.fneg(z, exact=True)
  622. for k in range(q+1):
  623. ak = a_s[k]
  624. C = [negz]
  625. Cp = [-ak]
  626. Gn = b_s + [ak] + [a_s[j]-ak for j in range(q+1) if j != k]
  627. Gd = a_s + [b_s[j]-ak for j in range(q)]
  628. Fn = [ak] + [ak-b_s[j]+1 for j in range(q)]
  629. Fd = [1-a_s[j]+ak for j in range(q+1) if j != k]
  630. Ts.append((C, Cp, Gn, Gd, Fn, Fd, recz))
  631. return Ts
  632. return ctx.hypercomb(h, a_s+b_s, **kwargs)
  633. @defun
  634. def _hyp_borel(ctx, p, q, a_s, b_s, z, **kwargs):
  635. if a_s:
  636. a_s, a_types = zip(*a_s)
  637. a_s = list(a_s)
  638. else:
  639. a_s, a_types = [], ()
  640. if b_s:
  641. b_s, b_types = zip(*b_s)
  642. b_s = list(b_s)
  643. else:
  644. b_s, b_types = [], ()
  645. kwargs['maxterms'] = kwargs.get('maxterms', ctx.prec)
  646. try:
  647. return ctx.hypsum(p, q, a_types+b_types, a_s+b_s, z, **kwargs)
  648. except ctx.NoConvergence:
  649. pass
  650. prec = ctx.prec
  651. try:
  652. tol = kwargs.get('asymp_tol', ctx.eps/4)
  653. ctx.prec += 10
  654. # hypsum is has a conservative tolerance. So we try again:
  655. def term(k, cache={0:ctx.one}):
  656. if k in cache:
  657. return cache[k]
  658. t = term(k-1)
  659. for a in a_s: t *= (a+(k-1))
  660. for b in b_s: t /= (b+(k-1))
  661. t *= z
  662. t /= k
  663. cache[k] = t
  664. return t
  665. s = ctx.one
  666. for k in xrange(1, ctx.prec):
  667. t = term(k)
  668. s += t
  669. if abs(t) <= tol:
  670. return s
  671. finally:
  672. ctx.prec = prec
  673. if p <= q+3:
  674. contour = kwargs.get('contour')
  675. if not contour:
  676. if ctx.arg(z) < 0.25:
  677. u = z / max(1, abs(z))
  678. if ctx.arg(z) >= 0:
  679. contour = [0, 2j, (2j+2)/u, 2/u, ctx.inf]
  680. else:
  681. contour = [0, -2j, (-2j+2)/u, 2/u, ctx.inf]
  682. #contour = [0, 2j/z, 2/z, ctx.inf]
  683. #contour = [0, 2j, 2/z, ctx.inf]
  684. #contour = [0, 2j, ctx.inf]
  685. else:
  686. contour = [0, ctx.inf]
  687. quad_kwargs = kwargs.get('quad_kwargs', {})
  688. def g(t):
  689. return ctx.exp(-t)*ctx.hyper(a_s, b_s+[1], t*z)
  690. I, err = ctx.quad(g, contour, error=True, **quad_kwargs)
  691. if err <= abs(I)*ctx.eps*8:
  692. return I
  693. raise ctx.NoConvergence
  694. @defun
  695. def _hyp2f2(ctx, a_s, b_s, z, **kwargs):
  696. (a1, a1type), (a2, a2type) = a_s
  697. (b1, b1type), (b2, b2type) = b_s
  698. absz = abs(z)
  699. magz = ctx.mag(z)
  700. orig = ctx.prec
  701. # Asymptotic expansion is ~ exp(z)
  702. asymp_extraprec = magz
  703. # Asymptotic series is in terms of 3F1
  704. can_use_asymptotic = (not kwargs.get('force_series')) and \
  705. (ctx.mag(absz) > 3)
  706. # TODO: much of the following could be shared with 2F3 instead of
  707. # copypasted
  708. if can_use_asymptotic:
  709. #print "using asymp"
  710. try:
  711. try:
  712. ctx.prec += asymp_extraprec
  713. # http://functions.wolfram.com/HypergeometricFunctions/
  714. # Hypergeometric2F2/06/02/02/0002/
  715. def h(a1,a2,b1,b2):
  716. X = a1+a2-b1-b2
  717. A2 = a1+a2
  718. B2 = b1+b2
  719. c = {}
  720. c[0] = ctx.one
  721. c[1] = (A2-1)*X+b1*b2-a1*a2
  722. s1 = 0
  723. k = 0
  724. tprev = 0
  725. while 1:
  726. if k not in c:
  727. 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
  728. uu2 = (k-A2+b1-1)*(k-A2+b2-1)*(k-X-2)
  729. c[k] = ctx.one/k * (uu1*c[k-1]-uu2*c[k-2])
  730. t1 = c[k] * z**(-k)
  731. if abs(t1) < 0.1*ctx.eps:
  732. #print "Convergence :)"
  733. break
  734. # Quit if the series doesn't converge quickly enough
  735. if k > 5 and abs(tprev) / abs(t1) < 1.5:
  736. #print "No convergence :("
  737. raise ctx.NoConvergence
  738. s1 += t1
  739. tprev = t1
  740. k += 1
  741. S = ctx.exp(z)*s1
  742. T1 = [z,S], [X,1], [b1,b2],[a1,a2],[],[],0
  743. T2 = [-z],[-a1],[b1,b2,a2-a1],[a2,b1-a1,b2-a1],[a1,a1-b1+1,a1-b2+1],[a1-a2+1],-1/z
  744. T3 = [-z],[-a2],[b1,b2,a1-a2],[a1,b1-a2,b2-a2],[a2,a2-b1+1,a2-b2+1],[-a1+a2+1],-1/z
  745. return T1, T2, T3
  746. v = ctx.hypercomb(h, [a1,a2,b1,b2], force_series=True, maxterms=4*ctx.prec)
  747. if sum(ctx._is_real_type(u) for u in [a1,a2,b1,b2,z]) == 5:
  748. v = ctx.re(v)
  749. return v
  750. except ctx.NoConvergence:
  751. pass
  752. finally:
  753. ctx.prec = orig
  754. return ctx.hypsum(2, 2, (a1type, a2type, b1type, b2type), [a1, a2, b1, b2], z, **kwargs)
  755. @defun
  756. def _hyp1f2(ctx, a_s, b_s, z, **kwargs):
  757. (a1, a1type), = a_s
  758. (b1, b1type), (b2, b2type) = b_s
  759. absz = abs(z)
  760. magz = ctx.mag(z)
  761. orig = ctx.prec
  762. # Asymptotic expansion is ~ exp(sqrt(z))
  763. asymp_extraprec = z and magz//2
  764. # Asymptotic series is in terms of 3F0
  765. can_use_asymptotic = (not kwargs.get('force_series')) and \
  766. (ctx.mag(absz) > 19) and \
  767. (ctx.sqrt(absz) > 1.5*orig) # and \
  768. # ctx._hyp_check_convergence([a1, a1-b1+1, a1-b2+1], [],
  769. # 1/absz, orig+40+asymp_extraprec)
  770. # TODO: much of the following could be shared with 2F3 instead of
  771. # copypasted
  772. if can_use_asymptotic:
  773. #print "using asymp"
  774. try:
  775. try:
  776. ctx.prec += asymp_extraprec
  777. # http://functions.wolfram.com/HypergeometricFunctions/
  778. # Hypergeometric1F2/06/02/03/
  779. def h(a1,b1,b2):
  780. X = ctx.mpq_1_2*(a1-b1-b2+ctx.mpq_1_2)
  781. c = {}
  782. c[0] = ctx.one
  783. c[1] = 2*(ctx.mpq_1_4*(3*a1+b1+b2-2)*(a1-b1-b2)+b1*b2-ctx.mpq_3_16)
  784. c[2] = 2*(b1*b2+ctx.mpq_1_4*(a1-b1-b2)*(3*a1+b1+b2-2)-ctx.mpq_3_16)**2+\
  785. ctx.mpq_1_16*(-16*(2*a1-3)*b1*b2 + \
  786. 4*(a1-b1-b2)*(-8*a1**2+11*a1+b1+b2-2)-3)
  787. s1 = 0
  788. s2 = 0
  789. k = 0
  790. tprev = 0
  791. while 1:
  792. if k not in c:
  793. uu1 = (3*k**2+(-6*a1+2*b1+2*b2-4)*k + 3*a1**2 - \
  794. (b1-b2)**2 - 2*a1*(b1+b2-2) + ctx.mpq_1_4)
  795. uu2 = (k-a1+b1-b2-ctx.mpq_1_2)*(k-a1-b1+b2-ctx.mpq_1_2)*\
  796. (k-a1+b1+b2-ctx.mpq_5_2)
  797. c[k] = ctx.one/(2*k)*(uu1*c[k-1]-uu2*c[k-2])
  798. w = c[k] * (-z)**(-0.5*k)
  799. t1 = (-ctx.j)**k * ctx.mpf(2)**(-k) * w
  800. t2 = ctx.j**k * ctx.mpf(2)**(-k) * w
  801. if abs(t1) < 0.1*ctx.eps:
  802. #print "Convergence :)"
  803. break
  804. # Quit if the series doesn't converge quickly enough
  805. if k > 5 and abs(tprev) / abs(t1) < 1.5:
  806. #print "No convergence :("
  807. raise ctx.NoConvergence
  808. s1 += t1
  809. s2 += t2
  810. tprev = t1
  811. k += 1
  812. S = ctx.expj(ctx.pi*X+2*ctx.sqrt(-z))*s1 + \
  813. ctx.expj(-(ctx.pi*X+2*ctx.sqrt(-z)))*s2
  814. T1 = [0.5*S, ctx.pi, -z], [1, -0.5, X], [b1, b2], [a1],\
  815. [], [], 0
  816. T2 = [-z], [-a1], [b1,b2],[b1-a1,b2-a1], \
  817. [a1,a1-b1+1,a1-b2+1], [], 1/z
  818. return T1, T2
  819. v = ctx.hypercomb(h, [a1,b1,b2], force_series=True, maxterms=4*ctx.prec)
  820. if sum(ctx._is_real_type(u) for u in [a1,b1,b2,z]) == 4:
  821. v = ctx.re(v)
  822. return v
  823. except ctx.NoConvergence:
  824. pass
  825. finally:
  826. ctx.prec = orig
  827. #print "not using asymp"
  828. return ctx.hypsum(1, 2, (a1type, b1type, b2type), [a1, b1, b2], z, **kwargs)
  829. @defun
  830. def _hyp2f3(ctx, a_s, b_s, z, **kwargs):
  831. (a1, a1type), (a2, a2type) = a_s
  832. (b1, b1type), (b2, b2type), (b3, b3type) = b_s
  833. absz = abs(z)
  834. magz = ctx.mag(z)
  835. # Asymptotic expansion is ~ exp(sqrt(z))
  836. asymp_extraprec = z and magz//2
  837. orig = ctx.prec
  838. # Asymptotic series is in terms of 4F1
  839. # The square root below empirically provides a plausible criterion
  840. # for the leading series to converge
  841. can_use_asymptotic = (not kwargs.get('force_series')) and \
  842. (ctx.mag(absz) > 19) and (ctx.sqrt(absz) > 1.5*orig)
  843. if can_use_asymptotic:
  844. #print "using asymp"
  845. try:
  846. try:
  847. ctx.prec += asymp_extraprec
  848. # http://functions.wolfram.com/HypergeometricFunctions/
  849. # Hypergeometric2F3/06/02/03/01/0002/
  850. def h(a1,a2,b1,b2,b3):
  851. X = ctx.mpq_1_2*(a1+a2-b1-b2-b3+ctx.mpq_1_2)
  852. A2 = a1+a2
  853. B3 = b1+b2+b3
  854. A = a1*a2
  855. B = b1*b2+b3*b2+b1*b3
  856. R = b1*b2*b3
  857. c = {}
  858. c[0] = ctx.one
  859. c[1] = 2*(B - A + ctx.mpq_1_4*(3*A2+B3-2)*(A2-B3) - ctx.mpq_3_16)
  860. c[2] = ctx.mpq_1_2*c[1]**2 + ctx.mpq_1_16*(-16*(2*A2-3)*(B-A) + 32*R +\
  861. 4*(-8*A2**2 + 11*A2 + 8*A + B3 - 2)*(A2-B3)-3)
  862. s1 = 0
  863. s2 = 0
  864. k = 0
  865. tprev = 0
  866. while 1:
  867. if k not in c:
  868. uu1 = (k-2*X-3)*(k-2*X-2*b1-1)*(k-2*X-2*b2-1)*\
  869. (k-2*X-2*b3-1)
  870. uu2 = (4*(k-1)**3 - 6*(4*X+B3)*(k-1)**2 + \
  871. 2*(24*X**2+12*B3*X+4*B+B3-1)*(k-1) - 32*X**3 - \
  872. 24*B3*X**2 - 4*B - 8*R - 4*(4*B+B3-1)*X + 2*B3-1)
  873. uu3 = (5*(k-1)**2+2*(-10*X+A2-3*B3+3)*(k-1)+2*c[1])
  874. c[k] = ctx.one/(2*k)*(uu1*c[k-3]-uu2*c[k-2]+uu3*c[k-1])
  875. w = c[k] * ctx.power(-z, -0.5*k)
  876. t1 = (-ctx.j)**k * ctx.mpf(2)**(-k) * w
  877. t2 = ctx.j**k * ctx.mpf(2)**(-k) * w
  878. if abs(t1) < 0.1*ctx.eps:
  879. break
  880. # Quit if the series doesn't converge quickly enough
  881. if k > 5 and abs(tprev) / abs(t1) < 1.5:
  882. raise ctx.NoConvergence
  883. s1 += t1
  884. s2 += t2
  885. tprev = t1
  886. k += 1
  887. S = ctx.expj(ctx.pi*X+2*ctx.sqrt(-z))*s1 + \
  888. ctx.expj(-(ctx.pi*X+2*ctx.sqrt(-z)))*s2
  889. T1 = [0.5*S, ctx.pi, -z], [1, -0.5, X], [b1, b2, b3], [a1, a2],\
  890. [], [], 0
  891. T2 = [-z], [-a1], [b1,b2,b3,a2-a1],[a2,b1-a1,b2-a1,b3-a1], \
  892. [a1,a1-b1+1,a1-b2+1,a1-b3+1], [a1-a2+1], 1/z
  893. T3 = [-z], [-a2], [b1,b2,b3,a1-a2],[a1,b1-a2,b2-a2,b3-a2], \
  894. [a2,a2-b1+1,a2-b2+1,a2-b3+1],[-a1+a2+1], 1/z
  895. return T1, T2, T3
  896. v = ctx.hypercomb(h, [a1,a2,b1,b2,b3], force_series=True, maxterms=4*ctx.prec)
  897. if sum(ctx._is_real_type(u) for u in [a1,a2,b1,b2,b3,z]) == 6:
  898. v = ctx.re(v)
  899. return v
  900. except ctx.NoConvergence:
  901. pass
  902. finally:
  903. ctx.prec = orig
  904. return ctx.hypsum(2, 3, (a1type, a2type, b1type, b2type, b3type), [a1, a2, b1, b2, b3], z, **kwargs)
  905. @defun
  906. def _hyp2f0(ctx, a_s, b_s, z, **kwargs):
  907. (a, atype), (b, btype) = a_s
  908. # We want to try aggressively to use the asymptotic expansion,
  909. # and fall back only when absolutely necessary
  910. try:
  911. kwargsb = kwargs.copy()
  912. kwargsb['maxterms'] = kwargsb.get('maxterms', ctx.prec)
  913. return ctx.hypsum(2, 0, (atype,btype), [a,b], z, **kwargsb)
  914. except ctx.NoConvergence:
  915. if kwargs.get('force_series'):
  916. raise
  917. pass
  918. def h(a, b):
  919. w = ctx.sinpi(b)
  920. rz = -1/z
  921. T1 = ([ctx.pi,w,rz],[1,-1,a],[],[a-b+1,b],[a],[b],rz)
  922. T2 = ([-ctx.pi,w,rz],[1,-1,1+a-b],[],[a,2-b],[a-b+1],[2-b],rz)
  923. return T1, T2
  924. return ctx.hypercomb(h, [a, 1+a-b], **kwargs)
  925. @defun
  926. def meijerg(ctx, a_s, b_s, z, r=1, series=None, **kwargs):
  927. an, ap = a_s
  928. bm, bq = b_s
  929. n = len(an)
  930. p = n + len(ap)
  931. m = len(bm)
  932. q = m + len(bq)
  933. a = an+ap
  934. b = bm+bq
  935. a = [ctx.convert(_) for _ in a]
  936. b = [ctx.convert(_) for _ in b]
  937. z = ctx.convert(z)
  938. if series is None:
  939. if p < q: series = 1
  940. if p > q: series = 2
  941. if p == q:
  942. if m+n == p and abs(z) > 1:
  943. series = 2
  944. else:
  945. series = 1
  946. if kwargs.get('verbose'):
  947. print("Meijer G m,n,p,q,series =", m,n,p,q,series)
  948. if series == 1:
  949. def h(*args):
  950. a = args[:p]
  951. b = args[p:]
  952. terms = []
  953. for k in range(m):
  954. bases = [z]
  955. expts = [b[k]/r]
  956. gn = [b[j]-b[k] for j in range(m) if j != k]
  957. gn += [1-a[j]+b[k] for j in range(n)]
  958. gd = [a[j]-b[k] for j in range(n,p)]
  959. gd += [1-b[j]+b[k] for j in range(m,q)]
  960. hn = [1-a[j]+b[k] for j in range(p)]
  961. hd = [1-b[j]+b[k] for j in range(q) if j != k]
  962. hz = (-ctx.one)**(p-m-n) * z**(ctx.one/r)
  963. terms.append((bases, expts, gn, gd, hn, hd, hz))
  964. return terms
  965. else:
  966. def h(*args):
  967. a = args[:p]
  968. b = args[p:]
  969. terms = []
  970. for k in range(n):
  971. bases = [z]
  972. if r == 1:
  973. expts = [a[k]-1]
  974. else:
  975. expts = [(a[k]-1)/ctx.convert(r)]
  976. gn = [a[k]-a[j] for j in range(n) if j != k]
  977. gn += [1-a[k]+b[j] for j in range(m)]
  978. gd = [a[k]-b[j] for j in range(m,q)]
  979. gd += [1-a[k]+a[j] for j in range(n,p)]
  980. hn = [1-a[k]+b[j] for j in range(q)]
  981. hd = [1+a[j]-a[k] for j in range(p) if j != k]
  982. hz = (-ctx.one)**(q-m-n) / z**(ctx.one/r)
  983. terms.append((bases, expts, gn, gd, hn, hd, hz))
  984. return terms
  985. return ctx.hypercomb(h, a+b, **kwargs)
  986. @defun_wrapped
  987. def appellf1(ctx,a,b1,b2,c,x,y,**kwargs):
  988. # Assume x smaller
  989. # We will use x for the outer loop
  990. if abs(x) > abs(y):
  991. x, y = y, x
  992. b1, b2 = b2, b1
  993. def ok(x):
  994. return abs(x) < 0.99
  995. # Finite cases
  996. if ctx.isnpint(a):
  997. pass
  998. elif ctx.isnpint(b1):
  999. pass
  1000. elif ctx.isnpint(b2):
  1001. x, y, b1, b2 = y, x, b2, b1
  1002. else:
  1003. #print x, y
  1004. # Note: ok if |y| > 1, because
  1005. # 2F1 implements analytic continuation
  1006. if not ok(x):
  1007. u1 = (x-y)/(x-1)
  1008. if not ok(u1):
  1009. raise ValueError("Analytic continuation not implemented")
  1010. #print "Using analytic continuation"
  1011. return (1-x)**(-b1)*(1-y)**(c-a-b2)*\
  1012. ctx.appellf1(c-a,b1,c-b1-b2,c,u1,y,**kwargs)
  1013. return ctx.hyper2d({'m+n':[a],'m':[b1],'n':[b2]}, {'m+n':[c]}, x,y, **kwargs)
  1014. @defun
  1015. def appellf2(ctx,a,b1,b2,c1,c2,x,y,**kwargs):
  1016. # TODO: continuation
  1017. return ctx.hyper2d({'m+n':[a],'m':[b1],'n':[b2]},
  1018. {'m':[c1],'n':[c2]}, x,y, **kwargs)
  1019. @defun
  1020. def appellf3(ctx,a1,a2,b1,b2,c,x,y,**kwargs):
  1021. outer_polynomial = ctx.isnpint(a1) or ctx.isnpint(b1)
  1022. inner_polynomial = ctx.isnpint(a2) or ctx.isnpint(b2)
  1023. if not outer_polynomial:
  1024. if inner_polynomial or abs(x) > abs(y):
  1025. x, y = y, x
  1026. a1,a2,b1,b2 = a2,a1,b2,b1
  1027. return ctx.hyper2d({'m':[a1,b1],'n':[a2,b2]}, {'m+n':[c]},x,y,**kwargs)
  1028. @defun
  1029. def appellf4(ctx,a,b,c1,c2,x,y,**kwargs):
  1030. # TODO: continuation
  1031. return ctx.hyper2d({'m+n':[a,b]}, {'m':[c1],'n':[c2]},x,y,**kwargs)
  1032. @defun
  1033. def hyper2d(ctx, a, b, x, y, **kwargs):
  1034. r"""
  1035. Sums the generalized 2D hypergeometric series
  1036. .. math ::
  1037. \sum_{m=0}^{\infty} \sum_{n=0}^{\infty}
  1038. \frac{P((a),m,n)}{Q((b),m,n)}
  1039. \frac{x^m y^n} {m! n!}
  1040. where `(a) = (a_1,\ldots,a_r)`, `(b) = (b_1,\ldots,b_s)` and where
  1041. `P` and `Q` are products of rising factorials such as `(a_j)_n` or
  1042. `(a_j)_{m+n}`. `P` and `Q` are specified in the form of dicts, with
  1043. the `m` and `n` dependence as keys and parameter lists as values.
  1044. The supported rising factorials are given in the following table
  1045. (note that only a few are supported in `Q`):
  1046. +------------+-------------------+--------+
  1047. | Key | Rising factorial | `Q` |
  1048. +============+===================+========+
  1049. | ``'m'`` | `(a_j)_m` | Yes |
  1050. +------------+-------------------+--------+
  1051. | ``'n'`` | `(a_j)_n` | Yes |
  1052. +------------+-------------------+--------+
  1053. | ``'m+n'`` | `(a_j)_{m+n}` | Yes |
  1054. +------------+-------------------+--------+
  1055. | ``'m-n'`` | `(a_j)_{m-n}` | No |
  1056. +------------+-------------------+--------+
  1057. | ``'n-m'`` | `(a_j)_{n-m}` | No |
  1058. +------------+-------------------+--------+
  1059. | ``'2m+n'`` | `(a_j)_{2m+n}` | No |
  1060. +------------+-------------------+--------+
  1061. | ``'2m-n'`` | `(a_j)_{2m-n}` | No |
  1062. +------------+-------------------+--------+
  1063. | ``'2n-m'`` | `(a_j)_{2n-m}` | No |
  1064. +------------+-------------------+--------+
  1065. For example, the Appell F1 and F4 functions
  1066. .. math ::
  1067. F_1 = \sum_{m=0}^{\infty} \sum_{n=0}^{\infty}
  1068. \frac{(a)_{m+n} (b)_m (c)_n}{(d)_{m+n}}
  1069. \frac{x^m y^n}{m! n!}
  1070. F_4 = \sum_{m=0}^{\infty} \sum_{n=0}^{\infty}
  1071. \frac{(a)_{m+n} (b)_{m+n}}{(c)_m (d)_{n}}
  1072. \frac{x^m y^n}{m! n!}
  1073. can be represented respectively as
  1074. ``hyper2d({'m+n':[a], 'm':[b], 'n':[c]}, {'m+n':[d]}, x, y)``
  1075. ``hyper2d({'m+n':[a,b]}, {'m':[c], 'n':[d]}, x, y)``
  1076. More generally, :func:`~mpmath.hyper2d` can evaluate any of the 34 distinct
  1077. convergent second-order (generalized Gaussian) hypergeometric
  1078. series enumerated by Horn, as well as the Kampe de Feriet
  1079. function.
  1080. The series is computed by rewriting it so that the inner
  1081. series (i.e. the series containing `n` and `y`) has the form of an
  1082. ordinary generalized hypergeometric series and thereby can be
  1083. evaluated efficiently using :func:`~mpmath.hyper`. If possible,
  1084. manually swapping `x` and `y` and the corresponding parameters
  1085. can sometimes give better results.
  1086. **Examples**
  1087. Two separable cases: a product of two geometric series, and a
  1088. product of two Gaussian hypergeometric functions::
  1089. >>> from mpmath import *
  1090. >>> mp.dps = 25; mp.pretty = True
  1091. >>> x, y = mpf(0.25), mpf(0.5)
  1092. >>> hyper2d({'m':1,'n':1}, {}, x,y)
  1093. 2.666666666666666666666667
  1094. >>> 1/(1-x)/(1-y)
  1095. 2.666666666666666666666667
  1096. >>> hyper2d({'m':[1,2],'n':[3,4]}, {'m':[5],'n':[6]}, x,y)
  1097. 4.164358531238938319669856
  1098. >>> hyp2f1(1,2,5,x)*hyp2f1(3,4,6,y)
  1099. 4.164358531238938319669856
  1100. Some more series that can be done in closed form::
  1101. >>> hyper2d({'m':1,'n':1},{'m+n':1},x,y)
  1102. 2.013417124712514809623881
  1103. >>> (exp(x)*x-exp(y)*y)/(x-y)
  1104. 2.013417124712514809623881
  1105. Six of the 34 Horn functions, G1-G3 and H1-H3::
  1106. >>> from mpmath import *
  1107. >>> mp.dps = 10; mp.pretty = True
  1108. >>> x, y = 0.0625, 0.125
  1109. >>> a1,a2,b1,b2,c1,c2,d = 1.1,-1.2,-1.3,-1.4,1.5,-1.6,1.7
  1110. >>> hyper2d({'m+n':a1,'n-m':b1,'m-n':b2},{},x,y) # G1
  1111. 1.139090746
  1112. >>> nsum(lambda m,n: rf(a1,m+n)*rf(b1,n-m)*rf(b2,m-n)*\
  1113. ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf])
  1114. 1.139090746
  1115. >>> hyper2d({'m':a1,'n':a2,'n-m':b1,'m-n':b2},{},x,y) # G2
  1116. 0.9503682696
  1117. >>> nsum(lambda m,n: rf(a1,m)*rf(a2,n)*rf(b1,n-m)*rf(b2,m-n)*\
  1118. ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf])
  1119. 0.9503682696
  1120. >>> hyper2d({'2n-m':a1,'2m-n':a2},{},x,y) # G3
  1121. 1.029372029
  1122. >>> nsum(lambda m,n: rf(a1,2*n-m)*rf(a2,2*m-n)*\
  1123. ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf])
  1124. 1.029372029
  1125. >>> hyper2d({'m-n':a1,'m+n':b1,'n':c1},{'m':d},x,y) # H1
  1126. -1.605331256
  1127. >>> nsum(lambda m,n: rf(a1,m-n)*rf(b1,m+n)*rf(c1,n)/rf(d,m)*\
  1128. ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf])
  1129. -1.605331256
  1130. >>> hyper2d({'m-n':a1,'m':b1,'n':[c1,c2]},{'m':d},x,y) # H2
  1131. -2.35405404
  1132. >>> nsum(lambda m,n: rf(a1,m-n)*rf(b1,m)*rf(c1,n)*rf(c2,n)/rf(d,m)*\
  1133. ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf])
  1134. -2.35405404
  1135. >>> hyper2d({'2m+n':a1,'n':b1},{'m+n':c1},x,y) # H3
  1136. 0.974479074
  1137. >>> nsum(lambda m,n: rf(a1,2*m+n)*rf(b1,n)/rf(c1,m+n)*\
  1138. ... x**m*y**n/fac(m)/fac(n), [0,inf], [0,inf])
  1139. 0.974479074
  1140. **References**
  1141. 1. [SrivastavaKarlsson]_
  1142. 2. [Weisstein]_ http://mathworld.wolfram.com/HornFunction.html
  1143. 3. [Weisstein]_ http://mathworld.wolfram.com/AppellHypergeometricFunction.html
  1144. """
  1145. x = ctx.convert(x)
  1146. y = ctx.convert(y)
  1147. def parse(dct, key):
  1148. args = dct.pop(key, [])
  1149. try:
  1150. args = list(args)
  1151. except TypeError:
  1152. args = [args]
  1153. return [ctx.convert(arg) for arg in args]
  1154. a_s = dict(a)
  1155. b_s = dict(b)
  1156. a_m = parse(a, 'm')
  1157. a_n = parse(a, 'n')
  1158. a_m_add_n = parse(a, 'm+n')
  1159. a_m_sub_n = parse(a, 'm-n')
  1160. a_n_sub_m = parse(a, 'n-m')
  1161. a_2m_add_n = parse(a, '2m+n')
  1162. a_2m_sub_n = parse(a, '2m-n')
  1163. a_2n_sub_m = parse(a, '2n-m')
  1164. b_m = parse(b, 'm')
  1165. b_n = parse(b, 'n')
  1166. b_m_add_n = parse(b, 'm+n')
  1167. if a: raise ValueError("unsupported key: %r" % a.keys()[0])
  1168. if b: raise ValueError("unsupported key: %r" % b.keys()[0])
  1169. s = 0
  1170. outer = ctx.one
  1171. m = ctx.mpf(0)
  1172. ok_count = 0
  1173. prec = ctx.prec
  1174. maxterms = kwargs.get('maxterms', 20*prec)
  1175. try:
  1176. ctx.prec += 10
  1177. tol = +ctx.eps
  1178. while 1:
  1179. inner_sign = 1
  1180. outer_sign = 1
  1181. inner_a = list(a_n)
  1182. inner_b = list(b_n)
  1183. outer_a = [a+m for a in a_m]
  1184. outer_b = [b+m for b in b_m]
  1185. # (a)_{m+n} = (a)_m (a+m)_n
  1186. for a in a_m_add_n:
  1187. a = a+m
  1188. inner_a.append(a)
  1189. outer_a.append(a)
  1190. # (b)_{m+n} = (b)_m (b+m)_n
  1191. for b in b_m_add_n:
  1192. b = b+m
  1193. inner_b.append(b)
  1194. outer_b.append(b)
  1195. # (a)_{n-m} = (a-m)_n / (a-m)_m
  1196. for a in a_n_sub_m:
  1197. inner_a.append(a-m)
  1198. outer_b.append(a-m-1)
  1199. # (a)_{m-n} = (-1)^(m+n) (1-a-m)_m / (1-a-m)_n
  1200. for a in a_m_sub_n:
  1201. inner_sign *= (-1)
  1202. outer_sign *= (-1)**(m)
  1203. inner_b.append(1-a-m)
  1204. outer_a.append(-a-m)
  1205. # (a)_{2m+n} = (a)_{2m} (a+2m)_n
  1206. for a in a_2m_add_n:
  1207. inner_a.append(a+2*m)
  1208. outer_a.append((a+2*m)*(1+a+2*m))
  1209. # (a)_{2m-n} = (-1)^(2m+n) (1-a-2m)_{2m} / (1-a-2m)_n
  1210. for a in a_2m_sub_n:
  1211. inner_sign *= (-1)
  1212. inner_b.append(1-a-2*m)
  1213. outer_a.append((a+2*m)*(1+a+2*m))
  1214. # (a)_{2n-m} = 4^n ((a-m)/2)_n ((a-m+1)/2)_n / (a-m)_m
  1215. for a in a_2n_sub_m:
  1216. inner_sign *= 4
  1217. inner_a.append(0.5*(a-m))
  1218. inner_a.append(0.5*(a-m+1))
  1219. outer_b.append(a-m-1)
  1220. inner = ctx.hyper(inner_a, inner_b, inner_sign*y,
  1221. zeroprec=ctx.prec, **kwargs)
  1222. term = outer * inner * outer_sign
  1223. if abs(term) < tol:
  1224. ok_count += 1
  1225. else:
  1226. ok_count = 0
  1227. if ok_count >= 3 or not outer:
  1228. break
  1229. s += term
  1230. for a in outer_a: outer *= a
  1231. for b in outer_b: outer /= b
  1232. m += 1
  1233. outer = outer * x / m
  1234. if m > maxterms:
  1235. raise ctx.NoConvergence("maxterms exceeded in hyper2d")
  1236. finally:
  1237. ctx.prec = prec
  1238. return +s
  1239. """
  1240. @defun
  1241. def kampe_de_feriet(ctx,a,b,c,d,e,f,x,y,**kwargs):
  1242. return ctx.hyper2d({'m+n':a,'m':b,'n':c},
  1243. {'m+n':d,'m':e,'n':f}, x,y, **kwargs)
  1244. """
  1245. @defun
  1246. def bihyper(ctx, a_s, b_s, z, **kwargs):
  1247. r"""
  1248. Evaluates the bilateral hypergeometric series
  1249. .. math ::
  1250. \,_AH_B(a_1, \ldots, a_k; b_1, \ldots, b_B; z) =
  1251. \sum_{n=-\infty}^{\infty}
  1252. \frac{(a_1)_n \ldots (a_A)_n}
  1253. {(b_1)_n \ldots (b_B)_n} \, z^n
  1254. where, for direct convergence, `A = B` and `|z| = 1`, although a
  1255. regularized sum exists more generally by considering the
  1256. bilateral series as a sum of two ordinary hypergeometric
  1257. functions. In order for the series to make sense, none of the
  1258. parameters may be integers.
  1259. **Examples**
  1260. The value of `\,_2H_2` at `z = 1` is given by Dougall's formula::
  1261. >>> from mpmath import *
  1262. >>> mp.dps = 25; mp.pretty = True
  1263. >>> a,b,c,d = 0.5, 1.5, 2.25, 3.25
  1264. >>> bihyper([a,b],[c,d],1)
  1265. -14.49118026212345786148847
  1266. >>> gammaprod([c,d,1-a,1-b,c+d-a-b-1],[c-a,d-a,c-b,d-b])
  1267. -14.49118026212345786148847
  1268. The regularized function `\,_1H_0` can be expressed as the
  1269. sum of one `\,_2F_0` function and one `\,_1F_1` function::
  1270. >>> a = mpf(0.25)
  1271. >>> z = mpf(0.75)
  1272. >>> bihyper([a], [], z)
  1273. (0.2454393389657273841385582 + 0.2454393389657273841385582j)
  1274. >>> hyper([a,1],[],z) + (hyper([1],[1-a],-1/z)-1)
  1275. (0.2454393389657273841385582 + 0.2454393389657273841385582j)
  1276. >>> hyper([a,1],[],z) + hyper([1],[2-a],-1/z)/z/(a-1)
  1277. (0.2454393389657273841385582 + 0.2454393389657273841385582j)
  1278. **References**
  1279. 1. [Slater]_ (chapter 6: "Bilateral Series", pp. 180-189)
  1280. 2. [Wikipedia]_ http://en.wikipedia.org/wiki/Bilateral_hypergeometric_series
  1281. """
  1282. z = ctx.convert(z)
  1283. c_s = a_s + b_s
  1284. p = len(a_s)
  1285. q = len(b_s)
  1286. if (p, q) == (0,0) or (p, q) == (1,1):
  1287. return ctx.zero * z
  1288. neg = (p-q) % 2
  1289. def h(*c_s):
  1290. a_s = list(c_s[:p])
  1291. b_s = list(c_s[p:])
  1292. aa_s = [2-b for b in b_s]
  1293. bb_s = [2-a for a in a_s]
  1294. rp = [(-1)**neg * z] + [1-b for b in b_s] + [1-a for a in a_s]
  1295. rc = [-1] + [1]*len(b_s) + [-1]*len(a_s)
  1296. T1 = [], [], [], [], a_s + [1], b_s, z
  1297. T2 = rp, rc, [], [], aa_s + [1], bb_s, (-1)**neg / z
  1298. return T1, T2
  1299. return ctx.hypercomb(h, c_s, **kwargs)