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