passagemath-objects 10.8.1a3__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. passagemath_objects/__init__.py +3 -0
  2. passagemath_objects-10.8.1a3.dist-info/DELVEWHEEL +2 -0
  3. passagemath_objects-10.8.1a3.dist-info/METADATA +114 -0
  4. passagemath_objects-10.8.1a3.dist-info/RECORD +283 -0
  5. passagemath_objects-10.8.1a3.dist-info/WHEEL +5 -0
  6. passagemath_objects-10.8.1a3.dist-info/top_level.txt +3 -0
  7. passagemath_objects.libs/libgmp-10-60021eeab4282b29024e43b2b1412b53.dll +0 -0
  8. sage/all__sagemath_objects.py +46 -0
  9. sage/arith/all__sagemath_objects.py +5 -0
  10. sage/arith/long.pxd +411 -0
  11. sage/arith/numerical_approx.cp314-win_amd64.pyd +0 -0
  12. sage/arith/numerical_approx.pxd +35 -0
  13. sage/arith/numerical_approx.pyx +75 -0
  14. sage/arith/power.cp314-win_amd64.pyd +0 -0
  15. sage/arith/power.pxd +31 -0
  16. sage/arith/power.pyx +127 -0
  17. sage/categories/action.cp314-win_amd64.pyd +0 -0
  18. sage/categories/action.pxd +29 -0
  19. sage/categories/action.pyx +641 -0
  20. sage/categories/algebra_functor.py +745 -0
  21. sage/categories/all__sagemath_objects.py +33 -0
  22. sage/categories/basic.py +71 -0
  23. sage/categories/cartesian_product.py +292 -0
  24. sage/categories/category.py +3379 -0
  25. sage/categories/category_cy_helper.cp314-win_amd64.pyd +0 -0
  26. sage/categories/category_cy_helper.pxd +8 -0
  27. sage/categories/category_cy_helper.pyx +322 -0
  28. sage/categories/category_singleton.cp314-win_amd64.pyd +0 -0
  29. sage/categories/category_singleton.pxd +3 -0
  30. sage/categories/category_singleton.pyx +343 -0
  31. sage/categories/category_types.py +637 -0
  32. sage/categories/category_with_axiom.py +2889 -0
  33. sage/categories/covariant_functorial_construction.py +700 -0
  34. sage/categories/facade_sets.py +228 -0
  35. sage/categories/functor.cp314-win_amd64.pyd +0 -0
  36. sage/categories/functor.pxd +7 -0
  37. sage/categories/functor.pyx +659 -0
  38. sage/categories/homset.py +1289 -0
  39. sage/categories/homsets.py +364 -0
  40. sage/categories/isomorphic_objects.py +73 -0
  41. sage/categories/map.cp314-win_amd64.pyd +0 -0
  42. sage/categories/map.pxd +34 -0
  43. sage/categories/map.pyx +2106 -0
  44. sage/categories/morphism.cp314-win_amd64.pyd +0 -0
  45. sage/categories/morphism.pxd +14 -0
  46. sage/categories/morphism.pyx +895 -0
  47. sage/categories/objects.py +167 -0
  48. sage/categories/primer.py +1695 -0
  49. sage/categories/pushout.py +4847 -0
  50. sage/categories/quotients.py +64 -0
  51. sage/categories/realizations.py +200 -0
  52. sage/categories/sets_cat.py +3305 -0
  53. sage/categories/sets_with_partial_maps.py +52 -0
  54. sage/categories/subobjects.py +64 -0
  55. sage/categories/subquotients.py +21 -0
  56. sage/categories/with_realizations.py +311 -0
  57. sage/cpython/__init__.py +22 -0
  58. sage/cpython/_py2_random.py +619 -0
  59. sage/cpython/all.py +3 -0
  60. sage/cpython/atexit.cp314-win_amd64.pyd +0 -0
  61. sage/cpython/atexit.pyx +269 -0
  62. sage/cpython/builtin_types.cp314-win_amd64.pyd +0 -0
  63. sage/cpython/builtin_types.pyx +7 -0
  64. sage/cpython/cython_metaclass.cp314-win_amd64.pyd +0 -0
  65. sage/cpython/cython_metaclass.h +117 -0
  66. sage/cpython/cython_metaclass.pxd +3 -0
  67. sage/cpython/cython_metaclass.pyx +130 -0
  68. sage/cpython/debug.cp314-win_amd64.pyd +0 -0
  69. sage/cpython/debug.pyx +302 -0
  70. sage/cpython/dict_del_by_value.cp314-win_amd64.pyd +0 -0
  71. sage/cpython/dict_del_by_value.pxd +9 -0
  72. sage/cpython/dict_del_by_value.pyx +191 -0
  73. sage/cpython/dict_internal.h +80 -0
  74. sage/cpython/getattr.cp314-win_amd64.pyd +0 -0
  75. sage/cpython/getattr.pxd +9 -0
  76. sage/cpython/getattr.pyx +439 -0
  77. sage/cpython/pycore_long.h +97 -0
  78. sage/cpython/pycore_long.pxd +10 -0
  79. sage/cpython/python_debug.h +44 -0
  80. sage/cpython/python_debug.pxd +47 -0
  81. sage/cpython/pyx_visit.h +13 -0
  82. sage/cpython/string.cp314-win_amd64.pyd +0 -0
  83. sage/cpython/string.pxd +76 -0
  84. sage/cpython/string.pyx +34 -0
  85. sage/cpython/string_impl.h +60 -0
  86. sage/cpython/type.cp314-win_amd64.pyd +0 -0
  87. sage/cpython/type.pxd +2 -0
  88. sage/cpython/type.pyx +40 -0
  89. sage/cpython/wrapperdescr.pxd +67 -0
  90. sage/ext/all__sagemath_objects.py +3 -0
  91. sage/ext/ccobject.h +64 -0
  92. sage/ext/cplusplus.pxd +17 -0
  93. sage/ext/mod_int.h +30 -0
  94. sage/ext/mod_int.pxd +24 -0
  95. sage/ext/stdsage.pxd +39 -0
  96. sage/groups/all__sagemath_objects.py +1 -0
  97. sage/groups/group.cp314-win_amd64.pyd +0 -0
  98. sage/groups/group.pxd +14 -0
  99. sage/groups/group.pyx +296 -0
  100. sage/groups/old.cp314-win_amd64.pyd +0 -0
  101. sage/groups/old.pxd +14 -0
  102. sage/groups/old.pyx +219 -0
  103. sage/libs/all__sagemath_objects.py +3 -0
  104. sage/libs/gmp/__init__.py +1 -0
  105. sage/libs/gmp/all.pxd +6 -0
  106. sage/libs/gmp/binop.pxd +23 -0
  107. sage/libs/gmp/misc.pxd +8 -0
  108. sage/libs/gmp/mpf.pxd +88 -0
  109. sage/libs/gmp/mpn.pxd +57 -0
  110. sage/libs/gmp/mpq.pxd +57 -0
  111. sage/libs/gmp/mpz.pxd +202 -0
  112. sage/libs/gmp/pylong.cp314-win_amd64.pyd +0 -0
  113. sage/libs/gmp/pylong.pxd +12 -0
  114. sage/libs/gmp/pylong.pyx +150 -0
  115. sage/libs/gmp/random.pxd +25 -0
  116. sage/libs/gmp/randomize.pxd +59 -0
  117. sage/libs/gmp/types.pxd +53 -0
  118. sage/libs/gmpxx.pxd +19 -0
  119. sage/misc/abstract_method.py +276 -0
  120. sage/misc/all__sagemath_objects.py +43 -0
  121. sage/misc/bindable_class.py +253 -0
  122. sage/misc/c3_controlled.cp314-win_amd64.pyd +0 -0
  123. sage/misc/c3_controlled.pxd +2 -0
  124. sage/misc/c3_controlled.pyx +1402 -0
  125. sage/misc/cachefunc.cp314-win_amd64.pyd +0 -0
  126. sage/misc/cachefunc.pxd +43 -0
  127. sage/misc/cachefunc.pyx +3801 -0
  128. sage/misc/call.py +188 -0
  129. sage/misc/classcall_metaclass.cp314-win_amd64.pyd +0 -0
  130. sage/misc/classcall_metaclass.pxd +14 -0
  131. sage/misc/classcall_metaclass.pyx +599 -0
  132. sage/misc/constant_function.cp314-win_amd64.pyd +0 -0
  133. sage/misc/constant_function.pyx +130 -0
  134. sage/misc/decorators.py +739 -0
  135. sage/misc/fast_methods.cp314-win_amd64.pyd +0 -0
  136. sage/misc/fast_methods.pxd +20 -0
  137. sage/misc/fast_methods.pyx +351 -0
  138. sage/misc/flatten.py +90 -0
  139. sage/misc/fpickle.cp314-win_amd64.pyd +0 -0
  140. sage/misc/fpickle.pyx +176 -0
  141. sage/misc/function_mangling.cp314-win_amd64.pyd +0 -0
  142. sage/misc/function_mangling.pxd +11 -0
  143. sage/misc/function_mangling.pyx +308 -0
  144. sage/misc/inherit_comparison.cp314-win_amd64.pyd +0 -0
  145. sage/misc/inherit_comparison.pxd +5 -0
  146. sage/misc/inherit_comparison.pyx +105 -0
  147. sage/misc/instancedoc.cp314-win_amd64.pyd +0 -0
  148. sage/misc/instancedoc.pyx +331 -0
  149. sage/misc/lazy_attribute.cp314-win_amd64.pyd +0 -0
  150. sage/misc/lazy_attribute.pyx +607 -0
  151. sage/misc/lazy_format.py +132 -0
  152. sage/misc/lazy_import.cp314-win_amd64.pyd +0 -0
  153. sage/misc/lazy_import.pxd +13 -0
  154. sage/misc/lazy_import.pyx +1307 -0
  155. sage/misc/lazy_import_cache.py +36 -0
  156. sage/misc/lazy_list.cp314-win_amd64.pyd +0 -0
  157. sage/misc/lazy_list.pxd +19 -0
  158. sage/misc/lazy_list.pyx +1187 -0
  159. sage/misc/lazy_string.cp314-win_amd64.pyd +0 -0
  160. sage/misc/lazy_string.pxd +7 -0
  161. sage/misc/lazy_string.pyx +546 -0
  162. sage/misc/misc.py +980 -0
  163. sage/misc/misc_c.cp314-win_amd64.pyd +0 -0
  164. sage/misc/misc_c.pxd +3 -0
  165. sage/misc/misc_c.pyx +765 -0
  166. sage/misc/namespace_package.py +37 -0
  167. sage/misc/nested_class.cp314-win_amd64.pyd +0 -0
  168. sage/misc/nested_class.pxd +3 -0
  169. sage/misc/nested_class.pyx +394 -0
  170. sage/misc/persist.cp314-win_amd64.pyd +0 -0
  171. sage/misc/persist.pyx +1279 -0
  172. sage/misc/prandom.py +418 -0
  173. sage/misc/randstate.cp314-win_amd64.pyd +0 -0
  174. sage/misc/randstate.pxd +31 -0
  175. sage/misc/randstate.pyx +1096 -0
  176. sage/misc/repr.py +203 -0
  177. sage/misc/reset.cp314-win_amd64.pyd +0 -0
  178. sage/misc/reset.pyx +196 -0
  179. sage/misc/sage_ostools.cp314-win_amd64.pyd +0 -0
  180. sage/misc/sage_ostools.pyx +323 -0
  181. sage/misc/sage_timeit.py +275 -0
  182. sage/misc/sage_timeit_class.cp314-win_amd64.pyd +0 -0
  183. sage/misc/sage_timeit_class.pyx +120 -0
  184. sage/misc/sage_unittest.py +639 -0
  185. sage/misc/sageinspect.py +2792 -0
  186. sage/misc/session.cp314-win_amd64.pyd +0 -0
  187. sage/misc/session.pyx +392 -0
  188. sage/misc/superseded.py +576 -0
  189. sage/misc/test_nested_class.py +228 -0
  190. sage/misc/timing.py +264 -0
  191. sage/misc/unknown.py +222 -0
  192. sage/misc/verbose.py +253 -0
  193. sage/misc/weak_dict.cp314-win_amd64.pyd +0 -0
  194. sage/misc/weak_dict.pxd +15 -0
  195. sage/misc/weak_dict.pyx +1197 -0
  196. sage/modules/all__sagemath_objects.py +1 -0
  197. sage/modules/module.cp314-win_amd64.pyd +0 -0
  198. sage/modules/module.pxd +5 -0
  199. sage/modules/module.pyx +329 -0
  200. sage/rings/all__sagemath_objects.py +3 -0
  201. sage/rings/integer_fake.h +22 -0
  202. sage/rings/integer_fake.pxd +55 -0
  203. sage/rings/integer_fake.pyi +8 -0
  204. sage/sets/all__sagemath_objects.py +3 -0
  205. sage/sets/pythonclass.cp314-win_amd64.pyd +0 -0
  206. sage/sets/pythonclass.pxd +9 -0
  207. sage/sets/pythonclass.pyx +247 -0
  208. sage/structure/__init__.py +13 -0
  209. sage/structure/all.py +30 -0
  210. sage/structure/category_object.cp314-win_amd64.pyd +0 -0
  211. sage/structure/category_object.pxd +28 -0
  212. sage/structure/category_object.pyx +1090 -0
  213. sage/structure/coerce.cp314-win_amd64.pyd +0 -0
  214. sage/structure/coerce.pxd +44 -0
  215. sage/structure/coerce.pyx +2113 -0
  216. sage/structure/coerce_actions.cp314-win_amd64.pyd +0 -0
  217. sage/structure/coerce_actions.pxd +27 -0
  218. sage/structure/coerce_actions.pyx +988 -0
  219. sage/structure/coerce_dict.cp314-win_amd64.pyd +0 -0
  220. sage/structure/coerce_dict.pxd +51 -0
  221. sage/structure/coerce_dict.pyx +1557 -0
  222. sage/structure/coerce_exceptions.py +23 -0
  223. sage/structure/coerce_maps.cp314-win_amd64.pyd +0 -0
  224. sage/structure/coerce_maps.pxd +24 -0
  225. sage/structure/coerce_maps.pyx +656 -0
  226. sage/structure/debug_options.cp314-win_amd64.pyd +0 -0
  227. sage/structure/debug_options.pxd +6 -0
  228. sage/structure/debug_options.pyx +54 -0
  229. sage/structure/dynamic_class.py +541 -0
  230. sage/structure/element.cp314-win_amd64.pyd +0 -0
  231. sage/structure/element.pxd +271 -0
  232. sage/structure/element.pyx +4584 -0
  233. sage/structure/element_wrapper.cp314-win_amd64.pyd +0 -0
  234. sage/structure/element_wrapper.pxd +12 -0
  235. sage/structure/element_wrapper.pyx +582 -0
  236. sage/structure/factorization.py +1457 -0
  237. sage/structure/factorization_integer.py +154 -0
  238. sage/structure/factory.cp314-win_amd64.pyd +0 -0
  239. sage/structure/factory.pyx +863 -0
  240. sage/structure/formal_sum.py +489 -0
  241. sage/structure/gens_py.py +73 -0
  242. sage/structure/global_options.py +1725 -0
  243. sage/structure/indexed_generators.py +863 -0
  244. sage/structure/list_clone.cp314-win_amd64.pyd +0 -0
  245. sage/structure/list_clone.pxd +65 -0
  246. sage/structure/list_clone.pyx +1867 -0
  247. sage/structure/list_clone_demo.cp314-win_amd64.pyd +0 -0
  248. sage/structure/list_clone_demo.pyx +248 -0
  249. sage/structure/list_clone_timings.py +179 -0
  250. sage/structure/list_clone_timings_cy.cp314-win_amd64.pyd +0 -0
  251. sage/structure/list_clone_timings_cy.pyx +86 -0
  252. sage/structure/mutability.cp314-win_amd64.pyd +0 -0
  253. sage/structure/mutability.pxd +21 -0
  254. sage/structure/mutability.pyx +346 -0
  255. sage/structure/nonexact.py +69 -0
  256. sage/structure/parent.cp314-win_amd64.pyd +0 -0
  257. sage/structure/parent.pxd +112 -0
  258. sage/structure/parent.pyx +3087 -0
  259. sage/structure/parent_base.cp314-win_amd64.pyd +0 -0
  260. sage/structure/parent_base.pxd +13 -0
  261. sage/structure/parent_base.pyx +35 -0
  262. sage/structure/parent_gens.cp314-win_amd64.pyd +0 -0
  263. sage/structure/parent_gens.pxd +22 -0
  264. sage/structure/parent_gens.pyx +374 -0
  265. sage/structure/parent_old.cp314-win_amd64.pyd +0 -0
  266. sage/structure/parent_old.pxd +24 -0
  267. sage/structure/parent_old.pyx +278 -0
  268. sage/structure/proof/__init__.py +1 -0
  269. sage/structure/proof/all.py +243 -0
  270. sage/structure/proof/proof.py +300 -0
  271. sage/structure/richcmp.cp314-win_amd64.pyd +0 -0
  272. sage/structure/richcmp.pxd +212 -0
  273. sage/structure/richcmp.pyx +494 -0
  274. sage/structure/sage_object.cp314-win_amd64.pyd +0 -0
  275. sage/structure/sage_object.pxd +3 -0
  276. sage/structure/sage_object.pyx +1088 -0
  277. sage/structure/sage_object_test.py +19 -0
  278. sage/structure/sequence.py +937 -0
  279. sage/structure/set_factories.py +1178 -0
  280. sage/structure/set_factories_example.py +527 -0
  281. sage/structure/support_view.py +164 -0
  282. sage/structure/test_factory.py +56 -0
  283. sage/structure/unique_representation.py +1443 -0
