test_diophantine.py 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. from sympy.core.add import Add
  2. from sympy.core.mul import Mul
  3. from sympy.core.numbers import (Rational, oo, pi)
  4. from sympy.core.relational import Eq
  5. from sympy.core.singleton import S
  6. from sympy.core.symbol import symbols
  7. from sympy.matrices.dense import Matrix
  8. from sympy.ntheory.factor_ import factorint
  9. from sympy.simplify.powsimp import powsimp
  10. from sympy.core.function import _mexpand
  11. from sympy.core.sorting import default_sort_key, ordered
  12. from sympy.functions.elementary.trigonometric import sin
  13. from sympy.solvers.diophantine import diophantine
  14. from sympy.solvers.diophantine.diophantine import (diop_DN,
  15. diop_solve, diop_ternary_quadratic_normal,
  16. diop_general_pythagorean, diop_ternary_quadratic, diop_linear,
  17. diop_quadratic, diop_general_sum_of_squares, diop_general_sum_of_even_powers,
  18. descent, diop_bf_DN, divisible, equivalent, find_DN, ldescent, length,
  19. reconstruct, partition, power_representation,
  20. prime_as_sum_of_two_squares, square_factor, sum_of_four_squares,
  21. sum_of_three_squares, transformation_to_DN, transformation_to_normal,
  22. classify_diop, base_solution_linear, cornacchia, sqf_normal, gaussian_reduce, holzer,
  23. check_param, parametrize_ternary_quadratic, sum_of_powers, sum_of_squares,
  24. _diop_ternary_quadratic_normal, _nint_or_floor,
  25. _odd, _even, _remove_gcd, _can_do_sum_of_squares, DiophantineSolutionSet, GeneralPythagorean,
  26. BinaryQuadratic)
  27. from sympy.testing.pytest import slow, raises, XFAIL
  28. from sympy.utilities.iterables import (
  29. signed_permutations)
  30. a, b, c, d, p, q, x, y, z, w, t, u, v, X, Y, Z = symbols(
  31. "a, b, c, d, p, q, x, y, z, w, t, u, v, X, Y, Z", integer=True)
  32. t_0, t_1, t_2, t_3, t_4, t_5, t_6 = symbols("t_:7", integer=True)
  33. m1, m2, m3 = symbols('m1:4', integer=True)
  34. n1 = symbols('n1', integer=True)
  35. def diop_simplify(eq):
  36. return _mexpand(powsimp(_mexpand(eq)))
  37. def test_input_format():
  38. raises(TypeError, lambda: diophantine(sin(x)))
  39. raises(TypeError, lambda: diophantine(x/pi - 3))
  40. def test_nosols():
  41. # diophantine should sympify eq so that these are equivalent
  42. assert diophantine(3) == set()
  43. assert diophantine(S(3)) == set()
  44. def test_univariate():
  45. assert diop_solve((x - 1)*(x - 2)**2) == {(1,), (2,)}
  46. assert diop_solve((x - 1)*(x - 2)) == {(1,), (2,)}
  47. def test_classify_diop():
  48. raises(TypeError, lambda: classify_diop(x**2/3 - 1))
  49. raises(ValueError, lambda: classify_diop(1))
  50. raises(NotImplementedError, lambda: classify_diop(w*x*y*z - 1))
  51. raises(NotImplementedError, lambda: classify_diop(x**3 + y**3 + z**4 - 90))
  52. assert classify_diop(14*x**2 + 15*x - 42) == (
  53. [x], {1: -42, x: 15, x**2: 14}, 'univariate')
  54. assert classify_diop(x*y + z) == (
  55. [x, y, z], {x*y: 1, z: 1}, 'inhomogeneous_ternary_quadratic')
  56. assert classify_diop(x*y + z + w + x**2) == (
  57. [w, x, y, z], {x*y: 1, w: 1, x**2: 1, z: 1}, 'inhomogeneous_general_quadratic')
  58. assert classify_diop(x*y + x*z + x**2 + 1) == (
  59. [x, y, z], {x*y: 1, x*z: 1, x**2: 1, 1: 1}, 'inhomogeneous_general_quadratic')
  60. assert classify_diop(x*y + z + w + 42) == (
  61. [w, x, y, z], {x*y: 1, w: 1, 1: 42, z: 1}, 'inhomogeneous_general_quadratic')
  62. assert classify_diop(x*y + z*w) == (
  63. [w, x, y, z], {x*y: 1, w*z: 1}, 'homogeneous_general_quadratic')
  64. assert classify_diop(x*y**2 + 1) == (
  65. [x, y], {x*y**2: 1, 1: 1}, 'cubic_thue')
  66. assert classify_diop(x**4 + y**4 + z**4 - (1 + 16 + 81)) == (
  67. [x, y, z], {1: -98, x**4: 1, z**4: 1, y**4: 1}, 'general_sum_of_even_powers')
  68. assert classify_diop(x**2 + y**2 + z**2) == (
  69. [x, y, z], {x**2: 1, y**2: 1, z**2: 1}, 'homogeneous_ternary_quadratic_normal')
  70. def test_linear():
  71. assert diop_solve(x) == (0,)
  72. assert diop_solve(1*x) == (0,)
  73. assert diop_solve(3*x) == (0,)
  74. assert diop_solve(x + 1) == (-1,)
  75. assert diop_solve(2*x + 1) == (None,)
  76. assert diop_solve(2*x + 4) == (-2,)
  77. assert diop_solve(y + x) == (t_0, -t_0)
  78. assert diop_solve(y + x + 0) == (t_0, -t_0)
  79. assert diop_solve(y + x - 0) == (t_0, -t_0)
  80. assert diop_solve(0*x - y - 5) == (-5,)
  81. assert diop_solve(3*y + 2*x - 5) == (3*t_0 - 5, -2*t_0 + 5)
  82. assert diop_solve(2*x - 3*y - 5) == (3*t_0 - 5, 2*t_0 - 5)
  83. assert diop_solve(-2*x - 3*y - 5) == (3*t_0 + 5, -2*t_0 - 5)
  84. assert diop_solve(7*x + 5*y) == (5*t_0, -7*t_0)
  85. assert diop_solve(2*x + 4*y) == (-2*t_0, t_0)
  86. assert diop_solve(4*x + 6*y - 4) == (3*t_0 - 2, -2*t_0 + 2)
  87. assert diop_solve(4*x + 6*y - 3) == (None, None)
  88. assert diop_solve(0*x + 3*y - 4*z + 5) == (4*t_0 + 5, 3*t_0 + 5)
  89. assert diop_solve(4*x + 3*y - 4*z + 5) == (t_0, 8*t_0 + 4*t_1 + 5, 7*t_0 + 3*t_1 + 5)
  90. assert diop_solve(4*x + 3*y - 4*z + 5, None) == (0, 5, 5)
  91. assert diop_solve(4*x + 2*y + 8*z - 5) == (None, None, None)
  92. assert diop_solve(5*x + 7*y - 2*z - 6) == (t_0, -3*t_0 + 2*t_1 + 6, -8*t_0 + 7*t_1 + 18)
  93. assert diop_solve(3*x - 6*y + 12*z - 9) == (2*t_0 + 3, t_0 + 2*t_1, t_1)
  94. assert diop_solve(6*w + 9*x + 20*y - z) == (t_0, t_1, t_1 + t_2, 6*t_0 + 29*t_1 + 20*t_2)
  95. # to ignore constant factors, use diophantine
  96. raises(TypeError, lambda: diop_solve(x/2))
  97. def test_quadratic_simple_hyperbolic_case():
  98. # Simple Hyperbolic case: A = C = 0 and B != 0
  99. assert diop_solve(3*x*y + 34*x - 12*y + 1) == \
  100. {(-133, -11), (5, -57)}
  101. assert diop_solve(6*x*y + 2*x + 3*y + 1) == set()
  102. assert diop_solve(-13*x*y + 2*x - 4*y - 54) == {(27, 0)}
  103. assert diop_solve(-27*x*y - 30*x - 12*y - 54) == {(-14, -1)}
  104. assert diop_solve(2*x*y + 5*x + 56*y + 7) == {(-161, -3), (-47, -6), (-35, -12),
  105. (-29, -69), (-27, 64), (-21, 7),
  106. (-9, 1), (105, -2)}
  107. assert diop_solve(6*x*y + 9*x + 2*y + 3) == set()
  108. assert diop_solve(x*y + x + y + 1) == {(-1, t), (t, -1)}
  109. assert diophantine(48*x*y)
  110. def test_quadratic_elliptical_case():
  111. # Elliptical case: B**2 - 4AC < 0
  112. assert diop_solve(42*x**2 + 8*x*y + 15*y**2 + 23*x + 17*y - 4915) == {(-11, -1)}
  113. assert diop_solve(4*x**2 + 3*y**2 + 5*x - 11*y + 12) == set()
  114. assert diop_solve(x**2 + y**2 + 2*x + 2*y + 2) == {(-1, -1)}
  115. assert diop_solve(15*x**2 - 9*x*y + 14*y**2 - 23*x - 14*y - 4950) == {(-15, 6)}
  116. assert diop_solve(10*x**2 + 12*x*y + 12*y**2 - 34) == \
  117. {(-1, -1), (-1, 2), (1, -2), (1, 1)}
  118. def test_quadratic_parabolic_case():
  119. # Parabolic case: B**2 - 4AC = 0
  120. assert check_solutions(8*x**2 - 24*x*y + 18*y**2 + 5*x + 7*y + 16)
  121. assert check_solutions(8*x**2 - 24*x*y + 18*y**2 + 6*x + 12*y - 6)
  122. assert check_solutions(8*x**2 + 24*x*y + 18*y**2 + 4*x + 6*y - 7)
  123. assert check_solutions(-4*x**2 + 4*x*y - y**2 + 2*x - 3)
  124. assert check_solutions(x**2 + 2*x*y + y**2 + 2*x + 2*y + 1)
  125. assert check_solutions(x**2 - 2*x*y + y**2 + 2*x + 2*y + 1)
  126. assert check_solutions(y**2 - 41*x + 40)
  127. def test_quadratic_perfect_square():
  128. # B**2 - 4*A*C > 0
  129. # B**2 - 4*A*C is a perfect square
  130. assert check_solutions(48*x*y)
  131. assert check_solutions(4*x**2 - 5*x*y + y**2 + 2)
  132. assert check_solutions(-2*x**2 - 3*x*y + 2*y**2 -2*x - 17*y + 25)
  133. assert check_solutions(12*x**2 + 13*x*y + 3*y**2 - 2*x + 3*y - 12)
  134. assert check_solutions(8*x**2 + 10*x*y + 2*y**2 - 32*x - 13*y - 23)
  135. assert check_solutions(4*x**2 - 4*x*y - 3*y- 8*x - 3)
  136. assert check_solutions(- 4*x*y - 4*y**2 - 3*y- 5*x - 10)
  137. assert check_solutions(x**2 - y**2 - 2*x - 2*y)
  138. assert check_solutions(x**2 - 9*y**2 - 2*x - 6*y)
  139. assert check_solutions(4*x**2 - 9*y**2 - 4*x - 12*y - 3)
  140. def test_quadratic_non_perfect_square():
  141. # B**2 - 4*A*C is not a perfect square
  142. # Used check_solutions() since the solutions are complex expressions involving
  143. # square roots and exponents
  144. assert check_solutions(x**2 - 2*x - 5*y**2)
  145. assert check_solutions(3*x**2 - 2*y**2 - 2*x - 2*y)
  146. assert check_solutions(x**2 - x*y - y**2 - 3*y)
  147. assert check_solutions(x**2 - 9*y**2 - 2*x - 6*y)
  148. assert BinaryQuadratic(x**2 + y**2 + 2*x + 2*y + 2).solve() == {(-1, -1)}
  149. def test_issue_9106():
  150. eq = -48 - 2*x*(3*x - 1) + y*(3*y - 1)
  151. v = (x, y)
  152. for sol in diophantine(eq):
  153. assert not diop_simplify(eq.xreplace(dict(zip(v, sol))))
  154. def test_issue_18138():
  155. eq = x**2 - x - y**2
  156. v = (x, y)
  157. for sol in diophantine(eq):
  158. assert not diop_simplify(eq.xreplace(dict(zip(v, sol))))
  159. @slow
  160. def test_quadratic_non_perfect_slow():
  161. assert check_solutions(8*x**2 + 10*x*y - 2*y**2 - 32*x - 13*y - 23)
  162. # This leads to very large numbers.
  163. # assert check_solutions(5*x**2 - 13*x*y + y**2 - 4*x - 4*y - 15)
  164. assert check_solutions(-3*x**2 - 2*x*y + 7*y**2 - 5*x - 7)
  165. assert check_solutions(-4 - x + 4*x**2 - y - 3*x*y - 4*y**2)
  166. assert check_solutions(1 + 2*x + 2*x**2 + 2*y + x*y - 2*y**2)
  167. def test_DN():
  168. # Most of the test cases were adapted from,
  169. # Solving the generalized Pell equation x**2 - D*y**2 = N, John P. Robertson, July 31, 2004.
  170. # https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf
  171. # others are verified using Wolfram Alpha.
  172. # Covers cases where D <= 0 or D > 0 and D is a square or N = 0
  173. # Solutions are straightforward in these cases.
  174. assert diop_DN(3, 0) == [(0, 0)]
  175. assert diop_DN(-17, -5) == []
  176. assert diop_DN(-19, 23) == [(2, 1)]
  177. assert diop_DN(-13, 17) == [(2, 1)]
  178. assert diop_DN(-15, 13) == []
  179. assert diop_DN(0, 5) == []
  180. assert diop_DN(0, 9) == [(3, t)]
  181. assert diop_DN(9, 0) == [(3*t, t)]
  182. assert diop_DN(16, 24) == []
  183. assert diop_DN(9, 180) == [(18, 4)]
  184. assert diop_DN(9, -180) == [(12, 6)]
  185. assert diop_DN(7, 0) == [(0, 0)]
  186. # When equation is x**2 + y**2 = N
  187. # Solutions are interchangeable
  188. assert diop_DN(-1, 5) == [(2, 1), (1, 2)]
  189. assert diop_DN(-1, 169) == [(12, 5), (5, 12), (13, 0), (0, 13)]
  190. # D > 0 and D is not a square
  191. # N = 1
  192. assert diop_DN(13, 1) == [(649, 180)]
  193. assert diop_DN(980, 1) == [(51841, 1656)]
  194. assert diop_DN(981, 1) == [(158070671986249, 5046808151700)]
  195. assert diop_DN(986, 1) == [(49299, 1570)]
  196. assert diop_DN(991, 1) == [(379516400906811930638014896080, 12055735790331359447442538767)]
  197. assert diop_DN(17, 1) == [(33, 8)]
  198. assert diop_DN(19, 1) == [(170, 39)]
  199. # N = -1
  200. assert diop_DN(13, -1) == [(18, 5)]
  201. assert diop_DN(991, -1) == []
  202. assert diop_DN(41, -1) == [(32, 5)]
  203. assert diop_DN(290, -1) == [(17, 1)]
  204. assert diop_DN(21257, -1) == [(13913102721304, 95427381109)]
  205. assert diop_DN(32, -1) == []
  206. # |N| > 1
  207. # Some tests were created using calculator at
  208. # http://www.numbertheory.org/php/patz.html
  209. assert diop_DN(13, -4) == [(3, 1), (393, 109), (36, 10)]
  210. # Source I referred returned (3, 1), (393, 109) and (-3, 1) as fundamental solutions
  211. # So (-3, 1) and (393, 109) should be in the same equivalent class
  212. assert equivalent(-3, 1, 393, 109, 13, -4) == True
  213. assert diop_DN(13, 27) == [(220, 61), (40, 11), (768, 213), (12, 3)]
  214. assert set(diop_DN(157, 12)) == {(13, 1), (10663, 851), (579160, 46222),
  215. (483790960, 38610722), (26277068347, 2097138361),
  216. (21950079635497, 1751807067011)}
  217. assert diop_DN(13, 25) == [(3245, 900)]
  218. assert diop_DN(192, 18) == []
  219. assert diop_DN(23, 13) == [(-6, 1), (6, 1)]
  220. assert diop_DN(167, 2) == [(13, 1)]
  221. assert diop_DN(167, -2) == []
  222. assert diop_DN(123, -2) == [(11, 1)]
  223. # One calculator returned [(11, 1), (-11, 1)] but both of these are in
  224. # the same equivalence class
  225. assert equivalent(11, 1, -11, 1, 123, -2)
  226. assert diop_DN(123, -23) == [(-10, 1), (10, 1)]
  227. assert diop_DN(0, 0, t) == [(0, t)]
  228. assert diop_DN(0, -1, t) == []
  229. def test_bf_pell():
  230. assert diop_bf_DN(13, -4) == [(3, 1), (-3, 1), (36, 10)]
  231. assert diop_bf_DN(13, 27) == [(12, 3), (-12, 3), (40, 11), (-40, 11)]
  232. assert diop_bf_DN(167, -2) == []
  233. assert diop_bf_DN(1729, 1) == [(44611924489705, 1072885712316)]
  234. assert diop_bf_DN(89, -8) == [(9, 1), (-9, 1)]
  235. assert diop_bf_DN(21257, -1) == [(13913102721304, 95427381109)]
  236. assert diop_bf_DN(340, -4) == [(756, 41)]
  237. assert diop_bf_DN(-1, 0, t) == [(0, 0)]
  238. assert diop_bf_DN(0, 0, t) == [(0, t)]
  239. assert diop_bf_DN(4, 0, t) == [(2*t, t), (-2*t, t)]
  240. assert diop_bf_DN(3, 0, t) == [(0, 0)]
  241. assert diop_bf_DN(1, -2, t) == []
  242. def test_length():
  243. assert length(2, 1, 0) == 1
  244. assert length(-2, 4, 5) == 3
  245. assert length(-5, 4, 17) == 4
  246. assert length(0, 4, 13) == 6
  247. assert length(7, 13, 11) == 23
  248. assert length(1, 6, 4) == 2
  249. def is_pell_transformation_ok(eq):
  250. """
  251. Test whether X*Y, X, or Y terms are present in the equation
  252. after transforming the equation using the transformation returned
  253. by transformation_to_pell(). If they are not present we are good.
  254. Moreover, coefficient of X**2 should be a divisor of coefficient of
  255. Y**2 and the constant term.
  256. """
  257. A, B = transformation_to_DN(eq)
  258. u = (A*Matrix([X, Y]) + B)[0]
  259. v = (A*Matrix([X, Y]) + B)[1]
  260. simplified = diop_simplify(eq.subs(zip((x, y), (u, v))))
  261. coeff = dict([reversed(t.as_independent(*[X, Y])) for t in simplified.args])
  262. for term in [X*Y, X, Y]:
  263. if term in coeff.keys():
  264. return False
  265. for term in [X**2, Y**2, 1]:
  266. if term not in coeff.keys():
  267. coeff[term] = 0
  268. if coeff[X**2] != 0:
  269. return divisible(coeff[Y**2], coeff[X**2]) and \
  270. divisible(coeff[1], coeff[X**2])
  271. return True
  272. def test_transformation_to_pell():
  273. assert is_pell_transformation_ok(-13*x**2 - 7*x*y + y**2 + 2*x - 2*y - 14)
  274. assert is_pell_transformation_ok(-17*x**2 + 19*x*y - 7*y**2 - 5*x - 13*y - 23)
  275. assert is_pell_transformation_ok(x**2 - y**2 + 17)
  276. assert is_pell_transformation_ok(-x**2 + 7*y**2 - 23)
  277. assert is_pell_transformation_ok(25*x**2 - 45*x*y + 5*y**2 - 5*x - 10*y + 5)
  278. assert is_pell_transformation_ok(190*x**2 + 30*x*y + y**2 - 3*y - 170*x - 130)
  279. assert is_pell_transformation_ok(x**2 - 2*x*y -190*y**2 - 7*y - 23*x - 89)
  280. assert is_pell_transformation_ok(15*x**2 - 9*x*y + 14*y**2 - 23*x - 14*y - 4950)
  281. def test_find_DN():
  282. assert find_DN(x**2 - 2*x - y**2) == (1, 1)
  283. assert find_DN(x**2 - 3*y**2 - 5) == (3, 5)
  284. assert find_DN(x**2 - 2*x*y - 4*y**2 - 7) == (5, 7)
  285. assert find_DN(4*x**2 - 8*x*y - y**2 - 9) == (20, 36)
  286. assert find_DN(7*x**2 - 2*x*y - y**2 - 12) == (8, 84)
  287. assert find_DN(-3*x**2 + 4*x*y -y**2) == (1, 0)
  288. assert find_DN(-13*x**2 - 7*x*y + y**2 + 2*x - 2*y -14) == (101, -7825480)
  289. def test_ldescent():
  290. # Equations which have solutions
  291. u = ([(13, 23), (3, -11), (41, -113), (4, -7), (-7, 4), (91, -3), (1, 1), (1, -1),
  292. (4, 32), (17, 13), (123689, 1), (19, -570)])
  293. for a, b in u:
  294. w, x, y = ldescent(a, b)
  295. assert a*x**2 + b*y**2 == w**2
  296. assert ldescent(-1, -1) is None
  297. assert ldescent(2, 6) is None
  298. def test_diop_ternary_quadratic_normal():
  299. assert check_solutions(234*x**2 - 65601*y**2 - z**2)
  300. assert check_solutions(23*x**2 + 616*y**2 - z**2)
  301. assert check_solutions(5*x**2 + 4*y**2 - z**2)
  302. assert check_solutions(3*x**2 + 6*y**2 - 3*z**2)
  303. assert check_solutions(x**2 + 3*y**2 - z**2)
  304. assert check_solutions(4*x**2 + 5*y**2 - z**2)
  305. assert check_solutions(x**2 + y**2 - z**2)
  306. assert check_solutions(16*x**2 + y**2 - 25*z**2)
  307. assert check_solutions(6*x**2 - y**2 + 10*z**2)
  308. assert check_solutions(213*x**2 + 12*y**2 - 9*z**2)
  309. assert check_solutions(34*x**2 - 3*y**2 - 301*z**2)
  310. assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2)
  311. def is_normal_transformation_ok(eq):
  312. A = transformation_to_normal(eq)
  313. X, Y, Z = A*Matrix([x, y, z])
  314. simplified = diop_simplify(eq.subs(zip((x, y, z), (X, Y, Z))))
  315. coeff = dict([reversed(t.as_independent(*[X, Y, Z])) for t in simplified.args])
  316. for term in [X*Y, Y*Z, X*Z]:
  317. if term in coeff.keys():
  318. return False
  319. return True
  320. def test_transformation_to_normal():
  321. assert is_normal_transformation_ok(x**2 + 3*y**2 + z**2 - 13*x*y - 16*y*z + 12*x*z)
  322. assert is_normal_transformation_ok(x**2 + 3*y**2 - 100*z**2)
  323. assert is_normal_transformation_ok(x**2 + 23*y*z)
  324. assert is_normal_transformation_ok(3*y**2 - 100*z**2 - 12*x*y)
  325. assert is_normal_transformation_ok(x**2 + 23*x*y - 34*y*z + 12*x*z)
  326. assert is_normal_transformation_ok(z**2 + 34*x*y - 23*y*z + x*z)
  327. assert is_normal_transformation_ok(x**2 + y**2 + z**2 - x*y - y*z - x*z)
  328. assert is_normal_transformation_ok(x**2 + 2*y*z + 3*z**2)
  329. assert is_normal_transformation_ok(x*y + 2*x*z + 3*y*z)
  330. assert is_normal_transformation_ok(2*x*z + 3*y*z)
  331. def test_diop_ternary_quadratic():
  332. assert check_solutions(2*x**2 + z**2 + y**2 - 4*x*y)
  333. assert check_solutions(x**2 - y**2 - z**2 - x*y - y*z)
  334. assert check_solutions(3*x**2 - x*y - y*z - x*z)
  335. assert check_solutions(x**2 - y*z - x*z)
  336. assert check_solutions(5*x**2 - 3*x*y - x*z)
  337. assert check_solutions(4*x**2 - 5*y**2 - x*z)
  338. assert check_solutions(3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z)
  339. assert check_solutions(8*x**2 - 12*y*z)
  340. assert check_solutions(45*x**2 - 7*y**2 - 8*x*y - z**2)
  341. assert check_solutions(x**2 - 49*y**2 - z**2 + 13*z*y -8*x*y)
  342. assert check_solutions(90*x**2 + 3*y**2 + 5*x*y + 2*z*y + 5*x*z)
  343. assert check_solutions(x**2 + 3*y**2 + z**2 - x*y - 17*y*z)
  344. assert check_solutions(x**2 + 3*y**2 + z**2 - x*y - 16*y*z + 12*x*z)
  345. assert check_solutions(x**2 + 3*y**2 + z**2 - 13*x*y - 16*y*z + 12*x*z)
  346. assert check_solutions(x*y - 7*y*z + 13*x*z)
  347. assert diop_ternary_quadratic_normal(x**2 + y**2 + z**2) == (None, None, None)
  348. assert diop_ternary_quadratic_normal(x**2 + y**2) is None
  349. raises(ValueError, lambda:
  350. _diop_ternary_quadratic_normal((x, y, z),
  351. {x*y: 1, x**2: 2, y**2: 3, z**2: 0}))
  352. eq = -2*x*y - 6*x*z + 7*y**2 - 3*y*z + 4*z**2
  353. assert diop_ternary_quadratic(eq) == (7, 2, 0)
  354. assert diop_ternary_quadratic_normal(4*x**2 + 5*y**2 - z**2) == \
  355. (1, 0, 2)
  356. assert diop_ternary_quadratic(x*y + 2*y*z) == \
  357. (-2, 0, n1)
  358. eq = -5*x*y - 8*x*z - 3*y*z + 8*z**2
  359. assert parametrize_ternary_quadratic(eq) == \
  360. (8*p**2 - 3*p*q, -8*p*q + 8*q**2, 5*p*q)
  361. # this cannot be tested with diophantine because it will
  362. # factor into a product
  363. assert diop_solve(x*y + 2*y*z) == (-2*p*q, -n1*p**2 + p**2, p*q)
  364. def test_square_factor():
  365. assert square_factor(1) == square_factor(-1) == 1
  366. assert square_factor(0) == 1
  367. assert square_factor(5) == square_factor(-5) == 1
  368. assert square_factor(4) == square_factor(-4) == 2
  369. assert square_factor(12) == square_factor(-12) == 2
  370. assert square_factor(6) == 1
  371. assert square_factor(18) == 3
  372. assert square_factor(52) == 2
  373. assert square_factor(49) == 7
  374. assert square_factor(392) == 14
  375. assert square_factor(factorint(-12)) == 2
  376. def test_parametrize_ternary_quadratic():
  377. assert check_solutions(x**2 + y**2 - z**2)
  378. assert check_solutions(x**2 + 2*x*y + z**2)
  379. assert check_solutions(234*x**2 - 65601*y**2 - z**2)
  380. assert check_solutions(3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z)
  381. assert check_solutions(x**2 - y**2 - z**2)
  382. assert check_solutions(x**2 - 49*y**2 - z**2 + 13*z*y - 8*x*y)
  383. assert check_solutions(8*x*y + z**2)
  384. assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2)
  385. assert check_solutions(236*x**2 - 225*y**2 - 11*x*y - 13*y*z - 17*x*z)
  386. assert check_solutions(90*x**2 + 3*y**2 + 5*x*y + 2*z*y + 5*x*z)
  387. assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2)
  388. def test_no_square_ternary_quadratic():
  389. assert check_solutions(2*x*y + y*z - 3*x*z)
  390. assert check_solutions(189*x*y - 345*y*z - 12*x*z)
  391. assert check_solutions(23*x*y + 34*y*z)
  392. assert check_solutions(x*y + y*z + z*x)
  393. assert check_solutions(23*x*y + 23*y*z + 23*x*z)
  394. def test_descent():
  395. u = ([(13, 23), (3, -11), (41, -113), (91, -3), (1, 1), (1, -1), (17, 13), (123689, 1), (19, -570)])
  396. for a, b in u:
  397. w, x, y = descent(a, b)
  398. assert a*x**2 + b*y**2 == w**2
  399. # the docstring warns against bad input, so these are expected results
  400. # - can't both be negative
  401. raises(TypeError, lambda: descent(-1, -3))
  402. # A can't be zero unless B != 1
  403. raises(ZeroDivisionError, lambda: descent(0, 3))
  404. # supposed to be square-free
  405. raises(TypeError, lambda: descent(4, 3))
  406. def test_diophantine():
  407. assert check_solutions((x - y)*(y - z)*(z - x))
  408. assert check_solutions((x - y)*(x**2 + y**2 - z**2))
  409. assert check_solutions((x - 3*y + 7*z)*(x**2 + y**2 - z**2))
  410. assert check_solutions(x**2 - 3*y**2 - 1)
  411. assert check_solutions(y**2 + 7*x*y)
  412. assert check_solutions(x**2 - 3*x*y + y**2)
  413. assert check_solutions(z*(x**2 - y**2 - 15))
  414. assert check_solutions(x*(2*y - 2*z + 5))
  415. assert check_solutions((x**2 - 3*y**2 - 1)*(x**2 - y**2 - 15))
  416. assert check_solutions((x**2 - 3*y**2 - 1)*(y - 7*z))
  417. assert check_solutions((x**2 + y**2 - z**2)*(x - 7*y - 3*z + 4*w))
  418. # Following test case caused problems in parametric representation
  419. # But this can be solved by factoring out y.
  420. # No need to use methods for ternary quadratic equations.
  421. assert check_solutions(y**2 - 7*x*y + 4*y*z)
  422. assert check_solutions(x**2 - 2*x + 1)
  423. assert diophantine(x - y) == diophantine(Eq(x, y))
  424. # 18196
  425. eq = x**4 + y**4 - 97
  426. assert diophantine(eq, permute=True) == diophantine(-eq, permute=True)
  427. assert diophantine(3*x*pi - 2*y*pi) == {(2*t_0, 3*t_0)}
  428. eq = x**2 + y**2 + z**2 - 14
  429. base_sol = {(1, 2, 3)}
  430. assert diophantine(eq) == base_sol
  431. complete_soln = set(signed_permutations(base_sol.pop()))
  432. assert diophantine(eq, permute=True) == complete_soln
  433. assert diophantine(x**2 + x*Rational(15, 14) - 3) == set()
  434. # test issue 11049
  435. eq = 92*x**2 - 99*y**2 - z**2
  436. coeff = eq.as_coefficients_dict()
  437. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  438. {(9, 7, 51)}
  439. assert diophantine(eq) == {(
  440. 891*p**2 + 9*q**2, -693*p**2 - 102*p*q + 7*q**2,
  441. 5049*p**2 - 1386*p*q - 51*q**2)}
  442. eq = 2*x**2 + 2*y**2 - z**2
  443. coeff = eq.as_coefficients_dict()
  444. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  445. {(1, 1, 2)}
  446. assert diophantine(eq) == {(
  447. 2*p**2 - q**2, -2*p**2 + 4*p*q - q**2,
  448. 4*p**2 - 4*p*q + 2*q**2)}
  449. eq = 411*x**2+57*y**2-221*z**2
  450. coeff = eq.as_coefficients_dict()
  451. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  452. {(2021, 2645, 3066)}
  453. assert diophantine(eq) == \
  454. {(115197*p**2 - 446641*q**2, -150765*p**2 + 1355172*p*q -
  455. 584545*q**2, 174762*p**2 - 301530*p*q + 677586*q**2)}
  456. eq = 573*x**2+267*y**2-984*z**2
  457. coeff = eq.as_coefficients_dict()
  458. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  459. {(49, 233, 127)}
  460. assert diophantine(eq) == \
  461. {(4361*p**2 - 16072*q**2, -20737*p**2 + 83312*p*q - 76424*q**2,
  462. 11303*p**2 - 41474*p*q + 41656*q**2)}
  463. # this produces factors during reconstruction
  464. eq = x**2 + 3*y**2 - 12*z**2
  465. coeff = eq.as_coefficients_dict()
  466. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  467. {(0, 2, 1)}
  468. assert diophantine(eq) == \
  469. {(24*p*q, 2*p**2 - 24*q**2, p**2 + 12*q**2)}
  470. # solvers have not been written for every type
  471. raises(NotImplementedError, lambda: diophantine(x*y**2 + 1))
  472. # rational expressions
  473. assert diophantine(1/x) == set()
  474. assert diophantine(1/x + 1/y - S.Half) == {(6, 3), (-2, 1), (4, 4), (1, -2), (3, 6)}
  475. assert diophantine(x**2 + y**2 +3*x- 5, permute=True) == \
  476. {(-1, 1), (-4, -1), (1, -1), (1, 1), (-4, 1), (-1, -1), (4, 1), (4, -1)}
  477. #test issue 18186
  478. assert diophantine(y**4 + x**4 - 2**4 - 3**4, syms=(x, y), permute=True) == \
  479. {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)}
  480. assert diophantine(y**4 + x**4 - 2**4 - 3**4, syms=(y, x), permute=True) == \
  481. {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)}
  482. # issue 18122
  483. assert check_solutions(x**2 - y)
  484. assert check_solutions(y**2 - x)
  485. assert diophantine((x**2 - y), t) == {(t, t**2)}
  486. assert diophantine((y**2 - x), t) == {(t**2, t)}
  487. def test_general_pythagorean():
  488. from sympy.abc import a, b, c, d, e
  489. assert check_solutions(a**2 + b**2 + c**2 - d**2)
  490. assert check_solutions(a**2 + 4*b**2 + 4*c**2 - d**2)
  491. assert check_solutions(9*a**2 + 4*b**2 + 4*c**2 - d**2)
  492. assert check_solutions(9*a**2 + 4*b**2 - 25*d**2 + 4*c**2 )
  493. assert check_solutions(9*a**2 - 16*d**2 + 4*b**2 + 4*c**2)
  494. assert check_solutions(-e**2 + 9*a**2 + 4*b**2 + 4*c**2 + 25*d**2)
  495. assert check_solutions(16*a**2 - b**2 + 9*c**2 + d**2 + 25*e**2)
  496. assert GeneralPythagorean(a**2 + b**2 + c**2 - d**2).solve(parameters=[x, y, z]) == \
  497. {(x**2 + y**2 - z**2, 2*x*z, 2*y*z, x**2 + y**2 + z**2)}
  498. def test_diop_general_sum_of_squares_quick():
  499. for i in range(3, 10):
  500. assert check_solutions(sum(i**2 for i in symbols(':%i' % i)) - i)
  501. assert diop_general_sum_of_squares(x**2 + y**2 - 2) is None
  502. assert diop_general_sum_of_squares(x**2 + y**2 + z**2 + 2) == set()
  503. eq = x**2 + y**2 + z**2 - (1 + 4 + 9)
  504. assert diop_general_sum_of_squares(eq) == \
  505. {(1, 2, 3)}
  506. eq = u**2 + v**2 + x**2 + y**2 + z**2 - 1313
  507. assert len(diop_general_sum_of_squares(eq, 3)) == 3
  508. # issue 11016
  509. var = symbols(':5') + (symbols('6', negative=True),)
  510. eq = Add(*[i**2 for i in var]) - 112
  511. base_soln = {(0, 1, 1, 5, 6, -7), (1, 1, 1, 3, 6, -8), (2, 3, 3, 4, 5, -7), (0, 1, 1, 1, 3, -10),
  512. (0, 0, 4, 4, 4, -8), (1, 2, 3, 3, 5, -8), (0, 1, 2, 3, 7, -7), (2, 2, 4, 4, 6, -6),
  513. (1, 1, 3, 4, 6, -7), (0, 2, 3, 3, 3, -9), (0, 0, 2, 2, 2, -10), (1, 1, 2, 3, 4, -9),
  514. (0, 1, 1, 2, 5, -9), (0, 0, 2, 6, 6, -6), (1, 3, 4, 5, 5, -6), (0, 2, 2, 2, 6, -8),
  515. (0, 3, 3, 3, 6, -7), (0, 2, 3, 5, 5, -7), (0, 1, 5, 5, 5, -6)}
  516. assert diophantine(eq) == base_soln
  517. assert len(diophantine(eq, permute=True)) == 196800
  518. # handle negated squares with signsimp
  519. assert diophantine(12 - x**2 - y**2 - z**2) == {(2, 2, 2)}
  520. # diophantine handles simplification, so classify_diop should
  521. # not have to look for additional patterns that are removed
  522. # by diophantine
  523. eq = a**2 + b**2 + c**2 + d**2 - 4
  524. raises(NotImplementedError, lambda: classify_diop(-eq))
  525. def test_issue_23807():
  526. # fixes recursion error
  527. eq = x**2 + y**2 + z**2 - 1000000
  528. base_soln = {(0, 0, 1000), (0, 352, 936), (480, 600, 640), (24, 640, 768), (192, 640, 744),
  529. (192, 480, 856), (168, 224, 960), (0, 600, 800), (280, 576, 768), (152, 480, 864),
  530. (0, 280, 960), (352, 360, 864), (424, 480, 768), (360, 480, 800), (224, 600, 768),
  531. (96, 360, 928), (168, 576, 800), (96, 480, 872)}
  532. assert diophantine(eq) == base_soln
  533. def test_diop_partition():
  534. for n in [8, 10]:
  535. for k in range(1, 8):
  536. for p in partition(n, k):
  537. assert len(p) == k
  538. assert list(partition(3, 5)) == []
  539. assert [list(p) for p in partition(3, 5, 1)] == [
  540. [0, 0, 0, 0, 3], [0, 0, 0, 1, 2], [0, 0, 1, 1, 1]]
  541. assert list(partition(0)) == [()]
  542. assert list(partition(1, 0)) == [()]
  543. assert [list(i) for i in partition(3)] == [[1, 1, 1], [1, 2], [3]]
  544. def test_prime_as_sum_of_two_squares():
  545. for i in [5, 13, 17, 29, 37, 41, 2341, 3557, 34841, 64601]:
  546. a, b = prime_as_sum_of_two_squares(i)
  547. assert a**2 + b**2 == i
  548. assert prime_as_sum_of_two_squares(7) is None
  549. ans = prime_as_sum_of_two_squares(800029)
  550. assert ans == (450, 773) and type(ans[0]) is int
  551. def test_sum_of_three_squares():
  552. for i in [0, 1, 2, 34, 123, 34304595905, 34304595905394941, 343045959052344,
  553. 800, 801, 802, 803, 804, 805, 806]:
  554. a, b, c = sum_of_three_squares(i)
  555. assert a**2 + b**2 + c**2 == i
  556. assert a >= 0
  557. # error
  558. raises(ValueError, lambda: sum_of_three_squares(-1))
  559. assert sum_of_three_squares(7) is None
  560. assert sum_of_three_squares((4**5)*15) is None
  561. # if there are two zeros, there might be a solution
  562. # with only one zero, e.g. 25 => (0, 3, 4) or
  563. # with no zeros, e.g. 49 => (2, 3, 6)
  564. assert sum_of_three_squares(25) == (0, 0, 5)
  565. assert sum_of_three_squares(4) == (0, 0, 2)
  566. def test_sum_of_four_squares():
  567. from sympy.core.random import randint
  568. # this should never fail
  569. n = randint(1, 100000000000000)
  570. assert sum(i**2 for i in sum_of_four_squares(n)) == n
  571. # error
  572. raises(ValueError, lambda: sum_of_four_squares(-1))
  573. for n in range(1000):
  574. result = sum_of_four_squares(n)
  575. assert len(result) == 4
  576. assert all(r >= 0 for r in result)
  577. assert sum(r**2 for r in result) == n
  578. assert list(result) == sorted(result)
  579. def test_power_representation():
  580. tests = [(1729, 3, 2), (234, 2, 4), (2, 1, 2), (3, 1, 3), (5, 2, 2), (12352, 2, 4),
  581. (32760, 2, 3)]
  582. for test in tests:
  583. n, p, k = test
  584. f = power_representation(n, p, k)
  585. while True:
  586. try:
  587. l = next(f)
  588. assert len(l) == k
  589. chk_sum = 0
  590. for l_i in l:
  591. chk_sum = chk_sum + l_i**p
  592. assert chk_sum == n
  593. except StopIteration:
  594. break
  595. assert list(power_representation(20, 2, 4, True)) == \
  596. [(1, 1, 3, 3), (0, 0, 2, 4)]
  597. raises(ValueError, lambda: list(power_representation(1.2, 2, 2)))
  598. raises(ValueError, lambda: list(power_representation(2, 0, 2)))
  599. raises(ValueError, lambda: list(power_representation(2, 2, 0)))
  600. assert list(power_representation(-1, 2, 2)) == []
  601. assert list(power_representation(1, 1, 1)) == [(1,)]
  602. assert list(power_representation(3, 2, 1)) == []
  603. assert list(power_representation(4, 2, 1)) == [(2,)]
  604. assert list(power_representation(3**4, 4, 6, zeros=True)) == \
  605. [(1, 2, 2, 2, 2, 2), (0, 0, 0, 0, 0, 3)]
  606. assert list(power_representation(3**4, 4, 5, zeros=False)) == []
  607. assert list(power_representation(-2, 3, 2)) == [(-1, -1)]
  608. assert list(power_representation(-2, 4, 2)) == []
  609. assert list(power_representation(0, 3, 2, True)) == [(0, 0)]
  610. assert list(power_representation(0, 3, 2, False)) == []
  611. # when we are dealing with squares, do feasibility checks
  612. assert len(list(power_representation(4**10*(8*10 + 7), 2, 3))) == 0
  613. # there will be a recursion error if these aren't recognized
  614. big = 2**30
  615. for i in [13, 10, 7, 5, 4, 2, 1]:
  616. assert list(sum_of_powers(big, 2, big - i)) == []
  617. def test_assumptions():
  618. """
  619. Test whether diophantine respects the assumptions.
  620. """
  621. #Test case taken from the below so question regarding assumptions in diophantine module
  622. #https://stackoverflow.com/questions/23301941/how-can-i-declare-natural-symbols-with-sympy
  623. m, n = symbols('m n', integer=True, positive=True)
  624. diof = diophantine(n**2 + m*n - 500)
  625. assert diof == {(5, 20), (40, 10), (95, 5), (121, 4), (248, 2), (499, 1)}
  626. a, b = symbols('a b', integer=True, positive=False)
  627. diof = diophantine(a*b + 2*a + 3*b - 6)
  628. assert diof == {(-15, -3), (-9, -4), (-7, -5), (-6, -6), (-5, -8), (-4, -14)}
  629. x, y = symbols('x y', integer=True)
  630. diof = diophantine(10*x**2 + 5*x*y - 3*y)
  631. assert diof == {(1, -5), (-3, 5), (0, 0)}
  632. x, y = symbols('x y', integer=True, positive=True)
  633. diof = diophantine(10*x**2 + 5*x*y - 3*y)
  634. assert diof == set()
  635. x, y = symbols('x y', integer=True, negative=False)
  636. diof = diophantine(10*x**2 + 5*x*y - 3*y)
  637. assert diof == {(0, 0)}
  638. def check_solutions(eq):
  639. """
  640. Determines whether solutions returned by diophantine() satisfy the original
  641. equation. Hope to generalize this so we can remove functions like check_ternay_quadratic,
  642. check_solutions_normal, check_solutions()
  643. """
  644. s = diophantine(eq)
  645. factors = Mul.make_args(eq)
  646. var = list(eq.free_symbols)
  647. var.sort(key=default_sort_key)
  648. while s:
  649. solution = s.pop()
  650. for f in factors:
  651. if diop_simplify(f.subs(zip(var, solution))) == 0:
  652. break
  653. else:
  654. return False
  655. return True
  656. def test_diopcoverage():
  657. eq = (2*x + y + 1)**2
  658. assert diop_solve(eq) == {(t_0, -2*t_0 - 1)}
  659. eq = 2*x**2 + 6*x*y + 12*x + 4*y**2 + 18*y + 18
  660. assert diop_solve(eq) == {(t, -t - 3), (-2*t - 3, t)}
  661. assert diop_quadratic(x + y**2 - 3) == {(-t**2 + 3, t)}
  662. assert diop_linear(x + y - 3) == (t_0, 3 - t_0)
  663. assert base_solution_linear(0, 1, 2, t=None) == (0, 0)
  664. ans = (3*t - 1, -2*t + 1)
  665. assert base_solution_linear(4, 8, 12, t) == ans
  666. assert base_solution_linear(4, 8, 12, t=None) == tuple(_.subs(t, 0) for _ in ans)
  667. assert cornacchia(1, 1, 20) == set()
  668. assert cornacchia(1, 1, 5) == {(2, 1)}
  669. assert cornacchia(1, 2, 17) == {(3, 2)}
  670. raises(ValueError, lambda: reconstruct(4, 20, 1))
  671. assert gaussian_reduce(4, 1, 3) == (1, 1)
  672. eq = -w**2 - x**2 - y**2 + z**2
  673. assert diop_general_pythagorean(eq) == \
  674. diop_general_pythagorean(-eq) == \
  675. (m1**2 + m2**2 - m3**2, 2*m1*m3,
  676. 2*m2*m3, m1**2 + m2**2 + m3**2)
  677. assert len(check_param(S(3) + x/3, S(4) + x/2, S(2), [x])) == 0
  678. assert len(check_param(Rational(3, 2), S(4) + x, S(2), [x])) == 0
  679. assert len(check_param(S(4) + x, Rational(3, 2), S(2), [x])) == 0
  680. assert _nint_or_floor(16, 10) == 2
  681. assert _odd(1) == (not _even(1)) == True
  682. assert _odd(0) == (not _even(0)) == False
  683. assert _remove_gcd(2, 4, 6) == (1, 2, 3)
  684. raises(TypeError, lambda: _remove_gcd((2, 4, 6)))
  685. assert sqf_normal(2*3**2*5, 2*5*11, 2*7**2*11) == \
  686. (11, 1, 5)
  687. # it's ok if these pass some day when the solvers are implemented
  688. raises(NotImplementedError, lambda: diophantine(x**2 + y**2 + x*y + 2*y*z - 12))
  689. raises(NotImplementedError, lambda: diophantine(x**3 + y**2))
  690. assert diop_quadratic(x**2 + y**2 - 1**2 - 3**4) == \
  691. {(-9, -1), (-9, 1), (-1, -9), (-1, 9), (1, -9), (1, 9), (9, -1), (9, 1)}
  692. def test_holzer():
  693. # if the input is good, don't let it diverge in holzer()
  694. # (but see test_fail_holzer below)
  695. assert holzer(2, 7, 13, 4, 79, 23) == (2, 7, 13)
  696. # None in uv condition met; solution is not Holzer reduced
  697. # so this will hopefully change but is here for coverage
  698. assert holzer(2, 6, 2, 1, 1, 10) == (2, 6, 2)
  699. raises(ValueError, lambda: holzer(2, 7, 14, 4, 79, 23))
  700. @XFAIL
  701. def test_fail_holzer():
  702. eq = lambda x, y, z: a*x**2 + b*y**2 - c*z**2
  703. a, b, c = 4, 79, 23
  704. x, y, z = xyz = 26, 1, 11
  705. X, Y, Z = ans = 2, 7, 13
  706. assert eq(*xyz) == 0
  707. assert eq(*ans) == 0
  708. assert max(a*x**2, b*y**2, c*z**2) <= a*b*c
  709. assert max(a*X**2, b*Y**2, c*Z**2) <= a*b*c
  710. h = holzer(x, y, z, a, b, c)
  711. assert h == ans # it would be nice to get the smaller soln
  712. def test_issue_9539():
  713. assert diophantine(6*w + 9*y + 20*x - z) == \
  714. {(t_0, t_1, t_1 + t_2, 6*t_0 + 29*t_1 + 9*t_2)}
  715. def test_issue_8943():
  716. assert diophantine(
  717. 3*(x**2 + y**2 + z**2) - 14*(x*y + y*z + z*x)) == \
  718. {(0, 0, 0)}
  719. def test_diop_sum_of_even_powers():
  720. eq = x**4 + y**4 + z**4 - 2673
  721. assert diop_solve(eq) == {(3, 6, 6), (2, 4, 7)}
  722. assert diop_general_sum_of_even_powers(eq, 2) == {(3, 6, 6), (2, 4, 7)}
  723. raises(NotImplementedError, lambda: diop_general_sum_of_even_powers(-eq, 2))
  724. neg = symbols('neg', negative=True)
  725. eq = x**4 + y**4 + neg**4 - 2673
  726. assert diop_general_sum_of_even_powers(eq) == {(-3, 6, 6)}
  727. assert diophantine(x**4 + y**4 + 2) == set()
  728. assert diop_general_sum_of_even_powers(x**4 + y**4 - 2, limit=0) == set()
  729. def test_sum_of_squares_powers():
  730. tru = {(0, 0, 1, 1, 11), (0, 0, 5, 7, 7), (0, 1, 3, 7, 8), (0, 1, 4, 5, 9), (0, 3, 4, 7, 7), (0, 3, 5, 5, 8),
  731. (1, 1, 2, 6, 9), (1, 1, 6, 6, 7), (1, 2, 3, 3, 10), (1, 3, 4, 4, 9), (1, 5, 5, 6, 6), (2, 2, 3, 5, 9),
  732. (2, 3, 5, 6, 7), (3, 3, 4, 5, 8)}
  733. eq = u**2 + v**2 + x**2 + y**2 + z**2 - 123
  734. ans = diop_general_sum_of_squares(eq, oo) # allow oo to be used
  735. assert len(ans) == 14
  736. assert ans == tru
  737. raises(ValueError, lambda: list(sum_of_squares(10, -1)))
  738. assert list(sum_of_squares(1, 1)) == [(1,)]
  739. assert list(sum_of_squares(1, 2)) == []
  740. assert list(sum_of_squares(1, 2, True)) == [(0, 1)]
  741. assert list(sum_of_squares(-10, 2)) == []
  742. assert list(sum_of_squares(2, 3)) == []
  743. assert list(sum_of_squares(0, 3, True)) == [(0, 0, 0)]
  744. assert list(sum_of_squares(0, 3)) == []
  745. assert list(sum_of_squares(4, 1)) == [(2,)]
  746. assert list(sum_of_squares(5, 1)) == []
  747. assert list(sum_of_squares(50, 2)) == [(5, 5), (1, 7)]
  748. assert list(sum_of_squares(11, 5, True)) == [
  749. (1, 1, 1, 2, 2), (0, 0, 1, 1, 3)]
  750. assert list(sum_of_squares(8, 8)) == [(1, 1, 1, 1, 1, 1, 1, 1)]
  751. assert [len(list(sum_of_squares(i, 5, True))) for i in range(30)] == [
  752. 1, 1, 1, 1, 2,
  753. 2, 1, 1, 2, 2,
  754. 2, 2, 2, 3, 2,
  755. 1, 3, 3, 3, 3,
  756. 4, 3, 3, 2, 2,
  757. 4, 4, 4, 4, 5]
  758. assert [len(list(sum_of_squares(i, 5))) for i in range(30)] == [
  759. 0, 0, 0, 0, 0,
  760. 1, 0, 0, 1, 0,
  761. 0, 1, 0, 1, 1,
  762. 0, 1, 1, 0, 1,
  763. 2, 1, 1, 1, 1,
  764. 1, 1, 1, 1, 3]
  765. for i in range(30):
  766. s1 = set(sum_of_squares(i, 5, True))
  767. assert not s1 or all(sum(j**2 for j in t) == i for t in s1)
  768. s2 = set(sum_of_squares(i, 5))
  769. assert all(sum(j**2 for j in t) == i for t in s2)
  770. raises(ValueError, lambda: list(sum_of_powers(2, -1, 1)))
  771. raises(ValueError, lambda: list(sum_of_powers(2, 1, -1)))
  772. assert list(sum_of_powers(-2, 3, 2)) == [(-1, -1)]
  773. assert list(sum_of_powers(-2, 4, 2)) == []
  774. assert list(sum_of_powers(2, 1, 1)) == [(2,)]
  775. assert list(sum_of_powers(2, 1, 3, True)) == [(0, 0, 2), (0, 1, 1)]
  776. assert list(sum_of_powers(5, 1, 2, True)) == [(0, 5), (1, 4), (2, 3)]
  777. assert list(sum_of_powers(6, 2, 2)) == []
  778. assert list(sum_of_powers(3**5, 3, 1)) == []
  779. assert list(sum_of_powers(3**6, 3, 1)) == [(9,)] and (9**3 == 3**6)
  780. assert list(sum_of_powers(2**1000, 5, 2)) == []
  781. def test__can_do_sum_of_squares():
  782. assert _can_do_sum_of_squares(3, -1) is False
  783. assert _can_do_sum_of_squares(-3, 1) is False
  784. assert _can_do_sum_of_squares(0, 1)
  785. assert _can_do_sum_of_squares(4, 1)
  786. assert _can_do_sum_of_squares(1, 2)
  787. assert _can_do_sum_of_squares(2, 2)
  788. assert _can_do_sum_of_squares(3, 2) is False
  789. def test_diophantine_permute_sign():
  790. from sympy.abc import a, b, c, d, e
  791. eq = a**4 + b**4 - (2**4 + 3**4)
  792. base_sol = {(2, 3)}
  793. assert diophantine(eq) == base_sol
  794. complete_soln = set(signed_permutations(base_sol.pop()))
  795. assert diophantine(eq, permute=True) == complete_soln
  796. eq = a**2 + b**2 + c**2 + d**2 + e**2 - 234
  797. assert len(diophantine(eq)) == 35
  798. assert len(diophantine(eq, permute=True)) == 62000
  799. soln = {(-1, -1), (-1, 2), (1, -2), (1, 1)}
  800. assert diophantine(10*x**2 + 12*x*y + 12*y**2 - 34, permute=True) == soln
  801. @XFAIL
  802. def test_not_implemented():
  803. eq = x**2 + y**4 - 1**2 - 3**4
  804. assert diophantine(eq, syms=[x, y]) == {(9, 1), (1, 3)}
  805. def test_issue_9538():
  806. eq = x - 3*y + 2
  807. assert diophantine(eq, syms=[y,x]) == {(t_0, 3*t_0 - 2)}
  808. raises(TypeError, lambda: diophantine(eq, syms={y, x}))
  809. def test_ternary_quadratic():
  810. # solution with 3 parameters
  811. s = diophantine(2*x**2 + y**2 - 2*z**2)
  812. p, q, r = ordered(S(s).free_symbols)
  813. assert s == {(
  814. p**2 - 2*q**2,
  815. -2*p**2 + 4*p*q - 4*p*r - 4*q**2,
  816. p**2 - 4*p*q + 2*q**2 - 4*q*r)}
  817. # solution with Mul in solution
  818. s = diophantine(x**2 + 2*y**2 - 2*z**2)
  819. assert s == {(4*p*q, p**2 - 2*q**2, p**2 + 2*q**2)}
  820. # solution with no Mul in solution
  821. s = diophantine(2*x**2 + 2*y**2 - z**2)
  822. assert s == {(2*p**2 - q**2, -2*p**2 + 4*p*q - q**2,
  823. 4*p**2 - 4*p*q + 2*q**2)}
  824. # reduced form when parametrized
  825. s = diophantine(3*x**2 + 72*y**2 - 27*z**2)
  826. assert s == {(24*p**2 - 9*q**2, 6*p*q, 8*p**2 + 3*q**2)}
  827. assert parametrize_ternary_quadratic(
  828. 3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z) == (
  829. 2*p**2 - 2*p*q - q**2, 2*p**2 + 2*p*q - q**2, 2*p**2 -
  830. 2*p*q + 3*q**2)
  831. assert parametrize_ternary_quadratic(
  832. 124*x**2 - 30*y**2 - 7729*z**2) == (
  833. -1410*p**2 - 363263*q**2, 2700*p**2 + 30916*p*q -
  834. 695610*q**2, -60*p**2 + 5400*p*q + 15458*q**2)
  835. def test_diophantine_solution_set():
  836. s1 = DiophantineSolutionSet([], [])
  837. assert set(s1) == set()
  838. assert s1.symbols == ()
  839. assert s1.parameters == ()
  840. raises(ValueError, lambda: s1.add((x,)))
  841. assert list(s1.dict_iterator()) == []
  842. s2 = DiophantineSolutionSet([x, y], [t, u])
  843. assert s2.symbols == (x, y)
  844. assert s2.parameters == (t, u)
  845. raises(ValueError, lambda: s2.add((1,)))
  846. s2.add((3, 4))
  847. assert set(s2) == {(3, 4)}
  848. s2.update((3, 4), (-1, u))
  849. assert set(s2) == {(3, 4), (-1, u)}
  850. raises(ValueError, lambda: s1.update(s2))
  851. assert list(s2.dict_iterator()) == [{x: -1, y: u}, {x: 3, y: 4}]
  852. s3 = DiophantineSolutionSet([x, y, z], [t, u])
  853. assert len(s3.parameters) == 2
  854. s3.add((t**2 + u, t - u, 1))
  855. assert set(s3) == {(t**2 + u, t - u, 1)}
  856. assert s3.subs(t, 2) == {(u + 4, 2 - u, 1)}
  857. assert s3(2) == {(u + 4, 2 - u, 1)}
  858. assert s3.subs({t: 7, u: 8}) == {(57, -1, 1)}
  859. assert s3(7, 8) == {(57, -1, 1)}
  860. assert s3.subs({t: 5}) == {(u + 25, 5 - u, 1)}
  861. assert s3(5) == {(u + 25, 5 - u, 1)}
  862. assert s3.subs(u, -3) == {(t**2 - 3, t + 3, 1)}
  863. assert s3(None, -3) == {(t**2 - 3, t + 3, 1)}
  864. assert s3.subs({t: 2, u: 8}) == {(12, -6, 1)}
  865. assert s3(2, 8) == {(12, -6, 1)}
  866. assert s3.subs({t: 5, u: -3}) == {(22, 8, 1)}
  867. assert s3(5, -3) == {(22, 8, 1)}
  868. raises(TypeError, lambda: s3.subs(x=1))
  869. raises(TypeError, lambda: s3.subs(1, 2, 3))
  870. raises(ValueError, lambda: s3.add(()))
  871. raises(ValueError, lambda: s3.add((1, 2, 3, 4)))
  872. raises(ValueError, lambda: s3.add((1, 2)))
  873. raises(ValueError, lambda: s3(1, 2, 3))
  874. raises(TypeError, lambda: s3(t=1))
  875. s4 = DiophantineSolutionSet([x, y], [t, u])
  876. s4.add((t, 11*t))
  877. s4.add((-t, 22*t))
  878. assert s4(0, 0) == {(0, 0)}
  879. def test_quadratic_parameter_passing():
  880. eq = -33*x*y + 3*y**2
  881. solution = BinaryQuadratic(eq).solve(parameters=[t, u])
  882. # test that parameters are passed all the way to the final solution
  883. assert solution == {(t, 11*t), (t, -22*t)}
  884. assert solution(0, 0) == {(0, 0)}
  885. def test_issue_18628():
  886. eq1 = x**2 - 15*x + y**2 - 8*y
  887. sol = diophantine(eq1)
  888. assert sol == {(15, 0), (15, 8), (-1, 4), (0, 0), (0, 8), (16, 4)}
  889. eq2 = 2*x**2 - 9*x + 4*y**2 - 8*y + 14
  890. sol = diophantine(eq2)
  891. assert sol == {(2, 1)}