图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1027 lines
41 KiB

  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. def test_diop_ternary_quadratic_normal():
  298. assert check_solutions(234*x**2 - 65601*y**2 - z**2)
  299. assert check_solutions(23*x**2 + 616*y**2 - z**2)
  300. assert check_solutions(5*x**2 + 4*y**2 - z**2)
  301. assert check_solutions(3*x**2 + 6*y**2 - 3*z**2)
  302. assert check_solutions(x**2 + 3*y**2 - z**2)
  303. assert check_solutions(4*x**2 + 5*y**2 - z**2)
  304. assert check_solutions(x**2 + y**2 - z**2)
  305. assert check_solutions(16*x**2 + y**2 - 25*z**2)
  306. assert check_solutions(6*x**2 - y**2 + 10*z**2)
  307. assert check_solutions(213*x**2 + 12*y**2 - 9*z**2)
  308. assert check_solutions(34*x**2 - 3*y**2 - 301*z**2)
  309. assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2)
  310. def is_normal_transformation_ok(eq):
  311. A = transformation_to_normal(eq)
  312. X, Y, Z = A*Matrix([x, y, z])
  313. simplified = diop_simplify(eq.subs(zip((x, y, z), (X, Y, Z))))
  314. coeff = dict([reversed(t.as_independent(*[X, Y, Z])) for t in simplified.args])
  315. for term in [X*Y, Y*Z, X*Z]:
  316. if term in coeff.keys():
  317. return False
  318. return True
  319. def test_transformation_to_normal():
  320. assert is_normal_transformation_ok(x**2 + 3*y**2 + z**2 - 13*x*y - 16*y*z + 12*x*z)
  321. assert is_normal_transformation_ok(x**2 + 3*y**2 - 100*z**2)
  322. assert is_normal_transformation_ok(x**2 + 23*y*z)
  323. assert is_normal_transformation_ok(3*y**2 - 100*z**2 - 12*x*y)
  324. assert is_normal_transformation_ok(x**2 + 23*x*y - 34*y*z + 12*x*z)
  325. assert is_normal_transformation_ok(z**2 + 34*x*y - 23*y*z + x*z)
  326. assert is_normal_transformation_ok(x**2 + y**2 + z**2 - x*y - y*z - x*z)
  327. assert is_normal_transformation_ok(x**2 + 2*y*z + 3*z**2)
  328. assert is_normal_transformation_ok(x*y + 2*x*z + 3*y*z)
  329. assert is_normal_transformation_ok(2*x*z + 3*y*z)
  330. def test_diop_ternary_quadratic():
  331. assert check_solutions(2*x**2 + z**2 + y**2 - 4*x*y)
  332. assert check_solutions(x**2 - y**2 - z**2 - x*y - y*z)
  333. assert check_solutions(3*x**2 - x*y - y*z - x*z)
  334. assert check_solutions(x**2 - y*z - x*z)
  335. assert check_solutions(5*x**2 - 3*x*y - x*z)
  336. assert check_solutions(4*x**2 - 5*y**2 - x*z)
  337. assert check_solutions(3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z)
  338. assert check_solutions(8*x**2 - 12*y*z)
  339. assert check_solutions(45*x**2 - 7*y**2 - 8*x*y - z**2)
  340. assert check_solutions(x**2 - 49*y**2 - z**2 + 13*z*y -8*x*y)
  341. assert check_solutions(90*x**2 + 3*y**2 + 5*x*y + 2*z*y + 5*x*z)
  342. assert check_solutions(x**2 + 3*y**2 + z**2 - x*y - 17*y*z)
  343. assert check_solutions(x**2 + 3*y**2 + z**2 - x*y - 16*y*z + 12*x*z)
  344. assert check_solutions(x**2 + 3*y**2 + z**2 - 13*x*y - 16*y*z + 12*x*z)
  345. assert check_solutions(x*y - 7*y*z + 13*x*z)
  346. assert diop_ternary_quadratic_normal(x**2 + y**2 + z**2) == (None, None, None)
  347. assert diop_ternary_quadratic_normal(x**2 + y**2) is None
  348. raises(ValueError, lambda:
  349. _diop_ternary_quadratic_normal((x, y, z),
  350. {x*y: 1, x**2: 2, y**2: 3, z**2: 0}))
  351. eq = -2*x*y - 6*x*z + 7*y**2 - 3*y*z + 4*z**2
  352. assert diop_ternary_quadratic(eq) == (7, 2, 0)
  353. assert diop_ternary_quadratic_normal(4*x**2 + 5*y**2 - z**2) == \
  354. (1, 0, 2)
  355. assert diop_ternary_quadratic(x*y + 2*y*z) == \
  356. (-2, 0, n1)
  357. eq = -5*x*y - 8*x*z - 3*y*z + 8*z**2
  358. assert parametrize_ternary_quadratic(eq) == \
  359. (8*p**2 - 3*p*q, -8*p*q + 8*q**2, 5*p*q)
  360. # this cannot be tested with diophantine because it will
  361. # factor into a product
  362. assert diop_solve(x*y + 2*y*z) == (-2*p*q, -n1*p**2 + p**2, p*q)
  363. def test_square_factor():
  364. assert square_factor(1) == square_factor(-1) == 1
  365. assert square_factor(0) == 1
  366. assert square_factor(5) == square_factor(-5) == 1
  367. assert square_factor(4) == square_factor(-4) == 2
  368. assert square_factor(12) == square_factor(-12) == 2
  369. assert square_factor(6) == 1
  370. assert square_factor(18) == 3
  371. assert square_factor(52) == 2
  372. assert square_factor(49) == 7
  373. assert square_factor(392) == 14
  374. assert square_factor(factorint(-12)) == 2
  375. def test_parametrize_ternary_quadratic():
  376. assert check_solutions(x**2 + y**2 - z**2)
  377. assert check_solutions(x**2 + 2*x*y + z**2)
  378. assert check_solutions(234*x**2 - 65601*y**2 - z**2)
  379. assert check_solutions(3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z)
  380. assert check_solutions(x**2 - y**2 - z**2)
  381. assert check_solutions(x**2 - 49*y**2 - z**2 + 13*z*y - 8*x*y)
  382. assert check_solutions(8*x*y + z**2)
  383. assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2)
  384. assert check_solutions(236*x**2 - 225*y**2 - 11*x*y - 13*y*z - 17*x*z)
  385. assert check_solutions(90*x**2 + 3*y**2 + 5*x*y + 2*z*y + 5*x*z)
  386. assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2)
  387. def test_no_square_ternary_quadratic():
  388. assert check_solutions(2*x*y + y*z - 3*x*z)
  389. assert check_solutions(189*x*y - 345*y*z - 12*x*z)
  390. assert check_solutions(23*x*y + 34*y*z)
  391. assert check_solutions(x*y + y*z + z*x)
  392. assert check_solutions(23*x*y + 23*y*z + 23*x*z)
  393. def test_descent():
  394. u = ([(13, 23), (3, -11), (41, -113), (91, -3), (1, 1), (1, -1), (17, 13), (123689, 1), (19, -570)])
  395. for a, b in u:
  396. w, x, y = descent(a, b)
  397. assert a*x**2 + b*y**2 == w**2
  398. # the docstring warns against bad input, so these are expected results
  399. # - can't both be negative
  400. raises(TypeError, lambda: descent(-1, -3))
  401. # A can't be zero unless B != 1
  402. raises(ZeroDivisionError, lambda: descent(0, 3))
  403. # supposed to be square-free
  404. raises(TypeError, lambda: descent(4, 3))
  405. def test_diophantine():
  406. assert check_solutions((x - y)*(y - z)*(z - x))
  407. assert check_solutions((x - y)*(x**2 + y**2 - z**2))
  408. assert check_solutions((x - 3*y + 7*z)*(x**2 + y**2 - z**2))
  409. assert check_solutions(x**2 - 3*y**2 - 1)
  410. assert check_solutions(y**2 + 7*x*y)
  411. assert check_solutions(x**2 - 3*x*y + y**2)
  412. assert check_solutions(z*(x**2 - y**2 - 15))
  413. assert check_solutions(x*(2*y - 2*z + 5))
  414. assert check_solutions((x**2 - 3*y**2 - 1)*(x**2 - y**2 - 15))
  415. assert check_solutions((x**2 - 3*y**2 - 1)*(y - 7*z))
  416. assert check_solutions((x**2 + y**2 - z**2)*(x - 7*y - 3*z + 4*w))
  417. # Following test case caused problems in parametric representation
  418. # But this can be solved by factoring out y.
  419. # No need to use methods for ternary quadratic equations.
  420. assert check_solutions(y**2 - 7*x*y + 4*y*z)
  421. assert check_solutions(x**2 - 2*x + 1)
  422. assert diophantine(x - y) == diophantine(Eq(x, y))
  423. # 18196
  424. eq = x**4 + y**4 - 97
  425. assert diophantine(eq, permute=True) == diophantine(-eq, permute=True)
  426. assert diophantine(3*x*pi - 2*y*pi) == {(2*t_0, 3*t_0)}
  427. eq = x**2 + y**2 + z**2 - 14
  428. base_sol = {(1, 2, 3)}
  429. assert diophantine(eq) == base_sol
  430. complete_soln = set(signed_permutations(base_sol.pop()))
  431. assert diophantine(eq, permute=True) == complete_soln
  432. assert diophantine(x**2 + x*Rational(15, 14) - 3) == set()
  433. # test issue 11049
  434. eq = 92*x**2 - 99*y**2 - z**2
  435. coeff = eq.as_coefficients_dict()
  436. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  437. {(9, 7, 51)}
  438. assert diophantine(eq) == {(
  439. 891*p**2 + 9*q**2, -693*p**2 - 102*p*q + 7*q**2,
  440. 5049*p**2 - 1386*p*q - 51*q**2)}
  441. eq = 2*x**2 + 2*y**2 - z**2
  442. coeff = eq.as_coefficients_dict()
  443. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  444. {(1, 1, 2)}
  445. assert diophantine(eq) == {(
  446. 2*p**2 - q**2, -2*p**2 + 4*p*q - q**2,
  447. 4*p**2 - 4*p*q + 2*q**2)}
  448. eq = 411*x**2+57*y**2-221*z**2
  449. coeff = eq.as_coefficients_dict()
  450. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  451. {(2021, 2645, 3066)}
  452. assert diophantine(eq) == \
  453. {(115197*p**2 - 446641*q**2, -150765*p**2 + 1355172*p*q -
  454. 584545*q**2, 174762*p**2 - 301530*p*q + 677586*q**2)}
  455. eq = 573*x**2+267*y**2-984*z**2
  456. coeff = eq.as_coefficients_dict()
  457. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  458. {(49, 233, 127)}
  459. assert diophantine(eq) == \
  460. {(4361*p**2 - 16072*q**2, -20737*p**2 + 83312*p*q - 76424*q**2,
  461. 11303*p**2 - 41474*p*q + 41656*q**2)}
  462. # this produces factors during reconstruction
  463. eq = x**2 + 3*y**2 - 12*z**2
  464. coeff = eq.as_coefficients_dict()
  465. assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \
  466. {(0, 2, 1)}
  467. assert diophantine(eq) == \
  468. {(24*p*q, 2*p**2 - 24*q**2, p**2 + 12*q**2)}
  469. # solvers have not been written for every type
  470. raises(NotImplementedError, lambda: diophantine(x*y**2 + 1))
  471. # rational expressions
  472. assert diophantine(1/x) == set()
  473. assert diophantine(1/x + 1/y - S.Half) == {(6, 3), (-2, 1), (4, 4), (1, -2), (3, 6)}
  474. assert diophantine(x**2 + y**2 +3*x- 5, permute=True) == \
  475. {(-1, 1), (-4, -1), (1, -1), (1, 1), (-4, 1), (-1, -1), (4, 1), (4, -1)}
  476. #test issue 18186
  477. assert diophantine(y**4 + x**4 - 2**4 - 3**4, syms=(x, y), permute=True) == \
  478. {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)}
  479. assert diophantine(y**4 + x**4 - 2**4 - 3**4, syms=(y, x), permute=True) == \
  480. {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)}
  481. # issue 18122
  482. assert check_solutions(x**2-y)
  483. assert check_solutions(y**2-x)
  484. assert diophantine((x**2-y), t) == {(t, t**2)}
  485. assert diophantine((y**2-x), t) == {(t**2, -t)}
  486. def test_general_pythagorean():
  487. from sympy.abc import a, b, c, d, e
  488. assert check_solutions(a**2 + b**2 + c**2 - d**2)
  489. assert check_solutions(a**2 + 4*b**2 + 4*c**2 - d**2)
  490. assert check_solutions(9*a**2 + 4*b**2 + 4*c**2 - d**2)
  491. assert check_solutions(9*a**2 + 4*b**2 - 25*d**2 + 4*c**2 )
  492. assert check_solutions(9*a**2 - 16*d**2 + 4*b**2 + 4*c**2)
  493. assert check_solutions(-e**2 + 9*a**2 + 4*b**2 + 4*c**2 + 25*d**2)
  494. assert check_solutions(16*a**2 - b**2 + 9*c**2 + d**2 + 25*e**2)
  495. assert GeneralPythagorean(a**2 + b**2 + c**2 - d**2).solve(parameters=[x, y, z]) == \
  496. {(x**2 + y**2 - z**2, 2*x*z, 2*y*z, x**2 + y**2 + z**2)}
  497. def test_diop_general_sum_of_squares_quick():
  498. for i in range(3, 10):
  499. assert check_solutions(sum(i**2 for i in symbols(':%i' % i)) - i)
  500. assert diop_general_sum_of_squares(x**2 + y**2 - 2) is None
  501. assert diop_general_sum_of_squares(x**2 + y**2 + z**2 + 2) == set()
  502. eq = x**2 + y**2 + z**2 - (1 + 4 + 9)
  503. assert diop_general_sum_of_squares(eq) == \
  504. {(1, 2, 3)}
  505. eq = u**2 + v**2 + x**2 + y**2 + z**2 - 1313
  506. assert len(diop_general_sum_of_squares(eq, 3)) == 3
  507. # issue 11016
  508. var = symbols(':5') + (symbols('6', negative=True),)
  509. eq = Add(*[i**2 for i in var]) - 112
  510. 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),
  511. (0, 0, 4, 4, 4, -8), (1, 2, 3, 3, 5, -8), (0, 1, 2, 3, 7, -7), (2, 2, 4, 4, 6, -6),
  512. (1, 1, 3, 4, 6, -7), (0, 2, 3, 3, 3, -9), (0, 0, 2, 2, 2, -10), (1, 1, 2, 3, 4, -9),
  513. (0, 1, 1, 2, 5, -9), (0, 0, 2, 6, 6, -6), (1, 3, 4, 5, 5, -6), (0, 2, 2, 2, 6, -8),
  514. (0, 3, 3, 3, 6, -7), (0, 2, 3, 5, 5, -7), (0, 1, 5, 5, 5, -6)}
  515. assert diophantine(eq) == base_soln
  516. assert len(diophantine(eq, permute=True)) == 196800
  517. # handle negated squares with signsimp
  518. assert diophantine(12 - x**2 - y**2 - z**2) == {(2, 2, 2)}
  519. # diophantine handles simplification, so classify_diop should
  520. # not have to look for additional patterns that are removed
  521. # by diophantine
  522. eq = a**2 + b**2 + c**2 + d**2 - 4
  523. raises(NotImplementedError, lambda: classify_diop(-eq))
  524. def test_diop_partition():
  525. for n in [8, 10]:
  526. for k in range(1, 8):
  527. for p in partition(n, k):
  528. assert len(p) == k
  529. assert [p for p in partition(3, 5)] == []
  530. assert [list(p) for p in partition(3, 5, 1)] == [
  531. [0, 0, 0, 0, 3], [0, 0, 0, 1, 2], [0, 0, 1, 1, 1]]
  532. assert list(partition(0)) == [()]
  533. assert list(partition(1, 0)) == [()]
  534. assert [list(i) for i in partition(3)] == [[1, 1, 1], [1, 2], [3]]
  535. def test_prime_as_sum_of_two_squares():
  536. for i in [5, 13, 17, 29, 37, 41, 2341, 3557, 34841, 64601]:
  537. a, b = prime_as_sum_of_two_squares(i)
  538. assert a**2 + b**2 == i
  539. assert prime_as_sum_of_two_squares(7) is None
  540. ans = prime_as_sum_of_two_squares(800029)
  541. assert ans == (450, 773) and type(ans[0]) is int
  542. def test_sum_of_three_squares():
  543. for i in [0, 1, 2, 34, 123, 34304595905, 34304595905394941, 343045959052344,
  544. 800, 801, 802, 803, 804, 805, 806]:
  545. a, b, c = sum_of_three_squares(i)
  546. assert a**2 + b**2 + c**2 == i
  547. assert sum_of_three_squares(7) is None
  548. assert sum_of_three_squares((4**5)*15) is None
  549. assert sum_of_three_squares(25) == (5, 0, 0)
  550. assert sum_of_three_squares(4) == (0, 0, 2)
  551. def test_sum_of_four_squares():
  552. from sympy.core.random import randint
  553. # this should never fail
  554. n = randint(1, 100000000000000)
  555. assert sum(i**2 for i in sum_of_four_squares(n)) == n
  556. assert sum_of_four_squares(0) == (0, 0, 0, 0)
  557. assert sum_of_four_squares(14) == (0, 1, 2, 3)
  558. assert sum_of_four_squares(15) == (1, 1, 2, 3)
  559. assert sum_of_four_squares(18) == (1, 2, 2, 3)
  560. assert sum_of_four_squares(19) == (0, 1, 3, 3)
  561. assert sum_of_four_squares(48) == (0, 4, 4, 4)
  562. def test_power_representation():
  563. tests = [(1729, 3, 2), (234, 2, 4), (2, 1, 2), (3, 1, 3), (5, 2, 2), (12352, 2, 4),
  564. (32760, 2, 3)]
  565. for test in tests:
  566. n, p, k = test
  567. f = power_representation(n, p, k)
  568. while True:
  569. try:
  570. l = next(f)
  571. assert len(l) == k
  572. chk_sum = 0
  573. for l_i in l:
  574. chk_sum = chk_sum + l_i**p
  575. assert chk_sum == n
  576. except StopIteration:
  577. break
  578. assert list(power_representation(20, 2, 4, True)) == \
  579. [(1, 1, 3, 3), (0, 0, 2, 4)]
  580. raises(ValueError, lambda: list(power_representation(1.2, 2, 2)))
  581. raises(ValueError, lambda: list(power_representation(2, 0, 2)))
  582. raises(ValueError, lambda: list(power_representation(2, 2, 0)))
  583. assert list(power_representation(-1, 2, 2)) == []
  584. assert list(power_representation(1, 1, 1)) == [(1,)]
  585. assert list(power_representation(3, 2, 1)) == []
  586. assert list(power_representation(4, 2, 1)) == [(2,)]
  587. assert list(power_representation(3**4, 4, 6, zeros=True)) == \
  588. [(1, 2, 2, 2, 2, 2), (0, 0, 0, 0, 0, 3)]
  589. assert list(power_representation(3**4, 4, 5, zeros=False)) == []
  590. assert list(power_representation(-2, 3, 2)) == [(-1, -1)]
  591. assert list(power_representation(-2, 4, 2)) == []
  592. assert list(power_representation(0, 3, 2, True)) == [(0, 0)]
  593. assert list(power_representation(0, 3, 2, False)) == []
  594. # when we are dealing with squares, do feasibility checks
  595. assert len(list(power_representation(4**10*(8*10 + 7), 2, 3))) == 0
  596. # there will be a recursion error if these aren't recognized
  597. big = 2**30
  598. for i in [13, 10, 7, 5, 4, 2, 1]:
  599. assert list(sum_of_powers(big, 2, big - i)) == []
  600. def test_assumptions():
  601. """
  602. Test whether diophantine respects the assumptions.
  603. """
  604. #Test case taken from the below so question regarding assumptions in diophantine module
  605. #https://stackoverflow.com/questions/23301941/how-can-i-declare-natural-symbols-with-sympy
  606. m, n = symbols('m n', integer=True, positive=True)
  607. diof = diophantine(n**2 + m*n - 500)
  608. assert diof == {(5, 20), (40, 10), (95, 5), (121, 4), (248, 2), (499, 1)}
  609. a, b = symbols('a b', integer=True, positive=False)
  610. diof = diophantine(a*b + 2*a + 3*b - 6)
  611. assert diof == {(-15, -3), (-9, -4), (-7, -5), (-6, -6), (-5, -8), (-4, -14)}
  612. def check_solutions(eq):
  613. """
  614. Determines whether solutions returned by diophantine() satisfy the original
  615. equation. Hope to generalize this so we can remove functions like check_ternay_quadratic,
  616. check_solutions_normal, check_solutions()
  617. """
  618. s = diophantine(eq)
  619. factors = Mul.make_args(eq)
  620. var = list(eq.free_symbols)
  621. var.sort(key=default_sort_key)
  622. while s:
  623. solution = s.pop()
  624. for f in factors:
  625. if diop_simplify(f.subs(zip(var, solution))) == 0:
  626. break
  627. else:
  628. return False
  629. return True
  630. def test_diopcoverage():
  631. eq = (2*x + y + 1)**2
  632. assert diop_solve(eq) == {(t_0, -2*t_0 - 1)}
  633. eq = 2*x**2 + 6*x*y + 12*x + 4*y**2 + 18*y + 18
  634. assert diop_solve(eq) == {(t, -t - 3), (2*t - 3, -t)}
  635. assert diop_quadratic(x + y**2 - 3) == {(-t**2 + 3, -t)}
  636. assert diop_linear(x + y - 3) == (t_0, 3 - t_0)
  637. assert base_solution_linear(0, 1, 2, t=None) == (0, 0)
  638. ans = (3*t - 1, -2*t + 1)
  639. assert base_solution_linear(4, 8, 12, t) == ans
  640. assert base_solution_linear(4, 8, 12, t=None) == tuple(_.subs(t, 0) for _ in ans)
  641. assert cornacchia(1, 1, 20) is None
  642. assert cornacchia(1, 1, 5) == {(2, 1)}
  643. assert cornacchia(1, 2, 17) == {(3, 2)}
  644. raises(ValueError, lambda: reconstruct(4, 20, 1))
  645. assert gaussian_reduce(4, 1, 3) == (1, 1)
  646. eq = -w**2 - x**2 - y**2 + z**2
  647. assert diop_general_pythagorean(eq) == \
  648. diop_general_pythagorean(-eq) == \
  649. (m1**2 + m2**2 - m3**2, 2*m1*m3,
  650. 2*m2*m3, m1**2 + m2**2 + m3**2)
  651. assert len(check_param(S(3) + x/3, S(4) + x/2, S(2), [x])) == 0
  652. assert len(check_param(Rational(3, 2), S(4) + x, S(2), [x])) == 0
  653. assert len(check_param(S(4) + x, Rational(3, 2), S(2), [x])) == 0
  654. assert _nint_or_floor(16, 10) == 2
  655. assert _odd(1) == (not _even(1)) == True
  656. assert _odd(0) == (not _even(0)) == False
  657. assert _remove_gcd(2, 4, 6) == (1, 2, 3)
  658. raises(TypeError, lambda: _remove_gcd((2, 4, 6)))
  659. assert sqf_normal(2*3**2*5, 2*5*11, 2*7**2*11) == \
  660. (11, 1, 5)
  661. # it's ok if these pass some day when the solvers are implemented
  662. raises(NotImplementedError, lambda: diophantine(x**2 + y**2 + x*y + 2*y*z - 12))
  663. raises(NotImplementedError, lambda: diophantine(x**3 + y**2))
  664. assert diop_quadratic(x**2 + y**2 - 1**2 - 3**4) == \
  665. {(-9, -1), (-9, 1), (-1, -9), (-1, 9), (1, -9), (1, 9), (9, -1), (9, 1)}
  666. def test_holzer():
  667. # if the input is good, don't let it diverge in holzer()
  668. # (but see test_fail_holzer below)
  669. assert holzer(2, 7, 13, 4, 79, 23) == (2, 7, 13)
  670. # None in uv condition met; solution is not Holzer reduced
  671. # so this will hopefully change but is here for coverage
  672. assert holzer(2, 6, 2, 1, 1, 10) == (2, 6, 2)
  673. raises(ValueError, lambda: holzer(2, 7, 14, 4, 79, 23))
  674. @XFAIL
  675. def test_fail_holzer():
  676. eq = lambda x, y, z: a*x**2 + b*y**2 - c*z**2
  677. a, b, c = 4, 79, 23
  678. x, y, z = xyz = 26, 1, 11
  679. X, Y, Z = ans = 2, 7, 13
  680. assert eq(*xyz) == 0
  681. assert eq(*ans) == 0
  682. assert max(a*x**2, b*y**2, c*z**2) <= a*b*c
  683. assert max(a*X**2, b*Y**2, c*Z**2) <= a*b*c
  684. h = holzer(x, y, z, a, b, c)
  685. assert h == ans # it would be nice to get the smaller soln
  686. def test_issue_9539():
  687. assert diophantine(6*w + 9*y + 20*x - z) == \
  688. {(t_0, t_1, t_1 + t_2, 6*t_0 + 29*t_1 + 9*t_2)}
  689. def test_issue_8943():
  690. assert diophantine(
  691. 3*(x**2 + y**2 + z**2) - 14*(x*y + y*z + z*x)) == \
  692. {(0, 0, 0)}
  693. def test_diop_sum_of_even_powers():
  694. eq = x**4 + y**4 + z**4 - 2673
  695. assert diop_solve(eq) == {(3, 6, 6), (2, 4, 7)}
  696. assert diop_general_sum_of_even_powers(eq, 2) == {(3, 6, 6), (2, 4, 7)}
  697. raises(NotImplementedError, lambda: diop_general_sum_of_even_powers(-eq, 2))
  698. neg = symbols('neg', negative=True)
  699. eq = x**4 + y**4 + neg**4 - 2673
  700. assert diop_general_sum_of_even_powers(eq) == {(-3, 6, 6)}
  701. assert diophantine(x**4 + y**4 + 2) == set()
  702. assert diop_general_sum_of_even_powers(x**4 + y**4 - 2, limit=0) == set()
  703. def test_sum_of_squares_powers():
  704. 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),
  705. (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),
  706. (2, 3, 5, 6, 7), (3, 3, 4, 5, 8)}
  707. eq = u**2 + v**2 + x**2 + y**2 + z**2 - 123
  708. ans = diop_general_sum_of_squares(eq, oo) # allow oo to be used
  709. assert len(ans) == 14
  710. assert ans == tru
  711. raises(ValueError, lambda: list(sum_of_squares(10, -1)))
  712. assert list(sum_of_squares(-10, 2)) == []
  713. assert list(sum_of_squares(2, 3)) == []
  714. assert list(sum_of_squares(0, 3, True)) == [(0, 0, 0)]
  715. assert list(sum_of_squares(0, 3)) == []
  716. assert list(sum_of_squares(4, 1)) == [(2,)]
  717. assert list(sum_of_squares(5, 1)) == []
  718. assert list(sum_of_squares(50, 2)) == [(5, 5), (1, 7)]
  719. assert list(sum_of_squares(11, 5, True)) == [
  720. (1, 1, 1, 2, 2), (0, 0, 1, 1, 3)]
  721. assert list(sum_of_squares(8, 8)) == [(1, 1, 1, 1, 1, 1, 1, 1)]
  722. assert [len(list(sum_of_squares(i, 5, True))) for i in range(30)] == [
  723. 1, 1, 1, 1, 2,
  724. 2, 1, 1, 2, 2,
  725. 2, 2, 2, 3, 2,
  726. 1, 3, 3, 3, 3,
  727. 4, 3, 3, 2, 2,
  728. 4, 4, 4, 4, 5]
  729. assert [len(list(sum_of_squares(i, 5))) for i in range(30)] == [
  730. 0, 0, 0, 0, 0,
  731. 1, 0, 0, 1, 0,
  732. 0, 1, 0, 1, 1,
  733. 0, 1, 1, 0, 1,
  734. 2, 1, 1, 1, 1,
  735. 1, 1, 1, 1, 3]
  736. for i in range(30):
  737. s1 = set(sum_of_squares(i, 5, True))
  738. assert not s1 or all(sum(j**2 for j in t) == i for t in s1)
  739. s2 = set(sum_of_squares(i, 5))
  740. assert all(sum(j**2 for j in t) == i for t in s2)
  741. raises(ValueError, lambda: list(sum_of_powers(2, -1, 1)))
  742. raises(ValueError, lambda: list(sum_of_powers(2, 1, -1)))
  743. assert list(sum_of_powers(-2, 3, 2)) == [(-1, -1)]
  744. assert list(sum_of_powers(-2, 4, 2)) == []
  745. assert list(sum_of_powers(2, 1, 1)) == [(2,)]
  746. assert list(sum_of_powers(2, 1, 3, True)) == [(0, 0, 2), (0, 1, 1)]
  747. assert list(sum_of_powers(5, 1, 2, True)) == [(0, 5), (1, 4), (2, 3)]
  748. assert list(sum_of_powers(6, 2, 2)) == []
  749. assert list(sum_of_powers(3**5, 3, 1)) == []
  750. assert list(sum_of_powers(3**6, 3, 1)) == [(9,)] and (9**3 == 3**6)
  751. assert list(sum_of_powers(2**1000, 5, 2)) == []
  752. def test__can_do_sum_of_squares():
  753. assert _can_do_sum_of_squares(3, -1) is False
  754. assert _can_do_sum_of_squares(-3, 1) is False
  755. assert _can_do_sum_of_squares(0, 1)
  756. assert _can_do_sum_of_squares(4, 1)
  757. assert _can_do_sum_of_squares(1, 2)
  758. assert _can_do_sum_of_squares(2, 2)
  759. assert _can_do_sum_of_squares(3, 2) is False
  760. def test_diophantine_permute_sign():
  761. from sympy.abc import a, b, c, d, e
  762. eq = a**4 + b**4 - (2**4 + 3**4)
  763. base_sol = {(2, 3)}
  764. assert diophantine(eq) == base_sol
  765. complete_soln = set(signed_permutations(base_sol.pop()))
  766. assert diophantine(eq, permute=True) == complete_soln
  767. eq = a**2 + b**2 + c**2 + d**2 + e**2 - 234
  768. assert len(diophantine(eq)) == 35
  769. assert len(diophantine(eq, permute=True)) == 62000
  770. soln = {(-1, -1), (-1, 2), (1, -2), (1, 1)}
  771. assert diophantine(10*x**2 + 12*x*y + 12*y**2 - 34, permute=True) == soln
  772. @XFAIL
  773. def test_not_implemented():
  774. eq = x**2 + y**4 - 1**2 - 3**4
  775. assert diophantine(eq, syms=[x, y]) == {(9, 1), (1, 3)}
  776. def test_issue_9538():
  777. eq = x - 3*y + 2
  778. assert diophantine(eq, syms=[y,x]) == {(t_0, 3*t_0 - 2)}
  779. raises(TypeError, lambda: diophantine(eq, syms={y, x}))
  780. def test_ternary_quadratic():
  781. # solution with 3 parameters
  782. s = diophantine(2*x**2 + y**2 - 2*z**2)
  783. p, q, r = ordered(S(s).free_symbols)
  784. assert s == {(
  785. p**2 - 2*q**2,
  786. -2*p**2 + 4*p*q - 4*p*r - 4*q**2,
  787. p**2 - 4*p*q + 2*q**2 - 4*q*r)}
  788. # solution with Mul in solution
  789. s = diophantine(x**2 + 2*y**2 - 2*z**2)
  790. assert s == {(4*p*q, p**2 - 2*q**2, p**2 + 2*q**2)}
  791. # solution with no Mul in solution
  792. s = diophantine(2*x**2 + 2*y**2 - z**2)
  793. assert s == {(2*p**2 - q**2, -2*p**2 + 4*p*q - q**2,
  794. 4*p**2 - 4*p*q + 2*q**2)}
  795. # reduced form when parametrized
  796. s = diophantine(3*x**2 + 72*y**2 - 27*z**2)
  797. assert s == {(24*p**2 - 9*q**2, 6*p*q, 8*p**2 + 3*q**2)}
  798. assert parametrize_ternary_quadratic(
  799. 3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z) == (
  800. 2*p**2 - 2*p*q - q**2, 2*p**2 + 2*p*q - q**2, 2*p**2 -
  801. 2*p*q + 3*q**2)
  802. assert parametrize_ternary_quadratic(
  803. 124*x**2 - 30*y**2 - 7729*z**2) == (
  804. -1410*p**2 - 363263*q**2, 2700*p**2 + 30916*p*q -
  805. 695610*q**2, -60*p**2 + 5400*p*q + 15458*q**2)
  806. def test_diophantine_solution_set():
  807. s1 = DiophantineSolutionSet([], [])
  808. assert set(s1) == set()
  809. assert s1.symbols == ()
  810. assert s1.parameters == ()
  811. raises(ValueError, lambda: s1.add((x,)))
  812. assert list(s1.dict_iterator()) == []
  813. s2 = DiophantineSolutionSet([x, y], [t, u])
  814. assert s2.symbols == (x, y)
  815. assert s2.parameters == (t, u)
  816. raises(ValueError, lambda: s2.add((1,)))
  817. s2.add((3, 4))
  818. assert set(s2) == {(3, 4)}
  819. s2.update((3, 4), (-1, u))
  820. assert set(s2) == {(3, 4), (-1, u)}
  821. raises(ValueError, lambda: s1.update(s2))
  822. assert list(s2.dict_iterator()) == [{x: -1, y: u}, {x: 3, y: 4}]
  823. s3 = DiophantineSolutionSet([x, y, z], [t, u])
  824. assert len(s3.parameters) == 2
  825. s3.add((t**2 + u, t - u, 1))
  826. assert set(s3) == {(t**2 + u, t - u, 1)}
  827. assert s3.subs(t, 2) == {(u + 4, 2 - u, 1)}
  828. assert s3(2) == {(u + 4, 2 - u, 1)}
  829. assert s3.subs({t: 7, u: 8}) == {(57, -1, 1)}
  830. assert s3(7, 8) == {(57, -1, 1)}
  831. assert s3.subs({t: 5}) == {(u + 25, 5 - u, 1)}
  832. assert s3(5) == {(u + 25, 5 - u, 1)}
  833. assert s3.subs(u, -3) == {(t**2 - 3, t + 3, 1)}
  834. assert s3(None, -3) == {(t**2 - 3, t + 3, 1)}
  835. assert s3.subs({t: 2, u: 8}) == {(12, -6, 1)}
  836. assert s3(2, 8) == {(12, -6, 1)}
  837. assert s3.subs({t: 5, u: -3}) == {(22, 8, 1)}
  838. assert s3(5, -3) == {(22, 8, 1)}
  839. raises(ValueError, lambda: s3.subs(x=1))
  840. raises(ValueError, lambda: s3.subs(1, 2, 3))
  841. raises(ValueError, lambda: s3.add(()))
  842. raises(ValueError, lambda: s3.add((1, 2, 3, 4)))
  843. raises(ValueError, lambda: s3.add((1, 2)))
  844. raises(ValueError, lambda: s3(1, 2, 3))
  845. raises(TypeError, lambda: s3(t=1))
  846. s4 = DiophantineSolutionSet([x, y], [t, u])
  847. s4.add((t, 11*t))
  848. s4.add((-t, 22*t))
  849. assert s4(0, 0) == {(0, 0)}
  850. def test_quadratic_parameter_passing():
  851. eq = -33*x*y + 3*y**2
  852. solution = BinaryQuadratic(eq).solve(parameters=[t, u])
  853. # test that parameters are passed all the way to the final solution
  854. assert solution == {(t, 11*t), (-t, 22*t)}
  855. assert solution(0, 0) == {(0, 0)}