rings.py 84 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096
  1. """Sparse polynomial rings. """
  2. from __future__ import annotations
  3. from operator import add, mul, lt, le, gt, ge
  4. from functools import reduce
  5. from types import GeneratorType
  6. from sympy.core.cache import cacheit
  7. from sympy.core.expr import Expr
  8. from sympy.core.intfunc import igcd
  9. from sympy.core.symbol import Symbol, symbols as _symbols
  10. from sympy.core.sympify import CantSympify, sympify
  11. from sympy.ntheory.multinomial import multinomial_coefficients
  12. from sympy.polys.compatibility import IPolys
  13. from sympy.polys.constructor import construct_domain
  14. from sympy.polys.densebasic import ninf, dmp_to_dict, dmp_from_dict
  15. from sympy.polys.domains.domain import Domain
  16. from sympy.polys.domains.domainelement import DomainElement
  17. from sympy.polys.domains.polynomialring import PolynomialRing
  18. from sympy.polys.heuristicgcd import heugcd
  19. from sympy.polys.monomials import MonomialOps
  20. from sympy.polys.orderings import lex, MonomialOrder
  21. from sympy.polys.polyerrors import (
  22. CoercionFailed, GeneratorsError,
  23. ExactQuotientFailed, MultivariatePolynomialError)
  24. from sympy.polys.polyoptions import (Domain as DomainOpt,
  25. Order as OrderOpt, build_options)
  26. from sympy.polys.polyutils import (expr_from_dict, _dict_reorder,
  27. _parallel_dict_from_expr)
  28. from sympy.printing.defaults import DefaultPrinting
  29. from sympy.utilities import public, subsets
  30. from sympy.utilities.iterables import is_sequence
  31. from sympy.utilities.magic import pollute
  32. @public
  33. def ring(symbols, domain, order: MonomialOrder|str = lex):
  34. """Construct a polynomial ring returning ``(ring, x_1, ..., x_n)``.
  35. Parameters
  36. ==========
  37. symbols : str
  38. Symbol/Expr or sequence of str, Symbol/Expr (non-empty)
  39. domain : :class:`~.Domain` or coercible
  40. order : :class:`~.MonomialOrder` or coercible, optional, defaults to ``lex``
  41. Examples
  42. ========
  43. >>> from sympy.polys.rings import ring
  44. >>> from sympy.polys.domains import ZZ
  45. >>> from sympy.polys.orderings import lex
  46. >>> R, x, y, z = ring("x,y,z", ZZ, lex)
  47. >>> R
  48. Polynomial ring in x, y, z over ZZ with lex order
  49. >>> x + y + z
  50. x + y + z
  51. >>> type(_)
  52. <class 'sympy.polys.rings.PolyElement'>
  53. """
  54. _ring = PolyRing(symbols, domain, order)
  55. return (_ring,) + _ring.gens
  56. @public
  57. def xring(symbols, domain, order=lex):
  58. """Construct a polynomial ring returning ``(ring, (x_1, ..., x_n))``.
  59. Parameters
  60. ==========
  61. symbols : str
  62. Symbol/Expr or sequence of str, Symbol/Expr (non-empty)
  63. domain : :class:`~.Domain` or coercible
  64. order : :class:`~.MonomialOrder` or coercible, optional, defaults to ``lex``
  65. Examples
  66. ========
  67. >>> from sympy.polys.rings import xring
  68. >>> from sympy.polys.domains import ZZ
  69. >>> from sympy.polys.orderings import lex
  70. >>> R, (x, y, z) = xring("x,y,z", ZZ, lex)
  71. >>> R
  72. Polynomial ring in x, y, z over ZZ with lex order
  73. >>> x + y + z
  74. x + y + z
  75. >>> type(_)
  76. <class 'sympy.polys.rings.PolyElement'>
  77. """
  78. _ring = PolyRing(symbols, domain, order)
  79. return (_ring, _ring.gens)
  80. @public
  81. def vring(symbols, domain, order=lex):
  82. """Construct a polynomial ring and inject ``x_1, ..., x_n`` into the global namespace.
  83. Parameters
  84. ==========
  85. symbols : str
  86. Symbol/Expr or sequence of str, Symbol/Expr (non-empty)
  87. domain : :class:`~.Domain` or coercible
  88. order : :class:`~.MonomialOrder` or coercible, optional, defaults to ``lex``
  89. Examples
  90. ========
  91. >>> from sympy.polys.rings import vring
  92. >>> from sympy.polys.domains import ZZ
  93. >>> from sympy.polys.orderings import lex
  94. >>> vring("x,y,z", ZZ, lex)
  95. Polynomial ring in x, y, z over ZZ with lex order
  96. >>> x + y + z # noqa:
  97. x + y + z
  98. >>> type(_)
  99. <class 'sympy.polys.rings.PolyElement'>
  100. """
  101. _ring = PolyRing(symbols, domain, order)
  102. pollute([ sym.name for sym in _ring.symbols ], _ring.gens)
  103. return _ring
  104. @public
  105. def sring(exprs, *symbols, **options):
  106. """Construct a ring deriving generators and domain from options and input expressions.
  107. Parameters
  108. ==========
  109. exprs : :class:`~.Expr` or sequence of :class:`~.Expr` (sympifiable)
  110. symbols : sequence of :class:`~.Symbol`/:class:`~.Expr`
  111. options : keyword arguments understood by :class:`~.Options`
  112. Examples
  113. ========
  114. >>> from sympy import sring, symbols
  115. >>> x, y, z = symbols("x,y,z")
  116. >>> R, f = sring(x + 2*y + 3*z)
  117. >>> R
  118. Polynomial ring in x, y, z over ZZ with lex order
  119. >>> f
  120. x + 2*y + 3*z
  121. >>> type(_)
  122. <class 'sympy.polys.rings.PolyElement'>
  123. """
  124. single = False
  125. if not is_sequence(exprs):
  126. exprs, single = [exprs], True
  127. exprs = list(map(sympify, exprs))
  128. opt = build_options(symbols, options)
  129. # TODO: rewrite this so that it doesn't use expand() (see poly()).
  130. reps, opt = _parallel_dict_from_expr(exprs, opt)
  131. if opt.domain is None:
  132. coeffs = sum([ list(rep.values()) for rep in reps ], [])
  133. opt.domain, coeffs_dom = construct_domain(coeffs, opt=opt)
  134. coeff_map = dict(zip(coeffs, coeffs_dom))
  135. reps = [{m: coeff_map[c] for m, c in rep.items()} for rep in reps]
  136. _ring = PolyRing(opt.gens, opt.domain, opt.order)
  137. polys = list(map(_ring.from_dict, reps))
  138. if single:
  139. return (_ring, polys[0])
  140. else:
  141. return (_ring, polys)
  142. def _parse_symbols(symbols):
  143. if isinstance(symbols, str):
  144. return _symbols(symbols, seq=True) if symbols else ()
  145. elif isinstance(symbols, Expr):
  146. return (symbols,)
  147. elif is_sequence(symbols):
  148. if all(isinstance(s, str) for s in symbols):
  149. return _symbols(symbols)
  150. elif all(isinstance(s, Expr) for s in symbols):
  151. return symbols
  152. raise GeneratorsError("expected a string, Symbol or expression or a non-empty sequence of strings, Symbols or expressions")
  153. class PolyRing(DefaultPrinting, IPolys):
  154. """Multivariate distributed polynomial ring. """
  155. gens: tuple[PolyElement, ...]
  156. symbols: tuple[Expr, ...]
  157. ngens: int
  158. domain: Domain
  159. order: MonomialOrder
  160. def __new__(cls, symbols, domain, order=lex):
  161. symbols = tuple(_parse_symbols(symbols))
  162. ngens = len(symbols)
  163. domain = DomainOpt.preprocess(domain)
  164. order = OrderOpt.preprocess(order)
  165. _hash_tuple = (cls.__name__, symbols, ngens, domain, order)
  166. if domain.is_Composite and set(symbols) & set(domain.symbols):
  167. raise GeneratorsError("polynomial ring and it's ground domain share generators")
  168. obj = object.__new__(cls)
  169. obj._hash_tuple = _hash_tuple
  170. obj._hash = hash(_hash_tuple)
  171. obj.symbols = symbols
  172. obj.ngens = ngens
  173. obj.domain = domain
  174. obj.order = order
  175. obj.dtype = PolyElement(obj, ()).new
  176. obj.zero_monom = (0,)*ngens
  177. obj.gens = obj._gens()
  178. obj._gens_set = set(obj.gens)
  179. obj._one = [(obj.zero_monom, domain.one)]
  180. if ngens:
  181. # These expect monomials in at least one variable
  182. codegen = MonomialOps(ngens)
  183. obj.monomial_mul = codegen.mul()
  184. obj.monomial_pow = codegen.pow()
  185. obj.monomial_mulpow = codegen.mulpow()
  186. obj.monomial_ldiv = codegen.ldiv()
  187. obj.monomial_div = codegen.div()
  188. obj.monomial_lcm = codegen.lcm()
  189. obj.monomial_gcd = codegen.gcd()
  190. else:
  191. monunit = lambda a, b: ()
  192. obj.monomial_mul = monunit
  193. obj.monomial_pow = monunit
  194. obj.monomial_mulpow = lambda a, b, c: ()
  195. obj.monomial_ldiv = monunit
  196. obj.monomial_div = monunit
  197. obj.monomial_lcm = monunit
  198. obj.monomial_gcd = monunit
  199. if order is lex:
  200. obj.leading_expv = max
  201. else:
  202. obj.leading_expv = lambda f: max(f, key=order)
  203. for symbol, generator in zip(obj.symbols, obj.gens):
  204. if isinstance(symbol, Symbol):
  205. name = symbol.name
  206. if not hasattr(obj, name):
  207. setattr(obj, name, generator)
  208. return obj
  209. def _gens(self):
  210. """Return a list of polynomial generators. """
  211. one = self.domain.one
  212. _gens = []
  213. for i in range(self.ngens):
  214. expv = self.monomial_basis(i)
  215. poly = self.zero
  216. poly[expv] = one
  217. _gens.append(poly)
  218. return tuple(_gens)
  219. def __getnewargs__(self):
  220. return (self.symbols, self.domain, self.order)
  221. def __getstate__(self):
  222. state = self.__dict__.copy()
  223. del state["leading_expv"]
  224. for key in state:
  225. if key.startswith("monomial_"):
  226. del state[key]
  227. return state
  228. def __hash__(self):
  229. return self._hash
  230. def __eq__(self, other):
  231. return isinstance(other, PolyRing) and \
  232. (self.symbols, self.domain, self.ngens, self.order) == \
  233. (other.symbols, other.domain, other.ngens, other.order)
  234. def __ne__(self, other):
  235. return not self == other
  236. def clone(self, symbols=None, domain=None, order=None):
  237. # Need a hashable tuple for cacheit to work
  238. if symbols is not None and isinstance(symbols, list):
  239. symbols = tuple(symbols)
  240. return self._clone(symbols, domain, order)
  241. @cacheit
  242. def _clone(self, symbols, domain, order):
  243. return self.__class__(symbols or self.symbols, domain or self.domain, order or self.order)
  244. def monomial_basis(self, i):
  245. """Return the ith-basis element. """
  246. basis = [0]*self.ngens
  247. basis[i] = 1
  248. return tuple(basis)
  249. @property
  250. def zero(self):
  251. return self.dtype([])
  252. @property
  253. def one(self):
  254. return self.dtype(self._one)
  255. def is_element(self, element):
  256. """True if ``element`` is an element of this ring. False otherwise. """
  257. return isinstance(element, PolyElement) and element.ring == self
  258. def domain_new(self, element, orig_domain=None):
  259. return self.domain.convert(element, orig_domain)
  260. def ground_new(self, coeff):
  261. return self.term_new(self.zero_monom, coeff)
  262. def term_new(self, monom, coeff):
  263. coeff = self.domain_new(coeff)
  264. poly = self.zero
  265. if coeff:
  266. poly[monom] = coeff
  267. return poly
  268. def ring_new(self, element):
  269. if isinstance(element, PolyElement):
  270. if self == element.ring:
  271. return element
  272. elif isinstance(self.domain, PolynomialRing) and self.domain.ring == element.ring:
  273. return self.ground_new(element)
  274. else:
  275. raise NotImplementedError("conversion")
  276. elif isinstance(element, str):
  277. raise NotImplementedError("parsing")
  278. elif isinstance(element, dict):
  279. return self.from_dict(element)
  280. elif isinstance(element, list):
  281. try:
  282. return self.from_terms(element)
  283. except ValueError:
  284. return self.from_list(element)
  285. elif isinstance(element, Expr):
  286. return self.from_expr(element)
  287. else:
  288. return self.ground_new(element)
  289. __call__ = ring_new
  290. def from_dict(self, element, orig_domain=None):
  291. domain_new = self.domain_new
  292. poly = self.zero
  293. for monom, coeff in element.items():
  294. coeff = domain_new(coeff, orig_domain)
  295. if coeff:
  296. poly[monom] = coeff
  297. return poly
  298. def from_terms(self, element, orig_domain=None):
  299. return self.from_dict(dict(element), orig_domain)
  300. def from_list(self, element):
  301. return self.from_dict(dmp_to_dict(element, self.ngens-1, self.domain))
  302. def _rebuild_expr(self, expr, mapping):
  303. domain = self.domain
  304. def _rebuild(expr):
  305. generator = mapping.get(expr)
  306. if generator is not None:
  307. return generator
  308. elif expr.is_Add:
  309. return reduce(add, list(map(_rebuild, expr.args)))
  310. elif expr.is_Mul:
  311. return reduce(mul, list(map(_rebuild, expr.args)))
  312. else:
  313. # XXX: Use as_base_exp() to handle Pow(x, n) and also exp(n)
  314. # XXX: E can be a generator e.g. sring([exp(2)]) -> ZZ[E]
  315. base, exp = expr.as_base_exp()
  316. if exp.is_Integer and exp > 1:
  317. return _rebuild(base)**int(exp)
  318. else:
  319. return self.ground_new(domain.convert(expr))
  320. return _rebuild(sympify(expr))
  321. def from_expr(self, expr):
  322. mapping = dict(list(zip(self.symbols, self.gens)))
  323. try:
  324. poly = self._rebuild_expr(expr, mapping)
  325. except CoercionFailed:
  326. raise ValueError("expected an expression convertible to a polynomial in %s, got %s" % (self, expr))
  327. else:
  328. return self.ring_new(poly)
  329. def index(self, gen):
  330. """Compute index of ``gen`` in ``self.gens``. """
  331. if gen is None:
  332. if self.ngens:
  333. i = 0
  334. else:
  335. i = -1 # indicate impossible choice
  336. elif isinstance(gen, int):
  337. i = gen
  338. if 0 <= i and i < self.ngens:
  339. pass
  340. elif -self.ngens <= i and i <= -1:
  341. i = -i - 1
  342. else:
  343. raise ValueError("invalid generator index: %s" % gen)
  344. elif self.is_element(gen):
  345. try:
  346. i = self.gens.index(gen)
  347. except ValueError:
  348. raise ValueError("invalid generator: %s" % gen)
  349. elif isinstance(gen, str):
  350. try:
  351. i = self.symbols.index(gen)
  352. except ValueError:
  353. raise ValueError("invalid generator: %s" % gen)
  354. else:
  355. raise ValueError("expected a polynomial generator, an integer, a string or None, got %s" % gen)
  356. return i
  357. def drop(self, *gens):
  358. """Remove specified generators from this ring. """
  359. indices = set(map(self.index, gens))
  360. symbols = [ s for i, s in enumerate(self.symbols) if i not in indices ]
  361. if not symbols:
  362. return self.domain
  363. else:
  364. return self.clone(symbols=symbols)
  365. def __getitem__(self, key):
  366. symbols = self.symbols[key]
  367. if not symbols:
  368. return self.domain
  369. else:
  370. return self.clone(symbols=symbols)
  371. def to_ground(self):
  372. # TODO: should AlgebraicField be a Composite domain?
  373. if self.domain.is_Composite or hasattr(self.domain, 'domain'):
  374. return self.clone(domain=self.domain.domain)
  375. else:
  376. raise ValueError("%s is not a composite domain" % self.domain)
  377. def to_domain(self):
  378. return PolynomialRing(self)
  379. def to_field(self):
  380. from sympy.polys.fields import FracField
  381. return FracField(self.symbols, self.domain, self.order)
  382. @property
  383. def is_univariate(self):
  384. return len(self.gens) == 1
  385. @property
  386. def is_multivariate(self):
  387. return len(self.gens) > 1
  388. def add(self, *objs):
  389. """
  390. Add a sequence of polynomials or containers of polynomials.
  391. Examples
  392. ========
  393. >>> from sympy.polys.rings import ring
  394. >>> from sympy.polys.domains import ZZ
  395. >>> R, x = ring("x", ZZ)
  396. >>> R.add([ x**2 + 2*i + 3 for i in range(4) ])
  397. 4*x**2 + 24
  398. >>> _.factor_list()
  399. (4, [(x**2 + 6, 1)])
  400. """
  401. p = self.zero
  402. for obj in objs:
  403. if is_sequence(obj, include=GeneratorType):
  404. p += self.add(*obj)
  405. else:
  406. p += obj
  407. return p
  408. def mul(self, *objs):
  409. """
  410. Multiply a sequence of polynomials or containers of polynomials.
  411. Examples
  412. ========
  413. >>> from sympy.polys.rings import ring
  414. >>> from sympy.polys.domains import ZZ
  415. >>> R, x = ring("x", ZZ)
  416. >>> R.mul([ x**2 + 2*i + 3 for i in range(4) ])
  417. x**8 + 24*x**6 + 206*x**4 + 744*x**2 + 945
  418. >>> _.factor_list()
  419. (1, [(x**2 + 3, 1), (x**2 + 5, 1), (x**2 + 7, 1), (x**2 + 9, 1)])
  420. """
  421. p = self.one
  422. for obj in objs:
  423. if is_sequence(obj, include=GeneratorType):
  424. p *= self.mul(*obj)
  425. else:
  426. p *= obj
  427. return p
  428. def drop_to_ground(self, *gens):
  429. r"""
  430. Remove specified generators from the ring and inject them into
  431. its domain.
  432. """
  433. indices = set(map(self.index, gens))
  434. symbols = [s for i, s in enumerate(self.symbols) if i not in indices]
  435. gens = [gen for i, gen in enumerate(self.gens) if i not in indices]
  436. if not symbols:
  437. return self
  438. else:
  439. return self.clone(symbols=symbols, domain=self.drop(*gens))
  440. def compose(self, other):
  441. """Add the generators of ``other`` to ``self``"""
  442. if self != other:
  443. syms = set(self.symbols).union(set(other.symbols))
  444. return self.clone(symbols=list(syms))
  445. else:
  446. return self
  447. def add_gens(self, symbols):
  448. """Add the elements of ``symbols`` as generators to ``self``"""
  449. syms = set(self.symbols).union(set(symbols))
  450. return self.clone(symbols=list(syms))
  451. def symmetric_poly(self, n):
  452. """
  453. Return the elementary symmetric polynomial of degree *n* over
  454. this ring's generators.
  455. """
  456. if n < 0 or n > self.ngens:
  457. raise ValueError("Cannot generate symmetric polynomial of order %s for %s" % (n, self.gens))
  458. elif not n:
  459. return self.one
  460. else:
  461. poly = self.zero
  462. for s in subsets(range(self.ngens), int(n)):
  463. monom = tuple(int(i in s) for i in range(self.ngens))
  464. poly += self.term_new(monom, self.domain.one)
  465. return poly
  466. class PolyElement(DomainElement, DefaultPrinting, CantSympify, dict):
  467. """Element of multivariate distributed polynomial ring. """
  468. def __init__(self, ring, init):
  469. super().__init__(init)
  470. self.ring = ring
  471. # This check would be too slow to run every time:
  472. # self._check()
  473. def _check(self):
  474. assert isinstance(self, PolyElement)
  475. assert isinstance(self.ring, PolyRing)
  476. dom = self.ring.domain
  477. assert isinstance(dom, Domain)
  478. for monom, coeff in self.items():
  479. assert dom.of_type(coeff)
  480. assert len(monom) == self.ring.ngens
  481. assert all(isinstance(exp, int) and exp >= 0 for exp in monom)
  482. def new(self, init):
  483. return self.__class__(self.ring, init)
  484. def parent(self):
  485. return self.ring.to_domain()
  486. def __getnewargs__(self):
  487. return (self.ring, list(self.iterterms()))
  488. _hash = None
  489. def __hash__(self):
  490. # XXX: This computes a hash of a dictionary, but currently we don't
  491. # protect dictionary from being changed so any use site modifications
  492. # will make hashing go wrong. Use this feature with caution until we
  493. # figure out how to make a safe API without compromising speed of this
  494. # low-level class.
  495. _hash = self._hash
  496. if _hash is None:
  497. self._hash = _hash = hash((self.ring, frozenset(self.items())))
  498. return _hash
  499. def copy(self):
  500. """Return a copy of polynomial self.
  501. Polynomials are mutable; if one is interested in preserving
  502. a polynomial, and one plans to use inplace operations, one
  503. can copy the polynomial. This method makes a shallow copy.
  504. Examples
  505. ========
  506. >>> from sympy.polys.domains import ZZ
  507. >>> from sympy.polys.rings import ring
  508. >>> R, x, y = ring('x, y', ZZ)
  509. >>> p = (x + y)**2
  510. >>> p1 = p.copy()
  511. >>> p2 = p
  512. >>> p[R.zero_monom] = 3
  513. >>> p
  514. x**2 + 2*x*y + y**2 + 3
  515. >>> p1
  516. x**2 + 2*x*y + y**2
  517. >>> p2
  518. x**2 + 2*x*y + y**2 + 3
  519. """
  520. return self.new(self)
  521. def set_ring(self, new_ring):
  522. if self.ring == new_ring:
  523. return self
  524. elif self.ring.symbols != new_ring.symbols:
  525. terms = list(zip(*_dict_reorder(self, self.ring.symbols, new_ring.symbols)))
  526. return new_ring.from_terms(terms, self.ring.domain)
  527. else:
  528. return new_ring.from_dict(self, self.ring.domain)
  529. def as_expr(self, *symbols):
  530. if not symbols:
  531. symbols = self.ring.symbols
  532. elif len(symbols) != self.ring.ngens:
  533. raise ValueError(
  534. "Wrong number of symbols, expected %s got %s" %
  535. (self.ring.ngens, len(symbols))
  536. )
  537. return expr_from_dict(self.as_expr_dict(), *symbols)
  538. def as_expr_dict(self):
  539. to_sympy = self.ring.domain.to_sympy
  540. return {monom: to_sympy(coeff) for monom, coeff in self.iterterms()}
  541. def clear_denoms(self):
  542. domain = self.ring.domain
  543. if not domain.is_Field or not domain.has_assoc_Ring:
  544. return domain.one, self
  545. ground_ring = domain.get_ring()
  546. common = ground_ring.one
  547. lcm = ground_ring.lcm
  548. denom = domain.denom
  549. for coeff in self.values():
  550. common = lcm(common, denom(coeff))
  551. poly = self.new([ (k, v*common) for k, v in self.items() ])
  552. return common, poly
  553. def strip_zero(self):
  554. """Eliminate monomials with zero coefficient. """
  555. for k, v in list(self.items()):
  556. if not v:
  557. del self[k]
  558. def __eq__(p1, p2):
  559. """Equality test for polynomials.
  560. Examples
  561. ========
  562. >>> from sympy.polys.domains import ZZ
  563. >>> from sympy.polys.rings import ring
  564. >>> _, x, y = ring('x, y', ZZ)
  565. >>> p1 = (x + y)**2 + (x - y)**2
  566. >>> p1 == 4*x*y
  567. False
  568. >>> p1 == 2*(x**2 + y**2)
  569. True
  570. """
  571. if not p2:
  572. return not p1
  573. elif p1.ring.is_element(p2):
  574. return dict.__eq__(p1, p2)
  575. elif len(p1) > 1:
  576. return False
  577. else:
  578. return p1.get(p1.ring.zero_monom) == p2
  579. def __ne__(p1, p2):
  580. return not p1 == p2
  581. def almosteq(p1, p2, tolerance=None):
  582. """Approximate equality test for polynomials. """
  583. ring = p1.ring
  584. if ring.is_element(p2):
  585. if set(p1.keys()) != set(p2.keys()):
  586. return False
  587. almosteq = ring.domain.almosteq
  588. for k in p1.keys():
  589. if not almosteq(p1[k], p2[k], tolerance):
  590. return False
  591. return True
  592. elif len(p1) > 1:
  593. return False
  594. else:
  595. try:
  596. p2 = ring.domain.convert(p2)
  597. except CoercionFailed:
  598. return False
  599. else:
  600. return ring.domain.almosteq(p1.const(), p2, tolerance)
  601. def sort_key(self):
  602. return (len(self), self.terms())
  603. def _cmp(p1, p2, op):
  604. if p1.ring.is_element(p2):
  605. return op(p1.sort_key(), p2.sort_key())
  606. else:
  607. return NotImplemented
  608. def __lt__(p1, p2):
  609. return p1._cmp(p2, lt)
  610. def __le__(p1, p2):
  611. return p1._cmp(p2, le)
  612. def __gt__(p1, p2):
  613. return p1._cmp(p2, gt)
  614. def __ge__(p1, p2):
  615. return p1._cmp(p2, ge)
  616. def _drop(self, gen):
  617. ring = self.ring
  618. i = ring.index(gen)
  619. if ring.ngens == 1:
  620. return i, ring.domain
  621. else:
  622. symbols = list(ring.symbols)
  623. del symbols[i]
  624. return i, ring.clone(symbols=symbols)
  625. def drop(self, gen):
  626. i, ring = self._drop(gen)
  627. if self.ring.ngens == 1:
  628. if self.is_ground:
  629. return self.coeff(1)
  630. else:
  631. raise ValueError("Cannot drop %s" % gen)
  632. else:
  633. poly = ring.zero
  634. for k, v in self.items():
  635. if k[i] == 0:
  636. K = list(k)
  637. del K[i]
  638. poly[tuple(K)] = v
  639. else:
  640. raise ValueError("Cannot drop %s" % gen)
  641. return poly
  642. def _drop_to_ground(self, gen):
  643. ring = self.ring
  644. i = ring.index(gen)
  645. symbols = list(ring.symbols)
  646. del symbols[i]
  647. return i, ring.clone(symbols=symbols, domain=ring[i])
  648. def drop_to_ground(self, gen):
  649. if self.ring.ngens == 1:
  650. raise ValueError("Cannot drop only generator to ground")
  651. i, ring = self._drop_to_ground(gen)
  652. poly = ring.zero
  653. gen = ring.domain.gens[0]
  654. for monom, coeff in self.iterterms():
  655. mon = monom[:i] + monom[i+1:]
  656. if mon not in poly:
  657. poly[mon] = (gen**monom[i]).mul_ground(coeff)
  658. else:
  659. poly[mon] += (gen**monom[i]).mul_ground(coeff)
  660. return poly
  661. def to_dense(self):
  662. return dmp_from_dict(self, self.ring.ngens-1, self.ring.domain)
  663. def to_dict(self):
  664. return dict(self)
  665. def str(self, printer, precedence, exp_pattern, mul_symbol):
  666. if not self:
  667. return printer._print(self.ring.domain.zero)
  668. prec_mul = precedence["Mul"]
  669. prec_atom = precedence["Atom"]
  670. ring = self.ring
  671. symbols = ring.symbols
  672. ngens = ring.ngens
  673. zm = ring.zero_monom
  674. sexpvs = []
  675. for expv, coeff in self.terms():
  676. negative = ring.domain.is_negative(coeff)
  677. sign = " - " if negative else " + "
  678. sexpvs.append(sign)
  679. if expv == zm:
  680. scoeff = printer._print(coeff)
  681. if negative and scoeff.startswith("-"):
  682. scoeff = scoeff[1:]
  683. else:
  684. if negative:
  685. coeff = -coeff
  686. if coeff != self.ring.domain.one:
  687. scoeff = printer.parenthesize(coeff, prec_mul, strict=True)
  688. else:
  689. scoeff = ''
  690. sexpv = []
  691. for i in range(ngens):
  692. exp = expv[i]
  693. if not exp:
  694. continue
  695. symbol = printer.parenthesize(symbols[i], prec_atom, strict=True)
  696. if exp != 1:
  697. if exp != int(exp) or exp < 0:
  698. sexp = printer.parenthesize(exp, prec_atom, strict=False)
  699. else:
  700. sexp = exp
  701. sexpv.append(exp_pattern % (symbol, sexp))
  702. else:
  703. sexpv.append('%s' % symbol)
  704. if scoeff:
  705. sexpv = [scoeff] + sexpv
  706. sexpvs.append(mul_symbol.join(sexpv))
  707. if sexpvs[0] in [" + ", " - "]:
  708. head = sexpvs.pop(0)
  709. if head == " - ":
  710. sexpvs.insert(0, "-")
  711. return "".join(sexpvs)
  712. @property
  713. def is_generator(self):
  714. return self in self.ring._gens_set
  715. @property
  716. def is_ground(self):
  717. return not self or (len(self) == 1 and self.ring.zero_monom in self)
  718. @property
  719. def is_monomial(self):
  720. return not self or (len(self) == 1 and self.LC == 1)
  721. @property
  722. def is_term(self):
  723. return len(self) <= 1
  724. @property
  725. def is_negative(self):
  726. return self.ring.domain.is_negative(self.LC)
  727. @property
  728. def is_positive(self):
  729. return self.ring.domain.is_positive(self.LC)
  730. @property
  731. def is_nonnegative(self):
  732. return self.ring.domain.is_nonnegative(self.LC)
  733. @property
  734. def is_nonpositive(self):
  735. return self.ring.domain.is_nonpositive(self.LC)
  736. @property
  737. def is_zero(f):
  738. return not f
  739. @property
  740. def is_one(f):
  741. return f == f.ring.one
  742. @property
  743. def is_monic(f):
  744. return f.ring.domain.is_one(f.LC)
  745. @property
  746. def is_primitive(f):
  747. return f.ring.domain.is_one(f.content())
  748. @property
  749. def is_linear(f):
  750. return all(sum(monom) <= 1 for monom in f.itermonoms())
  751. @property
  752. def is_quadratic(f):
  753. return all(sum(monom) <= 2 for monom in f.itermonoms())
  754. @property
  755. def is_squarefree(f):
  756. if not f.ring.ngens:
  757. return True
  758. return f.ring.dmp_sqf_p(f)
  759. @property
  760. def is_irreducible(f):
  761. if not f.ring.ngens:
  762. return True
  763. return f.ring.dmp_irreducible_p(f)
  764. @property
  765. def is_cyclotomic(f):
  766. if f.ring.is_univariate:
  767. return f.ring.dup_cyclotomic_p(f)
  768. else:
  769. raise MultivariatePolynomialError("cyclotomic polynomial")
  770. def __neg__(self):
  771. return self.new([ (monom, -coeff) for monom, coeff in self.iterterms() ])
  772. def __pos__(self):
  773. return self
  774. def __add__(p1, p2):
  775. """Add two polynomials.
  776. Examples
  777. ========
  778. >>> from sympy.polys.domains import ZZ
  779. >>> from sympy.polys.rings import ring
  780. >>> _, x, y = ring('x, y', ZZ)
  781. >>> (x + y)**2 + (x - y)**2
  782. 2*x**2 + 2*y**2
  783. """
  784. if not p2:
  785. return p1.copy()
  786. ring = p1.ring
  787. if ring.is_element(p2):
  788. p = p1.copy()
  789. get = p.get
  790. zero = ring.domain.zero
  791. for k, v in p2.items():
  792. v = get(k, zero) + v
  793. if v:
  794. p[k] = v
  795. else:
  796. del p[k]
  797. return p
  798. elif isinstance(p2, PolyElement):
  799. if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring:
  800. pass
  801. elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring:
  802. return p2.__radd__(p1)
  803. else:
  804. return NotImplemented
  805. try:
  806. cp2 = ring.domain_new(p2)
  807. except CoercionFailed:
  808. return NotImplemented
  809. else:
  810. p = p1.copy()
  811. if not cp2:
  812. return p
  813. zm = ring.zero_monom
  814. if zm not in p1.keys():
  815. p[zm] = cp2
  816. else:
  817. if p2 == -p[zm]:
  818. del p[zm]
  819. else:
  820. p[zm] += cp2
  821. return p
  822. def __radd__(p1, n):
  823. p = p1.copy()
  824. if not n:
  825. return p
  826. ring = p1.ring
  827. try:
  828. n = ring.domain_new(n)
  829. except CoercionFailed:
  830. return NotImplemented
  831. else:
  832. zm = ring.zero_monom
  833. if zm not in p1.keys():
  834. p[zm] = n
  835. else:
  836. if n == -p[zm]:
  837. del p[zm]
  838. else:
  839. p[zm] += n
  840. return p
  841. def __sub__(p1, p2):
  842. """Subtract polynomial p2 from p1.
  843. Examples
  844. ========
  845. >>> from sympy.polys.domains import ZZ
  846. >>> from sympy.polys.rings import ring
  847. >>> _, x, y = ring('x, y', ZZ)
  848. >>> p1 = x + y**2
  849. >>> p2 = x*y + y**2
  850. >>> p1 - p2
  851. -x*y + x
  852. """
  853. if not p2:
  854. return p1.copy()
  855. ring = p1.ring
  856. if ring.is_element(p2):
  857. p = p1.copy()
  858. get = p.get
  859. zero = ring.domain.zero
  860. for k, v in p2.items():
  861. v = get(k, zero) - v
  862. if v:
  863. p[k] = v
  864. else:
  865. del p[k]
  866. return p
  867. elif isinstance(p2, PolyElement):
  868. if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring:
  869. pass
  870. elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring:
  871. return p2.__rsub__(p1)
  872. else:
  873. return NotImplemented
  874. try:
  875. p2 = ring.domain_new(p2)
  876. except CoercionFailed:
  877. return NotImplemented
  878. else:
  879. p = p1.copy()
  880. zm = ring.zero_monom
  881. if zm not in p1.keys():
  882. p[zm] = -p2
  883. else:
  884. if p2 == p[zm]:
  885. del p[zm]
  886. else:
  887. p[zm] -= p2
  888. return p
  889. def __rsub__(p1, n):
  890. """n - p1 with n convertible to the coefficient domain.
  891. Examples
  892. ========
  893. >>> from sympy.polys.domains import ZZ
  894. >>> from sympy.polys.rings import ring
  895. >>> _, x, y = ring('x, y', ZZ)
  896. >>> p = x + y
  897. >>> 4 - p
  898. -x - y + 4
  899. """
  900. ring = p1.ring
  901. try:
  902. n = ring.domain_new(n)
  903. except CoercionFailed:
  904. return NotImplemented
  905. else:
  906. p = ring.zero
  907. for expv in p1:
  908. p[expv] = -p1[expv]
  909. p += n
  910. # p._check()
  911. return p
  912. def __mul__(p1, p2):
  913. """Multiply two polynomials.
  914. Examples
  915. ========
  916. >>> from sympy.polys.domains import QQ
  917. >>> from sympy.polys.rings import ring
  918. >>> _, x, y = ring('x, y', QQ)
  919. >>> p1 = x + y
  920. >>> p2 = x - y
  921. >>> p1*p2
  922. x**2 - y**2
  923. """
  924. ring = p1.ring
  925. p = ring.zero
  926. if not p1 or not p2:
  927. return p
  928. elif ring.is_element(p2):
  929. get = p.get
  930. zero = ring.domain.zero
  931. monomial_mul = ring.monomial_mul
  932. p2it = list(p2.items())
  933. for exp1, v1 in p1.items():
  934. for exp2, v2 in p2it:
  935. exp = monomial_mul(exp1, exp2)
  936. p[exp] = get(exp, zero) + v1*v2
  937. p.strip_zero()
  938. # p._check()
  939. return p
  940. elif isinstance(p2, PolyElement):
  941. if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring:
  942. pass
  943. elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring:
  944. return p2.__rmul__(p1)
  945. else:
  946. return NotImplemented
  947. try:
  948. p2 = ring.domain_new(p2)
  949. except CoercionFailed:
  950. return NotImplemented
  951. else:
  952. for exp1, v1 in p1.items():
  953. v = v1*p2
  954. if v:
  955. p[exp1] = v
  956. # p._check()
  957. return p
  958. def __rmul__(p1, p2):
  959. """p2 * p1 with p2 in the coefficient domain of p1.
  960. Examples
  961. ========
  962. >>> from sympy.polys.domains import ZZ
  963. >>> from sympy.polys.rings import ring
  964. >>> _, x, y = ring('x, y', ZZ)
  965. >>> p = x + y
  966. >>> 4 * p
  967. 4*x + 4*y
  968. """
  969. p = p1.ring.zero
  970. if not p2:
  971. return p
  972. try:
  973. p2 = p.ring.domain_new(p2)
  974. except CoercionFailed:
  975. return NotImplemented
  976. else:
  977. for exp1, v1 in p1.items():
  978. v = p2*v1
  979. if v:
  980. p[exp1] = v
  981. return p
  982. def __pow__(self, n):
  983. """raise polynomial to power `n`
  984. Examples
  985. ========
  986. >>> from sympy.polys.domains import ZZ
  987. >>> from sympy.polys.rings import ring
  988. >>> _, x, y = ring('x, y', ZZ)
  989. >>> p = x + y**2
  990. >>> p**3
  991. x**3 + 3*x**2*y**2 + 3*x*y**4 + y**6
  992. """
  993. if not isinstance(n, int):
  994. raise TypeError("exponent must be an integer, got %s" % n)
  995. elif n < 0:
  996. raise ValueError("exponent must be a non-negative integer, got %s" % n)
  997. ring = self.ring
  998. if not n:
  999. if self:
  1000. return ring.one
  1001. else:
  1002. raise ValueError("0**0")
  1003. elif len(self) == 1:
  1004. monom, coeff = list(self.items())[0]
  1005. p = ring.zero
  1006. if coeff == ring.domain.one:
  1007. p[ring.monomial_pow(monom, n)] = coeff
  1008. else:
  1009. p[ring.monomial_pow(monom, n)] = coeff**n
  1010. # p._check()
  1011. return p
  1012. # For ring series, we need negative and rational exponent support only
  1013. # with monomials.
  1014. n = int(n)
  1015. if n < 0:
  1016. raise ValueError("Negative exponent")
  1017. elif n == 1:
  1018. return self.copy()
  1019. elif n == 2:
  1020. return self.square()
  1021. elif n == 3:
  1022. return self*self.square()
  1023. elif len(self) <= 5: # TODO: use an actual density measure
  1024. return self._pow_multinomial(n)
  1025. else:
  1026. return self._pow_generic(n)
  1027. def _pow_generic(self, n):
  1028. p = self.ring.one
  1029. c = self
  1030. while True:
  1031. if n & 1:
  1032. p = p*c
  1033. n -= 1
  1034. if not n:
  1035. break
  1036. c = c.square()
  1037. n = n // 2
  1038. return p
  1039. def _pow_multinomial(self, n):
  1040. multinomials = multinomial_coefficients(len(self), n).items()
  1041. monomial_mulpow = self.ring.monomial_mulpow
  1042. zero_monom = self.ring.zero_monom
  1043. terms = self.items()
  1044. zero = self.ring.domain.zero
  1045. poly = self.ring.zero
  1046. for multinomial, multinomial_coeff in multinomials:
  1047. product_monom = zero_monom
  1048. product_coeff = multinomial_coeff
  1049. for exp, (monom, coeff) in zip(multinomial, terms):
  1050. if exp:
  1051. product_monom = monomial_mulpow(product_monom, monom, exp)
  1052. product_coeff *= coeff**exp
  1053. monom = tuple(product_monom)
  1054. coeff = product_coeff
  1055. coeff = poly.get(monom, zero) + coeff
  1056. if coeff:
  1057. poly[monom] = coeff
  1058. elif monom in poly:
  1059. del poly[monom]
  1060. return poly
  1061. def square(self):
  1062. """square of a polynomial
  1063. Examples
  1064. ========
  1065. >>> from sympy.polys.rings import ring
  1066. >>> from sympy.polys.domains import ZZ
  1067. >>> _, x, y = ring('x, y', ZZ)
  1068. >>> p = x + y**2
  1069. >>> p.square()
  1070. x**2 + 2*x*y**2 + y**4
  1071. """
  1072. ring = self.ring
  1073. p = ring.zero
  1074. get = p.get
  1075. keys = list(self.keys())
  1076. zero = ring.domain.zero
  1077. monomial_mul = ring.monomial_mul
  1078. for i in range(len(keys)):
  1079. k1 = keys[i]
  1080. pk = self[k1]
  1081. for j in range(i):
  1082. k2 = keys[j]
  1083. exp = monomial_mul(k1, k2)
  1084. p[exp] = get(exp, zero) + pk*self[k2]
  1085. p = p.imul_num(2)
  1086. get = p.get
  1087. for k, v in self.items():
  1088. k2 = monomial_mul(k, k)
  1089. p[k2] = get(k2, zero) + v**2
  1090. p.strip_zero()
  1091. # p._check()
  1092. return p
  1093. def __divmod__(p1, p2):
  1094. ring = p1.ring
  1095. if not p2:
  1096. raise ZeroDivisionError("polynomial division")
  1097. elif ring.is_element(p2):
  1098. return p1.div(p2)
  1099. elif isinstance(p2, PolyElement):
  1100. if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring:
  1101. pass
  1102. elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring:
  1103. return p2.__rdivmod__(p1)
  1104. else:
  1105. return NotImplemented
  1106. try:
  1107. p2 = ring.domain_new(p2)
  1108. except CoercionFailed:
  1109. return NotImplemented
  1110. else:
  1111. return (p1.quo_ground(p2), p1.rem_ground(p2))
  1112. def __rdivmod__(p1, p2):
  1113. ring = p1.ring
  1114. try:
  1115. p2 = ring.ground_new(p2)
  1116. except CoercionFailed:
  1117. return NotImplemented
  1118. else:
  1119. return p2.div(p1)
  1120. def __mod__(p1, p2):
  1121. ring = p1.ring
  1122. if not p2:
  1123. raise ZeroDivisionError("polynomial division")
  1124. elif ring.is_element(p2):
  1125. return p1.rem(p2)
  1126. elif isinstance(p2, PolyElement):
  1127. if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring:
  1128. pass
  1129. elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring:
  1130. return p2.__rmod__(p1)
  1131. else:
  1132. return NotImplemented
  1133. try:
  1134. p2 = ring.domain_new(p2)
  1135. except CoercionFailed:
  1136. return NotImplemented
  1137. else:
  1138. return p1.rem_ground(p2)
  1139. def __rmod__(p1, p2):
  1140. ring = p1.ring
  1141. try:
  1142. p2 = ring.ground_new(p2)
  1143. except CoercionFailed:
  1144. return NotImplemented
  1145. else:
  1146. return p2.rem(p1)
  1147. def __floordiv__(p1, p2):
  1148. ring = p1.ring
  1149. if not p2:
  1150. raise ZeroDivisionError("polynomial division")
  1151. elif ring.is_element(p2):
  1152. return p1.quo(p2)
  1153. elif isinstance(p2, PolyElement):
  1154. if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring:
  1155. pass
  1156. elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring:
  1157. return p2.__rtruediv__(p1)
  1158. else:
  1159. return NotImplemented
  1160. try:
  1161. p2 = ring.domain_new(p2)
  1162. except CoercionFailed:
  1163. return NotImplemented
  1164. else:
  1165. return p1.quo_ground(p2)
  1166. def __rfloordiv__(p1, p2):
  1167. ring = p1.ring
  1168. try:
  1169. p2 = ring.ground_new(p2)
  1170. except CoercionFailed:
  1171. return NotImplemented
  1172. else:
  1173. return p2.quo(p1)
  1174. def __truediv__(p1, p2):
  1175. ring = p1.ring
  1176. if not p2:
  1177. raise ZeroDivisionError("polynomial division")
  1178. elif ring.is_element(p2):
  1179. return p1.exquo(p2)
  1180. elif isinstance(p2, PolyElement):
  1181. if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring:
  1182. pass
  1183. elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring:
  1184. return p2.__rtruediv__(p1)
  1185. else:
  1186. return NotImplemented
  1187. try:
  1188. p2 = ring.domain_new(p2)
  1189. except CoercionFailed:
  1190. return NotImplemented
  1191. else:
  1192. return p1.quo_ground(p2)
  1193. def __rtruediv__(p1, p2):
  1194. ring = p1.ring
  1195. try:
  1196. p2 = ring.ground_new(p2)
  1197. except CoercionFailed:
  1198. return NotImplemented
  1199. else:
  1200. return p2.exquo(p1)
  1201. def _term_div(self):
  1202. zm = self.ring.zero_monom
  1203. domain = self.ring.domain
  1204. domain_quo = domain.quo
  1205. monomial_div = self.ring.monomial_div
  1206. if domain.is_Field:
  1207. def term_div(a_lm_a_lc, b_lm_b_lc):
  1208. a_lm, a_lc = a_lm_a_lc
  1209. b_lm, b_lc = b_lm_b_lc
  1210. if b_lm == zm: # apparently this is a very common case
  1211. monom = a_lm
  1212. else:
  1213. monom = monomial_div(a_lm, b_lm)
  1214. if monom is not None:
  1215. return monom, domain_quo(a_lc, b_lc)
  1216. else:
  1217. return None
  1218. else:
  1219. def term_div(a_lm_a_lc, b_lm_b_lc):
  1220. a_lm, a_lc = a_lm_a_lc
  1221. b_lm, b_lc = b_lm_b_lc
  1222. if b_lm == zm: # apparently this is a very common case
  1223. monom = a_lm
  1224. else:
  1225. monom = monomial_div(a_lm, b_lm)
  1226. if not (monom is None or a_lc % b_lc):
  1227. return monom, domain_quo(a_lc, b_lc)
  1228. else:
  1229. return None
  1230. return term_div
  1231. def div(self, fv):
  1232. """Division algorithm, see [CLO] p64.
  1233. fv array of polynomials
  1234. return qv, r such that
  1235. self = sum(fv[i]*qv[i]) + r
  1236. All polynomials are required not to be Laurent polynomials.
  1237. Examples
  1238. ========
  1239. >>> from sympy.polys.rings import ring
  1240. >>> from sympy.polys.domains import ZZ
  1241. >>> _, x, y = ring('x, y', ZZ)
  1242. >>> f = x**3
  1243. >>> f0 = x - y**2
  1244. >>> f1 = x - y
  1245. >>> qv, r = f.div((f0, f1))
  1246. >>> qv[0]
  1247. x**2 + x*y**2 + y**4
  1248. >>> qv[1]
  1249. 0
  1250. >>> r
  1251. y**6
  1252. """
  1253. ring = self.ring
  1254. ret_single = False
  1255. if isinstance(fv, PolyElement):
  1256. ret_single = True
  1257. fv = [fv]
  1258. if not all(fv):
  1259. raise ZeroDivisionError("polynomial division")
  1260. if not self:
  1261. if ret_single:
  1262. return ring.zero, ring.zero
  1263. else:
  1264. return [], ring.zero
  1265. for f in fv:
  1266. if f.ring != ring:
  1267. raise ValueError('self and f must have the same ring')
  1268. s = len(fv)
  1269. qv = [ring.zero for i in range(s)]
  1270. p = self.copy()
  1271. r = ring.zero
  1272. term_div = self._term_div()
  1273. expvs = [fx.leading_expv() for fx in fv]
  1274. while p:
  1275. i = 0
  1276. divoccurred = 0
  1277. while i < s and divoccurred == 0:
  1278. expv = p.leading_expv()
  1279. term = term_div((expv, p[expv]), (expvs[i], fv[i][expvs[i]]))
  1280. if term is not None:
  1281. expv1, c = term
  1282. qv[i] = qv[i]._iadd_monom((expv1, c))
  1283. p = p._iadd_poly_monom(fv[i], (expv1, -c))
  1284. divoccurred = 1
  1285. else:
  1286. i += 1
  1287. if not divoccurred:
  1288. expv = p.leading_expv()
  1289. r = r._iadd_monom((expv, p[expv]))
  1290. del p[expv]
  1291. if expv == ring.zero_monom:
  1292. r += p
  1293. if ret_single:
  1294. if not qv:
  1295. return ring.zero, r
  1296. else:
  1297. return qv[0], r
  1298. else:
  1299. return qv, r
  1300. def rem(self, G):
  1301. f = self
  1302. if isinstance(G, PolyElement):
  1303. G = [G]
  1304. if not all(G):
  1305. raise ZeroDivisionError("polynomial division")
  1306. ring = f.ring
  1307. domain = ring.domain
  1308. zero = domain.zero
  1309. monomial_mul = ring.monomial_mul
  1310. r = ring.zero
  1311. term_div = f._term_div()
  1312. ltf = f.LT
  1313. f = f.copy()
  1314. get = f.get
  1315. while f:
  1316. for g in G:
  1317. tq = term_div(ltf, g.LT)
  1318. if tq is not None:
  1319. m, c = tq
  1320. for mg, cg in g.iterterms():
  1321. m1 = monomial_mul(mg, m)
  1322. c1 = get(m1, zero) - c*cg
  1323. if not c1:
  1324. del f[m1]
  1325. else:
  1326. f[m1] = c1
  1327. ltm = f.leading_expv()
  1328. if ltm is not None:
  1329. ltf = ltm, f[ltm]
  1330. break
  1331. else:
  1332. ltm, ltc = ltf
  1333. if ltm in r:
  1334. r[ltm] += ltc
  1335. else:
  1336. r[ltm] = ltc
  1337. del f[ltm]
  1338. ltm = f.leading_expv()
  1339. if ltm is not None:
  1340. ltf = ltm, f[ltm]
  1341. return r
  1342. def quo(f, G):
  1343. return f.div(G)[0]
  1344. def exquo(f, G):
  1345. q, r = f.div(G)
  1346. if not r:
  1347. return q
  1348. else:
  1349. raise ExactQuotientFailed(f, G)
  1350. def _iadd_monom(self, mc):
  1351. """add to self the monomial coeff*x0**i0*x1**i1*...
  1352. unless self is a generator -- then just return the sum of the two.
  1353. mc is a tuple, (monom, coeff), where monomial is (i0, i1, ...)
  1354. Examples
  1355. ========
  1356. >>> from sympy.polys.rings import ring
  1357. >>> from sympy.polys.domains import ZZ
  1358. >>> _, x, y = ring('x, y', ZZ)
  1359. >>> p = x**4 + 2*y
  1360. >>> m = (1, 2)
  1361. >>> p1 = p._iadd_monom((m, 5))
  1362. >>> p1
  1363. x**4 + 5*x*y**2 + 2*y
  1364. >>> p1 is p
  1365. True
  1366. >>> p = x
  1367. >>> p1 = p._iadd_monom((m, 5))
  1368. >>> p1
  1369. 5*x*y**2 + x
  1370. >>> p1 is p
  1371. False
  1372. """
  1373. if self in self.ring._gens_set:
  1374. cpself = self.copy()
  1375. else:
  1376. cpself = self
  1377. expv, coeff = mc
  1378. c = cpself.get(expv)
  1379. if c is None:
  1380. cpself[expv] = coeff
  1381. else:
  1382. c += coeff
  1383. if c:
  1384. cpself[expv] = c
  1385. else:
  1386. del cpself[expv]
  1387. return cpself
  1388. def _iadd_poly_monom(self, p2, mc):
  1389. """add to self the product of (p)*(coeff*x0**i0*x1**i1*...)
  1390. unless self is a generator -- then just return the sum of the two.
  1391. mc is a tuple, (monom, coeff), where monomial is (i0, i1, ...)
  1392. Examples
  1393. ========
  1394. >>> from sympy.polys.rings import ring
  1395. >>> from sympy.polys.domains import ZZ
  1396. >>> _, x, y, z = ring('x, y, z', ZZ)
  1397. >>> p1 = x**4 + 2*y
  1398. >>> p2 = y + z
  1399. >>> m = (1, 2, 3)
  1400. >>> p1 = p1._iadd_poly_monom(p2, (m, 3))
  1401. >>> p1
  1402. x**4 + 3*x*y**3*z**3 + 3*x*y**2*z**4 + 2*y
  1403. """
  1404. p1 = self
  1405. if p1 in p1.ring._gens_set:
  1406. p1 = p1.copy()
  1407. (m, c) = mc
  1408. get = p1.get
  1409. zero = p1.ring.domain.zero
  1410. monomial_mul = p1.ring.monomial_mul
  1411. for k, v in p2.items():
  1412. ka = monomial_mul(k, m)
  1413. coeff = get(ka, zero) + v*c
  1414. if coeff:
  1415. p1[ka] = coeff
  1416. else:
  1417. del p1[ka]
  1418. return p1
  1419. def degree(f, x=None):
  1420. """
  1421. The leading degree in ``x`` or the main variable.
  1422. Note that the degree of 0 is negative infinity (``float('-inf')``)
  1423. """
  1424. i = f.ring.index(x)
  1425. if not f:
  1426. return ninf
  1427. elif i < 0:
  1428. return 0
  1429. else:
  1430. return max(monom[i] for monom in f.itermonoms())
  1431. def degrees(f):
  1432. """
  1433. A tuple containing leading degrees in all variables.
  1434. Note that the degree of 0 is negative infinity (``float('-inf')``)
  1435. """
  1436. if not f:
  1437. return (ninf,)*f.ring.ngens
  1438. else:
  1439. return tuple(map(max, list(zip(*f.itermonoms()))))
  1440. def tail_degree(f, x=None):
  1441. """
  1442. The tail degree in ``x`` or the main variable.
  1443. Note that the degree of 0 is negative infinity (``float('-inf')``)
  1444. """
  1445. i = f.ring.index(x)
  1446. if not f:
  1447. return ninf
  1448. elif i < 0:
  1449. return 0
  1450. else:
  1451. return min(monom[i] for monom in f.itermonoms())
  1452. def tail_degrees(f):
  1453. """
  1454. A tuple containing tail degrees in all variables.
  1455. Note that the degree of 0 is negative infinity (``float('-inf')``)
  1456. """
  1457. if not f:
  1458. return (ninf,)*f.ring.ngens
  1459. else:
  1460. return tuple(map(min, list(zip(*f.itermonoms()))))
  1461. def leading_expv(self):
  1462. """Leading monomial tuple according to the monomial ordering.
  1463. Examples
  1464. ========
  1465. >>> from sympy.polys.rings import ring
  1466. >>> from sympy.polys.domains import ZZ
  1467. >>> _, x, y, z = ring('x, y, z', ZZ)
  1468. >>> p = x**4 + x**3*y + x**2*z**2 + z**7
  1469. >>> p.leading_expv()
  1470. (4, 0, 0)
  1471. """
  1472. if self:
  1473. return self.ring.leading_expv(self)
  1474. else:
  1475. return None
  1476. def _get_coeff(self, expv):
  1477. return self.get(expv, self.ring.domain.zero)
  1478. def coeff(self, element):
  1479. """
  1480. Returns the coefficient that stands next to the given monomial.
  1481. Parameters
  1482. ==========
  1483. element : PolyElement (with ``is_monomial = True``) or 1
  1484. Examples
  1485. ========
  1486. >>> from sympy.polys.rings import ring
  1487. >>> from sympy.polys.domains import ZZ
  1488. >>> _, x, y, z = ring("x,y,z", ZZ)
  1489. >>> f = 3*x**2*y - x*y*z + 7*z**3 + 23
  1490. >>> f.coeff(x**2*y)
  1491. 3
  1492. >>> f.coeff(x*y)
  1493. 0
  1494. >>> f.coeff(1)
  1495. 23
  1496. """
  1497. if element == 1:
  1498. return self._get_coeff(self.ring.zero_monom)
  1499. elif self.ring.is_element(element):
  1500. terms = list(element.iterterms())
  1501. if len(terms) == 1:
  1502. monom, coeff = terms[0]
  1503. if coeff == self.ring.domain.one:
  1504. return self._get_coeff(monom)
  1505. raise ValueError("expected a monomial, got %s" % element)
  1506. def const(self):
  1507. """Returns the constant coefficient. """
  1508. return self._get_coeff(self.ring.zero_monom)
  1509. @property
  1510. def LC(self):
  1511. return self._get_coeff(self.leading_expv())
  1512. @property
  1513. def LM(self):
  1514. expv = self.leading_expv()
  1515. if expv is None:
  1516. return self.ring.zero_monom
  1517. else:
  1518. return expv
  1519. def leading_monom(self):
  1520. """
  1521. Leading monomial as a polynomial element.
  1522. Examples
  1523. ========
  1524. >>> from sympy.polys.rings import ring
  1525. >>> from sympy.polys.domains import ZZ
  1526. >>> _, x, y = ring('x, y', ZZ)
  1527. >>> (3*x*y + y**2).leading_monom()
  1528. x*y
  1529. """
  1530. p = self.ring.zero
  1531. expv = self.leading_expv()
  1532. if expv:
  1533. p[expv] = self.ring.domain.one
  1534. return p
  1535. @property
  1536. def LT(self):
  1537. expv = self.leading_expv()
  1538. if expv is None:
  1539. return (self.ring.zero_monom, self.ring.domain.zero)
  1540. else:
  1541. return (expv, self._get_coeff(expv))
  1542. def leading_term(self):
  1543. """Leading term as a polynomial element.
  1544. Examples
  1545. ========
  1546. >>> from sympy.polys.rings import ring
  1547. >>> from sympy.polys.domains import ZZ
  1548. >>> _, x, y = ring('x, y', ZZ)
  1549. >>> (3*x*y + y**2).leading_term()
  1550. 3*x*y
  1551. """
  1552. p = self.ring.zero
  1553. expv = self.leading_expv()
  1554. if expv is not None:
  1555. p[expv] = self[expv]
  1556. return p
  1557. def _sorted(self, seq, order):
  1558. if order is None:
  1559. order = self.ring.order
  1560. else:
  1561. order = OrderOpt.preprocess(order)
  1562. if order is lex:
  1563. return sorted(seq, key=lambda monom: monom[0], reverse=True)
  1564. else:
  1565. return sorted(seq, key=lambda monom: order(monom[0]), reverse=True)
  1566. def coeffs(self, order=None):
  1567. """Ordered list of polynomial coefficients.
  1568. Parameters
  1569. ==========
  1570. order : :class:`~.MonomialOrder` or coercible, optional
  1571. Examples
  1572. ========
  1573. >>> from sympy.polys.rings import ring
  1574. >>> from sympy.polys.domains import ZZ
  1575. >>> from sympy.polys.orderings import lex, grlex
  1576. >>> _, x, y = ring("x, y", ZZ, lex)
  1577. >>> f = x*y**7 + 2*x**2*y**3
  1578. >>> f.coeffs()
  1579. [2, 1]
  1580. >>> f.coeffs(grlex)
  1581. [1, 2]
  1582. """
  1583. return [ coeff for _, coeff in self.terms(order) ]
  1584. def monoms(self, order=None):
  1585. """Ordered list of polynomial monomials.
  1586. Parameters
  1587. ==========
  1588. order : :class:`~.MonomialOrder` or coercible, optional
  1589. Examples
  1590. ========
  1591. >>> from sympy.polys.rings import ring
  1592. >>> from sympy.polys.domains import ZZ
  1593. >>> from sympy.polys.orderings import lex, grlex
  1594. >>> _, x, y = ring("x, y", ZZ, lex)
  1595. >>> f = x*y**7 + 2*x**2*y**3
  1596. >>> f.monoms()
  1597. [(2, 3), (1, 7)]
  1598. >>> f.monoms(grlex)
  1599. [(1, 7), (2, 3)]
  1600. """
  1601. return [ monom for monom, _ in self.terms(order) ]
  1602. def terms(self, order=None):
  1603. """Ordered list of polynomial terms.
  1604. Parameters
  1605. ==========
  1606. order : :class:`~.MonomialOrder` or coercible, optional
  1607. Examples
  1608. ========
  1609. >>> from sympy.polys.rings import ring
  1610. >>> from sympy.polys.domains import ZZ
  1611. >>> from sympy.polys.orderings import lex, grlex
  1612. >>> _, x, y = ring("x, y", ZZ, lex)
  1613. >>> f = x*y**7 + 2*x**2*y**3
  1614. >>> f.terms()
  1615. [((2, 3), 2), ((1, 7), 1)]
  1616. >>> f.terms(grlex)
  1617. [((1, 7), 1), ((2, 3), 2)]
  1618. """
  1619. return self._sorted(list(self.items()), order)
  1620. def itercoeffs(self):
  1621. """Iterator over coefficients of a polynomial. """
  1622. return iter(self.values())
  1623. def itermonoms(self):
  1624. """Iterator over monomials of a polynomial. """
  1625. return iter(self.keys())
  1626. def iterterms(self):
  1627. """Iterator over terms of a polynomial. """
  1628. return iter(self.items())
  1629. def listcoeffs(self):
  1630. """Unordered list of polynomial coefficients. """
  1631. return list(self.values())
  1632. def listmonoms(self):
  1633. """Unordered list of polynomial monomials. """
  1634. return list(self.keys())
  1635. def listterms(self):
  1636. """Unordered list of polynomial terms. """
  1637. return list(self.items())
  1638. def imul_num(p, c):
  1639. """multiply inplace the polynomial p by an element in the
  1640. coefficient ring, provided p is not one of the generators;
  1641. else multiply not inplace
  1642. Examples
  1643. ========
  1644. >>> from sympy.polys.rings import ring
  1645. >>> from sympy.polys.domains import ZZ
  1646. >>> _, x, y = ring('x, y', ZZ)
  1647. >>> p = x + y**2
  1648. >>> p1 = p.imul_num(3)
  1649. >>> p1
  1650. 3*x + 3*y**2
  1651. >>> p1 is p
  1652. True
  1653. >>> p = x
  1654. >>> p1 = p.imul_num(3)
  1655. >>> p1
  1656. 3*x
  1657. >>> p1 is p
  1658. False
  1659. """
  1660. if p in p.ring._gens_set:
  1661. return p*c
  1662. if not c:
  1663. p.clear()
  1664. return
  1665. for exp in p:
  1666. p[exp] *= c
  1667. return p
  1668. def content(f):
  1669. """Returns GCD of polynomial's coefficients. """
  1670. domain = f.ring.domain
  1671. cont = domain.zero
  1672. gcd = domain.gcd
  1673. for coeff in f.itercoeffs():
  1674. cont = gcd(cont, coeff)
  1675. return cont
  1676. def primitive(f):
  1677. """Returns content and a primitive polynomial. """
  1678. cont = f.content()
  1679. if cont == f.ring.domain.zero:
  1680. return (cont, f)
  1681. return cont, f.quo_ground(cont)
  1682. def monic(f):
  1683. """Divides all coefficients by the leading coefficient. """
  1684. if not f:
  1685. return f
  1686. else:
  1687. return f.quo_ground(f.LC)
  1688. def mul_ground(f, x):
  1689. if not x:
  1690. return f.ring.zero
  1691. terms = [ (monom, coeff*x) for monom, coeff in f.iterterms() ]
  1692. return f.new(terms)
  1693. def mul_monom(f, monom):
  1694. monomial_mul = f.ring.monomial_mul
  1695. terms = [ (monomial_mul(f_monom, monom), f_coeff) for f_monom, f_coeff in f.items() ]
  1696. return f.new(terms)
  1697. def mul_term(f, term):
  1698. monom, coeff = term
  1699. if not f or not coeff:
  1700. return f.ring.zero
  1701. elif monom == f.ring.zero_monom:
  1702. return f.mul_ground(coeff)
  1703. monomial_mul = f.ring.monomial_mul
  1704. terms = [ (monomial_mul(f_monom, monom), f_coeff*coeff) for f_monom, f_coeff in f.items() ]
  1705. return f.new(terms)
  1706. def quo_ground(f, x):
  1707. domain = f.ring.domain
  1708. if not x:
  1709. raise ZeroDivisionError('polynomial division')
  1710. if not f or x == domain.one:
  1711. return f
  1712. if domain.is_Field:
  1713. quo = domain.quo
  1714. terms = [ (monom, quo(coeff, x)) for monom, coeff in f.iterterms() ]
  1715. else:
  1716. terms = [ (monom, coeff // x) for monom, coeff in f.iterterms() if not (coeff % x) ]
  1717. return f.new(terms)
  1718. def quo_term(f, term):
  1719. monom, coeff = term
  1720. if not coeff:
  1721. raise ZeroDivisionError("polynomial division")
  1722. elif not f:
  1723. return f.ring.zero
  1724. elif monom == f.ring.zero_monom:
  1725. return f.quo_ground(coeff)
  1726. term_div = f._term_div()
  1727. terms = [ term_div(t, term) for t in f.iterterms() ]
  1728. return f.new([ t for t in terms if t is not None ])
  1729. def trunc_ground(f, p):
  1730. if f.ring.domain.is_ZZ:
  1731. terms = []
  1732. for monom, coeff in f.iterterms():
  1733. coeff = coeff % p
  1734. if coeff > p // 2:
  1735. coeff = coeff - p
  1736. terms.append((monom, coeff))
  1737. else:
  1738. terms = [ (monom, coeff % p) for monom, coeff in f.iterterms() ]
  1739. poly = f.new(terms)
  1740. poly.strip_zero()
  1741. return poly
  1742. rem_ground = trunc_ground
  1743. def extract_ground(self, g):
  1744. f = self
  1745. fc = f.content()
  1746. gc = g.content()
  1747. gcd = f.ring.domain.gcd(fc, gc)
  1748. f = f.quo_ground(gcd)
  1749. g = g.quo_ground(gcd)
  1750. return gcd, f, g
  1751. def _norm(f, norm_func):
  1752. if not f:
  1753. return f.ring.domain.zero
  1754. else:
  1755. ground_abs = f.ring.domain.abs
  1756. return norm_func([ ground_abs(coeff) for coeff in f.itercoeffs() ])
  1757. def max_norm(f):
  1758. return f._norm(max)
  1759. def l1_norm(f):
  1760. return f._norm(sum)
  1761. def deflate(f, *G):
  1762. ring = f.ring
  1763. polys = [f] + list(G)
  1764. J = [0]*ring.ngens
  1765. for p in polys:
  1766. for monom in p.itermonoms():
  1767. for i, m in enumerate(monom):
  1768. J[i] = igcd(J[i], m)
  1769. for i, b in enumerate(J):
  1770. if not b:
  1771. J[i] = 1
  1772. J = tuple(J)
  1773. if all(b == 1 for b in J):
  1774. return J, polys
  1775. H = []
  1776. for p in polys:
  1777. h = ring.zero
  1778. for I, coeff in p.iterterms():
  1779. N = [ i // j for i, j in zip(I, J) ]
  1780. h[tuple(N)] = coeff
  1781. H.append(h)
  1782. return J, H
  1783. def inflate(f, J):
  1784. poly = f.ring.zero
  1785. for I, coeff in f.iterterms():
  1786. N = [ i*j for i, j in zip(I, J) ]
  1787. poly[tuple(N)] = coeff
  1788. return poly
  1789. def lcm(self, g):
  1790. f = self
  1791. domain = f.ring.domain
  1792. if not domain.is_Field:
  1793. fc, f = f.primitive()
  1794. gc, g = g.primitive()
  1795. c = domain.lcm(fc, gc)
  1796. h = (f*g).quo(f.gcd(g))
  1797. if not domain.is_Field:
  1798. return h.mul_ground(c)
  1799. else:
  1800. return h.monic()
  1801. def gcd(f, g):
  1802. return f.cofactors(g)[0]
  1803. def cofactors(f, g):
  1804. if not f and not g:
  1805. zero = f.ring.zero
  1806. return zero, zero, zero
  1807. elif not f:
  1808. h, cff, cfg = f._gcd_zero(g)
  1809. return h, cff, cfg
  1810. elif not g:
  1811. h, cfg, cff = g._gcd_zero(f)
  1812. return h, cff, cfg
  1813. elif len(f) == 1:
  1814. h, cff, cfg = f._gcd_monom(g)
  1815. return h, cff, cfg
  1816. elif len(g) == 1:
  1817. h, cfg, cff = g._gcd_monom(f)
  1818. return h, cff, cfg
  1819. J, (f, g) = f.deflate(g)
  1820. h, cff, cfg = f._gcd(g)
  1821. return (h.inflate(J), cff.inflate(J), cfg.inflate(J))
  1822. def _gcd_zero(f, g):
  1823. one, zero = f.ring.one, f.ring.zero
  1824. if g.is_nonnegative:
  1825. return g, zero, one
  1826. else:
  1827. return -g, zero, -one
  1828. def _gcd_monom(f, g):
  1829. ring = f.ring
  1830. ground_gcd = ring.domain.gcd
  1831. ground_quo = ring.domain.quo
  1832. monomial_gcd = ring.monomial_gcd
  1833. monomial_ldiv = ring.monomial_ldiv
  1834. mf, cf = list(f.iterterms())[0]
  1835. _mgcd, _cgcd = mf, cf
  1836. for mg, cg in g.iterterms():
  1837. _mgcd = monomial_gcd(_mgcd, mg)
  1838. _cgcd = ground_gcd(_cgcd, cg)
  1839. h = f.new([(_mgcd, _cgcd)])
  1840. cff = f.new([(monomial_ldiv(mf, _mgcd), ground_quo(cf, _cgcd))])
  1841. cfg = f.new([(monomial_ldiv(mg, _mgcd), ground_quo(cg, _cgcd)) for mg, cg in g.iterterms()])
  1842. return h, cff, cfg
  1843. def _gcd(f, g):
  1844. ring = f.ring
  1845. if ring.domain.is_QQ:
  1846. return f._gcd_QQ(g)
  1847. elif ring.domain.is_ZZ:
  1848. return f._gcd_ZZ(g)
  1849. else: # TODO: don't use dense representation (port PRS algorithms)
  1850. return ring.dmp_inner_gcd(f, g)
  1851. def _gcd_ZZ(f, g):
  1852. return heugcd(f, g)
  1853. def _gcd_QQ(self, g):
  1854. f = self
  1855. ring = f.ring
  1856. new_ring = ring.clone(domain=ring.domain.get_ring())
  1857. cf, f = f.clear_denoms()
  1858. cg, g = g.clear_denoms()
  1859. f = f.set_ring(new_ring)
  1860. g = g.set_ring(new_ring)
  1861. h, cff, cfg = f._gcd_ZZ(g)
  1862. h = h.set_ring(ring)
  1863. c, h = h.LC, h.monic()
  1864. cff = cff.set_ring(ring).mul_ground(ring.domain.quo(c, cf))
  1865. cfg = cfg.set_ring(ring).mul_ground(ring.domain.quo(c, cg))
  1866. return h, cff, cfg
  1867. def cancel(self, g):
  1868. """
  1869. Cancel common factors in a rational function ``f/g``.
  1870. Examples
  1871. ========
  1872. >>> from sympy.polys import ring, ZZ
  1873. >>> R, x,y = ring("x,y", ZZ)
  1874. >>> (2*x**2 - 2).cancel(x**2 - 2*x + 1)
  1875. (2*x + 2, x - 1)
  1876. """
  1877. f = self
  1878. ring = f.ring
  1879. if not f:
  1880. return f, ring.one
  1881. domain = ring.domain
  1882. if not (domain.is_Field and domain.has_assoc_Ring):
  1883. _, p, q = f.cofactors(g)
  1884. else:
  1885. new_ring = ring.clone(domain=domain.get_ring())
  1886. cq, f = f.clear_denoms()
  1887. cp, g = g.clear_denoms()
  1888. f = f.set_ring(new_ring)
  1889. g = g.set_ring(new_ring)
  1890. _, p, q = f.cofactors(g)
  1891. _, cp, cq = new_ring.domain.cofactors(cp, cq)
  1892. p = p.set_ring(ring)
  1893. q = q.set_ring(ring)
  1894. p = p.mul_ground(cp)
  1895. q = q.mul_ground(cq)
  1896. # Make canonical with respect to sign or quadrant in the case of ZZ_I
  1897. # or QQ_I. This ensures that the LC of the denominator is canonical by
  1898. # multiplying top and bottom by a unit of the ring.
  1899. u = q.canonical_unit()
  1900. if u == domain.one:
  1901. pass
  1902. elif u == -domain.one:
  1903. p, q = -p, -q
  1904. else:
  1905. p = p.mul_ground(u)
  1906. q = q.mul_ground(u)
  1907. return p, q
  1908. def canonical_unit(f):
  1909. domain = f.ring.domain
  1910. return domain.canonical_unit(f.LC)
  1911. def diff(f, x):
  1912. """Computes partial derivative in ``x``.
  1913. Examples
  1914. ========
  1915. >>> from sympy.polys.rings import ring
  1916. >>> from sympy.polys.domains import ZZ
  1917. >>> _, x, y = ring("x,y", ZZ)
  1918. >>> p = x + x**2*y**3
  1919. >>> p.diff(x)
  1920. 2*x*y**3 + 1
  1921. """
  1922. ring = f.ring
  1923. i = ring.index(x)
  1924. m = ring.monomial_basis(i)
  1925. g = ring.zero
  1926. for expv, coeff in f.iterterms():
  1927. if expv[i]:
  1928. e = ring.monomial_ldiv(expv, m)
  1929. g[e] = ring.domain_new(coeff*expv[i])
  1930. return g
  1931. def __call__(f, *values):
  1932. if 0 < len(values) <= f.ring.ngens:
  1933. return f.evaluate(list(zip(f.ring.gens, values)))
  1934. else:
  1935. raise ValueError("expected at least 1 and at most %s values, got %s" % (f.ring.ngens, len(values)))
  1936. def evaluate(self, x, a=None):
  1937. f = self
  1938. if isinstance(x, list) and a is None:
  1939. (X, a), x = x[0], x[1:]
  1940. f = f.evaluate(X, a)
  1941. if not x:
  1942. return f
  1943. else:
  1944. x = [ (Y.drop(X), a) for (Y, a) in x ]
  1945. return f.evaluate(x)
  1946. ring = f.ring
  1947. i = ring.index(x)
  1948. a = ring.domain.convert(a)
  1949. if ring.ngens == 1:
  1950. result = ring.domain.zero
  1951. for (n,), coeff in f.iterterms():
  1952. result += coeff*a**n
  1953. return result
  1954. else:
  1955. poly = ring.drop(x).zero
  1956. for monom, coeff in f.iterterms():
  1957. n, monom = monom[i], monom[:i] + monom[i+1:]
  1958. coeff = coeff*a**n
  1959. if monom in poly:
  1960. coeff = coeff + poly[monom]
  1961. if coeff:
  1962. poly[monom] = coeff
  1963. else:
  1964. del poly[monom]
  1965. else:
  1966. if coeff:
  1967. poly[monom] = coeff
  1968. return poly
  1969. def subs(self, x, a=None):
  1970. f = self
  1971. if isinstance(x, list) and a is None:
  1972. for X, a in x:
  1973. f = f.subs(X, a)
  1974. return f
  1975. ring = f.ring
  1976. i = ring.index(x)
  1977. a = ring.domain.convert(a)
  1978. if ring.ngens == 1:
  1979. result = ring.domain.zero
  1980. for (n,), coeff in f.iterterms():
  1981. result += coeff*a**n
  1982. return ring.ground_new(result)
  1983. else:
  1984. poly = ring.zero
  1985. for monom, coeff in f.iterterms():
  1986. n, monom = monom[i], monom[:i] + (0,) + monom[i+1:]
  1987. coeff = coeff*a**n
  1988. if monom in poly:
  1989. coeff = coeff + poly[monom]
  1990. if coeff:
  1991. poly[monom] = coeff
  1992. else:
  1993. del poly[monom]
  1994. else:
  1995. if coeff:
  1996. poly[monom] = coeff
  1997. return poly
  1998. def symmetrize(self):
  1999. r"""
  2000. Rewrite *self* in terms of elementary symmetric polynomials.
  2001. Explanation
  2002. ===========
  2003. If this :py:class:`~.PolyElement` belongs to a ring of $n$ variables,
  2004. we can try to write it as a function of the elementary symmetric
  2005. polynomials on $n$ variables. We compute a symmetric part, and a
  2006. remainder for any part we were not able to symmetrize.
  2007. Examples
  2008. ========
  2009. >>> from sympy.polys.rings import ring
  2010. >>> from sympy.polys.domains import ZZ
  2011. >>> R, x, y = ring("x,y", ZZ)
  2012. >>> f = x**2 + y**2
  2013. >>> f.symmetrize()
  2014. (x**2 - 2*y, 0, [(x, x + y), (y, x*y)])
  2015. >>> f = x**2 - y**2
  2016. >>> f.symmetrize()
  2017. (x**2 - 2*y, -2*y**2, [(x, x + y), (y, x*y)])
  2018. Returns
  2019. =======
  2020. Triple ``(p, r, m)``
  2021. ``p`` is a :py:class:`~.PolyElement` that represents our attempt
  2022. to express *self* as a function of elementary symmetric
  2023. polynomials. Each variable in ``p`` stands for one of the
  2024. elementary symmetric polynomials. The correspondence is given
  2025. by ``m``.
  2026. ``r`` is the remainder.
  2027. ``m`` is a list of pairs, giving the mapping from variables in
  2028. ``p`` to elementary symmetric polynomials.
  2029. The triple satisfies the equation ``p.compose(m) + r == self``.
  2030. If the remainder ``r`` is zero, *self* is symmetric. If it is
  2031. nonzero, we were not able to represent *self* as symmetric.
  2032. See Also
  2033. ========
  2034. sympy.polys.polyfuncs.symmetrize
  2035. References
  2036. ==========
  2037. .. [1] Lauer, E. Algorithms for symmetrical polynomials, Proc. 1976
  2038. ACM Symp. on Symbolic and Algebraic Computing, NY 242-247.
  2039. https://dl.acm.org/doi/pdf/10.1145/800205.806342
  2040. """
  2041. f = self.copy()
  2042. ring = f.ring
  2043. n = ring.ngens
  2044. if not n:
  2045. return f, ring.zero, []
  2046. polys = [ring.symmetric_poly(i+1) for i in range(n)]
  2047. poly_powers = {}
  2048. def get_poly_power(i, n):
  2049. if (i, n) not in poly_powers:
  2050. poly_powers[(i, n)] = polys[i]**n
  2051. return poly_powers[(i, n)]
  2052. indices = list(range(n - 1))
  2053. weights = list(range(n, 0, -1))
  2054. symmetric = ring.zero
  2055. while f:
  2056. _height, _monom, _coeff = -1, None, None
  2057. for i, (monom, coeff) in enumerate(f.terms()):
  2058. if all(monom[i] >= monom[i + 1] for i in indices):
  2059. height = max(n*m for n, m in zip(weights, monom))
  2060. if height > _height:
  2061. _height, _monom, _coeff = height, monom, coeff
  2062. if _height != -1:
  2063. monom, coeff = _monom, _coeff
  2064. else:
  2065. break
  2066. exponents = []
  2067. for m1, m2 in zip(monom, monom[1:] + (0,)):
  2068. exponents.append(m1 - m2)
  2069. symmetric += ring.term_new(tuple(exponents), coeff)
  2070. product = coeff
  2071. for i, n in enumerate(exponents):
  2072. product *= get_poly_power(i, n)
  2073. f -= product
  2074. mapping = list(zip(ring.gens, polys))
  2075. return symmetric, f, mapping
  2076. def compose(f, x, a=None):
  2077. ring = f.ring
  2078. poly = ring.zero
  2079. gens_map = dict(zip(ring.gens, range(ring.ngens)))
  2080. if a is not None:
  2081. replacements = [(x, a)]
  2082. else:
  2083. if isinstance(x, list):
  2084. replacements = list(x)
  2085. elif isinstance(x, dict):
  2086. replacements = sorted(x.items(), key=lambda k: gens_map[k[0]])
  2087. else:
  2088. raise ValueError("expected a generator, value pair a sequence of such pairs")
  2089. for k, (x, g) in enumerate(replacements):
  2090. replacements[k] = (gens_map[x], ring.ring_new(g))
  2091. for monom, coeff in f.iterterms():
  2092. monom = list(monom)
  2093. subpoly = ring.one
  2094. for i, g in replacements:
  2095. n, monom[i] = monom[i], 0
  2096. if n:
  2097. subpoly *= g**n
  2098. subpoly = subpoly.mul_term((tuple(monom), coeff))
  2099. poly += subpoly
  2100. return poly
  2101. def coeff_wrt(self, x, deg):
  2102. """
  2103. Coefficient of ``self`` with respect to ``x**deg``.
  2104. Treating ``self`` as a univariate polynomial in ``x`` this finds the
  2105. coefficient of ``x**deg`` as a polynomial in the other generators.
  2106. Parameters
  2107. ==========
  2108. x : generator or generator index
  2109. The generator or generator index to compute the expression for.
  2110. deg : int
  2111. The degree of the monomial to compute the expression for.
  2112. Returns
  2113. =======
  2114. :py:class:`~.PolyElement`
  2115. The coefficient of ``x**deg`` as a polynomial in the same ring.
  2116. Examples
  2117. ========
  2118. >>> from sympy.polys import ring, ZZ
  2119. >>> R, x, y, z = ring("x, y, z", ZZ)
  2120. >>> p = 2*x**4 + 3*y**4 + 10*z**2 + 10*x*z**2
  2121. >>> deg = 2
  2122. >>> p.coeff_wrt(2, deg) # Using the generator index
  2123. 10*x + 10
  2124. >>> p.coeff_wrt(z, deg) # Using the generator
  2125. 10*x + 10
  2126. >>> p.coeff(z**2) # shows the difference between coeff and coeff_wrt
  2127. 10
  2128. See Also
  2129. ========
  2130. coeff, coeffs
  2131. """
  2132. p = self
  2133. i = p.ring.index(x)
  2134. terms = [(m, c) for m, c in p.iterterms() if m[i] == deg]
  2135. if not terms:
  2136. return p.ring.zero
  2137. monoms, coeffs = zip(*terms)
  2138. monoms = [m[:i] + (0,) + m[i + 1:] for m in monoms]
  2139. return p.ring.from_dict(dict(zip(monoms, coeffs)))
  2140. def prem(self, g, x=None):
  2141. """
  2142. Pseudo-remainder of the polynomial ``self`` with respect to ``g``.
  2143. The pseudo-quotient ``q`` and pseudo-remainder ``r`` with respect to
  2144. ``z`` when dividing ``f`` by ``g`` satisfy ``m*f = g*q + r``,
  2145. where ``deg(r,z) < deg(g,z)`` and
  2146. ``m = LC(g,z)**(deg(f,z) - deg(g,z)+1)``.
  2147. See :meth:`pdiv` for explanation of pseudo-division.
  2148. Parameters
  2149. ==========
  2150. g : :py:class:`~.PolyElement`
  2151. The polynomial to divide ``self`` by.
  2152. x : generator or generator index, optional
  2153. The main variable of the polynomials and default is first generator.
  2154. Returns
  2155. =======
  2156. :py:class:`~.PolyElement`
  2157. The pseudo-remainder polynomial.
  2158. Raises
  2159. ======
  2160. ZeroDivisionError : If ``g`` is the zero polynomial.
  2161. Examples
  2162. ========
  2163. >>> from sympy.polys import ring, ZZ
  2164. >>> R, x, y = ring("x, y", ZZ)
  2165. >>> f = x**2 + x*y
  2166. >>> g = 2*x + 2
  2167. >>> f.prem(g) # first generator is chosen by default if it is not given
  2168. -4*y + 4
  2169. >>> f.rem(g) # shows the difference between prem and rem
  2170. x**2 + x*y
  2171. >>> f.prem(g, y) # generator is given
  2172. 0
  2173. >>> f.prem(g, 1) # generator index is given
  2174. 0
  2175. See Also
  2176. ========
  2177. pdiv, pquo, pexquo, sympy.polys.domains.ring.Ring.rem
  2178. """
  2179. f = self
  2180. x = f.ring.index(x)
  2181. df = f.degree(x)
  2182. dg = g.degree(x)
  2183. if dg < 0:
  2184. raise ZeroDivisionError('polynomial division')
  2185. r, dr = f, df
  2186. if df < dg:
  2187. return r
  2188. N = df - dg + 1
  2189. lc_g = g.coeff_wrt(x, dg)
  2190. xp = f.ring.gens[x]
  2191. while True:
  2192. lc_r = r.coeff_wrt(x, dr)
  2193. j, N = dr - dg, N - 1
  2194. R = r * lc_g
  2195. G = g * lc_r * xp**j
  2196. r = R - G
  2197. dr = r.degree(x)
  2198. if dr < dg:
  2199. break
  2200. c = lc_g ** N
  2201. return r * c
  2202. def pdiv(self, g, x=None):
  2203. """
  2204. Computes the pseudo-division of the polynomial ``self`` with respect to ``g``.
  2205. The pseudo-division algorithm is used to find the pseudo-quotient ``q``
  2206. and pseudo-remainder ``r`` such that ``m*f = g*q + r``, where ``m``
  2207. represents the multiplier and ``f`` is the dividend polynomial.
  2208. The pseudo-quotient ``q`` and pseudo-remainder ``r`` are polynomials in
  2209. the variable ``x``, with the degree of ``r`` with respect to ``x``
  2210. being strictly less than the degree of ``g`` with respect to ``x``.
  2211. The multiplier ``m`` is defined as
  2212. ``LC(g, x) ^ (deg(f, x) - deg(g, x) + 1)``,
  2213. where ``LC(g, x)`` represents the leading coefficient of ``g``.
  2214. It is important to note that in the context of the ``prem`` method,
  2215. multivariate polynomials in a ring, such as ``R[x,y,z]``, are treated
  2216. as univariate polynomials with coefficients that are polynomials,
  2217. such as ``R[x,y][z]``. When dividing ``f`` by ``g`` with respect to the
  2218. variable ``z``, the pseudo-quotient ``q`` and pseudo-remainder ``r``
  2219. satisfy ``m*f = g*q + r``, where ``deg(r, z) < deg(g, z)``
  2220. and ``m = LC(g, z)^(deg(f, z) - deg(g, z) + 1)``.
  2221. In this function, the pseudo-remainder ``r`` can be obtained using the
  2222. ``prem`` method, the pseudo-quotient ``q`` can
  2223. be obtained using the ``pquo`` method, and
  2224. the function ``pdiv`` itself returns a tuple ``(q, r)``.
  2225. Parameters
  2226. ==========
  2227. g : :py:class:`~.PolyElement`
  2228. The polynomial to divide ``self`` by.
  2229. x : generator or generator index, optional
  2230. The main variable of the polynomials and default is first generator.
  2231. Returns
  2232. =======
  2233. :py:class:`~.PolyElement`
  2234. The pseudo-division polynomial (tuple of ``q`` and ``r``).
  2235. Raises
  2236. ======
  2237. ZeroDivisionError : If ``g`` is the zero polynomial.
  2238. Examples
  2239. ========
  2240. >>> from sympy.polys import ring, ZZ
  2241. >>> R, x, y = ring("x, y", ZZ)
  2242. >>> f = x**2 + x*y
  2243. >>> g = 2*x + 2
  2244. >>> f.pdiv(g) # first generator is chosen by default if it is not given
  2245. (2*x + 2*y - 2, -4*y + 4)
  2246. >>> f.div(g) # shows the difference between pdiv and div
  2247. (0, x**2 + x*y)
  2248. >>> f.pdiv(g, y) # generator is given
  2249. (2*x**3 + 2*x**2*y + 6*x**2 + 2*x*y + 8*x + 4, 0)
  2250. >>> f.pdiv(g, 1) # generator index is given
  2251. (2*x**3 + 2*x**2*y + 6*x**2 + 2*x*y + 8*x + 4, 0)
  2252. See Also
  2253. ========
  2254. prem
  2255. Computes only the pseudo-remainder more efficiently than
  2256. `f.pdiv(g)[1]`.
  2257. pquo
  2258. Returns only the pseudo-quotient.
  2259. pexquo
  2260. Returns only an exact pseudo-quotient having no remainder.
  2261. div
  2262. Returns quotient and remainder of f and g polynomials.
  2263. """
  2264. f = self
  2265. x = f.ring.index(x)
  2266. df = f.degree(x)
  2267. dg = g.degree(x)
  2268. if dg < 0:
  2269. raise ZeroDivisionError("polynomial division")
  2270. q, r, dr = x, f, df
  2271. if df < dg:
  2272. return q, r
  2273. N = df - dg + 1
  2274. lc_g = g.coeff_wrt(x, dg)
  2275. xp = f.ring.gens[x]
  2276. while True:
  2277. lc_r = r.coeff_wrt(x, dr)
  2278. j, N = dr - dg, N - 1
  2279. Q = q * lc_g
  2280. q = Q + (lc_r)*xp**j
  2281. R = r * lc_g
  2282. G = g * lc_r * xp**j
  2283. r = R - G
  2284. dr = r.degree(x)
  2285. if dr < dg:
  2286. break
  2287. c = lc_g**N
  2288. q = q * c
  2289. r = r * c
  2290. return q, r
  2291. def pquo(self, g, x=None):
  2292. """
  2293. Polynomial pseudo-quotient in multivariate polynomial ring.
  2294. Examples
  2295. ========
  2296. >>> from sympy.polys import ring, ZZ
  2297. >>> R, x,y = ring("x,y", ZZ)
  2298. >>> f = x**2 + x*y
  2299. >>> g = 2*x + 2*y
  2300. >>> h = 2*x + 2
  2301. >>> f.pquo(g)
  2302. 2*x
  2303. >>> f.quo(g) # shows the difference between pquo and quo
  2304. 0
  2305. >>> f.pquo(h)
  2306. 2*x + 2*y - 2
  2307. >>> f.quo(h) # shows the difference between pquo and quo
  2308. 0
  2309. See Also
  2310. ========
  2311. prem, pdiv, pexquo, sympy.polys.domains.ring.Ring.quo
  2312. """
  2313. f = self
  2314. return f.pdiv(g, x)[0]
  2315. def pexquo(self, g, x=None):
  2316. """
  2317. Polynomial exact pseudo-quotient in multivariate polynomial ring.
  2318. Examples
  2319. ========
  2320. >>> from sympy.polys import ring, ZZ
  2321. >>> R, x,y = ring("x,y", ZZ)
  2322. >>> f = x**2 + x*y
  2323. >>> g = 2*x + 2*y
  2324. >>> h = 2*x + 2
  2325. >>> f.pexquo(g)
  2326. 2*x
  2327. >>> f.exquo(g) # shows the difference between pexquo and exquo
  2328. Traceback (most recent call last):
  2329. ...
  2330. ExactQuotientFailed: 2*x + 2*y does not divide x**2 + x*y
  2331. >>> f.pexquo(h)
  2332. Traceback (most recent call last):
  2333. ...
  2334. ExactQuotientFailed: 2*x + 2 does not divide x**2 + x*y
  2335. See Also
  2336. ========
  2337. prem, pdiv, pquo, sympy.polys.domains.ring.Ring.exquo
  2338. """
  2339. f = self
  2340. q, r = f.pdiv(g, x)
  2341. if r.is_zero:
  2342. return q
  2343. else:
  2344. raise ExactQuotientFailed(f, g)
  2345. def subresultants(self, g, x=None):
  2346. """
  2347. Computes the subresultant PRS of two polynomials ``self`` and ``g``.
  2348. Parameters
  2349. ==========
  2350. g : :py:class:`~.PolyElement`
  2351. The second polynomial.
  2352. x : generator or generator index
  2353. The variable with respect to which the subresultant sequence is computed.
  2354. Returns
  2355. =======
  2356. R : list
  2357. Returns a list polynomials representing the subresultant PRS.
  2358. Examples
  2359. ========
  2360. >>> from sympy.polys import ring, ZZ
  2361. >>> R, x, y = ring("x, y", ZZ)
  2362. >>> f = x**2*y + x*y
  2363. >>> g = x + y
  2364. >>> f.subresultants(g) # first generator is chosen by default if not given
  2365. [x**2*y + x*y, x + y, y**3 - y**2]
  2366. >>> f.subresultants(g, 0) # generator index is given
  2367. [x**2*y + x*y, x + y, y**3 - y**2]
  2368. >>> f.subresultants(g, y) # generator is given
  2369. [x**2*y + x*y, x + y, x**3 + x**2]
  2370. """
  2371. f = self
  2372. x = f.ring.index(x)
  2373. n = f.degree(x)
  2374. m = g.degree(x)
  2375. if n < m:
  2376. f, g = g, f
  2377. n, m = m, n
  2378. if f == 0:
  2379. return [0, 0]
  2380. if g == 0:
  2381. return [f, 1]
  2382. R = [f, g]
  2383. d = n - m
  2384. b = (-1) ** (d + 1)
  2385. # Compute the pseudo-remainder for f and g
  2386. h = f.prem(g, x)
  2387. h = h * b
  2388. # Compute the coefficient of g with respect to x**m
  2389. lc = g.coeff_wrt(x, m)
  2390. c = lc ** d
  2391. S = [1, c]
  2392. c = -c
  2393. while h:
  2394. k = h.degree(x)
  2395. R.append(h)
  2396. f, g, m, d = g, h, k, m - k
  2397. b = -lc * c ** d
  2398. h = f.prem(g, x)
  2399. h = h.exquo(b)
  2400. lc = g.coeff_wrt(x, k)
  2401. if d > 1:
  2402. p = (-lc) ** d
  2403. q = c ** (d - 1)
  2404. c = p.exquo(q)
  2405. else:
  2406. c = -lc
  2407. S.append(-c)
  2408. return R
  2409. # TODO: following methods should point to polynomial
  2410. # representation independent algorithm implementations.
  2411. def half_gcdex(f, g):
  2412. return f.ring.dmp_half_gcdex(f, g)
  2413. def gcdex(f, g):
  2414. return f.ring.dmp_gcdex(f, g)
  2415. def resultant(f, g):
  2416. return f.ring.dmp_resultant(f, g)
  2417. def discriminant(f):
  2418. return f.ring.dmp_discriminant(f)
  2419. def decompose(f):
  2420. if f.ring.is_univariate:
  2421. return f.ring.dup_decompose(f)
  2422. else:
  2423. raise MultivariatePolynomialError("polynomial decomposition")
  2424. def shift(f, a):
  2425. if f.ring.is_univariate:
  2426. return f.ring.dup_shift(f, a)
  2427. else:
  2428. raise MultivariatePolynomialError("shift: use shift_list instead")
  2429. def shift_list(f, a):
  2430. return f.ring.dmp_shift(f, a)
  2431. def sturm(f):
  2432. if f.ring.is_univariate:
  2433. return f.ring.dup_sturm(f)
  2434. else:
  2435. raise MultivariatePolynomialError("sturm sequence")
  2436. def gff_list(f):
  2437. return f.ring.dmp_gff_list(f)
  2438. def norm(f):
  2439. return f.ring.dmp_norm(f)
  2440. def sqf_norm(f):
  2441. return f.ring.dmp_sqf_norm(f)
  2442. def sqf_part(f):
  2443. return f.ring.dmp_sqf_part(f)
  2444. def sqf_list(f, all=False):
  2445. return f.ring.dmp_sqf_list(f, all=all)
  2446. def factor_list(f):
  2447. return f.ring.dmp_factor_list(f)