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

394 lines
11 KiB

  1. """Computations with ideals of polynomial rings."""
  2. from sympy.polys.polyerrors import CoercionFailed
  3. from sympy.polys.polyutils import IntegerPowerable
  4. class Ideal(IntegerPowerable):
  5. """
  6. Abstract base class for ideals.
  7. Do not instantiate - use explicit constructors in the ring class instead:
  8. >>> from sympy import QQ
  9. >>> from sympy.abc import x
  10. >>> QQ.old_poly_ring(x).ideal(x+1)
  11. <x + 1>
  12. Attributes
  13. - ring - the ring this ideal belongs to
  14. Non-implemented methods:
  15. - _contains_elem
  16. - _contains_ideal
  17. - _quotient
  18. - _intersect
  19. - _union
  20. - _product
  21. - is_whole_ring
  22. - is_zero
  23. - is_prime, is_maximal, is_primary, is_radical
  24. - is_principal
  25. - height, depth
  26. - radical
  27. Methods that likely should be overridden in subclasses:
  28. - reduce_element
  29. """
  30. def _contains_elem(self, x):
  31. """Implementation of element containment."""
  32. raise NotImplementedError
  33. def _contains_ideal(self, I):
  34. """Implementation of ideal containment."""
  35. raise NotImplementedError
  36. def _quotient(self, J):
  37. """Implementation of ideal quotient."""
  38. raise NotImplementedError
  39. def _intersect(self, J):
  40. """Implementation of ideal intersection."""
  41. raise NotImplementedError
  42. def is_whole_ring(self):
  43. """Return True if ``self`` is the whole ring."""
  44. raise NotImplementedError
  45. def is_zero(self):
  46. """Return True if ``self`` is the zero ideal."""
  47. raise NotImplementedError
  48. def _equals(self, J):
  49. """Implementation of ideal equality."""
  50. return self._contains_ideal(J) and J._contains_ideal(self)
  51. def is_prime(self):
  52. """Return True if ``self`` is a prime ideal."""
  53. raise NotImplementedError
  54. def is_maximal(self):
  55. """Return True if ``self`` is a maximal ideal."""
  56. raise NotImplementedError
  57. def is_radical(self):
  58. """Return True if ``self`` is a radical ideal."""
  59. raise NotImplementedError
  60. def is_primary(self):
  61. """Return True if ``self`` is a primary ideal."""
  62. raise NotImplementedError
  63. def is_principal(self):
  64. """Return True if ``self`` is a principal ideal."""
  65. raise NotImplementedError
  66. def radical(self):
  67. """Compute the radical of ``self``."""
  68. raise NotImplementedError
  69. def depth(self):
  70. """Compute the depth of ``self``."""
  71. raise NotImplementedError
  72. def height(self):
  73. """Compute the height of ``self``."""
  74. raise NotImplementedError
  75. # TODO more
  76. # non-implemented methods end here
  77. def __init__(self, ring):
  78. self.ring = ring
  79. def _check_ideal(self, J):
  80. """Helper to check ``J`` is an ideal of our ring."""
  81. if not isinstance(J, Ideal) or J.ring != self.ring:
  82. raise ValueError(
  83. 'J must be an ideal of %s, got %s' % (self.ring, J))
  84. def contains(self, elem):
  85. """
  86. Return True if ``elem`` is an element of this ideal.
  87. Examples
  88. ========
  89. >>> from sympy.abc import x
  90. >>> from sympy import QQ
  91. >>> QQ.old_poly_ring(x).ideal(x+1, x-1).contains(3)
  92. True
  93. >>> QQ.old_poly_ring(x).ideal(x**2, x**3).contains(x)
  94. False
  95. """
  96. return self._contains_elem(self.ring.convert(elem))
  97. def subset(self, other):
  98. """
  99. Returns True if ``other`` is is a subset of ``self``.
  100. Here ``other`` may be an ideal.
  101. Examples
  102. ========
  103. >>> from sympy.abc import x
  104. >>> from sympy import QQ
  105. >>> I = QQ.old_poly_ring(x).ideal(x+1)
  106. >>> I.subset([x**2 - 1, x**2 + 2*x + 1])
  107. True
  108. >>> I.subset([x**2 + 1, x + 1])
  109. False
  110. >>> I.subset(QQ.old_poly_ring(x).ideal(x**2 - 1))
  111. True
  112. """
  113. if isinstance(other, Ideal):
  114. return self._contains_ideal(other)
  115. return all(self._contains_elem(x) for x in other)
  116. def quotient(self, J, **opts):
  117. r"""
  118. Compute the ideal quotient of ``self`` by ``J``.
  119. That is, if ``self`` is the ideal `I`, compute the set
  120. `I : J = \{x \in R | xJ \subset I \}`.
  121. Examples
  122. ========
  123. >>> from sympy.abc import x, y
  124. >>> from sympy import QQ
  125. >>> R = QQ.old_poly_ring(x, y)
  126. >>> R.ideal(x*y).quotient(R.ideal(x))
  127. <y>
  128. """
  129. self._check_ideal(J)
  130. return self._quotient(J, **opts)
  131. def intersect(self, J):
  132. """
  133. Compute the intersection of self with ideal J.
  134. Examples
  135. ========
  136. >>> from sympy.abc import x, y
  137. >>> from sympy import QQ
  138. >>> R = QQ.old_poly_ring(x, y)
  139. >>> R.ideal(x).intersect(R.ideal(y))
  140. <x*y>
  141. """
  142. self._check_ideal(J)
  143. return self._intersect(J)
  144. def saturate(self, J):
  145. r"""
  146. Compute the ideal saturation of ``self`` by ``J``.
  147. That is, if ``self`` is the ideal `I`, compute the set
  148. `I : J^\infty = \{x \in R | xJ^n \subset I \text{ for some } n\}`.
  149. """
  150. raise NotImplementedError
  151. # Note this can be implemented using repeated quotient
  152. def union(self, J):
  153. """
  154. Compute the ideal generated by the union of ``self`` and ``J``.
  155. Examples
  156. ========
  157. >>> from sympy.abc import x
  158. >>> from sympy import QQ
  159. >>> QQ.old_poly_ring(x).ideal(x**2 - 1).union(QQ.old_poly_ring(x).ideal((x+1)**2)) == QQ.old_poly_ring(x).ideal(x+1)
  160. True
  161. """
  162. self._check_ideal(J)
  163. return self._union(J)
  164. def product(self, J):
  165. r"""
  166. Compute the ideal product of ``self`` and ``J``.
  167. That is, compute the ideal generated by products `xy`, for `x` an element
  168. of ``self`` and `y \in J`.
  169. Examples
  170. ========
  171. >>> from sympy.abc import x, y
  172. >>> from sympy import QQ
  173. >>> QQ.old_poly_ring(x, y).ideal(x).product(QQ.old_poly_ring(x, y).ideal(y))
  174. <x*y>
  175. """
  176. self._check_ideal(J)
  177. return self._product(J)
  178. def reduce_element(self, x):
  179. """
  180. Reduce the element ``x`` of our ring modulo the ideal ``self``.
  181. Here "reduce" has no specific meaning: it could return a unique normal
  182. form, simplify the expression a bit, or just do nothing.
  183. """
  184. return x
  185. def __add__(self, e):
  186. if not isinstance(e, Ideal):
  187. R = self.ring.quotient_ring(self)
  188. if isinstance(e, R.dtype):
  189. return e
  190. if isinstance(e, R.ring.dtype):
  191. return R(e)
  192. return R.convert(e)
  193. self._check_ideal(e)
  194. return self.union(e)
  195. __radd__ = __add__
  196. def __mul__(self, e):
  197. if not isinstance(e, Ideal):
  198. try:
  199. e = self.ring.ideal(e)
  200. except CoercionFailed:
  201. return NotImplemented
  202. self._check_ideal(e)
  203. return self.product(e)
  204. __rmul__ = __mul__
  205. def _zeroth_power(self):
  206. return self.ring.ideal(1)
  207. def _first_power(self):
  208. # Raising to any power but 1 returns a new instance. So we mult by 1
  209. # here so that the first power is no exception.
  210. return self * 1
  211. def __eq__(self, e):
  212. if not isinstance(e, Ideal) or e.ring != self.ring:
  213. return False
  214. return self._equals(e)
  215. def __ne__(self, e):
  216. return not (self == e)
  217. class ModuleImplementedIdeal(Ideal):
  218. """
  219. Ideal implementation relying on the modules code.
  220. Attributes:
  221. - _module - the underlying module
  222. """
  223. def __init__(self, ring, module):
  224. Ideal.__init__(self, ring)
  225. self._module = module
  226. def _contains_elem(self, x):
  227. return self._module.contains([x])
  228. def _contains_ideal(self, J):
  229. if not isinstance(J, ModuleImplementedIdeal):
  230. raise NotImplementedError
  231. return self._module.is_submodule(J._module)
  232. def _intersect(self, J):
  233. if not isinstance(J, ModuleImplementedIdeal):
  234. raise NotImplementedError
  235. return self.__class__(self.ring, self._module.intersect(J._module))
  236. def _quotient(self, J, **opts):
  237. if not isinstance(J, ModuleImplementedIdeal):
  238. raise NotImplementedError
  239. return self._module.module_quotient(J._module, **opts)
  240. def _union(self, J):
  241. if not isinstance(J, ModuleImplementedIdeal):
  242. raise NotImplementedError
  243. return self.__class__(self.ring, self._module.union(J._module))
  244. @property
  245. def gens(self):
  246. """
  247. Return generators for ``self``.
  248. Examples
  249. ========
  250. >>> from sympy import QQ
  251. >>> from sympy.abc import x, y
  252. >>> list(QQ.old_poly_ring(x, y).ideal(x, y, x**2 + y).gens)
  253. [x, y, x**2 + y]
  254. """
  255. return (x[0] for x in self._module.gens)
  256. def is_zero(self):
  257. """
  258. Return True if ``self`` is the zero ideal.
  259. Examples
  260. ========
  261. >>> from sympy.abc import x
  262. >>> from sympy import QQ
  263. >>> QQ.old_poly_ring(x).ideal(x).is_zero()
  264. False
  265. >>> QQ.old_poly_ring(x).ideal().is_zero()
  266. True
  267. """
  268. return self._module.is_zero()
  269. def is_whole_ring(self):
  270. """
  271. Return True if ``self`` is the whole ring, i.e. one generator is a unit.
  272. Examples
  273. ========
  274. >>> from sympy.abc import x
  275. >>> from sympy import QQ, ilex
  276. >>> QQ.old_poly_ring(x).ideal(x).is_whole_ring()
  277. False
  278. >>> QQ.old_poly_ring(x).ideal(3).is_whole_ring()
  279. True
  280. >>> QQ.old_poly_ring(x, order=ilex).ideal(2 + x).is_whole_ring()
  281. True
  282. """
  283. return self._module.is_full_module()
  284. def __repr__(self):
  285. from sympy.printing.str import sstr
  286. return '<' + ','.join(sstr(x) for [x] in self._module.gens) + '>'
  287. # NOTE this is the only method using the fact that the module is a SubModule
  288. def _product(self, J):
  289. if not isinstance(J, ModuleImplementedIdeal):
  290. raise NotImplementedError
  291. return self.__class__(self.ring, self._module.submodule(
  292. *[[x*y] for [x] in self._module.gens for [y] in J._module.gens]))
  293. def in_terms_of_generators(self, e):
  294. """
  295. Express ``e`` in terms of the generators of ``self``.
  296. Examples
  297. ========
  298. >>> from sympy.abc import x
  299. >>> from sympy import QQ
  300. >>> I = QQ.old_poly_ring(x).ideal(x**2 + 1, x)
  301. >>> I.in_terms_of_generators(1)
  302. [1, -x]
  303. """
  304. return self._module.in_terms_of_generators([e])
  305. def reduce_element(self, x, **options):
  306. return self._module.reduce_element([x], **options)[0]