@@ -0,0 +1,1457 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ r"""
3
+ Factorizations
4
+
5
+ The :class:`Factorization` class provides a structure for holding quite
6
+ general lists of objects with integer multiplicities. These may hold
7
+ the results of an arithmetic or algebraic factorization, where the
8
+ objects may be primes or irreducible polynomials and the
9
+ multiplicities are the (nonzero) exponents in the factorization. For
10
+ other types of examples, see below.
11
+
12
+ :class:`Factorization` class objects contain a ``list``, so can be
13
+ printed nicely and be manipulated like a list of prime-exponent pairs,
14
+ or easily turned into a plain list. For example, we factor the
15
+ integer `-45`::
16
+
17
+ sage: F = factor(-45)
18
+
19
+ This returns an object of type :class:`Factorization`::
20
+
21
+ sage: type(F)
22
+ <class 'sage.structure.factorization_integer.IntegerFactorization'>
23
+
24
+ It prints in a nice factored form::
25
+
26
+ sage: F
27
+ -1 * 3^2 * 5
28
+
29
+ There is an underlying list representation, which ignores the unit part::
30
+
31
+ sage: list(F)
32
+ [(3, 2), (5, 1)]
33
+
34
+ A :class:`Factorization` is not actually a list::
35
+
36
+ sage: isinstance(F, list)
37
+ False
38
+
39
+ However, we can access the :class:`Factorization` F itself as if it were a list::
40
+
41
+ sage: F[0]
42
+ (3, 2)
43
+ sage: F[1]
44
+ (5, 1)
45
+
46
+ To get at the unit part, use the :meth:`Factorization.unit` function::
47
+
48
+ sage: F.unit()
49
+ -1
50
+
51
+ All factorizations are immutable, up to ordering with ``sort()`` and
52
+ simplifying with ``simplify()``. Thus if you write a function that
53
+ returns a cached version of a factorization, you do not have to return
54
+ a copy.
55
+
56
+ ::
57
+
58
+ sage: F = factor(-12); F
59
+ -1 * 2^2 * 3
60
+ sage: F[0] = (5,4)
61
+ Traceback (most recent call last):
62
+ ...
63
+ TypeError: 'Factorization' object does not support item assignment
64
+
65
+ EXAMPLES:
66
+
67
+ This more complicated example involving polynomials also illustrates
68
+ that the unit part is not discarded from factorizations::
69
+
70
+ sage: # needs sage.libs.pari
71
+ sage: x = QQ['x'].0
72
+ sage: f = -5*(x-2)*(x-3)
73
+ sage: f
74
+ -5*x^2 + 25*x - 30
75
+ sage: F = f.factor(); F
76
+ (-5) * (x - 3) * (x - 2)
77
+ sage: F.unit()
78
+ -5
79
+ sage: F.value()
80
+ -5*x^2 + 25*x - 30
81
+
82
+ The underlying list is the list of pairs `(p_i, e_i)`, where each
83
+ `p_i` is a 'prime' and each `e_i` is an integer. The unit part
84
+ is discarded by the list::
85
+
86
+ sage: # needs sage.libs.pari
87
+ sage: list(F)
88
+ [(x - 3, 1), (x - 2, 1)]
89
+ sage: len(F)
90
+ 2
91
+ sage: F[1]
92
+ (x - 2, 1)
93
+
94
+ In the ring `\ZZ[x]`, the integer `-5` is not a unit, so the
95
+ factorization has three factors::
96
+
97
+ sage: # needs sage.libs.pari
98
+ sage: x = ZZ['x'].0
99
+ sage: f = -5*(x-2)*(x-3)
100
+ sage: f
101
+ -5*x^2 + 25*x - 30
102
+ sage: F = f.factor(); F
103
+ (-1) * 5 * (x - 3) * (x - 2)
104
+ sage: F.universe()
105
+ Univariate Polynomial Ring in x over Integer Ring
106
+ sage: F.unit()
107
+ -1
108
+ sage: list(F)
109
+ [(5, 1), (x - 3, 1), (x - 2, 1)]
110
+ sage: F.value()
111
+ -5*x^2 + 25*x - 30
112
+ sage: len(F)
113
+ 3
114
+
115
+ On the other hand, -1 is a unit in `\ZZ`, so it is included in the unit::
116
+
117
+ sage: # needs sage.libs.pari
118
+ sage: x = ZZ['x'].0
119
+ sage: f = -1 * (x-2) * (x-3)
120
+ sage: F = f.factor(); F
121
+ (-1) * (x - 3) * (x - 2)
122
+ sage: F.unit()
123
+ -1
124
+ sage: list(F)
125
+ [(x - 3, 1), (x - 2, 1)]
126
+
127
+ Factorizations can involve fairly abstract mathematical objects::
128
+
129
+ sage: # needs sage.modular
130
+ sage: F = ModularSymbols(11,4).factorization(); F
131
+ (Modular Symbols subspace of dimension 2 of Modular Symbols space
132
+ of dimension 6 for Gamma_0(11) of weight 4 with sign 0 over Rational Field) *
133
+ (Modular Symbols subspace of dimension 2 of Modular Symbols space
134
+ of dimension 6 for Gamma_0(11) of weight 4 with sign 0 over Rational Field) *
135
+ (Modular Symbols subspace of dimension 2 of Modular Symbols space
136
+ of dimension 6 for Gamma_0(11) of weight 4 with sign 0 over Rational Field)
137
+ sage: type(F)
138
+ <class 'sage.structure.factorization.Factorization'>
139
+
140
+
141
+ sage: # needs sage.rings.number_field
142
+ sage: x = ZZ['x'].0
143
+ sage: K.<a> = NumberField(x^2 + 3); K
144
+ Number Field in a with defining polynomial x^2 + 3
145
+ sage: f = K.factor(15); f
146
+ (Fractional ideal (-a))^2 * (Fractional ideal (5))
147
+ sage: f.universe()
148
+ Monoid of ideals of Number Field in a with defining polynomial x^2 + 3
149
+ sage: f.unit()
150
+ Fractional ideal (1)
151
+ sage: g = K.factor(9); g
152
+ (Fractional ideal (-a))^4
153
+ sage: f.lcm(g)
154
+ (Fractional ideal (-a))^4 * (Fractional ideal (5))
155
+ sage: f.gcd(g)
156
+ (Fractional ideal (-a))^2
157
+ sage: f.is_integral()
158
+ True
159
+
160
+ TESTS::
161
+
162
+ sage: F = factor(-20); F
163
+ -1 * 2^2 * 5
164
+ sage: G = loads(dumps(F)); G
165
+ -1 * 2^2 * 5
166
+ sage: G == F
167
+ True
168
+ sage: G is F
169
+ False
170
+
171
+ AUTHORS:
172
+
173
+ - William Stein (2006-01-22): added unit part as suggested by David Kohel.
174
+
175
+ - William Stein (2008-01-17): wrote much of the documentation and
176
+ fixed a couple of bugs.
177
+
178
+ - Nick Alexander (2008-01-19): added support for non-commuting factors.
179
+
180
+ - John Cremona (2008-08-22): added division, lcm, gcd, is_integral and
181
+ universe functions
182
+ """
183
+
184
+ # ****************************************************************************
185
+ # Copyright (C) 2005 William Stein <wstein@gmail.com>
186
+ #
187
+ # This program is free software: you can redistribute it and/or modify
188
+ # it under the terms of the GNU General Public License as published by
189
+ # the Free Software Foundation, either version 2 of the License, or
190
+ # (at your option) any later version.
191
+ # https://www.gnu.org/licenses/
192
+ # ****************************************************************************
193
+
194
+ from sage.structure.sage_object import SageObject
195
+ from sage.structure.element import Element
196
+ from sage.structure.sequence import Sequence
197
+ from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal
198
+ from sage.misc.cachefunc import cached_method
199
+
200
+
201
+ @richcmp_method
202
+ class Factorization(SageObject):
203
+ """
204
+ A formal factorization of an object.
205
+
206
+ EXAMPLES::
207
+
208
+ sage: N = 2006
209
+ sage: F = N.factor(); F
210
+ 2 * 17 * 59
211
+ sage: F.unit()
212
+ 1
213
+ sage: F = factor(-2006); F
214
+ -1 * 2 * 17 * 59
215
+ sage: F.unit()
216
+ -1
217
+ sage: loads(F.dumps()) == F
218
+ True
219
+ sage: F = Factorization([(x, 1/3)]) # needs sage.symbolic
220
+ Traceback (most recent call last):
221
+ ...
222
+ TypeError: no conversion of this rational to integer
223
+ """
224
+ def __init__(self, x, unit=None, cr=False, sort=True, simplify=True):
225
+ """
226
+ Create a :class:`Factorization` object.
227
+
228
+ INPUT:
229
+
230
+ - ``x`` -- list of pairs (p, e) with e an integer
231
+ otherwise a :exc:`TypeError` is raised
232
+
233
+ - ``unit`` -- (default: 1) the unit part of the factorization
234
+
235
+ - ``cr`` -- (default: ``False``) if ``True``, print the factorization
236
+ with carriage returns between factors
237
+
238
+ - ``sort`` -- (default: ``True``) if ``True``, sort the factors by
239
+ calling the sort function ``self.sort()`` after creating
240
+ the factorization
241
+
242
+ - ``simplify`` -- (default: ``True``) if ``True``, remove duplicate
243
+ factors from the factorization. See the documentation for
244
+ self.simplify.
245
+
246
+ OUTPUT: a Factorization object
247
+
248
+ EXAMPLES:
249
+
250
+ We create a factorization with all the default options::
251
+
252
+ sage: Factorization([(2,3), (5, 1)])
253
+ 2^3 * 5
254
+
255
+ We create a factorization with a specified unit part::
256
+
257
+ sage: Factorization([(2,3), (5, 1)], unit=-1)
258
+ -1 * 2^3 * 5
259
+
260
+ We try to create a factorization but with a string an exponent, which
261
+ results in a TypeError::
262
+
263
+ sage: Factorization([(2,3), (5, 'x')])
264
+ Traceback (most recent call last):
265
+ ...
266
+ TypeError: unable to convert 'x' to an integer
267
+
268
+ We create a factorization that puts newlines after each multiply sign
269
+ when printing. This is mainly useful when the primes are large::
270
+
271
+ sage: Factorization([(2,3), (5, 2)], cr=True)
272
+ 2^3 *
273
+ 5^2
274
+
275
+ Another factorization with newlines and nontrivial unit part, which
276
+ appears on a line by itself::
277
+
278
+ sage: Factorization([(2,3), (5, 2)], cr=True, unit=-2)
279
+ -2 *
280
+ 2^3 *
281
+ 5^2
282
+
283
+ A factorization, but where we do not sort the factors::
284
+
285
+ sage: Factorization([(5,3), (2, 3)], sort=False)
286
+ 5^3 * 2^3
287
+
288
+ By default, in the commutative case, factorizations are sorted by the
289
+ prime base::
290
+
291
+ sage: Factorization([(2, 7), (5,2), (2, 5)])
292
+ 2^12 * 5^2
293
+ sage: R.<a,b> = FreeAlgebra(QQ, 2) # needs sage.combinat sage.modules
294
+ sage: Factorization([(a,1), (b,1), (a,2)]) # needs sage.combinat sage.modules
295
+ a * b * a^2
296
+
297
+ Autosorting (the default) swaps around the factors below::
298
+
299
+ sage: F = Factorization([(ZZ^3, 2), (ZZ^2, 5)], cr=True); F # needs sage.modules
300
+ (Ambient free module of rank 2 over the principal ideal domain Integer Ring)^5 *
301
+ (Ambient free module of rank 3 over the principal ideal domain Integer Ring)^2
302
+ """
303
+ from sage.rings.integer import Integer
304
+ x = [(p, Integer(e)) for (p, e) in x]
305
+
306
+ try:
307
+ self.__universe = Sequence(t[0] for t in x).universe()
308
+ except TypeError:
309
+ self.__universe = None
310
+
311
+ self.__x = [(t[0], int(t[1])) for t in x]
312
+ if unit is None:
313
+ if x:
314
+ try:
315
+ unit = self.__universe(1)
316
+ except (AttributeError, TypeError):
317
+ unit = Integer(1)
318
+ else:
319
+ unit = Integer(1)
320
+ self.__unit = unit
321
+ self.__cr = cr
322
+ if sort and self.is_commutative():
323
+ self.sort()
324
+ if simplify:
325
+ self.simplify()
326
+
327
+ def __getitem__(self, i):
328
+ """
329
+ Return `i`-th factor of ``self``.
330
+
331
+ EXAMPLES::
332
+
333
+ sage: a = factor(-75); a
334
+ -1 * 3 * 5^2
335
+ sage: a[0]
336
+ (3, 1)
337
+ sage: a[1]
338
+ (5, 2)
339
+ sage: a[-1]
340
+ (5, 2)
341
+ sage: a[5]
342
+ Traceback (most recent call last):
343
+ ...
344
+ IndexError: list index out of range
345
+ """
346
+ return self.__x[i]
347
+
348
+ def __setitem__(self, i, v):
349
+ """
350
+ Set the `i`-th factor of ``self``.
351
+
352
+ .. warning::
353
+
354
+ NOT ALLOWED -- Factorizations are immutable.
355
+
356
+ EXAMPLES::
357
+
358
+ sage: a = factor(-75); a
359
+ -1 * 3 * 5^2
360
+ sage: a[0] = (2,3)
361
+ Traceback (most recent call last):
362
+ ...
363
+ TypeError: 'Factorization' object does not support item assignment
364
+ """
365
+ raise TypeError("'Factorization' object does not support item assignment")
366
+
367
+ def __len__(self):
368
+ """
369
+ Return the number of prime factors of ``self``, not counting
370
+ the unit part.
371
+
372
+ EXAMPLES::
373
+
374
+ sage: len(factor(15))
375
+ 2
376
+
377
+ Note that the unit part is not included in the count::
378
+
379
+ sage: a = factor(-75); a
380
+ -1 * 3 * 5^2
381
+ sage: len(a)
382
+ 2
383
+ sage: list(a)
384
+ [(3, 1), (5, 2)]
385
+ sage: len(list(a))
386
+ 2
387
+ """
388
+ return len(self.__x)
389
+
390
+ def __richcmp__(self, other, op):
391
+ """
392
+ Compare ``self`` and ``other``.
393
+
394
+ This first compares the values.
395
+
396
+ If values are equal, this compares the units.
397
+
398
+ If units are equal, this compares the underlying lists of
399
+ ``self`` and ``other``.
400
+
401
+ EXAMPLES:
402
+
403
+ We compare two contrived formal factorizations::
404
+
405
+ sage: a = Factorization([(2, 7), (5,2), (2, 5)])
406
+ sage: b = Factorization([(2, 7), (5,10), (7, 3)])
407
+ sage: a
408
+ 2^12 * 5^2
409
+ sage: b
410
+ 2^7 * 5^10 * 7^3
411
+ sage: a < b
412
+ True
413
+ sage: b < a
414
+ False
415
+ sage: a.value()
416
+ 102400
417
+ sage: b.value()
418
+ 428750000000
419
+
420
+ We compare factorizations of some polynomials::
421
+
422
+ sage: x = polygen(QQ)
423
+ sage: x^2 - 1 > x^2 - 4
424
+ True
425
+ sage: factor(x^2 - 1) > factor(x^2 - 4) # needs sage.libs.pari
426
+ True
427
+ """
428
+ if not isinstance(other, Factorization):
429
+ return NotImplemented
430
+
431
+ lx = self.value()
432
+ rx = other.value()
433
+ if lx != rx:
434
+ return richcmp_not_equal(lx, rx, op)
435
+
436
+ lx = self.__unit
437
+ rx = other.__unit
438
+ if lx != rx:
439
+ return richcmp_not_equal(lx, rx, op)
440
+
441
+ return richcmp(self.__x, other.__x, op)
442
+
443
+ def __hash__(self):
444
+ r"""
445
+ Return a hash of this factorization.
446
+
447
+ EXAMPLES::
448
+
449
+ sage: F = factor(2025); F
450
+ 3^4 * 5^2
451
+ sage: hash(F) # random
452
+ -3439993427179649882
453
+ """
454
+ return hash((self.__unit, tuple(self.__x)))
455
+
456
+ def __copy__(self):
457
+ r"""
458
+ Return a copy of ``self``.
459
+
460
+ This is *not* a deepcopy -- only references to the factors are
461
+ returned, not copies of them. Use ``deepcopy(self)`` if you need
462
+ a deep copy of ``self``.
463
+
464
+ EXAMPLES:
465
+
466
+ We create a factorization that has mutable primes::
467
+
468
+ sage: F = Factorization([([1,2], 5), ([5,6], 10)]); F
469
+ ([1, 2])^5 * ([5, 6])^10
470
+
471
+ We make a copy of it::
472
+
473
+ sage: G = copy(F); G
474
+ ([1, 2])^5 * ([5, 6])^10
475
+ sage: G is F
476
+ False
477
+
478
+ Note that if we change one of the mutable "primes" of F, this does
479
+ change G::
480
+
481
+ sage: F[1][0][0] = 'hello'
482
+ sage: G
483
+ ([1, 2])^5 * (['hello', 6])^10
484
+ """
485
+ # No need to sort, since the factorization is already sorted
486
+ # in whatever order is desired.
487
+ return Factorization(self.__x, unit=self.__unit, cr=self.__cr,
488
+ sort=False, simplify=False)
489
+
490
+ def __deepcopy__(self, memo):
491
+ r"""
492
+ Return a deep copy of ``self``.
493
+
494
+ EXAMPLES:
495
+
496
+ We make a factorization that has mutable entries::
497
+
498
+ sage: F = Factorization([([1,2], 5), ([5,6], 10)]); F
499
+ ([1, 2])^5 * ([5, 6])^10
500
+
501
+ Now we make a copy of it and a deep copy::
502
+
503
+ sage: K = copy(F)
504
+ sage: G = deepcopy(F); G
505
+ ([1, 2])^5 * ([5, 6])^10
506
+
507
+ We change one of the mutable entries of F::
508
+
509
+ sage: F[0][0][0] = 10
510
+
511
+ This of course changes F::
512
+
513
+ sage: F
514
+ ([10, 2])^5 * ([5, 6])^10
515
+
516
+ It also changes the copy K of F::
517
+
518
+ sage: K
519
+ ([10, 2])^5 * ([5, 6])^10
520
+
521
+ It does *not* change the deep copy G::
522
+
523
+ sage: G
524
+ ([1, 2])^5 * ([5, 6])^10
525
+ """
526
+ import copy
527
+ return Factorization(copy.deepcopy(list(self), memo),
528
+ cr=self.__cr, sort=False, simplify=False)
529
+
530
+ def universe(self):
531
+ r"""
532
+ Return the parent structure of my factors.
533
+
534
+ .. NOTE::
535
+
536
+ This used to be called ``base_ring``, but the universe
537
+ of a factorization need not be a ring.
538
+
539
+ EXAMPLES::
540
+
541
+ sage: F = factor(2006)
542
+ sage: F.universe()
543
+ Integer Ring
544
+
545
+ sage: R.<x,y,z> = FreeAlgebra(QQ, 3) # needs sage.combinat sage.modules
546
+ sage: F = Factorization([(z, 2)], 3) # needs sage.combinat sage.modules
547
+ sage: (F*F^-1).universe() # needs sage.combinat sage.modules
548
+ Free Algebra on 3 generators (x, y, z) over Rational Field
549
+
550
+ sage: F = ModularSymbols(11,4).factorization() # needs sage.modular
551
+ sage: F.universe() # needs sage.modular
552
+ """
553
+ try:
554
+ return self.__universe
555
+ except AttributeError:
556
+ return None
557
+
558
+ def base_change(self, U):
559
+ """
560
+ Return the factorization ``self``, with its factors (including the
561
+ unit part) coerced into the universe `U`.
562
+
563
+ EXAMPLES::
564
+
565
+ sage: F = factor(2006)
566
+ sage: F.universe()
567
+ Integer Ring
568
+ sage: P.<x> = ZZ[]
569
+ sage: F.base_change(P).universe()
570
+ Univariate Polynomial Ring in x over Integer Ring
571
+
572
+ This method will return a :exc:`TypeError` if the coercion is not
573
+ possible::
574
+
575
+ sage: g = x^2 - 1
576
+ sage: F = factor(g); F # needs sage.libs.pari
577
+ (x - 1) * (x + 1)
578
+ sage: F.universe() # needs sage.libs.pari
579
+ Univariate Polynomial Ring in x over Integer Ring
580
+ sage: F.base_change(ZZ) # needs sage.libs.pari
581
+ Traceback (most recent call last):
582
+ ...
583
+ TypeError: Impossible to coerce the factors of (x - 1) * (x + 1) into Integer Ring
584
+ """
585
+ if len(self) == 0:
586
+ return self
587
+ try:
588
+ return Factorization([(U(f[0]), f[1]) for f in list(self)], unit=U(self.unit()))
589
+ except TypeError:
590
+ raise TypeError("Impossible to coerce the factors of %s into %s" % (self, U))
591
+
592
+ def is_commutative(self) -> bool:
593
+ """
594
+ Return whether the factors commute.
595
+
596
+ EXAMPLES::
597
+
598
+ sage: F = factor(2006)
599
+ sage: F.is_commutative()
600
+ True
601
+
602
+ sage: # needs sage.rings.number_field
603
+ sage: K = QuadraticField(23, 'a')
604
+ sage: F = K.factor(13)
605
+ sage: F.is_commutative()
606
+ True
607
+
608
+ sage: # needs sage.combinat sage.modules
609
+ sage: R.<x,y,z> = FreeAlgebra(QQ, 3)
610
+ sage: F = Factorization([(z, 2)], 3)
611
+ sage: F.is_commutative()
612
+ False
613
+ sage: (F*F^-1).is_commutative()
614
+ False
615
+ """
616
+ try:
617
+ return self.universe().is_commutative()
618
+ except Exception:
619
+ # This is not the mathematically correct default, but agrees with
620
+ # history -- we've always assumed factored things commute
621
+ return True
622
+
623
+ def _set_cr(self, cr):
624
+ """
625
+ Change whether or not the factorization is printed with
626
+ carriage returns after each factor.
627
+
628
+ EXAMPLES::
629
+
630
+ sage: x = polygen(QQ,'x')
631
+ sage: F = factor(x^6 - 1); F # needs sage.libs.pari
632
+ (x - 1) * (x + 1) * (x^2 - x + 1) * (x^2 + x + 1)
633
+ sage: F._set_cr(True); F # needs sage.libs.pari
634
+ (x - 1) *
635
+ (x + 1) *
636
+ (x^2 - x + 1) *
637
+ (x^2 + x + 1)
638
+ sage: F._set_cr(False); F # needs sage.libs.pari
639
+ (x - 1) * (x + 1) * (x^2 - x + 1) * (x^2 + x + 1)
640
+ """
641
+ self.__cr = bool(cr)
642
+
643
+ def simplify(self):
644
+ """
645
+ Combine adjacent products as much as possible.
646
+
647
+ TESTS::
648
+
649
+ sage: # needs sage.combinat sage.modules
650
+ sage: R.<x,y> = FreeAlgebra(ZZ, 2)
651
+ sage: F = Factorization([(x,3), (y, 2), (y,2)], simplify=False); F
652
+ x^3 * y^2 * y^2
653
+ sage: F.simplify(); F
654
+ x^3 * y^4
655
+ sage: F * Factorization([(y, -2)], 2)
656
+ (2) * x^3 * y^2
657
+ """
658
+ repeat = False
659
+ simp = []
660
+ import itertools
661
+ for obj, agroup in itertools.groupby(list(self), lambda x: x[0]):
662
+ xs = list(agroup)
663
+ if len(xs) > 1:
664
+ repeat = True
665
+ n = sum([x[1] for x in xs])
666
+ if n != 0:
667
+ simp.append((obj, n))
668
+ self.__x[0:] = simp
669
+ if repeat:
670
+ self.simplify()
671
+
672
+ def sort(self, key=None):
673
+ r"""
674
+ Sort the factors in this factorization.
675
+
676
+ INPUT:
677
+
678
+ - ``key`` -- (default: ``None``) comparison key
679
+
680
+ OUTPUT: changes this factorization to be sorted (inplace)
681
+
682
+ If ``key`` is ``None``, we determine the comparison key as
683
+ follows:
684
+
685
+ If the prime in the first factor has a dimension
686
+ method, then we sort based first on *dimension* then on
687
+ the exponent.
688
+
689
+ If there is no dimension method, we next
690
+ attempt to sort based on a degree method, in which case, we
691
+ sort based first on *degree*, then exponent to break ties
692
+ when two factors have the same degree, and if those match
693
+ break ties based on the actual prime itself.
694
+
695
+ Otherwise, we sort according to the prime itself.
696
+
697
+ EXAMPLES:
698
+
699
+ We create a factored polynomial::
700
+
701
+ sage: x = polygen(QQ, 'x')
702
+ sage: F = factor(x^3 + 1); F # needs sage.libs.pari
703
+ (x + 1) * (x^2 - x + 1)
704
+
705
+ We sort it by decreasing degree::
706
+
707
+ sage: F.sort(key=lambda x: (-x[0].degree(), x)) # needs sage.libs.pari
708
+ sage: F # needs sage.libs.pari
709
+ (x^2 - x + 1) * (x + 1)
710
+ """
711
+ if len(self) == 0:
712
+ return
713
+
714
+ if key is not None:
715
+ self.__x.sort(key=key)
716
+ return
717
+
718
+ a = self.__x[0][0]
719
+ sort_key = None
720
+ if hasattr(a, 'dimension'):
721
+ try:
722
+ a.dimension()
723
+
724
+ def sort_key(f):
725
+ return (f[0].dimension(), f[1], f[0])
726
+ except (AttributeError, NotImplementedError, TypeError):
727
+ pass
728
+ elif hasattr(a, 'degree'):
729
+ try:
730
+ a.degree()
731
+
732
+ def sort_key(f):
733
+ return (f[0].degree(), f[1], f[0])
734
+ except (AttributeError, NotImplementedError, TypeError):
735
+ pass
736
+
737
+ if sort_key is None:
738
+
739
+ def sort_key(f):
740
+ return f[0]
741
+
742
+ self.__x.sort(key=sort_key)
743
+
744
+ def unit(self):
745
+ r"""
746
+ Return the unit part of this factorization.
747
+
748
+ EXAMPLES:
749
+
750
+ We create a polynomial over the real double field and factor it::
751
+
752
+ sage: x = polygen(RDF, 'x')
753
+ sage: F = factor(-2*x^2 - 1); F # needs numpy
754
+ (-2.0) * (x^2 + 0.5000000000000001)
755
+
756
+ Note that the unit part of the factorization is `-2.0`::
757
+
758
+ sage: F.unit() # needs numpy
759
+ -2.0
760
+
761
+ sage: F = factor(-2006); F
762
+ -1 * 2 * 17 * 59
763
+ sage: F.unit()
764
+ -1
765
+ """
766
+ return self.__unit
767
+
768
+ def _cr(self):
769
+ """
770
+ Return whether or not factorizations are printed with carriage
771
+ returns between factors.
772
+
773
+ EXAMPLES:
774
+
775
+ Our first example involves factoring an integer::
776
+
777
+ sage: F = factor(-93930); F
778
+ -1 * 2 * 3 * 5 * 31 * 101
779
+ sage: F._cr()
780
+ False
781
+ sage: F._set_cr(True)
782
+ sage: F._cr()
783
+ True
784
+
785
+ This of course looks funny::
786
+
787
+ sage: F
788
+ -1 *
789
+ 2 *
790
+ 3 *
791
+ 5 *
792
+ 31 *
793
+ 101
794
+
795
+ Next we factor a modular symbols space::
796
+
797
+ sage: F = ModularSymbols(11).factor(); F # needs sage.modular
798
+ (Modular Symbols subspace of dimension 1 of ...) *
799
+ (Modular Symbols subspace of dimension 1 of ...) *
800
+ (Modular Symbols subspace of dimension 1 of ...)
801
+ """
802
+ try:
803
+ return self.__cr
804
+ except AttributeError:
805
+ self.__cr = False
806
+ return False
807
+
808
+ def _repr_(self):
809
+ """
810
+ Return the string representation of this factorization.
811
+
812
+ EXAMPLES::
813
+
814
+ sage: f = factor(-100); f
815
+ -1 * 2^2 * 5^2
816
+ sage: f._repr_()
817
+ '-1 * 2^2 * 5^2'
818
+
819
+ Note that the default printing of a factorization can be overloaded
820
+ using the rename method::
821
+
822
+ sage: f.rename('factorization of -100')
823
+ sage: f
824
+ factorization of -100
825
+
826
+ However ``_repr_`` always prints normally::
827
+
828
+ sage: f._repr_()
829
+ '-1 * 2^2 * 5^2'
830
+
831
+ EXAMPLES::
832
+
833
+ sage: x = polygen(QQ)
834
+ sage: Factorization([(x-1,1), (x-2,2)])
835
+ (x - 1) * (x - 2)^2
836
+ sage: Factorization([(x + 1, -3)])
837
+ (x + 1)^-3
838
+ """
839
+ cr = self._cr()
840
+ if len(self) == 0:
841
+ return repr(self.__unit)
842
+ s = ''
843
+ mul = ' * '
844
+ if cr:
845
+ mul += '\n'
846
+ x = self.__x[0][0]
847
+ try:
848
+ atomic = (isinstance(x, int) or
849
+ self.universe()._repr_option('element_is_atomic'))
850
+ except AttributeError:
851
+ atomic = False
852
+
853
+ if isinstance(x, Element):
854
+ one = x.parent()(1)
855
+ else:
856
+ one = 1
857
+
858
+ for i in range(len(self)):
859
+ t = repr(self.__x[i][0])
860
+ n = self.__x[i][1]
861
+ if not atomic and (n != 1 or len(self) > 1 or self.__unit != one):
862
+ if '+' in t or '-' in t or ' ' in t:
863
+ t = '(%s)' % t
864
+ if n != 1:
865
+ t += '^%s' % n
866
+ s += t
867
+ if i < len(self) - 1:
868
+ s += mul
869
+ if self.__unit != one:
870
+ if atomic:
871
+ u = repr(self.__unit)
872
+ else:
873
+ u = '(%s)' % self.__unit
874
+ s = u + mul + s
875
+ return s
876
+
877
+ def _latex_(self):
878
+ r"""
879
+ Return the LaTeX representation of this factorization.
880
+
881
+ EXAMPLES::
882
+
883
+ sage: f = factor(-100); f
884
+ -1 * 2^2 * 5^2
885
+ sage: latex(f)
886
+ -1 \cdot 2^{2} \cdot 5^{2}
887
+ sage: f._latex_()
888
+ '-1 \\cdot 2^{2} \\cdot 5^{2}'
889
+ sage: x = AA['x'].0; factor(x^2 + x + 1)._latex_() # Issue #12178 # needs sage.rings.number_field
890
+ '(x^{2} + x + 1.000000000000000?)'
891
+ """
892
+ if len(self) == 0:
893
+ return self.__unit._latex_()
894
+ try:
895
+ atomic = (isinstance(self.__x[0][0], int) or
896
+ self.universe()._repr_option('element_is_atomic'))
897
+ except AttributeError:
898
+ atomic = False
899
+ s = ''
900
+ for i in range(len(self)):
901
+ t = self.__x[i][0]._latex_()
902
+ if not atomic and ('+' in t or '-' in t or ' ' in t):
903
+ t = '(%s)' % t
904
+ n = self.__x[i][1]
905
+ if n != 1:
906
+ t += '^{%s}' % n
907
+ s += t
908
+ if i < len(self) - 1:
909
+ s += ' \\cdot '
910
+ if self.__unit != 1:
911
+ if atomic:
912
+ u = self.__unit._latex_()
913
+ else:
914
+ u = '\\left(%s\\right)' % self.__unit._latex_()
915
+ s = u + ' \\cdot ' + s
916
+ return s
917
+
918
+ @cached_method
919
+ def __pari__(self):
920
+ """
921
+ Return the PARI factorization matrix corresponding to ``self``.
922
+
923
+ EXAMPLES::
924
+
925
+ sage: f = factor(-24)
926
+ sage: pari(f) # needs sage.libs.pari
927
+ [-1, 1; 2, 3; 3, 1]
928
+
929
+ sage: R.<x> = QQ[]
930
+ sage: g = factor(x^10 - 1) # needs sage.libs.pari
931
+ sage: pari(g) # needs sage.libs.pari
932
+ [x - 1, 1; x + 1, 1; x^4 - x^3 + x^2 - x + 1, 1; x^4 + x^3 + x^2 + x + 1, 1]
933
+ """
934
+ from sage.libs.pari import pari
935
+ from itertools import chain
936
+
937
+ n = len(self)
938
+ if self.__unit == 1:
939
+ init = ()
940
+ else:
941
+ init = (self.__unit, 1)
942
+ n += 1
943
+ # concatenate (p, e) tuples
944
+ entries = init + tuple(chain.from_iterable(self))
945
+ return pari.matrix(n, 2, entries)
946
+
947
+ def __add__(self, other):
948
+ """
949
+ Return the (unfactored) sum of ``self`` and ``other``.
950
+
951
+ EXAMPLES::
952
+
953
+ sage: factor(-10) + 16
954
+ 6
955
+ sage: factor(10) - 16
956
+ -6
957
+ sage: factor(100) + factor(19)
958
+ 119
959
+ """
960
+ if isinstance(other, Factorization):
961
+ other = other.value()
962
+ return self.value() + other
963
+
964
+ def __sub__(self, other):
965
+ """
966
+ Return the (unfactored) difference of ``self`` and ``other``.
967
+
968
+ EXAMPLES::
969
+
970
+ sage: factor(-10) + 16
971
+ 6
972
+ sage: factor(10) - 16
973
+ -6
974
+ """
975
+ if isinstance(other, Factorization):
976
+ other = other.value()
977
+ return self.value() - other
978
+
979
+ def __radd__(self, left):
980
+ """
981
+ Return the (unfactored) sum of ``self`` and ``left``.
982
+
983
+ EXAMPLES::
984
+
985
+ sage: 16 + factor(-10)
986
+ 6
987
+ """
988
+ return self.value() + left
989
+
990
+ def __rsub__(self, left):
991
+ """
992
+ Return the (unfactored) difference of ``left`` and ``self``.
993
+
994
+ EXAMPLES::
995
+
996
+ sage: 16 - factor(10)
997
+ 6
998
+ """
999
+ return left - self.value()
1000
+
1001
+ def __neg__(self):
1002
+ """
1003
+ Return negative of this factorization.
1004
+
1005
+ EXAMPLES::
1006
+
1007
+ sage: a = factor(-75); a
1008
+ -1 * 3 * 5^2
1009
+ sage: -a
1010
+ 3 * 5^2
1011
+ sage: (-a).unit()
1012
+ 1
1013
+ """
1014
+ unit = -self.__unit
1015
+ return Factorization(list(self), unit, self.__cr,
1016
+ sort=False, simplify=False)
1017
+
1018
+ def __rmul__(self, left):
1019
+ """
1020
+ Return the product ``left * self``, where ``left`` is not a Factorization.
1021
+
1022
+ EXAMPLES::
1023
+
1024
+ sage: a = factor(15); a
1025
+ 3 * 5
1026
+ sage: -2 * a
1027
+ -2 * 3 * 5
1028
+ sage: a * -2
1029
+ -2 * 3 * 5
1030
+ sage: R.<x,y> = FreeAlgebra(QQ, 2) # needs sage.combinat sage.modules
1031
+ sage: f = Factorization([(x,2), (y,3)]); f # needs sage.combinat sage.modules
1032
+ x^2 * y^3
1033
+ sage: x * f # needs sage.combinat sage.modules
1034
+ x^3 * y^3
1035
+ sage: f * x # needs sage.combinat sage.modules
1036
+ x^2 * y^3 * x
1037
+
1038
+ Note that this does not automatically factor ``left``::
1039
+
1040
+ sage: F = Factorization([(5,3), (2,3)])
1041
+ sage: 46 * F
1042
+ 2^3 * 5^3 * 46
1043
+ """
1044
+ return Factorization([(left, 1)]) * self
1045
+
1046
+ def __mul__(self, other):
1047
+ r"""
1048
+ Return the product of two factorizations, which is obtained by
1049
+ combining together like factors.
1050
+
1051
+ If the two factorizations have different universes, this
1052
+ method will attempt to find a common universe for the
1053
+ product. A :exc:`TypeError` is raised if this is impossible.
1054
+
1055
+ EXAMPLES::
1056
+
1057
+ sage: factor(-10) * factor(-16)
1058
+ 2^5 * 5
1059
+ sage: factor(-10) * factor(16)
1060
+ -1 * 2^5 * 5
1061
+
1062
+ sage: # needs sage.combinat sage.modules
1063
+ sage: R.<x,y> = FreeAlgebra(ZZ, 2)
1064
+ sage: F = Factorization([(x,3), (y, 2), (x,1)]); F
1065
+ x^3 * y^2 * x
1066
+ sage: F*F
1067
+ x^3 * y^2 * x^4 * y^2 * x
1068
+ sage: -1 * F
1069
+ (-1) * x^3 * y^2 * x
1070
+
1071
+ sage: P.<x> = ZZ[]
1072
+ sage: f = 2*x + 2
1073
+ sage: c = f.content(); g = f//c
1074
+ sage: Fc = factor(c); Fc.universe()
1075
+ Integer Ring
1076
+ sage: Fg = factor(g); Fg.universe()
1077
+ Univariate Polynomial Ring in x over Integer Ring
1078
+ sage: F = Fc * Fg; F.universe()
1079
+ Univariate Polynomial Ring in x over Integer Ring
1080
+ sage: [type(a[0]) for a in F]
1081
+ [<... 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'>,
1082
+ <... 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'>]
1083
+ """
1084
+ if not isinstance(other, Factorization):
1085
+ return self * Factorization([(other, 1)])
1086
+
1087
+ if len(self) and len(other):
1088
+ try:
1089
+ # since self is a factorization, all its factors
1090
+ # are in the same universe.
1091
+ # the same is true for the factorization other.
1092
+ # so if we want to put the factorizations together we just
1093
+ # need to find a common universe for the first factor of
1094
+ # self and the first factor of other
1095
+ U = Sequence([self[0][0], other[0][0]]).universe()
1096
+ self = self.base_change(U)
1097
+ other = other.base_change(U)
1098
+ except TypeError:
1099
+ raise TypeError("Cannot multiply %s and %s because they cannot be coerced into a common universe" % (self, other))
1100
+
1101
+ if self.is_commutative() and other.is_commutative():
1102
+ d1 = dict(self)
1103
+ d2 = dict(other)
1104
+ s = {}
1105
+ for a in set(d1).union(set(d2)):
1106
+ s[a] = d1.get(a, 0) + d2.get(a, 0)
1107
+ return Factorization(list(s.items()), unit=self.unit() * other.unit())
1108
+ else:
1109
+ return Factorization(list(self) + list(other), unit=self.unit() * other.unit())
1110
+
1111
+ def __pow__(self, n):
1112
+ """
1113
+ Return the `n`-th power of a factorization, which is got by
1114
+ combining together like factors.
1115
+
1116
+ EXAMPLES::
1117
+
1118
+ sage: f = factor(-100); f
1119
+ -1 * 2^2 * 5^2
1120
+ sage: f^3
1121
+ -1 * 2^6 * 5^6
1122
+ sage: f^4
1123
+ 2^8 * 5^8
1124
+
1125
+ sage: x = polygen(ZZ, 'x')
1126
+ sage: K.<a> = NumberField(x^3 - 39*x - 91) # needs sage.rings.number_field
1127
+ sage: F = K.factor(7); F # needs sage.rings.number_field
1128
+ (Fractional ideal (7, a)) * (Fractional ideal (7, a + 2)) * (Fractional ideal (7, a - 2))
1129
+ sage: F^9 # needs sage.rings.number_field
1130
+ (Fractional ideal (7, a))^9 * (Fractional ideal (7, a + 2))^9 * (Fractional ideal (7, a - 2))^9
1131
+
1132
+ sage: R.<x,y> = FreeAlgebra(ZZ, 2) # needs sage.combinat sage.modules
1133
+ sage: F = Factorization([(x,3), (y, 2), (x,1)]); F # needs sage.combinat sage.modules
1134
+ x^3 * y^2 * x
1135
+ sage: F**2 # needs sage.combinat sage.modules
1136
+ x^3 * y^2 * x^4 * y^2 * x
1137
+ """
1138
+ from sage.rings.integer import Integer
1139
+ if not isinstance(n, Integer):
1140
+ try:
1141
+ n = Integer(n)
1142
+ except TypeError:
1143
+ raise TypeError("Exponent n (= %s) must be an integer." % n)
1144
+ if n == 1:
1145
+ return self
1146
+ if n == 0:
1147
+ return Factorization([])
1148
+ if self.is_commutative():
1149
+ return Factorization([(p, n * e) for p, e in self], unit=self.unit()**n,
1150
+ cr=self.__cr, sort=False, simplify=False)
1151
+ if n < 0:
1152
+ self = ~self
1153
+ n = -n
1154
+ from sage.arith.power import generic_power
1155
+ return generic_power(self, n)
1156
+
1157
+ def __invert__(self):
1158
+ r"""
1159
+ Return the formal inverse of the factors in the factorization.
1160
+
1161
+ EXAMPLES::
1162
+
1163
+ sage: F = factor(2006); F
1164
+ 2 * 17 * 59
1165
+ sage: F^-1
1166
+ 2^-1 * 17^-1 * 59^-1
1167
+
1168
+ sage: R.<x,y> = FreeAlgebra(QQ, 2) # needs sage.combinat sage.modules
1169
+ sage: F = Factorization([(x,3), (y, 2), (x,1)], 2); F # needs sage.combinat sage.modules
1170
+ (2) * x^3 * y^2 * x
1171
+ sage: F^-1 # needs sage.combinat sage.modules
1172
+ (1/2) * x^-1 * y^-2 * x^-3
1173
+ """
1174
+ return Factorization([(p, -e) for p, e in reversed(self)],
1175
+ cr=self._cr(), unit=self.unit()**(-1))
1176
+
1177
+ def __truediv__(self, other):
1178
+ r"""
1179
+ Return the quotient of two factorizations, which is obtained by
1180
+ multiplying the first by the inverse of the second.
1181
+
1182
+ EXAMPLES::
1183
+
1184
+ sage: factor(-10) / factor(-16)
1185
+ 2^-3 * 5
1186
+ sage: factor(-10) / factor(16)
1187
+ -1 * 2^-3 * 5
1188
+
1189
+ sage: # needs sage.combinat sage.modules
1190
+ sage: R.<x,y> = FreeAlgebra(QQ, 2)
1191
+ sage: F = Factorization([(x,3), (y, 2), (x,1)]); F
1192
+ x^3 * y^2 * x
1193
+ sage: G = Factorization([(y, 1), (x,1)],1); G
1194
+ y * x
1195
+ sage: F / G
1196
+ x^3 * y
1197
+ """
1198
+ if not isinstance(other, Factorization):
1199
+ return self / Factorization([(other, 1)])
1200
+ return self * other**-1
1201
+
1202
+ def __call__(self, *args, **kwds):
1203
+ """
1204
+ Implement the substitution.
1205
+
1206
+ This is assuming that each term can be substituted.
1207
+
1208
+ There is another mechanism for substitution
1209
+ in symbolic products.
1210
+
1211
+ EXAMPLES::
1212
+
1213
+ sage: # needs sage.combinat sage.modules
1214
+ sage: R.<x,y> = FreeAlgebra(QQ, 2)
1215
+ sage: F = Factorization([(x,3), (y, 2), (x,1)])
1216
+ sage: F(x=4)
1217
+ 4^3 * y^2 * 4
1218
+ sage: F.subs({y:2})
1219
+ x^3 * 2^2 * x
1220
+
1221
+ sage: R.<x,y> = PolynomialRing(QQ, 2)
1222
+ sage: F = Factorization([(x,3), (y, 2), (x,1)])
1223
+ sage: F(x=4)
1224
+ 4 * 4^3 * y^2
1225
+ sage: F.subs({y:x})
1226
+ x * x^2 * x^3
1227
+ sage: F(x=y+x)
1228
+ (x + y) * y^2 * (x + y)^3
1229
+
1230
+ TESTS::
1231
+
1232
+ sage: R.<x,y> = PolynomialRing(QQ, 2)
1233
+ sage: F = Factorization([(x-2,3), (y+3, 2)])
1234
+ sage: F(x=2)
1235
+ 0
1236
+
1237
+ sage: QQt = QQ['t'].fraction_field()
1238
+ sage: t = QQt.gen()
1239
+ sage: R.<x> = PolynomialRing(QQt, 1)
1240
+ sage: F = Factorization([(x,3), (x+t, 2)], unit=QQt.gen())
1241
+ sage: F(t=0)
1242
+ 0
1243
+
1244
+ sage: # needs sage.libs.pari sage.modules
1245
+ sage: R.<x> = LaurentPolynomialRing(QQ, 1)
1246
+ sage: F = ((x+2)/x**3).factor()
1247
+ sage: F(x=4)
1248
+ 1/64 * 6
1249
+ """
1250
+ unit = self.__unit.subs(*args, **kwds)
1251
+ if unit == 0:
1252
+ return self.universe().zero()
1253
+ data = [(p.subs(*args, **kwds), e) for p, e in self.__x]
1254
+ if any(p == 0 for p, _ in data):
1255
+ return self.universe().zero()
1256
+ return Factorization(data, unit=unit, simplify=False)
1257
+
1258
+ subs = __call__
1259
+
1260
+ @cached_method
1261
+ def value(self):
1262
+ """
1263
+ Return the product of the factors in the factorization, multiplied out.
1264
+
1265
+ EXAMPLES::
1266
+
1267
+ sage: F = factor(-2006); F
1268
+ -1 * 2 * 17 * 59
1269
+ sage: F.value()
1270
+ -2006
1271
+
1272
+ sage: R.<x,y> = FreeAlgebra(ZZ, 2) # needs sage.combinat sage.modules
1273
+ sage: F = Factorization([(x,3), (y, 2), (x,1)]); F # needs sage.combinat sage.modules
1274
+ x^3 * y^2 * x
1275
+ sage: F.value() # needs sage.combinat sage.modules
1276
+ x^3*y^2*x
1277
+ """
1278
+ from sage.misc.misc_c import prod
1279
+ return prod([p**e for p, e in self.__x], self.__unit)
1280
+
1281
+ # Two aliases for ``value(self)``.
1282
+ expand = value
1283
+ prod = value
1284
+
1285
+ def gcd(self, other):
1286
+ r"""
1287
+ Return the gcd of two factorizations.
1288
+
1289
+ If the two factorizations have different universes, this
1290
+ method will attempt to find a common universe for the
1291
+ gcd. A :exc:`TypeError` is raised if this is impossible.
1292
+
1293
+ EXAMPLES::
1294
+
1295
+ sage: factor(-30).gcd(factor(-160))
1296
+ 2 * 5
1297
+ sage: factor(gcd(-30,160))
1298
+ 2 * 5
1299
+
1300
+ sage: R.<x> = ZZ[]
1301
+ sage: (factor(-20).gcd(factor(5*x+10))).universe() # needs sage.libs.pari
1302
+ Univariate Polynomial Ring in x over Integer Ring
1303
+ """
1304
+ if not isinstance(other, Factorization):
1305
+ raise NotImplementedError("can't take gcd of factorization and non-factorization")
1306
+
1307
+ if len(self) and len(other):
1308
+ try:
1309
+ # first get the two factorizations to have the same
1310
+ # universe
1311
+ U = Sequence([self[0][0], other[0][0]]).universe()
1312
+ self = self.base_change(U)
1313
+ other = other.base_change(U)
1314
+ except TypeError:
1315
+ raise TypeError("Cannot take the gcd of %s and %s because they cannot be coerced into a common universe" % (self, other))
1316
+
1317
+ if self.is_commutative() and other.is_commutative():
1318
+ d1 = dict(self)
1319
+ d2 = dict(other)
1320
+ s = {}
1321
+ for a in set(d1).intersection(set(d2)):
1322
+ s[a] = min(d1[a], d2[a])
1323
+ return Factorization(list(s.items()))
1324
+ else:
1325
+ raise NotImplementedError("gcd is not implemented for non-commutative factorizations")
1326
+
1327
+ def lcm(self, other):
1328
+ r"""
1329
+ Return the lcm of two factorizations.
1330
+
1331
+ If the two factorizations have different universes, this
1332
+ method will attempt to find a common universe for the
1333
+ lcm. A :exc:`TypeError` is raised if this is impossible.
1334
+
1335
+ EXAMPLES::
1336
+
1337
+ sage: factor(-10).lcm(factor(-16))
1338
+ 2^4 * 5
1339
+ sage: factor(lcm(-10,16))
1340
+ 2^4 * 5
1341
+
1342
+ sage: R.<x> = ZZ[]
1343
+ sage: (factor(-20).lcm(factor(5*x + 10))).universe() # needs sage.libs.pari
1344
+ Univariate Polynomial Ring in x over Integer Ring
1345
+ """
1346
+ if not isinstance(other, Factorization):
1347
+ raise NotImplementedError("can't take lcm of factorization and non-factorization")
1348
+
1349
+ if len(self) and len(other):
1350
+ try:
1351
+ # first get the two factorizations to have the same
1352
+ # universe
1353
+ U = Sequence([self[0][0], other[0][0]]).universe()
1354
+ self = self.base_change(U)
1355
+ other = other.base_change(U)
1356
+ except TypeError:
1357
+ raise TypeError("Cannot take the lcm of %s and %s because they cannot be coerced into a common universe" % (self, other))
1358
+
1359
+ if self.is_commutative() and other.is_commutative():
1360
+ d1 = dict(self)
1361
+ d2 = dict(other)
1362
+ s = {}
1363
+ for a in set(d1).union(set(d2)):
1364
+ s[a] = max(d1.get(a, 0), d2.get(a, 0))
1365
+ return Factorization(list(s.items()))
1366
+ else:
1367
+ raise NotImplementedError("lcm is not implemented for non-commutative factorizations")
1368
+
1369
+ def is_integral(self) -> bool:
1370
+ r"""
1371
+ Return whether all exponents of this Factorization are nonnegative.
1372
+
1373
+ EXAMPLES::
1374
+
1375
+ sage: F = factor(-10); F
1376
+ -1 * 2 * 5
1377
+ sage: F.is_integral()
1378
+ True
1379
+
1380
+ sage: F = factor(-10) / factor(16); F
1381
+ -1 * 2^-3 * 5
1382
+ sage: F.is_integral()
1383
+ False
1384
+ """
1385
+ return all(e >= 0 for p, e in self.__x)
1386
+
1387
+ def radical(self):
1388
+ """
1389
+ Return the factorization of the radical of the value of ``self``.
1390
+
1391
+ First, check that all exponents in the factorization are
1392
+ positive, raise :exc:`ValueError` otherwise. If all exponents are
1393
+ positive, return ``self`` with all exponents set to 1 and with the
1394
+ unit set to 1.
1395
+
1396
+ EXAMPLES::
1397
+
1398
+ sage: F = factor(-100); F
1399
+ -1 * 2^2 * 5^2
1400
+ sage: F.radical()
1401
+ 2 * 5
1402
+ sage: factor(1/2).radical()
1403
+ Traceback (most recent call last):
1404
+ ...
1405
+ ValueError: all exponents in the factorization must be positive
1406
+ """
1407
+ if not all(e > 0 for _, e in self.__x):
1408
+ raise ValueError("all exponents in the factorization must be positive")
1409
+ return Factorization([(p, 1) for p, _ in self.__x], unit=self.unit().parent()(1),
1410
+ cr=self.__cr, sort=False, simplify=False)
1411
+
1412
+ def radical_value(self):
1413
+ """
1414
+ Return the product of the prime factors in ``self``.
1415
+
1416
+ First, check that all exponents in the factorization are
1417
+ positive, raise :exc:`ValueError` otherwise. If all exponents are
1418
+ positive, return the product of the prime factors in ``self``.
1419
+ This should be functionally equivalent to
1420
+ ``self.radical().value()``.
1421
+
1422
+ EXAMPLES::
1423
+
1424
+ sage: F = factor(-100); F
1425
+ -1 * 2^2 * 5^2
1426
+ sage: F.radical_value()
1427
+ 10
1428
+ sage: factor(1/2).radical_value()
1429
+ Traceback (most recent call last):
1430
+ ...
1431
+ ValueError: all exponents in the factorization must be positive
1432
+ """
1433
+ if not all(e > 0 for _, e in self.__x):
1434
+ raise ValueError("all exponents in the factorization must be positive")
1435
+ from sage.misc.misc_c import prod
1436
+ return prod([p for p, _ in self.__x])
1437
+
1438
+ def is_complete_factorization(self):
1439
+ """
1440
+ Return whether this factorization is a complete rather than
1441
+ a partial factorization, i.e., whether all the bases
1442
+ are irreducible.
1443
+
1444
+ EXAMPLES::
1445
+
1446
+ sage: F = 143.factor(limit=9); F
1447
+ 143
1448
+ sage: F.is_complete_factorization()
1449
+ False
1450
+ sage: F = 143.factor(limit=12); F
1451
+ 11 * 13
1452
+ sage: F.is_complete_factorization()
1453
+ True
1454
+ sage: factor(-2006).is_complete_factorization()
1455
+ True
1456
+ """
1457
+ return all(p.is_irreducible() or p.is_unit() for p, _ in self.__x)