diophantine.py 117 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988
  1. from sympy.core.add import Add
  2. from sympy.core.assumptions import check_assumptions
  3. from sympy.core.containers import Tuple
  4. from sympy.core.exprtools import factor_terms
  5. from sympy.core.function import _mexpand
  6. from sympy.core.mul import Mul
  7. from sympy.core.numbers import Rational
  8. from sympy.core.numbers import igcdex, ilcm, igcd
  9. from sympy.core.power import integer_nthroot, isqrt
  10. from sympy.core.relational import Eq
  11. from sympy.core.singleton import S
  12. from sympy.core.sorting import default_sort_key, ordered
  13. from sympy.core.symbol import Symbol, symbols
  14. from sympy.core.sympify import _sympify
  15. from sympy.functions.elementary.complexes import sign
  16. from sympy.functions.elementary.integers import floor
  17. from sympy.functions.elementary.miscellaneous import sqrt
  18. from sympy.matrices.dense import MutableDenseMatrix as Matrix
  19. from sympy.ntheory.factor_ import (
  20. divisors, factorint, multiplicity, perfect_power)
  21. from sympy.ntheory.generate import nextprime
  22. from sympy.ntheory.primetest import is_square, isprime
  23. from sympy.ntheory.residue_ntheory import sqrt_mod
  24. from sympy.polys.polyerrors import GeneratorsNeeded
  25. from sympy.polys.polytools import Poly, factor_list
  26. from sympy.simplify.simplify import signsimp
  27. from sympy.solvers.solveset import solveset_real
  28. from sympy.utilities import numbered_symbols
  29. from sympy.utilities.misc import as_int, filldedent
  30. from sympy.utilities.iterables import (is_sequence, subsets, permute_signs,
  31. signed_permutations, ordered_partitions)
  32. # these are imported with 'from sympy.solvers.diophantine import *
  33. __all__ = ['diophantine', 'classify_diop']
  34. class DiophantineSolutionSet(set):
  35. """
  36. Container for a set of solutions to a particular diophantine equation.
  37. The base representation is a set of tuples representing each of the solutions.
  38. Parameters
  39. ==========
  40. symbols : list
  41. List of free symbols in the original equation.
  42. parameters: list
  43. List of parameters to be used in the solution.
  44. Examples
  45. ========
  46. Adding solutions:
  47. >>> from sympy.solvers.diophantine.diophantine import DiophantineSolutionSet
  48. >>> from sympy.abc import x, y, t, u
  49. >>> s1 = DiophantineSolutionSet([x, y], [t, u])
  50. >>> s1
  51. set()
  52. >>> s1.add((2, 3))
  53. >>> s1.add((-1, u))
  54. >>> s1
  55. {(-1, u), (2, 3)}
  56. >>> s2 = DiophantineSolutionSet([x, y], [t, u])
  57. >>> s2.add((3, 4))
  58. >>> s1.update(*s2)
  59. >>> s1
  60. {(-1, u), (2, 3), (3, 4)}
  61. Conversion of solutions into dicts:
  62. >>> list(s1.dict_iterator())
  63. [{x: -1, y: u}, {x: 2, y: 3}, {x: 3, y: 4}]
  64. Substituting values:
  65. >>> s3 = DiophantineSolutionSet([x, y], [t, u])
  66. >>> s3.add((t**2, t + u))
  67. >>> s3
  68. {(t**2, t + u)}
  69. >>> s3.subs({t: 2, u: 3})
  70. {(4, 5)}
  71. >>> s3.subs(t, -1)
  72. {(1, u - 1)}
  73. >>> s3.subs(t, 3)
  74. {(9, u + 3)}
  75. Evaluation at specific values. Positional arguments are given in the same order as the parameters:
  76. >>> s3(-2, 3)
  77. {(4, 1)}
  78. >>> s3(5)
  79. {(25, u + 5)}
  80. >>> s3(None, 2)
  81. {(t**2, t + 2)}
  82. """
  83. def __init__(self, symbols_seq, parameters):
  84. super().__init__()
  85. if not is_sequence(symbols_seq):
  86. raise ValueError("Symbols must be given as a sequence.")
  87. if not is_sequence(parameters):
  88. raise ValueError("Parameters must be given as a sequence.")
  89. self.symbols = tuple(symbols_seq)
  90. self.parameters = tuple(parameters)
  91. def add(self, solution):
  92. if len(solution) != len(self.symbols):
  93. raise ValueError("Solution should have a length of %s, not %s" % (len(self.symbols), len(solution)))
  94. super().add(Tuple(*solution))
  95. def update(self, *solutions):
  96. for solution in solutions:
  97. self.add(solution)
  98. def dict_iterator(self):
  99. for solution in ordered(self):
  100. yield dict(zip(self.symbols, solution))
  101. def subs(self, *args, **kwargs):
  102. result = DiophantineSolutionSet(self.symbols, self.parameters)
  103. for solution in self:
  104. result.add(solution.subs(*args, **kwargs))
  105. return result
  106. def __call__(self, *args):
  107. if len(args) > len(self.parameters):
  108. raise ValueError("Evaluation should have at most %s values, not %s" % (len(self.parameters), len(args)))
  109. return self.subs(list(zip(self.parameters, args)))
  110. class DiophantineEquationType:
  111. """
  112. Internal representation of a particular diophantine equation type.
  113. Parameters
  114. ==========
  115. equation :
  116. The diophantine equation that is being solved.
  117. free_symbols : list (optional)
  118. The symbols being solved for.
  119. Attributes
  120. ==========
  121. total_degree :
  122. The maximum of the degrees of all terms in the equation
  123. homogeneous :
  124. Does the equation contain a term of degree 0
  125. homogeneous_order :
  126. Does the equation contain any coefficient that is in the symbols being solved for
  127. dimension :
  128. The number of symbols being solved for
  129. """
  130. name = None # type: str
  131. def __init__(self, equation, free_symbols=None):
  132. self.equation = _sympify(equation).expand(force=True)
  133. if free_symbols is not None:
  134. self.free_symbols = free_symbols
  135. else:
  136. self.free_symbols = list(self.equation.free_symbols)
  137. self.free_symbols.sort(key=default_sort_key)
  138. if not self.free_symbols:
  139. raise ValueError('equation should have 1 or more free symbols')
  140. self.coeff = self.equation.as_coefficients_dict()
  141. if not all(_is_int(c) for c in self.coeff.values()):
  142. raise TypeError("Coefficients should be Integers")
  143. self.total_degree = Poly(self.equation).total_degree()
  144. self.homogeneous = 1 not in self.coeff
  145. self.homogeneous_order = not (set(self.coeff) & set(self.free_symbols))
  146. self.dimension = len(self.free_symbols)
  147. self._parameters = None
  148. def matches(self):
  149. """
  150. Determine whether the given equation can be matched to the particular equation type.
  151. """
  152. return False
  153. @property
  154. def n_parameters(self):
  155. return self.dimension
  156. @property
  157. def parameters(self):
  158. if self._parameters is None:
  159. self._parameters = symbols('t_:%i' % (self.n_parameters,), integer=True)
  160. return self._parameters
  161. def solve(self, parameters=None, limit=None) -> DiophantineSolutionSet:
  162. raise NotImplementedError('No solver has been written for %s.' % self.name)
  163. def pre_solve(self, parameters=None):
  164. if not self.matches():
  165. raise ValueError("This equation does not match the %s equation type." % self.name)
  166. if parameters is not None:
  167. if len(parameters) != self.n_parameters:
  168. raise ValueError("Expected %s parameter(s) but got %s" % (self.n_parameters, len(parameters)))
  169. self._parameters = parameters
  170. class Univariate(DiophantineEquationType):
  171. """
  172. Representation of a univariate diophantine equation.
  173. A univariate diophantine equation is an equation of the form
  174. `a_{0} + a_{1}x + a_{2}x^2 + .. + a_{n}x^n = 0` where `a_{1}, a_{2}, ..a_{n}` are
  175. integer constants and `x` is an integer variable.
  176. Examples
  177. ========
  178. >>> from sympy.solvers.diophantine.diophantine import Univariate
  179. >>> from sympy.abc import x
  180. >>> Univariate((x - 2)*(x - 3)**2).solve() # solves equation (x - 2)*(x - 3)**2 == 0
  181. {(2,), (3,)}
  182. """
  183. name = 'univariate'
  184. def matches(self):
  185. return self.dimension == 1
  186. def solve(self, parameters=None, limit=None):
  187. self.pre_solve(parameters)
  188. result = DiophantineSolutionSet(self.free_symbols, parameters=self.parameters)
  189. for i in solveset_real(self.equation, self.free_symbols[0]).intersect(S.Integers):
  190. result.add((i,))
  191. return result
  192. class Linear(DiophantineEquationType):
  193. """
  194. Representation of a linear diophantine equation.
  195. A linear diophantine equation is an equation of the form `a_{1}x_{1} +
  196. a_{2}x_{2} + .. + a_{n}x_{n} = 0` where `a_{1}, a_{2}, ..a_{n}` are
  197. integer constants and `x_{1}, x_{2}, ..x_{n}` are integer variables.
  198. Examples
  199. ========
  200. >>> from sympy.solvers.diophantine.diophantine import Linear
  201. >>> from sympy.abc import x, y, z
  202. >>> l1 = Linear(2*x - 3*y - 5)
  203. >>> l1.matches() # is this equation linear
  204. True
  205. >>> l1.solve() # solves equation 2*x - 3*y - 5 == 0
  206. {(3*t_0 - 5, 2*t_0 - 5)}
  207. Here x = -3*t_0 - 5 and y = -2*t_0 - 5
  208. >>> Linear(2*x - 3*y - 4*z -3).solve()
  209. {(t_0, 2*t_0 + 4*t_1 + 3, -t_0 - 3*t_1 - 3)}
  210. """
  211. name = 'linear'
  212. def matches(self):
  213. return self.total_degree == 1
  214. def solve(self, parameters=None, limit=None):
  215. self.pre_solve(parameters)
  216. coeff = self.coeff
  217. var = self.free_symbols
  218. if 1 in coeff:
  219. # negate coeff[] because input is of the form: ax + by + c == 0
  220. # but is used as: ax + by == -c
  221. c = -coeff[1]
  222. else:
  223. c = 0
  224. result = DiophantineSolutionSet(var, parameters=self.parameters)
  225. params = result.parameters
  226. if len(var) == 1:
  227. q, r = divmod(c, coeff[var[0]])
  228. if not r:
  229. result.add((q,))
  230. return result
  231. else:
  232. return result
  233. '''
  234. base_solution_linear() can solve diophantine equations of the form:
  235. a*x + b*y == c
  236. We break down multivariate linear diophantine equations into a
  237. series of bivariate linear diophantine equations which can then
  238. be solved individually by base_solution_linear().
  239. Consider the following:
  240. a_0*x_0 + a_1*x_1 + a_2*x_2 == c
  241. which can be re-written as:
  242. a_0*x_0 + g_0*y_0 == c
  243. where
  244. g_0 == gcd(a_1, a_2)
  245. and
  246. y == (a_1*x_1)/g_0 + (a_2*x_2)/g_0
  247. This leaves us with two binary linear diophantine equations.
  248. For the first equation:
  249. a == a_0
  250. b == g_0
  251. c == c
  252. For the second:
  253. a == a_1/g_0
  254. b == a_2/g_0
  255. c == the solution we find for y_0 in the first equation.
  256. The arrays A and B are the arrays of integers used for
  257. 'a' and 'b' in each of the n-1 bivariate equations we solve.
  258. '''
  259. A = [coeff[v] for v in var]
  260. B = []
  261. if len(var) > 2:
  262. B.append(igcd(A[-2], A[-1]))
  263. A[-2] = A[-2] // B[0]
  264. A[-1] = A[-1] // B[0]
  265. for i in range(len(A) - 3, 0, -1):
  266. gcd = igcd(B[0], A[i])
  267. B[0] = B[0] // gcd
  268. A[i] = A[i] // gcd
  269. B.insert(0, gcd)
  270. B.append(A[-1])
  271. '''
  272. Consider the trivariate linear equation:
  273. 4*x_0 + 6*x_1 + 3*x_2 == 2
  274. This can be re-written as:
  275. 4*x_0 + 3*y_0 == 2
  276. where
  277. y_0 == 2*x_1 + x_2
  278. (Note that gcd(3, 6) == 3)
  279. The complete integral solution to this equation is:
  280. x_0 == 2 + 3*t_0
  281. y_0 == -2 - 4*t_0
  282. where 't_0' is any integer.
  283. Now that we have a solution for 'x_0', find 'x_1' and 'x_2':
  284. 2*x_1 + x_2 == -2 - 4*t_0
  285. We can then solve for '-2' and '-4' independently,
  286. and combine the results:
  287. 2*x_1a + x_2a == -2
  288. x_1a == 0 + t_0
  289. x_2a == -2 - 2*t_0
  290. 2*x_1b + x_2b == -4*t_0
  291. x_1b == 0*t_0 + t_1
  292. x_2b == -4*t_0 - 2*t_1
  293. ==>
  294. x_1 == t_0 + t_1
  295. x_2 == -2 - 6*t_0 - 2*t_1
  296. where 't_0' and 't_1' are any integers.
  297. Note that:
  298. 4*(2 + 3*t_0) + 6*(t_0 + t_1) + 3*(-2 - 6*t_0 - 2*t_1) == 2
  299. for any integral values of 't_0', 't_1'; as required.
  300. This method is generalised for many variables, below.
  301. '''
  302. solutions = []
  303. for i in range(len(B)):
  304. tot_x, tot_y = [], []
  305. for j, arg in enumerate(Add.make_args(c)):
  306. if arg.is_Integer:
  307. # example: 5 -> k = 5
  308. k, p = arg, S.One
  309. pnew = params[0]
  310. else: # arg is a Mul or Symbol
  311. # example: 3*t_1 -> k = 3
  312. # example: t_0 -> k = 1
  313. k, p = arg.as_coeff_Mul()
  314. pnew = params[params.index(p) + 1]
  315. sol = sol_x, sol_y = base_solution_linear(k, A[i], B[i], pnew)
  316. if p is S.One:
  317. if None in sol:
  318. return result
  319. else:
  320. # convert a + b*pnew -> a*p + b*pnew
  321. if isinstance(sol_x, Add):
  322. sol_x = sol_x.args[0]*p + sol_x.args[1]
  323. if isinstance(sol_y, Add):
  324. sol_y = sol_y.args[0]*p + sol_y.args[1]
  325. tot_x.append(sol_x)
  326. tot_y.append(sol_y)
  327. solutions.append(Add(*tot_x))
  328. c = Add(*tot_y)
  329. solutions.append(c)
  330. result.add(solutions)
  331. return result
  332. class BinaryQuadratic(DiophantineEquationType):
  333. """
  334. Representation of a binary quadratic diophantine equation.
  335. A binary quadratic diophantine equation is an equation of the
  336. form `Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0`, where `A, B, C, D, E,
  337. F` are integer constants and `x` and `y` are integer variables.
  338. Examples
  339. ========
  340. >>> from sympy.abc import x, y
  341. >>> from sympy.solvers.diophantine.diophantine import BinaryQuadratic
  342. >>> b1 = BinaryQuadratic(x**3 + y**2 + 1)
  343. >>> b1.matches()
  344. False
  345. >>> b2 = BinaryQuadratic(x**2 + y**2 + 2*x + 2*y + 2)
  346. >>> b2.matches()
  347. True
  348. >>> b2.solve()
  349. {(-1, -1)}
  350. References
  351. ==========
  352. .. [1] Methods to solve Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0, [online],
  353. Available: http://www.alpertron.com.ar/METHODS.HTM
  354. .. [2] Solving the equation ax^2+ bxy + cy^2 + dx + ey + f= 0, [online],
  355. Available: https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf
  356. """
  357. name = 'binary_quadratic'
  358. def matches(self):
  359. return self.total_degree == 2 and self.dimension == 2
  360. def solve(self, parameters=None, limit=None) -> DiophantineSolutionSet:
  361. self.pre_solve(parameters)
  362. var = self.free_symbols
  363. coeff = self.coeff
  364. x, y = var
  365. A = coeff[x**2]
  366. B = coeff[x*y]
  367. C = coeff[y**2]
  368. D = coeff[x]
  369. E = coeff[y]
  370. F = coeff[S.One]
  371. A, B, C, D, E, F = [as_int(i) for i in _remove_gcd(A, B, C, D, E, F)]
  372. # (1) Simple-Hyperbolic case: A = C = 0, B != 0
  373. # In this case equation can be converted to (Bx + E)(By + D) = DE - BF
  374. # We consider two cases; DE - BF = 0 and DE - BF != 0
  375. # More details, http://www.alpertron.com.ar/METHODS.HTM#SHyperb
  376. result = DiophantineSolutionSet(var, self.parameters)
  377. t, u = result.parameters
  378. discr = B**2 - 4*A*C
  379. if A == 0 and C == 0 and B != 0:
  380. if D*E - B*F == 0:
  381. q, r = divmod(E, B)
  382. if not r:
  383. result.add((-q, t))
  384. q, r = divmod(D, B)
  385. if not r:
  386. result.add((t, -q))
  387. else:
  388. div = divisors(D*E - B*F)
  389. div = div + [-term for term in div]
  390. for d in div:
  391. x0, r = divmod(d - E, B)
  392. if not r:
  393. q, r = divmod(D*E - B*F, d)
  394. if not r:
  395. y0, r = divmod(q - D, B)
  396. if not r:
  397. result.add((x0, y0))
  398. # (2) Parabolic case: B**2 - 4*A*C = 0
  399. # There are two subcases to be considered in this case.
  400. # sqrt(c)D - sqrt(a)E = 0 and sqrt(c)D - sqrt(a)E != 0
  401. # More Details, http://www.alpertron.com.ar/METHODS.HTM#Parabol
  402. elif discr == 0:
  403. if A == 0:
  404. s = BinaryQuadratic(self.equation, free_symbols=[y, x]).solve(parameters=[t, u])
  405. for soln in s:
  406. result.add((soln[1], soln[0]))
  407. else:
  408. g = sign(A)*igcd(A, C)
  409. a = A // g
  410. c = C // g
  411. e = sign(B / A)
  412. sqa = isqrt(a)
  413. sqc = isqrt(c)
  414. _c = e*sqc*D - sqa*E
  415. if not _c:
  416. z = symbols("z", real=True)
  417. eq = sqa*g*z**2 + D*z + sqa*F
  418. roots = solveset_real(eq, z).intersect(S.Integers)
  419. for root in roots:
  420. ans = diop_solve(sqa*x + e*sqc*y - root)
  421. result.add((ans[0], ans[1]))
  422. elif _is_int(c):
  423. solve_x = lambda u: -e*sqc*g*_c*t**2 - (E + 2*e*sqc*g*u)*t \
  424. - (e*sqc*g*u**2 + E*u + e*sqc*F) // _c
  425. solve_y = lambda u: sqa*g*_c*t**2 + (D + 2*sqa*g*u)*t \
  426. + (sqa*g*u**2 + D*u + sqa*F) // _c
  427. for z0 in range(0, abs(_c)):
  428. # Check if the coefficients of y and x obtained are integers or not
  429. if (divisible(sqa*g*z0**2 + D*z0 + sqa*F, _c) and
  430. divisible(e*sqc*g*z0**2 + E*z0 + e*sqc*F, _c)):
  431. result.add((solve_x(z0), solve_y(z0)))
  432. # (3) Method used when B**2 - 4*A*C is a square, is described in p. 6 of the below paper
  433. # by John P. Robertson.
  434. # https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf
  435. elif is_square(discr):
  436. if A != 0:
  437. r = sqrt(discr)
  438. u, v = symbols("u, v", integer=True)
  439. eq = _mexpand(
  440. 4*A*r*u*v + 4*A*D*(B*v + r*u + r*v - B*u) +
  441. 2*A*4*A*E*(u - v) + 4*A*r*4*A*F)
  442. solution = diop_solve(eq, t)
  443. for s0, t0 in solution:
  444. num = B*t0 + r*s0 + r*t0 - B*s0
  445. x_0 = S(num) / (4*A*r)
  446. y_0 = S(s0 - t0) / (2*r)
  447. if isinstance(s0, Symbol) or isinstance(t0, Symbol):
  448. if len(check_param(x_0, y_0, 4*A*r, parameters)) > 0:
  449. ans = check_param(x_0, y_0, 4*A*r, parameters)
  450. result.update(*ans)
  451. elif x_0.is_Integer and y_0.is_Integer:
  452. if is_solution_quad(var, coeff, x_0, y_0):
  453. result.add((x_0, y_0))
  454. else:
  455. s = BinaryQuadratic(self.equation, free_symbols=var[::-1]).solve(parameters=[t, u]) # Interchange x and y
  456. while s:
  457. result.add(s.pop()[::-1]) # and solution <--------+
  458. # (4) B**2 - 4*A*C > 0 and B**2 - 4*A*C not a square or B**2 - 4*A*C < 0
  459. else:
  460. P, Q = _transformation_to_DN(var, coeff)
  461. D, N = _find_DN(var, coeff)
  462. solns_pell = diop_DN(D, N)
  463. if D < 0:
  464. for x0, y0 in solns_pell:
  465. for x in [-x0, x0]:
  466. for y in [-y0, y0]:
  467. s = P*Matrix([x, y]) + Q
  468. try:
  469. result.add([as_int(_) for _ in s])
  470. except ValueError:
  471. pass
  472. else:
  473. # In this case equation can be transformed into a Pell equation
  474. solns_pell = set(solns_pell)
  475. for X, Y in list(solns_pell):
  476. solns_pell.add((-X, -Y))
  477. a = diop_DN(D, 1)
  478. T = a[0][0]
  479. U = a[0][1]
  480. if all(_is_int(_) for _ in P[:4] + Q[:2]):
  481. for r, s in solns_pell:
  482. _a = (r + s*sqrt(D))*(T + U*sqrt(D))**t
  483. _b = (r - s*sqrt(D))*(T - U*sqrt(D))**t
  484. x_n = _mexpand(S(_a + _b) / 2)
  485. y_n = _mexpand(S(_a - _b) / (2*sqrt(D)))
  486. s = P*Matrix([x_n, y_n]) + Q
  487. result.add(s)
  488. else:
  489. L = ilcm(*[_.q for _ in P[:4] + Q[:2]])
  490. k = 1
  491. T_k = T
  492. U_k = U
  493. while (T_k - 1) % L != 0 or U_k % L != 0:
  494. T_k, U_k = T_k*T + D*U_k*U, T_k*U + U_k*T
  495. k += 1
  496. for X, Y in solns_pell:
  497. for i in range(k):
  498. if all(_is_int(_) for _ in P*Matrix([X, Y]) + Q):
  499. _a = (X + sqrt(D)*Y)*(T_k + sqrt(D)*U_k)**t
  500. _b = (X - sqrt(D)*Y)*(T_k - sqrt(D)*U_k)**t
  501. Xt = S(_a + _b) / 2
  502. Yt = S(_a - _b) / (2*sqrt(D))
  503. s = P*Matrix([Xt, Yt]) + Q
  504. result.add(s)
  505. X, Y = X*T + D*U*Y, X*U + Y*T
  506. return result
  507. class InhomogeneousTernaryQuadratic(DiophantineEquationType):
  508. """
  509. Representation of an inhomogeneous ternary quadratic.
  510. No solver is currently implemented for this equation type.
  511. """
  512. name = 'inhomogeneous_ternary_quadratic'
  513. def matches(self):
  514. if not (self.total_degree == 2 and self.dimension == 3):
  515. return False
  516. if not self.homogeneous:
  517. return False
  518. return not self.homogeneous_order
  519. class HomogeneousTernaryQuadraticNormal(DiophantineEquationType):
  520. """
  521. Representation of a homogeneous ternary quadratic normal diophantine equation.
  522. Examples
  523. ========
  524. >>> from sympy.abc import x, y, z
  525. >>> from sympy.solvers.diophantine.diophantine import HomogeneousTernaryQuadraticNormal
  526. >>> HomogeneousTernaryQuadraticNormal(4*x**2 - 5*y**2 + z**2).solve()
  527. {(1, 2, 4)}
  528. """
  529. name = 'homogeneous_ternary_quadratic_normal'
  530. def matches(self):
  531. if not (self.total_degree == 2 and self.dimension == 3):
  532. return False
  533. if not self.homogeneous:
  534. return False
  535. if not self.homogeneous_order:
  536. return False
  537. nonzero = [k for k in self.coeff if self.coeff[k]]
  538. return len(nonzero) == 3 and all(i**2 in nonzero for i in self.free_symbols)
  539. def solve(self, parameters=None, limit=None) -> DiophantineSolutionSet:
  540. self.pre_solve(parameters)
  541. var = self.free_symbols
  542. coeff = self.coeff
  543. x, y, z = var
  544. a = coeff[x**2]
  545. b = coeff[y**2]
  546. c = coeff[z**2]
  547. (sqf_of_a, sqf_of_b, sqf_of_c), (a_1, b_1, c_1), (a_2, b_2, c_2) = \
  548. sqf_normal(a, b, c, steps=True)
  549. A = -a_2*c_2
  550. B = -b_2*c_2
  551. result = DiophantineSolutionSet(var, parameters=self.parameters)
  552. # If following two conditions are satisfied then there are no solutions
  553. if A < 0 and B < 0:
  554. return result
  555. if (
  556. sqrt_mod(-b_2*c_2, a_2) is None or
  557. sqrt_mod(-c_2*a_2, b_2) is None or
  558. sqrt_mod(-a_2*b_2, c_2) is None):
  559. return result
  560. z_0, x_0, y_0 = descent(A, B)
  561. z_0, q = _rational_pq(z_0, abs(c_2))
  562. x_0 *= q
  563. y_0 *= q
  564. x_0, y_0, z_0 = _remove_gcd(x_0, y_0, z_0)
  565. # Holzer reduction
  566. if sign(a) == sign(b):
  567. x_0, y_0, z_0 = holzer(x_0, y_0, z_0, abs(a_2), abs(b_2), abs(c_2))
  568. elif sign(a) == sign(c):
  569. x_0, z_0, y_0 = holzer(x_0, z_0, y_0, abs(a_2), abs(c_2), abs(b_2))
  570. else:
  571. y_0, z_0, x_0 = holzer(y_0, z_0, x_0, abs(b_2), abs(c_2), abs(a_2))
  572. x_0 = reconstruct(b_1, c_1, x_0)
  573. y_0 = reconstruct(a_1, c_1, y_0)
  574. z_0 = reconstruct(a_1, b_1, z_0)
  575. sq_lcm = ilcm(sqf_of_a, sqf_of_b, sqf_of_c)
  576. x_0 = abs(x_0*sq_lcm // sqf_of_a)
  577. y_0 = abs(y_0*sq_lcm // sqf_of_b)
  578. z_0 = abs(z_0*sq_lcm // sqf_of_c)
  579. result.add(_remove_gcd(x_0, y_0, z_0))
  580. return result
  581. class HomogeneousTernaryQuadratic(DiophantineEquationType):
  582. """
  583. Representation of a homogeneous ternary quadratic diophantine equation.
  584. Examples
  585. ========
  586. >>> from sympy.abc import x, y, z
  587. >>> from sympy.solvers.diophantine.diophantine import HomogeneousTernaryQuadratic
  588. >>> HomogeneousTernaryQuadratic(x**2 + y**2 - 3*z**2 + x*y).solve()
  589. {(-1, 2, 1)}
  590. >>> HomogeneousTernaryQuadratic(3*x**2 + y**2 - 3*z**2 + 5*x*y + y*z).solve()
  591. {(3, 12, 13)}
  592. """
  593. name = 'homogeneous_ternary_quadratic'
  594. def matches(self):
  595. if not (self.total_degree == 2 and self.dimension == 3):
  596. return False
  597. if not self.homogeneous:
  598. return False
  599. if not self.homogeneous_order:
  600. return False
  601. nonzero = [k for k in self.coeff if self.coeff[k]]
  602. return not (len(nonzero) == 3 and all(i**2 in nonzero for i in self.free_symbols))
  603. def solve(self, parameters=None, limit=None):
  604. self.pre_solve(parameters)
  605. _var = self.free_symbols
  606. coeff = self.coeff
  607. x, y, z = _var
  608. var = [x, y, z]
  609. # Equations of the form B*x*y + C*z*x + E*y*z = 0 and At least two of the
  610. # coefficients A, B, C are non-zero.
  611. # There are infinitely many solutions for the equation.
  612. # Ex: (0, 0, t), (0, t, 0), (t, 0, 0)
  613. # Equation can be re-written as y*(B*x + E*z) = -C*x*z and we can find rather
  614. # unobvious solutions. Set y = -C and B*x + E*z = x*z. The latter can be solved by
  615. # using methods for binary quadratic diophantine equations. Let's select the
  616. # solution which minimizes |x| + |z|
  617. result = DiophantineSolutionSet(var, parameters=self.parameters)
  618. def unpack_sol(sol):
  619. if len(sol) > 0:
  620. return list(sol)[0]
  621. return None, None, None
  622. if not any(coeff[i**2] for i in var):
  623. if coeff[x*z]:
  624. sols = diophantine(coeff[x*y]*x + coeff[y*z]*z - x*z)
  625. s = sols.pop()
  626. min_sum = abs(s[0]) + abs(s[1])
  627. for r in sols:
  628. m = abs(r[0]) + abs(r[1])
  629. if m < min_sum:
  630. s = r
  631. min_sum = m
  632. result.add(_remove_gcd(s[0], -coeff[x*z], s[1]))
  633. return result
  634. else:
  635. var[0], var[1] = _var[1], _var[0]
  636. y_0, x_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, coeff))
  637. if x_0 is not None:
  638. result.add((x_0, y_0, z_0))
  639. return result
  640. if coeff[x**2] == 0:
  641. # If the coefficient of x is zero change the variables
  642. if coeff[y**2] == 0:
  643. var[0], var[2] = _var[2], _var[0]
  644. z_0, y_0, x_0 = unpack_sol(_diop_ternary_quadratic(var, coeff))
  645. else:
  646. var[0], var[1] = _var[1], _var[0]
  647. y_0, x_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, coeff))
  648. else:
  649. if coeff[x*y] or coeff[x*z]:
  650. # Apply the transformation x --> X - (B*y + C*z)/(2*A)
  651. A = coeff[x**2]
  652. B = coeff[x*y]
  653. C = coeff[x*z]
  654. D = coeff[y**2]
  655. E = coeff[y*z]
  656. F = coeff[z**2]
  657. _coeff = dict()
  658. _coeff[x**2] = 4*A**2
  659. _coeff[y**2] = 4*A*D - B**2
  660. _coeff[z**2] = 4*A*F - C**2
  661. _coeff[y*z] = 4*A*E - 2*B*C
  662. _coeff[x*y] = 0
  663. _coeff[x*z] = 0
  664. x_0, y_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, _coeff))
  665. if x_0 is None:
  666. return result
  667. p, q = _rational_pq(B*y_0 + C*z_0, 2*A)
  668. x_0, y_0, z_0 = x_0*q - p, y_0*q, z_0*q
  669. elif coeff[z*y] != 0:
  670. if coeff[y**2] == 0:
  671. if coeff[z**2] == 0:
  672. # Equations of the form A*x**2 + E*yz = 0.
  673. A = coeff[x**2]
  674. E = coeff[y*z]
  675. b, a = _rational_pq(-E, A)
  676. x_0, y_0, z_0 = b, a, b
  677. else:
  678. # Ax**2 + E*y*z + F*z**2 = 0
  679. var[0], var[2] = _var[2], _var[0]
  680. z_0, y_0, x_0 = unpack_sol(_diop_ternary_quadratic(var, coeff))
  681. else:
  682. # A*x**2 + D*y**2 + E*y*z + F*z**2 = 0, C may be zero
  683. var[0], var[1] = _var[1], _var[0]
  684. y_0, x_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, coeff))
  685. else:
  686. # Ax**2 + D*y**2 + F*z**2 = 0, C may be zero
  687. x_0, y_0, z_0 = unpack_sol(_diop_ternary_quadratic_normal(var, coeff))
  688. if x_0 is None:
  689. return result
  690. result.add(_remove_gcd(x_0, y_0, z_0))
  691. return result
  692. class InhomogeneousGeneralQuadratic(DiophantineEquationType):
  693. """
  694. Representation of an inhomogeneous general quadratic.
  695. No solver is currently implemented for this equation type.
  696. """
  697. name = 'inhomogeneous_general_quadratic'
  698. def matches(self):
  699. if not (self.total_degree == 2 and self.dimension >= 3):
  700. return False
  701. if not self.homogeneous_order:
  702. return True
  703. else:
  704. # there may be Pow keys like x**2 or Mul keys like x*y
  705. if any(k.is_Mul for k in self.coeff): # cross terms
  706. return not self.homogeneous
  707. return False
  708. class HomogeneousGeneralQuadratic(DiophantineEquationType):
  709. """
  710. Representation of a homogeneous general quadratic.
  711. No solver is currently implemented for this equation type.
  712. """
  713. name = 'homogeneous_general_quadratic'
  714. def matches(self):
  715. if not (self.total_degree == 2 and self.dimension >= 3):
  716. return False
  717. if not self.homogeneous_order:
  718. return False
  719. else:
  720. # there may be Pow keys like x**2 or Mul keys like x*y
  721. if any(k.is_Mul for k in self.coeff): # cross terms
  722. return self.homogeneous
  723. return False
  724. class GeneralSumOfSquares(DiophantineEquationType):
  725. r"""
  726. Representation of the diophantine equation
  727. `x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0`.
  728. Details
  729. =======
  730. When `n = 3` if `k = 4^a(8m + 7)` for some `a, m \in Z` then there will be
  731. no solutions. Refer [1]_ for more details.
  732. Examples
  733. ========
  734. >>> from sympy.solvers.diophantine.diophantine import GeneralSumOfSquares
  735. >>> from sympy.abc import a, b, c, d, e
  736. >>> GeneralSumOfSquares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345).solve()
  737. {(15, 22, 22, 24, 24)}
  738. By default only 1 solution is returned. Use the `limit` keyword for more:
  739. >>> sorted(GeneralSumOfSquares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345).solve(limit=3))
  740. [(15, 22, 22, 24, 24), (16, 19, 24, 24, 24), (16, 20, 22, 23, 26)]
  741. References
  742. ==========
  743. .. [1] Representing an integer as a sum of three squares, [online],
  744. Available:
  745. http://www.proofwiki.org/wiki/Integer_as_Sum_of_Three_Squares
  746. """
  747. name = 'general_sum_of_squares'
  748. def matches(self):
  749. if not (self.total_degree == 2 and self.dimension >= 3):
  750. return False
  751. if not self.homogeneous_order:
  752. return False
  753. if any(k.is_Mul for k in self.coeff):
  754. return False
  755. return all(self.coeff[k] == 1 for k in self.coeff if k != 1)
  756. def solve(self, parameters=None, limit=1):
  757. self.pre_solve(parameters)
  758. var = self.free_symbols
  759. k = -int(self.coeff[1])
  760. n = self.dimension
  761. result = DiophantineSolutionSet(var, parameters=self.parameters)
  762. if k < 0 or limit < 1:
  763. return result
  764. signs = [-1 if x.is_nonpositive else 1 for x in var]
  765. negs = signs.count(-1) != 0
  766. took = 0
  767. for t in sum_of_squares(k, n, zeros=True):
  768. if negs:
  769. result.add([signs[i]*j for i, j in enumerate(t)])
  770. else:
  771. result.add(t)
  772. took += 1
  773. if took == limit:
  774. break
  775. return result
  776. class GeneralPythagorean(DiophantineEquationType):
  777. """
  778. Representation of the general pythagorean equation,
  779. `a_{1}^2x_{1}^2 + a_{2}^2x_{2}^2 + . . . + a_{n}^2x_{n}^2 - a_{n + 1}^2x_{n + 1}^2 = 0`.
  780. Examples
  781. ========
  782. >>> from sympy.solvers.diophantine.diophantine import GeneralPythagorean
  783. >>> from sympy.abc import a, b, c, d, e, x, y, z, t
  784. >>> GeneralPythagorean(a**2 + b**2 + c**2 - d**2).solve()
  785. {(t_0**2 + t_1**2 - t_2**2, 2*t_0*t_2, 2*t_1*t_2, t_0**2 + t_1**2 + t_2**2)}
  786. >>> GeneralPythagorean(9*a**2 - 4*b**2 + 16*c**2 + 25*d**2 + e**2).solve(parameters=[x, y, z, t])
  787. {(-10*t**2 + 10*x**2 + 10*y**2 + 10*z**2, 15*t**2 + 15*x**2 + 15*y**2 + 15*z**2, 15*t*x, 12*t*y, 60*t*z)}
  788. """
  789. name = 'general_pythagorean'
  790. def matches(self):
  791. if not (self.total_degree == 2 and self.dimension >= 3):
  792. return False
  793. if not self.homogeneous_order:
  794. return False
  795. if any(k.is_Mul for k in self.coeff):
  796. return False
  797. if all(self.coeff[k] == 1 for k in self.coeff if k != 1):
  798. return False
  799. if not all(is_square(abs(self.coeff[k])) for k in self.coeff):
  800. return False
  801. # all but one has the same sign
  802. # e.g. 4*x**2 + y**2 - 4*z**2
  803. return abs(sum(sign(self.coeff[k]) for k in self.coeff)) == self.dimension - 2
  804. @property
  805. def n_parameters(self):
  806. return self.dimension - 1
  807. def solve(self, parameters=None, limit=1):
  808. self.pre_solve(parameters)
  809. coeff = self.coeff
  810. var = self.free_symbols
  811. n = self.dimension
  812. if sign(coeff[var[0] ** 2]) + sign(coeff[var[1] ** 2]) + sign(coeff[var[2] ** 2]) < 0:
  813. for key in coeff.keys():
  814. coeff[key] = -coeff[key]
  815. result = DiophantineSolutionSet(var, parameters=self.parameters)
  816. index = 0
  817. for i, v in enumerate(var):
  818. if sign(coeff[v ** 2]) == -1:
  819. index = i
  820. m = result.parameters
  821. ith = sum(m_i ** 2 for m_i in m)
  822. L = [ith - 2 * m[n - 2] ** 2]
  823. L.extend([2 * m[i] * m[n - 2] for i in range(n - 2)])
  824. sol = L[:index] + [ith] + L[index:]
  825. lcm = 1
  826. for i, v in enumerate(var):
  827. if i == index or (index > 0 and i == 0) or (index == 0 and i == 1):
  828. lcm = ilcm(lcm, sqrt(abs(coeff[v ** 2])))
  829. else:
  830. s = sqrt(coeff[v ** 2])
  831. lcm = ilcm(lcm, s if _odd(s) else s // 2)
  832. for i, v in enumerate(var):
  833. sol[i] = (lcm * sol[i]) / sqrt(abs(coeff[v ** 2]))
  834. result.add(sol)
  835. return result
  836. class CubicThue(DiophantineEquationType):
  837. """
  838. Representation of a cubic Thue diophantine equation.
  839. A cubic Thue diophantine equation is a polynomial of the form
  840. `f(x, y) = r` of degree 3, where `x` and `y` are integers
  841. and `r` is a rational number.
  842. No solver is currently implemented for this equation type.
  843. Examples
  844. ========
  845. >>> from sympy.abc import x, y
  846. >>> from sympy.solvers.diophantine.diophantine import CubicThue
  847. >>> c1 = CubicThue(x**3 + y**2 + 1)
  848. >>> c1.matches()
  849. True
  850. """
  851. name = 'cubic_thue'
  852. def matches(self):
  853. return self.total_degree == 3 and self.dimension == 2
  854. class GeneralSumOfEvenPowers(DiophantineEquationType):
  855. """
  856. Representation of the diophantine equation
  857. `x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0`
  858. where `e` is an even, integer power.
  859. Examples
  860. ========
  861. >>> from sympy.solvers.diophantine.diophantine import GeneralSumOfEvenPowers
  862. >>> from sympy.abc import a, b
  863. >>> GeneralSumOfEvenPowers(a**4 + b**4 - (2**4 + 3**4)).solve()
  864. {(2, 3)}
  865. """
  866. name = 'general_sum_of_even_powers'
  867. def matches(self):
  868. if not self.total_degree > 3:
  869. return False
  870. if self.total_degree % 2 != 0:
  871. return False
  872. if not all(k.is_Pow and k.exp == self.total_degree for k in self.coeff if k != 1):
  873. return False
  874. return all(self.coeff[k] == 1 for k in self.coeff if k != 1)
  875. def solve(self, parameters=None, limit=1):
  876. self.pre_solve(parameters)
  877. var = self.free_symbols
  878. coeff = self.coeff
  879. p = None
  880. for q in coeff.keys():
  881. if q.is_Pow and coeff[q]:
  882. p = q.exp
  883. k = len(var)
  884. n = -coeff[1]
  885. result = DiophantineSolutionSet(var, parameters=self.parameters)
  886. if n < 0 or limit < 1:
  887. return result
  888. sign = [-1 if x.is_nonpositive else 1 for x in var]
  889. negs = sign.count(-1) != 0
  890. took = 0
  891. for t in power_representation(n, p, k):
  892. if negs:
  893. result.add([sign[i]*j for i, j in enumerate(t)])
  894. else:
  895. result.add(t)
  896. took += 1
  897. if took == limit:
  898. break
  899. return result
  900. # these types are known (but not necessarily handled)
  901. # note that order is important here (in the current solver state)
  902. all_diop_classes = [
  903. Linear,
  904. Univariate,
  905. BinaryQuadratic,
  906. InhomogeneousTernaryQuadratic,
  907. HomogeneousTernaryQuadraticNormal,
  908. HomogeneousTernaryQuadratic,
  909. InhomogeneousGeneralQuadratic,
  910. HomogeneousGeneralQuadratic,
  911. GeneralSumOfSquares,
  912. GeneralPythagorean,
  913. CubicThue,
  914. GeneralSumOfEvenPowers,
  915. ]
  916. diop_known = {diop_class.name for diop_class in all_diop_classes}
  917. def _is_int(i):
  918. try:
  919. as_int(i)
  920. return True
  921. except ValueError:
  922. pass
  923. def _sorted_tuple(*i):
  924. return tuple(sorted(i))
  925. def _remove_gcd(*x):
  926. try:
  927. g = igcd(*x)
  928. except ValueError:
  929. fx = list(filter(None, x))
  930. if len(fx) < 2:
  931. return x
  932. g = igcd(*[i.as_content_primitive()[0] for i in fx])
  933. except TypeError:
  934. raise TypeError('_remove_gcd(a,b,c) or _remove_gcd(*container)')
  935. if g == 1:
  936. return x
  937. return tuple([i//g for i in x])
  938. def _rational_pq(a, b):
  939. # return `(numer, denom)` for a/b; sign in numer and gcd removed
  940. return _remove_gcd(sign(b)*a, abs(b))
  941. def _nint_or_floor(p, q):
  942. # return nearest int to p/q; in case of tie return floor(p/q)
  943. w, r = divmod(p, q)
  944. if abs(r) <= abs(q)//2:
  945. return w
  946. return w + 1
  947. def _odd(i):
  948. return i % 2 != 0
  949. def _even(i):
  950. return i % 2 == 0
  951. def diophantine(eq, param=symbols("t", integer=True), syms=None,
  952. permute=False):
  953. """
  954. Simplify the solution procedure of diophantine equation ``eq`` by
  955. converting it into a product of terms which should equal zero.
  956. Explanation
  957. ===========
  958. For example, when solving, `x^2 - y^2 = 0` this is treated as
  959. `(x + y)(x - y) = 0` and `x + y = 0` and `x - y = 0` are solved
  960. independently and combined. Each term is solved by calling
  961. ``diop_solve()``. (Although it is possible to call ``diop_solve()``
  962. directly, one must be careful to pass an equation in the correct
  963. form and to interpret the output correctly; ``diophantine()`` is
  964. the public-facing function to use in general.)
  965. Output of ``diophantine()`` is a set of tuples. The elements of the
  966. tuple are the solutions for each variable in the equation and
  967. are arranged according to the alphabetic ordering of the variables.
  968. e.g. For an equation with two variables, `a` and `b`, the first
  969. element of the tuple is the solution for `a` and the second for `b`.
  970. Usage
  971. =====
  972. ``diophantine(eq, t, syms)``: Solve the diophantine
  973. equation ``eq``.
  974. ``t`` is the optional parameter to be used by ``diop_solve()``.
  975. ``syms`` is an optional list of symbols which determines the
  976. order of the elements in the returned tuple.
  977. By default, only the base solution is returned. If ``permute`` is set to
  978. True then permutations of the base solution and/or permutations of the
  979. signs of the values will be returned when applicable.
  980. Examples
  981. ========
  982. >>> from sympy import diophantine
  983. >>> from sympy.abc import a, b
  984. >>> eq = a**4 + b**4 - (2**4 + 3**4)
  985. >>> diophantine(eq)
  986. {(2, 3)}
  987. >>> diophantine(eq, permute=True)
  988. {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)}
  989. Details
  990. =======
  991. ``eq`` should be an expression which is assumed to be zero.
  992. ``t`` is the parameter to be used in the solution.
  993. Examples
  994. ========
  995. >>> from sympy.abc import x, y, z
  996. >>> diophantine(x**2 - y**2)
  997. {(t_0, -t_0), (t_0, t_0)}
  998. >>> diophantine(x*(2*x + 3*y - z))
  999. {(0, n1, n2), (t_0, t_1, 2*t_0 + 3*t_1)}
  1000. >>> diophantine(x**2 + 3*x*y + 4*x)
  1001. {(0, n1), (3*t_0 - 4, -t_0)}
  1002. See Also
  1003. ========
  1004. diop_solve()
  1005. sympy.utilities.iterables.permute_signs
  1006. sympy.utilities.iterables.signed_permutations
  1007. """
  1008. eq = _sympify(eq)
  1009. if isinstance(eq, Eq):
  1010. eq = eq.lhs - eq.rhs
  1011. try:
  1012. var = list(eq.expand(force=True).free_symbols)
  1013. var.sort(key=default_sort_key)
  1014. if syms:
  1015. if not is_sequence(syms):
  1016. raise TypeError(
  1017. 'syms should be given as a sequence, e.g. a list')
  1018. syms = [i for i in syms if i in var]
  1019. if syms != var:
  1020. dict_sym_index = dict(zip(syms, range(len(syms))))
  1021. return {tuple([t[dict_sym_index[i]] for i in var])
  1022. for t in diophantine(eq, param, permute=permute)}
  1023. n, d = eq.as_numer_denom()
  1024. if n.is_number:
  1025. return set()
  1026. if not d.is_number:
  1027. dsol = diophantine(d)
  1028. good = diophantine(n) - dsol
  1029. return {s for s in good if _mexpand(d.subs(zip(var, s)))}
  1030. else:
  1031. eq = n
  1032. eq = factor_terms(eq)
  1033. assert not eq.is_number
  1034. eq = eq.as_independent(*var, as_Add=False)[1]
  1035. p = Poly(eq)
  1036. assert not any(g.is_number for g in p.gens)
  1037. eq = p.as_expr()
  1038. assert eq.is_polynomial()
  1039. except (GeneratorsNeeded, AssertionError):
  1040. raise TypeError(filldedent('''
  1041. Equation should be a polynomial with Rational coefficients.'''))
  1042. # permute only sign
  1043. do_permute_signs = False
  1044. # permute sign and values
  1045. do_permute_signs_var = False
  1046. # permute few signs
  1047. permute_few_signs = False
  1048. try:
  1049. # if we know that factoring should not be attempted, skip
  1050. # the factoring step
  1051. v, c, t = classify_diop(eq)
  1052. # check for permute sign
  1053. if permute:
  1054. len_var = len(v)
  1055. permute_signs_for = [
  1056. GeneralSumOfSquares.name,
  1057. GeneralSumOfEvenPowers.name]
  1058. permute_signs_check = [
  1059. HomogeneousTernaryQuadratic.name,
  1060. HomogeneousTernaryQuadraticNormal.name,
  1061. BinaryQuadratic.name]
  1062. if t in permute_signs_for:
  1063. do_permute_signs_var = True
  1064. elif t in permute_signs_check:
  1065. # if all the variables in eq have even powers
  1066. # then do_permute_sign = True
  1067. if len_var == 3:
  1068. var_mul = list(subsets(v, 2))
  1069. # here var_mul is like [(x, y), (x, z), (y, z)]
  1070. xy_coeff = True
  1071. x_coeff = True
  1072. var1_mul_var2 = map(lambda a: a[0]*a[1], var_mul)
  1073. # if coeff(y*z), coeff(y*x), coeff(x*z) is not 0 then
  1074. # `xy_coeff` => True and do_permute_sign => False.
  1075. # Means no permuted solution.
  1076. for v1_mul_v2 in var1_mul_var2:
  1077. try:
  1078. coeff = c[v1_mul_v2]
  1079. except KeyError:
  1080. coeff = 0
  1081. xy_coeff = bool(xy_coeff) and bool(coeff)
  1082. var_mul = list(subsets(v, 1))
  1083. # here var_mul is like [(x,), (y, )]
  1084. for v1 in var_mul:
  1085. try:
  1086. coeff = c[v1[0]]
  1087. except KeyError:
  1088. coeff = 0
  1089. x_coeff = bool(x_coeff) and bool(coeff)
  1090. if not any((xy_coeff, x_coeff)):
  1091. # means only x**2, y**2, z**2, const is present
  1092. do_permute_signs = True
  1093. elif not x_coeff:
  1094. permute_few_signs = True
  1095. elif len_var == 2:
  1096. var_mul = list(subsets(v, 2))
  1097. # here var_mul is like [(x, y)]
  1098. xy_coeff = True
  1099. x_coeff = True
  1100. var1_mul_var2 = map(lambda x: x[0]*x[1], var_mul)
  1101. for v1_mul_v2 in var1_mul_var2:
  1102. try:
  1103. coeff = c[v1_mul_v2]
  1104. except KeyError:
  1105. coeff = 0
  1106. xy_coeff = bool(xy_coeff) and bool(coeff)
  1107. var_mul = list(subsets(v, 1))
  1108. # here var_mul is like [(x,), (y, )]
  1109. for v1 in var_mul:
  1110. try:
  1111. coeff = c[v1[0]]
  1112. except KeyError:
  1113. coeff = 0
  1114. x_coeff = bool(x_coeff) and bool(coeff)
  1115. if not any((xy_coeff, x_coeff)):
  1116. # means only x**2, y**2 and const is present
  1117. # so we can get more soln by permuting this soln.
  1118. do_permute_signs = True
  1119. elif not x_coeff:
  1120. # when coeff(x), coeff(y) is not present then signs of
  1121. # x, y can be permuted such that their sign are same
  1122. # as sign of x*y.
  1123. # e.g 1. (x_val,y_val)=> (x_val,y_val), (-x_val,-y_val)
  1124. # 2. (-x_vall, y_val)=> (-x_val,y_val), (x_val,-y_val)
  1125. permute_few_signs = True
  1126. if t == 'general_sum_of_squares':
  1127. # trying to factor such expressions will sometimes hang
  1128. terms = [(eq, 1)]
  1129. else:
  1130. raise TypeError
  1131. except (TypeError, NotImplementedError):
  1132. fl = factor_list(eq)
  1133. if fl[0].is_Rational and fl[0] != 1:
  1134. return diophantine(eq/fl[0], param=param, syms=syms, permute=permute)
  1135. terms = fl[1]
  1136. sols = set()
  1137. for term in terms:
  1138. base, _ = term
  1139. var_t, _, eq_type = classify_diop(base, _dict=False)
  1140. _, base = signsimp(base, evaluate=False).as_coeff_Mul()
  1141. solution = diop_solve(base, param)
  1142. if eq_type in [
  1143. Linear.name,
  1144. HomogeneousTernaryQuadratic.name,
  1145. HomogeneousTernaryQuadraticNormal.name,
  1146. GeneralPythagorean.name]:
  1147. sols.add(merge_solution(var, var_t, solution))
  1148. elif eq_type in [
  1149. BinaryQuadratic.name,
  1150. GeneralSumOfSquares.name,
  1151. GeneralSumOfEvenPowers.name,
  1152. Univariate.name]:
  1153. for sol in solution:
  1154. sols.add(merge_solution(var, var_t, sol))
  1155. else:
  1156. raise NotImplementedError('unhandled type: %s' % eq_type)
  1157. # remove null merge results
  1158. if () in sols:
  1159. sols.remove(())
  1160. null = tuple([0]*len(var))
  1161. # if there is no solution, return trivial solution
  1162. if not sols and eq.subs(zip(var, null)).is_zero:
  1163. sols.add(null)
  1164. final_soln = set()
  1165. for sol in sols:
  1166. if all(_is_int(s) for s in sol):
  1167. if do_permute_signs:
  1168. permuted_sign = set(permute_signs(sol))
  1169. final_soln.update(permuted_sign)
  1170. elif permute_few_signs:
  1171. lst = list(permute_signs(sol))
  1172. lst = list(filter(lambda x: x[0]*x[1] == sol[1]*sol[0], lst))
  1173. permuted_sign = set(lst)
  1174. final_soln.update(permuted_sign)
  1175. elif do_permute_signs_var:
  1176. permuted_sign_var = set(signed_permutations(sol))
  1177. final_soln.update(permuted_sign_var)
  1178. else:
  1179. final_soln.add(sol)
  1180. else:
  1181. final_soln.add(sol)
  1182. return final_soln
  1183. def merge_solution(var, var_t, solution):
  1184. """
  1185. This is used to construct the full solution from the solutions of sub
  1186. equations.
  1187. Explanation
  1188. ===========
  1189. For example when solving the equation `(x - y)(x^2 + y^2 - z^2) = 0`,
  1190. solutions for each of the equations `x - y = 0` and `x^2 + y^2 - z^2` are
  1191. found independently. Solutions for `x - y = 0` are `(x, y) = (t, t)`. But
  1192. we should introduce a value for z when we output the solution for the
  1193. original equation. This function converts `(t, t)` into `(t, t, n_{1})`
  1194. where `n_{1}` is an integer parameter.
  1195. """
  1196. sol = []
  1197. if None in solution:
  1198. return ()
  1199. solution = iter(solution)
  1200. params = numbered_symbols("n", integer=True, start=1)
  1201. for v in var:
  1202. if v in var_t:
  1203. sol.append(next(solution))
  1204. else:
  1205. sol.append(next(params))
  1206. for val, symb in zip(sol, var):
  1207. if check_assumptions(val, **symb.assumptions0) is False:
  1208. return tuple()
  1209. return tuple(sol)
  1210. def _diop_solve(eq, params=None):
  1211. for diop_type in all_diop_classes:
  1212. if diop_type(eq).matches():
  1213. return diop_type(eq).solve(parameters=params)
  1214. def diop_solve(eq, param=symbols("t", integer=True)):
  1215. """
  1216. Solves the diophantine equation ``eq``.
  1217. Explanation
  1218. ===========
  1219. Unlike ``diophantine()``, factoring of ``eq`` is not attempted. Uses
  1220. ``classify_diop()`` to determine the type of the equation and calls
  1221. the appropriate solver function.
  1222. Use of ``diophantine()`` is recommended over other helper functions.
  1223. ``diop_solve()`` can return either a set or a tuple depending on the
  1224. nature of the equation.
  1225. Usage
  1226. =====
  1227. ``diop_solve(eq, t)``: Solve diophantine equation, ``eq`` using ``t``
  1228. as a parameter if needed.
  1229. Details
  1230. =======
  1231. ``eq`` should be an expression which is assumed to be zero.
  1232. ``t`` is a parameter to be used in the solution.
  1233. Examples
  1234. ========
  1235. >>> from sympy.solvers.diophantine import diop_solve
  1236. >>> from sympy.abc import x, y, z, w
  1237. >>> diop_solve(2*x + 3*y - 5)
  1238. (3*t_0 - 5, 5 - 2*t_0)
  1239. >>> diop_solve(4*x + 3*y - 4*z + 5)
  1240. (t_0, 8*t_0 + 4*t_1 + 5, 7*t_0 + 3*t_1 + 5)
  1241. >>> diop_solve(x + 3*y - 4*z + w - 6)
  1242. (t_0, t_0 + t_1, 6*t_0 + 5*t_1 + 4*t_2 - 6, 5*t_0 + 4*t_1 + 3*t_2 - 6)
  1243. >>> diop_solve(x**2 + y**2 - 5)
  1244. {(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)}
  1245. See Also
  1246. ========
  1247. diophantine()
  1248. """
  1249. var, coeff, eq_type = classify_diop(eq, _dict=False)
  1250. if eq_type == Linear.name:
  1251. return diop_linear(eq, param)
  1252. elif eq_type == BinaryQuadratic.name:
  1253. return diop_quadratic(eq, param)
  1254. elif eq_type == HomogeneousTernaryQuadratic.name:
  1255. return diop_ternary_quadratic(eq, parameterize=True)
  1256. elif eq_type == HomogeneousTernaryQuadraticNormal.name:
  1257. return diop_ternary_quadratic_normal(eq, parameterize=True)
  1258. elif eq_type == GeneralPythagorean.name:
  1259. return diop_general_pythagorean(eq, param)
  1260. elif eq_type == Univariate.name:
  1261. return diop_univariate(eq)
  1262. elif eq_type == GeneralSumOfSquares.name:
  1263. return diop_general_sum_of_squares(eq, limit=S.Infinity)
  1264. elif eq_type == GeneralSumOfEvenPowers.name:
  1265. return diop_general_sum_of_even_powers(eq, limit=S.Infinity)
  1266. if eq_type is not None and eq_type not in diop_known:
  1267. raise ValueError(filldedent('''
  1268. Alhough this type of equation was identified, it is not yet
  1269. handled. It should, however, be listed in `diop_known` at the
  1270. top of this file. Developers should see comments at the end of
  1271. `classify_diop`.
  1272. ''')) # pragma: no cover
  1273. else:
  1274. raise NotImplementedError(
  1275. 'No solver has been written for %s.' % eq_type)
  1276. def classify_diop(eq, _dict=True):
  1277. # docstring supplied externally
  1278. matched = False
  1279. diop_type = None
  1280. for diop_class in all_diop_classes:
  1281. diop_type = diop_class(eq)
  1282. if diop_type.matches():
  1283. matched = True
  1284. break
  1285. if matched:
  1286. return diop_type.free_symbols, dict(diop_type.coeff) if _dict else diop_type.coeff, diop_type.name
  1287. # new diop type instructions
  1288. # --------------------------
  1289. # if this error raises and the equation *can* be classified,
  1290. # * it should be identified in the if-block above
  1291. # * the type should be added to the diop_known
  1292. # if a solver can be written for it,
  1293. # * a dedicated handler should be written (e.g. diop_linear)
  1294. # * it should be passed to that handler in diop_solve
  1295. raise NotImplementedError(filldedent('''
  1296. This equation is not yet recognized or else has not been
  1297. simplified sufficiently to put it in a form recognized by
  1298. diop_classify().'''))
  1299. classify_diop.func_doc = ( # type: ignore
  1300. '''
  1301. Helper routine used by diop_solve() to find information about ``eq``.
  1302. Explanation
  1303. ===========
  1304. Returns a tuple containing the type of the diophantine equation
  1305. along with the variables (free symbols) and their coefficients.
  1306. Variables are returned as a list and coefficients are returned
  1307. as a dict with the key being the respective term and the constant
  1308. term is keyed to 1. The type is one of the following:
  1309. * %s
  1310. Usage
  1311. =====
  1312. ``classify_diop(eq)``: Return variables, coefficients and type of the
  1313. ``eq``.
  1314. Details
  1315. =======
  1316. ``eq`` should be an expression which is assumed to be zero.
  1317. ``_dict`` is for internal use: when True (default) a dict is returned,
  1318. otherwise a defaultdict which supplies 0 for missing keys is returned.
  1319. Examples
  1320. ========
  1321. >>> from sympy.solvers.diophantine import classify_diop
  1322. >>> from sympy.abc import x, y, z, w, t
  1323. >>> classify_diop(4*x + 6*y - 4)
  1324. ([x, y], {1: -4, x: 4, y: 6}, 'linear')
  1325. >>> classify_diop(x + 3*y -4*z + 5)
  1326. ([x, y, z], {1: 5, x: 1, y: 3, z: -4}, 'linear')
  1327. >>> classify_diop(x**2 + y**2 - x*y + x + 5)
  1328. ([x, y], {1: 5, x: 1, x**2: 1, y**2: 1, x*y: -1}, 'binary_quadratic')
  1329. ''' % ('\n * '.join(sorted(diop_known))))
  1330. def diop_linear(eq, param=symbols("t", integer=True)):
  1331. """
  1332. Solves linear diophantine equations.
  1333. A linear diophantine equation is an equation of the form `a_{1}x_{1} +
  1334. a_{2}x_{2} + .. + a_{n}x_{n} = 0` where `a_{1}, a_{2}, ..a_{n}` are
  1335. integer constants and `x_{1}, x_{2}, ..x_{n}` are integer variables.
  1336. Usage
  1337. =====
  1338. ``diop_linear(eq)``: Returns a tuple containing solutions to the
  1339. diophantine equation ``eq``. Values in the tuple is arranged in the same
  1340. order as the sorted variables.
  1341. Details
  1342. =======
  1343. ``eq`` is a linear diophantine equation which is assumed to be zero.
  1344. ``param`` is the parameter to be used in the solution.
  1345. Examples
  1346. ========
  1347. >>> from sympy.solvers.diophantine.diophantine import diop_linear
  1348. >>> from sympy.abc import x, y, z
  1349. >>> diop_linear(2*x - 3*y - 5) # solves equation 2*x - 3*y - 5 == 0
  1350. (3*t_0 - 5, 2*t_0 - 5)
  1351. Here x = -3*t_0 - 5 and y = -2*t_0 - 5
  1352. >>> diop_linear(2*x - 3*y - 4*z -3)
  1353. (t_0, 2*t_0 + 4*t_1 + 3, -t_0 - 3*t_1 - 3)
  1354. See Also
  1355. ========
  1356. diop_quadratic(), diop_ternary_quadratic(), diop_general_pythagorean(),
  1357. diop_general_sum_of_squares()
  1358. """
  1359. var, coeff, diop_type = classify_diop(eq, _dict=False)
  1360. if diop_type == Linear.name:
  1361. parameters = None
  1362. if param is not None:
  1363. parameters = symbols('%s_0:%i' % (param, len(var)), integer=True)
  1364. result = Linear(eq).solve(parameters=parameters)
  1365. if param is None:
  1366. result = result(*[0]*len(result.parameters))
  1367. if len(result) > 0:
  1368. return list(result)[0]
  1369. else:
  1370. return tuple([None]*len(result.parameters))
  1371. def base_solution_linear(c, a, b, t=None):
  1372. """
  1373. Return the base solution for the linear equation, `ax + by = c`.
  1374. Explanation
  1375. ===========
  1376. Used by ``diop_linear()`` to find the base solution of a linear
  1377. Diophantine equation. If ``t`` is given then the parametrized solution is
  1378. returned.
  1379. Usage
  1380. =====
  1381. ``base_solution_linear(c, a, b, t)``: ``a``, ``b``, ``c`` are coefficients
  1382. in `ax + by = c` and ``t`` is the parameter to be used in the solution.
  1383. Examples
  1384. ========
  1385. >>> from sympy.solvers.diophantine.diophantine import base_solution_linear
  1386. >>> from sympy.abc import t
  1387. >>> base_solution_linear(5, 2, 3) # equation 2*x + 3*y = 5
  1388. (-5, 5)
  1389. >>> base_solution_linear(0, 5, 7) # equation 5*x + 7*y = 0
  1390. (0, 0)
  1391. >>> base_solution_linear(5, 2, 3, t) # equation 2*x + 3*y = 5
  1392. (3*t - 5, 5 - 2*t)
  1393. >>> base_solution_linear(0, 5, 7, t) # equation 5*x + 7*y = 0
  1394. (7*t, -5*t)
  1395. """
  1396. a, b, c = _remove_gcd(a, b, c)
  1397. if c == 0:
  1398. if t is not None:
  1399. if b < 0:
  1400. t = -t
  1401. return (b*t, -a*t)
  1402. else:
  1403. return (0, 0)
  1404. else:
  1405. x0, y0, d = igcdex(abs(a), abs(b))
  1406. x0 *= sign(a)
  1407. y0 *= sign(b)
  1408. if divisible(c, d):
  1409. if t is not None:
  1410. if b < 0:
  1411. t = -t
  1412. return (c*x0 + b*t, c*y0 - a*t)
  1413. else:
  1414. return (c*x0, c*y0)
  1415. else:
  1416. return (None, None)
  1417. def diop_univariate(eq):
  1418. """
  1419. Solves a univariate diophantine equations.
  1420. Explanation
  1421. ===========
  1422. A univariate diophantine equation is an equation of the form
  1423. `a_{0} + a_{1}x + a_{2}x^2 + .. + a_{n}x^n = 0` where `a_{1}, a_{2}, ..a_{n}` are
  1424. integer constants and `x` is an integer variable.
  1425. Usage
  1426. =====
  1427. ``diop_univariate(eq)``: Returns a set containing solutions to the
  1428. diophantine equation ``eq``.
  1429. Details
  1430. =======
  1431. ``eq`` is a univariate diophantine equation which is assumed to be zero.
  1432. Examples
  1433. ========
  1434. >>> from sympy.solvers.diophantine.diophantine import diop_univariate
  1435. >>> from sympy.abc import x
  1436. >>> diop_univariate((x - 2)*(x - 3)**2) # solves equation (x - 2)*(x - 3)**2 == 0
  1437. {(2,), (3,)}
  1438. """
  1439. var, coeff, diop_type = classify_diop(eq, _dict=False)
  1440. if diop_type == Univariate.name:
  1441. return {(int(i),) for i in solveset_real(
  1442. eq, var[0]).intersect(S.Integers)}
  1443. def divisible(a, b):
  1444. """
  1445. Returns `True` if ``a`` is divisible by ``b`` and `False` otherwise.
  1446. """
  1447. return not a % b
  1448. def diop_quadratic(eq, param=symbols("t", integer=True)):
  1449. """
  1450. Solves quadratic diophantine equations.
  1451. i.e. equations of the form `Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0`. Returns a
  1452. set containing the tuples `(x, y)` which contains the solutions. If there
  1453. are no solutions then `(None, None)` is returned.
  1454. Usage
  1455. =====
  1456. ``diop_quadratic(eq, param)``: ``eq`` is a quadratic binary diophantine
  1457. equation. ``param`` is used to indicate the parameter to be used in the
  1458. solution.
  1459. Details
  1460. =======
  1461. ``eq`` should be an expression which is assumed to be zero.
  1462. ``param`` is a parameter to be used in the solution.
  1463. Examples
  1464. ========
  1465. >>> from sympy.abc import x, y, t
  1466. >>> from sympy.solvers.diophantine.diophantine import diop_quadratic
  1467. >>> diop_quadratic(x**2 + y**2 + 2*x + 2*y + 2, t)
  1468. {(-1, -1)}
  1469. References
  1470. ==========
  1471. .. [1] Methods to solve Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0, [online],
  1472. Available: http://www.alpertron.com.ar/METHODS.HTM
  1473. .. [2] Solving the equation ax^2+ bxy + cy^2 + dx + ey + f= 0, [online],
  1474. Available: https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf
  1475. See Also
  1476. ========
  1477. diop_linear(), diop_ternary_quadratic(), diop_general_sum_of_squares(),
  1478. diop_general_pythagorean()
  1479. """
  1480. var, coeff, diop_type = classify_diop(eq, _dict=False)
  1481. if diop_type == BinaryQuadratic.name:
  1482. if param is not None:
  1483. parameters = [param, Symbol("u", integer=True)]
  1484. else:
  1485. parameters = None
  1486. return set(BinaryQuadratic(eq).solve(parameters=parameters))
  1487. def is_solution_quad(var, coeff, u, v):
  1488. """
  1489. Check whether `(u, v)` is solution to the quadratic binary diophantine
  1490. equation with the variable list ``var`` and coefficient dictionary
  1491. ``coeff``.
  1492. Not intended for use by normal users.
  1493. """
  1494. reps = dict(zip(var, (u, v)))
  1495. eq = Add(*[j*i.xreplace(reps) for i, j in coeff.items()])
  1496. return _mexpand(eq) == 0
  1497. def diop_DN(D, N, t=symbols("t", integer=True)):
  1498. """
  1499. Solves the equation `x^2 - Dy^2 = N`.
  1500. Explanation
  1501. ===========
  1502. Mainly concerned with the case `D > 0, D` is not a perfect square,
  1503. which is the same as the generalized Pell equation. The LMM
  1504. algorithm [1]_ is used to solve this equation.
  1505. Returns one solution tuple, (`x, y)` for each class of the solutions.
  1506. Other solutions of the class can be constructed according to the
  1507. values of ``D`` and ``N``.
  1508. Usage
  1509. =====
  1510. ``diop_DN(D, N, t)``: D and N are integers as in `x^2 - Dy^2 = N` and
  1511. ``t`` is the parameter to be used in the solutions.
  1512. Details
  1513. =======
  1514. ``D`` and ``N`` correspond to D and N in the equation.
  1515. ``t`` is the parameter to be used in the solutions.
  1516. Examples
  1517. ========
  1518. >>> from sympy.solvers.diophantine.diophantine import diop_DN
  1519. >>> diop_DN(13, -4) # Solves equation x**2 - 13*y**2 = -4
  1520. [(3, 1), (393, 109), (36, 10)]
  1521. The output can be interpreted as follows: There are three fundamental
  1522. solutions to the equation `x^2 - 13y^2 = -4` given by (3, 1), (393, 109)
  1523. and (36, 10). Each tuple is in the form (x, y), i.e. solution (3, 1) means
  1524. that `x = 3` and `y = 1`.
  1525. >>> diop_DN(986, 1) # Solves equation x**2 - 986*y**2 = 1
  1526. [(49299, 1570)]
  1527. See Also
  1528. ========
  1529. find_DN(), diop_bf_DN()
  1530. References
  1531. ==========
  1532. .. [1] Solving the generalized Pell equation x**2 - D*y**2 = N, John P.
  1533. Robertson, July 31, 2004, Pages 16 - 17. [online], Available:
  1534. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf
  1535. """
  1536. if D < 0:
  1537. if N == 0:
  1538. return [(0, 0)]
  1539. elif N < 0:
  1540. return []
  1541. elif N > 0:
  1542. sol = []
  1543. for d in divisors(square_factor(N)):
  1544. sols = cornacchia(1, -D, N // d**2)
  1545. if sols:
  1546. for x, y in sols:
  1547. sol.append((d*x, d*y))
  1548. if D == -1:
  1549. sol.append((d*y, d*x))
  1550. return sol
  1551. elif D == 0:
  1552. if N < 0:
  1553. return []
  1554. if N == 0:
  1555. return [(0, t)]
  1556. sN, _exact = integer_nthroot(N, 2)
  1557. if _exact:
  1558. return [(sN, t)]
  1559. else:
  1560. return []
  1561. else: # D > 0
  1562. sD, _exact = integer_nthroot(D, 2)
  1563. if _exact:
  1564. if N == 0:
  1565. return [(sD*t, t)]
  1566. else:
  1567. sol = []
  1568. for y in range(floor(sign(N)*(N - 1)/(2*sD)) + 1):
  1569. try:
  1570. sq, _exact = integer_nthroot(D*y**2 + N, 2)
  1571. except ValueError:
  1572. _exact = False
  1573. if _exact:
  1574. sol.append((sq, y))
  1575. return sol
  1576. elif 1 < N**2 < D:
  1577. # It is much faster to call `_special_diop_DN`.
  1578. return _special_diop_DN(D, N)
  1579. else:
  1580. if N == 0:
  1581. return [(0, 0)]
  1582. elif abs(N) == 1:
  1583. pqa = PQa(0, 1, D)
  1584. j = 0
  1585. G = []
  1586. B = []
  1587. for i in pqa:
  1588. a = i[2]
  1589. G.append(i[5])
  1590. B.append(i[4])
  1591. if j != 0 and a == 2*sD:
  1592. break
  1593. j = j + 1
  1594. if _odd(j):
  1595. if N == -1:
  1596. x = G[j - 1]
  1597. y = B[j - 1]
  1598. else:
  1599. count = j
  1600. while count < 2*j - 1:
  1601. i = next(pqa)
  1602. G.append(i[5])
  1603. B.append(i[4])
  1604. count += 1
  1605. x = G[count]
  1606. y = B[count]
  1607. else:
  1608. if N == 1:
  1609. x = G[j - 1]
  1610. y = B[j - 1]
  1611. else:
  1612. return []
  1613. return [(x, y)]
  1614. else:
  1615. fs = []
  1616. sol = []
  1617. div = divisors(N)
  1618. for d in div:
  1619. if divisible(N, d**2):
  1620. fs.append(d)
  1621. for f in fs:
  1622. m = N // f**2
  1623. zs = sqrt_mod(D, abs(m), all_roots=True)
  1624. zs = [i for i in zs if i <= abs(m) // 2 ]
  1625. if abs(m) != 2:
  1626. zs = zs + [-i for i in zs if i] # omit dupl 0
  1627. for z in zs:
  1628. pqa = PQa(z, abs(m), D)
  1629. j = 0
  1630. G = []
  1631. B = []
  1632. for i in pqa:
  1633. G.append(i[5])
  1634. B.append(i[4])
  1635. if j != 0 and abs(i[1]) == 1:
  1636. r = G[j-1]
  1637. s = B[j-1]
  1638. if r**2 - D*s**2 == m:
  1639. sol.append((f*r, f*s))
  1640. elif diop_DN(D, -1) != []:
  1641. a = diop_DN(D, -1)
  1642. sol.append((f*(r*a[0][0] + a[0][1]*s*D), f*(r*a[0][1] + s*a[0][0])))
  1643. break
  1644. j = j + 1
  1645. if j == length(z, abs(m), D):
  1646. break
  1647. return sol
  1648. def _special_diop_DN(D, N):
  1649. """
  1650. Solves the equation `x^2 - Dy^2 = N` for the special case where
  1651. `1 < N**2 < D` and `D` is not a perfect square.
  1652. It is better to call `diop_DN` rather than this function, as
  1653. the former checks the condition `1 < N**2 < D`, and calls the latter only
  1654. if appropriate.
  1655. Usage
  1656. =====
  1657. WARNING: Internal method. Do not call directly!
  1658. ``_special_diop_DN(D, N)``: D and N are integers as in `x^2 - Dy^2 = N`.
  1659. Details
  1660. =======
  1661. ``D`` and ``N`` correspond to D and N in the equation.
  1662. Examples
  1663. ========
  1664. >>> from sympy.solvers.diophantine.diophantine import _special_diop_DN
  1665. >>> _special_diop_DN(13, -3) # Solves equation x**2 - 13*y**2 = -3
  1666. [(7, 2), (137, 38)]
  1667. The output can be interpreted as follows: There are two fundamental
  1668. solutions to the equation `x^2 - 13y^2 = -3` given by (7, 2) and
  1669. (137, 38). Each tuple is in the form (x, y), i.e. solution (7, 2) means
  1670. that `x = 7` and `y = 2`.
  1671. >>> _special_diop_DN(2445, -20) # Solves equation x**2 - 2445*y**2 = -20
  1672. [(445, 9), (17625560, 356454), (698095554475, 14118073569)]
  1673. See Also
  1674. ========
  1675. diop_DN()
  1676. References
  1677. ==========
  1678. .. [1] Section 4.4.4 of the following book:
  1679. Quadratic Diophantine Equations, T. Andreescu and D. Andrica,
  1680. Springer, 2015.
  1681. """
  1682. # The following assertion was removed for efficiency, with the understanding
  1683. # that this method is not called directly. The parent method, `diop_DN`
  1684. # is responsible for performing the appropriate checks.
  1685. #
  1686. # assert (1 < N**2 < D) and (not integer_nthroot(D, 2)[1])
  1687. sqrt_D = sqrt(D)
  1688. F = [(N, 1)]
  1689. f = 2
  1690. while True:
  1691. f2 = f**2
  1692. if f2 > abs(N):
  1693. break
  1694. n, r = divmod(N, f2)
  1695. if r == 0:
  1696. F.append((n, f))
  1697. f += 1
  1698. P = 0
  1699. Q = 1
  1700. G0, G1 = 0, 1
  1701. B0, B1 = 1, 0
  1702. solutions = []
  1703. i = 0
  1704. while True:
  1705. a = floor((P + sqrt_D) / Q)
  1706. P = a*Q - P
  1707. Q = (D - P**2) // Q
  1708. G2 = a*G1 + G0
  1709. B2 = a*B1 + B0
  1710. for n, f in F:
  1711. if G2**2 - D*B2**2 == n:
  1712. solutions.append((f*G2, f*B2))
  1713. i += 1
  1714. if Q == 1 and i % 2 == 0:
  1715. break
  1716. G0, G1 = G1, G2
  1717. B0, B1 = B1, B2
  1718. return solutions
  1719. def cornacchia(a, b, m):
  1720. r"""
  1721. Solves `ax^2 + by^2 = m` where `\gcd(a, b) = 1 = gcd(a, m)` and `a, b > 0`.
  1722. Explanation
  1723. ===========
  1724. Uses the algorithm due to Cornacchia. The method only finds primitive
  1725. solutions, i.e. ones with `\gcd(x, y) = 1`. So this method cannot be used to
  1726. find the solutions of `x^2 + y^2 = 20` since the only solution to former is
  1727. `(x, y) = (4, 2)` and it is not primitive. When `a = b`, only the
  1728. solutions with `x \leq y` are found. For more details, see the References.
  1729. Examples
  1730. ========
  1731. >>> from sympy.solvers.diophantine.diophantine import cornacchia
  1732. >>> cornacchia(2, 3, 35) # equation 2x**2 + 3y**2 = 35
  1733. {(2, 3), (4, 1)}
  1734. >>> cornacchia(1, 1, 25) # equation x**2 + y**2 = 25
  1735. {(4, 3)}
  1736. References
  1737. ===========
  1738. .. [1] A. Nitaj, "L'algorithme de Cornacchia"
  1739. .. [2] Solving the diophantine equation ax**2 + by**2 = m by Cornacchia's
  1740. method, [online], Available:
  1741. http://www.numbertheory.org/php/cornacchia.html
  1742. See Also
  1743. ========
  1744. sympy.utilities.iterables.signed_permutations
  1745. """
  1746. sols = set()
  1747. a1 = igcdex(a, m)[0]
  1748. v = sqrt_mod(-b*a1, m, all_roots=True)
  1749. if not v:
  1750. return None
  1751. for t in v:
  1752. if t < m // 2:
  1753. continue
  1754. u, r = t, m
  1755. while True:
  1756. u, r = r, u % r
  1757. if a*r**2 < m:
  1758. break
  1759. m1 = m - a*r**2
  1760. if m1 % b == 0:
  1761. m1 = m1 // b
  1762. s, _exact = integer_nthroot(m1, 2)
  1763. if _exact:
  1764. if a == b and r < s:
  1765. r, s = s, r
  1766. sols.add((int(r), int(s)))
  1767. return sols
  1768. def PQa(P_0, Q_0, D):
  1769. r"""
  1770. Returns useful information needed to solve the Pell equation.
  1771. Explanation
  1772. ===========
  1773. There are six sequences of integers defined related to the continued
  1774. fraction representation of `\\frac{P + \sqrt{D}}{Q}`, namely {`P_{i}`},
  1775. {`Q_{i}`}, {`a_{i}`},{`A_{i}`}, {`B_{i}`}, {`G_{i}`}. ``PQa()`` Returns
  1776. these values as a 6-tuple in the same order as mentioned above. Refer [1]_
  1777. for more detailed information.
  1778. Usage
  1779. =====
  1780. ``PQa(P_0, Q_0, D)``: ``P_0``, ``Q_0`` and ``D`` are integers corresponding
  1781. to `P_{0}`, `Q_{0}` and `D` in the continued fraction
  1782. `\\frac{P_{0} + \sqrt{D}}{Q_{0}}`.
  1783. Also it's assumed that `P_{0}^2 == D mod(|Q_{0}|)` and `D` is square free.
  1784. Examples
  1785. ========
  1786. >>> from sympy.solvers.diophantine.diophantine import PQa
  1787. >>> pqa = PQa(13, 4, 5) # (13 + sqrt(5))/4
  1788. >>> next(pqa) # (P_0, Q_0, a_0, A_0, B_0, G_0)
  1789. (13, 4, 3, 3, 1, -1)
  1790. >>> next(pqa) # (P_1, Q_1, a_1, A_1, B_1, G_1)
  1791. (-1, 1, 1, 4, 1, 3)
  1792. References
  1793. ==========
  1794. .. [1] Solving the generalized Pell equation x^2 - Dy^2 = N, John P.
  1795. Robertson, July 31, 2004, Pages 4 - 8. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf
  1796. """
  1797. A_i_2 = B_i_1 = 0
  1798. A_i_1 = B_i_2 = 1
  1799. G_i_2 = -P_0
  1800. G_i_1 = Q_0
  1801. P_i = P_0
  1802. Q_i = Q_0
  1803. while True:
  1804. a_i = floor((P_i + sqrt(D))/Q_i)
  1805. A_i = a_i*A_i_1 + A_i_2
  1806. B_i = a_i*B_i_1 + B_i_2
  1807. G_i = a_i*G_i_1 + G_i_2
  1808. yield P_i, Q_i, a_i, A_i, B_i, G_i
  1809. A_i_1, A_i_2 = A_i, A_i_1
  1810. B_i_1, B_i_2 = B_i, B_i_1
  1811. G_i_1, G_i_2 = G_i, G_i_1
  1812. P_i = a_i*Q_i - P_i
  1813. Q_i = (D - P_i**2)/Q_i
  1814. def diop_bf_DN(D, N, t=symbols("t", integer=True)):
  1815. r"""
  1816. Uses brute force to solve the equation, `x^2 - Dy^2 = N`.
  1817. Explanation
  1818. ===========
  1819. Mainly concerned with the generalized Pell equation which is the case when
  1820. `D > 0, D` is not a perfect square. For more information on the case refer
  1821. [1]_. Let `(t, u)` be the minimal positive solution of the equation
  1822. `x^2 - Dy^2 = 1`. Then this method requires
  1823. `\sqrt{\\frac{\mid N \mid (t \pm 1)}{2D}}` to be small.
  1824. Usage
  1825. =====
  1826. ``diop_bf_DN(D, N, t)``: ``D`` and ``N`` are coefficients in
  1827. `x^2 - Dy^2 = N` and ``t`` is the parameter to be used in the solutions.
  1828. Details
  1829. =======
  1830. ``D`` and ``N`` correspond to D and N in the equation.
  1831. ``t`` is the parameter to be used in the solutions.
  1832. Examples
  1833. ========
  1834. >>> from sympy.solvers.diophantine.diophantine import diop_bf_DN
  1835. >>> diop_bf_DN(13, -4)
  1836. [(3, 1), (-3, 1), (36, 10)]
  1837. >>> diop_bf_DN(986, 1)
  1838. [(49299, 1570)]
  1839. See Also
  1840. ========
  1841. diop_DN()
  1842. References
  1843. ==========
  1844. .. [1] Solving the generalized Pell equation x**2 - D*y**2 = N, John P.
  1845. Robertson, July 31, 2004, Page 15. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf
  1846. """
  1847. D = as_int(D)
  1848. N = as_int(N)
  1849. sol = []
  1850. a = diop_DN(D, 1)
  1851. u = a[0][0]
  1852. if abs(N) == 1:
  1853. return diop_DN(D, N)
  1854. elif N > 1:
  1855. L1 = 0
  1856. L2 = integer_nthroot(int(N*(u - 1)/(2*D)), 2)[0] + 1
  1857. elif N < -1:
  1858. L1, _exact = integer_nthroot(-int(N/D), 2)
  1859. if not _exact:
  1860. L1 += 1
  1861. L2 = integer_nthroot(-int(N*(u + 1)/(2*D)), 2)[0] + 1
  1862. else: # N = 0
  1863. if D < 0:
  1864. return [(0, 0)]
  1865. elif D == 0:
  1866. return [(0, t)]
  1867. else:
  1868. sD, _exact = integer_nthroot(D, 2)
  1869. if _exact:
  1870. return [(sD*t, t), (-sD*t, t)]
  1871. else:
  1872. return [(0, 0)]
  1873. for y in range(L1, L2):
  1874. try:
  1875. x, _exact = integer_nthroot(N + D*y**2, 2)
  1876. except ValueError:
  1877. _exact = False
  1878. if _exact:
  1879. sol.append((x, y))
  1880. if not equivalent(x, y, -x, y, D, N):
  1881. sol.append((-x, y))
  1882. return sol
  1883. def equivalent(u, v, r, s, D, N):
  1884. """
  1885. Returns True if two solutions `(u, v)` and `(r, s)` of `x^2 - Dy^2 = N`
  1886. belongs to the same equivalence class and False otherwise.
  1887. Explanation
  1888. ===========
  1889. Two solutions `(u, v)` and `(r, s)` to the above equation fall to the same
  1890. equivalence class iff both `(ur - Dvs)` and `(us - vr)` are divisible by
  1891. `N`. See reference [1]_. No test is performed to test whether `(u, v)` and
  1892. `(r, s)` are actually solutions to the equation. User should take care of
  1893. this.
  1894. Usage
  1895. =====
  1896. ``equivalent(u, v, r, s, D, N)``: `(u, v)` and `(r, s)` are two solutions
  1897. of the equation `x^2 - Dy^2 = N` and all parameters involved are integers.
  1898. Examples
  1899. ========
  1900. >>> from sympy.solvers.diophantine.diophantine import equivalent
  1901. >>> equivalent(18, 5, -18, -5, 13, -1)
  1902. True
  1903. >>> equivalent(3, 1, -18, 393, 109, -4)
  1904. False
  1905. References
  1906. ==========
  1907. .. [1] Solving the generalized Pell equation x**2 - D*y**2 = N, John P.
  1908. Robertson, July 31, 2004, Page 12. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf
  1909. """
  1910. return divisible(u*r - D*v*s, N) and divisible(u*s - v*r, N)
  1911. def length(P, Q, D):
  1912. r"""
  1913. Returns the (length of aperiodic part + length of periodic part) of
  1914. continued fraction representation of `\\frac{P + \sqrt{D}}{Q}`.
  1915. It is important to remember that this does NOT return the length of the
  1916. periodic part but the sum of the lengths of the two parts as mentioned
  1917. above.
  1918. Usage
  1919. =====
  1920. ``length(P, Q, D)``: ``P``, ``Q`` and ``D`` are integers corresponding to
  1921. the continued fraction `\\frac{P + \sqrt{D}}{Q}`.
  1922. Details
  1923. =======
  1924. ``P``, ``D`` and ``Q`` corresponds to P, D and Q in the continued fraction,
  1925. `\\frac{P + \sqrt{D}}{Q}`.
  1926. Examples
  1927. ========
  1928. >>> from sympy.solvers.diophantine.diophantine import length
  1929. >>> length(-2, 4, 5) # (-2 + sqrt(5))/4
  1930. 3
  1931. >>> length(-5, 4, 17) # (-5 + sqrt(17))/4
  1932. 4
  1933. See Also
  1934. ========
  1935. sympy.ntheory.continued_fraction.continued_fraction_periodic
  1936. """
  1937. from sympy.ntheory.continued_fraction import continued_fraction_periodic
  1938. v = continued_fraction_periodic(P, Q, D)
  1939. if isinstance(v[-1], list):
  1940. rpt = len(v[-1])
  1941. nonrpt = len(v) - 1
  1942. else:
  1943. rpt = 0
  1944. nonrpt = len(v)
  1945. return rpt + nonrpt
  1946. def transformation_to_DN(eq):
  1947. """
  1948. This function transforms general quadratic,
  1949. `ax^2 + bxy + cy^2 + dx + ey + f = 0`
  1950. to more easy to deal with `X^2 - DY^2 = N` form.
  1951. Explanation
  1952. ===========
  1953. This is used to solve the general quadratic equation by transforming it to
  1954. the latter form. Refer to [1]_ for more detailed information on the
  1955. transformation. This function returns a tuple (A, B) where A is a 2 X 2
  1956. matrix and B is a 2 X 1 matrix such that,
  1957. Transpose([x y]) = A * Transpose([X Y]) + B
  1958. Usage
  1959. =====
  1960. ``transformation_to_DN(eq)``: where ``eq`` is the quadratic to be
  1961. transformed.
  1962. Examples
  1963. ========
  1964. >>> from sympy.abc import x, y
  1965. >>> from sympy.solvers.diophantine.diophantine import transformation_to_DN
  1966. >>> A, B = transformation_to_DN(x**2 - 3*x*y - y**2 - 2*y + 1)
  1967. >>> A
  1968. Matrix([
  1969. [1/26, 3/26],
  1970. [ 0, 1/13]])
  1971. >>> B
  1972. Matrix([
  1973. [-6/13],
  1974. [-4/13]])
  1975. A, B returned are such that Transpose((x y)) = A * Transpose((X Y)) + B.
  1976. Substituting these values for `x` and `y` and a bit of simplifying work
  1977. will give an equation of the form `x^2 - Dy^2 = N`.
  1978. >>> from sympy.abc import X, Y
  1979. >>> from sympy import Matrix, simplify
  1980. >>> u = (A*Matrix([X, Y]) + B)[0] # Transformation for x
  1981. >>> u
  1982. X/26 + 3*Y/26 - 6/13
  1983. >>> v = (A*Matrix([X, Y]) + B)[1] # Transformation for y
  1984. >>> v
  1985. Y/13 - 4/13
  1986. Next we will substitute these formulas for `x` and `y` and do
  1987. ``simplify()``.
  1988. >>> eq = simplify((x**2 - 3*x*y - y**2 - 2*y + 1).subs(zip((x, y), (u, v))))
  1989. >>> eq
  1990. X**2/676 - Y**2/52 + 17/13
  1991. By multiplying the denominator appropriately, we can get a Pell equation
  1992. in the standard form.
  1993. >>> eq * 676
  1994. X**2 - 13*Y**2 + 884
  1995. If only the final equation is needed, ``find_DN()`` can be used.
  1996. See Also
  1997. ========
  1998. find_DN()
  1999. References
  2000. ==========
  2001. .. [1] Solving the equation ax^2 + bxy + cy^2 + dx + ey + f = 0,
  2002. John P.Robertson, May 8, 2003, Page 7 - 11.
  2003. https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf
  2004. """
  2005. var, coeff, diop_type = classify_diop(eq, _dict=False)
  2006. if diop_type == BinaryQuadratic.name:
  2007. return _transformation_to_DN(var, coeff)
  2008. def _transformation_to_DN(var, coeff):
  2009. x, y = var
  2010. a = coeff[x**2]
  2011. b = coeff[x*y]
  2012. c = coeff[y**2]
  2013. d = coeff[x]
  2014. e = coeff[y]
  2015. f = coeff[1]
  2016. a, b, c, d, e, f = [as_int(i) for i in _remove_gcd(a, b, c, d, e, f)]
  2017. X, Y = symbols("X, Y", integer=True)
  2018. if b:
  2019. B, C = _rational_pq(2*a, b)
  2020. A, T = _rational_pq(a, B**2)
  2021. # eq_1 = A*B*X**2 + B*(c*T - A*C**2)*Y**2 + d*T*X + (B*e*T - d*T*C)*Y + f*T*B
  2022. coeff = {X**2: A*B, X*Y: 0, Y**2: B*(c*T - A*C**2), X: d*T, Y: B*e*T - d*T*C, 1: f*T*B}
  2023. A_0, B_0 = _transformation_to_DN([X, Y], coeff)
  2024. return Matrix(2, 2, [S.One/B, -S(C)/B, 0, 1])*A_0, Matrix(2, 2, [S.One/B, -S(C)/B, 0, 1])*B_0
  2025. else:
  2026. if d:
  2027. B, C = _rational_pq(2*a, d)
  2028. A, T = _rational_pq(a, B**2)
  2029. # eq_2 = A*X**2 + c*T*Y**2 + e*T*Y + f*T - A*C**2
  2030. coeff = {X**2: A, X*Y: 0, Y**2: c*T, X: 0, Y: e*T, 1: f*T - A*C**2}
  2031. A_0, B_0 = _transformation_to_DN([X, Y], coeff)
  2032. return Matrix(2, 2, [S.One/B, 0, 0, 1])*A_0, Matrix(2, 2, [S.One/B, 0, 0, 1])*B_0 + Matrix([-S(C)/B, 0])
  2033. else:
  2034. if e:
  2035. B, C = _rational_pq(2*c, e)
  2036. A, T = _rational_pq(c, B**2)
  2037. # eq_3 = a*T*X**2 + A*Y**2 + f*T - A*C**2
  2038. coeff = {X**2: a*T, X*Y: 0, Y**2: A, X: 0, Y: 0, 1: f*T - A*C**2}
  2039. A_0, B_0 = _transformation_to_DN([X, Y], coeff)
  2040. return Matrix(2, 2, [1, 0, 0, S.One/B])*A_0, Matrix(2, 2, [1, 0, 0, S.One/B])*B_0 + Matrix([0, -S(C)/B])
  2041. else:
  2042. # TODO: pre-simplification: Not necessary but may simplify
  2043. # the equation.
  2044. return Matrix(2, 2, [S.One/a, 0, 0, 1]), Matrix([0, 0])
  2045. def find_DN(eq):
  2046. """
  2047. This function returns a tuple, `(D, N)` of the simplified form,
  2048. `x^2 - Dy^2 = N`, corresponding to the general quadratic,
  2049. `ax^2 + bxy + cy^2 + dx + ey + f = 0`.
  2050. Solving the general quadratic is then equivalent to solving the equation
  2051. `X^2 - DY^2 = N` and transforming the solutions by using the transformation
  2052. matrices returned by ``transformation_to_DN()``.
  2053. Usage
  2054. =====
  2055. ``find_DN(eq)``: where ``eq`` is the quadratic to be transformed.
  2056. Examples
  2057. ========
  2058. >>> from sympy.abc import x, y
  2059. >>> from sympy.solvers.diophantine.diophantine import find_DN
  2060. >>> find_DN(x**2 - 3*x*y - y**2 - 2*y + 1)
  2061. (13, -884)
  2062. Interpretation of the output is that we get `X^2 -13Y^2 = -884` after
  2063. transforming `x^2 - 3xy - y^2 - 2y + 1` using the transformation returned
  2064. by ``transformation_to_DN()``.
  2065. See Also
  2066. ========
  2067. transformation_to_DN()
  2068. References
  2069. ==========
  2070. .. [1] Solving the equation ax^2 + bxy + cy^2 + dx + ey + f = 0,
  2071. John P.Robertson, May 8, 2003, Page 7 - 11.
  2072. https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf
  2073. """
  2074. var, coeff, diop_type = classify_diop(eq, _dict=False)
  2075. if diop_type == BinaryQuadratic.name:
  2076. return _find_DN(var, coeff)
  2077. def _find_DN(var, coeff):
  2078. x, y = var
  2079. X, Y = symbols("X, Y", integer=True)
  2080. A, B = _transformation_to_DN(var, coeff)
  2081. u = (A*Matrix([X, Y]) + B)[0]
  2082. v = (A*Matrix([X, Y]) + B)[1]
  2083. eq = x**2*coeff[x**2] + x*y*coeff[x*y] + y**2*coeff[y**2] + x*coeff[x] + y*coeff[y] + coeff[1]
  2084. simplified = _mexpand(eq.subs(zip((x, y), (u, v))))
  2085. coeff = simplified.as_coefficients_dict()
  2086. return -coeff[Y**2]/coeff[X**2], -coeff[1]/coeff[X**2]
  2087. def check_param(x, y, a, params):
  2088. """
  2089. If there is a number modulo ``a`` such that ``x`` and ``y`` are both
  2090. integers, then return a parametric representation for ``x`` and ``y``
  2091. else return (None, None).
  2092. Here ``x`` and ``y`` are functions of ``t``.
  2093. """
  2094. from sympy.simplify.simplify import clear_coefficients
  2095. if x.is_number and not x.is_Integer:
  2096. return DiophantineSolutionSet([x, y], parameters=params)
  2097. if y.is_number and not y.is_Integer:
  2098. return DiophantineSolutionSet([x, y], parameters=params)
  2099. m, n = symbols("m, n", integer=True)
  2100. c, p = (m*x + n*y).as_content_primitive()
  2101. if a % c.q:
  2102. return DiophantineSolutionSet([x, y], parameters=params)
  2103. # clear_coefficients(mx + b, R)[1] -> (R - b)/m
  2104. eq = clear_coefficients(x, m)[1] - clear_coefficients(y, n)[1]
  2105. junk, eq = eq.as_content_primitive()
  2106. return _diop_solve(eq, params=params)
  2107. def diop_ternary_quadratic(eq, parameterize=False):
  2108. """
  2109. Solves the general quadratic ternary form,
  2110. `ax^2 + by^2 + cz^2 + fxy + gyz + hxz = 0`.
  2111. Returns a tuple `(x, y, z)` which is a base solution for the above
  2112. equation. If there are no solutions, `(None, None, None)` is returned.
  2113. Usage
  2114. =====
  2115. ``diop_ternary_quadratic(eq)``: Return a tuple containing a basic solution
  2116. to ``eq``.
  2117. Details
  2118. =======
  2119. ``eq`` should be an homogeneous expression of degree two in three variables
  2120. and it is assumed to be zero.
  2121. Examples
  2122. ========
  2123. >>> from sympy.abc import x, y, z
  2124. >>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic
  2125. >>> diop_ternary_quadratic(x**2 + 3*y**2 - z**2)
  2126. (1, 0, 1)
  2127. >>> diop_ternary_quadratic(4*x**2 + 5*y**2 - z**2)
  2128. (1, 0, 2)
  2129. >>> diop_ternary_quadratic(45*x**2 - 7*y**2 - 8*x*y - z**2)
  2130. (28, 45, 105)
  2131. >>> diop_ternary_quadratic(x**2 - 49*y**2 - z**2 + 13*z*y -8*x*y)
  2132. (9, 1, 5)
  2133. """
  2134. var, coeff, diop_type = classify_diop(eq, _dict=False)
  2135. if diop_type in (
  2136. HomogeneousTernaryQuadratic.name,
  2137. HomogeneousTernaryQuadraticNormal.name):
  2138. sol = _diop_ternary_quadratic(var, coeff)
  2139. if len(sol) > 0:
  2140. x_0, y_0, z_0 = list(sol)[0]
  2141. else:
  2142. x_0, y_0, z_0 = None, None, None
  2143. if parameterize:
  2144. return _parametrize_ternary_quadratic(
  2145. (x_0, y_0, z_0), var, coeff)
  2146. return x_0, y_0, z_0
  2147. def _diop_ternary_quadratic(_var, coeff):
  2148. eq = sum([i*coeff[i] for i in coeff])
  2149. if HomogeneousTernaryQuadratic(eq).matches():
  2150. return HomogeneousTernaryQuadratic(eq, free_symbols=_var).solve()
  2151. elif HomogeneousTernaryQuadraticNormal(eq).matches():
  2152. return HomogeneousTernaryQuadraticNormal(eq, free_symbols=_var).solve()
  2153. def transformation_to_normal(eq):
  2154. """
  2155. Returns the transformation Matrix that converts a general ternary
  2156. quadratic equation ``eq`` (`ax^2 + by^2 + cz^2 + dxy + eyz + fxz`)
  2157. to a form without cross terms: `ax^2 + by^2 + cz^2 = 0`. This is
  2158. not used in solving ternary quadratics; it is only implemented for
  2159. the sake of completeness.
  2160. """
  2161. var, coeff, diop_type = classify_diop(eq, _dict=False)
  2162. if diop_type in (
  2163. "homogeneous_ternary_quadratic",
  2164. "homogeneous_ternary_quadratic_normal"):
  2165. return _transformation_to_normal(var, coeff)
  2166. def _transformation_to_normal(var, coeff):
  2167. _var = list(var) # copy
  2168. x, y, z = var
  2169. if not any(coeff[i**2] for i in var):
  2170. # https://math.stackexchange.com/questions/448051/transform-quadratic-ternary-form-to-normal-form/448065#448065
  2171. a = coeff[x*y]
  2172. b = coeff[y*z]
  2173. c = coeff[x*z]
  2174. swap = False
  2175. if not a: # b can't be 0 or else there aren't 3 vars
  2176. swap = True
  2177. a, b = b, a
  2178. T = Matrix(((1, 1, -b/a), (1, -1, -c/a), (0, 0, 1)))
  2179. if swap:
  2180. T.row_swap(0, 1)
  2181. T.col_swap(0, 1)
  2182. return T
  2183. if coeff[x**2] == 0:
  2184. # If the coefficient of x is zero change the variables
  2185. if coeff[y**2] == 0:
  2186. _var[0], _var[2] = var[2], var[0]
  2187. T = _transformation_to_normal(_var, coeff)
  2188. T.row_swap(0, 2)
  2189. T.col_swap(0, 2)
  2190. return T
  2191. else:
  2192. _var[0], _var[1] = var[1], var[0]
  2193. T = _transformation_to_normal(_var, coeff)
  2194. T.row_swap(0, 1)
  2195. T.col_swap(0, 1)
  2196. return T
  2197. # Apply the transformation x --> X - (B*Y + C*Z)/(2*A)
  2198. if coeff[x*y] != 0 or coeff[x*z] != 0:
  2199. A = coeff[x**2]
  2200. B = coeff[x*y]
  2201. C = coeff[x*z]
  2202. D = coeff[y**2]
  2203. E = coeff[y*z]
  2204. F = coeff[z**2]
  2205. _coeff = dict()
  2206. _coeff[x**2] = 4*A**2
  2207. _coeff[y**2] = 4*A*D - B**2
  2208. _coeff[z**2] = 4*A*F - C**2
  2209. _coeff[y*z] = 4*A*E - 2*B*C
  2210. _coeff[x*y] = 0
  2211. _coeff[x*z] = 0
  2212. T_0 = _transformation_to_normal(_var, _coeff)
  2213. return Matrix(3, 3, [1, S(-B)/(2*A), S(-C)/(2*A), 0, 1, 0, 0, 0, 1])*T_0
  2214. elif coeff[y*z] != 0:
  2215. if coeff[y**2] == 0:
  2216. if coeff[z**2] == 0:
  2217. # Equations of the form A*x**2 + E*yz = 0.
  2218. # Apply transformation y -> Y + Z ans z -> Y - Z
  2219. return Matrix(3, 3, [1, 0, 0, 0, 1, 1, 0, 1, -1])
  2220. else:
  2221. # Ax**2 + E*y*z + F*z**2 = 0
  2222. _var[0], _var[2] = var[2], var[0]
  2223. T = _transformation_to_normal(_var, coeff)
  2224. T.row_swap(0, 2)
  2225. T.col_swap(0, 2)
  2226. return T
  2227. else:
  2228. # A*x**2 + D*y**2 + E*y*z + F*z**2 = 0, F may be zero
  2229. _var[0], _var[1] = var[1], var[0]
  2230. T = _transformation_to_normal(_var, coeff)
  2231. T.row_swap(0, 1)
  2232. T.col_swap(0, 1)
  2233. return T
  2234. else:
  2235. return Matrix.eye(3)
  2236. def parametrize_ternary_quadratic(eq):
  2237. """
  2238. Returns the parametrized general solution for the ternary quadratic
  2239. equation ``eq`` which has the form
  2240. `ax^2 + by^2 + cz^2 + fxy + gyz + hxz = 0`.
  2241. Examples
  2242. ========
  2243. >>> from sympy import Tuple, ordered
  2244. >>> from sympy.abc import x, y, z
  2245. >>> from sympy.solvers.diophantine.diophantine import parametrize_ternary_quadratic
  2246. The parametrized solution may be returned with three parameters:
  2247. >>> parametrize_ternary_quadratic(2*x**2 + y**2 - 2*z**2)
  2248. (p**2 - 2*q**2, -2*p**2 + 4*p*q - 4*p*r - 4*q**2, p**2 - 4*p*q + 2*q**2 - 4*q*r)
  2249. There might also be only two parameters:
  2250. >>> parametrize_ternary_quadratic(4*x**2 + 2*y**2 - 3*z**2)
  2251. (2*p**2 - 3*q**2, -4*p**2 + 12*p*q - 6*q**2, 4*p**2 - 8*p*q + 6*q**2)
  2252. Notes
  2253. =====
  2254. Consider ``p`` and ``q`` in the previous 2-parameter
  2255. solution and observe that more than one solution can be represented
  2256. by a given pair of parameters. If `p` and ``q`` are not coprime, this is
  2257. trivially true since the common factor will also be a common factor of the
  2258. solution values. But it may also be true even when ``p`` and
  2259. ``q`` are coprime:
  2260. >>> sol = Tuple(*_)
  2261. >>> p, q = ordered(sol.free_symbols)
  2262. >>> sol.subs([(p, 3), (q, 2)])
  2263. (6, 12, 12)
  2264. >>> sol.subs([(q, 1), (p, 1)])
  2265. (-1, 2, 2)
  2266. >>> sol.subs([(q, 0), (p, 1)])
  2267. (2, -4, 4)
  2268. >>> sol.subs([(q, 1), (p, 0)])
  2269. (-3, -6, 6)
  2270. Except for sign and a common factor, these are equivalent to
  2271. the solution of (1, 2, 2).
  2272. References
  2273. ==========
  2274. .. [1] The algorithmic resolution of Diophantine equations, Nigel P. Smart,
  2275. London Mathematical Society Student Texts 41, Cambridge University
  2276. Press, Cambridge, 1998.
  2277. """
  2278. var, coeff, diop_type = classify_diop(eq, _dict=False)
  2279. if diop_type in (
  2280. "homogeneous_ternary_quadratic",
  2281. "homogeneous_ternary_quadratic_normal"):
  2282. x_0, y_0, z_0 = list(_diop_ternary_quadratic(var, coeff))[0]
  2283. return _parametrize_ternary_quadratic(
  2284. (x_0, y_0, z_0), var, coeff)
  2285. def _parametrize_ternary_quadratic(solution, _var, coeff):
  2286. # called for a*x**2 + b*y**2 + c*z**2 + d*x*y + e*y*z + f*x*z = 0
  2287. assert 1 not in coeff
  2288. x_0, y_0, z_0 = solution
  2289. v = list(_var) # copy
  2290. if x_0 is None:
  2291. return (None, None, None)
  2292. if solution.count(0) >= 2:
  2293. # if there are 2 zeros the equation reduces
  2294. # to k*X**2 == 0 where X is x, y, or z so X must
  2295. # be zero, too. So there is only the trivial
  2296. # solution.
  2297. return (None, None, None)
  2298. if x_0 == 0:
  2299. v[0], v[1] = v[1], v[0]
  2300. y_p, x_p, z_p = _parametrize_ternary_quadratic(
  2301. (y_0, x_0, z_0), v, coeff)
  2302. return x_p, y_p, z_p
  2303. x, y, z = v
  2304. r, p, q = symbols("r, p, q", integer=True)
  2305. eq = sum(k*v for k, v in coeff.items())
  2306. eq_1 = _mexpand(eq.subs(zip(
  2307. (x, y, z), (r*x_0, r*y_0 + p, r*z_0 + q))))
  2308. A, B = eq_1.as_independent(r, as_Add=True)
  2309. x = A*x_0
  2310. y = (A*y_0 - _mexpand(B/r*p))
  2311. z = (A*z_0 - _mexpand(B/r*q))
  2312. return _remove_gcd(x, y, z)
  2313. def diop_ternary_quadratic_normal(eq, parameterize=False):
  2314. """
  2315. Solves the quadratic ternary diophantine equation,
  2316. `ax^2 + by^2 + cz^2 = 0`.
  2317. Explanation
  2318. ===========
  2319. Here the coefficients `a`, `b`, and `c` should be non zero. Otherwise the
  2320. equation will be a quadratic binary or univariate equation. If solvable,
  2321. returns a tuple `(x, y, z)` that satisfies the given equation. If the
  2322. equation does not have integer solutions, `(None, None, None)` is returned.
  2323. Usage
  2324. =====
  2325. ``diop_ternary_quadratic_normal(eq)``: where ``eq`` is an equation of the form
  2326. `ax^2 + by^2 + cz^2 = 0`.
  2327. Examples
  2328. ========
  2329. >>> from sympy.abc import x, y, z
  2330. >>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic_normal
  2331. >>> diop_ternary_quadratic_normal(x**2 + 3*y**2 - z**2)
  2332. (1, 0, 1)
  2333. >>> diop_ternary_quadratic_normal(4*x**2 + 5*y**2 - z**2)
  2334. (1, 0, 2)
  2335. >>> diop_ternary_quadratic_normal(34*x**2 - 3*y**2 - 301*z**2)
  2336. (4, 9, 1)
  2337. """
  2338. var, coeff, diop_type = classify_diop(eq, _dict=False)
  2339. if diop_type == HomogeneousTernaryQuadraticNormal.name:
  2340. sol = _diop_ternary_quadratic_normal(var, coeff)
  2341. if len(sol) > 0:
  2342. x_0, y_0, z_0 = list(sol)[0]
  2343. else:
  2344. x_0, y_0, z_0 = None, None, None
  2345. if parameterize:
  2346. return _parametrize_ternary_quadratic(
  2347. (x_0, y_0, z_0), var, coeff)
  2348. return x_0, y_0, z_0
  2349. def _diop_ternary_quadratic_normal(var, coeff):
  2350. eq = sum([i * coeff[i] for i in coeff])
  2351. return HomogeneousTernaryQuadraticNormal(eq, free_symbols=var).solve()
  2352. def sqf_normal(a, b, c, steps=False):
  2353. """
  2354. Return `a', b', c'`, the coefficients of the square-free normal
  2355. form of `ax^2 + by^2 + cz^2 = 0`, where `a', b', c'` are pairwise
  2356. prime. If `steps` is True then also return three tuples:
  2357. `sq`, `sqf`, and `(a', b', c')` where `sq` contains the square
  2358. factors of `a`, `b` and `c` after removing the `gcd(a, b, c)`;
  2359. `sqf` contains the values of `a`, `b` and `c` after removing
  2360. both the `gcd(a, b, c)` and the square factors.
  2361. The solutions for `ax^2 + by^2 + cz^2 = 0` can be
  2362. recovered from the solutions of `a'x^2 + b'y^2 + c'z^2 = 0`.
  2363. Examples
  2364. ========
  2365. >>> from sympy.solvers.diophantine.diophantine import sqf_normal
  2366. >>> sqf_normal(2 * 3**2 * 5, 2 * 5 * 11, 2 * 7**2 * 11)
  2367. (11, 1, 5)
  2368. >>> sqf_normal(2 * 3**2 * 5, 2 * 5 * 11, 2 * 7**2 * 11, True)
  2369. ((3, 1, 7), (5, 55, 11), (11, 1, 5))
  2370. References
  2371. ==========
  2372. .. [1] Legendre's Theorem, Legrange's Descent,
  2373. http://public.csusm.edu/aitken_html/notes/legendre.pdf
  2374. See Also
  2375. ========
  2376. reconstruct()
  2377. """
  2378. ABC = _remove_gcd(a, b, c)
  2379. sq = tuple(square_factor(i) for i in ABC)
  2380. sqf = A, B, C = tuple([i//j**2 for i,j in zip(ABC, sq)])
  2381. pc = igcd(A, B)
  2382. A /= pc
  2383. B /= pc
  2384. pa = igcd(B, C)
  2385. B /= pa
  2386. C /= pa
  2387. pb = igcd(A, C)
  2388. A /= pb
  2389. B /= pb
  2390. A *= pa
  2391. B *= pb
  2392. C *= pc
  2393. if steps:
  2394. return (sq, sqf, (A, B, C))
  2395. else:
  2396. return A, B, C
  2397. def square_factor(a):
  2398. r"""
  2399. Returns an integer `c` s.t. `a = c^2k, \ c,k \in Z`. Here `k` is square
  2400. free. `a` can be given as an integer or a dictionary of factors.
  2401. Examples
  2402. ========
  2403. >>> from sympy.solvers.diophantine.diophantine import square_factor
  2404. >>> square_factor(24)
  2405. 2
  2406. >>> square_factor(-36*3)
  2407. 6
  2408. >>> square_factor(1)
  2409. 1
  2410. >>> square_factor({3: 2, 2: 1, -1: 1}) # -18
  2411. 3
  2412. See Also
  2413. ========
  2414. sympy.ntheory.factor_.core
  2415. """
  2416. f = a if isinstance(a, dict) else factorint(a)
  2417. return Mul(*[p**(e//2) for p, e in f.items()])
  2418. def reconstruct(A, B, z):
  2419. """
  2420. Reconstruct the `z` value of an equivalent solution of `ax^2 + by^2 + cz^2`
  2421. from the `z` value of a solution of the square-free normal form of the
  2422. equation, `a'*x^2 + b'*y^2 + c'*z^2`, where `a'`, `b'` and `c'` are square
  2423. free and `gcd(a', b', c') == 1`.
  2424. """
  2425. f = factorint(igcd(A, B))
  2426. for p, e in f.items():
  2427. if e != 1:
  2428. raise ValueError('a and b should be square-free')
  2429. z *= p
  2430. return z
  2431. def ldescent(A, B):
  2432. """
  2433. Return a non-trivial solution to `w^2 = Ax^2 + By^2` using
  2434. Lagrange's method; return None if there is no such solution.
  2435. .
  2436. Here, `A \\neq 0` and `B \\neq 0` and `A` and `B` are square free. Output a
  2437. tuple `(w_0, x_0, y_0)` which is a solution to the above equation.
  2438. Examples
  2439. ========
  2440. >>> from sympy.solvers.diophantine.diophantine import ldescent
  2441. >>> ldescent(1, 1) # w^2 = x^2 + y^2
  2442. (1, 1, 0)
  2443. >>> ldescent(4, -7) # w^2 = 4x^2 - 7y^2
  2444. (2, -1, 0)
  2445. This means that `x = -1, y = 0` and `w = 2` is a solution to the equation
  2446. `w^2 = 4x^2 - 7y^2`
  2447. >>> ldescent(5, -1) # w^2 = 5x^2 - y^2
  2448. (2, 1, -1)
  2449. References
  2450. ==========
  2451. .. [1] The algorithmic resolution of Diophantine equations, Nigel P. Smart,
  2452. London Mathematical Society Student Texts 41, Cambridge University
  2453. Press, Cambridge, 1998.
  2454. .. [2] Efficient Solution of Rational Conices, J. E. Cremona and D. Rusin,
  2455. [online], Available:
  2456. http://eprints.nottingham.ac.uk/60/1/kvxefz87.pdf
  2457. """
  2458. if abs(A) > abs(B):
  2459. w, y, x = ldescent(B, A)
  2460. return w, x, y
  2461. if A == 1:
  2462. return (1, 1, 0)
  2463. if B == 1:
  2464. return (1, 0, 1)
  2465. if B == -1: # and A == -1
  2466. return
  2467. r = sqrt_mod(A, B)
  2468. Q = (r**2 - A) // B
  2469. if Q == 0:
  2470. B_0 = 1
  2471. d = 0
  2472. else:
  2473. div = divisors(Q)
  2474. B_0 = None
  2475. for i in div:
  2476. sQ, _exact = integer_nthroot(abs(Q) // i, 2)
  2477. if _exact:
  2478. B_0, d = sign(Q)*i, sQ
  2479. break
  2480. if B_0 is not None:
  2481. W, X, Y = ldescent(A, B_0)
  2482. return _remove_gcd((-A*X + r*W), (r*X - W), Y*(B_0*d))
  2483. def descent(A, B):
  2484. """
  2485. Returns a non-trivial solution, (x, y, z), to `x^2 = Ay^2 + Bz^2`
  2486. using Lagrange's descent method with lattice-reduction. `A` and `B`
  2487. are assumed to be valid for such a solution to exist.
  2488. This is faster than the normal Lagrange's descent algorithm because
  2489. the Gaussian reduction is used.
  2490. Examples
  2491. ========
  2492. >>> from sympy.solvers.diophantine.diophantine import descent
  2493. >>> descent(3, 1) # x**2 = 3*y**2 + z**2
  2494. (1, 0, 1)
  2495. `(x, y, z) = (1, 0, 1)` is a solution to the above equation.
  2496. >>> descent(41, -113)
  2497. (-16, -3, 1)
  2498. References
  2499. ==========
  2500. .. [1] Efficient Solution of Rational Conices, J. E. Cremona and D. Rusin,
  2501. Mathematics of Computation, Volume 00, Number 0.
  2502. """
  2503. if abs(A) > abs(B):
  2504. x, y, z = descent(B, A)
  2505. return x, z, y
  2506. if B == 1:
  2507. return (1, 0, 1)
  2508. if A == 1:
  2509. return (1, 1, 0)
  2510. if B == -A:
  2511. return (0, 1, 1)
  2512. if B == A:
  2513. x, z, y = descent(-1, A)
  2514. return (A*y, z, x)
  2515. w = sqrt_mod(A, B)
  2516. x_0, z_0 = gaussian_reduce(w, A, B)
  2517. t = (x_0**2 - A*z_0**2) // B
  2518. t_2 = square_factor(t)
  2519. t_1 = t // t_2**2
  2520. x_1, z_1, y_1 = descent(A, t_1)
  2521. return _remove_gcd(x_0*x_1 + A*z_0*z_1, z_0*x_1 + x_0*z_1, t_1*t_2*y_1)
  2522. def gaussian_reduce(w, a, b):
  2523. r"""
  2524. Returns a reduced solution `(x, z)` to the congruence
  2525. `X^2 - aZ^2 \equiv 0 \ (mod \ b)` so that `x^2 + |a|z^2` is minimal.
  2526. Details
  2527. =======
  2528. Here ``w`` is a solution of the congruence `x^2 \equiv a \ (mod \ b)`
  2529. References
  2530. ==========
  2531. .. [1] Gaussian lattice Reduction [online]. Available:
  2532. http://home.ie.cuhk.edu.hk/~wkshum/wordpress/?p=404
  2533. .. [2] Efficient Solution of Rational Conices, J. E. Cremona and D. Rusin,
  2534. Mathematics of Computation, Volume 00, Number 0.
  2535. """
  2536. u = (0, 1)
  2537. v = (1, 0)
  2538. if dot(u, v, w, a, b) < 0:
  2539. v = (-v[0], -v[1])
  2540. if norm(u, w, a, b) < norm(v, w, a, b):
  2541. u, v = v, u
  2542. while norm(u, w, a, b) > norm(v, w, a, b):
  2543. k = dot(u, v, w, a, b) // dot(v, v, w, a, b)
  2544. u, v = v, (u[0]- k*v[0], u[1]- k*v[1])
  2545. u, v = v, u
  2546. if dot(u, v, w, a, b) < dot(v, v, w, a, b)/2 or norm((u[0]-v[0], u[1]-v[1]), w, a, b) > norm(v, w, a, b):
  2547. c = v
  2548. else:
  2549. c = (u[0] - v[0], u[1] - v[1])
  2550. return c[0]*w + b*c[1], c[0]
  2551. def dot(u, v, w, a, b):
  2552. r"""
  2553. Returns a special dot product of the vectors `u = (u_{1}, u_{2})` and
  2554. `v = (v_{1}, v_{2})` which is defined in order to reduce solution of
  2555. the congruence equation `X^2 - aZ^2 \equiv 0 \ (mod \ b)`.
  2556. """
  2557. u_1, u_2 = u
  2558. v_1, v_2 = v
  2559. return (w*u_1 + b*u_2)*(w*v_1 + b*v_2) + abs(a)*u_1*v_1
  2560. def norm(u, w, a, b):
  2561. r"""
  2562. Returns the norm of the vector `u = (u_{1}, u_{2})` under the dot product
  2563. defined by `u \cdot v = (wu_{1} + bu_{2})(w*v_{1} + bv_{2}) + |a|*u_{1}*v_{1}`
  2564. where `u = (u_{1}, u_{2})` and `v = (v_{1}, v_{2})`.
  2565. """
  2566. u_1, u_2 = u
  2567. return sqrt(dot((u_1, u_2), (u_1, u_2), w, a, b))
  2568. def holzer(x, y, z, a, b, c):
  2569. r"""
  2570. Simplify the solution `(x, y, z)` of the equation
  2571. `ax^2 + by^2 = cz^2` with `a, b, c > 0` and `z^2 \geq \mid ab \mid` to
  2572. a new reduced solution `(x', y', z')` such that `z'^2 \leq \mid ab \mid`.
  2573. The algorithm is an interpretation of Mordell's reduction as described
  2574. on page 8 of Cremona and Rusin's paper [1]_ and the work of Mordell in
  2575. reference [2]_.
  2576. References
  2577. ==========
  2578. .. [1] Efficient Solution of Rational Conices, J. E. Cremona and D. Rusin,
  2579. Mathematics of Computation, Volume 00, Number 0.
  2580. .. [2] Diophantine Equations, L. J. Mordell, page 48.
  2581. """
  2582. if _odd(c):
  2583. k = 2*c
  2584. else:
  2585. k = c//2
  2586. small = a*b*c
  2587. step = 0
  2588. while True:
  2589. t1, t2, t3 = a*x**2, b*y**2, c*z**2
  2590. # check that it's a solution
  2591. if t1 + t2 != t3:
  2592. if step == 0:
  2593. raise ValueError('bad starting solution')
  2594. break
  2595. x_0, y_0, z_0 = x, y, z
  2596. if max(t1, t2, t3) <= small:
  2597. # Holzer condition
  2598. break
  2599. uv = u, v = base_solution_linear(k, y_0, -x_0)
  2600. if None in uv:
  2601. break
  2602. p, q = -(a*u*x_0 + b*v*y_0), c*z_0
  2603. r = Rational(p, q)
  2604. if _even(c):
  2605. w = _nint_or_floor(p, q)
  2606. assert abs(w - r) <= S.Half
  2607. else:
  2608. w = p//q # floor
  2609. if _odd(a*u + b*v + c*w):
  2610. w += 1
  2611. assert abs(w - r) <= S.One
  2612. A = (a*u**2 + b*v**2 + c*w**2)
  2613. B = (a*u*x_0 + b*v*y_0 + c*w*z_0)
  2614. x = Rational(x_0*A - 2*u*B, k)
  2615. y = Rational(y_0*A - 2*v*B, k)
  2616. z = Rational(z_0*A - 2*w*B, k)
  2617. assert all(i.is_Integer for i in (x, y, z))
  2618. step += 1
  2619. return tuple([int(i) for i in (x_0, y_0, z_0)])
  2620. def diop_general_pythagorean(eq, param=symbols("m", integer=True)):
  2621. """
  2622. Solves the general pythagorean equation,
  2623. `a_{1}^2x_{1}^2 + a_{2}^2x_{2}^2 + . . . + a_{n}^2x_{n}^2 - a_{n + 1}^2x_{n + 1}^2 = 0`.
  2624. Returns a tuple which contains a parametrized solution to the equation,
  2625. sorted in the same order as the input variables.
  2626. Usage
  2627. =====
  2628. ``diop_general_pythagorean(eq, param)``: where ``eq`` is a general
  2629. pythagorean equation which is assumed to be zero and ``param`` is the base
  2630. parameter used to construct other parameters by subscripting.
  2631. Examples
  2632. ========
  2633. >>> from sympy.solvers.diophantine.diophantine import diop_general_pythagorean
  2634. >>> from sympy.abc import a, b, c, d, e
  2635. >>> diop_general_pythagorean(a**2 + b**2 + c**2 - d**2)
  2636. (m1**2 + m2**2 - m3**2, 2*m1*m3, 2*m2*m3, m1**2 + m2**2 + m3**2)
  2637. >>> diop_general_pythagorean(9*a**2 - 4*b**2 + 16*c**2 + 25*d**2 + e**2)
  2638. (10*m1**2 + 10*m2**2 + 10*m3**2 - 10*m4**2, 15*m1**2 + 15*m2**2 + 15*m3**2 + 15*m4**2, 15*m1*m4, 12*m2*m4, 60*m3*m4)
  2639. """
  2640. var, coeff, diop_type = classify_diop(eq, _dict=False)
  2641. if diop_type == GeneralPythagorean.name:
  2642. if param is None:
  2643. params = None
  2644. else:
  2645. params = symbols('%s1:%i' % (param, len(var)), integer=True)
  2646. return list(GeneralPythagorean(eq).solve(parameters=params))[0]
  2647. def diop_general_sum_of_squares(eq, limit=1):
  2648. r"""
  2649. Solves the equation `x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0`.
  2650. Returns at most ``limit`` number of solutions.
  2651. Usage
  2652. =====
  2653. ``general_sum_of_squares(eq, limit)`` : Here ``eq`` is an expression which
  2654. is assumed to be zero. Also, ``eq`` should be in the form,
  2655. `x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0`.
  2656. Details
  2657. =======
  2658. When `n = 3` if `k = 4^a(8m + 7)` for some `a, m \in Z` then there will be
  2659. no solutions. Refer to [1]_ for more details.
  2660. Examples
  2661. ========
  2662. >>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_squares
  2663. >>> from sympy.abc import a, b, c, d, e
  2664. >>> diop_general_sum_of_squares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345)
  2665. {(15, 22, 22, 24, 24)}
  2666. Reference
  2667. =========
  2668. .. [1] Representing an integer as a sum of three squares, [online],
  2669. Available:
  2670. http://www.proofwiki.org/wiki/Integer_as_Sum_of_Three_Squares
  2671. """
  2672. var, coeff, diop_type = classify_diop(eq, _dict=False)
  2673. if diop_type == GeneralSumOfSquares.name:
  2674. return set(GeneralSumOfSquares(eq).solve(limit=limit))
  2675. def diop_general_sum_of_even_powers(eq, limit=1):
  2676. """
  2677. Solves the equation `x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0`
  2678. where `e` is an even, integer power.
  2679. Returns at most ``limit`` number of solutions.
  2680. Usage
  2681. =====
  2682. ``general_sum_of_even_powers(eq, limit)`` : Here ``eq`` is an expression which
  2683. is assumed to be zero. Also, ``eq`` should be in the form,
  2684. `x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0`.
  2685. Examples
  2686. ========
  2687. >>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_even_powers
  2688. >>> from sympy.abc import a, b
  2689. >>> diop_general_sum_of_even_powers(a**4 + b**4 - (2**4 + 3**4))
  2690. {(2, 3)}
  2691. See Also
  2692. ========
  2693. power_representation
  2694. """
  2695. var, coeff, diop_type = classify_diop(eq, _dict=False)
  2696. if diop_type == GeneralSumOfEvenPowers.name:
  2697. return set(GeneralSumOfEvenPowers(eq).solve(limit=limit))
  2698. ## Functions below this comment can be more suitably grouped under
  2699. ## an Additive number theory module rather than the Diophantine
  2700. ## equation module.
  2701. def partition(n, k=None, zeros=False):
  2702. """
  2703. Returns a generator that can be used to generate partitions of an integer
  2704. `n`.
  2705. Explanation
  2706. ===========
  2707. A partition of `n` is a set of positive integers which add up to `n`. For
  2708. example, partitions of 3 are 3, 1 + 2, 1 + 1 + 1. A partition is returned
  2709. as a tuple. If ``k`` equals None, then all possible partitions are returned
  2710. irrespective of their size, otherwise only the partitions of size ``k`` are
  2711. returned. If the ``zero`` parameter is set to True then a suitable
  2712. number of zeros are added at the end of every partition of size less than
  2713. ``k``.
  2714. ``zero`` parameter is considered only if ``k`` is not None. When the
  2715. partitions are over, the last `next()` call throws the ``StopIteration``
  2716. exception, so this function should always be used inside a try - except
  2717. block.
  2718. Details
  2719. =======
  2720. ``partition(n, k)``: Here ``n`` is a positive integer and ``k`` is the size
  2721. of the partition which is also positive integer.
  2722. Examples
  2723. ========
  2724. >>> from sympy.solvers.diophantine.diophantine import partition
  2725. >>> f = partition(5)
  2726. >>> next(f)
  2727. (1, 1, 1, 1, 1)
  2728. >>> next(f)
  2729. (1, 1, 1, 2)
  2730. >>> g = partition(5, 3)
  2731. >>> next(g)
  2732. (1, 1, 3)
  2733. >>> next(g)
  2734. (1, 2, 2)
  2735. >>> g = partition(5, 3, zeros=True)
  2736. >>> next(g)
  2737. (0, 0, 5)
  2738. """
  2739. if not zeros or k is None:
  2740. for i in ordered_partitions(n, k):
  2741. yield tuple(i)
  2742. else:
  2743. for m in range(1, k + 1):
  2744. for i in ordered_partitions(n, m):
  2745. i = tuple(i)
  2746. yield (0,)*(k - len(i)) + i
  2747. def prime_as_sum_of_two_squares(p):
  2748. """
  2749. Represent a prime `p` as a unique sum of two squares; this can
  2750. only be done if the prime is congruent to 1 mod 4.
  2751. Examples
  2752. ========
  2753. >>> from sympy.solvers.diophantine.diophantine import prime_as_sum_of_two_squares
  2754. >>> prime_as_sum_of_two_squares(7) # can't be done
  2755. >>> prime_as_sum_of_two_squares(5)
  2756. (1, 2)
  2757. Reference
  2758. =========
  2759. .. [1] Representing a number as a sum of four squares, [online],
  2760. Available: http://schorn.ch/lagrange.html
  2761. See Also
  2762. ========
  2763. sum_of_squares()
  2764. """
  2765. if not p % 4 == 1:
  2766. return
  2767. if p % 8 == 5:
  2768. b = 2
  2769. else:
  2770. b = 3
  2771. while pow(b, (p - 1) // 2, p) == 1:
  2772. b = nextprime(b)
  2773. b = pow(b, (p - 1) // 4, p)
  2774. a = p
  2775. while b**2 > p:
  2776. a, b = b, a % b
  2777. return (int(a % b), int(b)) # convert from long
  2778. def sum_of_three_squares(n):
  2779. r"""
  2780. Returns a 3-tuple $(a, b, c)$ such that $a^2 + b^2 + c^2 = n$ and
  2781. $a, b, c \geq 0$.
  2782. Returns None if $n = 4^a(8m + 7)$ for some `a, m \in \mathbb{Z}`. See
  2783. [1]_ for more details.
  2784. Usage
  2785. =====
  2786. ``sum_of_three_squares(n)``: Here ``n`` is a non-negative integer.
  2787. Examples
  2788. ========
  2789. >>> from sympy.solvers.diophantine.diophantine import sum_of_three_squares
  2790. >>> sum_of_three_squares(44542)
  2791. (18, 37, 207)
  2792. References
  2793. ==========
  2794. .. [1] Representing a number as a sum of three squares, [online],
  2795. Available: http://schorn.ch/lagrange.html
  2796. See Also
  2797. ========
  2798. sum_of_squares()
  2799. """
  2800. special = {1:(1, 0, 0), 2:(1, 1, 0), 3:(1, 1, 1), 10: (1, 3, 0), 34: (3, 3, 4), 58:(3, 7, 0),
  2801. 85:(6, 7, 0), 130:(3, 11, 0), 214:(3, 6, 13), 226:(8, 9, 9), 370:(8, 9, 15),
  2802. 526:(6, 7, 21), 706:(15, 15, 16), 730:(1, 27, 0), 1414:(6, 17, 33), 1906:(13, 21, 36),
  2803. 2986: (21, 32, 39), 9634: (56, 57, 57)}
  2804. v = 0
  2805. if n == 0:
  2806. return (0, 0, 0)
  2807. v = multiplicity(4, n)
  2808. n //= 4**v
  2809. if n % 8 == 7:
  2810. return
  2811. if n in special.keys():
  2812. x, y, z = special[n]
  2813. return _sorted_tuple(2**v*x, 2**v*y, 2**v*z)
  2814. s, _exact = integer_nthroot(n, 2)
  2815. if _exact:
  2816. return (2**v*s, 0, 0)
  2817. x = None
  2818. if n % 8 == 3:
  2819. s = s if _odd(s) else s - 1
  2820. for x in range(s, -1, -2):
  2821. N = (n - x**2) // 2
  2822. if isprime(N):
  2823. y, z = prime_as_sum_of_two_squares(N)
  2824. return _sorted_tuple(2**v*x, 2**v*(y + z), 2**v*abs(y - z))
  2825. return
  2826. if n % 8 in (2, 6):
  2827. s = s if _odd(s) else s - 1
  2828. else:
  2829. s = s - 1 if _odd(s) else s
  2830. for x in range(s, -1, -2):
  2831. N = n - x**2
  2832. if isprime(N):
  2833. y, z = prime_as_sum_of_two_squares(N)
  2834. return _sorted_tuple(2**v*x, 2**v*y, 2**v*z)
  2835. def sum_of_four_squares(n):
  2836. r"""
  2837. Returns a 4-tuple `(a, b, c, d)` such that `a^2 + b^2 + c^2 + d^2 = n`.
  2838. Here `a, b, c, d \geq 0`.
  2839. Usage
  2840. =====
  2841. ``sum_of_four_squares(n)``: Here ``n`` is a non-negative integer.
  2842. Examples
  2843. ========
  2844. >>> from sympy.solvers.diophantine.diophantine import sum_of_four_squares
  2845. >>> sum_of_four_squares(3456)
  2846. (8, 8, 32, 48)
  2847. >>> sum_of_four_squares(1294585930293)
  2848. (0, 1234, 2161, 1137796)
  2849. References
  2850. ==========
  2851. .. [1] Representing a number as a sum of four squares, [online],
  2852. Available: http://schorn.ch/lagrange.html
  2853. See Also
  2854. ========
  2855. sum_of_squares()
  2856. """
  2857. if n == 0:
  2858. return (0, 0, 0, 0)
  2859. v = multiplicity(4, n)
  2860. n //= 4**v
  2861. if n % 8 == 7:
  2862. d = 2
  2863. n = n - 4
  2864. elif n % 8 in (2, 6):
  2865. d = 1
  2866. n = n - 1
  2867. else:
  2868. d = 0
  2869. x, y, z = sum_of_three_squares(n)
  2870. return _sorted_tuple(2**v*d, 2**v*x, 2**v*y, 2**v*z)
  2871. def power_representation(n, p, k, zeros=False):
  2872. r"""
  2873. Returns a generator for finding k-tuples of integers,
  2874. `(n_{1}, n_{2}, . . . n_{k})`, such that
  2875. `n = n_{1}^p + n_{2}^p + . . . n_{k}^p`.
  2876. Usage
  2877. =====
  2878. ``power_representation(n, p, k, zeros)``: Represent non-negative number
  2879. ``n`` as a sum of ``k`` ``p``\ th powers. If ``zeros`` is true, then the
  2880. solutions is allowed to contain zeros.
  2881. Examples
  2882. ========
  2883. >>> from sympy.solvers.diophantine.diophantine import power_representation
  2884. Represent 1729 as a sum of two cubes:
  2885. >>> f = power_representation(1729, 3, 2)
  2886. >>> next(f)
  2887. (9, 10)
  2888. >>> next(f)
  2889. (1, 12)
  2890. If the flag `zeros` is True, the solution may contain tuples with
  2891. zeros; any such solutions will be generated after the solutions
  2892. without zeros:
  2893. >>> list(power_representation(125, 2, 3, zeros=True))
  2894. [(5, 6, 8), (3, 4, 10), (0, 5, 10), (0, 2, 11)]
  2895. For even `p` the `permute_sign` function can be used to get all
  2896. signed values:
  2897. >>> from sympy.utilities.iterables import permute_signs
  2898. >>> list(permute_signs((1, 12)))
  2899. [(1, 12), (-1, 12), (1, -12), (-1, -12)]
  2900. All possible signed permutations can also be obtained:
  2901. >>> from sympy.utilities.iterables import signed_permutations
  2902. >>> list(signed_permutations((1, 12)))
  2903. [(1, 12), (-1, 12), (1, -12), (-1, -12), (12, 1), (-12, 1), (12, -1), (-12, -1)]
  2904. """
  2905. n, p, k = [as_int(i) for i in (n, p, k)]
  2906. if n < 0:
  2907. if p % 2:
  2908. for t in power_representation(-n, p, k, zeros):
  2909. yield tuple(-i for i in t)
  2910. return
  2911. if p < 1 or k < 1:
  2912. raise ValueError(filldedent('''
  2913. Expecting positive integers for `(p, k)`, but got `(%s, %s)`'''
  2914. % (p, k)))
  2915. if n == 0:
  2916. if zeros:
  2917. yield (0,)*k
  2918. return
  2919. if k == 1:
  2920. if p == 1:
  2921. yield (n,)
  2922. else:
  2923. be = perfect_power(n)
  2924. if be:
  2925. b, e = be
  2926. d, r = divmod(e, p)
  2927. if not r:
  2928. yield (b**d,)
  2929. return
  2930. if p == 1:
  2931. for t in partition(n, k, zeros=zeros):
  2932. yield t
  2933. return
  2934. if p == 2:
  2935. feasible = _can_do_sum_of_squares(n, k)
  2936. if not feasible:
  2937. return
  2938. if not zeros and n > 33 and k >= 5 and k <= n and n - k in (
  2939. 13, 10, 7, 5, 4, 2, 1):
  2940. '''Todd G. Will, "When Is n^2 a Sum of k Squares?", [online].
  2941. Available: https://www.maa.org/sites/default/files/Will-MMz-201037918.pdf'''
  2942. return
  2943. if feasible is not True: # it's prime and k == 2
  2944. yield prime_as_sum_of_two_squares(n)
  2945. return
  2946. if k == 2 and p > 2:
  2947. be = perfect_power(n)
  2948. if be and be[1] % p == 0:
  2949. return # Fermat: a**n + b**n = c**n has no solution for n > 2
  2950. if n >= k:
  2951. a = integer_nthroot(n - (k - 1), p)[0]
  2952. for t in pow_rep_recursive(a, k, n, [], p):
  2953. yield tuple(reversed(t))
  2954. if zeros:
  2955. a = integer_nthroot(n, p)[0]
  2956. for i in range(1, k):
  2957. for t in pow_rep_recursive(a, i, n, [], p):
  2958. yield tuple(reversed(t + (0,)*(k - i)))
  2959. sum_of_powers = power_representation
  2960. def pow_rep_recursive(n_i, k, n_remaining, terms, p):
  2961. if k == 0 and n_remaining == 0:
  2962. yield tuple(terms)
  2963. else:
  2964. if n_i >= 1 and k > 0:
  2965. yield from pow_rep_recursive(n_i - 1, k, n_remaining, terms, p)
  2966. residual = n_remaining - pow(n_i, p)
  2967. if residual >= 0:
  2968. yield from pow_rep_recursive(n_i, k - 1, residual, terms + [n_i], p)
  2969. def sum_of_squares(n, k, zeros=False):
  2970. """Return a generator that yields the k-tuples of nonnegative
  2971. values, the squares of which sum to n. If zeros is False (default)
  2972. then the solution will not contain zeros. The nonnegative
  2973. elements of a tuple are sorted.
  2974. * If k == 1 and n is square, (n,) is returned.
  2975. * If k == 2 then n can only be written as a sum of squares if
  2976. every prime in the factorization of n that has the form
  2977. 4*k + 3 has an even multiplicity. If n is prime then
  2978. it can only be written as a sum of two squares if it is
  2979. in the form 4*k + 1.
  2980. * if k == 3 then n can be written as a sum of squares if it does
  2981. not have the form 4**m*(8*k + 7).
  2982. * all integers can be written as the sum of 4 squares.
  2983. * if k > 4 then n can be partitioned and each partition can
  2984. be written as a sum of 4 squares; if n is not evenly divisible
  2985. by 4 then n can be written as a sum of squares only if the
  2986. an additional partition can be written as sum of squares.
  2987. For example, if k = 6 then n is partitioned into two parts,
  2988. the first being written as a sum of 4 squares and the second
  2989. being written as a sum of 2 squares -- which can only be
  2990. done if the condition above for k = 2 can be met, so this will
  2991. automatically reject certain partitions of n.
  2992. Examples
  2993. ========
  2994. >>> from sympy.solvers.diophantine.diophantine import sum_of_squares
  2995. >>> list(sum_of_squares(25, 2))
  2996. [(3, 4)]
  2997. >>> list(sum_of_squares(25, 2, True))
  2998. [(3, 4), (0, 5)]
  2999. >>> list(sum_of_squares(25, 4))
  3000. [(1, 2, 2, 4)]
  3001. See Also
  3002. ========
  3003. sympy.utilities.iterables.signed_permutations
  3004. """
  3005. yield from power_representation(n, 2, k, zeros)
  3006. def _can_do_sum_of_squares(n, k):
  3007. """Return True if n can be written as the sum of k squares,
  3008. False if it cannot, or 1 if ``k == 2`` and ``n`` is prime (in which
  3009. case it *can* be written as a sum of two squares). A False
  3010. is returned only if it cannot be written as ``k``-squares, even
  3011. if 0s are allowed.
  3012. """
  3013. if k < 1:
  3014. return False
  3015. if n < 0:
  3016. return False
  3017. if n == 0:
  3018. return True
  3019. if k == 1:
  3020. return is_square(n)
  3021. if k == 2:
  3022. if n in (1, 2):
  3023. return True
  3024. if isprime(n):
  3025. if n % 4 == 1:
  3026. return 1 # signal that it was prime
  3027. return False
  3028. else:
  3029. f = factorint(n)
  3030. for p, m in f.items():
  3031. # we can proceed iff no prime factor in the form 4*k + 3
  3032. # has an odd multiplicity
  3033. if (p % 4 == 3) and m % 2:
  3034. return False
  3035. return True
  3036. if k == 3:
  3037. if (n//4**multiplicity(4, n)) % 8 == 7:
  3038. return False
  3039. # every number can be written as a sum of 4 squares; for k > 4 partitions
  3040. # can be 0
  3041. return True