solveset.py 130 KB

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