test_modules.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. from sympy.abc import x, zeta
  2. from sympy.polys import Poly, cyclotomic_poly
  3. from sympy.polys.domains import FF, QQ, ZZ
  4. from sympy.polys.matrices import DomainMatrix, DM
  5. from sympy.polys.numberfields.exceptions import (
  6. ClosureFailure, MissingUnityError, StructureError
  7. )
  8. from sympy.polys.numberfields.modules import (
  9. Module, ModuleElement, ModuleEndomorphism, PowerBasis, PowerBasisElement,
  10. find_min_poly, is_sq_maxrank_HNF, make_mod_elt, to_col,
  11. )
  12. from sympy.polys.numberfields.utilities import is_int
  13. from sympy.polys.polyerrors import UnificationFailed
  14. from sympy.testing.pytest import raises
  15. def test_to_col():
  16. c = [1, 2, 3, 4]
  17. m = to_col(c)
  18. assert m.domain.is_ZZ
  19. assert m.shape == (4, 1)
  20. assert m.flat() == c
  21. def test_Module_NotImplemented():
  22. M = Module()
  23. raises(NotImplementedError, lambda: M.n)
  24. raises(NotImplementedError, lambda: M.mult_tab())
  25. raises(NotImplementedError, lambda: M.represent(None))
  26. raises(NotImplementedError, lambda: M.starts_with_unity())
  27. raises(NotImplementedError, lambda: M.element_from_rational(QQ(2, 3)))
  28. def test_Module_ancestors():
  29. T = Poly(cyclotomic_poly(5, x))
  30. A = PowerBasis(T)
  31. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  32. C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  33. D = B.submodule_from_matrix(5 * DomainMatrix.eye(4, ZZ))
  34. assert C.ancestors(include_self=True) == [A, B, C]
  35. assert D.ancestors(include_self=True) == [A, B, D]
  36. assert C.power_basis_ancestor() == A
  37. assert C.nearest_common_ancestor(D) == B
  38. M = Module()
  39. assert M.power_basis_ancestor() is None
  40. def test_Module_compat_col():
  41. T = Poly(cyclotomic_poly(5, x))
  42. A = PowerBasis(T)
  43. col = to_col([1, 2, 3, 4])
  44. row = col.transpose()
  45. assert A.is_compat_col(col) is True
  46. assert A.is_compat_col(row) is False
  47. assert A.is_compat_col(1) is False
  48. assert A.is_compat_col(DomainMatrix.eye(3, ZZ)[:, 0]) is False
  49. assert A.is_compat_col(DomainMatrix.eye(4, QQ)[:, 0]) is False
  50. assert A.is_compat_col(DomainMatrix.eye(4, ZZ)[:, 0]) is True
  51. def test_Module_call():
  52. T = Poly(cyclotomic_poly(5, x))
  53. B = PowerBasis(T)
  54. assert B(0).col.flat() == [1, 0, 0, 0]
  55. assert B(1).col.flat() == [0, 1, 0, 0]
  56. col = DomainMatrix.eye(4, ZZ)[:, 2]
  57. assert B(col).col == col
  58. raises(ValueError, lambda: B(-1))
  59. def test_Module_starts_with_unity():
  60. T = Poly(cyclotomic_poly(5, x))
  61. A = PowerBasis(T)
  62. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  63. assert A.starts_with_unity() is True
  64. assert B.starts_with_unity() is False
  65. def test_Module_basis_elements():
  66. T = Poly(cyclotomic_poly(5, x))
  67. A = PowerBasis(T)
  68. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  69. basis = B.basis_elements()
  70. bp = B.basis_element_pullbacks()
  71. for i, (e, p) in enumerate(zip(basis, bp)):
  72. c = [0] * 4
  73. assert e.module == B
  74. assert p.module == A
  75. c[i] = 1
  76. assert e == B(to_col(c))
  77. c[i] = 2
  78. assert p == A(to_col(c))
  79. def test_Module_zero():
  80. T = Poly(cyclotomic_poly(5, x))
  81. A = PowerBasis(T)
  82. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  83. assert A.zero().col.flat() == [0, 0, 0, 0]
  84. assert A.zero().module == A
  85. assert B.zero().col.flat() == [0, 0, 0, 0]
  86. assert B.zero().module == B
  87. def test_Module_one():
  88. T = Poly(cyclotomic_poly(5, x))
  89. A = PowerBasis(T)
  90. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  91. assert A.one().col.flat() == [1, 0, 0, 0]
  92. assert A.one().module == A
  93. assert B.one().col.flat() == [1, 0, 0, 0]
  94. assert B.one().module == A
  95. def test_Module_element_from_rational():
  96. T = Poly(cyclotomic_poly(5, x))
  97. A = PowerBasis(T)
  98. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  99. rA = A.element_from_rational(QQ(22, 7))
  100. rB = B.element_from_rational(QQ(22, 7))
  101. assert rA.coeffs == [22, 0, 0, 0]
  102. assert rA.denom == 7
  103. assert rA.module == A
  104. assert rB.coeffs == [22, 0, 0, 0]
  105. assert rB.denom == 7
  106. assert rB.module == A
  107. def test_Module_submodule_from_gens():
  108. T = Poly(cyclotomic_poly(5, x))
  109. A = PowerBasis(T)
  110. gens = [2*A(0), 2*A(1), 6*A(0), 6*A(1)]
  111. B = A.submodule_from_gens(gens)
  112. # Because the 3rd and 4th generators do not add anything new, we expect
  113. # the cols of the matrix of B to just reproduce the first two gens:
  114. M = gens[0].column().hstack(gens[1].column())
  115. assert B.matrix == M
  116. # At least one generator must be provided:
  117. raises(ValueError, lambda: A.submodule_from_gens([]))
  118. # All generators must belong to A:
  119. raises(ValueError, lambda: A.submodule_from_gens([3*A(0), B(0)]))
  120. def test_Module_submodule_from_matrix():
  121. T = Poly(cyclotomic_poly(5, x))
  122. A = PowerBasis(T)
  123. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  124. e = B(to_col([1, 2, 3, 4]))
  125. f = e.to_parent()
  126. assert f.col.flat() == [2, 4, 6, 8]
  127. # Matrix must be over ZZ:
  128. raises(ValueError, lambda: A.submodule_from_matrix(DomainMatrix.eye(4, QQ)))
  129. # Number of rows of matrix must equal number of generators of module A:
  130. raises(ValueError, lambda: A.submodule_from_matrix(2 * DomainMatrix.eye(5, ZZ)))
  131. def test_Module_whole_submodule():
  132. T = Poly(cyclotomic_poly(5, x))
  133. A = PowerBasis(T)
  134. B = A.whole_submodule()
  135. e = B(to_col([1, 2, 3, 4]))
  136. f = e.to_parent()
  137. assert f.col.flat() == [1, 2, 3, 4]
  138. e0, e1, e2, e3 = B(0), B(1), B(2), B(3)
  139. assert e2 * e3 == e0
  140. assert e3 ** 2 == e1
  141. def test_PowerBasis_repr():
  142. T = Poly(cyclotomic_poly(5, x))
  143. A = PowerBasis(T)
  144. assert repr(A) == 'PowerBasis(x**4 + x**3 + x**2 + x + 1)'
  145. def test_PowerBasis_eq():
  146. T = Poly(cyclotomic_poly(5, x))
  147. A = PowerBasis(T)
  148. B = PowerBasis(T)
  149. assert A == B
  150. def test_PowerBasis_mult_tab():
  151. T = Poly(cyclotomic_poly(5, x))
  152. A = PowerBasis(T)
  153. M = A.mult_tab()
  154. exp = {0: {0: [1, 0, 0, 0], 1: [0, 1, 0, 0], 2: [0, 0, 1, 0], 3: [0, 0, 0, 1]},
  155. 1: {1: [0, 0, 1, 0], 2: [0, 0, 0, 1], 3: [-1, -1, -1, -1]},
  156. 2: {2: [-1, -1, -1, -1], 3: [1, 0, 0, 0]},
  157. 3: {3: [0, 1, 0, 0]}}
  158. # We get the table we expect:
  159. assert M == exp
  160. # And all entries are of expected type:
  161. assert all(is_int(c) for u in M for v in M[u] for c in M[u][v])
  162. def test_PowerBasis_represent():
  163. T = Poly(cyclotomic_poly(5, x))
  164. A = PowerBasis(T)
  165. col = to_col([1, 2, 3, 4])
  166. a = A(col)
  167. assert A.represent(a) == col
  168. b = A(col, denom=2)
  169. raises(ClosureFailure, lambda: A.represent(b))
  170. def test_PowerBasis_element_from_poly():
  171. T = Poly(cyclotomic_poly(5, x))
  172. A = PowerBasis(T)
  173. f = Poly(1 + 2*x)
  174. g = Poly(x**4)
  175. h = Poly(0, x)
  176. assert A.element_from_poly(f).coeffs == [1, 2, 0, 0]
  177. assert A.element_from_poly(g).coeffs == [-1, -1, -1, -1]
  178. assert A.element_from_poly(h).coeffs == [0, 0, 0, 0]
  179. def test_PowerBasis_element__conversions():
  180. k = QQ.cyclotomic_field(5)
  181. L = QQ.cyclotomic_field(7)
  182. B = PowerBasis(k)
  183. # ANP --> PowerBasisElement
  184. a = k([QQ(1, 2), QQ(1, 3), 5, 7])
  185. e = B.element_from_ANP(a)
  186. assert e.coeffs == [42, 30, 2, 3]
  187. assert e.denom == 6
  188. # PowerBasisElement --> ANP
  189. assert e.to_ANP() == a
  190. # Cannot convert ANP from different field
  191. d = L([QQ(1, 2), QQ(1, 3), 5, 7])
  192. raises(UnificationFailed, lambda: B.element_from_ANP(d))
  193. # AlgebraicNumber --> PowerBasisElement
  194. alpha = k.to_alg_num(a)
  195. eps = B.element_from_alg_num(alpha)
  196. assert eps.coeffs == [42, 30, 2, 3]
  197. assert eps.denom == 6
  198. # PowerBasisElement --> AlgebraicNumber
  199. assert eps.to_alg_num() == alpha
  200. # Cannot convert AlgebraicNumber from different field
  201. delta = L.to_alg_num(d)
  202. raises(UnificationFailed, lambda: B.element_from_alg_num(delta))
  203. # When we don't know the field:
  204. C = PowerBasis(k.ext.minpoly)
  205. # Can convert from AlgebraicNumber:
  206. eps = C.element_from_alg_num(alpha)
  207. assert eps.coeffs == [42, 30, 2, 3]
  208. assert eps.denom == 6
  209. # But can't convert back:
  210. raises(StructureError, lambda: eps.to_alg_num())
  211. def test_Submodule_repr():
  212. T = Poly(cyclotomic_poly(5, x))
  213. A = PowerBasis(T)
  214. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ), denom=3)
  215. assert repr(B) == 'Submodule[[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 2]]/3'
  216. def test_Submodule_reduced():
  217. T = Poly(cyclotomic_poly(5, x))
  218. A = PowerBasis(T)
  219. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  220. C = A.submodule_from_matrix(6 * DomainMatrix.eye(4, ZZ), denom=3)
  221. D = C.reduced()
  222. assert D.denom == 1 and D == C == B
  223. def test_Submodule_discard_before():
  224. T = Poly(cyclotomic_poly(5, x))
  225. A = PowerBasis(T)
  226. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  227. B.compute_mult_tab()
  228. C = B.discard_before(2)
  229. assert C.parent == B.parent
  230. assert B.is_sq_maxrank_HNF() and not C.is_sq_maxrank_HNF()
  231. assert C.matrix == B.matrix[:, 2:]
  232. assert C.mult_tab() == {0: {0: [-2, -2], 1: [0, 0]}, 1: {1: [0, 0]}}
  233. def test_Submodule_QQ_matrix():
  234. T = Poly(cyclotomic_poly(5, x))
  235. A = PowerBasis(T)
  236. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  237. C = A.submodule_from_matrix(6 * DomainMatrix.eye(4, ZZ), denom=3)
  238. assert C.QQ_matrix == B.QQ_matrix
  239. def test_Submodule_represent():
  240. T = Poly(cyclotomic_poly(5, x))
  241. A = PowerBasis(T)
  242. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  243. C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  244. a0 = A(to_col([6, 12, 18, 24]))
  245. a1 = A(to_col([2, 4, 6, 8]))
  246. a2 = A(to_col([1, 3, 5, 7]))
  247. b1 = B.represent(a1)
  248. assert b1.flat() == [1, 2, 3, 4]
  249. c0 = C.represent(a0)
  250. assert c0.flat() == [1, 2, 3, 4]
  251. Y = A.submodule_from_matrix(DomainMatrix([
  252. [1, 0, 0, 0],
  253. [0, 1, 0, 0],
  254. [0, 0, 1, 0],
  255. ], (3, 4), ZZ).transpose())
  256. U = Poly(cyclotomic_poly(7, x))
  257. Z = PowerBasis(U)
  258. z0 = Z(to_col([1, 2, 3, 4, 5, 6]))
  259. raises(ClosureFailure, lambda: Y.represent(A(3)))
  260. raises(ClosureFailure, lambda: B.represent(a2))
  261. raises(ClosureFailure, lambda: B.represent(z0))
  262. def test_Submodule_is_compat_submodule():
  263. T = Poly(cyclotomic_poly(5, x))
  264. A = PowerBasis(T)
  265. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  266. C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  267. D = C.submodule_from_matrix(5 * DomainMatrix.eye(4, ZZ))
  268. assert B.is_compat_submodule(C) is True
  269. assert B.is_compat_submodule(A) is False
  270. assert B.is_compat_submodule(D) is False
  271. def test_Submodule_eq():
  272. T = Poly(cyclotomic_poly(5, x))
  273. A = PowerBasis(T)
  274. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  275. C = A.submodule_from_matrix(6 * DomainMatrix.eye(4, ZZ), denom=3)
  276. assert C == B
  277. def test_Submodule_add():
  278. T = Poly(cyclotomic_poly(5, x))
  279. A = PowerBasis(T)
  280. B = A.submodule_from_matrix(DomainMatrix([
  281. [4, 0, 0, 0],
  282. [0, 4, 0, 0],
  283. ], (2, 4), ZZ).transpose(), denom=6)
  284. C = A.submodule_from_matrix(DomainMatrix([
  285. [0, 10, 0, 0],
  286. [0, 0, 7, 0],
  287. ], (2, 4), ZZ).transpose(), denom=15)
  288. D = A.submodule_from_matrix(DomainMatrix([
  289. [20, 0, 0, 0],
  290. [ 0, 20, 0, 0],
  291. [ 0, 0, 14, 0],
  292. ], (3, 4), ZZ).transpose(), denom=30)
  293. assert B + C == D
  294. U = Poly(cyclotomic_poly(7, x))
  295. Z = PowerBasis(U)
  296. Y = Z.submodule_from_gens([Z(0), Z(1)])
  297. raises(TypeError, lambda: B + Y)
  298. def test_Submodule_mul():
  299. T = Poly(cyclotomic_poly(5, x))
  300. A = PowerBasis(T)
  301. C = A.submodule_from_matrix(DomainMatrix([
  302. [0, 10, 0, 0],
  303. [0, 0, 7, 0],
  304. ], (2, 4), ZZ).transpose(), denom=15)
  305. C1 = A.submodule_from_matrix(DomainMatrix([
  306. [0, 20, 0, 0],
  307. [0, 0, 14, 0],
  308. ], (2, 4), ZZ).transpose(), denom=3)
  309. C2 = A.submodule_from_matrix(DomainMatrix([
  310. [0, 0, 10, 0],
  311. [0, 0, 0, 7],
  312. ], (2, 4), ZZ).transpose(), denom=15)
  313. C3_unred = A.submodule_from_matrix(DomainMatrix([
  314. [0, 0, 100, 0],
  315. [0, 0, 0, 70],
  316. [0, 0, 0, 70],
  317. [-49, -49, -49, -49]
  318. ], (4, 4), ZZ).transpose(), denom=225)
  319. C3 = A.submodule_from_matrix(DomainMatrix([
  320. [4900, 4900, 0, 0],
  321. [4410, 4410, 10, 0],
  322. [2107, 2107, 7, 7]
  323. ], (3, 4), ZZ).transpose(), denom=225)
  324. assert C * 1 == C
  325. assert C ** 1 == C
  326. assert C * 10 == C1
  327. assert C * A(1) == C2
  328. assert C.mul(C, hnf=False) == C3_unred
  329. assert C * C == C3
  330. assert C ** 2 == C3
  331. def test_Submodule_reduce_element():
  332. T = Poly(cyclotomic_poly(5, x))
  333. A = PowerBasis(T)
  334. B = A.whole_submodule()
  335. b = B(to_col([90, 84, 80, 75]), denom=120)
  336. C = B.submodule_from_matrix(DomainMatrix.eye(4, ZZ), denom=2)
  337. b_bar_expected = B(to_col([30, 24, 20, 15]), denom=120)
  338. b_bar = C.reduce_element(b)
  339. assert b_bar == b_bar_expected
  340. C = B.submodule_from_matrix(DomainMatrix.eye(4, ZZ), denom=4)
  341. b_bar_expected = B(to_col([0, 24, 20, 15]), denom=120)
  342. b_bar = C.reduce_element(b)
  343. assert b_bar == b_bar_expected
  344. C = B.submodule_from_matrix(DomainMatrix.eye(4, ZZ), denom=8)
  345. b_bar_expected = B(to_col([0, 9, 5, 0]), denom=120)
  346. b_bar = C.reduce_element(b)
  347. assert b_bar == b_bar_expected
  348. a = A(to_col([1, 2, 3, 4]))
  349. raises(NotImplementedError, lambda: C.reduce_element(a))
  350. C = B.submodule_from_matrix(DomainMatrix([
  351. [5, 4, 3, 2],
  352. [0, 8, 7, 6],
  353. [0, 0,11,12],
  354. [0, 0, 0, 1]
  355. ], (4, 4), ZZ).transpose())
  356. raises(StructureError, lambda: C.reduce_element(b))
  357. def test_is_HNF():
  358. M = DM([
  359. [3, 2, 1],
  360. [0, 2, 1],
  361. [0, 0, 1]
  362. ], ZZ)
  363. M1 = DM([
  364. [3, 2, 1],
  365. [0, -2, 1],
  366. [0, 0, 1]
  367. ], ZZ)
  368. M2 = DM([
  369. [3, 2, 3],
  370. [0, 2, 1],
  371. [0, 0, 1]
  372. ], ZZ)
  373. assert is_sq_maxrank_HNF(M) is True
  374. assert is_sq_maxrank_HNF(M1) is False
  375. assert is_sq_maxrank_HNF(M2) is False
  376. def test_make_mod_elt():
  377. T = Poly(cyclotomic_poly(5, x))
  378. A = PowerBasis(T)
  379. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  380. col = to_col([1, 2, 3, 4])
  381. eA = make_mod_elt(A, col)
  382. eB = make_mod_elt(B, col)
  383. assert isinstance(eA, PowerBasisElement)
  384. assert not isinstance(eB, PowerBasisElement)
  385. def test_ModuleElement_repr():
  386. T = Poly(cyclotomic_poly(5, x))
  387. A = PowerBasis(T)
  388. e = A(to_col([1, 2, 3, 4]), denom=2)
  389. assert repr(e) == '[1, 2, 3, 4]/2'
  390. def test_ModuleElement_reduced():
  391. T = Poly(cyclotomic_poly(5, x))
  392. A = PowerBasis(T)
  393. e = A(to_col([2, 4, 6, 8]), denom=2)
  394. f = e.reduced()
  395. assert f.denom == 1 and f == e
  396. def test_ModuleElement_reduced_mod_p():
  397. T = Poly(cyclotomic_poly(5, x))
  398. A = PowerBasis(T)
  399. e = A(to_col([20, 40, 60, 80]))
  400. f = e.reduced_mod_p(7)
  401. assert f.coeffs == [-1, -2, -3, 3]
  402. def test_ModuleElement_from_int_list():
  403. T = Poly(cyclotomic_poly(5, x))
  404. A = PowerBasis(T)
  405. c = [1, 2, 3, 4]
  406. assert ModuleElement.from_int_list(A, c).coeffs == c
  407. def test_ModuleElement_len():
  408. T = Poly(cyclotomic_poly(5, x))
  409. A = PowerBasis(T)
  410. e = A(0)
  411. assert len(e) == 4
  412. def test_ModuleElement_column():
  413. T = Poly(cyclotomic_poly(5, x))
  414. A = PowerBasis(T)
  415. e = A(0)
  416. col1 = e.column()
  417. assert col1 == e.col and col1 is not e.col
  418. col2 = e.column(domain=FF(5))
  419. assert col2.domain.is_FF
  420. def test_ModuleElement_QQ_col():
  421. T = Poly(cyclotomic_poly(5, x))
  422. A = PowerBasis(T)
  423. e = A(to_col([1, 2, 3, 4]), denom=1)
  424. f = A(to_col([3, 6, 9, 12]), denom=3)
  425. assert e.QQ_col == f.QQ_col
  426. def test_ModuleElement_to_ancestors():
  427. T = Poly(cyclotomic_poly(5, x))
  428. A = PowerBasis(T)
  429. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  430. C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  431. D = C.submodule_from_matrix(5 * DomainMatrix.eye(4, ZZ))
  432. eD = D(0)
  433. eC = eD.to_parent()
  434. eB = eD.to_ancestor(B)
  435. eA = eD.over_power_basis()
  436. assert eC.module is C and eC.coeffs == [5, 0, 0, 0]
  437. assert eB.module is B and eB.coeffs == [15, 0, 0, 0]
  438. assert eA.module is A and eA.coeffs == [30, 0, 0, 0]
  439. a = A(0)
  440. raises(ValueError, lambda: a.to_parent())
  441. def test_ModuleElement_compatibility():
  442. T = Poly(cyclotomic_poly(5, x))
  443. A = PowerBasis(T)
  444. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  445. C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  446. D = B.submodule_from_matrix(5 * DomainMatrix.eye(4, ZZ))
  447. assert C(0).is_compat(C(1)) is True
  448. assert C(0).is_compat(D(0)) is False
  449. u, v = C(0).unify(D(0))
  450. assert u.module is B and v.module is B
  451. assert C(C.represent(u)) == C(0) and D(D.represent(v)) == D(0)
  452. u, v = C(0).unify(C(1))
  453. assert u == C(0) and v == C(1)
  454. U = Poly(cyclotomic_poly(7, x))
  455. Z = PowerBasis(U)
  456. raises(UnificationFailed, lambda: C(0).unify(Z(1)))
  457. def test_ModuleElement_eq():
  458. T = Poly(cyclotomic_poly(5, x))
  459. A = PowerBasis(T)
  460. e = A(to_col([1, 2, 3, 4]), denom=1)
  461. f = A(to_col([3, 6, 9, 12]), denom=3)
  462. assert e == f
  463. U = Poly(cyclotomic_poly(7, x))
  464. Z = PowerBasis(U)
  465. assert e != Z(0)
  466. assert e != 3.14
  467. def test_ModuleElement_equiv():
  468. T = Poly(cyclotomic_poly(5, x))
  469. A = PowerBasis(T)
  470. e = A(to_col([1, 2, 3, 4]), denom=1)
  471. f = A(to_col([3, 6, 9, 12]), denom=3)
  472. assert e.equiv(f)
  473. C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  474. g = C(to_col([1, 2, 3, 4]), denom=1)
  475. h = A(to_col([3, 6, 9, 12]), denom=1)
  476. assert g.equiv(h)
  477. assert C(to_col([5, 0, 0, 0]), denom=7).equiv(QQ(15, 7))
  478. U = Poly(cyclotomic_poly(7, x))
  479. Z = PowerBasis(U)
  480. raises(UnificationFailed, lambda: e.equiv(Z(0)))
  481. assert e.equiv(3.14) is False
  482. def test_ModuleElement_add():
  483. T = Poly(cyclotomic_poly(5, x))
  484. A = PowerBasis(T)
  485. C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  486. e = A(to_col([1, 2, 3, 4]), denom=6)
  487. f = A(to_col([5, 6, 7, 8]), denom=10)
  488. g = C(to_col([1, 1, 1, 1]), denom=2)
  489. assert e + f == A(to_col([10, 14, 18, 22]), denom=15)
  490. assert e - f == A(to_col([-5, -4, -3, -2]), denom=15)
  491. assert e + g == A(to_col([10, 11, 12, 13]), denom=6)
  492. assert e + QQ(7, 10) == A(to_col([26, 10, 15, 20]), denom=30)
  493. assert g + QQ(7, 10) == A(to_col([22, 15, 15, 15]), denom=10)
  494. U = Poly(cyclotomic_poly(7, x))
  495. Z = PowerBasis(U)
  496. raises(TypeError, lambda: e + Z(0))
  497. raises(TypeError, lambda: e + 3.14)
  498. def test_ModuleElement_mul():
  499. T = Poly(cyclotomic_poly(5, x))
  500. A = PowerBasis(T)
  501. C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  502. e = A(to_col([0, 2, 0, 0]), denom=3)
  503. f = A(to_col([0, 0, 0, 7]), denom=5)
  504. g = C(to_col([0, 0, 0, 1]), denom=2)
  505. h = A(to_col([0, 0, 3, 1]), denom=7)
  506. assert e * f == A(to_col([-14, -14, -14, -14]), denom=15)
  507. assert e * g == A(to_col([-1, -1, -1, -1]))
  508. assert e * h == A(to_col([-2, -2, -2, 4]), denom=21)
  509. assert e * QQ(6, 5) == A(to_col([0, 4, 0, 0]), denom=5)
  510. assert (g * QQ(10, 21)).equiv(A(to_col([0, 0, 0, 5]), denom=7))
  511. assert e // QQ(6, 5) == A(to_col([0, 5, 0, 0]), denom=9)
  512. U = Poly(cyclotomic_poly(7, x))
  513. Z = PowerBasis(U)
  514. raises(TypeError, lambda: e * Z(0))
  515. raises(TypeError, lambda: e * 3.14)
  516. raises(TypeError, lambda: e // 3.14)
  517. raises(ZeroDivisionError, lambda: e // 0)
  518. def test_ModuleElement_div():
  519. T = Poly(cyclotomic_poly(5, x))
  520. A = PowerBasis(T)
  521. C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  522. e = A(to_col([0, 2, 0, 0]), denom=3)
  523. f = A(to_col([0, 0, 0, 7]), denom=5)
  524. g = C(to_col([1, 1, 1, 1]))
  525. assert e // f == 10*A(3)//21
  526. assert e // g == -2*A(2)//9
  527. assert 3 // g == -A(1)
  528. def test_ModuleElement_pow():
  529. T = Poly(cyclotomic_poly(5, x))
  530. A = PowerBasis(T)
  531. C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
  532. e = A(to_col([0, 2, 0, 0]), denom=3)
  533. g = C(to_col([0, 0, 0, 1]), denom=2)
  534. assert e ** 3 == A(to_col([0, 0, 0, 8]), denom=27)
  535. assert g ** 2 == C(to_col([0, 3, 0, 0]), denom=4)
  536. assert e ** 0 == A(to_col([1, 0, 0, 0]))
  537. assert g ** 0 == A(to_col([1, 0, 0, 0]))
  538. assert e ** 1 == e
  539. assert g ** 1 == g
  540. def test_ModuleElement_mod():
  541. T = Poly(cyclotomic_poly(5, x))
  542. A = PowerBasis(T)
  543. e = A(to_col([1, 15, 8, 0]), denom=2)
  544. assert e % 7 == A(to_col([1, 1, 8, 0]), denom=2)
  545. assert e % QQ(1, 2) == A.zero()
  546. assert e % QQ(1, 3) == A(to_col([1, 1, 0, 0]), denom=6)
  547. B = A.submodule_from_gens([A(0), 5*A(1), 3*A(2), A(3)])
  548. assert e % B == A(to_col([1, 5, 2, 0]), denom=2)
  549. C = B.whole_submodule()
  550. raises(TypeError, lambda: e % C)
  551. def test_PowerBasisElement_polys():
  552. T = Poly(cyclotomic_poly(5, x))
  553. A = PowerBasis(T)
  554. e = A(to_col([1, 15, 8, 0]), denom=2)
  555. assert e.numerator(x=zeta) == Poly(8 * zeta ** 2 + 15 * zeta + 1, domain=ZZ)
  556. assert e.poly(x=zeta) == Poly(4 * zeta ** 2 + QQ(15, 2) * zeta + QQ(1, 2), domain=QQ)
  557. def test_PowerBasisElement_norm():
  558. T = Poly(cyclotomic_poly(5, x))
  559. A = PowerBasis(T)
  560. lam = A(to_col([1, -1, 0, 0]))
  561. assert lam.norm() == 5
  562. def test_PowerBasisElement_inverse():
  563. T = Poly(cyclotomic_poly(5, x))
  564. A = PowerBasis(T)
  565. e = A(to_col([1, 1, 1, 1]))
  566. assert 2 // e == -2*A(1)
  567. assert e ** -3 == -A(3)
  568. def test_ModuleHomomorphism_matrix():
  569. T = Poly(cyclotomic_poly(5, x))
  570. A = PowerBasis(T)
  571. phi = ModuleEndomorphism(A, lambda a: a ** 2)
  572. M = phi.matrix()
  573. assert M == DomainMatrix([
  574. [1, 0, -1, 0],
  575. [0, 0, -1, 1],
  576. [0, 1, -1, 0],
  577. [0, 0, -1, 0]
  578. ], (4, 4), ZZ)
  579. def test_ModuleHomomorphism_kernel():
  580. T = Poly(cyclotomic_poly(5, x))
  581. A = PowerBasis(T)
  582. phi = ModuleEndomorphism(A, lambda a: a ** 5)
  583. N = phi.kernel()
  584. assert N.n == 3
  585. def test_EndomorphismRing_represent():
  586. T = Poly(cyclotomic_poly(5, x))
  587. A = PowerBasis(T)
  588. R = A.endomorphism_ring()
  589. phi = R.inner_endomorphism(A(1))
  590. col = R.represent(phi)
  591. assert col.transpose() == DomainMatrix([
  592. [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1]
  593. ], (1, 16), ZZ)
  594. B = A.submodule_from_matrix(DomainMatrix.zeros((4, 0), ZZ))
  595. S = B.endomorphism_ring()
  596. psi = S.inner_endomorphism(A(1))
  597. col = S.represent(psi)
  598. assert col == DomainMatrix([], (0, 0), ZZ)
  599. raises(NotImplementedError, lambda: R.represent(3.14))
  600. def test_find_min_poly():
  601. T = Poly(cyclotomic_poly(5, x))
  602. A = PowerBasis(T)
  603. powers = []
  604. m = find_min_poly(A(1), QQ, x=x, powers=powers)
  605. assert m == Poly(T, domain=QQ)
  606. assert len(powers) == 5
  607. # powers list need not be passed
  608. m = find_min_poly(A(1), QQ, x=x)
  609. assert m == Poly(T, domain=QQ)
  610. B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
  611. raises(MissingUnityError, lambda: find_min_poly(B(1), QQ))