modules.py 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932
  1. r"""Modules in number fields.
  2. The classes defined here allow us to work with finitely generated, free
  3. modules, whose generators are algebraic numbers.
  4. There is an abstract base class called :py:class:`~.Module`, which has two
  5. concrete subclasses, :py:class:`~.PowerBasis` and :py:class:`~.Submodule`.
  6. Every module is defined by its basis, or set of generators:
  7. * For a :py:class:`~.PowerBasis`, the generators are the first $n$ powers
  8. (starting with the zeroth) of an algebraic integer $\theta$ of degree $n$.
  9. The :py:class:`~.PowerBasis` is constructed by passing the minimal
  10. polynomial of $\theta$.
  11. * For a :py:class:`~.Submodule`, the generators are a set of
  12. $\mathbb{Q}$-linear combinations of the generators of another module. That
  13. other module is then the "parent" of the :py:class:`~.Submodule`. The
  14. coefficients of the $\mathbb{Q}$-linear combinations may be given by an
  15. integer matrix, and a positive integer denominator. Each column of the matrix
  16. defines a generator.
  17. >>> from sympy.polys import Poly, cyclotomic_poly, ZZ
  18. >>> from sympy.abc import x
  19. >>> from sympy.polys.matrices import DomainMatrix, DM
  20. >>> from sympy.polys.numberfields.modules import PowerBasis
  21. >>> T = Poly(cyclotomic_poly(5, x))
  22. >>> A = PowerBasis(T)
  23. >>> print(A)
  24. PowerBasis(x**4 + x**3 + x**2 + x + 1)
  25. >>> B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ), denom=3)
  26. >>> print(B)
  27. Submodule[[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 2]]/3
  28. >>> print(B.parent)
  29. PowerBasis(x**4 + x**3 + x**2 + x + 1)
  30. Thus, every module is either a :py:class:`~.PowerBasis`,
  31. or a :py:class:`~.Submodule`, some ancestor of which is a
  32. :py:class:`~.PowerBasis`. (If ``S`` is a :py:class:`~.Submodule`, then its
  33. ancestors are ``S.parent``, ``S.parent.parent``, and so on).
  34. The :py:class:`~.ModuleElement` class represents a linear combination of the
  35. generators of any module. Critically, the coefficients of this linear
  36. combination are not restricted to be integers, but may be any rational
  37. numbers. This is necessary so that any and all algebraic integers be
  38. representable, starting from the power basis in a primitive element $\theta$
  39. for the number field in question. For example, in a quadratic field
  40. $\mathbb{Q}(\sqrt{d})$ where $d \equiv 1 \mod{4}$, a denominator of $2$ is
  41. needed.
  42. A :py:class:`~.ModuleElement` can be constructed from an integer column vector
  43. and a denominator:
  44. >>> U = Poly(x**2 - 5)
  45. >>> M = PowerBasis(U)
  46. >>> e = M(DM([[1], [1]], ZZ), denom=2)
  47. >>> print(e)
  48. [1, 1]/2
  49. >>> print(e.module)
  50. PowerBasis(x**2 - 5)
  51. The :py:class:`~.PowerBasisElement` class is a subclass of
  52. :py:class:`~.ModuleElement` that represents elements of a
  53. :py:class:`~.PowerBasis`, and adds functionality pertinent to elements
  54. represented directly over powers of the primitive element $\theta$.
  55. Arithmetic with module elements
  56. ===============================
  57. While a :py:class:`~.ModuleElement` represents a linear combination over the
  58. generators of a particular module, recall that every module is either a
  59. :py:class:`~.PowerBasis` or a descendant (along a chain of
  60. :py:class:`~.Submodule` objects) thereof, so that in fact every
  61. :py:class:`~.ModuleElement` represents an algebraic number in some field
  62. $\mathbb{Q}(\theta)$, where $\theta$ is the defining element of some
  63. :py:class:`~.PowerBasis`. It thus makes sense to talk about the number field
  64. to which a given :py:class:`~.ModuleElement` belongs.
  65. This means that any two :py:class:`~.ModuleElement` instances can be added,
  66. subtracted, multiplied, or divided, provided they belong to the same number
  67. field. Similarly, since $\mathbb{Q}$ is a subfield of every number field,
  68. any :py:class:`~.ModuleElement` may be added, multiplied, etc. by any
  69. rational number.
  70. >>> from sympy import QQ
  71. >>> from sympy.polys.numberfields.modules import to_col
  72. >>> T = Poly(cyclotomic_poly(5))
  73. >>> A = PowerBasis(T)
  74. >>> C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  75. >>> e = A(to_col([0, 2, 0, 0]), denom=3)
  76. >>> f = A(to_col([0, 0, 0, 7]), denom=5)
  77. >>> g = C(to_col([1, 1, 1, 1]))
  78. >>> e + f
  79. [0, 10, 0, 21]/15
  80. >>> e - f
  81. [0, 10, 0, -21]/15
  82. >>> e - g
  83. [-9, -7, -9, -9]/3
  84. >>> e + QQ(7, 10)
  85. [21, 20, 0, 0]/30
  86. >>> e * f
  87. [-14, -14, -14, -14]/15
  88. >>> e ** 2
  89. [0, 0, 4, 0]/9
  90. >>> f // g
  91. [7, 7, 7, 7]/15
  92. >>> f * QQ(2, 3)
  93. [0, 0, 0, 14]/15
  94. However, care must be taken with arithmetic operations on
  95. :py:class:`~.ModuleElement`, because the module $C$ to which the result will
  96. belong will be the nearest common ancestor (NCA) of the modules $A$, $B$ to
  97. which the two operands belong, and $C$ may be different from either or both
  98. of $A$ and $B$.
  99. >>> A = PowerBasis(T)
  100. >>> B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  101. >>> C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  102. >>> print((B(0) * C(0)).module == A)
  103. True
  104. Before the arithmetic operation is performed, copies of the two operands are
  105. automatically converted into elements of the NCA (the operands themselves are
  106. not modified). This upward conversion along an ancestor chain is easy: it just
  107. requires the successive multiplication by the defining matrix of each
  108. :py:class:`~.Submodule`.
  109. Conversely, downward conversion, i.e. representing a given
  110. :py:class:`~.ModuleElement` in a submodule, is also supported -- namely by
  111. the :py:meth:`~sympy.polys.numberfields.modules.Submodule.represent` method
  112. -- but is not guaranteed to succeed in general, since the given element may
  113. not belong to the submodule. The main circumstance in which this issue tends
  114. to arise is with multiplication, since modules, while closed under addition,
  115. need not be closed under multiplication.
  116. Multiplication
  117. --------------
  118. Generally speaking, a module need not be closed under multiplication, i.e. need
  119. not form a ring. However, many of the modules we work with in the context of
  120. number fields are in fact rings, and our classes do support multiplication.
  121. Specifically, any :py:class:`~.Module` can attempt to compute its own
  122. multiplication table, but this does not happen unless an attempt is made to
  123. multiply two :py:class:`~.ModuleElement` instances belonging to it.
  124. >>> A = PowerBasis(T)
  125. >>> print(A._mult_tab is None)
  126. True
  127. >>> a = A(0)*A(1)
  128. >>> print(A._mult_tab is None)
  129. False
  130. Every :py:class:`~.PowerBasis` is, by its nature, closed under multiplication,
  131. so instances of :py:class:`~.PowerBasis` can always successfully compute their
  132. multiplication table.
  133. When a :py:class:`~.Submodule` attempts to compute its multiplication table,
  134. it converts each of its own generators into elements of its parent module,
  135. multiplies them there, in every possible pairing, and then tries to
  136. represent the results in itself, i.e. as $\mathbb{Z}$-linear combinations
  137. over its own generators. This will succeed if and only if the submodule is
  138. in fact closed under multiplication.
  139. Module Homomorphisms
  140. ====================
  141. Many important number theoretic algorithms require the calculation of the
  142. kernel of one or more module homomorphisms. Accordingly we have several
  143. lightweight classes, :py:class:`~.ModuleHomomorphism`,
  144. :py:class:`~.ModuleEndomorphism`, :py:class:`~.InnerEndomorphism`, and
  145. :py:class:`~.EndomorphismRing`, which provide the minimal necessary machinery
  146. to support this.
  147. """
  148. from sympy.core.numbers import igcd, ilcm
  149. from sympy.core.symbol import Dummy
  150. from sympy.polys.polytools import Poly
  151. from sympy.polys.densetools import dup_clear_denoms
  152. from sympy.polys.domains.finitefield import FF
  153. from sympy.polys.domains.rationalfield import QQ
  154. from sympy.polys.domains.integerring import ZZ
  155. from sympy.polys.matrices.domainmatrix import DomainMatrix
  156. from sympy.polys.matrices.exceptions import DMBadInputError
  157. from sympy.polys.matrices.normalforms import hermite_normal_form
  158. from sympy.polys.polyerrors import CoercionFailed, UnificationFailed
  159. from sympy.polys.polyutils import IntegerPowerable
  160. from .exceptions import ClosureFailure, MissingUnityError
  161. from .utilities import AlgIntPowers, is_int, is_rat, get_num_denom
  162. def to_col(coeffs):
  163. r"""Transform a list of integer coefficients into a column vector."""
  164. return DomainMatrix([[ZZ(c) for c in coeffs]], (1, len(coeffs)), ZZ).transpose()
  165. class Module:
  166. """
  167. Generic finitely-generated module.
  168. This is an abstract base class, and should not be instantiated directly.
  169. The two concrete subclasses are :py:class:`~.PowerBasis` and
  170. :py:class:`~.Submodule`.
  171. Every :py:class:`~.Submodule` is derived from another module, referenced
  172. by its ``parent`` attribute. If ``S`` is a submodule, then we refer to
  173. ``S.parent``, ``S.parent.parent``, and so on, as the "ancestors" of
  174. ``S``. Thus, every :py:class:`~.Module` is either a
  175. :py:class:`~.PowerBasis` or a :py:class:`~.Submodule`, some ancestor of
  176. which is a :py:class:`~.PowerBasis`.
  177. """
  178. @property
  179. def n(self):
  180. """The number of generators of this module."""
  181. raise NotImplementedError
  182. def mult_tab(self):
  183. """
  184. Get the multiplication table for this module (if closed under mult).
  185. Explanation
  186. ===========
  187. Computes a dictionary ``M`` of dictionaries of lists, representing the
  188. upper triangular half of the multiplication table.
  189. In other words, if ``0 <= i <= j < self.n``, then ``M[i][j]`` is the
  190. list ``c`` of coefficients such that
  191. ``g[i] * g[j] == sum(c[k]*g[k], k in range(self.n))``,
  192. where ``g`` is the list of generators of this module.
  193. If ``j < i`` then ``M[i][j]`` is undefined.
  194. Examples
  195. ========
  196. >>> from sympy.polys import Poly, cyclotomic_poly
  197. >>> from sympy.polys.numberfields.modules import PowerBasis
  198. >>> T = Poly(cyclotomic_poly(5))
  199. >>> A = PowerBasis(T)
  200. >>> print(A.mult_tab()) # doctest: +SKIP
  201. {0: {0: [1, 0, 0, 0], 1: [0, 1, 0, 0], 2: [0, 0, 1, 0], 3: [0, 0, 0, 1]},
  202. 1: {1: [0, 0, 1, 0], 2: [0, 0, 0, 1], 3: [-1, -1, -1, -1]},
  203. 2: {2: [-1, -1, -1, -1], 3: [1, 0, 0, 0]},
  204. 3: {3: [0, 1, 0, 0]}}
  205. Returns
  206. =======
  207. dict of dict of lists
  208. Raises
  209. ======
  210. ClosureFailure
  211. If the module is not closed under multiplication.
  212. """
  213. raise NotImplementedError
  214. @property
  215. def parent(self):
  216. """
  217. The parent module, if any, for this module.
  218. Explanation
  219. ===========
  220. For a :py:class:`~.Submodule` this is its ``parent`` attribute; for a
  221. :py:class:`~.PowerBasis` this is ``None``.
  222. Returns
  223. =======
  224. :py:class:`~.Module`, ``None``
  225. See Also
  226. ========
  227. Module
  228. """
  229. return None
  230. def represent(self, elt):
  231. r"""
  232. Represent a module element as an integer-linear combination over the
  233. generators of this module.
  234. Explanation
  235. ===========
  236. In our system, to "represent" always means to write a
  237. :py:class:`~.ModuleElement` as a :ref:`ZZ`-linear combination over the
  238. generators of the present :py:class:`~.Module`. Furthermore, the
  239. incoming :py:class:`~.ModuleElement` must belong to an ancestor of
  240. the present :py:class:`~.Module` (or to the present
  241. :py:class:`~.Module` itself).
  242. The most common application is to represent a
  243. :py:class:`~.ModuleElement` in a :py:class:`~.Submodule`. For example,
  244. this is involved in computing multiplication tables.
  245. On the other hand, representing in a :py:class:`~.PowerBasis` is an
  246. odd case, and one which tends not to arise in practice, except for
  247. example when using a :py:class:`~.ModuleEndomorphism` on a
  248. :py:class:`~.PowerBasis`.
  249. In such a case, (1) the incoming :py:class:`~.ModuleElement` must
  250. belong to the :py:class:`~.PowerBasis` itself (since the latter has no
  251. proper ancestors) and (2) it is "representable" iff it belongs to
  252. $\mathbb{Z}[\theta]$ (although generally a
  253. :py:class:`~.PowerBasisElement` may represent any element of
  254. $\mathbb{Q}(\theta)$, i.e. any algebraic number).
  255. Examples
  256. ========
  257. >>> from sympy import Poly, cyclotomic_poly
  258. >>> from sympy.polys.numberfields.modules import PowerBasis, to_col
  259. >>> from sympy.abc import zeta
  260. >>> T = Poly(cyclotomic_poly(5))
  261. >>> A = PowerBasis(T)
  262. >>> a = A(to_col([2, 4, 6, 8]))
  263. The :py:class:`~.ModuleElement` ``a`` has all even coefficients.
  264. If we represent ``a`` in the submodule ``B = 2*A``, the coefficients in
  265. the column vector will be halved:
  266. >>> B = A.submodule_from_gens([2*A(i) for i in range(4)])
  267. >>> b = B.represent(a)
  268. >>> print(b.transpose()) # doctest: +SKIP
  269. DomainMatrix([[1, 2, 3, 4]], (1, 4), ZZ)
  270. However, the element of ``B`` so defined still represents the same
  271. algebraic number:
  272. >>> print(a.poly(zeta).as_expr())
  273. 8*zeta**3 + 6*zeta**2 + 4*zeta + 2
  274. >>> print(B(b).over_power_basis().poly(zeta).as_expr())
  275. 8*zeta**3 + 6*zeta**2 + 4*zeta + 2
  276. Parameters
  277. ==========
  278. elt : :py:class:`~.ModuleElement`
  279. The module element to be represented. Must belong to some ancestor
  280. module of this module (including this module itself).
  281. Returns
  282. =======
  283. :py:class:`~.DomainMatrix` over :ref:`ZZ`
  284. This will be a column vector, representing the coefficients of a
  285. linear combination of this module's generators, which equals the
  286. given element.
  287. Raises
  288. ======
  289. ClosureFailure
  290. If the given element cannot be represented as a :ref:`ZZ`-linear
  291. combination over this module.
  292. See Also
  293. ========
  294. .Submodule.represent
  295. .PowerBasis.represent
  296. """
  297. raise NotImplementedError
  298. def ancestors(self, include_self=False):
  299. """
  300. Return the list of ancestor modules of this module, from the
  301. foundational :py:class:`~.PowerBasis` downward, optionally including
  302. ``self``.
  303. See Also
  304. ========
  305. Module
  306. """
  307. c = self.parent
  308. a = [] if c is None else c.ancestors(include_self=True)
  309. if include_self:
  310. a.append(self)
  311. return a
  312. def power_basis_ancestor(self):
  313. """
  314. Return the :py:class:`~.PowerBasis` that is an ancestor of this module.
  315. See Also
  316. ========
  317. Module
  318. """
  319. if isinstance(self, PowerBasis):
  320. return self
  321. c = self.parent
  322. if c is not None:
  323. return c.power_basis_ancestor()
  324. return None
  325. def nearest_common_ancestor(self, other):
  326. """
  327. Locate the nearest common ancestor of this module and another.
  328. Returns
  329. =======
  330. :py:class:`~.Module`, ``None``
  331. See Also
  332. ========
  333. Module
  334. """
  335. sA = self.ancestors(include_self=True)
  336. oA = other.ancestors(include_self=True)
  337. nca = None
  338. for sa, oa in zip(sA, oA):
  339. if sa == oa:
  340. nca = sa
  341. else:
  342. break
  343. return nca
  344. def is_compat_col(self, col):
  345. """Say whether *col* is a suitable column vector for this module."""
  346. return isinstance(col, DomainMatrix) and col.shape == (self.n, 1) and col.domain.is_ZZ
  347. def __call__(self, spec, denom=1):
  348. r"""
  349. Generate a :py:class:`~.ModuleElement` belonging to this module.
  350. Examples
  351. ========
  352. >>> from sympy.polys import Poly, cyclotomic_poly
  353. >>> from sympy.polys.numberfields.modules import PowerBasis, to_col
  354. >>> T = Poly(cyclotomic_poly(5))
  355. >>> A = PowerBasis(T)
  356. >>> e = A(to_col([1, 2, 3, 4]), denom=3)
  357. >>> print(e) # doctest: +SKIP
  358. [1, 2, 3, 4]/3
  359. >>> f = A(2)
  360. >>> print(f) # doctest: +SKIP
  361. [0, 0, 1, 0]
  362. Parameters
  363. ==========
  364. spec : :py:class:`~.DomainMatrix`, int
  365. Specifies the numerators of the coefficients of the
  366. :py:class:`~.ModuleElement`. Can be either a column vector over
  367. :ref:`ZZ`, whose length must equal the number $n$ of generators of
  368. this module, or else an integer ``j``, $0 \leq j < n$, which is a
  369. shorthand for column $j$ of $I_n$, the $n \times n$ identity
  370. matrix.
  371. denom : int, optional (default=1)
  372. Denominator for the coefficients of the
  373. :py:class:`~.ModuleElement`.
  374. Returns
  375. =======
  376. :py:class:`~.ModuleElement`
  377. The coefficients are the entries of the *spec* vector, divided by
  378. *denom*.
  379. """
  380. if isinstance(spec, int) and 0 <= spec < self.n:
  381. spec = DomainMatrix.eye(self.n, ZZ)[:, spec].to_dense()
  382. if not self.is_compat_col(spec):
  383. raise ValueError('Compatible column vector required.')
  384. return make_mod_elt(self, spec, denom=denom)
  385. def starts_with_unity(self):
  386. """Say whether the module's first generator equals unity."""
  387. raise NotImplementedError
  388. def basis_elements(self):
  389. """
  390. Get list of :py:class:`~.ModuleElement` being the generators of this
  391. module.
  392. """
  393. return [self(j) for j in range(self.n)]
  394. def zero(self):
  395. """Return a :py:class:`~.ModuleElement` representing zero."""
  396. return self(0) * 0
  397. def one(self):
  398. """
  399. Return a :py:class:`~.ModuleElement` representing unity,
  400. and belonging to the first ancestor of this module (including
  401. itself) that starts with unity.
  402. """
  403. return self.element_from_rational(1)
  404. def element_from_rational(self, a):
  405. """
  406. Return a :py:class:`~.ModuleElement` representing a rational number.
  407. Explanation
  408. ===========
  409. The returned :py:class:`~.ModuleElement` will belong to the first
  410. module on this module's ancestor chain (including this module
  411. itself) that starts with unity.
  412. Examples
  413. ========
  414. >>> from sympy.polys import Poly, cyclotomic_poly, QQ
  415. >>> from sympy.polys.numberfields.modules import PowerBasis
  416. >>> T = Poly(cyclotomic_poly(5))
  417. >>> A = PowerBasis(T)
  418. >>> a = A.element_from_rational(QQ(2, 3))
  419. >>> print(a) # doctest: +SKIP
  420. [2, 0, 0, 0]/3
  421. Parameters
  422. ==========
  423. a : int, :ref:`ZZ`, :ref:`QQ`
  424. Returns
  425. =======
  426. :py:class:`~.ModuleElement`
  427. """
  428. raise NotImplementedError
  429. def submodule_from_gens(self, gens, hnf=True, hnf_modulus=None):
  430. """
  431. Form the submodule generated by a list of :py:class:`~.ModuleElement`
  432. belonging to this module.
  433. Examples
  434. ========
  435. >>> from sympy.polys import Poly, cyclotomic_poly
  436. >>> from sympy.polys.numberfields.modules import PowerBasis
  437. >>> T = Poly(cyclotomic_poly(5))
  438. >>> A = PowerBasis(T)
  439. >>> gens = [A(0), 2*A(1), 3*A(2), 4*A(3)//5]
  440. >>> B = A.submodule_from_gens(gens)
  441. >>> print(B) # doctest: +SKIP
  442. Submodule[[5, 0, 0, 0], [0, 10, 0, 0], [0, 0, 15, 0], [0, 0, 0, 4]]/5
  443. Parameters
  444. ==========
  445. gens : list of :py:class:`~.ModuleElement` belonging to this module.
  446. hnf : boolean, optional (default=True)
  447. If True, we will reduce the matrix into Hermite Normal Form before
  448. forming the :py:class:`~.Submodule`.
  449. hnf_modulus : int, None, optional (default=None)
  450. Modulus for use in the HNF reduction algorithm. See
  451. :py:func:`~sympy.polys.matrices.normalforms.hermite_normal_form`.
  452. Returns
  453. =======
  454. :py:class:`~.Submodule`
  455. See Also
  456. ========
  457. submodule_from_matrix
  458. """
  459. if not all(g.module == self for g in gens):
  460. raise ValueError('Generators must belong to this module.')
  461. n = len(gens)
  462. if n == 0:
  463. raise ValueError('Need at least one generator.')
  464. m = gens[0].n
  465. d = gens[0].denom if n == 1 else ilcm(*[g.denom for g in gens])
  466. B = DomainMatrix.zeros((m, 0), ZZ).hstack(*[(d // g.denom) * g.col for g in gens])
  467. if hnf:
  468. B = hermite_normal_form(B, D=hnf_modulus)
  469. return self.submodule_from_matrix(B, denom=d)
  470. def submodule_from_matrix(self, B, denom=1):
  471. """
  472. Form the submodule generated by the elements of this module indicated
  473. by the columns of a matrix, with an optional denominator.
  474. Examples
  475. ========
  476. >>> from sympy.polys import Poly, cyclotomic_poly, ZZ
  477. >>> from sympy.polys.matrices import DM
  478. >>> from sympy.polys.numberfields.modules import PowerBasis
  479. >>> T = Poly(cyclotomic_poly(5))
  480. >>> A = PowerBasis(T)
  481. >>> B = A.submodule_from_matrix(DM([
  482. ... [0, 10, 0, 0],
  483. ... [0, 0, 7, 0],
  484. ... ], ZZ).transpose(), denom=15)
  485. >>> print(B) # doctest: +SKIP
  486. Submodule[[0, 10, 0, 0], [0, 0, 7, 0]]/15
  487. Parameters
  488. ==========
  489. B : :py:class:`~.DomainMatrix` over :ref:`ZZ`
  490. Each column gives the numerators of the coefficients of one
  491. generator of the submodule. Thus, the number of rows of *B* must
  492. equal the number of generators of the present module.
  493. denom : int, optional (default=1)
  494. Common denominator for all generators of the submodule.
  495. Returns
  496. =======
  497. :py:class:`~.Submodule`
  498. Raises
  499. ======
  500. ValueError
  501. If the given matrix *B* is not over :ref:`ZZ` or its number of rows
  502. does not equal the number of generators of the present module.
  503. See Also
  504. ========
  505. submodule_from_gens
  506. """
  507. m, n = B.shape
  508. if not B.domain.is_ZZ:
  509. raise ValueError('Matrix must be over ZZ.')
  510. if not m == self.n:
  511. raise ValueError('Matrix row count must match base module.')
  512. return Submodule(self, B, denom=denom)
  513. def whole_submodule(self):
  514. """
  515. Return a submodule equal to this entire module.
  516. Explanation
  517. ===========
  518. This is useful when you have a :py:class:`~.PowerBasis` and want to
  519. turn it into a :py:class:`~.Submodule` (in order to use methods
  520. belonging to the latter).
  521. """
  522. B = DomainMatrix.eye(self.n, ZZ)
  523. return self.submodule_from_matrix(B)
  524. def endomorphism_ring(self):
  525. """Form the :py:class:`~.EndomorphismRing` for this module."""
  526. return EndomorphismRing(self)
  527. class PowerBasis(Module):
  528. """The module generated by the powers of an algebraic integer."""
  529. def __init__(self, T):
  530. """
  531. Parameters
  532. ==========
  533. T : :py:class:`~.Poly`
  534. The monic, irreducible, univariate polynomial over :ref:`ZZ`, a
  535. root of which is the generator of the power basis.
  536. """
  537. self.T = T
  538. self._n = T.degree()
  539. self._mult_tab = None
  540. def __repr__(self):
  541. return f'PowerBasis({self.T.as_expr()})'
  542. def __eq__(self, other):
  543. if isinstance(other, PowerBasis):
  544. return self.T == other.T
  545. return NotImplemented
  546. @property
  547. def n(self):
  548. return self._n
  549. def mult_tab(self):
  550. if self._mult_tab is None:
  551. self.compute_mult_tab()
  552. return self._mult_tab
  553. def compute_mult_tab(self):
  554. theta_pow = AlgIntPowers(self.T)
  555. M = {}
  556. n = self.n
  557. for u in range(n):
  558. M[u] = {}
  559. for v in range(u, n):
  560. M[u][v] = theta_pow[u + v]
  561. self._mult_tab = M
  562. def represent(self, elt):
  563. r"""
  564. Represent a module element as an integer-linear combination over the
  565. generators of this module.
  566. See Also
  567. ========
  568. .Module.represent
  569. .Submodule.represent
  570. """
  571. if elt.module == self and elt.denom == 1:
  572. return elt.column()
  573. else:
  574. raise ClosureFailure('Element not representable in ZZ[theta].')
  575. def starts_with_unity(self):
  576. return True
  577. def element_from_rational(self, a):
  578. return self(0) * a
  579. def element_from_poly(self, f):
  580. """
  581. Produce an element of this module, representing *f* after reduction mod
  582. our defining minimal polynomial.
  583. Parameters
  584. ==========
  585. f : :py:class:`~.Poly` over :ref:`ZZ` in same var as our defining poly.
  586. Returns
  587. =======
  588. :py:class:`~.PowerBasisElement`
  589. """
  590. n, k = self.n, f.degree()
  591. if k >= n:
  592. f = f % self.T
  593. if f == 0:
  594. return self.zero()
  595. d, c = dup_clear_denoms(f.rep.rep, QQ, convert=True)
  596. c = list(reversed(c))
  597. ell = len(c)
  598. z = [ZZ(0)] * (n - ell)
  599. col = to_col(c + z)
  600. return self(col, denom=d)
  601. class Submodule(Module, IntegerPowerable):
  602. """A submodule of another module."""
  603. def __init__(self, parent, matrix, denom=1, mult_tab=None):
  604. """
  605. Parameters
  606. ==========
  607. parent : :py:class:`~.Module`
  608. The module from which this one is derived.
  609. matrix : :py:class:`~.DomainMatrix` over :ref:`ZZ`
  610. The matrix whose columns define this submodule's generators as
  611. linear combinations over the parent's generators.
  612. denom : int, optional (default=1)
  613. Denominator for the coefficients given by the matrix.
  614. mult_tab : dict, ``None``, optional
  615. If already known, the multiplication table for this module may be
  616. supplied.
  617. """
  618. self._parent = parent
  619. self._matrix = matrix
  620. self._denom = denom
  621. self._mult_tab = mult_tab
  622. self._n = matrix.shape[1]
  623. self._QQ_matrix = None
  624. self._starts_with_unity = None
  625. self._is_sq_maxrank_HNF = None
  626. def __repr__(self):
  627. r = 'Submodule' + repr(self.matrix.transpose().to_Matrix().tolist())
  628. if self.denom > 1:
  629. r += f'/{self.denom}'
  630. return r
  631. def reduced(self):
  632. """
  633. Produce a reduced version of this submodule.
  634. Explanation
  635. ===========
  636. In the reduced version, it is guaranteed that 1 is the only positive
  637. integer dividing both the submodule's denominator, and every entry in
  638. the submodule's matrix.
  639. Returns
  640. =======
  641. :py:class:`~.Submodule`
  642. """
  643. if self.denom == 1:
  644. return self
  645. g = igcd(self.denom, *self.coeffs)
  646. if g == 1:
  647. return self
  648. return type(self)(self.parent, (self.matrix / g).convert_to(ZZ), denom=self.denom // g, mult_tab=self._mult_tab)
  649. def discard_before(self, r):
  650. """
  651. Produce a new module by discarding all generators before a given
  652. index *r*.
  653. """
  654. W = self.matrix[:, r:]
  655. s = self.n - r
  656. M = None
  657. mt = self._mult_tab
  658. if mt is not None:
  659. M = {}
  660. for u in range(s):
  661. M[u] = {}
  662. for v in range(u, s):
  663. M[u][v] = mt[r + u][r + v][r:]
  664. return Submodule(self.parent, W, denom=self.denom, mult_tab=M)
  665. @property
  666. def n(self):
  667. return self._n
  668. def mult_tab(self):
  669. if self._mult_tab is None:
  670. self.compute_mult_tab()
  671. return self._mult_tab
  672. def compute_mult_tab(self):
  673. gens = self.basis_element_pullbacks()
  674. M = {}
  675. n = self.n
  676. for u in range(n):
  677. M[u] = {}
  678. for v in range(u, n):
  679. M[u][v] = self.represent(gens[u] * gens[v]).flat()
  680. self._mult_tab = M
  681. @property
  682. def parent(self):
  683. return self._parent
  684. @property
  685. def matrix(self):
  686. return self._matrix
  687. @property
  688. def coeffs(self):
  689. return self.matrix.flat()
  690. @property
  691. def denom(self):
  692. return self._denom
  693. @property
  694. def QQ_matrix(self):
  695. """
  696. :py:class:`~.DomainMatrix` over :ref:`QQ`, equal to
  697. ``self.matrix / self.denom``, and guaranteed to be dense.
  698. Explanation
  699. ===========
  700. Depending on how it is formed, a :py:class:`~.DomainMatrix` may have
  701. an internal representation that is sparse or dense. We guarantee a
  702. dense representation here, so that tests for equivalence of submodules
  703. always come out as expected.
  704. Examples
  705. ========
  706. >>> from sympy.polys import Poly, cyclotomic_poly, ZZ
  707. >>> from sympy.abc import x
  708. >>> from sympy.polys.matrices import DomainMatrix
  709. >>> from sympy.polys.numberfields.modules import PowerBasis
  710. >>> T = Poly(cyclotomic_poly(5, x))
  711. >>> A = PowerBasis(T)
  712. >>> B = A.submodule_from_matrix(3*DomainMatrix.eye(4, ZZ), denom=6)
  713. >>> C = A.submodule_from_matrix(DomainMatrix.eye(4, ZZ), denom=2)
  714. >>> print(B.QQ_matrix == C.QQ_matrix)
  715. True
  716. Returns
  717. =======
  718. :py:class:`~.DomainMatrix` over :ref:`QQ`
  719. """
  720. if self._QQ_matrix is None:
  721. self._QQ_matrix = (self.matrix / self.denom).to_dense()
  722. return self._QQ_matrix
  723. def starts_with_unity(self):
  724. if self._starts_with_unity is None:
  725. self._starts_with_unity = self(0).equiv(1)
  726. return self._starts_with_unity
  727. def is_sq_maxrank_HNF(self):
  728. if self._is_sq_maxrank_HNF is None:
  729. self._is_sq_maxrank_HNF = is_sq_maxrank_HNF(self._matrix)
  730. return self._is_sq_maxrank_HNF
  731. def is_power_basis_submodule(self):
  732. return isinstance(self.parent, PowerBasis)
  733. def element_from_rational(self, a):
  734. if self.starts_with_unity():
  735. return self(0) * a
  736. else:
  737. return self.parent.element_from_rational(a)
  738. def basis_element_pullbacks(self):
  739. """
  740. Return list of this submodule's basis elements as elements of the
  741. submodule's parent module.
  742. """
  743. return [e.to_parent() for e in self.basis_elements()]
  744. def represent(self, elt):
  745. """
  746. Represent a module element as an integer-linear combination over the
  747. generators of this module.
  748. See Also
  749. ========
  750. .Module.represent
  751. .PowerBasis.represent
  752. """
  753. if elt.module == self:
  754. return elt.column()
  755. elif elt.module == self.parent:
  756. try:
  757. # The given element should be a ZZ-linear combination over our
  758. # basis vectors; however, due to the presence of denominators,
  759. # we need to solve over QQ.
  760. A = self.QQ_matrix
  761. b = elt.QQ_col
  762. x = A._solve(b)[0].transpose()
  763. x = x.convert_to(ZZ)
  764. except DMBadInputError:
  765. raise ClosureFailure('Element outside QQ-span of this basis.')
  766. except CoercionFailed:
  767. raise ClosureFailure('Element in QQ-span but not ZZ-span of this basis.')
  768. return x
  769. elif isinstance(self.parent, Submodule):
  770. coeffs_in_parent = self.parent.represent(elt)
  771. parent_element = self.parent(coeffs_in_parent)
  772. return self.represent(parent_element)
  773. else:
  774. raise ClosureFailure('Element outside ancestor chain of this module.')
  775. def is_compat_submodule(self, other):
  776. return isinstance(other, Submodule) and other.parent == self.parent
  777. def __eq__(self, other):
  778. if self.is_compat_submodule(other):
  779. return other.QQ_matrix == self.QQ_matrix
  780. return NotImplemented
  781. def add(self, other, hnf=True, hnf_modulus=None):
  782. """
  783. Add this :py:class:`~.Submodule` to another.
  784. Explanation
  785. ===========
  786. This represents the module generated by the union of the two modules'
  787. sets of generators.
  788. Parameters
  789. ==========
  790. other : :py:class:`~.Submodule`
  791. hnf : boolean, optional (default=True)
  792. If ``True``, reduce the matrix of the combined module to its
  793. Hermite Normal Form.
  794. hnf_modulus : :ref:`ZZ`, None, optional
  795. If a positive integer is provided, use this as modulus in the
  796. HNF reduction. See
  797. :py:func:`~sympy.polys.matrices.normalforms.hermite_normal_form`.
  798. Returns
  799. =======
  800. :py:class:`~.Submodule`
  801. """
  802. d, e = self.denom, other.denom
  803. m = ilcm(d, e)
  804. a, b = m // d, m // e
  805. B = (a * self.matrix).hstack(b * other.matrix)
  806. if hnf:
  807. B = hermite_normal_form(B, D=hnf_modulus)
  808. return self.parent.submodule_from_matrix(B, denom=m)
  809. def __add__(self, other):
  810. if self.is_compat_submodule(other):
  811. return self.add(other)
  812. return NotImplemented
  813. __radd__ = __add__
  814. def mul(self, other, hnf=True, hnf_modulus=None):
  815. """
  816. Multiply this :py:class:`~.Submodule` by a rational number, a
  817. :py:class:`~.ModuleElement`, or another :py:class:`~.Submodule`.
  818. Explanation
  819. ===========
  820. To multiply by a rational number or :py:class:`~.ModuleElement` means
  821. to form the submodule whose generators are the products of this
  822. quantity with all the generators of the present submodule.
  823. To multiply by another :py:class:`~.Submodule` means to form the
  824. submodule whose generators are all the products of one generator from
  825. the one submodule, and one generator from the other.
  826. Parameters
  827. ==========
  828. other : int, :ref:`ZZ`, :ref:`QQ`, :py:class:`~.ModuleElement`, :py:class:`~.Submodule`
  829. hnf : boolean, optional (default=True)
  830. If ``True``, reduce the matrix of the product module to its
  831. Hermite Normal Form.
  832. hnf_modulus : :ref:`ZZ`, None, optional
  833. If a positive integer is provided, use this as modulus in the
  834. HNF reduction. See
  835. :py:func:`~sympy.polys.matrices.normalforms.hermite_normal_form`.
  836. Returns
  837. =======
  838. :py:class:`~.Submodule`
  839. """
  840. if is_rat(other):
  841. a, b = get_num_denom(other)
  842. if a == b == 1:
  843. return self
  844. else:
  845. return Submodule(self.parent,
  846. self.matrix * a, denom=self.denom * b,
  847. mult_tab=None).reduced()
  848. elif isinstance(other, ModuleElement) and other.module == self.parent:
  849. # The submodule is multiplied by an element of the parent module.
  850. # We presume this means we want a new submodule of the parent module.
  851. gens = [other * e for e in self.basis_element_pullbacks()]
  852. return self.parent.submodule_from_gens(gens, hnf=hnf, hnf_modulus=hnf_modulus)
  853. elif self.is_compat_submodule(other):
  854. # This case usually means you're multiplying ideals, and want another
  855. # ideal, i.e. another submodule of the same parent module.
  856. alphas, betas = self.basis_element_pullbacks(), other.basis_element_pullbacks()
  857. gens = [a * b for a in alphas for b in betas]
  858. return self.parent.submodule_from_gens(gens, hnf=hnf, hnf_modulus=hnf_modulus)
  859. return NotImplemented
  860. def __mul__(self, other):
  861. return self.mul(other)
  862. __rmul__ = __mul__
  863. def _first_power(self):
  864. return self
  865. def is_sq_maxrank_HNF(dm):
  866. r"""
  867. Say whether a :py:class:`~.DomainMatrix` is in that special case of Hermite
  868. Normal Form, in which the matrix is also square and of maximal rank.
  869. Explanation
  870. ===========
  871. We commonly work with :py:class:`~.Submodule` instances whose matrix is in
  872. this form, and it can be useful to be able to check that this condition is
  873. satisfied.
  874. For example this is the case with the :py:class:`~.Submodule` ``ZK``
  875. returned by :py:func:`~sympy.polys.numberfields.basis.round_two`, which
  876. represents the maximal order in a number field, and with ideals formed
  877. therefrom, such as ``2 * ZK``.
  878. """
  879. if dm.domain.is_ZZ and dm.is_square and dm.is_upper:
  880. n = dm.shape[0]
  881. for i in range(n):
  882. d = dm[i, i].element
  883. if d <= 0:
  884. return False
  885. for j in range(i + 1, n):
  886. if not (0 <= dm[i, j].element < d):
  887. return False
  888. return True
  889. return False
  890. def make_mod_elt(module, col, denom=1):
  891. r"""
  892. Factory function which builds a :py:class:`~.ModuleElement`, but ensures
  893. that it is a :py:class:`~.PowerBasisElement` if the module is a
  894. :py:class:`~.PowerBasis`.
  895. """
  896. if isinstance(module, PowerBasis):
  897. return PowerBasisElement(module, col, denom=denom)
  898. else:
  899. return ModuleElement(module, col, denom=denom)
  900. class ModuleElement(IntegerPowerable):
  901. r"""
  902. Represents an element of a :py:class:`~.Module`.
  903. NOTE: Should not be constructed directly. Use the
  904. :py:meth:`~.Module.__call__` method or the :py:func:`make_mod_elt()`
  905. factory function instead.
  906. """
  907. def __init__(self, module, col, denom=1):
  908. """
  909. Parameters
  910. ==========
  911. module : :py:class:`~.Module`
  912. The module to which this element belongs.
  913. col : :py:class:`~.DomainMatrix` over :ref:`ZZ`
  914. Column vector giving the numerators of the coefficients of this
  915. element.
  916. denom : int, optional (default=1)
  917. Denominator for the coefficients of this element.
  918. """
  919. self.module = module
  920. self.col = col
  921. self.denom = denom
  922. self._QQ_col = None
  923. def __repr__(self):
  924. r = str([int(c) for c in self.col.flat()])
  925. if self.denom > 1:
  926. r += f'/{self.denom}'
  927. return r
  928. def reduced(self):
  929. """
  930. Produce a reduced version of this ModuleElement, i.e. one in which the
  931. gcd of the denominator together with all numerator coefficients is 1.
  932. """
  933. if self.denom == 1:
  934. return self
  935. g = igcd(self.denom, *self.coeffs)
  936. if g == 1:
  937. return self
  938. return type(self)(self.module,
  939. (self.col / g).convert_to(ZZ),
  940. denom=self.denom // g)
  941. def reduced_mod_p(self, p):
  942. """
  943. Produce a version of this :py:class:`~.ModuleElement` in which all
  944. numerator coefficients have been reduced mod *p*.
  945. """
  946. return make_mod_elt(self.module,
  947. self.col.convert_to(FF(p)).convert_to(ZZ),
  948. denom=self.denom)
  949. @classmethod
  950. def from_int_list(cls, module, coeffs, denom=1):
  951. """
  952. Make a :py:class:`~.ModuleElement` from a list of ints (instead of a
  953. column vector).
  954. """
  955. col = to_col(coeffs)
  956. return cls(module, col, denom=denom)
  957. @property
  958. def n(self):
  959. """The length of this element's column."""
  960. return self.module.n
  961. def __len__(self):
  962. return self.n
  963. def column(self, domain=None):
  964. """
  965. Get a copy of this element's column, optionally converting to a domain.
  966. """
  967. return self.col.convert_to(domain)
  968. @property
  969. def coeffs(self):
  970. return self.col.flat()
  971. @property
  972. def QQ_col(self):
  973. """
  974. :py:class:`~.DomainMatrix` over :ref:`QQ`, equal to
  975. ``self.col / self.denom``, and guaranteed to be dense.
  976. See Also
  977. ========
  978. .Submodule.QQ_matrix
  979. """
  980. if self._QQ_col is None:
  981. self._QQ_col = (self.col / self.denom).to_dense()
  982. return self._QQ_col
  983. def to_parent(self):
  984. """
  985. Transform into a :py:class:`~.ModuleElement` belonging to the parent of
  986. this element's module.
  987. """
  988. if not isinstance(self.module, Submodule):
  989. raise ValueError('Not an element of a Submodule.')
  990. return make_mod_elt(
  991. self.module.parent, self.module.matrix * self.col,
  992. denom=self.module.denom * self.denom)
  993. def to_ancestor(self, anc):
  994. """
  995. Transform into a :py:class:`~.ModuleElement` belonging to a given
  996. ancestor of this element's module.
  997. Parameters
  998. ==========
  999. anc : :py:class:`~.Module`
  1000. """
  1001. if anc == self.module:
  1002. return self
  1003. else:
  1004. return self.to_parent().to_ancestor(anc)
  1005. def over_power_basis(self):
  1006. """
  1007. Transform into a :py:class:`~.PowerBasisElement` over our
  1008. :py:class:`~.PowerBasis` ancestor.
  1009. """
  1010. e = self
  1011. while not isinstance(e.module, PowerBasis):
  1012. e = e.to_parent()
  1013. return e
  1014. def is_compat(self, other):
  1015. """
  1016. Test whether other is another :py:class:`~.ModuleElement` with same
  1017. module.
  1018. """
  1019. return isinstance(other, ModuleElement) and other.module == self.module
  1020. def unify(self, other):
  1021. """
  1022. Try to make a compatible pair of :py:class:`~.ModuleElement`, one
  1023. equivalent to this one, and one equivalent to the other.
  1024. Explanation
  1025. ===========
  1026. We search for the nearest common ancestor module for the pair of
  1027. elements, and represent each one there.
  1028. Returns
  1029. =======
  1030. Pair ``(e1, e2)``
  1031. Each ``ei`` is a :py:class:`~.ModuleElement`, they belong to the
  1032. same :py:class:`~.Module`, ``e1`` is equivalent to ``self``, and
  1033. ``e2`` is equivalent to ``other``.
  1034. Raises
  1035. ======
  1036. UnificationFailed
  1037. If ``self`` and ``other`` have no common ancestor module.
  1038. """
  1039. if self.module == other.module:
  1040. return self, other
  1041. nca = self.module.nearest_common_ancestor(other.module)
  1042. if nca is not None:
  1043. return self.to_ancestor(nca), other.to_ancestor(nca)
  1044. raise UnificationFailed(f"Cannot unify {self} with {other}")
  1045. def __eq__(self, other):
  1046. if self.is_compat(other):
  1047. return self.QQ_col == other.QQ_col
  1048. return NotImplemented
  1049. def equiv(self, other):
  1050. """
  1051. A :py:class:`~.ModuleElement` may test as equivalent to a rational
  1052. number or another :py:class:`~.ModuleElement`, if they represent the
  1053. same algebraic number.
  1054. Explanation
  1055. ===========
  1056. This method is intended to check equivalence only in those cases in
  1057. which it is easy to test; namely, when *other* is either a
  1058. :py:class:`~.ModuleElement` that can be unified with this one (i.e. one
  1059. which shares a common :py:class:`~.PowerBasis` ancestor), or else a
  1060. rational number (which is easy because every :py:class:`~.PowerBasis`
  1061. represents every rational number).
  1062. Parameters
  1063. ==========
  1064. other : int, :ref:`ZZ`, :ref:`QQ`, :py:class:`~.ModuleElement`
  1065. Returns
  1066. =======
  1067. bool
  1068. Raises
  1069. ======
  1070. UnificationFailed
  1071. If ``self`` and ``other`` do not share a common
  1072. :py:class:`~.PowerBasis` ancestor.
  1073. """
  1074. if self == other:
  1075. return True
  1076. elif isinstance(other, ModuleElement):
  1077. a, b = self.unify(other)
  1078. return a == b
  1079. elif is_rat(other):
  1080. if isinstance(self, PowerBasisElement):
  1081. return self == self.module(0) * other
  1082. else:
  1083. return self.over_power_basis().equiv(other)
  1084. return False
  1085. def __add__(self, other):
  1086. """
  1087. A :py:class:`~.ModuleElement` can be added to a rational number, or to
  1088. another :py:class:`~.ModuleElement`.
  1089. Explanation
  1090. ===========
  1091. When the other summand is a rational number, it will be converted into
  1092. a :py:class:`~.ModuleElement` (belonging to the first ancestor of this
  1093. module that starts with unity).
  1094. In all cases, the sum belongs to the nearest common ancestor (NCA) of
  1095. the modules of the two summands. If the NCA does not exist, we return
  1096. ``NotImplemented``.
  1097. """
  1098. if self.is_compat(other):
  1099. d, e = self.denom, other.denom
  1100. m = ilcm(d, e)
  1101. u, v = m // d, m // e
  1102. col = to_col([u * a + v * b for a, b in zip(self.coeffs, other.coeffs)])
  1103. return type(self)(self.module, col, denom=m).reduced()
  1104. elif isinstance(other, ModuleElement):
  1105. try:
  1106. a, b = self.unify(other)
  1107. except UnificationFailed:
  1108. return NotImplemented
  1109. return a + b
  1110. elif is_rat(other):
  1111. return self + self.module.element_from_rational(other)
  1112. return NotImplemented
  1113. __radd__ = __add__
  1114. def __neg__(self):
  1115. return self * -1
  1116. def __sub__(self, other):
  1117. return self + (-other)
  1118. def __rsub__(self, other):
  1119. return -self + other
  1120. def __mul__(self, other):
  1121. """
  1122. A :py:class:`~.ModuleElement` can be multiplied by a rational number,
  1123. or by another :py:class:`~.ModuleElement`.
  1124. Explanation
  1125. ===========
  1126. When the multiplier is a rational number, the product is computed by
  1127. operating directly on the coefficients of this
  1128. :py:class:`~.ModuleElement`.
  1129. When the multiplier is another :py:class:`~.ModuleElement`, the product
  1130. will belong to the nearest common ancestor (NCA) of the modules of the
  1131. two operands, and that NCA must have a multiplication table. If the NCA
  1132. does not exist, we return ``NotImplemented``. If the NCA does not have
  1133. a mult. table, ``ClosureFailure`` will be raised.
  1134. """
  1135. if self.is_compat(other):
  1136. M = self.module.mult_tab()
  1137. A, B = self.col.flat(), other.col.flat()
  1138. n = self.n
  1139. C = [0] * n
  1140. for u in range(n):
  1141. for v in range(u, n):
  1142. c = A[u] * B[v]
  1143. if v > u:
  1144. c += A[v] * B[u]
  1145. if c != 0:
  1146. R = M[u][v]
  1147. for k in range(n):
  1148. C[k] += c * R[k]
  1149. d = self.denom * other.denom
  1150. return self.from_int_list(self.module, C, denom=d)
  1151. elif isinstance(other, ModuleElement):
  1152. try:
  1153. a, b = self.unify(other)
  1154. except UnificationFailed:
  1155. return NotImplemented
  1156. return a * b
  1157. elif is_rat(other):
  1158. a, b = get_num_denom(other)
  1159. if a == b == 1:
  1160. return self
  1161. else:
  1162. return make_mod_elt(self.module,
  1163. self.col * a, denom=self.denom * b).reduced()
  1164. return NotImplemented
  1165. __rmul__ = __mul__
  1166. def _zeroth_power(self):
  1167. return self.module.one()
  1168. def _first_power(self):
  1169. return self
  1170. def __floordiv__(self, a):
  1171. if is_rat(a):
  1172. a = QQ(a)
  1173. return self * (1/a)
  1174. elif isinstance(a, ModuleElement):
  1175. return self * (1//a)
  1176. return NotImplemented
  1177. def __rfloordiv__(self, a):
  1178. return a // self.over_power_basis()
  1179. def __mod__(self, m):
  1180. r"""
  1181. Reducing a :py:class:`~.ModuleElement` mod an integer *m* reduces all
  1182. numerator coeffs mod $d m$, where $d$ is the denominator of the
  1183. :py:class:`~.ModuleElement`.
  1184. Explanation
  1185. ===========
  1186. Recall that a :py:class:`~.ModuleElement` $b$ represents a
  1187. $\mathbb{Q}$-linear combination over the basis elements
  1188. $\{\beta_0, \beta_1, \ldots, \beta_{n-1}\}$ of a module $B$. It uses a
  1189. common denominator $d$, so that the representation is in the form
  1190. $b=\frac{c_0 \beta_0 + c_1 \beta_1 + \cdots + c_{n-1} \beta_{n-1}}{d}$,
  1191. with $d$ and all $c_i$ in $\mathbb{Z}$, and $d > 0$.
  1192. If we want to work modulo $m B$, this means we want to reduce the
  1193. coefficients of $b$ mod $m$. We can think of reducing an arbitrary
  1194. rational number $r/s$ mod $m$ as adding or subtracting an integer
  1195. multiple of $m$ so that the result is positive and less than $m$.
  1196. But this is equivalent to reducing $r$ mod $m \cdot s$.
  1197. Examples
  1198. ========
  1199. >>> from sympy import Poly, cyclotomic_poly
  1200. >>> from sympy.polys.numberfields.modules import PowerBasis
  1201. >>> T = Poly(cyclotomic_poly(5))
  1202. >>> A = PowerBasis(T)
  1203. >>> a = (A(0) + 15*A(1))//2
  1204. >>> print(a)
  1205. [1, 15, 0, 0]/2
  1206. Here, ``a`` represents the number $\frac{1 + 15\zeta}{2}$. If we reduce
  1207. mod 7,
  1208. >>> print(a % 7)
  1209. [1, 1, 0, 0]/2
  1210. we get $\frac{1 + \zeta}{2}$. Effectively, we subtracted $7 \zeta$.
  1211. But it was achieved by reducing the numerator coefficients mod $14$.
  1212. """
  1213. if is_int(m):
  1214. M = m * self.denom
  1215. col = to_col([c % M for c in self.coeffs])
  1216. return type(self)(self.module, col, denom=self.denom)
  1217. return NotImplemented
  1218. class PowerBasisElement(ModuleElement):
  1219. r"""
  1220. Subclass for :py:class:`~.ModuleElement` instances whose module is a
  1221. :py:class:`~.PowerBasis`.
  1222. """
  1223. @property
  1224. def T(self):
  1225. """Access the defining polynomial of the :py:class:`~.PowerBasis`."""
  1226. return self.module.T
  1227. def numerator(self, x=None):
  1228. """Obtain the numerator as a polynomial over :ref:`ZZ`."""
  1229. x = x or self.T.gen
  1230. return Poly(reversed(self.coeffs), x, domain=ZZ)
  1231. def poly(self, x=None):
  1232. """Obtain the number as a polynomial over :ref:`QQ`."""
  1233. return self.numerator(x=x) // self.denom
  1234. def norm(self, T=None):
  1235. """Compute the norm of this number."""
  1236. T = T or self.T
  1237. x = T.gen
  1238. A = self.numerator(x=x)
  1239. return T.resultant(A) // self.denom ** self.n
  1240. def inverse(self):
  1241. f = self.poly()
  1242. f_inv = f.invert(self.T)
  1243. return self.module.element_from_poly(f_inv)
  1244. def __rfloordiv__(self, a):
  1245. return self.inverse() * a
  1246. def _negative_power(self, e, modulo=None):
  1247. return self.inverse() ** abs(e)
  1248. class ModuleHomomorphism:
  1249. r"""A homomorphism from one module to another."""
  1250. def __init__(self, domain, codomain, mapping):
  1251. r"""
  1252. Parameters
  1253. ==========
  1254. domain : :py:class:`~.Module`
  1255. The domain of the mapping.
  1256. codomain : :py:class:`~.Module`
  1257. The codomain of the mapping.
  1258. mapping : callable
  1259. An arbitrary callable is accepted, but should be chosen so as
  1260. to represent an actual module homomorphism. In particular, should
  1261. accept elements of *domain* and return elements of *codomain*.
  1262. Examples
  1263. ========
  1264. >>> from sympy import Poly, cyclotomic_poly
  1265. >>> from sympy.polys.numberfields.modules import PowerBasis, ModuleHomomorphism
  1266. >>> T = Poly(cyclotomic_poly(5))
  1267. >>> A = PowerBasis(T)
  1268. >>> B = A.submodule_from_gens([2*A(j) for j in range(4)])
  1269. >>> phi = ModuleHomomorphism(A, B, lambda x: 6*x)
  1270. >>> print(phi.matrix()) # doctest: +SKIP
  1271. DomainMatrix([[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 3, 0], [0, 0, 0, 3]], (4, 4), ZZ)
  1272. """
  1273. self.domain = domain
  1274. self.codomain = codomain
  1275. self.mapping = mapping
  1276. def matrix(self, modulus=None):
  1277. r"""
  1278. Compute the matrix of this homomorphism.
  1279. Parameters
  1280. ==========
  1281. modulus : int, optional
  1282. A positive prime number $p$ if the matrix should be reduced mod
  1283. $p$.
  1284. Returns
  1285. =======
  1286. :py:class:`~.DomainMatrix`
  1287. The matrix is over :ref:`ZZ`, or else over :ref:`GF(p)` if a
  1288. modulus was given.
  1289. """
  1290. basis = self.domain.basis_elements()
  1291. cols = [self.codomain.represent(self.mapping(elt)) for elt in basis]
  1292. if not cols:
  1293. return DomainMatrix.zeros((self.codomain.n, 0), ZZ).to_dense()
  1294. M = cols[0].hstack(*cols[1:])
  1295. if modulus:
  1296. M = M.convert_to(FF(modulus))
  1297. return M
  1298. def kernel(self, modulus=None):
  1299. r"""
  1300. Compute a Submodule representing the kernel of this homomorphism.
  1301. Parameters
  1302. ==========
  1303. modulus : int, optional
  1304. A positive prime number $p$ if the kernel should be computed mod
  1305. $p$.
  1306. Returns
  1307. =======
  1308. :py:class:`~.Submodule`
  1309. This submodule's generators span the kernel of this
  1310. homomorphism over :ref:`ZZ`, or else over :ref:`GF(p)` if a
  1311. modulus was given.
  1312. """
  1313. M = self.matrix(modulus=modulus)
  1314. if modulus is None:
  1315. M = M.convert_to(QQ)
  1316. # Note: Even when working over a finite field, what we want here is
  1317. # the pullback into the integers, so in this case the conversion to ZZ
  1318. # below is appropriate. When working over ZZ, the kernel should be a
  1319. # ZZ-submodule, so, while the conversion to QQ above was required in
  1320. # order for the nullspace calculation to work, conversion back to ZZ
  1321. # afterward should always work.
  1322. # TODO:
  1323. # Watch <https://github.com/sympy/sympy/issues/21834>, which calls
  1324. # for fraction-free algorithms. If this is implemented, we can skip
  1325. # the conversion to `QQ` above.
  1326. K = M.nullspace().convert_to(ZZ).transpose()
  1327. return self.domain.submodule_from_matrix(K)
  1328. class ModuleEndomorphism(ModuleHomomorphism):
  1329. r"""A homomorphism from one module to itself."""
  1330. def __init__(self, domain, mapping):
  1331. r"""
  1332. Parameters
  1333. ==========
  1334. domain : :py:class:`~.Module`
  1335. The common domain and codomain of the mapping.
  1336. mapping : callable
  1337. An arbitrary callable is accepted, but should be chosen so as
  1338. to represent an actual module endomorphism. In particular, should
  1339. accept and return elements of *domain*.
  1340. """
  1341. super().__init__(domain, domain, mapping)
  1342. class InnerEndomorphism(ModuleEndomorphism):
  1343. r"""
  1344. An inner endomorphism on a module, i.e. the endomorphism corresponding to
  1345. multiplication by a fixed element.
  1346. """
  1347. def __init__(self, domain, multiplier):
  1348. r"""
  1349. Parameters
  1350. ==========
  1351. domain : :py:class:`~.Module`
  1352. The domain and codomain of the endomorphism.
  1353. multiplier : :py:class:`~.ModuleElement`
  1354. The element $a$ defining the mapping as $x \mapsto a x$.
  1355. """
  1356. super().__init__(domain, lambda x: multiplier * x)
  1357. self.multiplier = multiplier
  1358. class EndomorphismRing:
  1359. r"""The ring of endomorphisms on a module."""
  1360. def __init__(self, domain):
  1361. """
  1362. Parameters
  1363. ==========
  1364. domain : :py:class:`~.Module`
  1365. The domain and codomain of the endomorphisms.
  1366. """
  1367. self.domain = domain
  1368. def inner_endomorphism(self, multiplier):
  1369. r"""
  1370. Form an inner endomorphism belonging to this endomorphism ring.
  1371. Parameters
  1372. ==========
  1373. multiplier : :py:class:`~.ModuleElement`
  1374. Element $a$ defining the inner endomorphism $x \mapsto a x$.
  1375. Returns
  1376. =======
  1377. :py:class:`~.InnerEndomorphism`
  1378. """
  1379. return InnerEndomorphism(self.domain, multiplier)
  1380. def represent(self, element):
  1381. r"""
  1382. Represent an element of this endomorphism ring, as a single column
  1383. vector.
  1384. Explanation
  1385. ===========
  1386. Let $M$ be a module, and $E$ its ring of endomorphisms. Let $N$ be
  1387. another module, and consider a homomorphism $\varphi: N \rightarrow E$.
  1388. In the event that $\varphi$ is to be represented by a matrix $A$, each
  1389. column of $A$ must represent an element of $E$. This is possible when
  1390. the elements of $E$ are themselves representable as matrices, by
  1391. stacking the columns of such a matrix into a single column.
  1392. This method supports calculating such matrices $A$, by representing
  1393. an element of this endomorphism ring first as a matrix, and then
  1394. stacking that matrix's columns into a single column.
  1395. Examples
  1396. ========
  1397. Note that in these examples we print matrix transposes, to make their
  1398. columns easier to inspect.
  1399. >>> from sympy import Poly, cyclotomic_poly
  1400. >>> from sympy.polys.numberfields.modules import PowerBasis
  1401. >>> from sympy.polys.numberfields.modules import ModuleHomomorphism
  1402. >>> T = Poly(cyclotomic_poly(5))
  1403. >>> M = PowerBasis(T)
  1404. >>> E = M.endomorphism_ring()
  1405. Let $\zeta$ be a primitive 5th root of unity, a generator of our field,
  1406. and consider the inner endomorphism $\tau$ on the ring of integers,
  1407. induced by $\zeta$:
  1408. >>> zeta = M(1)
  1409. >>> tau = E.inner_endomorphism(zeta)
  1410. >>> tau.matrix().transpose() # doctest: +SKIP
  1411. DomainMatrix(
  1412. [[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [-1, -1, -1, -1]],
  1413. (4, 4), ZZ)
  1414. The matrix representation of $\tau$ is as expected. The first column
  1415. shows that multiplying by $\zeta$ carries $1$ to $\zeta$, the second
  1416. column that it carries $\zeta$ to $\zeta^2$, and so forth.
  1417. The ``represent`` method of the endomorphism ring ``E`` stacks these
  1418. into a single column:
  1419. >>> E.represent(tau).transpose() # doctest: +SKIP
  1420. DomainMatrix(
  1421. [[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1]],
  1422. (1, 16), ZZ)
  1423. This is useful when we want to consider a homomorphism $\varphi$ having
  1424. ``E`` as codomain:
  1425. >>> phi = ModuleHomomorphism(M, E, lambda x: E.inner_endomorphism(x))
  1426. and we want to compute the matrix of such a homomorphism:
  1427. >>> phi.matrix().transpose() # doctest: +SKIP
  1428. DomainMatrix(
  1429. [[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
  1430. [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1],
  1431. [0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1, 1, 0, 0, 0],
  1432. [0, 0, 0, 1, -1, -1, -1, -1, 1, 0, 0, 0, 0, 1, 0, 0]],
  1433. (4, 16), ZZ)
  1434. Note that the stacked matrix of $\tau$ occurs as the second column in
  1435. this example. This is because $\zeta$ is the second basis element of
  1436. ``M``, and $\varphi(\zeta) = \tau$.
  1437. Parameters
  1438. ==========
  1439. element : :py:class:`~.ModuleEndomorphism` belonging to this ring.
  1440. Returns
  1441. =======
  1442. :py:class:`~.DomainMatrix`
  1443. Column vector equalling the vertical stacking of all the columns
  1444. of the matrix that represents the given *element* as a mapping.
  1445. """
  1446. if isinstance(element, ModuleEndomorphism) and element.domain == self.domain:
  1447. M = element.matrix()
  1448. # Transform the matrix into a single column, which should reproduce
  1449. # the original columns, one after another.
  1450. m, n = M.shape
  1451. if n == 0:
  1452. return M
  1453. return M[:, 0].vstack(*[M[:, j] for j in range(1, n)])
  1454. raise NotImplementedError
  1455. def find_min_poly(alpha, domain, x=None, powers=None):
  1456. r"""
  1457. Find a polynomial of least degree (not necessarily irreducible) satisfied
  1458. by an element of a finitely-generated ring with unity.
  1459. Examples
  1460. ========
  1461. For the $n$th cyclotomic field, $n$ an odd prime, consider the quadratic
  1462. equation whose roots are the two periods of length $(n-1)/2$. Article 356
  1463. of Gauss tells us that we should get $x^2 + x - (n-1)/4$ or
  1464. $x^2 + x + (n+1)/4$ according to whether $n$ is 1 or 3 mod 4, respectively.
  1465. >>> from sympy import Poly, cyclotomic_poly, primitive_root, QQ
  1466. >>> from sympy.abc import x
  1467. >>> from sympy.polys.numberfields.modules import PowerBasis, find_min_poly
  1468. >>> n = 13
  1469. >>> g = primitive_root(n)
  1470. >>> C = PowerBasis(Poly(cyclotomic_poly(n, x)))
  1471. >>> ee = [g**(2*k+1) % n for k in range((n-1)//2)]
  1472. >>> eta = sum(C(e) for e in ee)
  1473. >>> print(find_min_poly(eta, QQ, x=x).as_expr())
  1474. x**2 + x - 3
  1475. >>> n = 19
  1476. >>> g = primitive_root(n)
  1477. >>> C = PowerBasis(Poly(cyclotomic_poly(n, x)))
  1478. >>> ee = [g**(2*k+2) % n for k in range((n-1)//2)]
  1479. >>> eta = sum(C(e) for e in ee)
  1480. >>> print(find_min_poly(eta, QQ, x=x).as_expr())
  1481. x**2 + x + 5
  1482. Parameters
  1483. ==========
  1484. alpha : :py:class:`~.ModuleElement`
  1485. The element whose min poly is to be found, and whose module has
  1486. multiplication and starts with unity.
  1487. domain : :py:class:`~.Domain`
  1488. The desired domain of the polynomial.
  1489. x : :py:class:`~.Symbol`, optional
  1490. The desired variable for the polynomial.
  1491. powers : list, optional
  1492. If desired, pass an empty list. The powers of *alpha* (as
  1493. :py:class:`~.ModuleElement` instances) from the zeroth up to the degree
  1494. of the min poly will be recorded here, as we compute them.
  1495. Returns
  1496. =======
  1497. :py:class:`~.Poly`, ``None``
  1498. The minimal polynomial for alpha, or ``None`` if no polynomial could be
  1499. found over the desired domain.
  1500. Raises
  1501. ======
  1502. MissingUnityError
  1503. If the module to which alpha belongs does not start with unity.
  1504. ClosureFailure
  1505. If the module to which alpha belongs is not closed under
  1506. multiplication.
  1507. """
  1508. R = alpha.module
  1509. if not R.starts_with_unity():
  1510. raise MissingUnityError("alpha must belong to finitely generated ring with unity.")
  1511. if powers is None:
  1512. powers = []
  1513. one = R(0)
  1514. powers.append(one)
  1515. powers_matrix = one.column(domain=domain)
  1516. ak = alpha
  1517. m = None
  1518. for k in range(1, R.n + 1):
  1519. powers.append(ak)
  1520. ak_col = ak.column(domain=domain)
  1521. try:
  1522. X = powers_matrix._solve(ak_col)[0]
  1523. except DMBadInputError:
  1524. # This means alpha^k still isn't in the domain-span of the lower powers.
  1525. powers_matrix = powers_matrix.hstack(ak_col)
  1526. ak *= alpha
  1527. else:
  1528. # alpha^k is in the domain-span of the lower powers, so we have found a
  1529. # minimal-degree poly for alpha.
  1530. coeffs = [1] + [-c for c in reversed(X.to_list_flat())]
  1531. x = x or Dummy('x')
  1532. if domain.is_FF:
  1533. m = Poly(coeffs, x, modulus=domain.mod)
  1534. else:
  1535. m = Poly(coeffs, x, domain=domain)
  1536. break
  1537. return m