fu.py 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099
  1. from collections import defaultdict
  2. from sympy.core.add import Add
  3. from sympy.core.expr import Expr
  4. from sympy.core.exprtools import Factors, gcd_terms, factor_terms
  5. from sympy.core.function import expand_mul
  6. from sympy.core.mul import Mul
  7. from sympy.core.numbers import pi, I
  8. from sympy.core.power import Pow
  9. from sympy.core.singleton import S
  10. from sympy.core.sorting import ordered
  11. from sympy.core.symbol import Dummy
  12. from sympy.core.sympify import sympify
  13. from sympy.core.traversal import bottom_up
  14. from sympy.functions.combinatorial.factorials import binomial
  15. from sympy.functions.elementary.hyperbolic import (
  16. cosh, sinh, tanh, coth, sech, csch, HyperbolicFunction)
  17. from sympy.functions.elementary.trigonometric import (
  18. cos, sin, tan, cot, sec, csc, sqrt, TrigonometricFunction)
  19. from sympy.ntheory.factor_ import perfect_power
  20. from sympy.polys.polytools import factor
  21. from sympy.strategies.tree import greedy
  22. from sympy.strategies.core import identity, debug
  23. from sympy import SYMPY_DEBUG
  24. # ================== Fu-like tools ===========================
  25. def TR0(rv):
  26. """Simplification of rational polynomials, trying to simplify
  27. the expression, e.g. combine things like 3*x + 2*x, etc....
  28. """
  29. # although it would be nice to use cancel, it doesn't work
  30. # with noncommutatives
  31. return rv.normal().factor().expand()
  32. def TR1(rv):
  33. """Replace sec, csc with 1/cos, 1/sin
  34. Examples
  35. ========
  36. >>> from sympy.simplify.fu import TR1, sec, csc
  37. >>> from sympy.abc import x
  38. >>> TR1(2*csc(x) + sec(x))
  39. 1/cos(x) + 2/sin(x)
  40. """
  41. def f(rv):
  42. if isinstance(rv, sec):
  43. a = rv.args[0]
  44. return S.One/cos(a)
  45. elif isinstance(rv, csc):
  46. a = rv.args[0]
  47. return S.One/sin(a)
  48. return rv
  49. return bottom_up(rv, f)
  50. def TR2(rv):
  51. """Replace tan and cot with sin/cos and cos/sin
  52. Examples
  53. ========
  54. >>> from sympy.simplify.fu import TR2
  55. >>> from sympy.abc import x
  56. >>> from sympy import tan, cot, sin, cos
  57. >>> TR2(tan(x))
  58. sin(x)/cos(x)
  59. >>> TR2(cot(x))
  60. cos(x)/sin(x)
  61. >>> TR2(tan(tan(x) - sin(x)/cos(x)))
  62. 0
  63. """
  64. def f(rv):
  65. if isinstance(rv, tan):
  66. a = rv.args[0]
  67. return sin(a)/cos(a)
  68. elif isinstance(rv, cot):
  69. a = rv.args[0]
  70. return cos(a)/sin(a)
  71. return rv
  72. return bottom_up(rv, f)
  73. def TR2i(rv, half=False):
  74. """Converts ratios involving sin and cos as follows::
  75. sin(x)/cos(x) -> tan(x)
  76. sin(x)/(cos(x) + 1) -> tan(x/2) if half=True
  77. Examples
  78. ========
  79. >>> from sympy.simplify.fu import TR2i
  80. >>> from sympy.abc import x, a
  81. >>> from sympy import sin, cos
  82. >>> TR2i(sin(x)/cos(x))
  83. tan(x)
  84. Powers of the numerator and denominator are also recognized
  85. >>> TR2i(sin(x)**2/(cos(x) + 1)**2, half=True)
  86. tan(x/2)**2
  87. The transformation does not take place unless assumptions allow
  88. (i.e. the base must be positive or the exponent must be an integer
  89. for both numerator and denominator)
  90. >>> TR2i(sin(x)**a/(cos(x) + 1)**a)
  91. sin(x)**a/(cos(x) + 1)**a
  92. """
  93. def f(rv):
  94. if not rv.is_Mul:
  95. return rv
  96. n, d = rv.as_numer_denom()
  97. if n.is_Atom or d.is_Atom:
  98. return rv
  99. def ok(k, e):
  100. # initial filtering of factors
  101. return (
  102. (e.is_integer or k.is_positive) and (
  103. k.func in (sin, cos) or (half and
  104. k.is_Add and
  105. len(k.args) >= 2 and
  106. any(any(isinstance(ai, cos) or ai.is_Pow and ai.base is cos
  107. for ai in Mul.make_args(a)) for a in k.args))))
  108. n = n.as_powers_dict()
  109. ndone = [(k, n.pop(k)) for k in list(n.keys()) if not ok(k, n[k])]
  110. if not n:
  111. return rv
  112. d = d.as_powers_dict()
  113. ddone = [(k, d.pop(k)) for k in list(d.keys()) if not ok(k, d[k])]
  114. if not d:
  115. return rv
  116. # factoring if necessary
  117. def factorize(d, ddone):
  118. newk = []
  119. for k in d:
  120. if k.is_Add and len(k.args) > 1:
  121. knew = factor(k) if half else factor_terms(k)
  122. if knew != k:
  123. newk.append((k, knew))
  124. if newk:
  125. for i, (k, knew) in enumerate(newk):
  126. del d[k]
  127. newk[i] = knew
  128. newk = Mul(*newk).as_powers_dict()
  129. for k in newk:
  130. v = d[k] + newk[k]
  131. if ok(k, v):
  132. d[k] = v
  133. else:
  134. ddone.append((k, v))
  135. del newk
  136. factorize(n, ndone)
  137. factorize(d, ddone)
  138. # joining
  139. t = []
  140. for k in n:
  141. if isinstance(k, sin):
  142. a = cos(k.args[0], evaluate=False)
  143. if a in d and d[a] == n[k]:
  144. t.append(tan(k.args[0])**n[k])
  145. n[k] = d[a] = None
  146. elif half:
  147. a1 = 1 + a
  148. if a1 in d and d[a1] == n[k]:
  149. t.append((tan(k.args[0]/2))**n[k])
  150. n[k] = d[a1] = None
  151. elif isinstance(k, cos):
  152. a = sin(k.args[0], evaluate=False)
  153. if a in d and d[a] == n[k]:
  154. t.append(tan(k.args[0])**-n[k])
  155. n[k] = d[a] = None
  156. elif half and k.is_Add and k.args[0] is S.One and \
  157. isinstance(k.args[1], cos):
  158. a = sin(k.args[1].args[0], evaluate=False)
  159. if a in d and d[a] == n[k] and (d[a].is_integer or \
  160. a.is_positive):
  161. t.append(tan(a.args[0]/2)**-n[k])
  162. n[k] = d[a] = None
  163. if t:
  164. rv = Mul(*(t + [b**e for b, e in n.items() if e]))/\
  165. Mul(*[b**e for b, e in d.items() if e])
  166. rv *= Mul(*[b**e for b, e in ndone])/Mul(*[b**e for b, e in ddone])
  167. return rv
  168. return bottom_up(rv, f)
  169. def TR3(rv):
  170. """Induced formula: example sin(-a) = -sin(a)
  171. Examples
  172. ========
  173. >>> from sympy.simplify.fu import TR3
  174. >>> from sympy.abc import x, y
  175. >>> from sympy import pi
  176. >>> from sympy import cos
  177. >>> TR3(cos(y - x*(y - x)))
  178. cos(x*(x - y) + y)
  179. >>> cos(pi/2 + x)
  180. -sin(x)
  181. >>> cos(30*pi/2 + x)
  182. -cos(x)
  183. """
  184. from sympy.simplify.simplify import signsimp
  185. # Negative argument (already automatic for funcs like sin(-x) -> -sin(x)
  186. # but more complicated expressions can use it, too). Also, trig angles
  187. # between pi/4 and pi/2 are not reduced to an angle between 0 and pi/4.
  188. # The following are automatically handled:
  189. # Argument of type: pi/2 +/- angle
  190. # Argument of type: pi +/- angle
  191. # Argument of type : 2k*pi +/- angle
  192. def f(rv):
  193. if not isinstance(rv, TrigonometricFunction):
  194. return rv
  195. rv = rv.func(signsimp(rv.args[0]))
  196. if not isinstance(rv, TrigonometricFunction):
  197. return rv
  198. if (rv.args[0] - S.Pi/4).is_positive is (S.Pi/2 - rv.args[0]).is_positive is True:
  199. fmap = {cos: sin, sin: cos, tan: cot, cot: tan, sec: csc, csc: sec}
  200. rv = fmap[type(rv)](S.Pi/2 - rv.args[0])
  201. return rv
  202. return bottom_up(rv, f)
  203. def TR4(rv):
  204. """Identify values of special angles.
  205. a= 0 pi/6 pi/4 pi/3 pi/2
  206. ----------------------------------------------------
  207. sin(a) 0 1/2 sqrt(2)/2 sqrt(3)/2 1
  208. cos(a) 1 sqrt(3)/2 sqrt(2)/2 1/2 0
  209. tan(a) 0 sqt(3)/3 1 sqrt(3) --
  210. Examples
  211. ========
  212. >>> from sympy import pi
  213. >>> from sympy import cos, sin, tan, cot
  214. >>> for s in (0, pi/6, pi/4, pi/3, pi/2):
  215. ... print('%s %s %s %s' % (cos(s), sin(s), tan(s), cot(s)))
  216. ...
  217. 1 0 0 zoo
  218. sqrt(3)/2 1/2 sqrt(3)/3 sqrt(3)
  219. sqrt(2)/2 sqrt(2)/2 1 1
  220. 1/2 sqrt(3)/2 sqrt(3) sqrt(3)/3
  221. 0 1 zoo 0
  222. """
  223. # special values at 0, pi/6, pi/4, pi/3, pi/2 already handled
  224. return rv
  225. def _TR56(rv, f, g, h, max, pow):
  226. """Helper for TR5 and TR6 to replace f**2 with h(g**2)
  227. Options
  228. =======
  229. max : controls size of exponent that can appear on f
  230. e.g. if max=4 then f**4 will be changed to h(g**2)**2.
  231. pow : controls whether the exponent must be a perfect power of 2
  232. e.g. if pow=True (and max >= 6) then f**6 will not be changed
  233. but f**8 will be changed to h(g**2)**4
  234. >>> from sympy.simplify.fu import _TR56 as T
  235. >>> from sympy.abc import x
  236. >>> from sympy import sin, cos
  237. >>> h = lambda x: 1 - x
  238. >>> T(sin(x)**3, sin, cos, h, 4, False)
  239. (1 - cos(x)**2)*sin(x)
  240. >>> T(sin(x)**6, sin, cos, h, 6, False)
  241. (1 - cos(x)**2)**3
  242. >>> T(sin(x)**6, sin, cos, h, 6, True)
  243. sin(x)**6
  244. >>> T(sin(x)**8, sin, cos, h, 10, True)
  245. (1 - cos(x)**2)**4
  246. """
  247. def _f(rv):
  248. # I'm not sure if this transformation should target all even powers
  249. # or only those expressible as powers of 2. Also, should it only
  250. # make the changes in powers that appear in sums -- making an isolated
  251. # change is not going to allow a simplification as far as I can tell.
  252. if not (rv.is_Pow and rv.base.func == f):
  253. return rv
  254. if not rv.exp.is_real:
  255. return rv
  256. if (rv.exp < 0) == True:
  257. return rv
  258. if (rv.exp > max) == True:
  259. return rv
  260. if rv.exp == 1:
  261. return rv
  262. if rv.exp == 2:
  263. return h(g(rv.base.args[0])**2)
  264. else:
  265. if rv.exp % 2 == 1:
  266. e = rv.exp//2
  267. return f(rv.base.args[0])*h(g(rv.base.args[0])**2)**e
  268. elif rv.exp == 4:
  269. e = 2
  270. elif not pow:
  271. if rv.exp % 2:
  272. return rv
  273. e = rv.exp//2
  274. else:
  275. p = perfect_power(rv.exp)
  276. if not p:
  277. return rv
  278. e = rv.exp//2
  279. return h(g(rv.base.args[0])**2)**e
  280. return bottom_up(rv, _f)
  281. def TR5(rv, max=4, pow=False):
  282. """Replacement of sin**2 with 1 - cos(x)**2.
  283. See _TR56 docstring for advanced use of ``max`` and ``pow``.
  284. Examples
  285. ========
  286. >>> from sympy.simplify.fu import TR5
  287. >>> from sympy.abc import x
  288. >>> from sympy import sin
  289. >>> TR5(sin(x)**2)
  290. 1 - cos(x)**2
  291. >>> TR5(sin(x)**-2) # unchanged
  292. sin(x)**(-2)
  293. >>> TR5(sin(x)**4)
  294. (1 - cos(x)**2)**2
  295. """
  296. return _TR56(rv, sin, cos, lambda x: 1 - x, max=max, pow=pow)
  297. def TR6(rv, max=4, pow=False):
  298. """Replacement of cos**2 with 1 - sin(x)**2.
  299. See _TR56 docstring for advanced use of ``max`` and ``pow``.
  300. Examples
  301. ========
  302. >>> from sympy.simplify.fu import TR6
  303. >>> from sympy.abc import x
  304. >>> from sympy import cos
  305. >>> TR6(cos(x)**2)
  306. 1 - sin(x)**2
  307. >>> TR6(cos(x)**-2) #unchanged
  308. cos(x)**(-2)
  309. >>> TR6(cos(x)**4)
  310. (1 - sin(x)**2)**2
  311. """
  312. return _TR56(rv, cos, sin, lambda x: 1 - x, max=max, pow=pow)
  313. def TR7(rv):
  314. """Lowering the degree of cos(x)**2.
  315. Examples
  316. ========
  317. >>> from sympy.simplify.fu import TR7
  318. >>> from sympy.abc import x
  319. >>> from sympy import cos
  320. >>> TR7(cos(x)**2)
  321. cos(2*x)/2 + 1/2
  322. >>> TR7(cos(x)**2 + 1)
  323. cos(2*x)/2 + 3/2
  324. """
  325. def f(rv):
  326. if not (rv.is_Pow and rv.base.func == cos and rv.exp == 2):
  327. return rv
  328. return (1 + cos(2*rv.base.args[0]))/2
  329. return bottom_up(rv, f)
  330. def TR8(rv, first=True):
  331. """Converting products of ``cos`` and/or ``sin`` to a sum or
  332. difference of ``cos`` and or ``sin`` terms.
  333. Examples
  334. ========
  335. >>> from sympy.simplify.fu import TR8
  336. >>> from sympy import cos, sin
  337. >>> TR8(cos(2)*cos(3))
  338. cos(5)/2 + cos(1)/2
  339. >>> TR8(cos(2)*sin(3))
  340. sin(5)/2 + sin(1)/2
  341. >>> TR8(sin(2)*sin(3))
  342. -cos(5)/2 + cos(1)/2
  343. """
  344. def f(rv):
  345. if not (
  346. rv.is_Mul or
  347. rv.is_Pow and
  348. rv.base.func in (cos, sin) and
  349. (rv.exp.is_integer or rv.base.is_positive)):
  350. return rv
  351. if first:
  352. n, d = [expand_mul(i) for i in rv.as_numer_denom()]
  353. newn = TR8(n, first=False)
  354. newd = TR8(d, first=False)
  355. if newn != n or newd != d:
  356. rv = gcd_terms(newn/newd)
  357. if rv.is_Mul and rv.args[0].is_Rational and \
  358. len(rv.args) == 2 and rv.args[1].is_Add:
  359. rv = Mul(*rv.as_coeff_Mul())
  360. return rv
  361. args = {cos: [], sin: [], None: []}
  362. for a in ordered(Mul.make_args(rv)):
  363. if a.func in (cos, sin):
  364. args[type(a)].append(a.args[0])
  365. elif (a.is_Pow and a.exp.is_Integer and a.exp > 0 and \
  366. a.base.func in (cos, sin)):
  367. # XXX this is ok but pathological expression could be handled
  368. # more efficiently as in TRmorrie
  369. args[type(a.base)].extend([a.base.args[0]]*a.exp)
  370. else:
  371. args[None].append(a)
  372. c = args[cos]
  373. s = args[sin]
  374. if not (c and s or len(c) > 1 or len(s) > 1):
  375. return rv
  376. args = args[None]
  377. n = min(len(c), len(s))
  378. for i in range(n):
  379. a1 = s.pop()
  380. a2 = c.pop()
  381. args.append((sin(a1 + a2) + sin(a1 - a2))/2)
  382. while len(c) > 1:
  383. a1 = c.pop()
  384. a2 = c.pop()
  385. args.append((cos(a1 + a2) + cos(a1 - a2))/2)
  386. if c:
  387. args.append(cos(c.pop()))
  388. while len(s) > 1:
  389. a1 = s.pop()
  390. a2 = s.pop()
  391. args.append((-cos(a1 + a2) + cos(a1 - a2))/2)
  392. if s:
  393. args.append(sin(s.pop()))
  394. return TR8(expand_mul(Mul(*args)))
  395. return bottom_up(rv, f)
  396. def TR9(rv):
  397. """Sum of ``cos`` or ``sin`` terms as a product of ``cos`` or ``sin``.
  398. Examples
  399. ========
  400. >>> from sympy.simplify.fu import TR9
  401. >>> from sympy import cos, sin
  402. >>> TR9(cos(1) + cos(2))
  403. 2*cos(1/2)*cos(3/2)
  404. >>> TR9(cos(1) + 2*sin(1) + 2*sin(2))
  405. cos(1) + 4*sin(3/2)*cos(1/2)
  406. If no change is made by TR9, no re-arrangement of the
  407. expression will be made. For example, though factoring
  408. of common term is attempted, if the factored expression
  409. wasn't changed, the original expression will be returned:
  410. >>> TR9(cos(3) + cos(3)*cos(2))
  411. cos(3) + cos(2)*cos(3)
  412. """
  413. def f(rv):
  414. if not rv.is_Add:
  415. return rv
  416. def do(rv, first=True):
  417. # cos(a)+/-cos(b) can be combined into a product of cosines and
  418. # sin(a)+/-sin(b) can be combined into a product of cosine and
  419. # sine.
  420. #
  421. # If there are more than two args, the pairs which "work" will
  422. # have a gcd extractable and the remaining two terms will have
  423. # the above structure -- all pairs must be checked to find the
  424. # ones that work. args that don't have a common set of symbols
  425. # are skipped since this doesn't lead to a simpler formula and
  426. # also has the arbitrariness of combining, for example, the x
  427. # and y term instead of the y and z term in something like
  428. # cos(x) + cos(y) + cos(z).
  429. if not rv.is_Add:
  430. return rv
  431. args = list(ordered(rv.args))
  432. if len(args) != 2:
  433. hit = False
  434. for i in range(len(args)):
  435. ai = args[i]
  436. if ai is None:
  437. continue
  438. for j in range(i + 1, len(args)):
  439. aj = args[j]
  440. if aj is None:
  441. continue
  442. was = ai + aj
  443. new = do(was)
  444. if new != was:
  445. args[i] = new # update in place
  446. args[j] = None
  447. hit = True
  448. break # go to next i
  449. if hit:
  450. rv = Add(*[_f for _f in args if _f])
  451. if rv.is_Add:
  452. rv = do(rv)
  453. return rv
  454. # two-arg Add
  455. split = trig_split(*args)
  456. if not split:
  457. return rv
  458. gcd, n1, n2, a, b, iscos = split
  459. # application of rule if possible
  460. if iscos:
  461. if n1 == n2:
  462. return gcd*n1*2*cos((a + b)/2)*cos((a - b)/2)
  463. if n1 < 0:
  464. a, b = b, a
  465. return -2*gcd*sin((a + b)/2)*sin((a - b)/2)
  466. else:
  467. if n1 == n2:
  468. return gcd*n1*2*sin((a + b)/2)*cos((a - b)/2)
  469. if n1 < 0:
  470. a, b = b, a
  471. return 2*gcd*cos((a + b)/2)*sin((a - b)/2)
  472. return process_common_addends(rv, do) # DON'T sift by free symbols
  473. return bottom_up(rv, f)
  474. def TR10(rv, first=True):
  475. """Separate sums in ``cos`` and ``sin``.
  476. Examples
  477. ========
  478. >>> from sympy.simplify.fu import TR10
  479. >>> from sympy.abc import a, b, c
  480. >>> from sympy import cos, sin
  481. >>> TR10(cos(a + b))
  482. -sin(a)*sin(b) + cos(a)*cos(b)
  483. >>> TR10(sin(a + b))
  484. sin(a)*cos(b) + sin(b)*cos(a)
  485. >>> TR10(sin(a + b + c))
  486. (-sin(a)*sin(b) + cos(a)*cos(b))*sin(c) + \
  487. (sin(a)*cos(b) + sin(b)*cos(a))*cos(c)
  488. """
  489. def f(rv):
  490. if rv.func not in (cos, sin):
  491. return rv
  492. f = rv.func
  493. arg = rv.args[0]
  494. if arg.is_Add:
  495. if first:
  496. args = list(ordered(arg.args))
  497. else:
  498. args = list(arg.args)
  499. a = args.pop()
  500. b = Add._from_args(args)
  501. if b.is_Add:
  502. if f == sin:
  503. return sin(a)*TR10(cos(b), first=False) + \
  504. cos(a)*TR10(sin(b), first=False)
  505. else:
  506. return cos(a)*TR10(cos(b), first=False) - \
  507. sin(a)*TR10(sin(b), first=False)
  508. else:
  509. if f == sin:
  510. return sin(a)*cos(b) + cos(a)*sin(b)
  511. else:
  512. return cos(a)*cos(b) - sin(a)*sin(b)
  513. return rv
  514. return bottom_up(rv, f)
  515. def TR10i(rv):
  516. """Sum of products to function of sum.
  517. Examples
  518. ========
  519. >>> from sympy.simplify.fu import TR10i
  520. >>> from sympy import cos, sin, sqrt
  521. >>> from sympy.abc import x
  522. >>> TR10i(cos(1)*cos(3) + sin(1)*sin(3))
  523. cos(2)
  524. >>> TR10i(cos(1)*sin(3) + sin(1)*cos(3) + cos(3))
  525. cos(3) + sin(4)
  526. >>> TR10i(sqrt(2)*cos(x)*x + sqrt(6)*sin(x)*x)
  527. 2*sqrt(2)*x*sin(x + pi/6)
  528. """
  529. global _ROOT2, _ROOT3, _invROOT3
  530. if _ROOT2 is None:
  531. _roots()
  532. def f(rv):
  533. if not rv.is_Add:
  534. return rv
  535. def do(rv, first=True):
  536. # args which can be expressed as A*(cos(a)*cos(b)+/-sin(a)*sin(b))
  537. # or B*(cos(a)*sin(b)+/-cos(b)*sin(a)) can be combined into
  538. # A*f(a+/-b) where f is either sin or cos.
  539. #
  540. # If there are more than two args, the pairs which "work" will have
  541. # a gcd extractable and the remaining two terms will have the above
  542. # structure -- all pairs must be checked to find the ones that
  543. # work.
  544. if not rv.is_Add:
  545. return rv
  546. args = list(ordered(rv.args))
  547. if len(args) != 2:
  548. hit = False
  549. for i in range(len(args)):
  550. ai = args[i]
  551. if ai is None:
  552. continue
  553. for j in range(i + 1, len(args)):
  554. aj = args[j]
  555. if aj is None:
  556. continue
  557. was = ai + aj
  558. new = do(was)
  559. if new != was:
  560. args[i] = new # update in place
  561. args[j] = None
  562. hit = True
  563. break # go to next i
  564. if hit:
  565. rv = Add(*[_f for _f in args if _f])
  566. if rv.is_Add:
  567. rv = do(rv)
  568. return rv
  569. # two-arg Add
  570. split = trig_split(*args, two=True)
  571. if not split:
  572. return rv
  573. gcd, n1, n2, a, b, same = split
  574. # identify and get c1 to be cos then apply rule if possible
  575. if same: # coscos, sinsin
  576. gcd = n1*gcd
  577. if n1 == n2:
  578. return gcd*cos(a - b)
  579. return gcd*cos(a + b)
  580. else: #cossin, cossin
  581. gcd = n1*gcd
  582. if n1 == n2:
  583. return gcd*sin(a + b)
  584. return gcd*sin(b - a)
  585. rv = process_common_addends(
  586. rv, do, lambda x: tuple(ordered(x.free_symbols)))
  587. # need to check for inducible pairs in ratio of sqrt(3):1 that
  588. # appeared in different lists when sorting by coefficient
  589. while rv.is_Add:
  590. byrad = defaultdict(list)
  591. for a in rv.args:
  592. hit = 0
  593. if a.is_Mul:
  594. for ai in a.args:
  595. if ai.is_Pow and ai.exp is S.Half and \
  596. ai.base.is_Integer:
  597. byrad[ai].append(a)
  598. hit = 1
  599. break
  600. if not hit:
  601. byrad[S.One].append(a)
  602. # no need to check all pairs -- just check for the onees
  603. # that have the right ratio
  604. args = []
  605. for a in byrad:
  606. for b in [_ROOT3*a, _invROOT3]:
  607. if b in byrad:
  608. for i in range(len(byrad[a])):
  609. if byrad[a][i] is None:
  610. continue
  611. for j in range(len(byrad[b])):
  612. if byrad[b][j] is None:
  613. continue
  614. was = Add(byrad[a][i] + byrad[b][j])
  615. new = do(was)
  616. if new != was:
  617. args.append(new)
  618. byrad[a][i] = None
  619. byrad[b][j] = None
  620. break
  621. if args:
  622. rv = Add(*(args + [Add(*[_f for _f in v if _f])
  623. for v in byrad.values()]))
  624. else:
  625. rv = do(rv) # final pass to resolve any new inducible pairs
  626. break
  627. return rv
  628. return bottom_up(rv, f)
  629. def TR11(rv, base=None):
  630. """Function of double angle to product. The ``base`` argument can be used
  631. to indicate what is the un-doubled argument, e.g. if 3*pi/7 is the base
  632. then cosine and sine functions with argument 6*pi/7 will be replaced.
  633. Examples
  634. ========
  635. >>> from sympy.simplify.fu import TR11
  636. >>> from sympy import cos, sin, pi
  637. >>> from sympy.abc import x
  638. >>> TR11(sin(2*x))
  639. 2*sin(x)*cos(x)
  640. >>> TR11(cos(2*x))
  641. -sin(x)**2 + cos(x)**2
  642. >>> TR11(sin(4*x))
  643. 4*(-sin(x)**2 + cos(x)**2)*sin(x)*cos(x)
  644. >>> TR11(sin(4*x/3))
  645. 4*(-sin(x/3)**2 + cos(x/3)**2)*sin(x/3)*cos(x/3)
  646. If the arguments are simply integers, no change is made
  647. unless a base is provided:
  648. >>> TR11(cos(2))
  649. cos(2)
  650. >>> TR11(cos(4), 2)
  651. -sin(2)**2 + cos(2)**2
  652. There is a subtle issue here in that autosimplification will convert
  653. some higher angles to lower angles
  654. >>> cos(6*pi/7) + cos(3*pi/7)
  655. -cos(pi/7) + cos(3*pi/7)
  656. The 6*pi/7 angle is now pi/7 but can be targeted with TR11 by supplying
  657. the 3*pi/7 base:
  658. >>> TR11(_, 3*pi/7)
  659. -sin(3*pi/7)**2 + cos(3*pi/7)**2 + cos(3*pi/7)
  660. """
  661. def f(rv):
  662. if rv.func not in (cos, sin):
  663. return rv
  664. if base:
  665. f = rv.func
  666. t = f(base*2)
  667. co = S.One
  668. if t.is_Mul:
  669. co, t = t.as_coeff_Mul()
  670. if t.func not in (cos, sin):
  671. return rv
  672. if rv.args[0] == t.args[0]:
  673. c = cos(base)
  674. s = sin(base)
  675. if f is cos:
  676. return (c**2 - s**2)/co
  677. else:
  678. return 2*c*s/co
  679. return rv
  680. elif not rv.args[0].is_Number:
  681. # make a change if the leading coefficient's numerator is
  682. # divisible by 2
  683. c, m = rv.args[0].as_coeff_Mul(rational=True)
  684. if c.p % 2 == 0:
  685. arg = c.p//2*m/c.q
  686. c = TR11(cos(arg))
  687. s = TR11(sin(arg))
  688. if rv.func == sin:
  689. rv = 2*s*c
  690. else:
  691. rv = c**2 - s**2
  692. return rv
  693. return bottom_up(rv, f)
  694. def _TR11(rv):
  695. """
  696. Helper for TR11 to find half-arguments for sin in factors of
  697. num/den that appear in cos or sin factors in the den/num.
  698. Examples
  699. ========
  700. >>> from sympy.simplify.fu import TR11, _TR11
  701. >>> from sympy import cos, sin
  702. >>> from sympy.abc import x
  703. >>> TR11(sin(x/3)/(cos(x/6)))
  704. sin(x/3)/cos(x/6)
  705. >>> _TR11(sin(x/3)/(cos(x/6)))
  706. 2*sin(x/6)
  707. >>> TR11(sin(x/6)/(sin(x/3)))
  708. sin(x/6)/sin(x/3)
  709. >>> _TR11(sin(x/6)/(sin(x/3)))
  710. 1/(2*cos(x/6))
  711. """
  712. def f(rv):
  713. if not isinstance(rv, Expr):
  714. return rv
  715. def sincos_args(flat):
  716. # find arguments of sin and cos that
  717. # appears as bases in args of flat
  718. # and have Integer exponents
  719. args = defaultdict(set)
  720. for fi in Mul.make_args(flat):
  721. b, e = fi.as_base_exp()
  722. if e.is_Integer and e > 0:
  723. if b.func in (cos, sin):
  724. args[type(b)].add(b.args[0])
  725. return args
  726. num_args, den_args = map(sincos_args, rv.as_numer_denom())
  727. def handle_match(rv, num_args, den_args):
  728. # for arg in sin args of num_args, look for arg/2
  729. # in den_args and pass this half-angle to TR11
  730. # for handling in rv
  731. for narg in num_args[sin]:
  732. half = narg/2
  733. if half in den_args[cos]:
  734. func = cos
  735. elif half in den_args[sin]:
  736. func = sin
  737. else:
  738. continue
  739. rv = TR11(rv, half)
  740. den_args[func].remove(half)
  741. return rv
  742. # sin in num, sin or cos in den
  743. rv = handle_match(rv, num_args, den_args)
  744. # sin in den, sin or cos in num
  745. rv = handle_match(rv, den_args, num_args)
  746. return rv
  747. return bottom_up(rv, f)
  748. def TR12(rv, first=True):
  749. """Separate sums in ``tan``.
  750. Examples
  751. ========
  752. >>> from sympy.abc import x, y
  753. >>> from sympy import tan
  754. >>> from sympy.simplify.fu import TR12
  755. >>> TR12(tan(x + y))
  756. (tan(x) + tan(y))/(-tan(x)*tan(y) + 1)
  757. """
  758. def f(rv):
  759. if not rv.func == tan:
  760. return rv
  761. arg = rv.args[0]
  762. if arg.is_Add:
  763. if first:
  764. args = list(ordered(arg.args))
  765. else:
  766. args = list(arg.args)
  767. a = args.pop()
  768. b = Add._from_args(args)
  769. if b.is_Add:
  770. tb = TR12(tan(b), first=False)
  771. else:
  772. tb = tan(b)
  773. return (tan(a) + tb)/(1 - tan(a)*tb)
  774. return rv
  775. return bottom_up(rv, f)
  776. def TR12i(rv):
  777. """Combine tan arguments as
  778. (tan(y) + tan(x))/(tan(x)*tan(y) - 1) -> -tan(x + y).
  779. Examples
  780. ========
  781. >>> from sympy.simplify.fu import TR12i
  782. >>> from sympy import tan
  783. >>> from sympy.abc import a, b, c
  784. >>> ta, tb, tc = [tan(i) for i in (a, b, c)]
  785. >>> TR12i((ta + tb)/(-ta*tb + 1))
  786. tan(a + b)
  787. >>> TR12i((ta + tb)/(ta*tb - 1))
  788. -tan(a + b)
  789. >>> TR12i((-ta - tb)/(ta*tb - 1))
  790. tan(a + b)
  791. >>> eq = (ta + tb)/(-ta*tb + 1)**2*(-3*ta - 3*tc)/(2*(ta*tc - 1))
  792. >>> TR12i(eq.expand())
  793. -3*tan(a + b)*tan(a + c)/(2*(tan(a) + tan(b) - 1))
  794. """
  795. def f(rv):
  796. if not (rv.is_Add or rv.is_Mul or rv.is_Pow):
  797. return rv
  798. n, d = rv.as_numer_denom()
  799. if not d.args or not n.args:
  800. return rv
  801. dok = {}
  802. def ok(di):
  803. m = as_f_sign_1(di)
  804. if m:
  805. g, f, s = m
  806. if s is S.NegativeOne and f.is_Mul and len(f.args) == 2 and \
  807. all(isinstance(fi, tan) for fi in f.args):
  808. return g, f
  809. d_args = list(Mul.make_args(d))
  810. for i, di in enumerate(d_args):
  811. m = ok(di)
  812. if m:
  813. g, t = m
  814. s = Add(*[_.args[0] for _ in t.args])
  815. dok[s] = S.One
  816. d_args[i] = g
  817. continue
  818. if di.is_Add:
  819. di = factor(di)
  820. if di.is_Mul:
  821. d_args.extend(di.args)
  822. d_args[i] = S.One
  823. elif di.is_Pow and (di.exp.is_integer or di.base.is_positive):
  824. m = ok(di.base)
  825. if m:
  826. g, t = m
  827. s = Add(*[_.args[0] for _ in t.args])
  828. dok[s] = di.exp
  829. d_args[i] = g**di.exp
  830. else:
  831. di = factor(di)
  832. if di.is_Mul:
  833. d_args.extend(di.args)
  834. d_args[i] = S.One
  835. if not dok:
  836. return rv
  837. def ok(ni):
  838. if ni.is_Add and len(ni.args) == 2:
  839. a, b = ni.args
  840. if isinstance(a, tan) and isinstance(b, tan):
  841. return a, b
  842. n_args = list(Mul.make_args(factor_terms(n)))
  843. hit = False
  844. for i, ni in enumerate(n_args):
  845. m = ok(ni)
  846. if not m:
  847. m = ok(-ni)
  848. if m:
  849. n_args[i] = S.NegativeOne
  850. else:
  851. if ni.is_Add:
  852. ni = factor(ni)
  853. if ni.is_Mul:
  854. n_args.extend(ni.args)
  855. n_args[i] = S.One
  856. continue
  857. elif ni.is_Pow and (
  858. ni.exp.is_integer or ni.base.is_positive):
  859. m = ok(ni.base)
  860. if m:
  861. n_args[i] = S.One
  862. else:
  863. ni = factor(ni)
  864. if ni.is_Mul:
  865. n_args.extend(ni.args)
  866. n_args[i] = S.One
  867. continue
  868. else:
  869. continue
  870. else:
  871. n_args[i] = S.One
  872. hit = True
  873. s = Add(*[_.args[0] for _ in m])
  874. ed = dok[s]
  875. newed = ed.extract_additively(S.One)
  876. if newed is not None:
  877. if newed:
  878. dok[s] = newed
  879. else:
  880. dok.pop(s)
  881. n_args[i] *= -tan(s)
  882. if hit:
  883. rv = Mul(*n_args)/Mul(*d_args)/Mul(*[(Add(*[
  884. tan(a) for a in i.args]) - 1)**e for i, e in dok.items()])
  885. return rv
  886. return bottom_up(rv, f)
  887. def TR13(rv):
  888. """Change products of ``tan`` or ``cot``.
  889. Examples
  890. ========
  891. >>> from sympy.simplify.fu import TR13
  892. >>> from sympy import tan, cot
  893. >>> TR13(tan(3)*tan(2))
  894. -tan(2)/tan(5) - tan(3)/tan(5) + 1
  895. >>> TR13(cot(3)*cot(2))
  896. cot(2)*cot(5) + 1 + cot(3)*cot(5)
  897. """
  898. def f(rv):
  899. if not rv.is_Mul:
  900. return rv
  901. # XXX handle products of powers? or let power-reducing handle it?
  902. args = {tan: [], cot: [], None: []}
  903. for a in ordered(Mul.make_args(rv)):
  904. if a.func in (tan, cot):
  905. args[type(a)].append(a.args[0])
  906. else:
  907. args[None].append(a)
  908. t = args[tan]
  909. c = args[cot]
  910. if len(t) < 2 and len(c) < 2:
  911. return rv
  912. args = args[None]
  913. while len(t) > 1:
  914. t1 = t.pop()
  915. t2 = t.pop()
  916. args.append(1 - (tan(t1)/tan(t1 + t2) + tan(t2)/tan(t1 + t2)))
  917. if t:
  918. args.append(tan(t.pop()))
  919. while len(c) > 1:
  920. t1 = c.pop()
  921. t2 = c.pop()
  922. args.append(1 + cot(t1)*cot(t1 + t2) + cot(t2)*cot(t1 + t2))
  923. if c:
  924. args.append(cot(c.pop()))
  925. return Mul(*args)
  926. return bottom_up(rv, f)
  927. def TRmorrie(rv):
  928. """Returns cos(x)*cos(2*x)*...*cos(2**(k-1)*x) -> sin(2**k*x)/(2**k*sin(x))
  929. Examples
  930. ========
  931. >>> from sympy.simplify.fu import TRmorrie, TR8, TR3
  932. >>> from sympy.abc import x
  933. >>> from sympy import Mul, cos, pi
  934. >>> TRmorrie(cos(x)*cos(2*x))
  935. sin(4*x)/(4*sin(x))
  936. >>> TRmorrie(7*Mul(*[cos(x) for x in range(10)]))
  937. 7*sin(12)*sin(16)*cos(5)*cos(7)*cos(9)/(64*sin(1)*sin(3))
  938. Sometimes autosimplification will cause a power to be
  939. not recognized. e.g. in the following, cos(4*pi/7) automatically
  940. simplifies to -cos(3*pi/7) so only 2 of the 3 terms are
  941. recognized:
  942. >>> TRmorrie(cos(pi/7)*cos(2*pi/7)*cos(4*pi/7))
  943. -sin(3*pi/7)*cos(3*pi/7)/(4*sin(pi/7))
  944. A touch by TR8 resolves the expression to a Rational
  945. >>> TR8(_)
  946. -1/8
  947. In this case, if eq is unsimplified, the answer is obtained
  948. directly:
  949. >>> eq = cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9)
  950. >>> TRmorrie(eq)
  951. 1/16
  952. But if angles are made canonical with TR3 then the answer
  953. is not simplified without further work:
  954. >>> TR3(eq)
  955. sin(pi/18)*cos(pi/9)*cos(2*pi/9)/2
  956. >>> TRmorrie(_)
  957. sin(pi/18)*sin(4*pi/9)/(8*sin(pi/9))
  958. >>> TR8(_)
  959. cos(7*pi/18)/(16*sin(pi/9))
  960. >>> TR3(_)
  961. 1/16
  962. The original expression would have resolve to 1/16 directly with TR8,
  963. however:
  964. >>> TR8(eq)
  965. 1/16
  966. References
  967. ==========
  968. .. [1] https://en.wikipedia.org/wiki/Morrie%27s_law
  969. """
  970. def f(rv, first=True):
  971. if not rv.is_Mul:
  972. return rv
  973. if first:
  974. n, d = rv.as_numer_denom()
  975. return f(n, 0)/f(d, 0)
  976. args = defaultdict(list)
  977. coss = {}
  978. other = []
  979. for c in rv.args:
  980. b, e = c.as_base_exp()
  981. if e.is_Integer and isinstance(b, cos):
  982. co, a = b.args[0].as_coeff_Mul()
  983. args[a].append(co)
  984. coss[b] = e
  985. else:
  986. other.append(c)
  987. new = []
  988. for a in args:
  989. c = args[a]
  990. c.sort()
  991. while c:
  992. k = 0
  993. cc = ci = c[0]
  994. while cc in c:
  995. k += 1
  996. cc *= 2
  997. if k > 1:
  998. newarg = sin(2**k*ci*a)/2**k/sin(ci*a)
  999. # see how many times this can be taken
  1000. take = None
  1001. ccs = []
  1002. for i in range(k):
  1003. cc /= 2
  1004. key = cos(a*cc, evaluate=False)
  1005. ccs.append(cc)
  1006. take = min(coss[key], take or coss[key])
  1007. # update exponent counts
  1008. for i in range(k):
  1009. cc = ccs.pop()
  1010. key = cos(a*cc, evaluate=False)
  1011. coss[key] -= take
  1012. if not coss[key]:
  1013. c.remove(cc)
  1014. new.append(newarg**take)
  1015. else:
  1016. b = cos(c.pop(0)*a)
  1017. other.append(b**coss[b])
  1018. if new:
  1019. rv = Mul(*(new + other + [
  1020. cos(k*a, evaluate=False) for a in args for k in args[a]]))
  1021. return rv
  1022. return bottom_up(rv, f)
  1023. def TR14(rv, first=True):
  1024. """Convert factored powers of sin and cos identities into simpler
  1025. expressions.
  1026. Examples
  1027. ========
  1028. >>> from sympy.simplify.fu import TR14
  1029. >>> from sympy.abc import x, y
  1030. >>> from sympy import cos, sin
  1031. >>> TR14((cos(x) - 1)*(cos(x) + 1))
  1032. -sin(x)**2
  1033. >>> TR14((sin(x) - 1)*(sin(x) + 1))
  1034. -cos(x)**2
  1035. >>> p1 = (cos(x) + 1)*(cos(x) - 1)
  1036. >>> p2 = (cos(y) - 1)*2*(cos(y) + 1)
  1037. >>> p3 = (3*(cos(y) - 1))*(3*(cos(y) + 1))
  1038. >>> TR14(p1*p2*p3*(x - 1))
  1039. -18*(x - 1)*sin(x)**2*sin(y)**4
  1040. """
  1041. def f(rv):
  1042. if not rv.is_Mul:
  1043. return rv
  1044. if first:
  1045. # sort them by location in numerator and denominator
  1046. # so the code below can just deal with positive exponents
  1047. n, d = rv.as_numer_denom()
  1048. if d is not S.One:
  1049. newn = TR14(n, first=False)
  1050. newd = TR14(d, first=False)
  1051. if newn != n or newd != d:
  1052. rv = newn/newd
  1053. return rv
  1054. other = []
  1055. process = []
  1056. for a in rv.args:
  1057. if a.is_Pow:
  1058. b, e = a.as_base_exp()
  1059. if not (e.is_integer or b.is_positive):
  1060. other.append(a)
  1061. continue
  1062. a = b
  1063. else:
  1064. e = S.One
  1065. m = as_f_sign_1(a)
  1066. if not m or m[1].func not in (cos, sin):
  1067. if e is S.One:
  1068. other.append(a)
  1069. else:
  1070. other.append(a**e)
  1071. continue
  1072. g, f, si = m
  1073. process.append((g, e.is_Number, e, f, si, a))
  1074. # sort them to get like terms next to each other
  1075. process = list(ordered(process))
  1076. # keep track of whether there was any change
  1077. nother = len(other)
  1078. # access keys
  1079. keys = (g, t, e, f, si, a) = list(range(6))
  1080. while process:
  1081. A = process.pop(0)
  1082. if process:
  1083. B = process[0]
  1084. if A[e].is_Number and B[e].is_Number:
  1085. # both exponents are numbers
  1086. if A[f] == B[f]:
  1087. if A[si] != B[si]:
  1088. B = process.pop(0)
  1089. take = min(A[e], B[e])
  1090. # reinsert any remainder
  1091. # the B will likely sort after A so check it first
  1092. if B[e] != take:
  1093. rem = [B[i] for i in keys]
  1094. rem[e] -= take
  1095. process.insert(0, rem)
  1096. elif A[e] != take:
  1097. rem = [A[i] for i in keys]
  1098. rem[e] -= take
  1099. process.insert(0, rem)
  1100. if isinstance(A[f], cos):
  1101. t = sin
  1102. else:
  1103. t = cos
  1104. other.append((-A[g]*B[g]*t(A[f].args[0])**2)**take)
  1105. continue
  1106. elif A[e] == B[e]:
  1107. # both exponents are equal symbols
  1108. if A[f] == B[f]:
  1109. if A[si] != B[si]:
  1110. B = process.pop(0)
  1111. take = A[e]
  1112. if isinstance(A[f], cos):
  1113. t = sin
  1114. else:
  1115. t = cos
  1116. other.append((-A[g]*B[g]*t(A[f].args[0])**2)**take)
  1117. continue
  1118. # either we are done or neither condition above applied
  1119. other.append(A[a]**A[e])
  1120. if len(other) != nother:
  1121. rv = Mul(*other)
  1122. return rv
  1123. return bottom_up(rv, f)
  1124. def TR15(rv, max=4, pow=False):
  1125. """Convert sin(x)**-2 to 1 + cot(x)**2.
  1126. See _TR56 docstring for advanced use of ``max`` and ``pow``.
  1127. Examples
  1128. ========
  1129. >>> from sympy.simplify.fu import TR15
  1130. >>> from sympy.abc import x
  1131. >>> from sympy import sin
  1132. >>> TR15(1 - 1/sin(x)**2)
  1133. -cot(x)**2
  1134. """
  1135. def f(rv):
  1136. if not (isinstance(rv, Pow) and isinstance(rv.base, sin)):
  1137. return rv
  1138. e = rv.exp
  1139. if e % 2 == 1:
  1140. return TR15(rv.base**(e + 1))/rv.base
  1141. ia = 1/rv
  1142. a = _TR56(ia, sin, cot, lambda x: 1 + x, max=max, pow=pow)
  1143. if a != ia:
  1144. rv = a
  1145. return rv
  1146. return bottom_up(rv, f)
  1147. def TR16(rv, max=4, pow=False):
  1148. """Convert cos(x)**-2 to 1 + tan(x)**2.
  1149. See _TR56 docstring for advanced use of ``max`` and ``pow``.
  1150. Examples
  1151. ========
  1152. >>> from sympy.simplify.fu import TR16
  1153. >>> from sympy.abc import x
  1154. >>> from sympy import cos
  1155. >>> TR16(1 - 1/cos(x)**2)
  1156. -tan(x)**2
  1157. """
  1158. def f(rv):
  1159. if not (isinstance(rv, Pow) and isinstance(rv.base, cos)):
  1160. return rv
  1161. e = rv.exp
  1162. if e % 2 == 1:
  1163. return TR15(rv.base**(e + 1))/rv.base
  1164. ia = 1/rv
  1165. a = _TR56(ia, cos, tan, lambda x: 1 + x, max=max, pow=pow)
  1166. if a != ia:
  1167. rv = a
  1168. return rv
  1169. return bottom_up(rv, f)
  1170. def TR111(rv):
  1171. """Convert f(x)**-i to g(x)**i where either ``i`` is an integer
  1172. or the base is positive and f, g are: tan, cot; sin, csc; or cos, sec.
  1173. Examples
  1174. ========
  1175. >>> from sympy.simplify.fu import TR111
  1176. >>> from sympy.abc import x
  1177. >>> from sympy import tan
  1178. >>> TR111(1 - 1/tan(x)**2)
  1179. 1 - cot(x)**2
  1180. """
  1181. def f(rv):
  1182. if not (
  1183. isinstance(rv, Pow) and
  1184. (rv.base.is_positive or rv.exp.is_integer and rv.exp.is_negative)):
  1185. return rv
  1186. if isinstance(rv.base, tan):
  1187. return cot(rv.base.args[0])**-rv.exp
  1188. elif isinstance(rv.base, sin):
  1189. return csc(rv.base.args[0])**-rv.exp
  1190. elif isinstance(rv.base, cos):
  1191. return sec(rv.base.args[0])**-rv.exp
  1192. return rv
  1193. return bottom_up(rv, f)
  1194. def TR22(rv, max=4, pow=False):
  1195. """Convert tan(x)**2 to sec(x)**2 - 1 and cot(x)**2 to csc(x)**2 - 1.
  1196. See _TR56 docstring for advanced use of ``max`` and ``pow``.
  1197. Examples
  1198. ========
  1199. >>> from sympy.simplify.fu import TR22
  1200. >>> from sympy.abc import x
  1201. >>> from sympy import tan, cot
  1202. >>> TR22(1 + tan(x)**2)
  1203. sec(x)**2
  1204. >>> TR22(1 + cot(x)**2)
  1205. csc(x)**2
  1206. """
  1207. def f(rv):
  1208. if not (isinstance(rv, Pow) and rv.base.func in (cot, tan)):
  1209. return rv
  1210. rv = _TR56(rv, tan, sec, lambda x: x - 1, max=max, pow=pow)
  1211. rv = _TR56(rv, cot, csc, lambda x: x - 1, max=max, pow=pow)
  1212. return rv
  1213. return bottom_up(rv, f)
  1214. def TRpower(rv):
  1215. """Convert sin(x)**n and cos(x)**n with positive n to sums.
  1216. Examples
  1217. ========
  1218. >>> from sympy.simplify.fu import TRpower
  1219. >>> from sympy.abc import x
  1220. >>> from sympy import cos, sin
  1221. >>> TRpower(sin(x)**6)
  1222. -15*cos(2*x)/32 + 3*cos(4*x)/16 - cos(6*x)/32 + 5/16
  1223. >>> TRpower(sin(x)**3*cos(2*x)**4)
  1224. (3*sin(x)/4 - sin(3*x)/4)*(cos(4*x)/2 + cos(8*x)/8 + 3/8)
  1225. References
  1226. ==========
  1227. .. [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Power-reduction_formulae
  1228. """
  1229. def f(rv):
  1230. if not (isinstance(rv, Pow) and isinstance(rv.base, (sin, cos))):
  1231. return rv
  1232. b, n = rv.as_base_exp()
  1233. x = b.args[0]
  1234. if n.is_Integer and n.is_positive:
  1235. if n.is_odd and isinstance(b, cos):
  1236. rv = 2**(1-n)*Add(*[binomial(n, k)*cos((n - 2*k)*x)
  1237. for k in range((n + 1)/2)])
  1238. elif n.is_odd and isinstance(b, sin):
  1239. rv = 2**(1-n)*S.NegativeOne**((n-1)/2)*Add(*[binomial(n, k)*
  1240. S.NegativeOne**k*sin((n - 2*k)*x) for k in range((n + 1)/2)])
  1241. elif n.is_even and isinstance(b, cos):
  1242. rv = 2**(1-n)*Add(*[binomial(n, k)*cos((n - 2*k)*x)
  1243. for k in range(n/2)])
  1244. elif n.is_even and isinstance(b, sin):
  1245. rv = 2**(1-n)*S.NegativeOne**(n/2)*Add(*[binomial(n, k)*
  1246. S.NegativeOne**k*cos((n - 2*k)*x) for k in range(n/2)])
  1247. if n.is_even:
  1248. rv += 2**(-n)*binomial(n, n/2)
  1249. return rv
  1250. return bottom_up(rv, f)
  1251. def L(rv):
  1252. """Return count of trigonometric functions in expression.
  1253. Examples
  1254. ========
  1255. >>> from sympy.simplify.fu import L
  1256. >>> from sympy.abc import x
  1257. >>> from sympy import cos, sin
  1258. >>> L(cos(x)+sin(x))
  1259. 2
  1260. """
  1261. return S(rv.count(TrigonometricFunction))
  1262. # ============== end of basic Fu-like tools =====================
  1263. if SYMPY_DEBUG:
  1264. (TR0, TR1, TR2, TR3, TR4, TR5, TR6, TR7, TR8, TR9, TR10, TR11, TR12, TR13,
  1265. TR2i, TRmorrie, TR14, TR15, TR16, TR12i, TR111, TR22
  1266. )= list(map(debug,
  1267. (TR0, TR1, TR2, TR3, TR4, TR5, TR6, TR7, TR8, TR9, TR10, TR11, TR12, TR13,
  1268. TR2i, TRmorrie, TR14, TR15, TR16, TR12i, TR111, TR22)))
  1269. # tuples are chains -- (f, g) -> lambda x: g(f(x))
  1270. # lists are choices -- [f, g] -> lambda x: min(f(x), g(x), key=objective)
  1271. CTR1 = [(TR5, TR0), (TR6, TR0), identity]
  1272. CTR2 = (TR11, [(TR5, TR0), (TR6, TR0), TR0])
  1273. CTR3 = [(TRmorrie, TR8, TR0), (TRmorrie, TR8, TR10i, TR0), identity]
  1274. CTR4 = [(TR4, TR10i), identity]
  1275. RL1 = (TR4, TR3, TR4, TR12, TR4, TR13, TR4, TR0)
  1276. # XXX it's a little unclear how this one is to be implemented
  1277. # see Fu paper of reference, page 7. What is the Union symbol referring to?
  1278. # The diagram shows all these as one chain of transformations, but the
  1279. # text refers to them being applied independently. Also, a break
  1280. # if L starts to increase has not been implemented.
  1281. RL2 = [
  1282. (TR4, TR3, TR10, TR4, TR3, TR11),
  1283. (TR5, TR7, TR11, TR4),
  1284. (CTR3, CTR1, TR9, CTR2, TR4, TR9, TR9, CTR4),
  1285. identity,
  1286. ]
  1287. def fu(rv, measure=lambda x: (L(x), x.count_ops())):
  1288. """Attempt to simplify expression by using transformation rules given
  1289. in the algorithm by Fu et al.
  1290. :func:`fu` will try to minimize the objective function ``measure``.
  1291. By default this first minimizes the number of trig terms and then minimizes
  1292. the number of total operations.
  1293. Examples
  1294. ========
  1295. >>> from sympy.simplify.fu import fu
  1296. >>> from sympy import cos, sin, tan, pi, S, sqrt
  1297. >>> from sympy.abc import x, y, a, b
  1298. >>> fu(sin(50)**2 + cos(50)**2 + sin(pi/6))
  1299. 3/2
  1300. >>> fu(sqrt(6)*cos(x) + sqrt(2)*sin(x))
  1301. 2*sqrt(2)*sin(x + pi/3)
  1302. CTR1 example
  1303. >>> eq = sin(x)**4 - cos(y)**2 + sin(y)**2 + 2*cos(x)**2
  1304. >>> fu(eq)
  1305. cos(x)**4 - 2*cos(y)**2 + 2
  1306. CTR2 example
  1307. >>> fu(S.Half - cos(2*x)/2)
  1308. sin(x)**2
  1309. CTR3 example
  1310. >>> fu(sin(a)*(cos(b) - sin(b)) + cos(a)*(sin(b) + cos(b)))
  1311. sqrt(2)*sin(a + b + pi/4)
  1312. CTR4 example
  1313. >>> fu(sqrt(3)*cos(x)/2 + sin(x)/2)
  1314. sin(x + pi/3)
  1315. Example 1
  1316. >>> fu(1-sin(2*x)**2/4-sin(y)**2-cos(x)**4)
  1317. -cos(x)**2 + cos(y)**2
  1318. Example 2
  1319. >>> fu(cos(4*pi/9))
  1320. sin(pi/18)
  1321. >>> fu(cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9))
  1322. 1/16
  1323. Example 3
  1324. >>> fu(tan(7*pi/18)+tan(5*pi/18)-sqrt(3)*tan(5*pi/18)*tan(7*pi/18))
  1325. -sqrt(3)
  1326. Objective function example
  1327. >>> fu(sin(x)/cos(x)) # default objective function
  1328. tan(x)
  1329. >>> fu(sin(x)/cos(x), measure=lambda x: -x.count_ops()) # maximize op count
  1330. sin(x)/cos(x)
  1331. References
  1332. ==========
  1333. .. [1] https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.657.2478&rep=rep1&type=pdf
  1334. """
  1335. fRL1 = greedy(RL1, measure)
  1336. fRL2 = greedy(RL2, measure)
  1337. was = rv
  1338. rv = sympify(rv)
  1339. if not isinstance(rv, Expr):
  1340. return rv.func(*[fu(a, measure=measure) for a in rv.args])
  1341. rv = TR1(rv)
  1342. if rv.has(tan, cot):
  1343. rv1 = fRL1(rv)
  1344. if (measure(rv1) < measure(rv)):
  1345. rv = rv1
  1346. if rv.has(tan, cot):
  1347. rv = TR2(rv)
  1348. if rv.has(sin, cos):
  1349. rv1 = fRL2(rv)
  1350. rv2 = TR8(TRmorrie(rv1))
  1351. rv = min([was, rv, rv1, rv2], key=measure)
  1352. return min(TR2i(rv), rv, key=measure)
  1353. def process_common_addends(rv, do, key2=None, key1=True):
  1354. """Apply ``do`` to addends of ``rv`` that (if ``key1=True``) share at least
  1355. a common absolute value of their coefficient and the value of ``key2`` when
  1356. applied to the argument. If ``key1`` is False ``key2`` must be supplied and
  1357. will be the only key applied.
  1358. """
  1359. # collect by absolute value of coefficient and key2
  1360. absc = defaultdict(list)
  1361. if key1:
  1362. for a in rv.args:
  1363. c, a = a.as_coeff_Mul()
  1364. if c < 0:
  1365. c = -c
  1366. a = -a # put the sign on `a`
  1367. absc[(c, key2(a) if key2 else 1)].append(a)
  1368. elif key2:
  1369. for a in rv.args:
  1370. absc[(S.One, key2(a))].append(a)
  1371. else:
  1372. raise ValueError('must have at least one key')
  1373. args = []
  1374. hit = False
  1375. for k in absc:
  1376. v = absc[k]
  1377. c, _ = k
  1378. if len(v) > 1:
  1379. e = Add(*v, evaluate=False)
  1380. new = do(e)
  1381. if new != e:
  1382. e = new
  1383. hit = True
  1384. args.append(c*e)
  1385. else:
  1386. args.append(c*v[0])
  1387. if hit:
  1388. rv = Add(*args)
  1389. return rv
  1390. fufuncs = '''
  1391. TR0 TR1 TR2 TR3 TR4 TR5 TR6 TR7 TR8 TR9 TR10 TR10i TR11
  1392. TR12 TR13 L TR2i TRmorrie TR12i
  1393. TR14 TR15 TR16 TR111 TR22'''.split()
  1394. FU = dict(list(zip(fufuncs, list(map(locals().get, fufuncs)))))
  1395. def _roots():
  1396. global _ROOT2, _ROOT3, _invROOT3
  1397. _ROOT2, _ROOT3 = sqrt(2), sqrt(3)
  1398. _invROOT3 = 1/_ROOT3
  1399. _ROOT2 = None
  1400. def trig_split(a, b, two=False):
  1401. """Return the gcd, s1, s2, a1, a2, bool where
  1402. If two is False (default) then::
  1403. a + b = gcd*(s1*f(a1) + s2*f(a2)) where f = cos if bool else sin
  1404. else:
  1405. if bool, a + b was +/- cos(a1)*cos(a2) +/- sin(a1)*sin(a2) and equals
  1406. n1*gcd*cos(a - b) if n1 == n2 else
  1407. n1*gcd*cos(a + b)
  1408. else a + b was +/- cos(a1)*sin(a2) +/- sin(a1)*cos(a2) and equals
  1409. n1*gcd*sin(a + b) if n1 = n2 else
  1410. n1*gcd*sin(b - a)
  1411. Examples
  1412. ========
  1413. >>> from sympy.simplify.fu import trig_split
  1414. >>> from sympy.abc import x, y, z
  1415. >>> from sympy import cos, sin, sqrt
  1416. >>> trig_split(cos(x), cos(y))
  1417. (1, 1, 1, x, y, True)
  1418. >>> trig_split(2*cos(x), -2*cos(y))
  1419. (2, 1, -1, x, y, True)
  1420. >>> trig_split(cos(x)*sin(y), cos(y)*sin(y))
  1421. (sin(y), 1, 1, x, y, True)
  1422. >>> trig_split(cos(x), -sqrt(3)*sin(x), two=True)
  1423. (2, 1, -1, x, pi/6, False)
  1424. >>> trig_split(cos(x), sin(x), two=True)
  1425. (sqrt(2), 1, 1, x, pi/4, False)
  1426. >>> trig_split(cos(x), -sin(x), two=True)
  1427. (sqrt(2), 1, -1, x, pi/4, False)
  1428. >>> trig_split(sqrt(2)*cos(x), -sqrt(6)*sin(x), two=True)
  1429. (2*sqrt(2), 1, -1, x, pi/6, False)
  1430. >>> trig_split(-sqrt(6)*cos(x), -sqrt(2)*sin(x), two=True)
  1431. (-2*sqrt(2), 1, 1, x, pi/3, False)
  1432. >>> trig_split(cos(x)/sqrt(6), sin(x)/sqrt(2), two=True)
  1433. (sqrt(6)/3, 1, 1, x, pi/6, False)
  1434. >>> trig_split(-sqrt(6)*cos(x)*sin(y), -sqrt(2)*sin(x)*sin(y), two=True)
  1435. (-2*sqrt(2)*sin(y), 1, 1, x, pi/3, False)
  1436. >>> trig_split(cos(x), sin(x))
  1437. >>> trig_split(cos(x), sin(z))
  1438. >>> trig_split(2*cos(x), -sin(x))
  1439. >>> trig_split(cos(x), -sqrt(3)*sin(x))
  1440. >>> trig_split(cos(x)*cos(y), sin(x)*sin(z))
  1441. >>> trig_split(cos(x)*cos(y), sin(x)*sin(y))
  1442. >>> trig_split(-sqrt(6)*cos(x), sqrt(2)*sin(x)*sin(y), two=True)
  1443. """
  1444. global _ROOT2, _ROOT3, _invROOT3
  1445. if _ROOT2 is None:
  1446. _roots()
  1447. a, b = [Factors(i) for i in (a, b)]
  1448. ua, ub = a.normal(b)
  1449. gcd = a.gcd(b).as_expr()
  1450. n1 = n2 = 1
  1451. if S.NegativeOne in ua.factors:
  1452. ua = ua.quo(S.NegativeOne)
  1453. n1 = -n1
  1454. elif S.NegativeOne in ub.factors:
  1455. ub = ub.quo(S.NegativeOne)
  1456. n2 = -n2
  1457. a, b = [i.as_expr() for i in (ua, ub)]
  1458. def pow_cos_sin(a, two):
  1459. """Return ``a`` as a tuple (r, c, s) such that
  1460. ``a = (r or 1)*(c or 1)*(s or 1)``.
  1461. Three arguments are returned (radical, c-factor, s-factor) as
  1462. long as the conditions set by ``two`` are met; otherwise None is
  1463. returned. If ``two`` is True there will be one or two non-None
  1464. values in the tuple: c and s or c and r or s and r or s or c with c
  1465. being a cosine function (if possible) else a sine, and s being a sine
  1466. function (if possible) else oosine. If ``two`` is False then there
  1467. will only be a c or s term in the tuple.
  1468. ``two`` also require that either two cos and/or sin be present (with
  1469. the condition that if the functions are the same the arguments are
  1470. different or vice versa) or that a single cosine or a single sine
  1471. be present with an optional radical.
  1472. If the above conditions dictated by ``two`` are not met then None
  1473. is returned.
  1474. """
  1475. c = s = None
  1476. co = S.One
  1477. if a.is_Mul:
  1478. co, a = a.as_coeff_Mul()
  1479. if len(a.args) > 2 or not two:
  1480. return None
  1481. if a.is_Mul:
  1482. args = list(a.args)
  1483. else:
  1484. args = [a]
  1485. a = args.pop(0)
  1486. if isinstance(a, cos):
  1487. c = a
  1488. elif isinstance(a, sin):
  1489. s = a
  1490. elif a.is_Pow and a.exp is S.Half: # autoeval doesn't allow -1/2
  1491. co *= a
  1492. else:
  1493. return None
  1494. if args:
  1495. b = args[0]
  1496. if isinstance(b, cos):
  1497. if c:
  1498. s = b
  1499. else:
  1500. c = b
  1501. elif isinstance(b, sin):
  1502. if s:
  1503. c = b
  1504. else:
  1505. s = b
  1506. elif b.is_Pow and b.exp is S.Half:
  1507. co *= b
  1508. else:
  1509. return None
  1510. return co if co is not S.One else None, c, s
  1511. elif isinstance(a, cos):
  1512. c = a
  1513. elif isinstance(a, sin):
  1514. s = a
  1515. if c is None and s is None:
  1516. return
  1517. co = co if co is not S.One else None
  1518. return co, c, s
  1519. # get the parts
  1520. m = pow_cos_sin(a, two)
  1521. if m is None:
  1522. return
  1523. coa, ca, sa = m
  1524. m = pow_cos_sin(b, two)
  1525. if m is None:
  1526. return
  1527. cob, cb, sb = m
  1528. # check them
  1529. if (not ca) and cb or ca and isinstance(ca, sin):
  1530. coa, ca, sa, cob, cb, sb = cob, cb, sb, coa, ca, sa
  1531. n1, n2 = n2, n1
  1532. if not two: # need cos(x) and cos(y) or sin(x) and sin(y)
  1533. c = ca or sa
  1534. s = cb or sb
  1535. if not isinstance(c, s.func):
  1536. return None
  1537. return gcd, n1, n2, c.args[0], s.args[0], isinstance(c, cos)
  1538. else:
  1539. if not coa and not cob:
  1540. if (ca and cb and sa and sb):
  1541. if isinstance(ca, sa.func) is not isinstance(cb, sb.func):
  1542. return
  1543. args = {j.args for j in (ca, sa)}
  1544. if not all(i.args in args for i in (cb, sb)):
  1545. return
  1546. return gcd, n1, n2, ca.args[0], sa.args[0], isinstance(ca, sa.func)
  1547. if ca and sa or cb and sb or \
  1548. two and (ca is None and sa is None or cb is None and sb is None):
  1549. return
  1550. c = ca or sa
  1551. s = cb or sb
  1552. if c.args != s.args:
  1553. return
  1554. if not coa:
  1555. coa = S.One
  1556. if not cob:
  1557. cob = S.One
  1558. if coa is cob:
  1559. gcd *= _ROOT2
  1560. return gcd, n1, n2, c.args[0], pi/4, False
  1561. elif coa/cob == _ROOT3:
  1562. gcd *= 2*cob
  1563. return gcd, n1, n2, c.args[0], pi/3, False
  1564. elif coa/cob == _invROOT3:
  1565. gcd *= 2*coa
  1566. return gcd, n1, n2, c.args[0], pi/6, False
  1567. def as_f_sign_1(e):
  1568. """If ``e`` is a sum that can be written as ``g*(a + s)`` where
  1569. ``s`` is ``+/-1``, return ``g``, ``a``, and ``s`` where ``a`` does
  1570. not have a leading negative coefficient.
  1571. Examples
  1572. ========
  1573. >>> from sympy.simplify.fu import as_f_sign_1
  1574. >>> from sympy.abc import x
  1575. >>> as_f_sign_1(x + 1)
  1576. (1, x, 1)
  1577. >>> as_f_sign_1(x - 1)
  1578. (1, x, -1)
  1579. >>> as_f_sign_1(-x + 1)
  1580. (-1, x, -1)
  1581. >>> as_f_sign_1(-x - 1)
  1582. (-1, x, 1)
  1583. >>> as_f_sign_1(2*x + 2)
  1584. (2, x, 1)
  1585. """
  1586. if not e.is_Add or len(e.args) != 2:
  1587. return
  1588. # exact match
  1589. a, b = e.args
  1590. if a in (S.NegativeOne, S.One):
  1591. g = S.One
  1592. if b.is_Mul and b.args[0].is_Number and b.args[0] < 0:
  1593. a, b = -a, -b
  1594. g = -g
  1595. return g, b, a
  1596. # gcd match
  1597. a, b = [Factors(i) for i in e.args]
  1598. ua, ub = a.normal(b)
  1599. gcd = a.gcd(b).as_expr()
  1600. if S.NegativeOne in ua.factors:
  1601. ua = ua.quo(S.NegativeOne)
  1602. n1 = -1
  1603. n2 = 1
  1604. elif S.NegativeOne in ub.factors:
  1605. ub = ub.quo(S.NegativeOne)
  1606. n1 = 1
  1607. n2 = -1
  1608. else:
  1609. n1 = n2 = 1
  1610. a, b = [i.as_expr() for i in (ua, ub)]
  1611. if a is S.One:
  1612. a, b = b, a
  1613. n1, n2 = n2, n1
  1614. if n1 == -1:
  1615. gcd = -gcd
  1616. n2 = -n2
  1617. if b is S.One:
  1618. return gcd, a, n2
  1619. def _osborne(e, d):
  1620. """Replace all hyperbolic functions with trig functions using
  1621. the Osborne rule.
  1622. Notes
  1623. =====
  1624. ``d`` is a dummy variable to prevent automatic evaluation
  1625. of trigonometric/hyperbolic functions.
  1626. References
  1627. ==========
  1628. .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function
  1629. """
  1630. def f(rv):
  1631. if not isinstance(rv, HyperbolicFunction):
  1632. return rv
  1633. a = rv.args[0]
  1634. a = a*d if not a.is_Add else Add._from_args([i*d for i in a.args])
  1635. if isinstance(rv, sinh):
  1636. return I*sin(a)
  1637. elif isinstance(rv, cosh):
  1638. return cos(a)
  1639. elif isinstance(rv, tanh):
  1640. return I*tan(a)
  1641. elif isinstance(rv, coth):
  1642. return cot(a)/I
  1643. elif isinstance(rv, sech):
  1644. return sec(a)
  1645. elif isinstance(rv, csch):
  1646. return csc(a)/I
  1647. else:
  1648. raise NotImplementedError('unhandled %s' % rv.func)
  1649. return bottom_up(e, f)
  1650. def _osbornei(e, d):
  1651. """Replace all trig functions with hyperbolic functions using
  1652. the Osborne rule.
  1653. Notes
  1654. =====
  1655. ``d`` is a dummy variable to prevent automatic evaluation
  1656. of trigonometric/hyperbolic functions.
  1657. References
  1658. ==========
  1659. .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function
  1660. """
  1661. def f(rv):
  1662. if not isinstance(rv, TrigonometricFunction):
  1663. return rv
  1664. const, x = rv.args[0].as_independent(d, as_Add=True)
  1665. a = x.xreplace({d: S.One}) + const*I
  1666. if isinstance(rv, sin):
  1667. return sinh(a)/I
  1668. elif isinstance(rv, cos):
  1669. return cosh(a)
  1670. elif isinstance(rv, tan):
  1671. return tanh(a)/I
  1672. elif isinstance(rv, cot):
  1673. return coth(a)*I
  1674. elif isinstance(rv, sec):
  1675. return sech(a)
  1676. elif isinstance(rv, csc):
  1677. return csch(a)*I
  1678. else:
  1679. raise NotImplementedError('unhandled %s' % rv.func)
  1680. return bottom_up(e, f)
  1681. def hyper_as_trig(rv):
  1682. """Return an expression containing hyperbolic functions in terms
  1683. of trigonometric functions. Any trigonometric functions initially
  1684. present are replaced with Dummy symbols and the function to undo
  1685. the masking and the conversion back to hyperbolics is also returned. It
  1686. should always be true that::
  1687. t, f = hyper_as_trig(expr)
  1688. expr == f(t)
  1689. Examples
  1690. ========
  1691. >>> from sympy.simplify.fu import hyper_as_trig, fu
  1692. >>> from sympy.abc import x
  1693. >>> from sympy import cosh, sinh
  1694. >>> eq = sinh(x)**2 + cosh(x)**2
  1695. >>> t, f = hyper_as_trig(eq)
  1696. >>> f(fu(t))
  1697. cosh(2*x)
  1698. References
  1699. ==========
  1700. .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function
  1701. """
  1702. from sympy.simplify.simplify import signsimp
  1703. from sympy.simplify.radsimp import collect
  1704. # mask off trig functions
  1705. trigs = rv.atoms(TrigonometricFunction)
  1706. reps = [(t, Dummy()) for t in trigs]
  1707. masked = rv.xreplace(dict(reps))
  1708. # get inversion substitutions in place
  1709. reps = [(v, k) for k, v in reps]
  1710. d = Dummy()
  1711. return _osborne(masked, d), lambda x: collect(signsimp(
  1712. _osbornei(x, d).xreplace(dict(reps))), S.ImaginaryUnit)
  1713. def sincos_to_sum(expr):
  1714. """Convert products and powers of sin and cos to sums.
  1715. Explanation
  1716. ===========
  1717. Applied power reduction TRpower first, then expands products, and
  1718. converts products to sums with TR8.
  1719. Examples
  1720. ========
  1721. >>> from sympy.simplify.fu import sincos_to_sum
  1722. >>> from sympy.abc import x
  1723. >>> from sympy import cos, sin
  1724. >>> sincos_to_sum(16*sin(x)**3*cos(2*x)**2)
  1725. 7*sin(x) - 5*sin(3*x) + 3*sin(5*x) - sin(7*x)
  1726. """
  1727. if not expr.has(cos, sin):
  1728. return expr
  1729. else:
  1730. return TR8(expand_mul(TRpower(expr)))