图片解析应用
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.

269 lines
9.0 KiB

  1. from sympy import QQ, ZZ, S
  2. from sympy.abc import x, theta
  3. from sympy.core.mul import prod
  4. from sympy.ntheory import factorint
  5. from sympy.ntheory.residue_ntheory import n_order
  6. from sympy.polys import Poly, cyclotomic_poly
  7. from sympy.polys.matrices import DomainMatrix
  8. from sympy.polys.numberfields.basis import round_two
  9. from sympy.polys.numberfields.exceptions import StructureError
  10. from sympy.polys.numberfields.modules import PowerBasis
  11. from sympy.polys.numberfields.primes import (
  12. prime_decomp, _two_elt_rep,
  13. _check_formal_conditions_for_maximal_order,
  14. )
  15. from sympy.polys.polyerrors import GeneratorsNeeded
  16. from sympy.testing.pytest import raises
  17. def test_check_formal_conditions_for_maximal_order():
  18. T = Poly(cyclotomic_poly(5, x))
  19. A = PowerBasis(T)
  20. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  21. C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  22. D = A.submodule_from_matrix(DomainMatrix.eye(4, ZZ)[:, :-1])
  23. # Is a direct submodule of a power basis, but lacks 1 as first generator:
  24. raises(StructureError, lambda: _check_formal_conditions_for_maximal_order(B))
  25. # Is not a direct submodule of a power basis:
  26. raises(StructureError, lambda: _check_formal_conditions_for_maximal_order(C))
  27. # Is direct submod of pow basis, and starts with 1, but not sq/max rank/HNF:
  28. raises(StructureError, lambda: _check_formal_conditions_for_maximal_order(D))
  29. def test_two_elt_rep():
  30. ell = 7
  31. T = Poly(cyclotomic_poly(ell))
  32. ZK, dK = round_two(T)
  33. for p in [29, 13, 11, 5]:
  34. P = prime_decomp(p, T)
  35. for Pi in P:
  36. # We have Pi in two-element representation, and, because we are
  37. # looking at a cyclotomic field, this was computed by the "easy"
  38. # method that just factors T mod p. We will now convert this to
  39. # a set of Z-generators, then convert that back into a two-element
  40. # rep. The latter need not be identical to the two-elt rep we
  41. # already have, but it must have the same HNF.
  42. H = p*ZK + Pi.alpha*ZK
  43. gens = H.basis_element_pullbacks()
  44. # Note: we could supply f = Pi.f, but prefer to test behavior without it.
  45. b = _two_elt_rep(gens, ZK, p)
  46. if b != Pi.alpha:
  47. H2 = p*ZK + b*ZK
  48. assert H2 == H
  49. def test_valuation_at_prime_ideal():
  50. p = 7
  51. T = Poly(cyclotomic_poly(p))
  52. ZK, dK = round_two(T)
  53. P = prime_decomp(p, T, dK=dK, ZK=ZK)
  54. assert len(P) == 1
  55. P0 = P[0]
  56. v = P0.valuation(p*ZK)
  57. assert v == P0.e
  58. # Test easy 0 case:
  59. assert P0.valuation(5*ZK) == 0
  60. def test_decomp_1():
  61. # All prime decompositions in cyclotomic fields are in the "easy case,"
  62. # since the index is unity.
  63. # Here we check the ramified prime.
  64. T = Poly(cyclotomic_poly(7))
  65. raises(ValueError, lambda: prime_decomp(7))
  66. P = prime_decomp(7, T)
  67. assert len(P) == 1
  68. P0 = P[0]
  69. assert P0.e == 6
  70. assert P0.f == 1
  71. # Test powers:
  72. assert P0**0 == P0.ZK
  73. assert P0**1 == P0
  74. assert P0**6 == 7 * P0.ZK
  75. def test_decomp_2():
  76. # More easy cyclotomic cases, but here we check unramified primes.
  77. ell = 7
  78. T = Poly(cyclotomic_poly(ell))
  79. for p in [29, 13, 11, 5]:
  80. f_exp = n_order(p, ell)
  81. g_exp = (ell - 1) // f_exp
  82. P = prime_decomp(p, T)
  83. assert len(P) == g_exp
  84. for Pi in P:
  85. assert Pi.e == 1
  86. assert Pi.f == f_exp
  87. def test_decomp_3():
  88. T = Poly(x ** 2 - 35)
  89. rad = {}
  90. ZK, dK = round_two(T, radicals=rad)
  91. # 35 is 3 mod 4, so field disc is 4*5*7, and theory says each of the
  92. # rational primes 2, 5, 7 should be the square of a prime ideal.
  93. for p in [2, 5, 7]:
  94. P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=rad.get(p))
  95. assert len(P) == 1
  96. assert P[0].e == 2
  97. assert P[0]**2 == p*ZK
  98. def test_decomp_4():
  99. T = Poly(x ** 2 - 21)
  100. rad = {}
  101. ZK, dK = round_two(T, radicals=rad)
  102. # 21 is 1 mod 4, so field disc is 3*7, and theory says the
  103. # rational primes 3, 7 should be the square of a prime ideal.
  104. for p in [3, 7]:
  105. P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=rad.get(p))
  106. assert len(P) == 1
  107. assert P[0].e == 2
  108. assert P[0]**2 == p*ZK
  109. def test_decomp_5():
  110. # Here is our first test of the "hard case" of prime decomposition.
  111. # We work in a quadratic extension Q(sqrt(d)) where d is 1 mod 4, and
  112. # we consider the factorization of the rational prime 2, which divides
  113. # the index.
  114. # Theory says the form of p's factorization depends on the residue of
  115. # d mod 8, so we consider both cases, d = 1 mod 8 and d = 5 mod 8.
  116. for d in [-7, -3]:
  117. T = Poly(x ** 2 - d)
  118. rad = {}
  119. ZK, dK = round_two(T, radicals=rad)
  120. p = 2
  121. P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=rad.get(p))
  122. if d % 8 == 1:
  123. assert len(P) == 2
  124. assert all(P[i].e == 1 and P[i].f == 1 for i in range(2))
  125. assert prod(Pi**Pi.e for Pi in P) == p * ZK
  126. else:
  127. assert d % 8 == 5
  128. assert len(P) == 1
  129. assert P[0].e == 1
  130. assert P[0].f == 2
  131. assert P[0].as_submodule() == p * ZK
  132. def test_decomp_6():
  133. # Another case where 2 divides the index. This is Dedekind's example of
  134. # an essential discriminant divisor. (See Cohen, Excercise 6.10.)
  135. T = Poly(x ** 3 + x ** 2 - 2 * x + 8)
  136. rad = {}
  137. ZK, dK = round_two(T, radicals=rad)
  138. p = 2
  139. P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=rad.get(p))
  140. assert len(P) == 3
  141. assert all(Pi.e == Pi.f == 1 for Pi in P)
  142. assert prod(Pi**Pi.e for Pi in P) == p*ZK
  143. def test_decomp_7():
  144. # Try working through an AlgebraicField
  145. T = Poly(x ** 3 + x ** 2 - 2 * x + 8)
  146. K = QQ.algebraic_field((T, theta))
  147. p = 2
  148. P = K.primes_above(p)
  149. ZK = K.maximal_order()
  150. assert len(P) == 3
  151. assert all(Pi.e == Pi.f == 1 for Pi in P)
  152. assert prod(Pi**Pi.e for Pi in P) == p*ZK
  153. def test_decomp_8():
  154. # This time we consider various cubics, and try factoring all primes
  155. # dividing the index.
  156. cases = (
  157. x ** 3 + 3 * x ** 2 - 4 * x + 4,
  158. x ** 3 + 3 * x ** 2 + 3 * x - 3,
  159. x ** 3 + 5 * x ** 2 - x + 3,
  160. x ** 3 + 5 * x ** 2 - 5 * x - 5,
  161. x ** 3 + 3 * x ** 2 + 5,
  162. x ** 3 + 6 * x ** 2 + 3 * x - 1,
  163. x ** 3 + 6 * x ** 2 + 4,
  164. x ** 3 + 7 * x ** 2 + 7 * x - 7,
  165. x ** 3 + 7 * x ** 2 - x + 5,
  166. x ** 3 + 7 * x ** 2 - 5 * x + 5,
  167. x ** 3 + 4 * x ** 2 - 3 * x + 7,
  168. x ** 3 + 8 * x ** 2 + 5 * x - 1,
  169. x ** 3 + 8 * x ** 2 - 2 * x + 6,
  170. x ** 3 + 6 * x ** 2 - 3 * x + 8,
  171. x ** 3 + 9 * x ** 2 + 6 * x - 8,
  172. x ** 3 + 15 * x ** 2 - 9 * x + 13,
  173. )
  174. '''
  175. def display(T, p, radical, P, I, J):
  176. """Useful for inspection, when running test manually."""
  177. print('=' * 20)
  178. print(T, p, radical)
  179. for Pi in P:
  180. print(f' ({Pi.pretty()})')
  181. print("I: ", I)
  182. print("J: ", J)
  183. print(f'Equal: {I == J}')
  184. '''
  185. for g in cases:
  186. T = Poly(g)
  187. rad = {}
  188. ZK, dK = round_two(T, radicals=rad)
  189. dT = T.discriminant()
  190. f_squared = dT // dK
  191. F = factorint(f_squared)
  192. for p in F:
  193. radical = rad.get(p)
  194. P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=radical)
  195. I = prod(Pi**Pi.e for Pi in P)
  196. J = p * ZK
  197. #display(T, p, radical, P, I, J)
  198. assert I == J
  199. def test_PrimeIdeal_eq():
  200. # `==` should fail on objects of different types, so even a completely
  201. # inert PrimeIdeal should test unequal to the rational prime it divides.
  202. T = Poly(cyclotomic_poly(7))
  203. P0 = prime_decomp(5, T)[0]
  204. assert P0.f == 6
  205. assert P0.as_submodule() == 5 * P0.ZK
  206. assert P0 != 5
  207. def test_PrimeIdeal_add():
  208. T = Poly(cyclotomic_poly(7))
  209. P0 = prime_decomp(7, T)[0]
  210. # Adding ideals computes their GCD, so adding the ramified prime dividing
  211. # 7 to 7 itself should reproduce this prime (as a submodule).
  212. assert P0 + 7 * P0.ZK == P0.as_submodule()
  213. def test_pretty_printing():
  214. d = -7
  215. T = Poly(x ** 2 - d)
  216. rad = {}
  217. ZK, dK = round_two(T, radicals=rad)
  218. p = 2
  219. P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=rad.get(p))
  220. assert repr(P[0]) == '[ (2, (3*x + 1)/2) e=1, f=1 ]'
  221. assert P[0]._pretty(field_gen=theta) == '[ (2, (3*theta + 1)/2) e=1, f=1 ]'
  222. assert P[0]._pretty(field_gen=theta, just_gens=True) == '(2, (3*theta + 1)/2)'
  223. def test_PrimeIdeal_reduce_poly():
  224. T = Poly(cyclotomic_poly(7, x))
  225. k = QQ.algebraic_field((T, x))
  226. P = k.primes_above(11)
  227. frp = P[0]
  228. B = k.integral_basis(fmt='sympy')
  229. assert [frp._reduce_poly(b, x) for b in B] == [
  230. 1, x, x ** 2, -5 * x ** 2 - 4 * x + 1, -x ** 2 - x - 5,
  231. 4 * x ** 2 - x - 1]
  232. Q = k.primes_above(19)
  233. frq = Q[0]
  234. assert frq.alpha.equiv(0)
  235. assert frq._reduce_poly(20 * x ** 2 + 10) == x ** 2 - 9
  236. raises(GeneratorsNeeded, lambda: frp._reduce_poly(S(1)))
  237. raises(NotImplementedError, lambda: frp._reduce_poly(1))