solveset.py 138 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878
  1. """
  2. This module contains functions to:
  3. - solve a single equation for a single variable, in any domain either real or complex.
  4. - solve a single transcendental equation for a single variable in any domain either real or complex.
  5. (currently supports solving in real domain only)
  6. - solve a system of linear equations with N variables and M equations.
  7. - solve a system of Non Linear Equations with N variables and M equations
  8. """
  9. from sympy.core.sympify import sympify
  10. from sympy.core import (S, Pow, Dummy, pi, Expr, Wild, Mul, Equality,
  11. Add, Basic)
  12. from sympy.core.containers import Tuple
  13. from sympy.core.function import (Lambda, expand_complex, AppliedUndef,
  14. expand_log, _mexpand, expand_trig, nfloat)
  15. from sympy.core.mod import Mod
  16. from sympy.core.numbers import igcd, I, Number, Rational, oo, ilcm
  17. from sympy.core.power import integer_log
  18. from sympy.core.relational import Eq, Ne, Relational
  19. from sympy.core.sorting import default_sort_key, ordered
  20. from sympy.core.symbol import Symbol, _uniquely_named_symbol
  21. from sympy.core.sympify import _sympify
  22. from sympy.polys.matrices.linsolve import _linear_eq_to_dict
  23. from sympy.polys.polyroots import UnsolvableFactorError
  24. from sympy.simplify.simplify import simplify, fraction, trigsimp, nsimplify
  25. from sympy.simplify import powdenest, logcombine
  26. from sympy.functions import (log, tan, cot, sin, cos, sec, csc, exp,
  27. acos, asin, acsc, asec,
  28. piecewise_fold, Piecewise)
  29. from sympy.functions.elementary.complexes import Abs, arg, re, im
  30. from sympy.functions.elementary.hyperbolic import HyperbolicFunction
  31. from sympy.functions.elementary.miscellaneous import real_root
  32. from sympy.functions.elementary.trigonometric import TrigonometricFunction
  33. from sympy.logic.boolalg import And, BooleanTrue
  34. from sympy.sets import (FiniteSet, imageset, Interval, Intersection,
  35. Union, ConditionSet, ImageSet, Complement, Contains)
  36. from sympy.sets.sets import Set, ProductSet
  37. from sympy.matrices import zeros, Matrix, MatrixBase
  38. from sympy.ntheory import totient
  39. from sympy.ntheory.factor_ import divisors
  40. from sympy.ntheory.residue_ntheory import discrete_log, nthroot_mod
  41. from sympy.polys import (roots, Poly, degree, together, PolynomialError,
  42. RootOf, factor, lcm, gcd)
  43. from sympy.polys.polyerrors import CoercionFailed
  44. from sympy.polys.polytools import invert, groebner, poly
  45. from sympy.polys.solvers import (sympy_eqs_to_ring, solve_lin_sys,
  46. PolyNonlinearError)
  47. from sympy.polys.matrices.linsolve import _linsolve
  48. from sympy.solvers.solvers import (checksol, denoms, unrad,
  49. _simple_dens, recast_to_symbols)
  50. from sympy.solvers.polysys import solve_poly_system
  51. from sympy.utilities import filldedent
  52. from sympy.utilities.iterables import (numbered_symbols, has_dups,
  53. is_sequence, iterable)
  54. from sympy.calculus.util import periodicity, continuous_domain, function_range
  55. from types import GeneratorType
  56. class NonlinearError(ValueError):
  57. """Raised when unexpectedly encountering nonlinear equations"""
  58. pass
  59. _rc = Dummy("R", real=True), Dummy("C", complex=True)
  60. def _masked(f, *atoms):
  61. """Return ``f``, with all objects given by ``atoms`` replaced with
  62. Dummy symbols, ``d``, and the list of replacements, ``(d, e)``,
  63. where ``e`` is an object of type given by ``atoms`` in which
  64. any other instances of atoms have been recursively replaced with
  65. Dummy symbols, too. The tuples are ordered so that if they are
  66. applied in sequence, the origin ``f`` will be restored.
  67. Examples
  68. ========
  69. >>> from sympy import cos
  70. >>> from sympy.abc import x
  71. >>> from sympy.solvers.solveset import _masked
  72. >>> f = cos(cos(x) + 1)
  73. >>> f, reps = _masked(cos(1 + cos(x)), cos)
  74. >>> f
  75. _a1
  76. >>> reps
  77. [(_a1, cos(_a0 + 1)), (_a0, cos(x))]
  78. >>> for d, e in reps:
  79. ... f = f.xreplace({d: e})
  80. >>> f
  81. cos(cos(x) + 1)
  82. """
  83. sym = numbered_symbols('a', cls=Dummy, real=True)
  84. mask = []
  85. for a in ordered(f.atoms(*atoms)):
  86. for i in mask:
  87. a = a.replace(*i)
  88. mask.append((a, next(sym)))
  89. for i, (o, n) in enumerate(mask):
  90. f = f.replace(o, n)
  91. mask[i] = (n, o)
  92. mask = list(reversed(mask))
  93. return f, mask
  94. def _invert(f_x, y, x, domain=S.Complexes):
  95. r"""
  96. Reduce the complex valued equation $f(x) = y$ to a set of equations
  97. $$\left\{g(x) = h_1(y),\ g(x) = h_2(y),\ \dots,\ g(x) = h_n(y) \right\}$$
  98. where $g(x)$ is a simpler function than $f(x)$. The return value is a tuple
  99. $(g(x), \mathrm{set}_h)$, where $g(x)$ is a function of $x$ and $\mathrm{set}_h$ is
  100. the set of function $\left\{h_1(y), h_2(y), \dots, h_n(y)\right\}$.
  101. Here, $y$ is not necessarily a symbol.
  102. $\mathrm{set}_h$ contains the functions, along with the information
  103. about the domain in which they are valid, through set
  104. operations. For instance, if :math:`y = |x| - n` is inverted
  105. in the real domain, then $\mathrm{set}_h$ is not simply
  106. $\{-n, n\}$ as the nature of `n` is unknown; rather, it is:
  107. $$ \left(\left[0, \infty\right) \cap \left\{n\right\}\right) \cup
  108. \left(\left(-\infty, 0\right] \cap \left\{- n\right\}\right)$$
  109. By default, the complex domain is used which means that inverting even
  110. seemingly simple functions like $\exp(x)$ will give very different
  111. results from those obtained in the real domain.
  112. (In the case of $\exp(x)$, the inversion via $\log$ is multi-valued
  113. in the complex domain, having infinitely many branches.)
  114. If you are working with real values only (or you are not sure which
  115. function to use) you should probably set the domain to
  116. ``S.Reals`` (or use ``invert_real`` which does that automatically).
  117. Examples
  118. ========
  119. >>> from sympy.solvers.solveset import invert_complex, invert_real
  120. >>> from sympy.abc import x, y
  121. >>> from sympy import exp
  122. When does exp(x) == y?
  123. >>> invert_complex(exp(x), y, x)
  124. (x, ImageSet(Lambda(_n, I*(2*_n*pi + arg(y)) + log(Abs(y))), Integers))
  125. >>> invert_real(exp(x), y, x)
  126. (x, Intersection({log(y)}, Reals))
  127. When does exp(x) == 1?
  128. >>> invert_complex(exp(x), 1, x)
  129. (x, ImageSet(Lambda(_n, 2*_n*I*pi), Integers))
  130. >>> invert_real(exp(x), 1, x)
  131. (x, {0})
  132. See Also
  133. ========
  134. invert_real, invert_complex
  135. """
  136. x = sympify(x)
  137. if not x.is_Symbol:
  138. raise ValueError("x must be a symbol")
  139. f_x = sympify(f_x)
  140. if x not in f_x.free_symbols:
  141. raise ValueError("Inverse of constant function doesn't exist")
  142. y = sympify(y)
  143. if x in y.free_symbols:
  144. raise ValueError("y should be independent of x ")
  145. if domain.is_subset(S.Reals):
  146. x1, s = _invert_real(f_x, FiniteSet(y), x)
  147. else:
  148. x1, s = _invert_complex(f_x, FiniteSet(y), x)
  149. if not isinstance(s, FiniteSet) or x1 != x:
  150. return x1, s
  151. # Avoid adding gratuitous intersections with S.Complexes. Actual
  152. # conditions should be handled by the respective inverters.
  153. if domain is S.Complexes:
  154. return x1, s
  155. else:
  156. return x1, s.intersection(domain)
  157. invert_complex = _invert
  158. def invert_real(f_x, y, x):
  159. """
  160. Inverts a real-valued function. Same as :func:`invert_complex`, but sets
  161. the domain to ``S.Reals`` before inverting.
  162. """
  163. return _invert(f_x, y, x, S.Reals)
  164. def _invert_real(f, g_ys, symbol):
  165. """Helper function for _invert."""
  166. if f == symbol or g_ys is S.EmptySet:
  167. return (f, g_ys)
  168. n = Dummy('n', real=True)
  169. if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1):
  170. return _invert_real(f.exp,
  171. imageset(Lambda(n, log(n)), g_ys),
  172. symbol)
  173. if hasattr(f, 'inverse') and f.inverse() is not None and not isinstance(f, (
  174. TrigonometricFunction,
  175. HyperbolicFunction,
  176. )):
  177. if len(f.args) > 1:
  178. raise ValueError("Only functions with one argument are supported.")
  179. return _invert_real(f.args[0],
  180. imageset(Lambda(n, f.inverse()(n)), g_ys),
  181. symbol)
  182. if isinstance(f, Abs):
  183. return _invert_abs(f.args[0], g_ys, symbol)
  184. if f.is_Add:
  185. # f = g + h
  186. g, h = f.as_independent(symbol)
  187. if g is not S.Zero:
  188. return _invert_real(h, imageset(Lambda(n, n - g), g_ys), symbol)
  189. if f.is_Mul:
  190. # f = g*h
  191. g, h = f.as_independent(symbol)
  192. if g is not S.One:
  193. return _invert_real(h, imageset(Lambda(n, n/g), g_ys), symbol)
  194. if f.is_Pow:
  195. base, expo = f.args
  196. base_has_sym = base.has(symbol)
  197. expo_has_sym = expo.has(symbol)
  198. if not expo_has_sym:
  199. if expo.is_rational:
  200. num, den = expo.as_numer_denom()
  201. if den % 2 == 0 and num % 2 == 1 and den.is_zero is False:
  202. # Here we have f(x)**(num/den) = y
  203. # where den is nonzero and even and y is an element
  204. # of the set g_ys.
  205. # den is even, so we are only interested in the cases
  206. # where both f(x) and y are positive.
  207. # Restricting y to be positive (using the set g_ys_pos)
  208. # means that y**(den/num) is always positive.
  209. # Therefore it isn't necessary to also constrain f(x)
  210. # to be positive because we are only going to
  211. # find solutions of f(x) = y**(d/n)
  212. # where the rhs is already required to be positive.
  213. root = Lambda(n, real_root(n, expo))
  214. g_ys_pos = g_ys & Interval(0, oo)
  215. res = imageset(root, g_ys_pos)
  216. _inv, _set = _invert_real(base, res, symbol)
  217. return (_inv, _set)
  218. if den % 2 == 1:
  219. root = Lambda(n, real_root(n, expo))
  220. res = imageset(root, g_ys)
  221. if num % 2 == 0:
  222. neg_res = imageset(Lambda(n, -n), res)
  223. return _invert_real(base, res + neg_res, symbol)
  224. if num % 2 == 1:
  225. return _invert_real(base, res, symbol)
  226. elif expo.is_irrational:
  227. root = Lambda(n, real_root(n, expo))
  228. g_ys_pos = g_ys & Interval(0, oo)
  229. res = imageset(root, g_ys_pos)
  230. return _invert_real(base, res, symbol)
  231. else:
  232. # indeterminate exponent, e.g. Float or parity of
  233. # num, den of rational could not be determined
  234. pass # use default return
  235. if not base_has_sym:
  236. rhs = g_ys.args[0]
  237. if base.is_positive:
  238. return _invert_real(expo,
  239. imageset(Lambda(n, log(n, base, evaluate=False)), g_ys), symbol)
  240. elif base.is_negative:
  241. s, b = integer_log(rhs, base)
  242. if b:
  243. return _invert_real(expo, FiniteSet(s), symbol)
  244. else:
  245. return (expo, S.EmptySet)
  246. elif base.is_zero:
  247. one = Eq(rhs, 1)
  248. if one == S.true:
  249. # special case: 0**x - 1
  250. return _invert_real(expo, FiniteSet(0), symbol)
  251. elif one == S.false:
  252. return (expo, S.EmptySet)
  253. if isinstance(f, TrigonometricFunction):
  254. if isinstance(g_ys, FiniteSet):
  255. def inv(trig):
  256. if isinstance(trig, (sin, csc)):
  257. F = asin if isinstance(trig, sin) else acsc
  258. return (lambda a: n*pi + S.NegativeOne**n*F(a),)
  259. if isinstance(trig, (cos, sec)):
  260. F = acos if isinstance(trig, cos) else asec
  261. return (
  262. lambda a: 2*n*pi + F(a),
  263. lambda a: 2*n*pi - F(a),)
  264. if isinstance(trig, (tan, cot)):
  265. return (lambda a: n*pi + trig.inverse()(a),)
  266. n = Dummy('n', integer=True)
  267. invs = S.EmptySet
  268. for L in inv(f):
  269. invs += Union(*[imageset(Lambda(n, L(g)), S.Integers) for g in g_ys])
  270. return _invert_real(f.args[0], invs, symbol)
  271. return (f, g_ys)
  272. def _invert_complex(f, g_ys, symbol):
  273. """Helper function for _invert."""
  274. if f == symbol or g_ys is S.EmptySet:
  275. return (f, g_ys)
  276. n = Dummy('n')
  277. if f.is_Add:
  278. # f = g + h
  279. g, h = f.as_independent(symbol)
  280. if g is not S.Zero:
  281. return _invert_complex(h, imageset(Lambda(n, n - g), g_ys), symbol)
  282. if f.is_Mul:
  283. # f = g*h
  284. g, h = f.as_independent(symbol)
  285. if g is not S.One:
  286. if g in {S.NegativeInfinity, S.ComplexInfinity, S.Infinity}:
  287. return (h, S.EmptySet)
  288. return _invert_complex(h, imageset(Lambda(n, n/g), g_ys), symbol)
  289. if f.is_Pow:
  290. base, expo = f.args
  291. # special case: g**r = 0
  292. # Could be improved like `_invert_real` to handle more general cases.
  293. if expo.is_Rational and g_ys == FiniteSet(0):
  294. if expo.is_positive:
  295. return _invert_complex(base, g_ys, symbol)
  296. if hasattr(f, 'inverse') and f.inverse() is not None and \
  297. not isinstance(f, TrigonometricFunction) and \
  298. not isinstance(f, HyperbolicFunction) and \
  299. not isinstance(f, exp):
  300. if len(f.args) > 1:
  301. raise ValueError("Only functions with one argument are supported.")
  302. return _invert_complex(f.args[0],
  303. imageset(Lambda(n, f.inverse()(n)), g_ys), symbol)
  304. if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1):
  305. if isinstance(g_ys, ImageSet):
  306. # can solve upto `(d*exp(exp(...(exp(a*x + b))...) + c)` format.
  307. # Further can be improved to `(d*exp(exp(...(exp(a*x**n + b*x**(n-1) + ... + f))...) + c)`.
  308. g_ys_expr = g_ys.lamda.expr
  309. g_ys_vars = g_ys.lamda.variables
  310. k = Dummy('k{}'.format(len(g_ys_vars)))
  311. g_ys_vars_1 = (k,) + g_ys_vars
  312. exp_invs = Union(*[imageset(Lambda((g_ys_vars_1,), (I*(2*k*pi + arg(g_ys_expr))
  313. + log(Abs(g_ys_expr)))), S.Integers**(len(g_ys_vars_1)))])
  314. return _invert_complex(f.exp, exp_invs, symbol)
  315. elif isinstance(g_ys, FiniteSet):
  316. exp_invs = Union(*[imageset(Lambda(n, I*(2*n*pi + arg(g_y)) +
  317. log(Abs(g_y))), S.Integers)
  318. for g_y in g_ys if g_y != 0])
  319. return _invert_complex(f.exp, exp_invs, symbol)
  320. return (f, g_ys)
  321. def _invert_abs(f, g_ys, symbol):
  322. """Helper function for inverting absolute value functions.
  323. Returns the complete result of inverting an absolute value
  324. function along with the conditions which must also be satisfied.
  325. If it is certain that all these conditions are met, a :class:`~.FiniteSet`
  326. of all possible solutions is returned. If any condition cannot be
  327. satisfied, an :class:`~.EmptySet` is returned. Otherwise, a
  328. :class:`~.ConditionSet` of the solutions, with all the required conditions
  329. specified, is returned.
  330. """
  331. if not g_ys.is_FiniteSet:
  332. # this could be used for FiniteSet, but the
  333. # results are more compact if they aren't, e.g.
  334. # ConditionSet(x, Contains(n, Interval(0, oo)), {-n, n}) vs
  335. # Union(Intersection(Interval(0, oo), {n}), Intersection(Interval(-oo, 0), {-n}))
  336. # for the solution of abs(x) - n
  337. pos = Intersection(g_ys, Interval(0, S.Infinity))
  338. parg = _invert_real(f, pos, symbol)
  339. narg = _invert_real(-f, pos, symbol)
  340. if parg[0] != narg[0]:
  341. raise NotImplementedError
  342. return parg[0], Union(narg[1], parg[1])
  343. # check conditions: all these must be true. If any are unknown
  344. # then return them as conditions which must be satisfied
  345. unknown = []
  346. for a in g_ys.args:
  347. ok = a.is_nonnegative if a.is_Number else a.is_positive
  348. if ok is None:
  349. unknown.append(a)
  350. elif not ok:
  351. return symbol, S.EmptySet
  352. if unknown:
  353. conditions = And(*[Contains(i, Interval(0, oo))
  354. for i in unknown])
  355. else:
  356. conditions = True
  357. n = Dummy('n', real=True)
  358. # this is slightly different than above: instead of solving
  359. # +/-f on positive values, here we solve for f on +/- g_ys
  360. g_x, values = _invert_real(f, Union(
  361. imageset(Lambda(n, n), g_ys),
  362. imageset(Lambda(n, -n), g_ys)), symbol)
  363. return g_x, ConditionSet(g_x, conditions, values)
  364. def domain_check(f, symbol, p):
  365. """Returns False if point p is infinite or any subexpression of f
  366. is infinite or becomes so after replacing symbol with p. If none of
  367. these conditions is met then True will be returned.
  368. Examples
  369. ========
  370. >>> from sympy import Mul, oo
  371. >>> from sympy.abc import x
  372. >>> from sympy.solvers.solveset import domain_check
  373. >>> g = 1/(1 + (1/(x + 1))**2)
  374. >>> domain_check(g, x, -1)
  375. False
  376. >>> domain_check(x**2, x, 0)
  377. True
  378. >>> domain_check(1/x, x, oo)
  379. False
  380. * The function relies on the assumption that the original form
  381. of the equation has not been changed by automatic simplification.
  382. >>> domain_check(x/x, x, 0) # x/x is automatically simplified to 1
  383. True
  384. * To deal with automatic evaluations use evaluate=False:
  385. >>> domain_check(Mul(x, 1/x, evaluate=False), x, 0)
  386. False
  387. """
  388. f, p = sympify(f), sympify(p)
  389. if p.is_infinite:
  390. return False
  391. return _domain_check(f, symbol, p)
  392. def _domain_check(f, symbol, p):
  393. # helper for domain check
  394. if f.is_Atom and f.is_finite:
  395. return True
  396. elif f.subs(symbol, p).is_infinite:
  397. return False
  398. elif isinstance(f, Piecewise):
  399. # Check the cases of the Piecewise in turn. There might be invalid
  400. # expressions in later cases that don't apply e.g.
  401. # solveset(Piecewise((0, Eq(x, 0)), (1/x, True)), x)
  402. for expr, cond in f.args:
  403. condsubs = cond.subs(symbol, p)
  404. if condsubs is S.false:
  405. continue
  406. elif condsubs is S.true:
  407. return _domain_check(expr, symbol, p)
  408. else:
  409. # We don't know which case of the Piecewise holds. On this
  410. # basis we cannot decide whether any solution is in or out of
  411. # the domain. Ideally this function would allow returning a
  412. # symbolic condition for the validity of the solution that
  413. # could be handled in the calling code. In the mean time we'll
  414. # give this particular solution the benefit of the doubt and
  415. # let it pass.
  416. return True
  417. else:
  418. # TODO : We should not blindly recurse through all args of arbitrary expressions like this
  419. return all(_domain_check(g, symbol, p)
  420. for g in f.args)
  421. def _is_finite_with_finite_vars(f, domain=S.Complexes):
  422. """
  423. Return True if the given expression is finite. For symbols that
  424. do not assign a value for `complex` and/or `real`, the domain will
  425. be used to assign a value; symbols that do not assign a value
  426. for `finite` will be made finite. All other assumptions are
  427. left unmodified.
  428. """
  429. def assumptions(s):
  430. A = s.assumptions0
  431. A.setdefault('finite', A.get('finite', True))
  432. if domain.is_subset(S.Reals):
  433. # if this gets set it will make complex=True, too
  434. A.setdefault('real', True)
  435. else:
  436. # don't change 'real' because being complex implies
  437. # nothing about being real
  438. A.setdefault('complex', True)
  439. return A
  440. reps = {s: Dummy(**assumptions(s)) for s in f.free_symbols}
  441. return f.xreplace(reps).is_finite
  442. def _is_function_class_equation(func_class, f, symbol):
  443. """ Tests whether the equation is an equation of the given function class.
  444. The given equation belongs to the given function class if it is
  445. comprised of functions of the function class which are multiplied by
  446. or added to expressions independent of the symbol. In addition, the
  447. arguments of all such functions must be linear in the symbol as well.
  448. Examples
  449. ========
  450. >>> from sympy.solvers.solveset import _is_function_class_equation
  451. >>> from sympy import tan, sin, tanh, sinh, exp
  452. >>> from sympy.abc import x
  453. >>> from sympy.functions.elementary.trigonometric import TrigonometricFunction
  454. >>> from sympy.functions.elementary.hyperbolic import HyperbolicFunction
  455. >>> _is_function_class_equation(TrigonometricFunction, exp(x) + tan(x), x)
  456. False
  457. >>> _is_function_class_equation(TrigonometricFunction, tan(x) + sin(x), x)
  458. True
  459. >>> _is_function_class_equation(TrigonometricFunction, tan(x**2), x)
  460. False
  461. >>> _is_function_class_equation(TrigonometricFunction, tan(x + 2), x)
  462. True
  463. >>> _is_function_class_equation(HyperbolicFunction, tanh(x) + sinh(x), x)
  464. True
  465. """
  466. if f.is_Mul or f.is_Add:
  467. return all(_is_function_class_equation(func_class, arg, symbol)
  468. for arg in f.args)
  469. if f.is_Pow:
  470. if not f.exp.has(symbol):
  471. return _is_function_class_equation(func_class, f.base, symbol)
  472. else:
  473. return False
  474. if not f.has(symbol):
  475. return True
  476. if isinstance(f, func_class):
  477. try:
  478. g = Poly(f.args[0], symbol)
  479. return g.degree() <= 1
  480. except PolynomialError:
  481. return False
  482. else:
  483. return False
  484. def _solve_as_rational(f, symbol, domain):
  485. """ solve rational functions"""
  486. f = together(_mexpand(f, recursive=True), deep=True)
  487. g, h = fraction(f)
  488. if not h.has(symbol):
  489. try:
  490. return _solve_as_poly(g, symbol, domain)
  491. except NotImplementedError:
  492. # The polynomial formed from g could end up having
  493. # coefficients in a ring over which finding roots
  494. # isn't implemented yet, e.g. ZZ[a] for some symbol a
  495. return ConditionSet(symbol, Eq(f, 0), domain)
  496. except CoercionFailed:
  497. # contained oo, zoo or nan
  498. return S.EmptySet
  499. else:
  500. valid_solns = _solveset(g, symbol, domain)
  501. invalid_solns = _solveset(h, symbol, domain)
  502. return valid_solns - invalid_solns
  503. class _SolveTrig1Error(Exception):
  504. """Raised when _solve_trig1 heuristics do not apply"""
  505. def _solve_trig(f, symbol, domain):
  506. """Function to call other helpers to solve trigonometric equations """
  507. sol = None
  508. try:
  509. sol = _solve_trig1(f, symbol, domain)
  510. except _SolveTrig1Error:
  511. try:
  512. sol = _solve_trig2(f, symbol, domain)
  513. except ValueError:
  514. raise NotImplementedError(filldedent('''
  515. Solution to this kind of trigonometric equations
  516. is yet to be implemented'''))
  517. return sol
  518. def _solve_trig1(f, symbol, domain):
  519. """Primary solver for trigonometric and hyperbolic equations
  520. Returns either the solution set as a ConditionSet (auto-evaluated to a
  521. union of ImageSets if no variables besides 'symbol' are involved) or
  522. raises _SolveTrig1Error if f == 0 cannot be solved.
  523. Notes
  524. =====
  525. Algorithm:
  526. 1. Do a change of variable x -> mu*x in arguments to trigonometric and
  527. hyperbolic functions, in order to reduce them to small integers. (This
  528. step is crucial to keep the degrees of the polynomials of step 4 low.)
  529. 2. Rewrite trigonometric/hyperbolic functions as exponentials.
  530. 3. Proceed to a 2nd change of variable, replacing exp(I*x) or exp(x) by y.
  531. 4. Solve the resulting rational equation.
  532. 5. Use invert_complex or invert_real to return to the original variable.
  533. 6. If the coefficients of 'symbol' were symbolic in nature, add the
  534. necessary consistency conditions in a ConditionSet.
  535. """
  536. # Prepare change of variable
  537. x = Dummy('x')
  538. if _is_function_class_equation(HyperbolicFunction, f, symbol):
  539. cov = exp(x)
  540. inverter = invert_real if domain.is_subset(S.Reals) else invert_complex
  541. else:
  542. cov = exp(I*x)
  543. inverter = invert_complex
  544. f = trigsimp(f)
  545. f_original = f
  546. trig_functions = f.atoms(TrigonometricFunction, HyperbolicFunction)
  547. trig_arguments = [e.args[0] for e in trig_functions]
  548. # trigsimp may have reduced the equation to an expression
  549. # that is independent of 'symbol' (e.g. cos**2+sin**2)
  550. if not any(a.has(symbol) for a in trig_arguments):
  551. return solveset(f_original, symbol, domain)
  552. denominators = []
  553. numerators = []
  554. for ar in trig_arguments:
  555. try:
  556. poly_ar = Poly(ar, symbol)
  557. except PolynomialError:
  558. raise _SolveTrig1Error("trig argument is not a polynomial")
  559. if poly_ar.degree() > 1: # degree >1 still bad
  560. raise _SolveTrig1Error("degree of variable must not exceed one")
  561. if poly_ar.degree() == 0: # degree 0, don't care
  562. continue
  563. c = poly_ar.all_coeffs()[0] # got the coefficient of 'symbol'
  564. numerators.append(fraction(c)[0])
  565. denominators.append(fraction(c)[1])
  566. mu = lcm(denominators)/gcd(numerators)
  567. f = f.subs(symbol, mu*x)
  568. f = f.rewrite(exp)
  569. f = together(f)
  570. g, h = fraction(f)
  571. y = Dummy('y')
  572. g, h = g.expand(), h.expand()
  573. g, h = g.subs(cov, y), h.subs(cov, y)
  574. if g.has(x) or h.has(x):
  575. raise _SolveTrig1Error("change of variable not possible")
  576. solns = solveset_complex(g, y) - solveset_complex(h, y)
  577. if isinstance(solns, ConditionSet):
  578. raise _SolveTrig1Error("polynomial has ConditionSet solution")
  579. if isinstance(solns, FiniteSet):
  580. if any(isinstance(s, RootOf) for s in solns):
  581. raise _SolveTrig1Error("polynomial results in RootOf object")
  582. # revert the change of variable
  583. cov = cov.subs(x, symbol/mu)
  584. result = Union(*[inverter(cov, s, symbol)[1] for s in solns])
  585. # In case of symbolic coefficients, the solution set is only valid
  586. # if numerator and denominator of mu are non-zero.
  587. if mu.has(Symbol):
  588. syms = (mu).atoms(Symbol)
  589. munum, muden = fraction(mu)
  590. condnum = munum.as_independent(*syms, as_Add=False)[1]
  591. condden = muden.as_independent(*syms, as_Add=False)[1]
  592. cond = And(Ne(condnum, 0), Ne(condden, 0))
  593. else:
  594. cond = True
  595. # Actual conditions are returned as part of the ConditionSet. Adding an
  596. # intersection with C would only complicate some solution sets due to
  597. # current limitations of intersection code. (e.g. #19154)
  598. if domain is S.Complexes:
  599. # This is a slight abuse of ConditionSet. Ideally this should
  600. # be some kind of "PiecewiseSet". (See #19507 discussion)
  601. return ConditionSet(symbol, cond, result)
  602. else:
  603. return ConditionSet(symbol, cond, Intersection(result, domain))
  604. elif solns is S.EmptySet:
  605. return S.EmptySet
  606. else:
  607. raise _SolveTrig1Error("polynomial solutions must form FiniteSet")
  608. def _solve_trig2(f, symbol, domain):
  609. """Secondary helper to solve trigonometric equations,
  610. called when first helper fails """
  611. f = trigsimp(f)
  612. f_original = f
  613. trig_functions = f.atoms(sin, cos, tan, sec, cot, csc)
  614. trig_arguments = [e.args[0] for e in trig_functions]
  615. denominators = []
  616. numerators = []
  617. # todo: This solver can be extended to hyperbolics if the
  618. # analogous change of variable to tanh (instead of tan)
  619. # is used.
  620. if not trig_functions:
  621. return ConditionSet(symbol, Eq(f_original, 0), domain)
  622. # todo: The pre-processing below (extraction of numerators, denominators,
  623. # gcd, lcm, mu, etc.) should be updated to the enhanced version in
  624. # _solve_trig1. (See #19507)
  625. for ar in trig_arguments:
  626. try:
  627. poly_ar = Poly(ar, symbol)
  628. except PolynomialError:
  629. raise ValueError("give up, we cannot solve if this is not a polynomial in x")
  630. if poly_ar.degree() > 1: # degree >1 still bad
  631. raise ValueError("degree of variable inside polynomial should not exceed one")
  632. if poly_ar.degree() == 0: # degree 0, don't care
  633. continue
  634. c = poly_ar.all_coeffs()[0] # got the coefficient of 'symbol'
  635. try:
  636. numerators.append(Rational(c).p)
  637. denominators.append(Rational(c).q)
  638. except TypeError:
  639. return ConditionSet(symbol, Eq(f_original, 0), domain)
  640. x = Dummy('x')
  641. # ilcm() and igcd() require more than one argument
  642. if len(numerators) > 1:
  643. mu = Rational(2)*ilcm(*denominators)/igcd(*numerators)
  644. else:
  645. assert len(numerators) == 1
  646. mu = Rational(2)*denominators[0]/numerators[0]
  647. f = f.subs(symbol, mu*x)
  648. f = f.rewrite(tan)
  649. f = expand_trig(f)
  650. f = together(f)
  651. g, h = fraction(f)
  652. y = Dummy('y')
  653. g, h = g.expand(), h.expand()
  654. g, h = g.subs(tan(x), y), h.subs(tan(x), y)
  655. if g.has(x) or h.has(x):
  656. return ConditionSet(symbol, Eq(f_original, 0), domain)
  657. solns = solveset(g, y, S.Reals) - solveset(h, y, S.Reals)
  658. if isinstance(solns, FiniteSet):
  659. result = Union(*[invert_real(tan(symbol/mu), s, symbol)[1]
  660. for s in solns])
  661. dsol = invert_real(tan(symbol/mu), oo, symbol)[1]
  662. if degree(h) > degree(g): # If degree(denom)>degree(num) then there
  663. result = Union(result, dsol) # would be another sol at Lim(denom-->oo)
  664. return Intersection(result, domain)
  665. elif solns is S.EmptySet:
  666. return S.EmptySet
  667. else:
  668. return ConditionSet(symbol, Eq(f_original, 0), S.Reals)
  669. def _solve_as_poly(f, symbol, domain=S.Complexes):
  670. """
  671. Solve the equation using polynomial techniques if it already is a
  672. polynomial equation or, with a change of variables, can be made so.
  673. """
  674. result = None
  675. if f.is_polynomial(symbol):
  676. solns = roots(f, symbol, cubics=True, quartics=True,
  677. quintics=True, domain='EX')
  678. num_roots = sum(solns.values())
  679. if degree(f, symbol) <= num_roots:
  680. result = FiniteSet(*solns.keys())
  681. else:
  682. poly = Poly(f, symbol)
  683. solns = poly.all_roots()
  684. if poly.degree() <= len(solns):
  685. result = FiniteSet(*solns)
  686. else:
  687. result = ConditionSet(symbol, Eq(f, 0), domain)
  688. else:
  689. poly = Poly(f)
  690. if poly is None:
  691. result = ConditionSet(symbol, Eq(f, 0), domain)
  692. gens = [g for g in poly.gens if g.has(symbol)]
  693. if len(gens) == 1:
  694. poly = Poly(poly, gens[0])
  695. gen = poly.gen
  696. deg = poly.degree()
  697. poly = Poly(poly.as_expr(), poly.gen, composite=True)
  698. poly_solns = FiniteSet(*roots(poly, cubics=True, quartics=True,
  699. quintics=True).keys())
  700. if len(poly_solns) < deg:
  701. result = ConditionSet(symbol, Eq(f, 0), domain)
  702. if gen != symbol:
  703. y = Dummy('y')
  704. inverter = invert_real if domain.is_subset(S.Reals) else invert_complex
  705. lhs, rhs_s = inverter(gen, y, symbol)
  706. if lhs == symbol:
  707. result = Union(*[rhs_s.subs(y, s) for s in poly_solns])
  708. if isinstance(result, FiniteSet) and isinstance(gen, Pow
  709. ) and gen.base.is_Rational:
  710. result = FiniteSet(*[expand_log(i) for i in result])
  711. else:
  712. result = ConditionSet(symbol, Eq(f, 0), domain)
  713. else:
  714. result = ConditionSet(symbol, Eq(f, 0), domain)
  715. if result is not None:
  716. if isinstance(result, FiniteSet):
  717. # this is to simplify solutions like -sqrt(-I) to sqrt(2)/2
  718. # - sqrt(2)*I/2. We are not expanding for solution with symbols
  719. # or undefined functions because that makes the solution more complicated.
  720. # For example, expand_complex(a) returns re(a) + I*im(a)
  721. if all(s.atoms(Symbol, AppliedUndef) == set() and not isinstance(s, RootOf)
  722. for s in result):
  723. s = Dummy('s')
  724. result = imageset(Lambda(s, expand_complex(s)), result)
  725. if isinstance(result, FiniteSet) and domain != S.Complexes:
  726. # Avoid adding gratuitous intersections with S.Complexes. Actual
  727. # conditions should be handled elsewhere.
  728. result = result.intersection(domain)
  729. return result
  730. else:
  731. return ConditionSet(symbol, Eq(f, 0), domain)
  732. def _solve_radical(f, unradf, symbol, solveset_solver):
  733. """ Helper function to solve equations with radicals """
  734. res = unradf
  735. eq, cov = res if res else (f, [])
  736. if not cov:
  737. result = solveset_solver(eq, symbol) - \
  738. Union(*[solveset_solver(g, symbol) for g in denoms(f, symbol)])
  739. else:
  740. y, yeq = cov
  741. if not solveset_solver(y - I, y):
  742. yreal = Dummy('yreal', real=True)
  743. yeq = yeq.xreplace({y: yreal})
  744. eq = eq.xreplace({y: yreal})
  745. y = yreal
  746. g_y_s = solveset_solver(yeq, symbol)
  747. f_y_sols = solveset_solver(eq, y)
  748. result = Union(*[imageset(Lambda(y, g_y), f_y_sols)
  749. for g_y in g_y_s])
  750. def check_finiteset(solutions):
  751. f_set = [] # solutions for FiniteSet
  752. c_set = [] # solutions for ConditionSet
  753. for s in solutions:
  754. if checksol(f, symbol, s):
  755. f_set.append(s)
  756. else:
  757. c_set.append(s)
  758. return FiniteSet(*f_set) + ConditionSet(symbol, Eq(f, 0), FiniteSet(*c_set))
  759. def check_set(solutions):
  760. if solutions is S.EmptySet:
  761. return solutions
  762. elif isinstance(solutions, ConditionSet):
  763. # XXX: Maybe the base set should be checked?
  764. return solutions
  765. elif isinstance(solutions, FiniteSet):
  766. return check_finiteset(solutions)
  767. elif isinstance(solutions, Complement):
  768. A, B = solutions.args
  769. return Complement(check_set(A), B)
  770. elif isinstance(solutions, Union):
  771. return Union(*[check_set(s) for s in solutions.args])
  772. else:
  773. # XXX: There should be more cases checked here. The cases above
  774. # are all those that come up in the test suite for now.
  775. return solutions
  776. solution_set = check_set(result)
  777. return solution_set
  778. def _solve_abs(f, symbol, domain):
  779. """ Helper function to solve equation involving absolute value function """
  780. if not domain.is_subset(S.Reals):
  781. raise ValueError(filldedent('''
  782. Absolute values cannot be inverted in the
  783. complex domain.'''))
  784. p, q, r = Wild('p'), Wild('q'), Wild('r')
  785. pattern_match = f.match(p*Abs(q) + r) or {}
  786. f_p, f_q, f_r = [pattern_match.get(i, S.Zero) for i in (p, q, r)]
  787. if not (f_p.is_zero or f_q.is_zero):
  788. domain = continuous_domain(f_q, symbol, domain)
  789. from .inequalities import solve_univariate_inequality
  790. q_pos_cond = solve_univariate_inequality(f_q >= 0, symbol,
  791. relational=False, domain=domain, continuous=True)
  792. q_neg_cond = q_pos_cond.complement(domain)
  793. sols_q_pos = solveset_real(f_p*f_q + f_r,
  794. symbol).intersect(q_pos_cond)
  795. sols_q_neg = solveset_real(f_p*(-f_q) + f_r,
  796. symbol).intersect(q_neg_cond)
  797. return Union(sols_q_pos, sols_q_neg)
  798. else:
  799. return ConditionSet(symbol, Eq(f, 0), domain)
  800. def solve_decomposition(f, symbol, domain):
  801. """
  802. Function to solve equations via the principle of "Decomposition
  803. and Rewriting".
  804. Examples
  805. ========
  806. >>> from sympy import exp, sin, Symbol, pprint, S
  807. >>> from sympy.solvers.solveset import solve_decomposition as sd
  808. >>> x = Symbol('x')
  809. >>> f1 = exp(2*x) - 3*exp(x) + 2
  810. >>> sd(f1, x, S.Reals)
  811. {0, log(2)}
  812. >>> f2 = sin(x)**2 + 2*sin(x) + 1
  813. >>> pprint(sd(f2, x, S.Reals), use_unicode=False)
  814. 3*pi
  815. {2*n*pi + ---- | n in Integers}
  816. 2
  817. >>> f3 = sin(x + 2)
  818. >>> pprint(sd(f3, x, S.Reals), use_unicode=False)
  819. {2*n*pi - 2 | n in Integers} U {2*n*pi - 2 + pi | n in Integers}
  820. """
  821. from sympy.solvers.decompogen import decompogen
  822. # decompose the given function
  823. g_s = decompogen(f, symbol)
  824. # `y_s` represents the set of values for which the function `g` is to be
  825. # solved.
  826. # `solutions` represent the solutions of the equations `g = y_s` or
  827. # `g = 0` depending on the type of `y_s`.
  828. # As we are interested in solving the equation: f = 0
  829. y_s = FiniteSet(0)
  830. for g in g_s:
  831. frange = function_range(g, symbol, domain)
  832. y_s = Intersection(frange, y_s)
  833. result = S.EmptySet
  834. if isinstance(y_s, FiniteSet):
  835. for y in y_s:
  836. solutions = solveset(Eq(g, y), symbol, domain)
  837. if not isinstance(solutions, ConditionSet):
  838. result += solutions
  839. else:
  840. if isinstance(y_s, ImageSet):
  841. iter_iset = (y_s,)
  842. elif isinstance(y_s, Union):
  843. iter_iset = y_s.args
  844. elif y_s is S.EmptySet:
  845. # y_s is not in the range of g in g_s, so no solution exists
  846. #in the given domain
  847. return S.EmptySet
  848. for iset in iter_iset:
  849. new_solutions = solveset(Eq(iset.lamda.expr, g), symbol, domain)
  850. dummy_var = tuple(iset.lamda.expr.free_symbols)[0]
  851. (base_set,) = iset.base_sets
  852. if isinstance(new_solutions, FiniteSet):
  853. new_exprs = new_solutions
  854. elif isinstance(new_solutions, Intersection):
  855. if isinstance(new_solutions.args[1], FiniteSet):
  856. new_exprs = new_solutions.args[1]
  857. for new_expr in new_exprs:
  858. result += ImageSet(Lambda(dummy_var, new_expr), base_set)
  859. if result is S.EmptySet:
  860. return ConditionSet(symbol, Eq(f, 0), domain)
  861. y_s = result
  862. return y_s
  863. def _solveset(f, symbol, domain, _check=False):
  864. """Helper for solveset to return a result from an expression
  865. that has already been sympify'ed and is known to contain the
  866. given symbol."""
  867. # _check controls whether the answer is checked or not
  868. from sympy.simplify.simplify import signsimp
  869. if isinstance(f, BooleanTrue):
  870. return domain
  871. orig_f = f
  872. if f.is_Mul:
  873. coeff, f = f.as_independent(symbol, as_Add=False)
  874. if coeff in {S.ComplexInfinity, S.NegativeInfinity, S.Infinity}:
  875. f = together(orig_f)
  876. elif f.is_Add:
  877. a, h = f.as_independent(symbol)
  878. m, h = h.as_independent(symbol, as_Add=False)
  879. if m not in {S.ComplexInfinity, S.Zero, S.Infinity,
  880. S.NegativeInfinity}:
  881. f = a/m + h # XXX condition `m != 0` should be added to soln
  882. # assign the solvers to use
  883. solver = lambda f, x, domain=domain: _solveset(f, x, domain)
  884. inverter = lambda f, rhs, symbol: _invert(f, rhs, symbol, domain)
  885. result = S.EmptySet
  886. if f.expand().is_zero:
  887. return domain
  888. elif not f.has(symbol):
  889. return S.EmptySet
  890. elif f.is_Mul and all(_is_finite_with_finite_vars(m, domain)
  891. for m in f.args):
  892. # if f(x) and g(x) are both finite we can say that the solution of
  893. # f(x)*g(x) == 0 is same as Union(f(x) == 0, g(x) == 0) is not true in
  894. # general. g(x) can grow to infinitely large for the values where
  895. # f(x) == 0. To be sure that we are not silently allowing any
  896. # wrong solutions we are using this technique only if both f and g are
  897. # finite for a finite input.
  898. result = Union(*[solver(m, symbol) for m in f.args])
  899. elif _is_function_class_equation(TrigonometricFunction, f, symbol) or \
  900. _is_function_class_equation(HyperbolicFunction, f, symbol):
  901. result = _solve_trig(f, symbol, domain)
  902. elif isinstance(f, arg):
  903. a = f.args[0]
  904. result = Intersection(_solveset(re(a) > 0, symbol, domain),
  905. _solveset(im(a), symbol, domain))
  906. elif f.is_Piecewise:
  907. expr_set_pairs = f.as_expr_set_pairs(domain)
  908. for (expr, in_set) in expr_set_pairs:
  909. if in_set.is_Relational:
  910. in_set = in_set.as_set()
  911. solns = solver(expr, symbol, in_set)
  912. result += solns
  913. elif isinstance(f, Eq):
  914. result = solver(Add(f.lhs, - f.rhs, evaluate=False), symbol, domain)
  915. elif f.is_Relational:
  916. from .inequalities import solve_univariate_inequality
  917. try:
  918. result = solve_univariate_inequality(
  919. f, symbol, domain=domain, relational=False)
  920. except NotImplementedError:
  921. result = ConditionSet(symbol, f, domain)
  922. return result
  923. elif _is_modular(f, symbol):
  924. result = _solve_modular(f, symbol, domain)
  925. else:
  926. lhs, rhs_s = inverter(f, 0, symbol)
  927. if lhs == symbol:
  928. # do some very minimal simplification since
  929. # repeated inversion may have left the result
  930. # in a state that other solvers (e.g. poly)
  931. # would have simplified; this is done here
  932. # rather than in the inverter since here it
  933. # is only done once whereas there it would
  934. # be repeated for each step of the inversion
  935. if isinstance(rhs_s, FiniteSet):
  936. rhs_s = FiniteSet(*[Mul(*
  937. signsimp(i).as_content_primitive())
  938. for i in rhs_s])
  939. result = rhs_s
  940. elif isinstance(rhs_s, FiniteSet):
  941. for equation in [lhs - rhs for rhs in rhs_s]:
  942. if equation == f:
  943. u = unrad(f, symbol)
  944. if u:
  945. result += _solve_radical(equation, u,
  946. symbol,
  947. solver)
  948. elif equation.has(Abs):
  949. result += _solve_abs(f, symbol, domain)
  950. else:
  951. result_rational = _solve_as_rational(equation, symbol, domain)
  952. if not isinstance(result_rational, ConditionSet):
  953. result += result_rational
  954. else:
  955. # may be a transcendental type equation
  956. t_result = _transolve(equation, symbol, domain)
  957. if isinstance(t_result, ConditionSet):
  958. # might need factoring; this is expensive so we
  959. # have delayed until now. To avoid recursion
  960. # errors look for a non-trivial factoring into
  961. # a product of symbol dependent terms; I think
  962. # that something that factors as a Pow would
  963. # have already been recognized by now.
  964. factored = equation.factor()
  965. if factored.is_Mul and equation != factored:
  966. _, dep = factored.as_independent(symbol)
  967. if not dep.is_Add:
  968. # non-trivial factoring of equation
  969. # but use form with constants
  970. # in case they need special handling
  971. t_results = []
  972. for fac in Mul.make_args(factored):
  973. if fac.has(symbol):
  974. t_results.append(solver(fac, symbol))
  975. t_result = Union(*t_results)
  976. result += t_result
  977. else:
  978. result += solver(equation, symbol)
  979. elif rhs_s is not S.EmptySet:
  980. result = ConditionSet(symbol, Eq(f, 0), domain)
  981. if isinstance(result, ConditionSet):
  982. if isinstance(f, Expr):
  983. num, den = f.as_numer_denom()
  984. if den.has(symbol):
  985. _result = _solveset(num, symbol, domain)
  986. if not isinstance(_result, ConditionSet):
  987. singularities = _solveset(den, symbol, domain)
  988. result = _result - singularities
  989. if _check:
  990. if isinstance(result, ConditionSet):
  991. # it wasn't solved or has enumerated all conditions
  992. # -- leave it alone
  993. return result
  994. # whittle away all but the symbol-containing core
  995. # to use this for testing
  996. if isinstance(orig_f, Expr):
  997. fx = orig_f.as_independent(symbol, as_Add=True)[1]
  998. fx = fx.as_independent(symbol, as_Add=False)[1]
  999. else:
  1000. fx = orig_f
  1001. if isinstance(result, FiniteSet):
  1002. # check the result for invalid solutions
  1003. result = FiniteSet(*[s for s in result
  1004. if isinstance(s, RootOf)
  1005. or domain_check(fx, symbol, s)])
  1006. return result
  1007. def _is_modular(f, symbol):
  1008. """
  1009. Helper function to check below mentioned types of modular equations.
  1010. ``A - Mod(B, C) = 0``
  1011. A -> This can or cannot be a function of symbol.
  1012. B -> This is surely a function of symbol.
  1013. C -> It is an integer.
  1014. Parameters
  1015. ==========
  1016. f : Expr
  1017. The equation to be checked.
  1018. symbol : Symbol
  1019. The concerned variable for which the equation is to be checked.
  1020. Examples
  1021. ========
  1022. >>> from sympy import symbols, exp, Mod
  1023. >>> from sympy.solvers.solveset import _is_modular as check
  1024. >>> x, y = symbols('x y')
  1025. >>> check(Mod(x, 3) - 1, x)
  1026. True
  1027. >>> check(Mod(x, 3) - 1, y)
  1028. False
  1029. >>> check(Mod(x, 3)**2 - 5, x)
  1030. False
  1031. >>> check(Mod(x, 3)**2 - y, x)
  1032. False
  1033. >>> check(exp(Mod(x, 3)) - 1, x)
  1034. False
  1035. >>> check(Mod(3, y) - 1, y)
  1036. False
  1037. """
  1038. if not f.has(Mod):
  1039. return False
  1040. # extract modterms from f.
  1041. modterms = list(f.atoms(Mod))
  1042. return (len(modterms) == 1 and # only one Mod should be present
  1043. modterms[0].args[0].has(symbol) and # B-> function of symbol
  1044. modterms[0].args[1].is_integer and # C-> to be an integer.
  1045. any(isinstance(term, Mod)
  1046. for term in list(_term_factors(f))) # free from other funcs
  1047. )
  1048. def _invert_modular(modterm, rhs, n, symbol):
  1049. """
  1050. Helper function to invert modular equation.
  1051. ``Mod(a, m) - rhs = 0``
  1052. Generally it is inverted as (a, ImageSet(Lambda(n, m*n + rhs), S.Integers)).
  1053. More simplified form will be returned if possible.
  1054. If it is not invertible then (modterm, rhs) is returned.
  1055. The following cases arise while inverting equation ``Mod(a, m) - rhs = 0``:
  1056. 1. If a is symbol then m*n + rhs is the required solution.
  1057. 2. If a is an instance of ``Add`` then we try to find two symbol independent
  1058. parts of a and the symbol independent part gets transferred to the other
  1059. side and again the ``_invert_modular`` is called on the symbol
  1060. dependent part.
  1061. 3. If a is an instance of ``Mul`` then same as we done in ``Add`` we separate
  1062. out the symbol dependent and symbol independent parts and transfer the
  1063. symbol independent part to the rhs with the help of invert and again the
  1064. ``_invert_modular`` is called on the symbol dependent part.
  1065. 4. If a is an instance of ``Pow`` then two cases arise as following:
  1066. - If a is of type (symbol_indep)**(symbol_dep) then the remainder is
  1067. evaluated with the help of discrete_log function and then the least
  1068. period is being found out with the help of totient function.
  1069. period*n + remainder is the required solution in this case.
  1070. For reference: (https://en.wikipedia.org/wiki/Euler's_theorem)
  1071. - If a is of type (symbol_dep)**(symbol_indep) then we try to find all
  1072. primitive solutions list with the help of nthroot_mod function.
  1073. m*n + rem is the general solution where rem belongs to solutions list
  1074. from nthroot_mod function.
  1075. Parameters
  1076. ==========
  1077. modterm, rhs : Expr
  1078. The modular equation to be inverted, ``modterm - rhs = 0``
  1079. symbol : Symbol
  1080. The variable in the equation to be inverted.
  1081. n : Dummy
  1082. Dummy variable for output g_n.
  1083. Returns
  1084. =======
  1085. A tuple (f_x, g_n) is being returned where f_x is modular independent function
  1086. of symbol and g_n being set of values f_x can have.
  1087. Examples
  1088. ========
  1089. >>> from sympy import symbols, exp, Mod, Dummy, S
  1090. >>> from sympy.solvers.solveset import _invert_modular as invert_modular
  1091. >>> x, y = symbols('x y')
  1092. >>> n = Dummy('n')
  1093. >>> invert_modular(Mod(exp(x), 7), S(5), n, x)
  1094. (Mod(exp(x), 7), 5)
  1095. >>> invert_modular(Mod(x, 7), S(5), n, x)
  1096. (x, ImageSet(Lambda(_n, 7*_n + 5), Integers))
  1097. >>> invert_modular(Mod(3*x + 8, 7), S(5), n, x)
  1098. (x, ImageSet(Lambda(_n, 7*_n + 6), Integers))
  1099. >>> invert_modular(Mod(x**4, 7), S(5), n, x)
  1100. (x, EmptySet)
  1101. >>> invert_modular(Mod(2**(x**2 + x + 1), 7), S(2), n, x)
  1102. (x**2 + x + 1, ImageSet(Lambda(_n, 3*_n + 1), Naturals0))
  1103. """
  1104. a, m = modterm.args
  1105. if rhs.is_real is False or any(term.is_real is False
  1106. for term in list(_term_factors(a))):
  1107. # Check for complex arguments
  1108. return modterm, rhs
  1109. if abs(rhs) >= abs(m):
  1110. # if rhs has value greater than value of m.
  1111. return symbol, S.EmptySet
  1112. if a == symbol:
  1113. return symbol, ImageSet(Lambda(n, m*n + rhs), S.Integers)
  1114. if a.is_Add:
  1115. # g + h = a
  1116. g, h = a.as_independent(symbol)
  1117. if g is not S.Zero:
  1118. x_indep_term = rhs - Mod(g, m)
  1119. return _invert_modular(Mod(h, m), Mod(x_indep_term, m), n, symbol)
  1120. if a.is_Mul:
  1121. # g*h = a
  1122. g, h = a.as_independent(symbol)
  1123. if g is not S.One:
  1124. x_indep_term = rhs*invert(g, m)
  1125. return _invert_modular(Mod(h, m), Mod(x_indep_term, m), n, symbol)
  1126. if a.is_Pow:
  1127. # base**expo = a
  1128. base, expo = a.args
  1129. if expo.has(symbol) and not base.has(symbol):
  1130. # remainder -> solution independent of n of equation.
  1131. # m, rhs are made coprime by dividing igcd(m, rhs)
  1132. try:
  1133. remainder = discrete_log(m / igcd(m, rhs), rhs, a.base)
  1134. except ValueError: # log does not exist
  1135. return modterm, rhs
  1136. # period -> coefficient of n in the solution and also referred as
  1137. # the least period of expo in which it is repeats itself.
  1138. # (a**(totient(m)) - 1) divides m. Here is link of theorem:
  1139. # (https://en.wikipedia.org/wiki/Euler's_theorem)
  1140. period = totient(m)
  1141. for p in divisors(period):
  1142. # there might a lesser period exist than totient(m).
  1143. if pow(a.base, p, m / igcd(m, a.base)) == 1:
  1144. period = p
  1145. break
  1146. # recursion is not applied here since _invert_modular is currently
  1147. # not smart enough to handle infinite rhs as here expo has infinite
  1148. # rhs = ImageSet(Lambda(n, period*n + remainder), S.Naturals0).
  1149. return expo, ImageSet(Lambda(n, period*n + remainder), S.Naturals0)
  1150. elif base.has(symbol) and not expo.has(symbol):
  1151. try:
  1152. remainder_list = nthroot_mod(rhs, expo, m, all_roots=True)
  1153. if remainder_list == []:
  1154. return symbol, S.EmptySet
  1155. except (ValueError, NotImplementedError):
  1156. return modterm, rhs
  1157. g_n = S.EmptySet
  1158. for rem in remainder_list:
  1159. g_n += ImageSet(Lambda(n, m*n + rem), S.Integers)
  1160. return base, g_n
  1161. return modterm, rhs
  1162. def _solve_modular(f, symbol, domain):
  1163. r"""
  1164. Helper function for solving modular equations of type ``A - Mod(B, C) = 0``,
  1165. where A can or cannot be a function of symbol, B is surely a function of
  1166. symbol and C is an integer.
  1167. Currently ``_solve_modular`` is only able to solve cases
  1168. where A is not a function of symbol.
  1169. Parameters
  1170. ==========
  1171. f : Expr
  1172. The modular equation to be solved, ``f = 0``
  1173. symbol : Symbol
  1174. The variable in the equation to be solved.
  1175. domain : Set
  1176. A set over which the equation is solved. It has to be a subset of
  1177. Integers.
  1178. Returns
  1179. =======
  1180. A set of integer solutions satisfying the given modular equation.
  1181. A ``ConditionSet`` if the equation is unsolvable.
  1182. Examples
  1183. ========
  1184. >>> from sympy.solvers.solveset import _solve_modular as solve_modulo
  1185. >>> from sympy import S, Symbol, sin, Intersection, Interval, Mod
  1186. >>> x = Symbol('x')
  1187. >>> solve_modulo(Mod(5*x - 8, 7) - 3, x, S.Integers)
  1188. ImageSet(Lambda(_n, 7*_n + 5), Integers)
  1189. >>> solve_modulo(Mod(5*x - 8, 7) - 3, x, S.Reals) # domain should be subset of integers.
  1190. ConditionSet(x, Eq(Mod(5*x + 6, 7) - 3, 0), Reals)
  1191. >>> solve_modulo(-7 + Mod(x, 5), x, S.Integers)
  1192. EmptySet
  1193. >>> solve_modulo(Mod(12**x, 21) - 18, x, S.Integers)
  1194. ImageSet(Lambda(_n, 6*_n + 2), Naturals0)
  1195. >>> solve_modulo(Mod(sin(x), 7) - 3, x, S.Integers) # not solvable
  1196. ConditionSet(x, Eq(Mod(sin(x), 7) - 3, 0), Integers)
  1197. >>> solve_modulo(3 - Mod(x, 5), x, Intersection(S.Integers, Interval(0, 100)))
  1198. Intersection(ImageSet(Lambda(_n, 5*_n + 3), Integers), Range(0, 101, 1))
  1199. """
  1200. # extract modterm and g_y from f
  1201. unsolved_result = ConditionSet(symbol, Eq(f, 0), domain)
  1202. modterm = list(f.atoms(Mod))[0]
  1203. rhs = -S.One*(f.subs(modterm, S.Zero))
  1204. if f.as_coefficients_dict()[modterm].is_negative:
  1205. # checks if coefficient of modterm is negative in main equation.
  1206. rhs *= -S.One
  1207. if not domain.is_subset(S.Integers):
  1208. return unsolved_result
  1209. if rhs.has(symbol):
  1210. # TODO Case: A-> function of symbol, can be extended here
  1211. # in future.
  1212. return unsolved_result
  1213. n = Dummy('n', integer=True)
  1214. f_x, g_n = _invert_modular(modterm, rhs, n, symbol)
  1215. if f_x == modterm and g_n == rhs:
  1216. return unsolved_result
  1217. if f_x == symbol:
  1218. if domain is not S.Integers:
  1219. return domain.intersect(g_n)
  1220. return g_n
  1221. if isinstance(g_n, ImageSet):
  1222. lamda_expr = g_n.lamda.expr
  1223. lamda_vars = g_n.lamda.variables
  1224. base_sets = g_n.base_sets
  1225. sol_set = _solveset(f_x - lamda_expr, symbol, S.Integers)
  1226. if isinstance(sol_set, FiniteSet):
  1227. tmp_sol = S.EmptySet
  1228. for sol in sol_set:
  1229. tmp_sol += ImageSet(Lambda(lamda_vars, sol), *base_sets)
  1230. sol_set = tmp_sol
  1231. else:
  1232. sol_set = ImageSet(Lambda(lamda_vars, sol_set), *base_sets)
  1233. return domain.intersect(sol_set)
  1234. return unsolved_result
  1235. def _term_factors(f):
  1236. """
  1237. Iterator to get the factors of all terms present
  1238. in the given equation.
  1239. Parameters
  1240. ==========
  1241. f : Expr
  1242. Equation that needs to be addressed
  1243. Returns
  1244. =======
  1245. Factors of all terms present in the equation.
  1246. Examples
  1247. ========
  1248. >>> from sympy import symbols
  1249. >>> from sympy.solvers.solveset import _term_factors
  1250. >>> x = symbols('x')
  1251. >>> list(_term_factors(-2 - x**2 + x*(x + 1)))
  1252. [-2, -1, x**2, x, x + 1]
  1253. """
  1254. for add_arg in Add.make_args(f):
  1255. yield from Mul.make_args(add_arg)
  1256. def _solve_exponential(lhs, rhs, symbol, domain):
  1257. r"""
  1258. Helper function for solving (supported) exponential equations.
  1259. Exponential equations are the sum of (currently) at most
  1260. two terms with one or both of them having a power with a
  1261. symbol-dependent exponent.
  1262. For example
  1263. .. math:: 5^{2x + 3} - 5^{3x - 1}
  1264. .. math:: 4^{5 - 9x} - e^{2 - x}
  1265. Parameters
  1266. ==========
  1267. lhs, rhs : Expr
  1268. The exponential equation to be solved, `lhs = rhs`
  1269. symbol : Symbol
  1270. The variable in which the equation is solved
  1271. domain : Set
  1272. A set over which the equation is solved.
  1273. Returns
  1274. =======
  1275. A set of solutions satisfying the given equation.
  1276. A ``ConditionSet`` if the equation is unsolvable or
  1277. if the assumptions are not properly defined, in that case
  1278. a different style of ``ConditionSet`` is returned having the
  1279. solution(s) of the equation with the desired assumptions.
  1280. Examples
  1281. ========
  1282. >>> from sympy.solvers.solveset import _solve_exponential as solve_expo
  1283. >>> from sympy import symbols, S
  1284. >>> x = symbols('x', real=True)
  1285. >>> a, b = symbols('a b')
  1286. >>> solve_expo(2**x + 3**x - 5**x, 0, x, S.Reals) # not solvable
  1287. ConditionSet(x, Eq(2**x + 3**x - 5**x, 0), Reals)
  1288. >>> solve_expo(a**x - b**x, 0, x, S.Reals) # solvable but incorrect assumptions
  1289. ConditionSet(x, (a > 0) & (b > 0), {0})
  1290. >>> solve_expo(3**(2*x) - 2**(x + 3), 0, x, S.Reals)
  1291. {-3*log(2)/(-2*log(3) + log(2))}
  1292. >>> solve_expo(2**x - 4**x, 0, x, S.Reals)
  1293. {0}
  1294. * Proof of correctness of the method
  1295. The logarithm function is the inverse of the exponential function.
  1296. The defining relation between exponentiation and logarithm is:
  1297. .. math:: {\log_b x} = y \enspace if \enspace b^y = x
  1298. Therefore if we are given an equation with exponent terms, we can
  1299. convert every term to its corresponding logarithmic form. This is
  1300. achieved by taking logarithms and expanding the equation using
  1301. logarithmic identities so that it can easily be handled by ``solveset``.
  1302. For example:
  1303. .. math:: 3^{2x} = 2^{x + 3}
  1304. Taking log both sides will reduce the equation to
  1305. .. math:: (2x)\log(3) = (x + 3)\log(2)
  1306. This form can be easily handed by ``solveset``.
  1307. """
  1308. unsolved_result = ConditionSet(symbol, Eq(lhs - rhs, 0), domain)
  1309. newlhs = powdenest(lhs)
  1310. if lhs != newlhs:
  1311. # it may also be advantageous to factor the new expr
  1312. neweq = factor(newlhs - rhs)
  1313. if neweq != (lhs - rhs):
  1314. return _solveset(neweq, symbol, domain) # try again with _solveset
  1315. if not (isinstance(lhs, Add) and len(lhs.args) == 2):
  1316. # solving for the sum of more than two powers is possible
  1317. # but not yet implemented
  1318. return unsolved_result
  1319. if rhs != 0:
  1320. return unsolved_result
  1321. a, b = list(ordered(lhs.args))
  1322. a_term = a.as_independent(symbol)[1]
  1323. b_term = b.as_independent(symbol)[1]
  1324. a_base, a_exp = a_term.as_base_exp()
  1325. b_base, b_exp = b_term.as_base_exp()
  1326. if domain.is_subset(S.Reals):
  1327. conditions = And(
  1328. a_base > 0,
  1329. b_base > 0,
  1330. Eq(im(a_exp), 0),
  1331. Eq(im(b_exp), 0))
  1332. else:
  1333. conditions = And(
  1334. Ne(a_base, 0),
  1335. Ne(b_base, 0))
  1336. L, R = (expand_log(log(i), force=True) for i in (a, -b))
  1337. solutions = _solveset(L - R, symbol, domain)
  1338. return ConditionSet(symbol, conditions, solutions)
  1339. def _is_exponential(f, symbol):
  1340. r"""
  1341. Return ``True`` if one or more terms contain ``symbol`` only in
  1342. exponents, else ``False``.
  1343. Parameters
  1344. ==========
  1345. f : Expr
  1346. The equation to be checked
  1347. symbol : Symbol
  1348. The variable in which the equation is checked
  1349. Examples
  1350. ========
  1351. >>> from sympy import symbols, cos, exp
  1352. >>> from sympy.solvers.solveset import _is_exponential as check
  1353. >>> x, y = symbols('x y')
  1354. >>> check(y, y)
  1355. False
  1356. >>> check(x**y - 1, y)
  1357. True
  1358. >>> check(x**y*2**y - 1, y)
  1359. True
  1360. >>> check(exp(x + 3) + 3**x, x)
  1361. True
  1362. >>> check(cos(2**x), x)
  1363. False
  1364. * Philosophy behind the helper
  1365. The function extracts each term of the equation and checks if it is
  1366. of exponential form w.r.t ``symbol``.
  1367. """
  1368. rv = False
  1369. for expr_arg in _term_factors(f):
  1370. if symbol not in expr_arg.free_symbols:
  1371. continue
  1372. if (isinstance(expr_arg, Pow) and
  1373. symbol not in expr_arg.base.free_symbols or
  1374. isinstance(expr_arg, exp)):
  1375. rv = True # symbol in exponent
  1376. else:
  1377. return False # dependent on symbol in non-exponential way
  1378. return rv
  1379. def _solve_logarithm(lhs, rhs, symbol, domain):
  1380. r"""
  1381. Helper to solve logarithmic equations which are reducible
  1382. to a single instance of `\log`.
  1383. Logarithmic equations are (currently) the equations that contains
  1384. `\log` terms which can be reduced to a single `\log` term or
  1385. a constant using various logarithmic identities.
  1386. For example:
  1387. .. math:: \log(x) + \log(x - 4)
  1388. can be reduced to:
  1389. .. math:: \log(x(x - 4))
  1390. Parameters
  1391. ==========
  1392. lhs, rhs : Expr
  1393. The logarithmic equation to be solved, `lhs = rhs`
  1394. symbol : Symbol
  1395. The variable in which the equation is solved
  1396. domain : Set
  1397. A set over which the equation is solved.
  1398. Returns
  1399. =======
  1400. A set of solutions satisfying the given equation.
  1401. A ``ConditionSet`` if the equation is unsolvable.
  1402. Examples
  1403. ========
  1404. >>> from sympy import symbols, log, S
  1405. >>> from sympy.solvers.solveset import _solve_logarithm as solve_log
  1406. >>> x = symbols('x')
  1407. >>> f = log(x - 3) + log(x + 3)
  1408. >>> solve_log(f, 0, x, S.Reals)
  1409. {-sqrt(10), sqrt(10)}
  1410. * Proof of correctness
  1411. A logarithm is another way to write exponent and is defined by
  1412. .. math:: {\log_b x} = y \enspace if \enspace b^y = x
  1413. When one side of the equation contains a single logarithm, the
  1414. equation can be solved by rewriting the equation as an equivalent
  1415. exponential equation as defined above. But if one side contains
  1416. more than one logarithm, we need to use the properties of logarithm
  1417. to condense it into a single logarithm.
  1418. Take for example
  1419. .. math:: \log(2x) - 15 = 0
  1420. contains single logarithm, therefore we can directly rewrite it to
  1421. exponential form as
  1422. .. math:: x = \frac{e^{15}}{2}
  1423. But if the equation has more than one logarithm as
  1424. .. math:: \log(x - 3) + \log(x + 3) = 0
  1425. we use logarithmic identities to convert it into a reduced form
  1426. Using,
  1427. .. math:: \log(a) + \log(b) = \log(ab)
  1428. the equation becomes,
  1429. .. math:: \log((x - 3)(x + 3))
  1430. This equation contains one logarithm and can be solved by rewriting
  1431. to exponents.
  1432. """
  1433. new_lhs = logcombine(lhs, force=True)
  1434. new_f = new_lhs - rhs
  1435. return _solveset(new_f, symbol, domain)
  1436. def _is_logarithmic(f, symbol):
  1437. r"""
  1438. Return ``True`` if the equation is in the form
  1439. `a\log(f(x)) + b\log(g(x)) + ... + c` else ``False``.
  1440. Parameters
  1441. ==========
  1442. f : Expr
  1443. The equation to be checked
  1444. symbol : Symbol
  1445. The variable in which the equation is checked
  1446. Returns
  1447. =======
  1448. ``True`` if the equation is logarithmic otherwise ``False``.
  1449. Examples
  1450. ========
  1451. >>> from sympy import symbols, tan, log
  1452. >>> from sympy.solvers.solveset import _is_logarithmic as check
  1453. >>> x, y = symbols('x y')
  1454. >>> check(log(x + 2) - log(x + 3), x)
  1455. True
  1456. >>> check(tan(log(2*x)), x)
  1457. False
  1458. >>> check(x*log(x), x)
  1459. False
  1460. >>> check(x + log(x), x)
  1461. False
  1462. >>> check(y + log(x), x)
  1463. True
  1464. * Philosophy behind the helper
  1465. The function extracts each term and checks whether it is
  1466. logarithmic w.r.t ``symbol``.
  1467. """
  1468. rv = False
  1469. for term in Add.make_args(f):
  1470. saw_log = False
  1471. for term_arg in Mul.make_args(term):
  1472. if symbol not in term_arg.free_symbols:
  1473. continue
  1474. if isinstance(term_arg, log):
  1475. if saw_log:
  1476. return False # more than one log in term
  1477. saw_log = True
  1478. else:
  1479. return False # dependent on symbol in non-log way
  1480. if saw_log:
  1481. rv = True
  1482. return rv
  1483. def _is_lambert(f, symbol):
  1484. r"""
  1485. If this returns ``False`` then the Lambert solver (``_solve_lambert``) will not be called.
  1486. Explanation
  1487. ===========
  1488. Quick check for cases that the Lambert solver might be able to handle.
  1489. 1. Equations containing more than two operands and `symbol`s involving any of
  1490. `Pow`, `exp`, `HyperbolicFunction`,`TrigonometricFunction`, `log` terms.
  1491. 2. In `Pow`, `exp` the exponent should have `symbol` whereas for
  1492. `HyperbolicFunction`,`TrigonometricFunction`, `log` should contain `symbol`.
  1493. 3. For `HyperbolicFunction`,`TrigonometricFunction` the number of trigonometric functions in
  1494. equation should be less than number of symbols. (since `A*cos(x) + B*sin(x) - c`
  1495. is not the Lambert type).
  1496. Some forms of lambert equations are:
  1497. 1. X**X = C
  1498. 2. X*(B*log(X) + D)**A = C
  1499. 3. A*log(B*X + A) + d*X = C
  1500. 4. (B*X + A)*exp(d*X + g) = C
  1501. 5. g*exp(B*X + h) - B*X = C
  1502. 6. A*D**(E*X + g) - B*X = C
  1503. 7. A*cos(X) + B*sin(X) - D*X = C
  1504. 8. A*cosh(X) + B*sinh(X) - D*X = C
  1505. Where X is any variable,
  1506. A, B, C, D, E are any constants,
  1507. g, h are linear functions or log terms.
  1508. Parameters
  1509. ==========
  1510. f : Expr
  1511. The equation to be checked
  1512. symbol : Symbol
  1513. The variable in which the equation is checked
  1514. Returns
  1515. =======
  1516. If this returns ``False`` then the Lambert solver (``_solve_lambert``) will not be called.
  1517. Examples
  1518. ========
  1519. >>> from sympy.solvers.solveset import _is_lambert
  1520. >>> from sympy import symbols, cosh, sinh, log
  1521. >>> x = symbols('x')
  1522. >>> _is_lambert(3*log(x) - x*log(3), x)
  1523. True
  1524. >>> _is_lambert(log(log(x - 3)) + log(x-3), x)
  1525. True
  1526. >>> _is_lambert(cosh(x) - sinh(x), x)
  1527. False
  1528. >>> _is_lambert((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1), x)
  1529. True
  1530. See Also
  1531. ========
  1532. _solve_lambert
  1533. """
  1534. term_factors = list(_term_factors(f.expand()))
  1535. # total number of symbols in equation
  1536. no_of_symbols = len([arg for arg in term_factors if arg.has(symbol)])
  1537. # total number of trigonometric terms in equation
  1538. no_of_trig = len([arg for arg in term_factors \
  1539. if arg.has(HyperbolicFunction, TrigonometricFunction)])
  1540. if f.is_Add and no_of_symbols >= 2:
  1541. # `log`, `HyperbolicFunction`, `TrigonometricFunction` should have symbols
  1542. # and no_of_trig < no_of_symbols
  1543. lambert_funcs = (log, HyperbolicFunction, TrigonometricFunction)
  1544. if any(isinstance(arg, lambert_funcs)\
  1545. for arg in term_factors if arg.has(symbol)):
  1546. if no_of_trig < no_of_symbols:
  1547. return True
  1548. # here, `Pow`, `exp` exponent should have symbols
  1549. elif any(isinstance(arg, (Pow, exp)) \
  1550. for arg in term_factors if (arg.as_base_exp()[1]).has(symbol)):
  1551. return True
  1552. return False
  1553. def _transolve(f, symbol, domain):
  1554. r"""
  1555. Function to solve transcendental equations. It is a helper to
  1556. ``solveset`` and should be used internally. ``_transolve``
  1557. currently supports the following class of equations:
  1558. - Exponential equations
  1559. - Logarithmic equations
  1560. Parameters
  1561. ==========
  1562. f : Any transcendental equation that needs to be solved.
  1563. This needs to be an expression, which is assumed
  1564. to be equal to ``0``.
  1565. symbol : The variable for which the equation is solved.
  1566. This needs to be of class ``Symbol``.
  1567. domain : A set over which the equation is solved.
  1568. This needs to be of class ``Set``.
  1569. Returns
  1570. =======
  1571. Set
  1572. A set of values for ``symbol`` for which ``f`` is equal to
  1573. zero. An ``EmptySet`` is returned if ``f`` does not have solutions
  1574. in respective domain. A ``ConditionSet`` is returned as unsolved
  1575. object if algorithms to evaluate complete solution are not
  1576. yet implemented.
  1577. How to use ``_transolve``
  1578. =========================
  1579. ``_transolve`` should not be used as an independent function, because
  1580. it assumes that the equation (``f``) and the ``symbol`` comes from
  1581. ``solveset`` and might have undergone a few modification(s).
  1582. To use ``_transolve`` as an independent function the equation (``f``)
  1583. and the ``symbol`` should be passed as they would have been by
  1584. ``solveset``.
  1585. Examples
  1586. ========
  1587. >>> from sympy.solvers.solveset import _transolve as transolve
  1588. >>> from sympy.solvers.solvers import _tsolve as tsolve
  1589. >>> from sympy import symbols, S, pprint
  1590. >>> x = symbols('x', real=True) # assumption added
  1591. >>> transolve(5**(x - 3) - 3**(2*x + 1), x, S.Reals)
  1592. {-(log(3) + 3*log(5))/(-log(5) + 2*log(3))}
  1593. How ``_transolve`` works
  1594. ========================
  1595. ``_transolve`` uses two types of helper functions to solve equations
  1596. of a particular class:
  1597. Identifying helpers: To determine whether a given equation
  1598. belongs to a certain class of equation or not. Returns either
  1599. ``True`` or ``False``.
  1600. Solving helpers: Once an equation is identified, a corresponding
  1601. helper either solves the equation or returns a form of the equation
  1602. that ``solveset`` might better be able to handle.
  1603. * Philosophy behind the module
  1604. The purpose of ``_transolve`` is to take equations which are not
  1605. already polynomial in their generator(s) and to either recast them
  1606. as such through a valid transformation or to solve them outright.
  1607. A pair of helper functions for each class of supported
  1608. transcendental functions are employed for this purpose. One
  1609. identifies the transcendental form of an equation and the other
  1610. either solves it or recasts it into a tractable form that can be
  1611. solved by ``solveset``.
  1612. For example, an equation in the form `ab^{f(x)} - cd^{g(x)} = 0`
  1613. can be transformed to
  1614. `\log(a) + f(x)\log(b) - \log(c) - g(x)\log(d) = 0`
  1615. (under certain assumptions) and this can be solved with ``solveset``
  1616. if `f(x)` and `g(x)` are in polynomial form.
  1617. How ``_transolve`` is better than ``_tsolve``
  1618. =============================================
  1619. 1) Better output
  1620. ``_transolve`` provides expressions in a more simplified form.
  1621. Consider a simple exponential equation
  1622. >>> f = 3**(2*x) - 2**(x + 3)
  1623. >>> pprint(transolve(f, x, S.Reals), use_unicode=False)
  1624. -3*log(2)
  1625. {------------------}
  1626. -2*log(3) + log(2)
  1627. >>> pprint(tsolve(f, x), use_unicode=False)
  1628. / 3 \
  1629. | --------|
  1630. | log(2/9)|
  1631. [-log\2 /]
  1632. 2) Extensible
  1633. The API of ``_transolve`` is designed such that it is easily
  1634. extensible, i.e. the code that solves a given class of
  1635. equations is encapsulated in a helper and not mixed in with
  1636. the code of ``_transolve`` itself.
  1637. 3) Modular
  1638. ``_transolve`` is designed to be modular i.e, for every class of
  1639. equation a separate helper for identification and solving is
  1640. implemented. This makes it easy to change or modify any of the
  1641. method implemented directly in the helpers without interfering
  1642. with the actual structure of the API.
  1643. 4) Faster Computation
  1644. Solving equation via ``_transolve`` is much faster as compared to
  1645. ``_tsolve``. In ``solve``, attempts are made computing every possibility
  1646. to get the solutions. This series of attempts makes solving a bit
  1647. slow. In ``_transolve``, computation begins only after a particular
  1648. type of equation is identified.
  1649. How to add new class of equations
  1650. =================================
  1651. Adding a new class of equation solver is a three-step procedure:
  1652. - Identify the type of the equations
  1653. Determine the type of the class of equations to which they belong:
  1654. it could be of ``Add``, ``Pow``, etc. types. Separate internal functions
  1655. are used for each type. Write identification and solving helpers
  1656. and use them from within the routine for the given type of equation
  1657. (after adding it, if necessary). Something like:
  1658. .. code-block:: python
  1659. def add_type(lhs, rhs, x):
  1660. ....
  1661. if _is_exponential(lhs, x):
  1662. new_eq = _solve_exponential(lhs, rhs, x)
  1663. ....
  1664. rhs, lhs = eq.as_independent(x)
  1665. if lhs.is_Add:
  1666. result = add_type(lhs, rhs, x)
  1667. - Define the identification helper.
  1668. - Define the solving helper.
  1669. Apart from this, a few other things needs to be taken care while
  1670. adding an equation solver:
  1671. - Naming conventions:
  1672. Name of the identification helper should be as
  1673. ``_is_class`` where class will be the name or abbreviation
  1674. of the class of equation. The solving helper will be named as
  1675. ``_solve_class``.
  1676. For example: for exponential equations it becomes
  1677. ``_is_exponential`` and ``_solve_expo``.
  1678. - The identifying helpers should take two input parameters,
  1679. the equation to be checked and the variable for which a solution
  1680. is being sought, while solving helpers would require an additional
  1681. domain parameter.
  1682. - Be sure to consider corner cases.
  1683. - Add tests for each helper.
  1684. - Add a docstring to your helper that describes the method
  1685. implemented.
  1686. The documentation of the helpers should identify:
  1687. - the purpose of the helper,
  1688. - the method used to identify and solve the equation,
  1689. - a proof of correctness
  1690. - the return values of the helpers
  1691. """
  1692. def add_type(lhs, rhs, symbol, domain):
  1693. """
  1694. Helper for ``_transolve`` to handle equations of
  1695. ``Add`` type, i.e. equations taking the form as
  1696. ``a*f(x) + b*g(x) + .... = c``.
  1697. For example: 4**x + 8**x = 0
  1698. """
  1699. result = ConditionSet(symbol, Eq(lhs - rhs, 0), domain)
  1700. # check if it is exponential type equation
  1701. if _is_exponential(lhs, symbol):
  1702. result = _solve_exponential(lhs, rhs, symbol, domain)
  1703. # check if it is logarithmic type equation
  1704. elif _is_logarithmic(lhs, symbol):
  1705. result = _solve_logarithm(lhs, rhs, symbol, domain)
  1706. return result
  1707. result = ConditionSet(symbol, Eq(f, 0), domain)
  1708. # invert_complex handles the call to the desired inverter based
  1709. # on the domain specified.
  1710. lhs, rhs_s = invert_complex(f, 0, symbol, domain)
  1711. if isinstance(rhs_s, FiniteSet):
  1712. assert (len(rhs_s.args)) == 1
  1713. rhs = rhs_s.args[0]
  1714. if lhs.is_Add:
  1715. result = add_type(lhs, rhs, symbol, domain)
  1716. else:
  1717. result = rhs_s
  1718. return result
  1719. def solveset(f, symbol=None, domain=S.Complexes):
  1720. r"""Solves a given inequality or equation with set as output
  1721. Parameters
  1722. ==========
  1723. f : Expr or a relational.
  1724. The target equation or inequality
  1725. symbol : Symbol
  1726. The variable for which the equation is solved
  1727. domain : Set
  1728. The domain over which the equation is solved
  1729. Returns
  1730. =======
  1731. Set
  1732. A set of values for `symbol` for which `f` is True or is equal to
  1733. zero. An :class:`~.EmptySet` is returned if `f` is False or nonzero.
  1734. A :class:`~.ConditionSet` is returned as unsolved object if algorithms
  1735. to evaluate complete solution are not yet implemented.
  1736. ``solveset`` claims to be complete in the solution set that it returns.
  1737. Raises
  1738. ======
  1739. NotImplementedError
  1740. The algorithms to solve inequalities in complex domain are
  1741. not yet implemented.
  1742. ValueError
  1743. The input is not valid.
  1744. RuntimeError
  1745. It is a bug, please report to the github issue tracker.
  1746. Notes
  1747. =====
  1748. Python interprets 0 and 1 as False and True, respectively, but
  1749. in this function they refer to solutions of an expression. So 0 and 1
  1750. return the domain and EmptySet, respectively, while True and False
  1751. return the opposite (as they are assumed to be solutions of relational
  1752. expressions).
  1753. See Also
  1754. ========
  1755. solveset_real: solver for real domain
  1756. solveset_complex: solver for complex domain
  1757. Examples
  1758. ========
  1759. >>> from sympy import exp, sin, Symbol, pprint, S, Eq
  1760. >>> from sympy.solvers.solveset import solveset, solveset_real
  1761. * The default domain is complex. Not specifying a domain will lead
  1762. to the solving of the equation in the complex domain (and this
  1763. is not affected by the assumptions on the symbol):
  1764. >>> x = Symbol('x')
  1765. >>> pprint(solveset(exp(x) - 1, x), use_unicode=False)
  1766. {2*n*I*pi | n in Integers}
  1767. >>> x = Symbol('x', real=True)
  1768. >>> pprint(solveset(exp(x) - 1, x), use_unicode=False)
  1769. {2*n*I*pi | n in Integers}
  1770. * If you want to use ``solveset`` to solve the equation in the
  1771. real domain, provide a real domain. (Using ``solveset_real``
  1772. does this automatically.)
  1773. >>> R = S.Reals
  1774. >>> x = Symbol('x')
  1775. >>> solveset(exp(x) - 1, x, R)
  1776. {0}
  1777. >>> solveset_real(exp(x) - 1, x)
  1778. {0}
  1779. The solution is unaffected by assumptions on the symbol:
  1780. >>> p = Symbol('p', positive=True)
  1781. >>> pprint(solveset(p**2 - 4))
  1782. {-2, 2}
  1783. When a :class:`~.ConditionSet` is returned, symbols with assumptions that
  1784. would alter the set are replaced with more generic symbols:
  1785. >>> i = Symbol('i', imaginary=True)
  1786. >>> solveset(Eq(i**2 + i*sin(i), 1), i, domain=S.Reals)
  1787. ConditionSet(_R, Eq(_R**2 + _R*sin(_R) - 1, 0), Reals)
  1788. * Inequalities can be solved over the real domain only. Use of a complex
  1789. domain leads to a NotImplementedError.
  1790. >>> solveset(exp(x) > 1, x, R)
  1791. Interval.open(0, oo)
  1792. """
  1793. f = sympify(f)
  1794. symbol = sympify(symbol)
  1795. if f is S.true:
  1796. return domain
  1797. if f is S.false:
  1798. return S.EmptySet
  1799. if not isinstance(f, (Expr, Relational, Number)):
  1800. raise ValueError("%s is not a valid SymPy expression" % f)
  1801. if not isinstance(symbol, (Expr, Relational)) and symbol is not None:
  1802. raise ValueError("%s is not a valid SymPy symbol" % (symbol,))
  1803. if not isinstance(domain, Set):
  1804. raise ValueError("%s is not a valid domain" %(domain))
  1805. free_symbols = f.free_symbols
  1806. if f.has(Piecewise):
  1807. f = piecewise_fold(f)
  1808. if symbol is None and not free_symbols:
  1809. b = Eq(f, 0)
  1810. if b is S.true:
  1811. return domain
  1812. elif b is S.false:
  1813. return S.EmptySet
  1814. else:
  1815. raise NotImplementedError(filldedent('''
  1816. relationship between value and 0 is unknown: %s''' % b))
  1817. if symbol is None:
  1818. if len(free_symbols) == 1:
  1819. symbol = free_symbols.pop()
  1820. elif free_symbols:
  1821. raise ValueError(filldedent('''
  1822. The independent variable must be specified for a
  1823. multivariate equation.'''))
  1824. elif not isinstance(symbol, Symbol):
  1825. f, s, swap = recast_to_symbols([f], [symbol])
  1826. # the xreplace will be needed if a ConditionSet is returned
  1827. return solveset(f[0], s[0], domain).xreplace(swap)
  1828. # solveset should ignore assumptions on symbols
  1829. if symbol not in _rc:
  1830. x = _rc[0] if domain.is_subset(S.Reals) else _rc[1]
  1831. rv = solveset(f.xreplace({symbol: x}), x, domain)
  1832. # try to use the original symbol if possible
  1833. try:
  1834. _rv = rv.xreplace({x: symbol})
  1835. except TypeError:
  1836. _rv = rv
  1837. if rv.dummy_eq(_rv):
  1838. rv = _rv
  1839. return rv
  1840. # Abs has its own handling method which avoids the
  1841. # rewriting property that the first piece of abs(x)
  1842. # is for x >= 0 and the 2nd piece for x < 0 -- solutions
  1843. # can look better if the 2nd condition is x <= 0. Since
  1844. # the solution is a set, duplication of results is not
  1845. # an issue, e.g. {y, -y} when y is 0 will be {0}
  1846. f, mask = _masked(f, Abs)
  1847. f = f.rewrite(Piecewise) # everything that's not an Abs
  1848. for d, e in mask:
  1849. # everything *in* an Abs
  1850. e = e.func(e.args[0].rewrite(Piecewise))
  1851. f = f.xreplace({d: e})
  1852. f = piecewise_fold(f)
  1853. return _solveset(f, symbol, domain, _check=True)
  1854. def solveset_real(f, symbol):
  1855. return solveset(f, symbol, S.Reals)
  1856. def solveset_complex(f, symbol):
  1857. return solveset(f, symbol, S.Complexes)
  1858. def _solveset_multi(eqs, syms, domains):
  1859. '''Basic implementation of a multivariate solveset.
  1860. For internal use (not ready for public consumption)'''
  1861. rep = {}
  1862. for sym, dom in zip(syms, domains):
  1863. if dom is S.Reals:
  1864. rep[sym] = Symbol(sym.name, real=True)
  1865. eqs = [eq.subs(rep) for eq in eqs]
  1866. syms = [sym.subs(rep) for sym in syms]
  1867. syms = tuple(syms)
  1868. if len(eqs) == 0:
  1869. return ProductSet(*domains)
  1870. if len(syms) == 1:
  1871. sym = syms[0]
  1872. domain = domains[0]
  1873. solsets = [solveset(eq, sym, domain) for eq in eqs]
  1874. solset = Intersection(*solsets)
  1875. return ImageSet(Lambda((sym,), (sym,)), solset).doit()
  1876. eqs = sorted(eqs, key=lambda eq: len(eq.free_symbols & set(syms)))
  1877. for n, eq in enumerate(eqs):
  1878. sols = []
  1879. all_handled = True
  1880. for sym in syms:
  1881. if sym not in eq.free_symbols:
  1882. continue
  1883. sol = solveset(eq, sym, domains[syms.index(sym)])
  1884. if isinstance(sol, FiniteSet):
  1885. i = syms.index(sym)
  1886. symsp = syms[:i] + syms[i+1:]
  1887. domainsp = domains[:i] + domains[i+1:]
  1888. eqsp = eqs[:n] + eqs[n+1:]
  1889. for s in sol:
  1890. eqsp_sub = [eq.subs(sym, s) for eq in eqsp]
  1891. sol_others = _solveset_multi(eqsp_sub, symsp, domainsp)
  1892. fun = Lambda((symsp,), symsp[:i] + (s,) + symsp[i:])
  1893. sols.append(ImageSet(fun, sol_others).doit())
  1894. else:
  1895. all_handled = False
  1896. if all_handled:
  1897. return Union(*sols)
  1898. def solvify(f, symbol, domain):
  1899. """Solves an equation using solveset and returns the solution in accordance
  1900. with the `solve` output API.
  1901. Returns
  1902. =======
  1903. We classify the output based on the type of solution returned by `solveset`.
  1904. Solution | Output
  1905. ----------------------------------------
  1906. FiniteSet | list
  1907. ImageSet, | list (if `f` is periodic)
  1908. Union |
  1909. Union | list (with FiniteSet)
  1910. EmptySet | empty list
  1911. Others | None
  1912. Raises
  1913. ======
  1914. NotImplementedError
  1915. A ConditionSet is the input.
  1916. Examples
  1917. ========
  1918. >>> from sympy.solvers.solveset import solvify
  1919. >>> from sympy.abc import x
  1920. >>> from sympy import S, tan, sin, exp
  1921. >>> solvify(x**2 - 9, x, S.Reals)
  1922. [-3, 3]
  1923. >>> solvify(sin(x) - 1, x, S.Reals)
  1924. [pi/2]
  1925. >>> solvify(tan(x), x, S.Reals)
  1926. [0]
  1927. >>> solvify(exp(x) - 1, x, S.Complexes)
  1928. >>> solvify(exp(x) - 1, x, S.Reals)
  1929. [0]
  1930. """
  1931. solution_set = solveset(f, symbol, domain)
  1932. result = None
  1933. if solution_set is S.EmptySet:
  1934. result = []
  1935. elif isinstance(solution_set, ConditionSet):
  1936. raise NotImplementedError('solveset is unable to solve this equation.')
  1937. elif isinstance(solution_set, FiniteSet):
  1938. result = list(solution_set)
  1939. else:
  1940. period = periodicity(f, symbol)
  1941. if period is not None:
  1942. solutions = S.EmptySet
  1943. iter_solutions = ()
  1944. if isinstance(solution_set, ImageSet):
  1945. iter_solutions = (solution_set,)
  1946. elif isinstance(solution_set, Union):
  1947. if all(isinstance(i, ImageSet) for i in solution_set.args):
  1948. iter_solutions = solution_set.args
  1949. for solution in iter_solutions:
  1950. solutions += solution.intersect(Interval(0, period, False, True))
  1951. if isinstance(solutions, FiniteSet):
  1952. result = list(solutions)
  1953. else:
  1954. solution = solution_set.intersect(domain)
  1955. if isinstance(solution, Union):
  1956. # concerned about only FiniteSet with Union but not about ImageSet
  1957. # if required could be extend
  1958. if any(isinstance(i, FiniteSet) for i in solution.args):
  1959. result = [sol for soln in solution.args \
  1960. for sol in soln.args if isinstance(soln,FiniteSet)]
  1961. else:
  1962. return None
  1963. elif isinstance(solution, FiniteSet):
  1964. result += solution
  1965. return result
  1966. ###############################################################################
  1967. ################################ LINSOLVE #####################################
  1968. ###############################################################################
  1969. def linear_coeffs(eq, *syms, dict=False):
  1970. """Return a list whose elements are the coefficients of the
  1971. corresponding symbols in the sum of terms in ``eq``.
  1972. The additive constant is returned as the last element of the
  1973. list.
  1974. Raises
  1975. ======
  1976. NonlinearError
  1977. The equation contains a nonlinear term
  1978. ValueError
  1979. duplicate or unordered symbols are passed
  1980. Parameters
  1981. ==========
  1982. dict - (default False) when True, return coefficients as a
  1983. dictionary with coefficients keyed to syms that were present;
  1984. key 1 gives the constant term
  1985. Examples
  1986. ========
  1987. >>> from sympy.solvers.solveset import linear_coeffs
  1988. >>> from sympy.abc import x, y, z
  1989. >>> linear_coeffs(3*x + 2*y - 1, x, y)
  1990. [3, 2, -1]
  1991. It is not necessary to expand the expression:
  1992. >>> linear_coeffs(x + y*(z*(x*3 + 2) + 3), x)
  1993. [3*y*z + 1, y*(2*z + 3)]
  1994. When nonlinear is detected, an error will be raised:
  1995. * even if they would cancel after expansion (so the
  1996. situation does not pass silently past the caller's
  1997. attention)
  1998. >>> eq = 1/x*(x - 1) + 1/x
  1999. >>> linear_coeffs(eq.expand(), x)
  2000. [0, 1]
  2001. >>> linear_coeffs(eq, x)
  2002. Traceback (most recent call last):
  2003. ...
  2004. NonlinearError:
  2005. nonlinear in given generators
  2006. * when there are cross terms
  2007. >>> linear_coeffs(x*(y + 1), x, y)
  2008. Traceback (most recent call last):
  2009. ...
  2010. NonlinearError:
  2011. symbol-dependent cross-terms encountered
  2012. * when there are terms that contain an expression
  2013. dependent on the symbols that is not linear
  2014. >>> linear_coeffs(x**2, x)
  2015. Traceback (most recent call last):
  2016. ...
  2017. NonlinearError:
  2018. nonlinear in given generators
  2019. """
  2020. eq = _sympify(eq)
  2021. if len(syms) == 1 and iterable(syms[0]) and not isinstance(syms[0], Basic):
  2022. raise ValueError('expecting unpacked symbols, *syms')
  2023. symset = set(syms)
  2024. if len(symset) != len(syms):
  2025. raise ValueError('duplicate symbols given')
  2026. try:
  2027. d, c = _linear_eq_to_dict([eq], symset)
  2028. d = d[0]
  2029. c = c[0]
  2030. except PolyNonlinearError as err:
  2031. raise NonlinearError(str(err))
  2032. if dict:
  2033. if c:
  2034. d[S.One] = c
  2035. return d
  2036. rv = [S.Zero]*(len(syms) + 1)
  2037. rv[-1] = c
  2038. for i, k in enumerate(syms):
  2039. if k not in d:
  2040. continue
  2041. rv[i] = d[k]
  2042. return rv
  2043. def linear_eq_to_matrix(equations, *symbols):
  2044. r"""
  2045. Converts a given System of Equations into Matrix form.
  2046. Here `equations` must be a linear system of equations in
  2047. `symbols`. Element ``M[i, j]`` corresponds to the coefficient
  2048. of the jth symbol in the ith equation.
  2049. The Matrix form corresponds to the augmented matrix form.
  2050. For example:
  2051. .. math:: 4x + 2y + 3z = 1
  2052. .. math:: 3x + y + z = -6
  2053. .. math:: 2x + 4y + 9z = 2
  2054. This system will return $A$ and $b$ as:
  2055. $$ A = \left[\begin{array}{ccc}
  2056. 4 & 2 & 3 \\
  2057. 3 & 1 & 1 \\
  2058. 2 & 4 & 9
  2059. \end{array}\right] \ \ b = \left[\begin{array}{c}
  2060. 1 \\ -6 \\ 2
  2061. \end{array}\right] $$
  2062. The only simplification performed is to convert
  2063. ``Eq(a, b)`` $\Rightarrow a - b$.
  2064. Raises
  2065. ======
  2066. NonlinearError
  2067. The equations contain a nonlinear term.
  2068. ValueError
  2069. The symbols are not given or are not unique.
  2070. Examples
  2071. ========
  2072. >>> from sympy import linear_eq_to_matrix, symbols
  2073. >>> c, x, y, z = symbols('c, x, y, z')
  2074. The coefficients (numerical or symbolic) of the symbols will
  2075. be returned as matrices:
  2076. >>> eqns = [c*x + z - 1 - c, y + z, x - y]
  2077. >>> A, b = linear_eq_to_matrix(eqns, [x, y, z])
  2078. >>> A
  2079. Matrix([
  2080. [c, 0, 1],
  2081. [0, 1, 1],
  2082. [1, -1, 0]])
  2083. >>> b
  2084. Matrix([
  2085. [c + 1],
  2086. [ 0],
  2087. [ 0]])
  2088. This routine does not simplify expressions and will raise an error
  2089. if nonlinearity is encountered:
  2090. >>> eqns = [
  2091. ... (x**2 - 3*x)/(x - 3) - 3,
  2092. ... y**2 - 3*y - y*(y - 4) + x - 4]
  2093. >>> linear_eq_to_matrix(eqns, [x, y])
  2094. Traceback (most recent call last):
  2095. ...
  2096. NonlinearError:
  2097. symbol-dependent term can be ignored using `strict=False`
  2098. Simplifying these equations will discard the removable singularity
  2099. in the first and reveal the linear structure of the second:
  2100. >>> [e.simplify() for e in eqns]
  2101. [x - 3, x + y - 4]
  2102. Any such simplification needed to eliminate nonlinear terms must
  2103. be done *before* calling this routine.
  2104. """
  2105. if not symbols:
  2106. raise ValueError(filldedent('''
  2107. Symbols must be given, for which coefficients
  2108. are to be found.
  2109. '''))
  2110. if hasattr(symbols[0], '__iter__'):
  2111. symbols = symbols[0]
  2112. if has_dups(symbols):
  2113. raise ValueError('Symbols must be unique')
  2114. equations = sympify(equations)
  2115. if isinstance(equations, MatrixBase):
  2116. equations = list(equations)
  2117. elif isinstance(equations, (Expr, Eq)):
  2118. equations = [equations]
  2119. elif not is_sequence(equations):
  2120. raise ValueError(filldedent('''
  2121. Equation(s) must be given as a sequence, Expr,
  2122. Eq or Matrix.
  2123. '''))
  2124. # construct the dictionaries
  2125. try:
  2126. eq, c = _linear_eq_to_dict(equations, symbols)
  2127. except PolyNonlinearError as err:
  2128. raise NonlinearError(str(err))
  2129. # prepare output matrices
  2130. n, m = shape = len(eq), len(symbols)
  2131. ix = dict(zip(symbols, range(m)))
  2132. A = zeros(*shape)
  2133. for row, d in enumerate(eq):
  2134. for k in d:
  2135. col = ix[k]
  2136. A[row, col] = d[k]
  2137. b = Matrix(n, 1, [-i for i in c])
  2138. return A, b
  2139. def linsolve(system, *symbols):
  2140. r"""
  2141. Solve system of $N$ linear equations with $M$ variables; both
  2142. underdetermined and overdetermined systems are supported.
  2143. The possible number of solutions is zero, one or infinite.
  2144. Zero solutions throws a ValueError, whereas infinite
  2145. solutions are represented parametrically in terms of the given
  2146. symbols. For unique solution a :class:`~.FiniteSet` of ordered tuples
  2147. is returned.
  2148. All standard input formats are supported:
  2149. For the given set of equations, the respective input types
  2150. are given below:
  2151. .. math:: 3x + 2y - z = 1
  2152. .. math:: 2x - 2y + 4z = -2
  2153. .. math:: 2x - y + 2z = 0
  2154. * Augmented matrix form, ``system`` given below:
  2155. $$ \text{system} = \left[{array}{cccc}
  2156. 3 & 2 & -1 & 1\\
  2157. 2 & -2 & 4 & -2\\
  2158. 2 & -1 & 2 & 0
  2159. \end{array}\right] $$
  2160. ::
  2161. system = Matrix([[3, 2, -1, 1], [2, -2, 4, -2], [2, -1, 2, 0]])
  2162. * List of equations form
  2163. ::
  2164. system = [3x + 2y - z - 1, 2x - 2y + 4z + 2, 2x - y + 2z]
  2165. * Input $A$ and $b$ in matrix form (from $Ax = b$) are given as:
  2166. $$ A = \left[\begin{array}{ccc}
  2167. 3 & 2 & -1 \\
  2168. 2 & -2 & 4 \\
  2169. 2 & -1 & 2
  2170. \end{array}\right] \ \ b = \left[\begin{array}{c}
  2171. 1 \\ -2 \\ 0
  2172. \end{array}\right] $$
  2173. ::
  2174. A = Matrix([[3, 2, -1], [2, -2, 4], [2, -1, 2]])
  2175. b = Matrix([[1], [-2], [0]])
  2176. system = (A, b)
  2177. Symbols can always be passed but are actually only needed
  2178. when 1) a system of equations is being passed and 2) the
  2179. system is passed as an underdetermined matrix and one wants
  2180. to control the name of the free variables in the result.
  2181. An error is raised if no symbols are used for case 1, but if
  2182. no symbols are provided for case 2, internally generated symbols
  2183. will be provided. When providing symbols for case 2, there should
  2184. be at least as many symbols are there are columns in matrix A.
  2185. The algorithm used here is Gauss-Jordan elimination, which
  2186. results, after elimination, in a row echelon form matrix.
  2187. Returns
  2188. =======
  2189. A FiniteSet containing an ordered tuple of values for the
  2190. unknowns for which the `system` has a solution. (Wrapping
  2191. the tuple in FiniteSet is used to maintain a consistent
  2192. output format throughout solveset.)
  2193. Returns EmptySet, if the linear system is inconsistent.
  2194. Raises
  2195. ======
  2196. ValueError
  2197. The input is not valid.
  2198. The symbols are not given.
  2199. Examples
  2200. ========
  2201. >>> from sympy import Matrix, linsolve, symbols
  2202. >>> x, y, z = symbols("x, y, z")
  2203. >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 10]])
  2204. >>> b = Matrix([3, 6, 9])
  2205. >>> A
  2206. Matrix([
  2207. [1, 2, 3],
  2208. [4, 5, 6],
  2209. [7, 8, 10]])
  2210. >>> b
  2211. Matrix([
  2212. [3],
  2213. [6],
  2214. [9]])
  2215. >>> linsolve((A, b), [x, y, z])
  2216. {(-1, 2, 0)}
  2217. * Parametric Solution: In case the system is underdetermined, the
  2218. function will return a parametric solution in terms of the given
  2219. symbols. Those that are free will be returned unchanged. e.g. in
  2220. the system below, `z` is returned as the solution for variable z;
  2221. it can take on any value.
  2222. >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  2223. >>> b = Matrix([3, 6, 9])
  2224. >>> linsolve((A, b), x, y, z)
  2225. {(z - 1, 2 - 2*z, z)}
  2226. If no symbols are given, internally generated symbols will be used.
  2227. The ``tau0`` in the third position indicates (as before) that the third
  2228. variable -- whatever it is named -- can take on any value:
  2229. >>> linsolve((A, b))
  2230. {(tau0 - 1, 2 - 2*tau0, tau0)}
  2231. * List of equations as input
  2232. >>> Eqns = [3*x + 2*y - z - 1, 2*x - 2*y + 4*z + 2, - x + y/2 - z]
  2233. >>> linsolve(Eqns, x, y, z)
  2234. {(1, -2, -2)}
  2235. * Augmented matrix as input
  2236. >>> aug = Matrix([[2, 1, 3, 1], [2, 6, 8, 3], [6, 8, 18, 5]])
  2237. >>> aug
  2238. Matrix([
  2239. [2, 1, 3, 1],
  2240. [2, 6, 8, 3],
  2241. [6, 8, 18, 5]])
  2242. >>> linsolve(aug, x, y, z)
  2243. {(3/10, 2/5, 0)}
  2244. * Solve for symbolic coefficients
  2245. >>> a, b, c, d, e, f = symbols('a, b, c, d, e, f')
  2246. >>> eqns = [a*x + b*y - c, d*x + e*y - f]
  2247. >>> linsolve(eqns, x, y)
  2248. {((-b*f + c*e)/(a*e - b*d), (a*f - c*d)/(a*e - b*d))}
  2249. * A degenerate system returns solution as set of given
  2250. symbols.
  2251. >>> system = Matrix(([0, 0, 0], [0, 0, 0], [0, 0, 0]))
  2252. >>> linsolve(system, x, y)
  2253. {(x, y)}
  2254. * For an empty system linsolve returns empty set
  2255. >>> linsolve([], x)
  2256. EmptySet
  2257. * An error is raised if any nonlinearity is detected, even
  2258. if it could be removed with expansion
  2259. >>> linsolve([x*(1/x - 1)], x)
  2260. Traceback (most recent call last):
  2261. ...
  2262. NonlinearError: nonlinear term: 1/x
  2263. >>> linsolve([x*(y + 1)], x, y)
  2264. Traceback (most recent call last):
  2265. ...
  2266. NonlinearError: nonlinear cross-term: x*(y + 1)
  2267. >>> linsolve([x**2 - 1], x)
  2268. Traceback (most recent call last):
  2269. ...
  2270. NonlinearError: nonlinear term: x**2
  2271. """
  2272. if not system:
  2273. return S.EmptySet
  2274. # If second argument is an iterable
  2275. if symbols and hasattr(symbols[0], '__iter__'):
  2276. symbols = symbols[0]
  2277. sym_gen = isinstance(symbols, GeneratorType)
  2278. dup_msg = 'duplicate symbols given'
  2279. b = None # if we don't get b the input was bad
  2280. # unpack system
  2281. if hasattr(system, '__iter__'):
  2282. # 1). (A, b)
  2283. if len(system) == 2 and isinstance(system[0], MatrixBase):
  2284. A, b = system
  2285. # 2). (eq1, eq2, ...)
  2286. if not isinstance(system[0], MatrixBase):
  2287. if sym_gen or not symbols:
  2288. raise ValueError(filldedent('''
  2289. When passing a system of equations, the explicit
  2290. symbols for which a solution is being sought must
  2291. be given as a sequence, too.
  2292. '''))
  2293. if len(set(symbols)) != len(symbols):
  2294. raise ValueError(dup_msg)
  2295. #
  2296. # Pass to the sparse solver implemented in polys. It is important
  2297. # that we do not attempt to convert the equations to a matrix
  2298. # because that would be very inefficient for large sparse systems
  2299. # of equations.
  2300. #
  2301. eqs = system
  2302. eqs = [sympify(eq) for eq in eqs]
  2303. try:
  2304. sol = _linsolve(eqs, symbols)
  2305. except PolyNonlinearError as exc:
  2306. # e.g. cos(x) contains an element of the set of generators
  2307. raise NonlinearError(str(exc))
  2308. if sol is None:
  2309. return S.EmptySet
  2310. sol = FiniteSet(Tuple(*(sol.get(sym, sym) for sym in symbols)))
  2311. return sol
  2312. elif isinstance(system, MatrixBase) and not (
  2313. symbols and not isinstance(symbols, GeneratorType) and
  2314. isinstance(symbols[0], MatrixBase)):
  2315. # 3). A augmented with b
  2316. A, b = system[:, :-1], system[:, -1:]
  2317. if b is None:
  2318. raise ValueError("Invalid arguments")
  2319. if sym_gen:
  2320. symbols = [next(symbols) for i in range(A.cols)]
  2321. symset = set(symbols)
  2322. if any(symset & (A.free_symbols | b.free_symbols)):
  2323. raise ValueError(filldedent('''
  2324. At least one of the symbols provided
  2325. already appears in the system to be solved.
  2326. One way to avoid this is to use Dummy symbols in
  2327. the generator, e.g. numbered_symbols('%s', cls=Dummy)
  2328. ''' % symbols[0].name.rstrip('1234567890')))
  2329. elif len(symset) != len(symbols):
  2330. raise ValueError(dup_msg)
  2331. if not symbols:
  2332. symbols = [Dummy() for _ in range(A.cols)]
  2333. name = _uniquely_named_symbol('tau', (A, b),
  2334. compare=lambda i: str(i).rstrip('1234567890')).name
  2335. gen = numbered_symbols(name)
  2336. else:
  2337. gen = None
  2338. # This is just a wrapper for solve_lin_sys
  2339. eqs = []
  2340. rows = A.tolist()
  2341. for rowi, bi in zip(rows, b):
  2342. terms = [elem * sym for elem, sym in zip(rowi, symbols) if elem]
  2343. terms.append(-bi)
  2344. eqs.append(Add(*terms))
  2345. eqs, ring = sympy_eqs_to_ring(eqs, symbols)
  2346. sol = solve_lin_sys(eqs, ring, _raw=False)
  2347. if sol is None:
  2348. return S.EmptySet
  2349. #sol = {sym:val for sym, val in sol.items() if sym != val}
  2350. sol = FiniteSet(Tuple(*(sol.get(sym, sym) for sym in symbols)))
  2351. if gen is not None:
  2352. solsym = sol.free_symbols
  2353. rep = {sym: next(gen) for sym in symbols if sym in solsym}
  2354. sol = sol.subs(rep)
  2355. return sol
  2356. ##############################################################################
  2357. # ------------------------------nonlinsolve ---------------------------------#
  2358. ##############################################################################
  2359. def _return_conditionset(eqs, symbols):
  2360. # return conditionset
  2361. eqs = (Eq(lhs, 0) for lhs in eqs)
  2362. condition_set = ConditionSet(
  2363. Tuple(*symbols), And(*eqs), S.Complexes**len(symbols))
  2364. return condition_set
  2365. def substitution(system, symbols, result=[{}], known_symbols=[],
  2366. exclude=[], all_symbols=None):
  2367. r"""
  2368. Solves the `system` using substitution method. It is used in
  2369. :func:`~.nonlinsolve`. This will be called from :func:`~.nonlinsolve` when any
  2370. equation(s) is non polynomial equation.
  2371. Parameters
  2372. ==========
  2373. system : list of equations
  2374. The target system of equations
  2375. symbols : list of symbols to be solved.
  2376. The variable(s) for which the system is solved
  2377. known_symbols : list of solved symbols
  2378. Values are known for these variable(s)
  2379. result : An empty list or list of dict
  2380. If No symbol values is known then empty list otherwise
  2381. symbol as keys and corresponding value in dict.
  2382. exclude : Set of expression.
  2383. Mostly denominator expression(s) of the equations of the system.
  2384. Final solution should not satisfy these expressions.
  2385. all_symbols : known_symbols + symbols(unsolved).
  2386. Returns
  2387. =======
  2388. A FiniteSet of ordered tuple of values of `all_symbols` for which the
  2389. `system` has solution. Order of values in the tuple is same as symbols
  2390. present in the parameter `all_symbols`. If parameter `all_symbols` is None
  2391. then same as symbols present in the parameter `symbols`.
  2392. Please note that general FiniteSet is unordered, the solution returned
  2393. here is not simply a FiniteSet of solutions, rather it is a FiniteSet of
  2394. ordered tuple, i.e. the first & only argument to FiniteSet is a tuple of
  2395. solutions, which is ordered, & hence the returned solution is ordered.
  2396. Also note that solution could also have been returned as an ordered tuple,
  2397. FiniteSet is just a wrapper `{}` around the tuple. It has no other
  2398. significance except for the fact it is just used to maintain a consistent
  2399. output format throughout the solveset.
  2400. Raises
  2401. ======
  2402. ValueError
  2403. The input is not valid.
  2404. The symbols are not given.
  2405. AttributeError
  2406. The input symbols are not :class:`~.Symbol` type.
  2407. Examples
  2408. ========
  2409. >>> from sympy import symbols, substitution
  2410. >>> x, y = symbols('x, y', real=True)
  2411. >>> substitution([x + y], [x], [{y: 1}], [y], set([]), [x, y])
  2412. {(-1, 1)}
  2413. * When you want a soln not satisfying $x + 1 = 0$
  2414. >>> substitution([x + y], [x], [{y: 1}], [y], set([x + 1]), [y, x])
  2415. EmptySet
  2416. >>> substitution([x + y], [x], [{y: 1}], [y], set([x - 1]), [y, x])
  2417. {(1, -1)}
  2418. >>> substitution([x + y - 1, y - x**2 + 5], [x, y])
  2419. {(-3, 4), (2, -1)}
  2420. * Returns both real and complex solution
  2421. >>> x, y, z = symbols('x, y, z')
  2422. >>> from sympy import exp, sin
  2423. >>> substitution([exp(x) - sin(y), y**2 - 4], [x, y])
  2424. {(ImageSet(Lambda(_n, I*(2*_n*pi + pi) + log(sin(2))), Integers), -2),
  2425. (ImageSet(Lambda(_n, 2*_n*I*pi + log(sin(2))), Integers), 2)}
  2426. >>> eqs = [z**2 + exp(2*x) - sin(y), -3 + exp(-y)]
  2427. >>> substitution(eqs, [y, z])
  2428. {(-log(3), -sqrt(-exp(2*x) - sin(log(3)))),
  2429. (-log(3), sqrt(-exp(2*x) - sin(log(3)))),
  2430. (ImageSet(Lambda(_n, 2*_n*I*pi - log(3)), Integers),
  2431. ImageSet(Lambda(_n, -sqrt(-exp(2*x) + sin(2*_n*I*pi - log(3)))), Integers)),
  2432. (ImageSet(Lambda(_n, 2*_n*I*pi - log(3)), Integers),
  2433. ImageSet(Lambda(_n, sqrt(-exp(2*x) + sin(2*_n*I*pi - log(3)))), Integers))}
  2434. """
  2435. if not system:
  2436. return S.EmptySet
  2437. if not symbols:
  2438. msg = ('Symbols must be given, for which solution of the '
  2439. 'system is to be found.')
  2440. raise ValueError(filldedent(msg))
  2441. if not is_sequence(symbols):
  2442. msg = ('symbols should be given as a sequence, e.g. a list.'
  2443. 'Not type %s: %s')
  2444. raise TypeError(filldedent(msg % (type(symbols), symbols)))
  2445. if not getattr(symbols[0], 'is_Symbol', False):
  2446. msg = ('Iterable of symbols must be given as '
  2447. 'second argument, not type %s: %s')
  2448. raise ValueError(filldedent(msg % (type(symbols[0]), symbols[0])))
  2449. # By default `all_symbols` will be same as `symbols`
  2450. if all_symbols is None:
  2451. all_symbols = symbols
  2452. old_result = result
  2453. # storing complements and intersection for particular symbol
  2454. complements = {}
  2455. intersections = {}
  2456. # when total_solveset_call equals total_conditionset
  2457. # it means that solveset failed to solve all eqs.
  2458. total_conditionset = -1
  2459. total_solveset_call = -1
  2460. def _unsolved_syms(eq, sort=False):
  2461. """Returns the unsolved symbol present
  2462. in the equation `eq`.
  2463. """
  2464. free = eq.free_symbols
  2465. unsolved = (free - set(known_symbols)) & set(all_symbols)
  2466. if sort:
  2467. unsolved = list(unsolved)
  2468. unsolved.sort(key=default_sort_key)
  2469. return unsolved
  2470. # end of _unsolved_syms()
  2471. # sort such that equation with the fewest potential symbols is first.
  2472. # means eq with less number of variable first in the list.
  2473. eqs_in_better_order = list(
  2474. ordered(system, lambda _: len(_unsolved_syms(_))))
  2475. def add_intersection_complement(result, intersection_dict, complement_dict):
  2476. # If solveset has returned some intersection/complement
  2477. # for any symbol, it will be added in the final solution.
  2478. final_result = []
  2479. for res in result:
  2480. res_copy = res
  2481. for key_res, value_res in res.items():
  2482. intersect_set, complement_set = None, None
  2483. for key_sym, value_sym in intersection_dict.items():
  2484. if key_sym == key_res:
  2485. intersect_set = value_sym
  2486. for key_sym, value_sym in complement_dict.items():
  2487. if key_sym == key_res:
  2488. complement_set = value_sym
  2489. if intersect_set or complement_set:
  2490. new_value = FiniteSet(value_res)
  2491. if intersect_set and intersect_set != S.Complexes:
  2492. new_value = Intersection(new_value, intersect_set)
  2493. if complement_set:
  2494. new_value = Complement(new_value, complement_set)
  2495. if new_value is S.EmptySet:
  2496. res_copy = None
  2497. break
  2498. elif new_value.is_FiniteSet and len(new_value) == 1:
  2499. res_copy[key_res] = set(new_value).pop()
  2500. else:
  2501. res_copy[key_res] = new_value
  2502. if res_copy is not None:
  2503. final_result.append(res_copy)
  2504. return final_result
  2505. # end of def add_intersection_complement()
  2506. def _extract_main_soln(sym, sol, soln_imageset):
  2507. """Separate the Complements, Intersections, ImageSet lambda expr and
  2508. its base_set. This function returns the unmasks sol from different classes
  2509. of sets and also returns the appended ImageSet elements in a
  2510. soln_imageset (dict: where key as unmasked element and value as ImageSet).
  2511. """
  2512. # if there is union, then need to check
  2513. # Complement, Intersection, Imageset.
  2514. # Order should not be changed.
  2515. if isinstance(sol, ConditionSet):
  2516. # extracts any solution in ConditionSet
  2517. sol = sol.base_set
  2518. if isinstance(sol, Complement):
  2519. # extract solution and complement
  2520. complements[sym] = sol.args[1]
  2521. sol = sol.args[0]
  2522. # complement will be added at the end
  2523. # using `add_intersection_complement` method
  2524. # if there is union of Imageset or other in soln.
  2525. # no testcase is written for this if block
  2526. if isinstance(sol, Union):
  2527. sol_args = sol.args
  2528. sol = S.EmptySet
  2529. # We need in sequence so append finteset elements
  2530. # and then imageset or other.
  2531. for sol_arg2 in sol_args:
  2532. if isinstance(sol_arg2, FiniteSet):
  2533. sol += sol_arg2
  2534. else:
  2535. # ImageSet, Intersection, complement then
  2536. # append them directly
  2537. sol += FiniteSet(sol_arg2)
  2538. if isinstance(sol, Intersection):
  2539. # Interval/Set will be at 0th index always
  2540. if sol.args[0] not in (S.Reals, S.Complexes):
  2541. # Sometimes solveset returns soln with intersection
  2542. # S.Reals or S.Complexes. We don't consider that
  2543. # intersection.
  2544. intersections[sym] = sol.args[0]
  2545. sol = sol.args[1]
  2546. # after intersection and complement Imageset should
  2547. # be checked.
  2548. if isinstance(sol, ImageSet):
  2549. soln_imagest = sol
  2550. expr2 = sol.lamda.expr
  2551. sol = FiniteSet(expr2)
  2552. soln_imageset[expr2] = soln_imagest
  2553. if not isinstance(sol, FiniteSet):
  2554. sol = FiniteSet(sol)
  2555. return sol, soln_imageset
  2556. # end of def _extract_main_soln()
  2557. # helper function for _append_new_soln
  2558. def _check_exclude(rnew, imgset_yes):
  2559. rnew_ = rnew
  2560. if imgset_yes:
  2561. # replace all dummy variables (Imageset lambda variables)
  2562. # with zero before `checksol`. Considering fundamental soln
  2563. # for `checksol`.
  2564. rnew_copy = rnew.copy()
  2565. dummy_n = imgset_yes[0]
  2566. for key_res, value_res in rnew_copy.items():
  2567. rnew_copy[key_res] = value_res.subs(dummy_n, 0)
  2568. rnew_ = rnew_copy
  2569. # satisfy_exclude == true if it satisfies the expr of `exclude` list.
  2570. try:
  2571. # something like : `Mod(-log(3), 2*I*pi)` can't be
  2572. # simplified right now, so `checksol` returns `TypeError`.
  2573. # when this issue is fixed this try block should be
  2574. # removed. Mod(-log(3), 2*I*pi) == -log(3)
  2575. satisfy_exclude = any(
  2576. checksol(d, rnew_) for d in exclude)
  2577. except TypeError:
  2578. satisfy_exclude = None
  2579. return satisfy_exclude
  2580. # end of def _check_exclude()
  2581. # helper function for _append_new_soln
  2582. def _restore_imgset(rnew, original_imageset, newresult):
  2583. restore_sym = set(rnew.keys()) & \
  2584. set(original_imageset.keys())
  2585. for key_sym in restore_sym:
  2586. img = original_imageset[key_sym]
  2587. rnew[key_sym] = img
  2588. if rnew not in newresult:
  2589. newresult.append(rnew)
  2590. # end of def _restore_imgset()
  2591. def _append_eq(eq, result, res, delete_soln, n=None):
  2592. u = Dummy('u')
  2593. if n:
  2594. eq = eq.subs(n, 0)
  2595. satisfy = eq if eq in (True, False) else checksol(u, u, eq, minimal=True)
  2596. if satisfy is False:
  2597. delete_soln = True
  2598. res = {}
  2599. else:
  2600. result.append(res)
  2601. return result, res, delete_soln
  2602. def _append_new_soln(rnew, sym, sol, imgset_yes, soln_imageset,
  2603. original_imageset, newresult, eq=None):
  2604. """If `rnew` (A dict <symbol: soln>) contains valid soln
  2605. append it to `newresult` list.
  2606. `imgset_yes` is (base, dummy_var) if there was imageset in previously
  2607. calculated result(otherwise empty tuple). `original_imageset` is dict
  2608. of imageset expr and imageset from this result.
  2609. `soln_imageset` dict of imageset expr and imageset of new soln.
  2610. """
  2611. satisfy_exclude = _check_exclude(rnew, imgset_yes)
  2612. delete_soln = False
  2613. # soln should not satisfy expr present in `exclude` list.
  2614. if not satisfy_exclude:
  2615. local_n = None
  2616. # if it is imageset
  2617. if imgset_yes:
  2618. local_n = imgset_yes[0]
  2619. base = imgset_yes[1]
  2620. if sym and sol:
  2621. # when `sym` and `sol` is `None` means no new
  2622. # soln. In that case we will append rnew directly after
  2623. # substituting original imagesets in rnew values if present
  2624. # (second last line of this function using _restore_imgset)
  2625. dummy_list = list(sol.atoms(Dummy))
  2626. # use one dummy `n` which is in
  2627. # previous imageset
  2628. local_n_list = [
  2629. local_n for i in range(
  2630. 0, len(dummy_list))]
  2631. dummy_zip = zip(dummy_list, local_n_list)
  2632. lam = Lambda(local_n, sol.subs(dummy_zip))
  2633. rnew[sym] = ImageSet(lam, base)
  2634. if eq is not None:
  2635. newresult, rnew, delete_soln = _append_eq(
  2636. eq, newresult, rnew, delete_soln, local_n)
  2637. elif eq is not None:
  2638. newresult, rnew, delete_soln = _append_eq(
  2639. eq, newresult, rnew, delete_soln)
  2640. elif sol in soln_imageset.keys():
  2641. rnew[sym] = soln_imageset[sol]
  2642. # restore original imageset
  2643. _restore_imgset(rnew, original_imageset, newresult)
  2644. else:
  2645. newresult.append(rnew)
  2646. elif satisfy_exclude:
  2647. delete_soln = True
  2648. rnew = {}
  2649. _restore_imgset(rnew, original_imageset, newresult)
  2650. return newresult, delete_soln
  2651. # end of def _append_new_soln()
  2652. def _new_order_result(result, eq):
  2653. # separate first, second priority. `res` that makes `eq` value equals
  2654. # to zero, should be used first then other result(second priority).
  2655. # If it is not done then we may miss some soln.
  2656. first_priority = []
  2657. second_priority = []
  2658. for res in result:
  2659. if not any(isinstance(val, ImageSet) for val in res.values()):
  2660. if eq.subs(res) == 0:
  2661. first_priority.append(res)
  2662. else:
  2663. second_priority.append(res)
  2664. if first_priority or second_priority:
  2665. return first_priority + second_priority
  2666. return result
  2667. def _solve_using_known_values(result, solver):
  2668. """Solves the system using already known solution
  2669. (result contains the dict <symbol: value>).
  2670. solver is :func:`~.solveset_complex` or :func:`~.solveset_real`.
  2671. """
  2672. # stores imageset <expr: imageset(Lambda(n, expr), base)>.
  2673. soln_imageset = {}
  2674. total_solvest_call = 0
  2675. total_conditionst = 0
  2676. # sort such that equation with the fewest potential symbols is first.
  2677. # means eq with less variable first
  2678. for index, eq in enumerate(eqs_in_better_order):
  2679. newresult = []
  2680. original_imageset = {}
  2681. # if imageset expr is used to solve other symbol
  2682. imgset_yes = False
  2683. result = _new_order_result(result, eq)
  2684. for res in result:
  2685. got_symbol = set() # symbols solved in one iteration
  2686. # find the imageset and use its expr.
  2687. for key_res, value_res in res.items():
  2688. if isinstance(value_res, ImageSet):
  2689. res[key_res] = value_res.lamda.expr
  2690. original_imageset[key_res] = value_res
  2691. dummy_n = value_res.lamda.expr.atoms(Dummy).pop()
  2692. (base,) = value_res.base_sets
  2693. imgset_yes = (dummy_n, base)
  2694. # update eq with everything that is known so far
  2695. eq2 = eq.subs(res).expand()
  2696. unsolved_syms = _unsolved_syms(eq2, sort=True)
  2697. if not unsolved_syms:
  2698. if res:
  2699. newresult, delete_res = _append_new_soln(
  2700. res, None, None, imgset_yes, soln_imageset,
  2701. original_imageset, newresult, eq2)
  2702. if delete_res:
  2703. # `delete_res` is true, means substituting `res` in
  2704. # eq2 doesn't return `zero` or deleting the `res`
  2705. # (a soln) since it staisfies expr of `exclude`
  2706. # list.
  2707. result.remove(res)
  2708. continue # skip as it's independent of desired symbols
  2709. depen1, depen2 = (eq2.rewrite(Add)).as_independent(*unsolved_syms)
  2710. if (depen1.has(Abs) or depen2.has(Abs)) and solver == solveset_complex:
  2711. # Absolute values cannot be inverted in the
  2712. # complex domain
  2713. continue
  2714. soln_imageset = {}
  2715. for sym in unsolved_syms:
  2716. not_solvable = False
  2717. try:
  2718. soln = solver(eq2, sym)
  2719. total_solvest_call += 1
  2720. soln_new = S.EmptySet
  2721. if isinstance(soln, Complement):
  2722. # separate solution and complement
  2723. complements[sym] = soln.args[1]
  2724. soln = soln.args[0]
  2725. # complement will be added at the end
  2726. if isinstance(soln, Intersection):
  2727. # Interval will be at 0th index always
  2728. if soln.args[0] != Interval(-oo, oo):
  2729. # sometimes solveset returns soln
  2730. # with intersection S.Reals, to confirm that
  2731. # soln is in domain=S.Reals
  2732. intersections[sym] = soln.args[0]
  2733. soln_new += soln.args[1]
  2734. soln = soln_new if soln_new else soln
  2735. if index > 0 and solver == solveset_real:
  2736. # one symbol's real soln, another symbol may have
  2737. # corresponding complex soln.
  2738. if not isinstance(soln, (ImageSet, ConditionSet)):
  2739. soln += solveset_complex(eq2, sym) # might give ValueError with Abs
  2740. except (NotImplementedError, ValueError):
  2741. # If solveset is not able to solve equation `eq2`. Next
  2742. # time we may get soln using next equation `eq2`
  2743. continue
  2744. if isinstance(soln, ConditionSet):
  2745. if soln.base_set in (S.Reals, S.Complexes):
  2746. soln = S.EmptySet
  2747. # don't do `continue` we may get soln
  2748. # in terms of other symbol(s)
  2749. not_solvable = True
  2750. total_conditionst += 1
  2751. else:
  2752. soln = soln.base_set
  2753. if soln is not S.EmptySet:
  2754. soln, soln_imageset = _extract_main_soln(
  2755. sym, soln, soln_imageset)
  2756. for sol in soln:
  2757. # sol is not a `Union` since we checked it
  2758. # before this loop
  2759. sol, soln_imageset = _extract_main_soln(
  2760. sym, sol, soln_imageset)
  2761. sol = set(sol).pop()
  2762. free = sol.free_symbols
  2763. if got_symbol and any(
  2764. ss in free for ss in got_symbol
  2765. ):
  2766. # sol depends on previously solved symbols
  2767. # then continue
  2768. continue
  2769. rnew = res.copy()
  2770. # put each solution in res and append the new result
  2771. # in the new result list (solution for symbol `s`)
  2772. # along with old results.
  2773. for k, v in res.items():
  2774. if isinstance(v, Expr) and isinstance(sol, Expr):
  2775. # if any unsolved symbol is present
  2776. # Then subs known value
  2777. rnew[k] = v.subs(sym, sol)
  2778. # and add this new solution
  2779. if sol in soln_imageset.keys():
  2780. # replace all lambda variables with 0.
  2781. imgst = soln_imageset[sol]
  2782. rnew[sym] = imgst.lamda(
  2783. *[0 for i in range(0, len(
  2784. imgst.lamda.variables))])
  2785. else:
  2786. rnew[sym] = sol
  2787. newresult, delete_res = _append_new_soln(
  2788. rnew, sym, sol, imgset_yes, soln_imageset,
  2789. original_imageset, newresult)
  2790. if delete_res:
  2791. # deleting the `res` (a soln) since it staisfies
  2792. # eq of `exclude` list
  2793. result.remove(res)
  2794. # solution got for sym
  2795. if not not_solvable:
  2796. got_symbol.add(sym)
  2797. # next time use this new soln
  2798. if newresult:
  2799. result = newresult
  2800. return result, total_solvest_call, total_conditionst
  2801. # end def _solve_using_know_values()
  2802. new_result_real, solve_call1, cnd_call1 = _solve_using_known_values(
  2803. old_result, solveset_real)
  2804. new_result_complex, solve_call2, cnd_call2 = _solve_using_known_values(
  2805. old_result, solveset_complex)
  2806. # If total_solveset_call is equal to total_conditionset
  2807. # then solveset failed to solve all of the equations.
  2808. # In this case we return a ConditionSet here.
  2809. total_conditionset += (cnd_call1 + cnd_call2)
  2810. total_solveset_call += (solve_call1 + solve_call2)
  2811. if total_conditionset == total_solveset_call and total_solveset_call != -1:
  2812. return _return_conditionset(eqs_in_better_order, all_symbols)
  2813. # don't keep duplicate solutions
  2814. filtered_complex = []
  2815. for i in list(new_result_complex):
  2816. for j in list(new_result_real):
  2817. if i.keys() != j.keys():
  2818. continue
  2819. if all(a.dummy_eq(b) for a, b in zip(i.values(), j.values()) \
  2820. if not (isinstance(a, int) and isinstance(b, int))):
  2821. break
  2822. else:
  2823. filtered_complex.append(i)
  2824. # overall result
  2825. result = new_result_real + filtered_complex
  2826. result_all_variables = []
  2827. result_infinite = []
  2828. for res in result:
  2829. if not res:
  2830. # means {None : None}
  2831. continue
  2832. # If length < len(all_symbols) means infinite soln.
  2833. # Some or all the soln is dependent on 1 symbol.
  2834. # eg. {x: y+2} then final soln {x: y+2, y: y}
  2835. if len(res) < len(all_symbols):
  2836. solved_symbols = res.keys()
  2837. unsolved = list(filter(
  2838. lambda x: x not in solved_symbols, all_symbols))
  2839. for unsolved_sym in unsolved:
  2840. res[unsolved_sym] = unsolved_sym
  2841. result_infinite.append(res)
  2842. if res not in result_all_variables:
  2843. result_all_variables.append(res)
  2844. if result_infinite:
  2845. # we have general soln
  2846. # eg : [{x: -1, y : 1}, {x : -y, y: y}] then
  2847. # return [{x : -y, y : y}]
  2848. result_all_variables = result_infinite
  2849. if intersections or complements:
  2850. result_all_variables = add_intersection_complement(
  2851. result_all_variables, intersections, complements)
  2852. # convert to ordered tuple
  2853. result = S.EmptySet
  2854. for r in result_all_variables:
  2855. temp = [r[symb] for symb in all_symbols]
  2856. result += FiniteSet(tuple(temp))
  2857. return result
  2858. # end of def substitution()
  2859. def _solveset_work(system, symbols):
  2860. soln = solveset(system[0], symbols[0])
  2861. if isinstance(soln, FiniteSet):
  2862. _soln = FiniteSet(*[(s,) for s in soln])
  2863. return _soln
  2864. else:
  2865. return FiniteSet(tuple(FiniteSet(soln)))
  2866. def _handle_positive_dimensional(polys, symbols, denominators):
  2867. from sympy.polys.polytools import groebner
  2868. # substitution method where new system is groebner basis of the system
  2869. _symbols = list(symbols)
  2870. _symbols.sort(key=default_sort_key)
  2871. basis = groebner(polys, _symbols, polys=True)
  2872. new_system = []
  2873. for poly_eq in basis:
  2874. new_system.append(poly_eq.as_expr())
  2875. result = [{}]
  2876. result = substitution(
  2877. new_system, symbols, result, [],
  2878. denominators)
  2879. return result
  2880. # end of def _handle_positive_dimensional()
  2881. def _handle_zero_dimensional(polys, symbols, system):
  2882. # solve 0 dimensional poly system using `solve_poly_system`
  2883. result = solve_poly_system(polys, *symbols)
  2884. # May be some extra soln is added because
  2885. # we used `unrad` in `_separate_poly_nonpoly`, so
  2886. # need to check and remove if it is not a soln.
  2887. result_update = S.EmptySet
  2888. for res in result:
  2889. dict_sym_value = dict(list(zip(symbols, res)))
  2890. if all(checksol(eq, dict_sym_value) for eq in system):
  2891. result_update += FiniteSet(res)
  2892. return result_update
  2893. # end of def _handle_zero_dimensional()
  2894. def _separate_poly_nonpoly(system, symbols):
  2895. polys = []
  2896. polys_expr = []
  2897. nonpolys = []
  2898. # unrad_changed stores a list of expressions containing
  2899. # radicals that were processed using unrad
  2900. # this is useful if solutions need to be checked later.
  2901. unrad_changed = []
  2902. denominators = set()
  2903. poly = None
  2904. for eq in system:
  2905. # Store denom expressions that contain symbols
  2906. denominators.update(_simple_dens(eq, symbols))
  2907. # Convert equality to expression
  2908. if isinstance(eq, Equality):
  2909. eq = eq.rewrite(Add)
  2910. # try to remove sqrt and rational power
  2911. without_radicals = unrad(simplify(eq), *symbols)
  2912. if without_radicals:
  2913. unrad_changed.append(eq)
  2914. eq_unrad, cov = without_radicals
  2915. if not cov:
  2916. eq = eq_unrad
  2917. if isinstance(eq, Expr):
  2918. eq = eq.as_numer_denom()[0]
  2919. poly = eq.as_poly(*symbols, extension=True)
  2920. elif simplify(eq).is_number:
  2921. continue
  2922. if poly is not None:
  2923. polys.append(poly)
  2924. polys_expr.append(poly.as_expr())
  2925. else:
  2926. nonpolys.append(eq)
  2927. return polys, polys_expr, nonpolys, denominators, unrad_changed
  2928. # end of def _separate_poly_nonpoly()
  2929. def _handle_poly(polys, symbols):
  2930. # _handle_poly(polys, symbols) -> (poly_sol, poly_eqs)
  2931. #
  2932. # We will return possible solution information to nonlinsolve as well as a
  2933. # new system of polynomial equations to be solved if we cannot solve
  2934. # everything directly here. The new system of polynomial equations will be
  2935. # a lex-order Groebner basis for the original system. The lex basis
  2936. # hopefully separate some of the variables and equations and give something
  2937. # easier for substitution to work with.
  2938. # The format for representing solution sets in nonlinsolve and substitution
  2939. # is a list of dicts. These are the special cases:
  2940. no_information = [{}] # No equations solved yet
  2941. no_solutions = [] # The system is inconsistent and has no solutions.
  2942. # If there is no need to attempt further solution of these equations then
  2943. # we return no equations:
  2944. no_equations = []
  2945. inexact = any(not p.domain.is_Exact for p in polys)
  2946. if inexact:
  2947. # The use of Groebner over RR is likely to result incorrectly in an
  2948. # inconsistent Groebner basis. So, convert any float coefficients to
  2949. # Rational before computing the Groebner basis.
  2950. polys = [poly(nsimplify(p, rational=True)) for p in polys]
  2951. # Compute a Groebner basis in grevlex order wrt the ordering given. We will
  2952. # try to convert this to lex order later. Usually it seems to be more
  2953. # efficient to compute a lex order basis by computing a grevlex basis and
  2954. # converting to lex with fglm.
  2955. basis = groebner(polys, symbols, order='grevlex', polys=False)
  2956. #
  2957. # No solutions (inconsistent equations)?
  2958. #
  2959. if 1 in basis:
  2960. # No solutions:
  2961. poly_sol = no_solutions
  2962. poly_eqs = no_equations
  2963. #
  2964. # Finite number of solutions (zero-dimensional case)
  2965. #
  2966. elif basis.is_zero_dimensional:
  2967. # Convert Groebner basis to lex ordering
  2968. basis = basis.fglm('lex')
  2969. # Convert polynomial coefficients back to float before calling
  2970. # solve_poly_system
  2971. if inexact:
  2972. basis = [nfloat(p) for p in basis]
  2973. # Solve the zero-dimensional case using solve_poly_system if possible.
  2974. # If some polynomials have factors that cannot be solved in radicals
  2975. # then this will fail. Using solve_poly_system(..., strict=True)
  2976. # ensures that we either get a complete solution set in radicals or
  2977. # UnsolvableFactorError will be raised.
  2978. try:
  2979. result = solve_poly_system(basis, *symbols, strict=True)
  2980. except UnsolvableFactorError:
  2981. # Failure... not fully solvable in radicals. Return the lex-order
  2982. # basis for substitution to handle.
  2983. poly_sol = no_information
  2984. poly_eqs = list(basis)
  2985. else:
  2986. # Success! We have a finite solution set and solve_poly_system has
  2987. # succeeded in finding all solutions. Return the solutions and also
  2988. # an empty list of remaining equations to be solved.
  2989. poly_sol = [dict(zip(symbols, res)) for res in result]
  2990. poly_eqs = no_equations
  2991. #
  2992. # Infinite families of solutions (positive-dimensional case)
  2993. #
  2994. else:
  2995. # In this case the grevlex basis cannot be converted to lex using the
  2996. # fglm method and also solve_poly_system cannot solve the equations. We
  2997. # would like to return a lex basis but since we can't use fglm we
  2998. # compute the lex basis directly here. The time required to recompute
  2999. # the basis is generally significantly less than the time required by
  3000. # substitution to solve the new system.
  3001. poly_sol = no_information
  3002. poly_eqs = list(groebner(polys, symbols, order='lex', polys=False))
  3003. if inexact:
  3004. poly_eqs = [nfloat(p) for p in poly_eqs]
  3005. return poly_sol, poly_eqs
  3006. def nonlinsolve(system, *symbols):
  3007. r"""
  3008. Solve system of $N$ nonlinear equations with $M$ variables, which means both
  3009. under and overdetermined systems are supported. Positive dimensional
  3010. system is also supported (A system with infinitely many solutions is said
  3011. to be positive-dimensional). In a positive dimensional system the solution will
  3012. be dependent on at least one symbol. Returns both real solution
  3013. and complex solution (if they exist).
  3014. Parameters
  3015. ==========
  3016. system : list of equations
  3017. The target system of equations
  3018. symbols : list of Symbols
  3019. symbols should be given as a sequence eg. list
  3020. Returns
  3021. =======
  3022. A :class:`~.FiniteSet` of ordered tuple of values of `symbols` for which the `system`
  3023. has solution. Order of values in the tuple is same as symbols present in
  3024. the parameter `symbols`.
  3025. Please note that general :class:`~.FiniteSet` is unordered, the solution
  3026. returned here is not simply a :class:`~.FiniteSet` of solutions, rather it
  3027. is a :class:`~.FiniteSet` of ordered tuple, i.e. the first and only
  3028. argument to :class:`~.FiniteSet` is a tuple of solutions, which is
  3029. ordered, and, hence ,the returned solution is ordered.
  3030. Also note that solution could also have been returned as an ordered tuple,
  3031. FiniteSet is just a wrapper ``{}`` around the tuple. It has no other
  3032. significance except for the fact it is just used to maintain a consistent
  3033. output format throughout the solveset.
  3034. For the given set of equations, the respective input types
  3035. are given below:
  3036. .. math:: xy - 1 = 0
  3037. .. math:: 4x^2 + y^2 - 5 = 0
  3038. ::
  3039. system = [x*y - 1, 4*x**2 + y**2 - 5]
  3040. symbols = [x, y]
  3041. Raises
  3042. ======
  3043. ValueError
  3044. The input is not valid.
  3045. The symbols are not given.
  3046. AttributeError
  3047. The input symbols are not `Symbol` type.
  3048. Examples
  3049. ========
  3050. >>> from sympy import symbols, nonlinsolve
  3051. >>> x, y, z = symbols('x, y, z', real=True)
  3052. >>> nonlinsolve([x*y - 1, 4*x**2 + y**2 - 5], [x, y])
  3053. {(-1, -1), (-1/2, -2), (1/2, 2), (1, 1)}
  3054. 1. Positive dimensional system and complements:
  3055. >>> from sympy import pprint
  3056. >>> from sympy.polys.polytools import is_zero_dimensional
  3057. >>> a, b, c, d = symbols('a, b, c, d', extended_real=True)
  3058. >>> eq1 = a + b + c + d
  3059. >>> eq2 = a*b + b*c + c*d + d*a
  3060. >>> eq3 = a*b*c + b*c*d + c*d*a + d*a*b
  3061. >>> eq4 = a*b*c*d - 1
  3062. >>> system = [eq1, eq2, eq3, eq4]
  3063. >>> is_zero_dimensional(system)
  3064. False
  3065. >>> pprint(nonlinsolve(system, [a, b, c, d]), use_unicode=False)
  3066. -1 1 1 -1
  3067. {(---, -d, -, {d} \ {0}), (-, -d, ---, {d} \ {0})}
  3068. d d d d
  3069. >>> nonlinsolve([(x+y)**2 - 4, x + y - 2], [x, y])
  3070. {(2 - y, y)}
  3071. 2. If some of the equations are non-polynomial then `nonlinsolve`
  3072. will call the ``substitution`` function and return real and complex solutions,
  3073. if present.
  3074. >>> from sympy import exp, sin
  3075. >>> nonlinsolve([exp(x) - sin(y), y**2 - 4], [x, y])
  3076. {(ImageSet(Lambda(_n, I*(2*_n*pi + pi) + log(sin(2))), Integers), -2),
  3077. (ImageSet(Lambda(_n, 2*_n*I*pi + log(sin(2))), Integers), 2)}
  3078. 3. If system is non-linear polynomial and zero-dimensional then it
  3079. returns both solution (real and complex solutions, if present) using
  3080. :func:`~.solve_poly_system`:
  3081. >>> from sympy import sqrt
  3082. >>> nonlinsolve([x**2 - 2*y**2 -2, x*y - 2], [x, y])
  3083. {(-2, -1), (2, 1), (-sqrt(2)*I, sqrt(2)*I), (sqrt(2)*I, -sqrt(2)*I)}
  3084. 4. ``nonlinsolve`` can solve some linear (zero or positive dimensional)
  3085. system (because it uses the :func:`sympy.polys.polytools.groebner` function to get the
  3086. groebner basis and then uses the ``substitution`` function basis as the
  3087. new `system`). But it is not recommended to solve linear system using
  3088. ``nonlinsolve``, because :func:`~.linsolve` is better for general linear systems.
  3089. >>> nonlinsolve([x + 2*y -z - 3, x - y - 4*z + 9, y + z - 4], [x, y, z])
  3090. {(3*z - 5, 4 - z, z)}
  3091. 5. System having polynomial equations and only real solution is
  3092. solved using :func:`~.solve_poly_system`:
  3093. >>> e1 = sqrt(x**2 + y**2) - 10
  3094. >>> e2 = sqrt(y**2 + (-x + 10)**2) - 3
  3095. >>> nonlinsolve((e1, e2), (x, y))
  3096. {(191/20, -3*sqrt(391)/20), (191/20, 3*sqrt(391)/20)}
  3097. >>> nonlinsolve([x**2 + 2/y - 2, x + y - 3], [x, y])
  3098. {(1, 2), (1 - sqrt(5), 2 + sqrt(5)), (1 + sqrt(5), 2 - sqrt(5))}
  3099. >>> nonlinsolve([x**2 + 2/y - 2, x + y - 3], [y, x])
  3100. {(2, 1), (2 - sqrt(5), 1 + sqrt(5)), (2 + sqrt(5), 1 - sqrt(5))}
  3101. 6. It is better to use symbols instead of trigonometric functions or
  3102. :class:`~.Function`. For example, replace $\sin(x)$ with a symbol, replace
  3103. $f(x)$ with a symbol and so on. Get a solution from ``nonlinsolve`` and then
  3104. use :func:`~.solveset` to get the value of $x$.
  3105. How nonlinsolve is better than old solver ``_solve_system`` :
  3106. =============================================================
  3107. 1. A positive dimensional system solver: nonlinsolve can return
  3108. solution for positive dimensional system. It finds the
  3109. Groebner Basis of the positive dimensional system(calling it as
  3110. basis) then we can start solving equation(having least number of
  3111. variable first in the basis) using solveset and substituting that
  3112. solved solutions into other equation(of basis) to get solution in
  3113. terms of minimum variables. Here the important thing is how we
  3114. are substituting the known values and in which equations.
  3115. 2. Real and complex solutions: nonlinsolve returns both real
  3116. and complex solution. If all the equations in the system are polynomial
  3117. then using :func:`~.solve_poly_system` both real and complex solution is returned.
  3118. If all the equations in the system are not polynomial equation then goes to
  3119. ``substitution`` method with this polynomial and non polynomial equation(s),
  3120. to solve for unsolved variables. Here to solve for particular variable
  3121. solveset_real and solveset_complex is used. For both real and complex
  3122. solution ``_solve_using_known_values`` is used inside ``substitution``
  3123. (``substitution`` will be called when any non-polynomial equation is present).
  3124. If a solution is valid its general solution is added to the final result.
  3125. 3. :class:`~.Complement` and :class:`~.Intersection` will be added:
  3126. nonlinsolve maintains dict for complements and intersections. If solveset
  3127. find complements or/and intersections with any interval or set during the
  3128. execution of ``substitution`` function, then complement or/and
  3129. intersection for that variable is added before returning final solution.
  3130. """
  3131. if not system:
  3132. return S.EmptySet
  3133. if not symbols:
  3134. msg = ('Symbols must be given, for which solution of the '
  3135. 'system is to be found.')
  3136. raise ValueError(filldedent(msg))
  3137. if hasattr(symbols[0], '__iter__'):
  3138. symbols = symbols[0]
  3139. if not is_sequence(symbols) or not symbols:
  3140. msg = ('Symbols must be given, for which solution of the '
  3141. 'system is to be found.')
  3142. raise IndexError(filldedent(msg))
  3143. symbols = list(map(_sympify, symbols))
  3144. system, symbols, swap = recast_to_symbols(system, symbols)
  3145. if swap:
  3146. soln = nonlinsolve(system, symbols)
  3147. return FiniteSet(*[tuple(i.xreplace(swap) for i in s) for s in soln])
  3148. if len(system) == 1 and len(symbols) == 1:
  3149. return _solveset_work(system, symbols)
  3150. # main code of def nonlinsolve() starts from here
  3151. polys, polys_expr, nonpolys, denominators, unrad_changed = \
  3152. _separate_poly_nonpoly(system, symbols)
  3153. poly_eqs = []
  3154. poly_sol = [{}]
  3155. if polys:
  3156. poly_sol, poly_eqs = _handle_poly(polys, symbols)
  3157. if poly_sol and poly_sol[0]:
  3158. poly_syms = set().union(*(eq.free_symbols for eq in polys))
  3159. unrad_syms = set().union(*(eq.free_symbols for eq in unrad_changed))
  3160. if unrad_syms == poly_syms and unrad_changed:
  3161. # if all the symbols have been solved by _handle_poly
  3162. # and unrad has been used then check solutions
  3163. poly_sol = [sol for sol in poly_sol if checksol(unrad_changed, sol)]
  3164. # Collect together the unsolved polynomials with the non-polynomial
  3165. # equations.
  3166. remaining = poly_eqs + nonpolys
  3167. # to_tuple converts a solution dictionary to a tuple containing the
  3168. # value for each symbol
  3169. to_tuple = lambda sol: tuple(sol[s] for s in symbols)
  3170. if not remaining:
  3171. # If there is nothing left to solve then return the solution from
  3172. # solve_poly_system directly.
  3173. return FiniteSet(*map(to_tuple, poly_sol))
  3174. else:
  3175. # Here we handle:
  3176. #
  3177. # 1. The Groebner basis if solve_poly_system failed.
  3178. # 2. The Groebner basis in the positive-dimensional case.
  3179. # 3. Any non-polynomial equations
  3180. #
  3181. # If solve_poly_system did succeed then we pass those solutions in as
  3182. # preliminary results.
  3183. subs_res = substitution(remaining, symbols, result=poly_sol, exclude=denominators)
  3184. if not isinstance(subs_res, FiniteSet):
  3185. return subs_res
  3186. # check solutions produced by substitution. Currently, checking is done for
  3187. # only those solutions which have non-Set variable values.
  3188. if unrad_changed:
  3189. result = [dict(zip(symbols, sol)) for sol in subs_res.args]
  3190. correct_sols = [sol for sol in result if any(isinstance(v, Set) for v in sol)
  3191. or checksol(unrad_changed, sol) != False]
  3192. return FiniteSet(*map(to_tuple, correct_sols))
  3193. else:
  3194. return subs_res