specialpolys.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. """Functions for generating interesting polynomials, e.g. for benchmarking. """
  2. from sympy.core import Add, Mul, Symbol, sympify, Dummy, symbols
  3. from sympy.core.containers import Tuple
  4. from sympy.core.singleton import S
  5. from sympy.functions.elementary.miscellaneous import sqrt
  6. from sympy.ntheory import nextprime
  7. from sympy.polys.densearith import (
  8. dmp_add_term, dmp_neg, dmp_mul, dmp_sqr
  9. )
  10. from sympy.polys.densebasic import (
  11. dmp_zero, dmp_one, dmp_ground,
  12. dup_from_raw_dict, dmp_raise, dup_random
  13. )
  14. from sympy.polys.domains import ZZ
  15. from sympy.polys.factortools import dup_zz_cyclotomic_poly
  16. from sympy.polys.polyclasses import DMP
  17. from sympy.polys.polytools import Poly, PurePoly
  18. from sympy.polys.polyutils import _analyze_gens
  19. from sympy.utilities import subsets, public, filldedent
  20. @public
  21. def swinnerton_dyer_poly(n, x=None, polys=False):
  22. """Generates n-th Swinnerton-Dyer polynomial in `x`.
  23. Parameters
  24. ----------
  25. n : int
  26. `n` decides the order of polynomial
  27. x : optional
  28. polys : bool, optional
  29. ``polys=True`` returns an expression, otherwise
  30. (default) returns an expression.
  31. """
  32. from .numberfields import minimal_polynomial
  33. if n <= 0:
  34. raise ValueError(
  35. "Cannot generate Swinnerton-Dyer polynomial of order %s" % n)
  36. if x is not None:
  37. sympify(x)
  38. else:
  39. x = Dummy('x')
  40. if n > 3:
  41. p = 2
  42. a = [sqrt(2)]
  43. for i in range(2, n + 1):
  44. p = nextprime(p)
  45. a.append(sqrt(p))
  46. return minimal_polynomial(Add(*a), x, polys=polys)
  47. if n == 1:
  48. ex = x**2 - 2
  49. elif n == 2:
  50. ex = x**4 - 10*x**2 + 1
  51. elif n == 3:
  52. ex = x**8 - 40*x**6 + 352*x**4 - 960*x**2 + 576
  53. return PurePoly(ex, x) if polys else ex
  54. @public
  55. def cyclotomic_poly(n, x=None, polys=False):
  56. """Generates cyclotomic polynomial of order `n` in `x`.
  57. Parameters
  58. ----------
  59. n : int
  60. `n` decides the order of polynomial
  61. x : optional
  62. polys : bool, optional
  63. ``polys=True`` returns an expression, otherwise
  64. (default) returns an expression.
  65. """
  66. if n <= 0:
  67. raise ValueError(
  68. "Cannot generate cyclotomic polynomial of order %s" % n)
  69. poly = DMP(dup_zz_cyclotomic_poly(int(n), ZZ), ZZ)
  70. if x is not None:
  71. poly = Poly.new(poly, x)
  72. else:
  73. poly = PurePoly.new(poly, Dummy('x'))
  74. return poly if polys else poly.as_expr()
  75. @public
  76. def symmetric_poly(n, *gens, **args):
  77. """Generates symmetric polynomial of order `n`.
  78. Returns a Poly object when ``polys=True``, otherwise
  79. (default) returns an expression.
  80. """
  81. # TODO: use an explicit keyword argument
  82. gens = _analyze_gens(gens)
  83. if n < 0 or n > len(gens) or not gens:
  84. raise ValueError("Cannot generate symmetric polynomial of order %s for %s" % (n, gens))
  85. elif not n:
  86. poly = S.One
  87. else:
  88. poly = Add(*[Mul(*s) for s in subsets(gens, int(n))])
  89. if not args.get('polys', False):
  90. return poly
  91. else:
  92. return Poly(poly, *gens)
  93. @public
  94. def random_poly(x, n, inf, sup, domain=ZZ, polys=False):
  95. """Generates a polynomial of degree ``n`` with coefficients in
  96. ``[inf, sup]``.
  97. Parameters
  98. ----------
  99. x
  100. `x` is the independent term of polynomial
  101. n : int
  102. `n` decides the order of polynomial
  103. inf
  104. Lower limit of range in which coefficients lie
  105. sup
  106. Upper limit of range in which coefficients lie
  107. domain : optional
  108. Decides what ring the coefficients are supposed
  109. to belong. Default is set to Integers.
  110. polys : bool, optional
  111. ``polys=True`` returns an expression, otherwise
  112. (default) returns an expression.
  113. """
  114. poly = Poly(dup_random(n, inf, sup, domain), x, domain=domain)
  115. return poly if polys else poly.as_expr()
  116. @public
  117. def interpolating_poly(n, x, X='x', Y='y'):
  118. """Construct Lagrange interpolating polynomial for ``n``
  119. data points. If a sequence of values are given for ``X`` and ``Y``
  120. then the first ``n`` values will be used.
  121. """
  122. ok = getattr(x, 'free_symbols', None)
  123. if isinstance(X, str):
  124. X = symbols("%s:%s" % (X, n))
  125. elif ok and ok & Tuple(*X).free_symbols:
  126. ok = False
  127. if isinstance(Y, str):
  128. Y = symbols("%s:%s" % (Y, n))
  129. elif ok and ok & Tuple(*Y).free_symbols:
  130. ok = False
  131. if not ok:
  132. raise ValueError(filldedent('''
  133. Expecting symbol for x that does not appear in X or Y.
  134. Use `interpolate(list(zip(X, Y)), x)` instead.'''))
  135. coeffs = []
  136. numert = Mul(*[x - X[i] for i in range(n)])
  137. for i in range(n):
  138. numer = numert/(x - X[i])
  139. denom = Mul(*[(X[i] - X[j]) for j in range(n) if i != j])
  140. coeffs.append(numer/denom)
  141. return Add(*[coeff*y for coeff, y in zip(coeffs, Y)])
  142. def fateman_poly_F_1(n):
  143. """Fateman's GCD benchmark: trivial GCD """
  144. Y = [Symbol('y_' + str(i)) for i in range(n + 1)]
  145. y_0, y_1 = Y[0], Y[1]
  146. u = y_0 + Add(*[y for y in Y[1:]])
  147. v = y_0**2 + Add(*[y**2 for y in Y[1:]])
  148. F = ((u + 1)*(u + 2)).as_poly(*Y)
  149. G = ((v + 1)*(-3*y_1*y_0**2 + y_1**2 - 1)).as_poly(*Y)
  150. H = Poly(1, *Y)
  151. return F, G, H
  152. def dmp_fateman_poly_F_1(n, K):
  153. """Fateman's GCD benchmark: trivial GCD """
  154. u = [K(1), K(0)]
  155. for i in range(n):
  156. u = [dmp_one(i, K), u]
  157. v = [K(1), K(0), K(0)]
  158. for i in range(0, n):
  159. v = [dmp_one(i, K), dmp_zero(i), v]
  160. m = n - 1
  161. U = dmp_add_term(u, dmp_ground(K(1), m), 0, n, K)
  162. V = dmp_add_term(u, dmp_ground(K(2), m), 0, n, K)
  163. f = [[-K(3), K(0)], [], [K(1), K(0), -K(1)]]
  164. W = dmp_add_term(v, dmp_ground(K(1), m), 0, n, K)
  165. Y = dmp_raise(f, m, 1, K)
  166. F = dmp_mul(U, V, n, K)
  167. G = dmp_mul(W, Y, n, K)
  168. H = dmp_one(n, K)
  169. return F, G, H
  170. def fateman_poly_F_2(n):
  171. """Fateman's GCD benchmark: linearly dense quartic inputs """
  172. Y = [Symbol('y_' + str(i)) for i in range(n + 1)]
  173. y_0 = Y[0]
  174. u = Add(*[y for y in Y[1:]])
  175. H = Poly((y_0 + u + 1)**2, *Y)
  176. F = Poly((y_0 - u - 2)**2, *Y)
  177. G = Poly((y_0 + u + 2)**2, *Y)
  178. return H*F, H*G, H
  179. def dmp_fateman_poly_F_2(n, K):
  180. """Fateman's GCD benchmark: linearly dense quartic inputs """
  181. u = [K(1), K(0)]
  182. for i in range(n - 1):
  183. u = [dmp_one(i, K), u]
  184. m = n - 1
  185. v = dmp_add_term(u, dmp_ground(K(2), m - 1), 0, n, K)
  186. f = dmp_sqr([dmp_one(m, K), dmp_neg(v, m, K)], n, K)
  187. g = dmp_sqr([dmp_one(m, K), v], n, K)
  188. v = dmp_add_term(u, dmp_one(m - 1, K), 0, n, K)
  189. h = dmp_sqr([dmp_one(m, K), v], n, K)
  190. return dmp_mul(f, h, n, K), dmp_mul(g, h, n, K), h
  191. def fateman_poly_F_3(n):
  192. """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """
  193. Y = [Symbol('y_' + str(i)) for i in range(n + 1)]
  194. y_0 = Y[0]
  195. u = Add(*[y**(n + 1) for y in Y[1:]])
  196. H = Poly((y_0**(n + 1) + u + 1)**2, *Y)
  197. F = Poly((y_0**(n + 1) - u - 2)**2, *Y)
  198. G = Poly((y_0**(n + 1) + u + 2)**2, *Y)
  199. return H*F, H*G, H
  200. def dmp_fateman_poly_F_3(n, K):
  201. """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """
  202. u = dup_from_raw_dict({n + 1: K.one}, K)
  203. for i in range(0, n - 1):
  204. u = dmp_add_term([u], dmp_one(i, K), n + 1, i + 1, K)
  205. v = dmp_add_term(u, dmp_ground(K(2), n - 2), 0, n, K)
  206. f = dmp_sqr(
  207. dmp_add_term([dmp_neg(v, n - 1, K)], dmp_one(n - 1, K), n + 1, n, K), n, K)
  208. g = dmp_sqr(dmp_add_term([v], dmp_one(n - 1, K), n + 1, n, K), n, K)
  209. v = dmp_add_term(u, dmp_one(n - 2, K), 0, n - 1, K)
  210. h = dmp_sqr(dmp_add_term([v], dmp_one(n - 1, K), n + 1, n, K), n, K)
  211. return dmp_mul(f, h, n, K), dmp_mul(g, h, n, K), h
  212. # A few useful polynomials from Wang's paper ('78).
  213. from sympy.polys.rings import ring
  214. def _f_0():
  215. R, x, y, z = ring("x,y,z", ZZ)
  216. return x**2*y*z**2 + 2*x**2*y*z + 3*x**2*y + 2*x**2 + 3*x + 4*y**2*z**2 + 5*y**2*z + 6*y**2 + y*z**2 + 2*y*z + y + 1
  217. def _f_1():
  218. R, x, y, z = ring("x,y,z", ZZ)
  219. return x**3*y*z + x**2*y**2*z**2 + x**2*y**2 + 20*x**2*y*z + 30*x**2*y + x**2*z**2 + 10*x**2*z + x*y**3*z + 30*x*y**2*z + 20*x*y**2 + x*y*z**3 + 10*x*y*z**2 + x*y*z + 610*x*y + 20*x*z**2 + 230*x*z + 300*x + y**2*z**2 + 10*y**2*z + 30*y*z**2 + 320*y*z + 200*y + 600*z + 6000
  220. def _f_2():
  221. R, x, y, z = ring("x,y,z", ZZ)
  222. return x**5*y**3 + x**5*y**2*z + x**5*y*z**2 + x**5*z**3 + x**3*y**2 + x**3*y*z + 90*x**3*y + 90*x**3*z + x**2*y**2*z - 11*x**2*y**2 + x**2*z**3 - 11*x**2*z**2 + y*z - 11*y + 90*z - 990
  223. def _f_3():
  224. R, x, y, z = ring("x,y,z", ZZ)
  225. return x**5*y**2 + x**4*z**4 + x**4 + x**3*y**3*z + x**3*z + x**2*y**4 + x**2*y**3*z**3 + x**2*y*z**5 + x**2*y*z + x*y**2*z**4 + x*y**2 + x*y*z**7 + x*y*z**3 + x*y*z**2 + y**2*z + y*z**4
  226. def _f_4():
  227. R, x, y, z = ring("x,y,z", ZZ)
  228. return -x**9*y**8*z - x**8*y**5*z**3 - x**7*y**12*z**2 - 5*x**7*y**8 - x**6*y**9*z**4 + x**6*y**7*z**3 + 3*x**6*y**7*z - 5*x**6*y**5*z**2 - x**6*y**4*z**3 + x**5*y**4*z**5 + 3*x**5*y**4*z**3 - x**5*y*z**5 + x**4*y**11*z**4 + 3*x**4*y**11*z**2 - x**4*y**8*z**4 + 5*x**4*y**7*z**2 + 15*x**4*y**7 - 5*x**4*y**4*z**2 + x**3*y**8*z**6 + 3*x**3*y**8*z**4 - x**3*y**5*z**6 + 5*x**3*y**4*z**4 + 15*x**3*y**4*z**2 + x**3*y**3*z**5 + 3*x**3*y**3*z**3 - 5*x**3*y*z**4 + x**2*z**7 + 3*x**2*z**5 + x*y**7*z**6 + 3*x*y**7*z**4 + 5*x*y**3*z**4 + 15*x*y**3*z**2 + y**4*z**8 + 3*y**4*z**6 + 5*z**6 + 15*z**4
  229. def _f_5():
  230. R, x, y, z = ring("x,y,z", ZZ)
  231. return -x**3 - 3*x**2*y + 3*x**2*z - 3*x*y**2 + 6*x*y*z - 3*x*z**2 - y**3 + 3*y**2*z - 3*y*z**2 + z**3
  232. def _f_6():
  233. R, x, y, z, t = ring("x,y,z,t", ZZ)
  234. return 2115*x**4*y + 45*x**3*z**3*t**2 - 45*x**3*t**2 - 423*x*y**4 - 47*x*y**3 + 141*x*y*z**3 + 94*x*y*z*t - 9*y**3*z**3*t**2 + 9*y**3*t**2 - y**2*z**3*t**2 + y**2*t**2 + 3*z**6*t**2 + 2*z**4*t**3 - 3*z**3*t**2 - 2*z*t**3
  235. def _w_1():
  236. R, x, y, z = ring("x,y,z", ZZ)
  237. return 4*x**6*y**4*z**2 + 4*x**6*y**3*z**3 - 4*x**6*y**2*z**4 - 4*x**6*y*z**5 + x**5*y**4*z**3 + 12*x**5*y**3*z - x**5*y**2*z**5 + 12*x**5*y**2*z**2 - 12*x**5*y*z**3 - 12*x**5*z**4 + 8*x**4*y**4 + 6*x**4*y**3*z**2 + 8*x**4*y**3*z - 4*x**4*y**2*z**4 + 4*x**4*y**2*z**3 - 8*x**4*y**2*z**2 - 4*x**4*y*z**5 - 2*x**4*y*z**4 - 8*x**4*y*z**3 + 2*x**3*y**4*z + x**3*y**3*z**3 - x**3*y**2*z**5 - 2*x**3*y**2*z**3 + 9*x**3*y**2*z - 12*x**3*y*z**3 + 12*x**3*y*z**2 - 12*x**3*z**4 + 3*x**3*z**3 + 6*x**2*y**3 - 6*x**2*y**2*z**2 + 8*x**2*y**2*z - 2*x**2*y*z**4 - 8*x**2*y*z**3 + 2*x**2*y*z**2 + 2*x*y**3*z - 2*x*y**2*z**3 - 3*x*y*z + 3*x*z**3 - 2*y**2 + 2*y*z**2
  238. def _w_2():
  239. R, x, y = ring("x,y", ZZ)
  240. return 24*x**8*y**3 + 48*x**8*y**2 + 24*x**7*y**5 - 72*x**7*y**2 + 25*x**6*y**4 + 2*x**6*y**3 + 4*x**6*y + 8*x**6 + x**5*y**6 + x**5*y**3 - 12*x**5 + x**4*y**5 - x**4*y**4 - 2*x**4*y**3 + 292*x**4*y**2 - x**3*y**6 + 3*x**3*y**3 - x**2*y**5 + 12*x**2*y**3 + 48*x**2 - 12*y**3
  241. def f_polys():
  242. return _f_0(), _f_1(), _f_2(), _f_3(), _f_4(), _f_5(), _f_6()
  243. def w_polys():
  244. return _w_1(), _w_2()