ring_series.py 58 KB

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