ring_series.py 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025
  1. """Power series evaluation and manipulation using sparse Polynomials
  2. Implementing a new function
  3. ---------------------------
  4. There are a few things to be kept in mind when adding a new function here::
  5. - The implementation should work on all possible input domains/rings.
  6. Special cases include the ``EX`` ring and a constant term in the series
  7. to be expanded. There can be two types of constant terms in the series:
  8. + A constant value or symbol.
  9. + A term of a multivariate series not involving the generator, with
  10. respect to which the series is to expanded.
  11. Strictly speaking, a generator of a ring should not be considered a
  12. constant. However, for series expansion both the cases need similar
  13. treatment (as the user doesn't care about inner details), i.e, use an
  14. addition formula to separate the constant part and the variable part (see
  15. rs_sin for reference).
  16. - All the algorithms used here are primarily designed to work for Taylor
  17. series (number of iterations in the algo equals the required order).
  18. Hence, it becomes tricky to get the series of the right order if a
  19. Puiseux series is input. Use rs_puiseux? in your function if your
  20. algorithm is not designed to handle fractional powers.
  21. Extending rs_series
  22. -------------------
  23. To make a function work with rs_series you need to do two things::
  24. - Many sure it works with a constant term (as explained above).
  25. - If the series contains constant terms, you might need to extend its ring.
  26. You do so by adding the new terms to the rings as generators.
  27. ``PolyRing.compose`` and ``PolyRing.add_gens`` are two functions that do
  28. so and need to be called every time you expand a series containing a
  29. constant term.
  30. Look at rs_sin and rs_series for further reference.
  31. """
  32. from sympy.polys.domains import QQ, EX
  33. from sympy.polys.rings import PolyElement, ring, sring
  34. from sympy.polys.polyerrors import DomainError
  35. from sympy.polys.monomials import (monomial_min, monomial_mul, monomial_div,
  36. monomial_ldiv)
  37. from mpmath.libmp.libintmath import ifac
  38. from sympy.core import PoleError, Function, Expr
  39. from sympy.core.numbers import Rational, igcd
  40. from sympy.functions import sin, cos, tan, atan, exp, atanh, tanh, log, ceiling
  41. from sympy.utilities.misc import as_int
  42. from mpmath.libmp.libintmath import giant_steps
  43. import math
  44. def _invert_monoms(p1):
  45. """
  46. Compute ``x**n * p1(1/x)`` for a univariate polynomial ``p1`` in ``x``.
  47. Examples
  48. ========
  49. >>> from sympy.polys.domains import ZZ
  50. >>> from sympy.polys.rings import ring
  51. >>> from sympy.polys.ring_series import _invert_monoms
  52. >>> R, x = ring('x', ZZ)
  53. >>> p = x**2 + 2*x + 3
  54. >>> _invert_monoms(p)
  55. 3*x**2 + 2*x + 1
  56. See Also
  57. ========
  58. sympy.polys.densebasic.dup_reverse
  59. """
  60. terms = list(p1.items())
  61. terms.sort()
  62. deg = p1.degree()
  63. R = p1.ring
  64. p = R.zero
  65. cv = p1.listcoeffs()
  66. mv = p1.listmonoms()
  67. for i in range(len(mv)):
  68. p[(deg - mv[i][0],)] = cv[i]
  69. return p
  70. def _giant_steps(target):
  71. """Return a list of precision steps for the Newton's method"""
  72. res = giant_steps(2, target)
  73. if res[0] != 2:
  74. res = [2] + res
  75. return res
  76. def rs_trunc(p1, x, prec):
  77. """
  78. Truncate the series in the ``x`` variable with precision ``prec``,
  79. that is, modulo ``O(x**prec)``
  80. Examples
  81. ========
  82. >>> from sympy.polys.domains import QQ
  83. >>> from sympy.polys.rings import ring
  84. >>> from sympy.polys.ring_series import rs_trunc
  85. >>> R, x = ring('x', QQ)
  86. >>> p = x**10 + x**5 + x + 1
  87. >>> rs_trunc(p, x, 12)
  88. x**10 + x**5 + x + 1
  89. >>> rs_trunc(p, x, 10)
  90. x**5 + x + 1
  91. """
  92. R = p1.ring
  93. p = R.zero
  94. i = R.gens.index(x)
  95. for exp1 in p1:
  96. if exp1[i] >= prec:
  97. continue
  98. p[exp1] = p1[exp1]
  99. return p
  100. def rs_is_puiseux(p, x):
  101. """
  102. Test if ``p`` is Puiseux series in ``x``.
  103. Raise an exception if it has a negative power in ``x``.
  104. Examples
  105. ========
  106. >>> from sympy.polys.domains import QQ
  107. >>> from sympy.polys.rings import ring
  108. >>> from sympy.polys.ring_series import rs_is_puiseux
  109. >>> R, x = ring('x', QQ)
  110. >>> p = x**QQ(2,5) + x**QQ(2,3) + x
  111. >>> rs_is_puiseux(p, x)
  112. True
  113. """
  114. index = p.ring.gens.index(x)
  115. for k in p:
  116. if k[index] != int(k[index]):
  117. return True
  118. if k[index] < 0:
  119. raise ValueError('The series is not regular in %s' % x)
  120. return False
  121. def rs_puiseux(f, p, x, prec):
  122. """
  123. Return the puiseux series for `f(p, x, prec)`.
  124. To be used when function ``f`` is implemented only for regular series.
  125. Examples
  126. ========
  127. >>> from sympy.polys.domains import QQ
  128. >>> from sympy.polys.rings import ring
  129. >>> from sympy.polys.ring_series import rs_puiseux, rs_exp
  130. >>> R, x = ring('x', QQ)
  131. >>> p = x**QQ(2,5) + x**QQ(2,3) + x
  132. >>> rs_puiseux(rs_exp,p, x, 1)
  133. 1/2*x**(4/5) + x**(2/3) + x**(2/5) + 1
  134. """
  135. index = p.ring.gens.index(x)
  136. n = 1
  137. for k in p:
  138. power = k[index]
  139. if isinstance(power, Rational):
  140. num, den = power.as_numer_denom()
  141. n = int(n*den // igcd(n, den))
  142. elif power != int(power):
  143. den = power.denominator
  144. n = int(n*den // igcd(n, den))
  145. if n != 1:
  146. p1 = pow_xin(p, index, n)
  147. r = f(p1, x, prec*n)
  148. n1 = QQ(1, n)
  149. if isinstance(r, tuple):
  150. r = tuple([pow_xin(rx, index, n1) for rx in r])
  151. else:
  152. r = pow_xin(r, index, n1)
  153. else:
  154. r = f(p, x, prec)
  155. return r
  156. def rs_puiseux2(f, p, q, x, prec):
  157. """
  158. Return the puiseux series for `f(p, q, x, prec)`.
  159. To be used when function ``f`` is implemented only for regular series.
  160. """
  161. index = p.ring.gens.index(x)
  162. n = 1
  163. for k in p:
  164. power = k[index]
  165. if isinstance(power, Rational):
  166. num, den = power.as_numer_denom()
  167. n = n*den // igcd(n, den)
  168. elif power != int(power):
  169. den = power.denominator
  170. n = n*den // igcd(n, den)
  171. if n != 1:
  172. p1 = pow_xin(p, index, n)
  173. r = f(p1, q, x, prec*n)
  174. n1 = QQ(1, n)
  175. r = pow_xin(r, index, n1)
  176. else:
  177. r = f(p, q, x, prec)
  178. return r
  179. def rs_mul(p1, p2, x, prec):
  180. """
  181. Return the product of the given two series, modulo ``O(x**prec)``.
  182. ``x`` is the series variable or its position in the generators.
  183. Examples
  184. ========
  185. >>> from sympy.polys.domains import QQ
  186. >>> from sympy.polys.rings import ring
  187. >>> from sympy.polys.ring_series import rs_mul
  188. >>> R, x = ring('x', QQ)
  189. >>> p1 = x**2 + 2*x + 1
  190. >>> p2 = x + 1
  191. >>> rs_mul(p1, p2, x, 3)
  192. 3*x**2 + 3*x + 1
  193. """
  194. R = p1.ring
  195. p = R.zero
  196. if R.__class__ != p2.ring.__class__ or R != p2.ring:
  197. raise ValueError('p1 and p2 must have the same ring')
  198. iv = R.gens.index(x)
  199. if not isinstance(p2, PolyElement):
  200. raise ValueError('p1 and p2 must have the same ring')
  201. if R == p2.ring:
  202. get = p.get
  203. items2 = list(p2.items())
  204. items2.sort(key=lambda e: e[0][iv])
  205. if R.ngens == 1:
  206. for exp1, v1 in p1.items():
  207. for exp2, v2 in items2:
  208. exp = exp1[0] + exp2[0]
  209. if exp < prec:
  210. exp = (exp, )
  211. p[exp] = get(exp, 0) + v1*v2
  212. else:
  213. break
  214. else:
  215. monomial_mul = R.monomial_mul
  216. for exp1, v1 in p1.items():
  217. for exp2, v2 in items2:
  218. if exp1[iv] + exp2[iv] < prec:
  219. exp = monomial_mul(exp1, exp2)
  220. p[exp] = get(exp, 0) + v1*v2
  221. else:
  222. break
  223. p.strip_zero()
  224. return p
  225. def rs_square(p1, x, prec):
  226. """
  227. Square the series modulo ``O(x**prec)``
  228. Examples
  229. ========
  230. >>> from sympy.polys.domains import QQ
  231. >>> from sympy.polys.rings import ring
  232. >>> from sympy.polys.ring_series import rs_square
  233. >>> R, x = ring('x', QQ)
  234. >>> p = x**2 + 2*x + 1
  235. >>> rs_square(p, x, 3)
  236. 6*x**2 + 4*x + 1
  237. """
  238. R = p1.ring
  239. p = R.zero
  240. iv = R.gens.index(x)
  241. get = p.get
  242. items = list(p1.items())
  243. items.sort(key=lambda e: e[0][iv])
  244. monomial_mul = R.monomial_mul
  245. for i in range(len(items)):
  246. exp1, v1 = items[i]
  247. for j in range(i):
  248. exp2, v2 = items[j]
  249. if exp1[iv] + exp2[iv] < prec:
  250. exp = monomial_mul(exp1, exp2)
  251. p[exp] = get(exp, 0) + v1*v2
  252. else:
  253. break
  254. p = p.imul_num(2)
  255. get = p.get
  256. for expv, v in p1.items():
  257. if 2*expv[iv] < prec:
  258. e2 = monomial_mul(expv, expv)
  259. p[e2] = get(e2, 0) + v**2
  260. p.strip_zero()
  261. return p
  262. def rs_pow(p1, n, x, prec):
  263. """
  264. Return ``p1**n`` modulo ``O(x**prec)``
  265. Examples
  266. ========
  267. >>> from sympy.polys.domains import QQ
  268. >>> from sympy.polys.rings import ring
  269. >>> from sympy.polys.ring_series import rs_pow
  270. >>> R, x = ring('x', QQ)
  271. >>> p = x + 1
  272. >>> rs_pow(p, 4, x, 3)
  273. 6*x**2 + 4*x + 1
  274. """
  275. R = p1.ring
  276. if isinstance(n, Rational):
  277. np = int(n.p)
  278. nq = int(n.q)
  279. if nq != 1:
  280. res = rs_nth_root(p1, nq, x, prec)
  281. if np != 1:
  282. res = rs_pow(res, np, x, prec)
  283. else:
  284. res = rs_pow(p1, np, x, prec)
  285. return res
  286. n = as_int(n)
  287. if n == 0:
  288. if p1:
  289. return R(1)
  290. else:
  291. raise ValueError('0**0 is undefined')
  292. if n < 0:
  293. p1 = rs_pow(p1, -n, x, prec)
  294. return rs_series_inversion(p1, x, prec)
  295. if n == 1:
  296. return rs_trunc(p1, x, prec)
  297. if n == 2:
  298. return rs_square(p1, x, prec)
  299. if n == 3:
  300. p2 = rs_square(p1, x, prec)
  301. return rs_mul(p1, p2, x, prec)
  302. p = R(1)
  303. while 1:
  304. if n & 1:
  305. p = rs_mul(p1, p, x, prec)
  306. n -= 1
  307. if not n:
  308. break
  309. p1 = rs_square(p1, x, prec)
  310. n = n // 2
  311. return p
  312. def rs_subs(p, rules, x, prec):
  313. """
  314. Substitution with truncation according to the mapping in ``rules``.
  315. Return a series with precision ``prec`` in the generator ``x``
  316. Note that substitutions are not done one after the other
  317. >>> from sympy.polys.domains import QQ
  318. >>> from sympy.polys.rings import ring
  319. >>> from sympy.polys.ring_series import rs_subs
  320. >>> R, x, y = ring('x, y', QQ)
  321. >>> p = x**2 + y**2
  322. >>> rs_subs(p, {x: x+ y, y: x+ 2*y}, x, 3)
  323. 2*x**2 + 6*x*y + 5*y**2
  324. >>> (x + y)**2 + (x + 2*y)**2
  325. 2*x**2 + 6*x*y + 5*y**2
  326. which differs from
  327. >>> rs_subs(rs_subs(p, {x: x+ y}, x, 3), {y: x+ 2*y}, x, 3)
  328. 5*x**2 + 12*x*y + 8*y**2
  329. Parameters
  330. ----------
  331. p : :class:`~.PolyElement` Input series.
  332. rules : ``dict`` with substitution mappings.
  333. x : :class:`~.PolyElement` in which the series truncation is to be done.
  334. prec : :class:`~.Integer` order of the series after truncation.
  335. Examples
  336. ========
  337. >>> from sympy.polys.domains import QQ
  338. >>> from sympy.polys.rings import ring
  339. >>> from sympy.polys.ring_series import rs_subs
  340. >>> R, x, y = ring('x, y', QQ)
  341. >>> rs_subs(x**2+y**2, {y: (x+y)**2}, x, 3)
  342. 6*x**2*y**2 + x**2 + 4*x*y**3 + y**4
  343. """
  344. R = p.ring
  345. ngens = R.ngens
  346. d = R(0)
  347. for i in range(ngens):
  348. d[(i, 1)] = R.gens[i]
  349. for var in rules:
  350. d[(R.index(var), 1)] = rules[var]
  351. p1 = R(0)
  352. p_keys = sorted(p.keys())
  353. for expv in p_keys:
  354. p2 = R(1)
  355. for i in range(ngens):
  356. power = expv[i]
  357. if power == 0:
  358. continue
  359. if (i, power) not in d:
  360. q, r = divmod(power, 2)
  361. if r == 0 and (i, q) in d:
  362. d[(i, power)] = rs_square(d[(i, q)], x, prec)
  363. elif (i, power - 1) in d:
  364. d[(i, power)] = rs_mul(d[(i, power - 1)], d[(i, 1)],
  365. x, prec)
  366. else:
  367. d[(i, power)] = rs_pow(d[(i, 1)], power, x, prec)
  368. p2 = rs_mul(p2, d[(i, power)], x, prec)
  369. p1 += p2*p[expv]
  370. return p1
  371. def _has_constant_term(p, x):
  372. """
  373. Check if ``p`` has a constant term in ``x``
  374. Examples
  375. ========
  376. >>> from sympy.polys.domains import QQ
  377. >>> from sympy.polys.rings import ring
  378. >>> from sympy.polys.ring_series import _has_constant_term
  379. >>> R, x = ring('x', QQ)
  380. >>> p = x**2 + x + 1
  381. >>> _has_constant_term(p, x)
  382. True
  383. """
  384. R = p.ring
  385. iv = R.gens.index(x)
  386. zm = R.zero_monom
  387. a = [0]*R.ngens
  388. a[iv] = 1
  389. miv = tuple(a)
  390. for expv in p:
  391. if monomial_min(expv, miv) == zm:
  392. return True
  393. return False
  394. def _get_constant_term(p, x):
  395. """Return constant term in p with respect to x
  396. Note that it is not simply `p[R.zero_monom]` as there might be multiple
  397. generators in the ring R. We want the `x`-free term which can contain other
  398. generators.
  399. """
  400. R = p.ring
  401. i = R.gens.index(x)
  402. zm = R.zero_monom
  403. a = [0]*R.ngens
  404. a[i] = 1
  405. miv = tuple(a)
  406. c = 0
  407. for expv in p:
  408. if monomial_min(expv, miv) == zm:
  409. c += R({expv: p[expv]})
  410. return c
  411. def _check_series_var(p, x, name):
  412. index = p.ring.gens.index(x)
  413. m = min(p, key=lambda k: k[index])[index]
  414. if m < 0:
  415. raise PoleError("Asymptotic expansion of %s around [oo] not "
  416. "implemented." % name)
  417. return index, m
  418. def _series_inversion1(p, x, prec):
  419. """
  420. Univariate series inversion ``1/p`` modulo ``O(x**prec)``.
  421. The Newton method is used.
  422. Examples
  423. ========
  424. >>> from sympy.polys.domains import QQ
  425. >>> from sympy.polys.rings import ring
  426. >>> from sympy.polys.ring_series import _series_inversion1
  427. >>> R, x = ring('x', QQ)
  428. >>> p = x + 1
  429. >>> _series_inversion1(p, x, 4)
  430. -x**3 + x**2 - x + 1
  431. """
  432. if rs_is_puiseux(p, x):
  433. return rs_puiseux(_series_inversion1, p, x, prec)
  434. R = p.ring
  435. zm = R.zero_monom
  436. c = p[zm]
  437. # giant_steps does not seem to work with PythonRational numbers with 1 as
  438. # denominator. This makes sure such a number is converted to integer.
  439. if prec == int(prec):
  440. prec = int(prec)
  441. if zm not in p:
  442. raise ValueError("No constant term in series")
  443. if _has_constant_term(p - c, x):
  444. raise ValueError("p cannot contain a constant term depending on "
  445. "parameters")
  446. one = R(1)
  447. if R.domain is EX:
  448. one = 1
  449. if c != one:
  450. # TODO add check that it is a unit
  451. p1 = R(1)/c
  452. else:
  453. p1 = R(1)
  454. for precx in _giant_steps(prec):
  455. t = 1 - rs_mul(p1, p, x, precx)
  456. p1 = p1 + rs_mul(p1, t, x, precx)
  457. return p1
  458. def rs_series_inversion(p, x, prec):
  459. """
  460. Multivariate series inversion ``1/p`` modulo ``O(x**prec)``.
  461. Examples
  462. ========
  463. >>> from sympy.polys.domains import QQ
  464. >>> from sympy.polys.rings import ring
  465. >>> from sympy.polys.ring_series import rs_series_inversion
  466. >>> R, x, y = ring('x, y', QQ)
  467. >>> rs_series_inversion(1 + x*y**2, x, 4)
  468. -x**3*y**6 + x**2*y**4 - x*y**2 + 1
  469. >>> rs_series_inversion(1 + x*y**2, y, 4)
  470. -x*y**2 + 1
  471. >>> rs_series_inversion(x + x**2, x, 4)
  472. x**3 - x**2 + x - 1 + x**(-1)
  473. """
  474. R = p.ring
  475. if p == R.zero:
  476. raise ZeroDivisionError
  477. zm = R.zero_monom
  478. index = R.gens.index(x)
  479. m = min(p, key=lambda k: k[index])[index]
  480. if m:
  481. p = mul_xin(p, index, -m)
  482. prec = prec + m
  483. if zm not in p:
  484. raise NotImplementedError("No constant term in series")
  485. if _has_constant_term(p - p[zm], x):
  486. raise NotImplementedError("p - p[0] must not have a constant term in "
  487. "the series variables")
  488. r = _series_inversion1(p, x, prec)
  489. if m != 0:
  490. r = mul_xin(r, index, -m)
  491. return r
  492. def _coefficient_t(p, t):
  493. r"""Coefficient of `x_i**j` in p, where ``t`` = (i, j)"""
  494. i, j = t
  495. R = p.ring
  496. expv1 = [0]*R.ngens
  497. expv1[i] = j
  498. expv1 = tuple(expv1)
  499. p1 = R(0)
  500. for expv in p:
  501. if expv[i] == j:
  502. p1[monomial_div(expv, expv1)] = p[expv]
  503. return p1
  504. def rs_series_reversion(p, x, n, y):
  505. r"""
  506. Reversion of a series.
  507. ``p`` is a series with ``O(x**n)`` of the form $p = ax + f(x)$
  508. where $a$ is a number different from 0.
  509. $f(x) = \sum_{k=2}^{n-1} a_kx_k$
  510. Parameters
  511. ==========
  512. a_k : Can depend polynomially on other variables, not indicated.
  513. x : Variable with name x.
  514. y : Variable with name y.
  515. Returns
  516. =======
  517. Solve $p = y$, that is, given $ax + f(x) - y = 0$,
  518. find the solution $x = r(y)$ up to $O(y^n)$.
  519. Algorithm
  520. =========
  521. If $r_i$ is the solution at order $i$, then:
  522. $ar_i + f(r_i) - y = O\left(y^{i + 1}\right)$
  523. and if $r_{i + 1}$ is the solution at order $i + 1$, then:
  524. $ar_{i + 1} + f(r_{i + 1}) - y = O\left(y^{i + 2}\right)$
  525. We have, $r_{i + 1} = r_i + e$, such that,
  526. $ae + f(r_i) = O\left(y^{i + 2}\right)$
  527. or $e = -f(r_i)/a$
  528. So we use the recursion relation:
  529. $r_{i + 1} = r_i - f(r_i)/a$
  530. with the boundary condition: $r_1 = y$
  531. Examples
  532. ========
  533. >>> from sympy.polys.domains import QQ
  534. >>> from sympy.polys.rings import ring
  535. >>> from sympy.polys.ring_series import rs_series_reversion, rs_trunc
  536. >>> R, x, y, a, b = ring('x, y, a, b', QQ)
  537. >>> p = x - x**2 - 2*b*x**2 + 2*a*b*x**2
  538. >>> p1 = rs_series_reversion(p, x, 3, y); p1
  539. -2*y**2*a*b + 2*y**2*b + y**2 + y
  540. >>> rs_trunc(p.compose(x, p1), y, 3)
  541. y
  542. """
  543. if rs_is_puiseux(p, x):
  544. raise NotImplementedError
  545. R = p.ring
  546. nx = R.gens.index(x)
  547. y = R(y)
  548. ny = R.gens.index(y)
  549. if _has_constant_term(p, x):
  550. raise ValueError("p must not contain a constant term in the series "
  551. "variable")
  552. a = _coefficient_t(p, (nx, 1))
  553. zm = R.zero_monom
  554. assert zm in a and len(a) == 1
  555. a = a[zm]
  556. r = y/a
  557. for i in range(2, n):
  558. sp = rs_subs(p, {x: r}, y, i + 1)
  559. sp = _coefficient_t(sp, (ny, i))*y**i
  560. r -= sp/a
  561. return r
  562. def rs_series_from_list(p, c, x, prec, concur=1):
  563. """
  564. Return a series `sum c[n]*p**n` modulo `O(x**prec)`.
  565. It reduces the number of multiplications by summing concurrently.
  566. `ax = [1, p, p**2, .., p**(J - 1)]`
  567. `s = sum(c[i]*ax[i]` for i in `range(r, (r + 1)*J))*p**((K - 1)*J)`
  568. with `K >= (n + 1)/J`
  569. Examples
  570. ========
  571. >>> from sympy.polys.domains import QQ
  572. >>> from sympy.polys.rings import ring
  573. >>> from sympy.polys.ring_series import rs_series_from_list, rs_trunc
  574. >>> R, x = ring('x', QQ)
  575. >>> p = x**2 + x + 1
  576. >>> c = [1, 2, 3]
  577. >>> rs_series_from_list(p, c, x, 4)
  578. 6*x**3 + 11*x**2 + 8*x + 6
  579. >>> rs_trunc(1 + 2*p + 3*p**2, x, 4)
  580. 6*x**3 + 11*x**2 + 8*x + 6
  581. >>> pc = R.from_list(list(reversed(c)))
  582. >>> rs_trunc(pc.compose(x, p), x, 4)
  583. 6*x**3 + 11*x**2 + 8*x + 6
  584. """
  585. # TODO: Add this when it is documented in Sphinx
  586. """
  587. See Also
  588. ========
  589. sympy.polys.rings.PolyRing.compose
  590. """
  591. R = p.ring
  592. n = len(c)
  593. if not concur:
  594. q = R(1)
  595. s = c[0]*q
  596. for i in range(1, n):
  597. q = rs_mul(q, p, x, prec)
  598. s += c[i]*q
  599. return s
  600. J = int(math.sqrt(n) + 1)
  601. K, r = divmod(n, J)
  602. if r:
  603. K += 1
  604. ax = [R(1)]
  605. q = R(1)
  606. if len(p) < 20:
  607. for i in range(1, J):
  608. q = rs_mul(q, p, x, prec)
  609. ax.append(q)
  610. else:
  611. for i in range(1, J):
  612. if i % 2 == 0:
  613. q = rs_square(ax[i//2], x, prec)
  614. else:
  615. q = rs_mul(q, p, x, prec)
  616. ax.append(q)
  617. # optimize using rs_square
  618. pj = rs_mul(ax[-1], p, x, prec)
  619. b = R(1)
  620. s = R(0)
  621. for k in range(K - 1):
  622. r = J*k
  623. s1 = c[r]
  624. for j in range(1, J):
  625. s1 += c[r + j]*ax[j]
  626. s1 = rs_mul(s1, b, x, prec)
  627. s += s1
  628. b = rs_mul(b, pj, x, prec)
  629. if not b:
  630. break
  631. k = K - 1
  632. r = J*k
  633. if r < n:
  634. s1 = c[r]*R(1)
  635. for j in range(1, J):
  636. if r + j >= n:
  637. break
  638. s1 += c[r + j]*ax[j]
  639. s1 = rs_mul(s1, b, x, prec)
  640. s += s1
  641. return s
  642. def rs_diff(p, x):
  643. """
  644. Return partial derivative of ``p`` with respect to ``x``.
  645. Parameters
  646. ==========
  647. x : :class:`~.PolyElement` with respect to which ``p`` is differentiated.
  648. Examples
  649. ========
  650. >>> from sympy.polys.domains import QQ
  651. >>> from sympy.polys.rings import ring
  652. >>> from sympy.polys.ring_series import rs_diff
  653. >>> R, x, y = ring('x, y', QQ)
  654. >>> p = x + x**2*y**3
  655. >>> rs_diff(p, x)
  656. 2*x*y**3 + 1
  657. """
  658. R = p.ring
  659. n = R.gens.index(x)
  660. p1 = R.zero
  661. mn = [0]*R.ngens
  662. mn[n] = 1
  663. mn = tuple(mn)
  664. for expv in p:
  665. if expv[n]:
  666. e = monomial_ldiv(expv, mn)
  667. p1[e] = R.domain_new(p[expv]*expv[n])
  668. return p1
  669. def rs_integrate(p, x):
  670. """
  671. Integrate ``p`` with respect to ``x``.
  672. Parameters
  673. ==========
  674. x : :class:`~.PolyElement` with respect to which ``p`` is integrated.
  675. Examples
  676. ========
  677. >>> from sympy.polys.domains import QQ
  678. >>> from sympy.polys.rings import ring
  679. >>> from sympy.polys.ring_series import rs_integrate
  680. >>> R, x, y = ring('x, y', QQ)
  681. >>> p = x + x**2*y**3
  682. >>> rs_integrate(p, x)
  683. 1/3*x**3*y**3 + 1/2*x**2
  684. """
  685. R = p.ring
  686. p1 = R.zero
  687. n = R.gens.index(x)
  688. mn = [0]*R.ngens
  689. mn[n] = 1
  690. mn = tuple(mn)
  691. for expv in p:
  692. e = monomial_mul(expv, mn)
  693. p1[e] = R.domain_new(p[expv]/(expv[n] + 1))
  694. return p1
  695. def rs_fun(p, f, *args):
  696. r"""
  697. Function of a multivariate series computed by substitution.
  698. The case with f method name is used to compute `rs\_tan` and `rs\_nth\_root`
  699. of a multivariate series:
  700. `rs\_fun(p, tan, iv, prec)`
  701. tan series is first computed for a dummy variable _x,
  702. i.e, `rs\_tan(\_x, iv, prec)`. Then we substitute _x with p to get the
  703. desired series
  704. Parameters
  705. ==========
  706. p : :class:`~.PolyElement` The multivariate series to be expanded.
  707. f : `ring\_series` function to be applied on `p`.
  708. args[-2] : :class:`~.PolyElement` with respect to which, the series is to be expanded.
  709. args[-1] : Required order of the expanded series.
  710. Examples
  711. ========
  712. >>> from sympy.polys.domains import QQ
  713. >>> from sympy.polys.rings import ring
  714. >>> from sympy.polys.ring_series import rs_fun, _tan1
  715. >>> R, x, y = ring('x, y', QQ)
  716. >>> p = x + x*y + x**2*y + x**3*y**2
  717. >>> rs_fun(p, _tan1, x, 4)
  718. 1/3*x**3*y**3 + 2*x**3*y**2 + x**3*y + 1/3*x**3 + x**2*y + x*y + x
  719. """
  720. _R = p.ring
  721. R1, _x = ring('_x', _R.domain)
  722. h = int(args[-1])
  723. args1 = args[:-2] + (_x, h)
  724. zm = _R.zero_monom
  725. # separate the constant term of the series
  726. # compute the univariate series f(_x, .., 'x', sum(nv))
  727. if zm in p:
  728. x1 = _x + p[zm]
  729. p1 = p - p[zm]
  730. else:
  731. x1 = _x
  732. p1 = p
  733. if isinstance(f, str):
  734. q = getattr(x1, f)(*args1)
  735. else:
  736. q = f(x1, *args1)
  737. a = sorted(q.items())
  738. c = [0]*h
  739. for x in a:
  740. c[x[0][0]] = x[1]
  741. p1 = rs_series_from_list(p1, c, args[-2], args[-1])
  742. return p1
  743. def mul_xin(p, i, n):
  744. r"""
  745. Return `p*x_i**n`.
  746. `x\_i` is the ith variable in ``p``.
  747. """
  748. R = p.ring
  749. q = R(0)
  750. for k, v in p.items():
  751. k1 = list(k)
  752. k1[i] += n
  753. q[tuple(k1)] = v
  754. return q
  755. def pow_xin(p, i, n):
  756. """
  757. >>> from sympy.polys.domains import QQ
  758. >>> from sympy.polys.rings import ring
  759. >>> from sympy.polys.ring_series import pow_xin
  760. >>> R, x, y = ring('x, y', QQ)
  761. >>> p = x**QQ(2,5) + x + x**QQ(2,3)
  762. >>> index = p.ring.gens.index(x)
  763. >>> pow_xin(p, index, 15)
  764. x**15 + x**10 + x**6
  765. """
  766. R = p.ring
  767. q = R(0)
  768. for k, v in p.items():
  769. k1 = list(k)
  770. k1[i] *= n
  771. q[tuple(k1)] = v
  772. return q
  773. def _nth_root1(p, n, x, prec):
  774. """
  775. Univariate series expansion of the nth root of ``p``.
  776. The Newton method is used.
  777. """
  778. if rs_is_puiseux(p, x):
  779. return rs_puiseux2(_nth_root1, p, n, x, prec)
  780. R = p.ring
  781. zm = R.zero_monom
  782. if zm not in p:
  783. raise NotImplementedError('No constant term in series')
  784. n = as_int(n)
  785. assert p[zm] == 1
  786. p1 = R(1)
  787. if p == 1:
  788. return p
  789. if n == 0:
  790. return R(1)
  791. if n == 1:
  792. return p
  793. if n < 0:
  794. n = -n
  795. sign = 1
  796. else:
  797. sign = 0
  798. for precx in _giant_steps(prec):
  799. tmp = rs_pow(p1, n + 1, x, precx)
  800. tmp = rs_mul(tmp, p, x, precx)
  801. p1 += p1/n - tmp/n
  802. if sign:
  803. return p1
  804. else:
  805. return _series_inversion1(p1, x, prec)
  806. def rs_nth_root(p, n, x, prec):
  807. """
  808. Multivariate series expansion of the nth root of ``p``.
  809. Parameters
  810. ==========
  811. p : Expr
  812. The polynomial to computer the root of.
  813. n : integer
  814. The order of the root to be computed.
  815. x : :class:`~.PolyElement`
  816. prec : integer
  817. Order of the expanded series.
  818. Notes
  819. =====
  820. The result of this function is dependent on the ring over which the
  821. polynomial has been defined. If the answer involves a root of a constant,
  822. make sure that the polynomial is over a real field. It cannot yet handle
  823. roots of symbols.
  824. Examples
  825. ========
  826. >>> from sympy.polys.domains import QQ, RR
  827. >>> from sympy.polys.rings import ring
  828. >>> from sympy.polys.ring_series import rs_nth_root
  829. >>> R, x, y = ring('x, y', QQ)
  830. >>> rs_nth_root(1 + x + x*y, -3, x, 3)
  831. 2/9*x**2*y**2 + 4/9*x**2*y + 2/9*x**2 - 1/3*x*y - 1/3*x + 1
  832. >>> R, x, y = ring('x, y', RR)
  833. >>> rs_nth_root(3 + x + x*y, 3, x, 2)
  834. 0.160249952256379*x*y + 0.160249952256379*x + 1.44224957030741
  835. """
  836. if n == 0:
  837. if p == 0:
  838. raise ValueError('0**0 expression')
  839. else:
  840. return p.ring(1)
  841. if n == 1:
  842. return rs_trunc(p, x, prec)
  843. R = p.ring
  844. index = R.gens.index(x)
  845. m = min(p, key=lambda k: k[index])[index]
  846. p = mul_xin(p, index, -m)
  847. prec -= m
  848. if _has_constant_term(p - 1, x):
  849. zm = R.zero_monom
  850. c = p[zm]
  851. if R.domain is EX:
  852. c_expr = c.as_expr()
  853. const = c_expr**QQ(1, n)
  854. elif isinstance(c, PolyElement):
  855. try:
  856. c_expr = c.as_expr()
  857. const = R(c_expr**(QQ(1, n)))
  858. except ValueError:
  859. raise DomainError("The given series cannot be expanded in "
  860. "this domain.")
  861. else:
  862. try: # RealElement doesn't support
  863. const = R(c**Rational(1, n)) # exponentiation with mpq object
  864. except ValueError: # as exponent
  865. raise DomainError("The given series cannot be expanded in "
  866. "this domain.")
  867. res = rs_nth_root(p/c, n, x, prec)*const
  868. else:
  869. res = _nth_root1(p, n, x, prec)
  870. if m:
  871. m = QQ(m, n)
  872. res = mul_xin(res, index, m)
  873. return res
  874. def rs_log(p, x, prec):
  875. """
  876. The Logarithm of ``p`` modulo ``O(x**prec)``.
  877. Notes
  878. =====
  879. Truncation of ``integral dx p**-1*d p/dx`` is used.
  880. Examples
  881. ========
  882. >>> from sympy.polys.domains import QQ
  883. >>> from sympy.polys.rings import ring
  884. >>> from sympy.polys.ring_series import rs_log
  885. >>> R, x = ring('x', QQ)
  886. >>> rs_log(1 + x, x, 8)
  887. 1/7*x**7 - 1/6*x**6 + 1/5*x**5 - 1/4*x**4 + 1/3*x**3 - 1/2*x**2 + x
  888. >>> rs_log(x**QQ(3, 2) + 1, x, 5)
  889. 1/3*x**(9/2) - 1/2*x**3 + x**(3/2)
  890. """
  891. if rs_is_puiseux(p, x):
  892. return rs_puiseux(rs_log, p, x, prec)
  893. R = p.ring
  894. if p == 1:
  895. return R.zero
  896. c = _get_constant_term(p, x)
  897. if c:
  898. const = 0
  899. if c == 1:
  900. pass
  901. else:
  902. c_expr = c.as_expr()
  903. if R.domain is EX:
  904. const = log(c_expr)
  905. elif isinstance(c, PolyElement):
  906. try:
  907. const = R(log(c_expr))
  908. except ValueError:
  909. R = R.add_gens([log(c_expr)])
  910. p = p.set_ring(R)
  911. x = x.set_ring(R)
  912. c = c.set_ring(R)
  913. const = R(log(c_expr))
  914. else:
  915. try:
  916. const = R(log(c))
  917. except ValueError:
  918. raise DomainError("The given series cannot be expanded in "
  919. "this domain.")
  920. dlog = p.diff(x)
  921. dlog = rs_mul(dlog, _series_inversion1(p, x, prec), x, prec - 1)
  922. return rs_integrate(dlog, x) + const
  923. else:
  924. raise NotImplementedError
  925. def rs_LambertW(p, x, prec):
  926. """
  927. Calculate the series expansion of the principal branch of the Lambert W
  928. function.
  929. Examples
  930. ========
  931. >>> from sympy.polys.domains import QQ
  932. >>> from sympy.polys.rings import ring
  933. >>> from sympy.polys.ring_series import rs_LambertW
  934. >>> R, x, y = ring('x, y', QQ)
  935. >>> rs_LambertW(x + x*y, x, 3)
  936. -x**2*y**2 - 2*x**2*y - x**2 + x*y + x
  937. See Also
  938. ========
  939. LambertW
  940. """
  941. if rs_is_puiseux(p, x):
  942. return rs_puiseux(rs_LambertW, p, x, prec)
  943. R = p.ring
  944. p1 = R(0)
  945. if _has_constant_term(p, x):
  946. raise NotImplementedError("Polynomial must not have constant term in "
  947. "the series variables")
  948. if x in R.gens:
  949. for precx in _giant_steps(prec):
  950. e = rs_exp(p1, x, precx)
  951. p2 = rs_mul(e, p1, x, precx) - p
  952. p3 = rs_mul(e, p1 + 1, x, precx)
  953. p3 = rs_series_inversion(p3, x, precx)
  954. tmp = rs_mul(p2, p3, x, precx)
  955. p1 -= tmp
  956. return p1
  957. else:
  958. raise NotImplementedError
  959. def _exp1(p, x, prec):
  960. r"""Helper function for `rs\_exp`. """
  961. R = p.ring
  962. p1 = R(1)
  963. for precx in _giant_steps(prec):
  964. pt = p - rs_log(p1, x, precx)
  965. tmp = rs_mul(pt, p1, x, precx)
  966. p1 += tmp
  967. return p1
  968. def rs_exp(p, x, prec):
  969. """
  970. Exponentiation of a series modulo ``O(x**prec)``
  971. Examples
  972. ========
  973. >>> from sympy.polys.domains import QQ
  974. >>> from sympy.polys.rings import ring
  975. >>> from sympy.polys.ring_series import rs_exp
  976. >>> R, x = ring('x', QQ)
  977. >>> rs_exp(x**2, x, 7)
  978. 1/6*x**6 + 1/2*x**4 + x**2 + 1
  979. """
  980. if rs_is_puiseux(p, x):
  981. return rs_puiseux(rs_exp, p, x, prec)
  982. R = p.ring
  983. c = _get_constant_term(p, x)
  984. if c:
  985. if R.domain is EX:
  986. c_expr = c.as_expr()
  987. const = exp(c_expr)
  988. elif isinstance(c, PolyElement):
  989. try:
  990. c_expr = c.as_expr()
  991. const = R(exp(c_expr))
  992. except ValueError:
  993. R = R.add_gens([exp(c_expr)])
  994. p = p.set_ring(R)
  995. x = x.set_ring(R)
  996. c = c.set_ring(R)
  997. const = R(exp(c_expr))
  998. else:
  999. try:
  1000. const = R(exp(c))
  1001. except ValueError:
  1002. raise DomainError("The given series cannot be expanded in "
  1003. "this domain.")
  1004. p1 = p - c
  1005. # Makes use of SymPy functions to evaluate the values of the cos/sin
  1006. # of the constant term.
  1007. return const*rs_exp(p1, x, prec)
  1008. if len(p) > 20:
  1009. return _exp1(p, x, prec)
  1010. one = R(1)
  1011. n = 1
  1012. c = []
  1013. for k in range(prec):
  1014. c.append(one/n)
  1015. k += 1
  1016. n *= k
  1017. r = rs_series_from_list(p, c, x, prec)
  1018. return r
  1019. def _atan(p, iv, prec):
  1020. """
  1021. Expansion using formula.
  1022. Faster on very small and univariate series.
  1023. """
  1024. R = p.ring
  1025. mo = R(-1)
  1026. c = [-mo]
  1027. p2 = rs_square(p, iv, prec)
  1028. for k in range(1, prec):
  1029. c.append(mo**k/(2*k + 1))
  1030. s = rs_series_from_list(p2, c, iv, prec)
  1031. s = rs_mul(s, p, iv, prec)
  1032. return s
  1033. def rs_atan(p, x, prec):
  1034. """
  1035. The arctangent of a series
  1036. Return the series expansion of the atan of ``p``, about 0.
  1037. Examples
  1038. ========
  1039. >>> from sympy.polys.domains import QQ
  1040. >>> from sympy.polys.rings import ring
  1041. >>> from sympy.polys.ring_series import rs_atan
  1042. >>> R, x, y = ring('x, y', QQ)
  1043. >>> rs_atan(x + x*y, x, 4)
  1044. -1/3*x**3*y**3 - x**3*y**2 - x**3*y - 1/3*x**3 + x*y + x
  1045. See Also
  1046. ========
  1047. atan
  1048. """
  1049. if rs_is_puiseux(p, x):
  1050. return rs_puiseux(rs_atan, p, x, prec)
  1051. R = p.ring
  1052. const = 0
  1053. if _has_constant_term(p, x):
  1054. zm = R.zero_monom
  1055. c = p[zm]
  1056. if R.domain is EX:
  1057. c_expr = c.as_expr()
  1058. const = atan(c_expr)
  1059. elif isinstance(c, PolyElement):
  1060. try:
  1061. c_expr = c.as_expr()
  1062. const = R(atan(c_expr))
  1063. except ValueError:
  1064. raise DomainError("The given series cannot be expanded in "
  1065. "this domain.")
  1066. else:
  1067. try:
  1068. const = R(atan(c))
  1069. except ValueError:
  1070. raise DomainError("The given series cannot be expanded in "
  1071. "this domain.")
  1072. # Instead of using a closed form formula, we differentiate atan(p) to get
  1073. # `1/(1+p**2) * dp`, whose series expansion is much easier to calculate.
  1074. # Finally we integrate to get back atan
  1075. dp = p.diff(x)
  1076. p1 = rs_square(p, x, prec) + R(1)
  1077. p1 = rs_series_inversion(p1, x, prec - 1)
  1078. p1 = rs_mul(dp, p1, x, prec - 1)
  1079. return rs_integrate(p1, x) + const
  1080. def rs_asin(p, x, prec):
  1081. """
  1082. Arcsine of a series
  1083. Return the series expansion of the asin of ``p``, about 0.
  1084. Examples
  1085. ========
  1086. >>> from sympy.polys.domains import QQ
  1087. >>> from sympy.polys.rings import ring
  1088. >>> from sympy.polys.ring_series import rs_asin
  1089. >>> R, x, y = ring('x, y', QQ)
  1090. >>> rs_asin(x, x, 8)
  1091. 5/112*x**7 + 3/40*x**5 + 1/6*x**3 + x
  1092. See Also
  1093. ========
  1094. asin
  1095. """
  1096. if rs_is_puiseux(p, x):
  1097. return rs_puiseux(rs_asin, p, x, prec)
  1098. if _has_constant_term(p, x):
  1099. raise NotImplementedError("Polynomial must not have constant term in "
  1100. "series variables")
  1101. R = p.ring
  1102. if x in R.gens:
  1103. # get a good value
  1104. if len(p) > 20:
  1105. dp = rs_diff(p, x)
  1106. p1 = 1 - rs_square(p, x, prec - 1)
  1107. p1 = rs_nth_root(p1, -2, x, prec - 1)
  1108. p1 = rs_mul(dp, p1, x, prec - 1)
  1109. return rs_integrate(p1, x)
  1110. one = R(1)
  1111. c = [0, one, 0]
  1112. for k in range(3, prec, 2):
  1113. c.append((k - 2)**2*c[-2]/(k*(k - 1)))
  1114. c.append(0)
  1115. return rs_series_from_list(p, c, x, prec)
  1116. else:
  1117. raise NotImplementedError
  1118. def _tan1(p, x, prec):
  1119. r"""
  1120. Helper function of :func:`rs_tan`.
  1121. Return the series expansion of tan of a univariate series using Newton's
  1122. method. It takes advantage of the fact that series expansion of atan is
  1123. easier than that of tan.
  1124. Consider `f(x) = y - \arctan(x)`
  1125. Let r be a root of f(x) found using Newton's method.
  1126. Then `f(r) = 0`
  1127. Or `y = \arctan(x)` where `x = \tan(y)` as required.
  1128. """
  1129. R = p.ring
  1130. p1 = R(0)
  1131. for precx in _giant_steps(prec):
  1132. tmp = p - rs_atan(p1, x, precx)
  1133. tmp = rs_mul(tmp, 1 + rs_square(p1, x, precx), x, precx)
  1134. p1 += tmp
  1135. return p1
  1136. def rs_tan(p, x, prec):
  1137. """
  1138. Tangent of a series.
  1139. Return the series expansion of the tan of ``p``, about 0.
  1140. Examples
  1141. ========
  1142. >>> from sympy.polys.domains import QQ
  1143. >>> from sympy.polys.rings import ring
  1144. >>> from sympy.polys.ring_series import rs_tan
  1145. >>> R, x, y = ring('x, y', QQ)
  1146. >>> rs_tan(x + x*y, x, 4)
  1147. 1/3*x**3*y**3 + x**3*y**2 + x**3*y + 1/3*x**3 + x*y + x
  1148. See Also
  1149. ========
  1150. _tan1, tan
  1151. """
  1152. if rs_is_puiseux(p, x):
  1153. r = rs_puiseux(rs_tan, p, x, prec)
  1154. return r
  1155. R = p.ring
  1156. const = 0
  1157. c = _get_constant_term(p, x)
  1158. if c:
  1159. if R.domain is EX:
  1160. c_expr = c.as_expr()
  1161. const = tan(c_expr)
  1162. elif isinstance(c, PolyElement):
  1163. try:
  1164. c_expr = c.as_expr()
  1165. const = R(tan(c_expr))
  1166. except ValueError:
  1167. R = R.add_gens([tan(c_expr, )])
  1168. p = p.set_ring(R)
  1169. x = x.set_ring(R)
  1170. c = c.set_ring(R)
  1171. const = R(tan(c_expr))
  1172. else:
  1173. try:
  1174. const = R(tan(c))
  1175. except ValueError:
  1176. raise DomainError("The given series cannot be expanded in "
  1177. "this domain.")
  1178. p1 = p - c
  1179. # Makes use of SymPy functions to evaluate the values of the cos/sin
  1180. # of the constant term.
  1181. t2 = rs_tan(p1, x, prec)
  1182. t = rs_series_inversion(1 - const*t2, x, prec)
  1183. return rs_mul(const + t2, t, x, prec)
  1184. if R.ngens == 1:
  1185. return _tan1(p, x, prec)
  1186. else:
  1187. return rs_fun(p, rs_tan, x, prec)
  1188. def rs_cot(p, x, prec):
  1189. """
  1190. Cotangent of a series
  1191. Return the series expansion of the cot of ``p``, about 0.
  1192. Examples
  1193. ========
  1194. >>> from sympy.polys.domains import QQ
  1195. >>> from sympy.polys.rings import ring
  1196. >>> from sympy.polys.ring_series import rs_cot
  1197. >>> R, x, y = ring('x, y', QQ)
  1198. >>> rs_cot(x, x, 6)
  1199. -2/945*x**5 - 1/45*x**3 - 1/3*x + x**(-1)
  1200. See Also
  1201. ========
  1202. cot
  1203. """
  1204. # It can not handle series like `p = x + x*y` where the coefficient of the
  1205. # linear term in the series variable is symbolic.
  1206. if rs_is_puiseux(p, x):
  1207. r = rs_puiseux(rs_cot, p, x, prec)
  1208. return r
  1209. i, m = _check_series_var(p, x, 'cot')
  1210. prec1 = prec + 2*m
  1211. c, s = rs_cos_sin(p, x, prec1)
  1212. s = mul_xin(s, i, -m)
  1213. s = rs_series_inversion(s, x, prec1)
  1214. res = rs_mul(c, s, x, prec1)
  1215. res = mul_xin(res, i, -m)
  1216. res = rs_trunc(res, x, prec)
  1217. return res
  1218. def rs_sin(p, x, prec):
  1219. """
  1220. Sine of a series
  1221. Return the series expansion of the sin of ``p``, about 0.
  1222. Examples
  1223. ========
  1224. >>> from sympy.polys.domains import QQ
  1225. >>> from sympy.polys.rings import ring
  1226. >>> from sympy.polys.ring_series import rs_sin
  1227. >>> R, x, y = ring('x, y', QQ)
  1228. >>> rs_sin(x + x*y, x, 4)
  1229. -1/6*x**3*y**3 - 1/2*x**3*y**2 - 1/2*x**3*y - 1/6*x**3 + x*y + x
  1230. >>> rs_sin(x**QQ(3, 2) + x*y**QQ(7, 5), x, 4)
  1231. -1/2*x**(7/2)*y**(14/5) - 1/6*x**3*y**(21/5) + x**(3/2) + x*y**(7/5)
  1232. See Also
  1233. ========
  1234. sin
  1235. """
  1236. if rs_is_puiseux(p, x):
  1237. return rs_puiseux(rs_sin, p, x, prec)
  1238. R = x.ring
  1239. if not p:
  1240. return R(0)
  1241. c = _get_constant_term(p, x)
  1242. if c:
  1243. if R.domain is EX:
  1244. c_expr = c.as_expr()
  1245. t1, t2 = sin(c_expr), cos(c_expr)
  1246. elif isinstance(c, PolyElement):
  1247. try:
  1248. c_expr = c.as_expr()
  1249. t1, t2 = R(sin(c_expr)), R(cos(c_expr))
  1250. except ValueError:
  1251. R = R.add_gens([sin(c_expr), cos(c_expr)])
  1252. p = p.set_ring(R)
  1253. x = x.set_ring(R)
  1254. c = c.set_ring(R)
  1255. t1, t2 = R(sin(c_expr)), R(cos(c_expr))
  1256. else:
  1257. try:
  1258. t1, t2 = R(sin(c)), R(cos(c))
  1259. except ValueError:
  1260. raise DomainError("The given series cannot be expanded in "
  1261. "this domain.")
  1262. p1 = p - c
  1263. # Makes use of SymPy cos, sin functions to evaluate the values of the
  1264. # cos/sin of the constant term.
  1265. return rs_sin(p1, x, prec)*t2 + rs_cos(p1, x, prec)*t1
  1266. # Series is calculated in terms of tan as its evaluation is fast.
  1267. if len(p) > 20 and R.ngens == 1:
  1268. t = rs_tan(p/2, x, prec)
  1269. t2 = rs_square(t, x, prec)
  1270. p1 = rs_series_inversion(1 + t2, x, prec)
  1271. return rs_mul(p1, 2*t, x, prec)
  1272. one = R(1)
  1273. n = 1
  1274. c = [0]
  1275. for k in range(2, prec + 2, 2):
  1276. c.append(one/n)
  1277. c.append(0)
  1278. n *= -k*(k + 1)
  1279. return rs_series_from_list(p, c, x, prec)
  1280. def rs_cos(p, x, prec):
  1281. """
  1282. Cosine of a series
  1283. Return the series expansion of the cos of ``p``, about 0.
  1284. Examples
  1285. ========
  1286. >>> from sympy.polys.domains import QQ
  1287. >>> from sympy.polys.rings import ring
  1288. >>> from sympy.polys.ring_series import rs_cos
  1289. >>> R, x, y = ring('x, y', QQ)
  1290. >>> rs_cos(x + x*y, x, 4)
  1291. -1/2*x**2*y**2 - x**2*y - 1/2*x**2 + 1
  1292. >>> rs_cos(x + x*y, x, 4)/x**QQ(7, 5)
  1293. -1/2*x**(3/5)*y**2 - x**(3/5)*y - 1/2*x**(3/5) + x**(-7/5)
  1294. See Also
  1295. ========
  1296. cos
  1297. """
  1298. if rs_is_puiseux(p, x):
  1299. return rs_puiseux(rs_cos, p, x, prec)
  1300. R = p.ring
  1301. c = _get_constant_term(p, x)
  1302. if c:
  1303. if R.domain is EX:
  1304. c_expr = c.as_expr()
  1305. _, _ = sin(c_expr), cos(c_expr)
  1306. elif isinstance(c, PolyElement):
  1307. try:
  1308. c_expr = c.as_expr()
  1309. _, _ = R(sin(c_expr)), R(cos(c_expr))
  1310. except ValueError:
  1311. R = R.add_gens([sin(c_expr), cos(c_expr)])
  1312. p = p.set_ring(R)
  1313. x = x.set_ring(R)
  1314. c = c.set_ring(R)
  1315. else:
  1316. try:
  1317. _, _ = R(sin(c)), R(cos(c))
  1318. except ValueError:
  1319. raise DomainError("The given series cannot be expanded in "
  1320. "this domain.")
  1321. p1 = p - c
  1322. # Makes use of SymPy cos, sin functions to evaluate the values of the
  1323. # cos/sin of the constant term.
  1324. p_cos = rs_cos(p1, x, prec)
  1325. p_sin = rs_sin(p1, x, prec)
  1326. R = R.compose(p_cos.ring).compose(p_sin.ring)
  1327. p_cos.set_ring(R)
  1328. p_sin.set_ring(R)
  1329. t1, t2 = R(sin(c_expr)), R(cos(c_expr))
  1330. return p_cos*t2 - p_sin*t1
  1331. # Series is calculated in terms of tan as its evaluation is fast.
  1332. if len(p) > 20 and R.ngens == 1:
  1333. t = rs_tan(p/2, x, prec)
  1334. t2 = rs_square(t, x, prec)
  1335. p1 = rs_series_inversion(1+t2, x, prec)
  1336. return rs_mul(p1, 1 - t2, x, prec)
  1337. one = R(1)
  1338. n = 1
  1339. c = []
  1340. for k in range(2, prec + 2, 2):
  1341. c.append(one/n)
  1342. c.append(0)
  1343. n *= -k*(k - 1)
  1344. return rs_series_from_list(p, c, x, prec)
  1345. def rs_cos_sin(p, x, prec):
  1346. r"""
  1347. Return the tuple ``(rs_cos(p, x, prec)`, `rs_sin(p, x, prec))``.
  1348. Is faster than calling rs_cos and rs_sin separately
  1349. """
  1350. if rs_is_puiseux(p, x):
  1351. return rs_puiseux(rs_cos_sin, p, x, prec)
  1352. t = rs_tan(p/2, x, prec)
  1353. t2 = rs_square(t, x, prec)
  1354. p1 = rs_series_inversion(1 + t2, x, prec)
  1355. return (rs_mul(p1, 1 - t2, x, prec), rs_mul(p1, 2*t, x, prec))
  1356. def _atanh(p, x, prec):
  1357. """
  1358. Expansion using formula
  1359. Faster for very small and univariate series
  1360. """
  1361. R = p.ring
  1362. one = R(1)
  1363. c = [one]
  1364. p2 = rs_square(p, x, prec)
  1365. for k in range(1, prec):
  1366. c.append(one/(2*k + 1))
  1367. s = rs_series_from_list(p2, c, x, prec)
  1368. s = rs_mul(s, p, x, prec)
  1369. return s
  1370. def rs_atanh(p, x, prec):
  1371. """
  1372. Hyperbolic arctangent of a series
  1373. Return the series expansion of the atanh of ``p``, about 0.
  1374. Examples
  1375. ========
  1376. >>> from sympy.polys.domains import QQ
  1377. >>> from sympy.polys.rings import ring
  1378. >>> from sympy.polys.ring_series import rs_atanh
  1379. >>> R, x, y = ring('x, y', QQ)
  1380. >>> rs_atanh(x + x*y, x, 4)
  1381. 1/3*x**3*y**3 + x**3*y**2 + x**3*y + 1/3*x**3 + x*y + x
  1382. See Also
  1383. ========
  1384. atanh
  1385. """
  1386. if rs_is_puiseux(p, x):
  1387. return rs_puiseux(rs_atanh, p, x, prec)
  1388. R = p.ring
  1389. const = 0
  1390. if _has_constant_term(p, x):
  1391. zm = R.zero_monom
  1392. c = p[zm]
  1393. if R.domain is EX:
  1394. c_expr = c.as_expr()
  1395. const = atanh(c_expr)
  1396. elif isinstance(c, PolyElement):
  1397. try:
  1398. c_expr = c.as_expr()
  1399. const = R(atanh(c_expr))
  1400. except ValueError:
  1401. raise DomainError("The given series cannot be expanded in "
  1402. "this domain.")
  1403. else:
  1404. try:
  1405. const = R(atanh(c))
  1406. except ValueError:
  1407. raise DomainError("The given series cannot be expanded in "
  1408. "this domain.")
  1409. # Instead of using a closed form formula, we differentiate atanh(p) to get
  1410. # `1/(1-p**2) * dp`, whose series expansion is much easier to calculate.
  1411. # Finally we integrate to get back atanh
  1412. dp = rs_diff(p, x)
  1413. p1 = - rs_square(p, x, prec) + 1
  1414. p1 = rs_series_inversion(p1, x, prec - 1)
  1415. p1 = rs_mul(dp, p1, x, prec - 1)
  1416. return rs_integrate(p1, x) + const
  1417. def rs_sinh(p, x, prec):
  1418. """
  1419. Hyperbolic sine of a series
  1420. Return the series expansion of the sinh of ``p``, about 0.
  1421. Examples
  1422. ========
  1423. >>> from sympy.polys.domains import QQ
  1424. >>> from sympy.polys.rings import ring
  1425. >>> from sympy.polys.ring_series import rs_sinh
  1426. >>> R, x, y = ring('x, y', QQ)
  1427. >>> rs_sinh(x + x*y, x, 4)
  1428. 1/6*x**3*y**3 + 1/2*x**3*y**2 + 1/2*x**3*y + 1/6*x**3 + x*y + x
  1429. See Also
  1430. ========
  1431. sinh
  1432. """
  1433. if rs_is_puiseux(p, x):
  1434. return rs_puiseux(rs_sinh, p, x, prec)
  1435. t = rs_exp(p, x, prec)
  1436. t1 = rs_series_inversion(t, x, prec)
  1437. return (t - t1)/2
  1438. def rs_cosh(p, x, prec):
  1439. """
  1440. Hyperbolic cosine of a series
  1441. Return the series expansion of the cosh of ``p``, about 0.
  1442. Examples
  1443. ========
  1444. >>> from sympy.polys.domains import QQ
  1445. >>> from sympy.polys.rings import ring
  1446. >>> from sympy.polys.ring_series import rs_cosh
  1447. >>> R, x, y = ring('x, y', QQ)
  1448. >>> rs_cosh(x + x*y, x, 4)
  1449. 1/2*x**2*y**2 + x**2*y + 1/2*x**2 + 1
  1450. See Also
  1451. ========
  1452. cosh
  1453. """
  1454. if rs_is_puiseux(p, x):
  1455. return rs_puiseux(rs_cosh, p, x, prec)
  1456. t = rs_exp(p, x, prec)
  1457. t1 = rs_series_inversion(t, x, prec)
  1458. return (t + t1)/2
  1459. def _tanh(p, x, prec):
  1460. r"""
  1461. Helper function of :func:`rs_tanh`
  1462. Return the series expansion of tanh of a univariate series using Newton's
  1463. method. It takes advantage of the fact that series expansion of atanh is
  1464. easier than that of tanh.
  1465. See Also
  1466. ========
  1467. _tanh
  1468. """
  1469. R = p.ring
  1470. p1 = R(0)
  1471. for precx in _giant_steps(prec):
  1472. tmp = p - rs_atanh(p1, x, precx)
  1473. tmp = rs_mul(tmp, 1 - rs_square(p1, x, prec), x, precx)
  1474. p1 += tmp
  1475. return p1
  1476. def rs_tanh(p, x, prec):
  1477. """
  1478. Hyperbolic tangent of a series
  1479. Return the series expansion of the tanh of ``p``, about 0.
  1480. Examples
  1481. ========
  1482. >>> from sympy.polys.domains import QQ
  1483. >>> from sympy.polys.rings import ring
  1484. >>> from sympy.polys.ring_series import rs_tanh
  1485. >>> R, x, y = ring('x, y', QQ)
  1486. >>> rs_tanh(x + x*y, x, 4)
  1487. -1/3*x**3*y**3 - x**3*y**2 - x**3*y - 1/3*x**3 + x*y + x
  1488. See Also
  1489. ========
  1490. tanh
  1491. """
  1492. if rs_is_puiseux(p, x):
  1493. return rs_puiseux(rs_tanh, p, x, prec)
  1494. R = p.ring
  1495. const = 0
  1496. if _has_constant_term(p, x):
  1497. zm = R.zero_monom
  1498. c = p[zm]
  1499. if R.domain is EX:
  1500. c_expr = c.as_expr()
  1501. const = tanh(c_expr)
  1502. elif isinstance(c, PolyElement):
  1503. try:
  1504. c_expr = c.as_expr()
  1505. const = R(tanh(c_expr))
  1506. except ValueError:
  1507. raise DomainError("The given series cannot be expanded in "
  1508. "this domain.")
  1509. else:
  1510. try:
  1511. const = R(tanh(c))
  1512. except ValueError:
  1513. raise DomainError("The given series cannot be expanded in "
  1514. "this domain.")
  1515. p1 = p - c
  1516. t1 = rs_tanh(p1, x, prec)
  1517. t = rs_series_inversion(1 + const*t1, x, prec)
  1518. return rs_mul(const + t1, t, x, prec)
  1519. if R.ngens == 1:
  1520. return _tanh(p, x, prec)
  1521. else:
  1522. return rs_fun(p, _tanh, x, prec)
  1523. def rs_newton(p, x, prec):
  1524. """
  1525. Compute the truncated Newton sum of the polynomial ``p``
  1526. Examples
  1527. ========
  1528. >>> from sympy.polys.domains import QQ
  1529. >>> from sympy.polys.rings import ring
  1530. >>> from sympy.polys.ring_series import rs_newton
  1531. >>> R, x = ring('x', QQ)
  1532. >>> p = x**2 - 2
  1533. >>> rs_newton(p, x, 5)
  1534. 8*x**4 + 4*x**2 + 2
  1535. """
  1536. deg = p.degree()
  1537. p1 = _invert_monoms(p)
  1538. p2 = rs_series_inversion(p1, x, prec)
  1539. p3 = rs_mul(p1.diff(x), p2, x, prec)
  1540. res = deg - p3*x
  1541. return res
  1542. def rs_hadamard_exp(p1, inverse=False):
  1543. """
  1544. Return ``sum f_i/i!*x**i`` from ``sum f_i*x**i``,
  1545. where ``x`` is the first variable.
  1546. If ``invers=True`` return ``sum f_i*i!*x**i``
  1547. Examples
  1548. ========
  1549. >>> from sympy.polys.domains import QQ
  1550. >>> from sympy.polys.rings import ring
  1551. >>> from sympy.polys.ring_series import rs_hadamard_exp
  1552. >>> R, x = ring('x', QQ)
  1553. >>> p = 1 + x + x**2 + x**3
  1554. >>> rs_hadamard_exp(p)
  1555. 1/6*x**3 + 1/2*x**2 + x + 1
  1556. """
  1557. R = p1.ring
  1558. if R.domain != QQ:
  1559. raise NotImplementedError
  1560. p = R.zero
  1561. if not inverse:
  1562. for exp1, v1 in p1.items():
  1563. p[exp1] = v1/int(ifac(exp1[0]))
  1564. else:
  1565. for exp1, v1 in p1.items():
  1566. p[exp1] = v1*int(ifac(exp1[0]))
  1567. return p
  1568. def rs_compose_add(p1, p2):
  1569. """
  1570. compute the composed sum ``prod(p2(x - beta) for beta root of p1)``
  1571. Examples
  1572. ========
  1573. >>> from sympy.polys.domains import QQ
  1574. >>> from sympy.polys.rings import ring
  1575. >>> from sympy.polys.ring_series import rs_compose_add
  1576. >>> R, x = ring('x', QQ)
  1577. >>> f = x**2 - 2
  1578. >>> g = x**2 - 3
  1579. >>> rs_compose_add(f, g)
  1580. x**4 - 10*x**2 + 1
  1581. References
  1582. ==========
  1583. .. [1] A. Bostan, P. Flajolet, B. Salvy and E. Schost
  1584. "Fast Computation with Two Algebraic Numbers",
  1585. (2002) Research Report 4579, Institut
  1586. National de Recherche en Informatique et en Automatique
  1587. """
  1588. R = p1.ring
  1589. x = R.gens[0]
  1590. prec = p1.degree()*p2.degree() + 1
  1591. np1 = rs_newton(p1, x, prec)
  1592. np1e = rs_hadamard_exp(np1)
  1593. np2 = rs_newton(p2, x, prec)
  1594. np2e = rs_hadamard_exp(np2)
  1595. np3e = rs_mul(np1e, np2e, x, prec)
  1596. np3 = rs_hadamard_exp(np3e, True)
  1597. np3a = (np3[(0,)] - np3)/x
  1598. q = rs_integrate(np3a, x)
  1599. q = rs_exp(q, x, prec)
  1600. q = _invert_monoms(q)
  1601. q = q.primitive()[1]
  1602. dp = p1.degree()*p2.degree() - q.degree()
  1603. # `dp` is the multiplicity of the zeroes of the resultant;
  1604. # these zeroes are missed in this computation so they are put here.
  1605. # if p1 and p2 are monic irreducible polynomials,
  1606. # there are zeroes in the resultant
  1607. # if and only if p1 = p2 ; in fact in that case p1 and p2 have a
  1608. # root in common, so gcd(p1, p2) != 1; being p1 and p2 irreducible
  1609. # this means p1 = p2
  1610. if dp:
  1611. q = q*x**dp
  1612. return q
  1613. _convert_func = {
  1614. 'sin': 'rs_sin',
  1615. 'cos': 'rs_cos',
  1616. 'exp': 'rs_exp',
  1617. 'tan': 'rs_tan',
  1618. 'log': 'rs_log'
  1619. }
  1620. def rs_min_pow(expr, series_rs, a):
  1621. """Find the minimum power of `a` in the series expansion of expr"""
  1622. series = 0
  1623. n = 2
  1624. while series == 0:
  1625. series = _rs_series(expr, series_rs, a, n)
  1626. n *= 2
  1627. R = series.ring
  1628. a = R(a)
  1629. i = R.gens.index(a)
  1630. return min(series, key=lambda t: t[i])[i]
  1631. def _rs_series(expr, series_rs, a, prec):
  1632. # TODO Use _parallel_dict_from_expr instead of sring as sring is
  1633. # inefficient. For details, read the todo in sring.
  1634. args = expr.args
  1635. R = series_rs.ring
  1636. # expr does not contain any function to be expanded
  1637. if not any(arg.has(Function) for arg in args) and not expr.is_Function:
  1638. return series_rs
  1639. if not expr.has(a):
  1640. return series_rs
  1641. elif expr.is_Function:
  1642. arg = args[0]
  1643. if len(args) > 1:
  1644. raise NotImplementedError
  1645. R1, series = sring(arg, domain=QQ, expand=False, series=True)
  1646. series_inner = _rs_series(arg, series, a, prec)
  1647. # Why do we need to compose these three rings?
  1648. #
  1649. # We want to use a simple domain (like ``QQ`` or ``RR``) but they don't
  1650. # support symbolic coefficients. We need a ring that for example lets
  1651. # us have `sin(1)` and `cos(1)` as coefficients if we are expanding
  1652. # `sin(x + 1)`. The ``EX`` domain allows all symbolic coefficients, but
  1653. # that makes it very complex and hence slow.
  1654. #
  1655. # To solve this problem, we add only those symbolic elements as
  1656. # generators to our ring, that we need. Here, series_inner might
  1657. # involve terms like `sin(4)`, `exp(a)`, etc, which are not there in
  1658. # R1 or R. Hence, we compose these three rings to create one that has
  1659. # the generators of all three.
  1660. R = R.compose(R1).compose(series_inner.ring)
  1661. series_inner = series_inner.set_ring(R)
  1662. series = eval(_convert_func[str(expr.func)])(series_inner,
  1663. R(a), prec)
  1664. return series
  1665. elif expr.is_Mul:
  1666. n = len(args)
  1667. for arg in args: # XXX Looks redundant
  1668. if not arg.is_Number:
  1669. R1, _ = sring(arg, expand=False, series=True)
  1670. R = R.compose(R1)
  1671. min_pows = list(map(rs_min_pow, args, [R(arg) for arg in args],
  1672. [a]*len(args)))
  1673. sum_pows = sum(min_pows)
  1674. series = R(1)
  1675. for i in range(n):
  1676. _series = _rs_series(args[i], R(args[i]), a, prec - sum_pows +
  1677. min_pows[i])
  1678. R = R.compose(_series.ring)
  1679. _series = _series.set_ring(R)
  1680. series = series.set_ring(R)
  1681. series *= _series
  1682. series = rs_trunc(series, R(a), prec)
  1683. return series
  1684. elif expr.is_Add:
  1685. n = len(args)
  1686. series = R(0)
  1687. for i in range(n):
  1688. _series = _rs_series(args[i], R(args[i]), a, prec)
  1689. R = R.compose(_series.ring)
  1690. _series = _series.set_ring(R)
  1691. series = series.set_ring(R)
  1692. series += _series
  1693. return series
  1694. elif expr.is_Pow:
  1695. R1, _ = sring(expr.base, domain=QQ, expand=False, series=True)
  1696. R = R.compose(R1)
  1697. series_inner = _rs_series(expr.base, R(expr.base), a, prec)
  1698. return rs_pow(series_inner, expr.exp, series_inner.ring(a), prec)
  1699. # The `is_constant` method is buggy hence we check it at the end.
  1700. # See issue #9786 for details.
  1701. elif isinstance(expr, Expr) and expr.is_constant():
  1702. return sring(expr, domain=QQ, expand=False, series=True)[1]
  1703. else:
  1704. raise NotImplementedError
  1705. def rs_series(expr, a, prec):
  1706. """Return the series expansion of an expression about 0.
  1707. Parameters
  1708. ==========
  1709. expr : :class:`Expr`
  1710. a : :class:`Symbol` with respect to which expr is to be expanded
  1711. prec : order of the series expansion
  1712. Currently supports multivariate Taylor series expansion. This is much
  1713. faster that SymPy's series method as it uses sparse polynomial operations.
  1714. It automatically creates the simplest ring required to represent the series
  1715. expansion through repeated calls to sring.
  1716. Examples
  1717. ========
  1718. >>> from sympy.polys.ring_series import rs_series
  1719. >>> from sympy import sin, cos, exp, tan, symbols, QQ
  1720. >>> a, b, c = symbols('a, b, c')
  1721. >>> rs_series(sin(a) + exp(a), a, 5)
  1722. 1/24*a**4 + 1/2*a**2 + 2*a + 1
  1723. >>> series = rs_series(tan(a + b)*cos(a + c), a, 2)
  1724. >>> series.as_expr()
  1725. -a*sin(c)*tan(b) + a*cos(c)*tan(b)**2 + a*cos(c) + cos(c)*tan(b)
  1726. >>> series = rs_series(exp(a**QQ(1,3) + a**QQ(2, 5)), a, 1)
  1727. >>> series.as_expr()
  1728. a**(11/15) + a**(4/5)/2 + a**(2/5) + a**(2/3)/2 + a**(1/3) + 1
  1729. """
  1730. R, series = sring(expr, domain=QQ, expand=False, series=True)
  1731. if a not in R.symbols:
  1732. R = R.add_gens([a, ])
  1733. series = series.set_ring(R)
  1734. series = _rs_series(expr, series, a, prec)
  1735. R = series.ring
  1736. gen = R(a)
  1737. prec_got = series.degree(gen) + 1
  1738. if prec_got >= prec:
  1739. return rs_trunc(series, gen, prec)
  1740. else:
  1741. # increase the requested number of terms to get the desired
  1742. # number keep increasing (up to 9) until the received order
  1743. # is different than the original order and then predict how
  1744. # many additional terms are needed
  1745. for more in range(1, 9):
  1746. p1 = _rs_series(expr, series, a, prec=prec + more)
  1747. gen = gen.set_ring(p1.ring)
  1748. new_prec = p1.degree(gen) + 1
  1749. if new_prec != prec_got:
  1750. prec_do = ceiling(prec + (prec - prec_got)*more/(new_prec -
  1751. prec_got))
  1752. p1 = _rs_series(expr, series, a, prec=prec_do)
  1753. while p1.degree(gen) + 1 < prec:
  1754. p1 = _rs_series(expr, series, a, prec=prec_do)
  1755. gen = gen.set_ring(p1.ring)
  1756. prec_do *= 2
  1757. break
  1758. else:
  1759. break
  1760. else:
  1761. raise ValueError('Could not calculate %s terms for %s'
  1762. % (str(prec), expr))
  1763. return rs_trunc(p1, gen, prec)