passagemath-flint 10.6.1rc10__cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. passagemath_flint-10.6.1rc10.dist-info/METADATA +122 -0
  2. passagemath_flint-10.6.1rc10.dist-info/RECORD +360 -0
  3. passagemath_flint-10.6.1rc10.dist-info/WHEEL +6 -0
  4. passagemath_flint-10.6.1rc10.dist-info/top_level.txt +2 -0
  5. passagemath_flint.libs/libflint-3701249d.so.21.0.0 +0 -0
  6. passagemath_flint.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
  7. passagemath_flint.libs/libgfortran-8a9a71bc.so.5.0.0 +0 -0
  8. passagemath_flint.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
  9. passagemath_flint.libs/libgsl-e3525837.so.28.0.0 +0 -0
  10. passagemath_flint.libs/libmpfi-ad12a86d.so.0.0.0 +0 -0
  11. passagemath_flint.libs/libmpfr-e0f11cf3.so.6.2.1 +0 -0
  12. passagemath_flint.libs/libntl-1004113e.so.44.0.1 +0 -0
  13. passagemath_flint.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
  14. sage/all__sagemath_flint.py +29 -0
  15. sage/combinat/all__sagemath_flint.py +1 -0
  16. sage/combinat/posets/all__sagemath_flint.py +1 -0
  17. sage/combinat/posets/hasse_cython_flint.cpython-311-aarch64-linux-gnu.so +0 -0
  18. sage/combinat/posets/hasse_cython_flint.pyx +194 -0
  19. sage/data_structures/all__sagemath_flint.py +1 -0
  20. sage/data_structures/bounded_integer_sequences.cpython-311-aarch64-linux-gnu.so +0 -0
  21. sage/data_structures/bounded_integer_sequences.pxd +62 -0
  22. sage/data_structures/bounded_integer_sequences.pyx +1418 -0
  23. sage/graphs/all__sagemath_flint.py +1 -0
  24. sage/graphs/chrompoly.cpython-311-aarch64-linux-gnu.so +0 -0
  25. sage/graphs/chrompoly.pyx +555 -0
  26. sage/graphs/matchpoly.cpython-311-aarch64-linux-gnu.so +0 -0
  27. sage/graphs/matchpoly.pyx +412 -0
  28. sage/libs/all__sagemath_flint.py +17 -0
  29. sage/libs/arb/__init__.py +1 -0
  30. sage/libs/arb/acb.pxd +154 -0
  31. sage/libs/arb/acb_calc.pxd +9 -0
  32. sage/libs/arb/acb_elliptic.pxd +25 -0
  33. sage/libs/arb/acb_hypgeom.pxd +74 -0
  34. sage/libs/arb/acb_mat.pxd +62 -0
  35. sage/libs/arb/acb_modular.pxd +17 -0
  36. sage/libs/arb/acb_poly.pxd +216 -0
  37. sage/libs/arb/arb.pxd +240 -0
  38. sage/libs/arb/arb_fmpz_poly.pxd +21 -0
  39. sage/libs/arb/arb_hypgeom.pxd +83 -0
  40. sage/libs/arb/arb_wrap.h +34 -0
  41. sage/libs/arb/arf.pxd +131 -0
  42. sage/libs/arb/arith.cpython-311-aarch64-linux-gnu.so +0 -0
  43. sage/libs/arb/arith.pyx +87 -0
  44. sage/libs/arb/bernoulli.pxd +6 -0
  45. sage/libs/arb/mag.pxd +77 -0
  46. sage/libs/arb/types.pxd +37 -0
  47. sage/libs/flint/__init__.py +1 -0
  48. sage/libs/flint/acb.pxd +270 -0
  49. sage/libs/flint/acb_calc.pxd +22 -0
  50. sage/libs/flint/acb_dft.pxd +51 -0
  51. sage/libs/flint/acb_dirichlet.pxd +112 -0
  52. sage/libs/flint/acb_elliptic.pxd +42 -0
  53. sage/libs/flint/acb_hypgeom.pxd +169 -0
  54. sage/libs/flint/acb_macros.pxd +9 -0
  55. sage/libs/flint/acb_mat.pxd +136 -0
  56. sage/libs/flint/acb_mat_macros.pxd +10 -0
  57. sage/libs/flint/acb_modular.pxd +62 -0
  58. sage/libs/flint/acb_poly.pxd +251 -0
  59. sage/libs/flint/acb_poly_macros.pxd +8 -0
  60. sage/libs/flint/acb_theta.pxd +124 -0
  61. sage/libs/flint/acf.pxd +32 -0
  62. sage/libs/flint/aprcl.pxd +84 -0
  63. sage/libs/flint/arb.pxd +382 -0
  64. sage/libs/flint/arb_calc.pxd +31 -0
  65. sage/libs/flint/arb_fmpz_poly.pxd +34 -0
  66. sage/libs/flint/arb_fpwrap.pxd +215 -0
  67. sage/libs/flint/arb_hypgeom.pxd +147 -0
  68. sage/libs/flint/arb_macros.pxd +9 -0
  69. sage/libs/flint/arb_mat.pxd +140 -0
  70. sage/libs/flint/arb_mat_macros.pxd +10 -0
  71. sage/libs/flint/arb_poly.pxd +237 -0
  72. sage/libs/flint/arf.pxd +167 -0
  73. sage/libs/flint/arith.cpython-311-aarch64-linux-gnu.so +0 -0
  74. sage/libs/flint/arith.pxd +76 -0
  75. sage/libs/flint/arith.pyx +77 -0
  76. sage/libs/flint/arith_sage.cpython-311-aarch64-linux-gnu.so +0 -0
  77. sage/libs/flint/arith_sage.pyx +308 -0
  78. sage/libs/flint/bernoulli.pxd +28 -0
  79. sage/libs/flint/bool_mat.pxd +52 -0
  80. sage/libs/flint/ca.pxd +203 -0
  81. sage/libs/flint/ca_ext.pxd +34 -0
  82. sage/libs/flint/ca_field.pxd +32 -0
  83. sage/libs/flint/ca_mat.pxd +117 -0
  84. sage/libs/flint/ca_poly.pxd +104 -0
  85. sage/libs/flint/ca_vec.pxd +46 -0
  86. sage/libs/flint/calcium.pxd +27 -0
  87. sage/libs/flint/d_mat.pxd +39 -0
  88. sage/libs/flint/d_vec.pxd +32 -0
  89. sage/libs/flint/dirichlet.pxd +57 -0
  90. sage/libs/flint/dlog.pxd +53 -0
  91. sage/libs/flint/double_extras.pxd +24 -0
  92. sage/libs/flint/double_interval.pxd +36 -0
  93. sage/libs/flint/fexpr.pxd +104 -0
  94. sage/libs/flint/fexpr_builtin.pxd +20 -0
  95. sage/libs/flint/fft.pxd +66 -0
  96. sage/libs/flint/flint.pxd +36 -0
  97. sage/libs/flint/flint_ntl_wrap.h +35 -0
  98. sage/libs/flint/flint_sage.cpython-311-aarch64-linux-gnu.so +0 -0
  99. sage/libs/flint/flint_sage.pyx +163 -0
  100. sage/libs/flint/flint_wrap.h +190 -0
  101. sage/libs/flint/fmpq.pxd +137 -0
  102. sage/libs/flint/fmpq_mat.pxd +105 -0
  103. sage/libs/flint/fmpq_mat_macros.pxd +10 -0
  104. sage/libs/flint/fmpq_mpoly.pxd +165 -0
  105. sage/libs/flint/fmpq_mpoly_factor.pxd +30 -0
  106. sage/libs/flint/fmpq_poly.pxd +241 -0
  107. sage/libs/flint/fmpq_poly_macros.pxd +9 -0
  108. sage/libs/flint/fmpq_poly_sage.cpython-311-aarch64-linux-gnu.so +0 -0
  109. sage/libs/flint/fmpq_poly_sage.pxd +31 -0
  110. sage/libs/flint/fmpq_poly_sage.pyx +48 -0
  111. sage/libs/flint/fmpq_vec.pxd +27 -0
  112. sage/libs/flint/fmpz.pxd +256 -0
  113. sage/libs/flint/fmpz_extras.pxd +32 -0
  114. sage/libs/flint/fmpz_factor.pxd +42 -0
  115. sage/libs/flint/fmpz_factor_sage.cpython-311-aarch64-linux-gnu.so +0 -0
  116. sage/libs/flint/fmpz_factor_sage.pxd +4 -0
  117. sage/libs/flint/fmpz_factor_sage.pyx +29 -0
  118. sage/libs/flint/fmpz_lll.pxd +49 -0
  119. sage/libs/flint/fmpz_macros.pxd +8 -0
  120. sage/libs/flint/fmpz_mat.pxd +184 -0
  121. sage/libs/flint/fmpz_mat_macros.pxd +10 -0
  122. sage/libs/flint/fmpz_mod.pxd +46 -0
  123. sage/libs/flint/fmpz_mod_mat.pxd +71 -0
  124. sage/libs/flint/fmpz_mod_mpoly.pxd +161 -0
  125. sage/libs/flint/fmpz_mod_mpoly_factor.pxd +28 -0
  126. sage/libs/flint/fmpz_mod_poly.pxd +249 -0
  127. sage/libs/flint/fmpz_mod_poly_factor.pxd +46 -0
  128. sage/libs/flint/fmpz_mod_vec.pxd +27 -0
  129. sage/libs/flint/fmpz_mpoly.pxd +224 -0
  130. sage/libs/flint/fmpz_mpoly_factor.pxd +29 -0
  131. sage/libs/flint/fmpz_mpoly_q.pxd +57 -0
  132. sage/libs/flint/fmpz_poly.cpython-311-aarch64-linux-gnu.so +0 -0
  133. sage/libs/flint/fmpz_poly.pxd +407 -0
  134. sage/libs/flint/fmpz_poly.pyx +19 -0
  135. sage/libs/flint/fmpz_poly_factor.pxd +33 -0
  136. sage/libs/flint/fmpz_poly_macros.pxd +8 -0
  137. sage/libs/flint/fmpz_poly_mat.pxd +71 -0
  138. sage/libs/flint/fmpz_poly_q.pxd +55 -0
  139. sage/libs/flint/fmpz_poly_sage.cpython-311-aarch64-linux-gnu.so +0 -0
  140. sage/libs/flint/fmpz_poly_sage.pxd +20 -0
  141. sage/libs/flint/fmpz_poly_sage.pyx +500 -0
  142. sage/libs/flint/fmpz_vec.pxd +80 -0
  143. sage/libs/flint/fmpzi.pxd +52 -0
  144. sage/libs/flint/fq.pxd +97 -0
  145. sage/libs/flint/fq_default.pxd +84 -0
  146. sage/libs/flint/fq_default_mat.pxd +70 -0
  147. sage/libs/flint/fq_default_poly.pxd +97 -0
  148. sage/libs/flint/fq_default_poly_factor.pxd +39 -0
  149. sage/libs/flint/fq_embed.pxd +28 -0
  150. sage/libs/flint/fq_mat.pxd +83 -0
  151. sage/libs/flint/fq_nmod.pxd +95 -0
  152. sage/libs/flint/fq_nmod_embed.pxd +28 -0
  153. sage/libs/flint/fq_nmod_mat.pxd +83 -0
  154. sage/libs/flint/fq_nmod_mpoly.pxd +130 -0
  155. sage/libs/flint/fq_nmod_mpoly_factor.pxd +28 -0
  156. sage/libs/flint/fq_nmod_poly.pxd +202 -0
  157. sage/libs/flint/fq_nmod_poly_factor.pxd +47 -0
  158. sage/libs/flint/fq_nmod_vec.pxd +33 -0
  159. sage/libs/flint/fq_poly.pxd +204 -0
  160. sage/libs/flint/fq_poly_factor.pxd +47 -0
  161. sage/libs/flint/fq_vec.pxd +33 -0
  162. sage/libs/flint/fq_zech.pxd +99 -0
  163. sage/libs/flint/fq_zech_embed.pxd +28 -0
  164. sage/libs/flint/fq_zech_mat.pxd +78 -0
  165. sage/libs/flint/fq_zech_poly.pxd +198 -0
  166. sage/libs/flint/fq_zech_poly_factor.pxd +47 -0
  167. sage/libs/flint/fq_zech_vec.pxd +33 -0
  168. sage/libs/flint/gr.pxd +174 -0
  169. sage/libs/flint/gr_generic.pxd +215 -0
  170. sage/libs/flint/gr_mat.pxd +161 -0
  171. sage/libs/flint/gr_mpoly.pxd +68 -0
  172. sage/libs/flint/gr_poly.pxd +276 -0
  173. sage/libs/flint/gr_special.pxd +237 -0
  174. sage/libs/flint/gr_vec.pxd +120 -0
  175. sage/libs/flint/hypgeom.pxd +24 -0
  176. sage/libs/flint/long_extras.pxd +23 -0
  177. sage/libs/flint/mag.pxd +131 -0
  178. sage/libs/flint/mag_macros.pxd +8 -0
  179. sage/libs/flint/mpf_mat.pxd +36 -0
  180. sage/libs/flint/mpf_vec.pxd +34 -0
  181. sage/libs/flint/mpfr_mat.pxd +27 -0
  182. sage/libs/flint/mpfr_vec.pxd +25 -0
  183. sage/libs/flint/mpn_extras.pxd +41 -0
  184. sage/libs/flint/mpoly.pxd +72 -0
  185. sage/libs/flint/nf.pxd +19 -0
  186. sage/libs/flint/nf_elem.pxd +74 -0
  187. sage/libs/flint/nmod.pxd +35 -0
  188. sage/libs/flint/nmod_mat.pxd +104 -0
  189. sage/libs/flint/nmod_mpoly.pxd +144 -0
  190. sage/libs/flint/nmod_mpoly_factor.pxd +28 -0
  191. sage/libs/flint/nmod_poly.pxd +339 -0
  192. sage/libs/flint/nmod_poly_factor.pxd +44 -0
  193. sage/libs/flint/nmod_poly_linkage.pxi +710 -0
  194. sage/libs/flint/nmod_poly_mat.pxd +76 -0
  195. sage/libs/flint/nmod_vec.pxd +40 -0
  196. sage/libs/flint/ntl_interface.pxd +17 -0
  197. sage/libs/flint/padic.pxd +93 -0
  198. sage/libs/flint/padic_mat.pxd +64 -0
  199. sage/libs/flint/padic_poly.pxd +88 -0
  200. sage/libs/flint/partitions.pxd +23 -0
  201. sage/libs/flint/perm.pxd +26 -0
  202. sage/libs/flint/profiler.pxd +24 -0
  203. sage/libs/flint/qadic.pxd +77 -0
  204. sage/libs/flint/qfb.pxd +44 -0
  205. sage/libs/flint/qqbar.pxd +172 -0
  206. sage/libs/flint/qsieve.cpython-311-aarch64-linux-gnu.so +0 -0
  207. sage/libs/flint/qsieve.pxd +41 -0
  208. sage/libs/flint/qsieve.pyx +21 -0
  209. sage/libs/flint/qsieve_sage.cpython-311-aarch64-linux-gnu.so +0 -0
  210. sage/libs/flint/qsieve_sage.pyx +67 -0
  211. sage/libs/flint/thread_pool.pxd +25 -0
  212. sage/libs/flint/types.pxd +2076 -0
  213. sage/libs/flint/ulong_extras.cpython-311-aarch64-linux-gnu.so +0 -0
  214. sage/libs/flint/ulong_extras.pxd +141 -0
  215. sage/libs/flint/ulong_extras.pyx +21 -0
  216. sage/libs/flint/ulong_extras_sage.cpython-311-aarch64-linux-gnu.so +0 -0
  217. sage/libs/flint/ulong_extras_sage.pyx +21 -0
  218. sage/matrix/all__sagemath_flint.py +1 -0
  219. sage/matrix/change_ring.cpython-311-aarch64-linux-gnu.so +0 -0
  220. sage/matrix/change_ring.pyx +43 -0
  221. sage/matrix/matrix_complex_ball_dense.cpython-311-aarch64-linux-gnu.so +0 -0
  222. sage/matrix/matrix_complex_ball_dense.pxd +14 -0
  223. sage/matrix/matrix_complex_ball_dense.pyx +973 -0
  224. sage/matrix/matrix_cyclo_dense.cpython-311-aarch64-linux-gnu.so +0 -0
  225. sage/matrix/matrix_cyclo_dense.pxd +16 -0
  226. sage/matrix/matrix_cyclo_dense.pyx +1761 -0
  227. sage/matrix/matrix_integer_dense.cpython-311-aarch64-linux-gnu.so +0 -0
  228. sage/matrix/matrix_integer_dense.pxd +32 -0
  229. sage/matrix/matrix_integer_dense.pyx +5801 -0
  230. sage/matrix/matrix_integer_dense_hnf.py +1294 -0
  231. sage/matrix/matrix_integer_dense_saturation.py +346 -0
  232. sage/matrix/matrix_integer_sparse.cpython-311-aarch64-linux-gnu.so +0 -0
  233. sage/matrix/matrix_integer_sparse.pxd +9 -0
  234. sage/matrix/matrix_integer_sparse.pyx +1090 -0
  235. sage/matrix/matrix_rational_dense.cpython-311-aarch64-linux-gnu.so +0 -0
  236. sage/matrix/matrix_rational_dense.pxd +23 -0
  237. sage/matrix/matrix_rational_dense.pyx +2995 -0
  238. sage/matrix/matrix_rational_sparse.cpython-311-aarch64-linux-gnu.so +0 -0
  239. sage/matrix/matrix_rational_sparse.pxd +11 -0
  240. sage/matrix/matrix_rational_sparse.pyx +789 -0
  241. sage/matrix/misc_flint.cpython-311-aarch64-linux-gnu.so +0 -0
  242. sage/matrix/misc_flint.pyx +109 -0
  243. sage/modular/all__sagemath_flint.py +1 -0
  244. sage/modular/modform/all__sagemath_flint.py +1 -0
  245. sage/modular/modform/eis_series_cython.cpython-311-aarch64-linux-gnu.so +0 -0
  246. sage/modular/modform/eis_series_cython.pyx +226 -0
  247. sage/modular/modsym/all__sagemath_flint.py +1 -0
  248. sage/modular/modsym/apply.cpython-311-aarch64-linux-gnu.so +0 -0
  249. sage/modular/modsym/apply.pxd +6 -0
  250. sage/modular/modsym/apply.pyx +113 -0
  251. sage/modular/modsym/heilbronn.cpython-311-aarch64-linux-gnu.so +0 -0
  252. sage/modular/modsym/heilbronn.pyx +966 -0
  253. sage/modular/pollack_stevens/all__sagemath_flint.py +1 -0
  254. sage/modular/pollack_stevens/dist.cpython-311-aarch64-linux-gnu.so +0 -0
  255. sage/modular/pollack_stevens/dist.pxd +38 -0
  256. sage/modular/pollack_stevens/dist.pyx +1439 -0
  257. sage/quivers/algebra.py +691 -0
  258. sage/quivers/algebra_elements.cpython-311-aarch64-linux-gnu.so +0 -0
  259. sage/quivers/algebra_elements.pxd +97 -0
  260. sage/quivers/algebra_elements.pxi +1324 -0
  261. sage/quivers/algebra_elements.pyx +1424 -0
  262. sage/quivers/all.py +1 -0
  263. sage/quivers/ar_quiver.py +917 -0
  264. sage/quivers/homspace.py +640 -0
  265. sage/quivers/morphism.py +1282 -0
  266. sage/quivers/path_semigroup.py +1155 -0
  267. sage/quivers/paths.cpython-311-aarch64-linux-gnu.so +0 -0
  268. sage/quivers/paths.pxd +13 -0
  269. sage/quivers/paths.pyx +809 -0
  270. sage/quivers/representation.py +2975 -0
  271. sage/rings/all__sagemath_flint.py +37 -0
  272. sage/rings/cif.py +4 -0
  273. sage/rings/complex_arb.cpython-311-aarch64-linux-gnu.so +0 -0
  274. sage/rings/complex_arb.pxd +29 -0
  275. sage/rings/complex_arb.pyx +5176 -0
  276. sage/rings/complex_interval.cpython-311-aarch64-linux-gnu.so +0 -0
  277. sage/rings/complex_interval.pxd +30 -0
  278. sage/rings/complex_interval.pyx +2475 -0
  279. sage/rings/complex_interval_field.py +711 -0
  280. sage/rings/convert/all.py +1 -0
  281. sage/rings/convert/mpfi.cpython-311-aarch64-linux-gnu.so +0 -0
  282. sage/rings/convert/mpfi.pxd +6 -0
  283. sage/rings/convert/mpfi.pyx +576 -0
  284. sage/rings/factorint_flint.cpython-311-aarch64-linux-gnu.so +0 -0
  285. sage/rings/factorint_flint.pyx +99 -0
  286. sage/rings/fraction_field_FpT.cpython-311-aarch64-linux-gnu.so +0 -0
  287. sage/rings/fraction_field_FpT.pxd +28 -0
  288. sage/rings/fraction_field_FpT.pyx +2043 -0
  289. sage/rings/imaginary_unit.py +5 -0
  290. sage/rings/monomials.py +73 -0
  291. sage/rings/number_field/S_unit_solver.py +2870 -0
  292. sage/rings/number_field/all__sagemath_flint.py +7 -0
  293. sage/rings/number_field/bdd_height.py +664 -0
  294. sage/rings/number_field/class_group.py +762 -0
  295. sage/rings/number_field/galois_group.py +1307 -0
  296. sage/rings/number_field/homset.py +612 -0
  297. sage/rings/number_field/maps.py +687 -0
  298. sage/rings/number_field/morphism.py +272 -0
  299. sage/rings/number_field/number_field.py +12820 -0
  300. sage/rings/number_field/number_field_element.cpython-311-aarch64-linux-gnu.so +0 -0
  301. sage/rings/number_field/number_field_element.pxd +59 -0
  302. sage/rings/number_field/number_field_element.pyx +5735 -0
  303. sage/rings/number_field/number_field_element_quadratic.cpython-311-aarch64-linux-gnu.so +0 -0
  304. sage/rings/number_field/number_field_element_quadratic.pxd +34 -0
  305. sage/rings/number_field/number_field_element_quadratic.pyx +3185 -0
  306. sage/rings/number_field/number_field_ideal_rel.py +925 -0
  307. sage/rings/number_field/number_field_morphisms.cpython-311-aarch64-linux-gnu.so +0 -0
  308. sage/rings/number_field/number_field_morphisms.pyx +781 -0
  309. sage/rings/number_field/number_field_rel.py +2734 -0
  310. sage/rings/number_field/order.py +2981 -0
  311. sage/rings/number_field/order_ideal.py +804 -0
  312. sage/rings/number_field/selmer_group.py +715 -0
  313. sage/rings/number_field/small_primes_of_degree_one.py +242 -0
  314. sage/rings/number_field/splitting_field.py +606 -0
  315. sage/rings/number_field/structure.py +380 -0
  316. sage/rings/number_field/unit_group.py +721 -0
  317. sage/rings/padics/all__sagemath_flint.py +3 -0
  318. sage/rings/polynomial/all__sagemath_flint.py +1 -0
  319. sage/rings/polynomial/complex_roots.py +312 -0
  320. sage/rings/polynomial/evaluation_flint.cpython-311-aarch64-linux-gnu.so +0 -0
  321. sage/rings/polynomial/evaluation_flint.pxd +7 -0
  322. sage/rings/polynomial/evaluation_flint.pyx +68 -0
  323. sage/rings/polynomial/hilbert.cpython-311-aarch64-linux-gnu.so +0 -0
  324. sage/rings/polynomial/hilbert.pyx +602 -0
  325. sage/rings/polynomial/polynomial_complex_arb.cpython-311-aarch64-linux-gnu.so +0 -0
  326. sage/rings/polynomial/polynomial_complex_arb.pxd +7 -0
  327. sage/rings/polynomial/polynomial_complex_arb.pyx +963 -0
  328. sage/rings/polynomial/polynomial_integer_dense_flint.cpython-311-aarch64-linux-gnu.so +0 -0
  329. sage/rings/polynomial/polynomial_integer_dense_flint.pxd +13 -0
  330. sage/rings/polynomial/polynomial_integer_dense_flint.pyx +1881 -0
  331. sage/rings/polynomial/polynomial_number_field.cpython-311-aarch64-linux-gnu.so +0 -0
  332. sage/rings/polynomial/polynomial_number_field.pyx +345 -0
  333. sage/rings/polynomial/polynomial_rational_flint.cpython-311-aarch64-linux-gnu.so +0 -0
  334. sage/rings/polynomial/polynomial_rational_flint.pxd +20 -0
  335. sage/rings/polynomial/polynomial_rational_flint.pyx +2598 -0
  336. sage/rings/polynomial/polynomial_zmod_flint.cpython-311-aarch64-linux-gnu.so +0 -0
  337. sage/rings/polynomial/polynomial_zmod_flint.pxd +20 -0
  338. sage/rings/polynomial/polynomial_zmod_flint.pyx +1063 -0
  339. sage/rings/polynomial/real_roots.cpython-311-aarch64-linux-gnu.so +0 -0
  340. sage/rings/polynomial/real_roots.pxd +81 -0
  341. sage/rings/polynomial/real_roots.pyx +4704 -0
  342. sage/rings/polynomial/refine_root.cpython-311-aarch64-linux-gnu.so +0 -0
  343. sage/rings/polynomial/refine_root.pyx +142 -0
  344. sage/rings/polynomial/weil/all.py +4 -0
  345. sage/rings/polynomial/weil/power_sums.h +46 -0
  346. sage/rings/polynomial/weil/weil_polynomials.cpython-311-aarch64-linux-gnu.so +0 -0
  347. sage/rings/polynomial/weil/weil_polynomials.pyx +596 -0
  348. sage/rings/qqbar.py +9025 -0
  349. sage/rings/real_arb.cpython-311-aarch64-linux-gnu.so +0 -0
  350. sage/rings/real_arb.pxd +21 -0
  351. sage/rings/real_arb.pyx +4065 -0
  352. sage/rings/real_interval_absolute.cpython-311-aarch64-linux-gnu.so +0 -0
  353. sage/rings/real_interval_absolute.pyx +1073 -0
  354. sage/rings/real_mpfi.cpython-311-aarch64-linux-gnu.so +0 -0
  355. sage/rings/real_mpfi.pyx +5428 -0
  356. sage/schemes/all__sagemath_flint.py +1 -0
  357. sage/schemes/elliptic_curves/all__sagemath_flint.py +1 -0
  358. sage/schemes/elliptic_curves/descent_two_isogeny.cpython-311-aarch64-linux-gnu.so +0 -0
  359. sage/schemes/elliptic_curves/descent_two_isogeny.pyx +1387 -0
  360. sage/schemes/elliptic_curves/descent_two_isogeny_pari.pxd +5 -0
@@ -0,0 +1,2975 @@
1
+ # sage_setup: distribution = sagemath-flint
2
+ # sage.doctest: needs sage.graphs sage.modules
3
+ r"""
4
+ Quiver Representations
5
+
6
+ AUTHORS:
7
+
8
+ - Jim Stark (2012-03-04): Initial implementation of acyclic quivers without
9
+ relations.
10
+ - Simon King (2013-05, 2014-02): Split code up. Allow cyclic quivers where
11
+ possible.
12
+
13
+ A quiver is a directed graph used for representation theory. In our
14
+ representation theoretic code, it is assumed that
15
+
16
+ - the vertices of the quiver are labelled by integers, and
17
+
18
+ - each edge of the quiver is labelled with a nonempty string. The label
19
+ cannot begin with ``'e_'`` or contain ``'*'`` and distinct edges must have
20
+ distinct labels.
21
+
22
+ As far as the :class:`~sage.graphs.digraph.DiGraph` class is concerned, a
23
+ path is a finite list of pairwise distinct vertices `v_1, ..., v_n` such
24
+ that there exists an edge from `v_i` to `v_{i + 1}`. If there are
25
+ multiple edges between the same two vertices this does not contribute
26
+ additional paths as listed by the :class:`~sage.graphs.digraph.DiGraph`
27
+ class; for example only two paths are listed from 1 to 3 in ``Q``::
28
+
29
+ sage: Q = DiGraph({1:{2:['a','b'], 3:['c']}, 2:{3:['d']}})
30
+ sage: Q.edges(sort=True)
31
+ [(1, 2, 'a'), (1, 2, 'b'), (1, 3, 'c'), (2, 3, 'd')]
32
+ sage: Q.all_paths(1, 3)
33
+ [[1, 2, 3], [1, 3]]
34
+
35
+ The notion of a path in a quiver (in representation theory) is
36
+ fundamentally different in several aspects. First, paths are no longer
37
+ required to have distinct vertices, or even distinct edges; thus, "path"
38
+ in quiver theory is closer to the notion of "walk" in graph theory.
39
+ Furthermore, paths in quiver theory "know" their edges, so parallel edges
40
+ between the same two vertices of a Quiver make different paths. But
41
+ paths in quiver theory also "know" their vertices, so that a length-`0`
42
+ path from `a` to `a` is not the same as a length-`0` path from `b` to `b`
43
+ for `a \neq b`.
44
+ Formally, we say that a path is given by two vertices, ``start`` and
45
+ ``end``, and a finite (possibly empty) list of edges `e_1, e_2, \ldots, e_n`
46
+ such that the initial vertex of `e_1` is ``start``, the final vertex of `e_i`
47
+ is the initial vertex of `e_{i + 1}`, and the final vertex of `e_n` is
48
+ ``end``. In the case where no edges are specified, we must have
49
+ ``start = end`` and the path is called the trivial path at the given vertex.
50
+
51
+ Quiver paths in the sense stated above correspond to the elements of a
52
+ partial semigroup, with multiplication of paths given by concatenation. Hence,
53
+ rather than overloading the method name inherited from
54
+ :class:`~sage.graphs.digraph.DiGraph` or inventing a
55
+ new method name, we move this functionality to this so-called *path
56
+ semigroup*. Note that with this definition there are three paths from 1 to 3
57
+ in our example::
58
+
59
+ sage: Q.path_semigroup().all_paths(1, 3)
60
+ [a*d, b*d, c]
61
+
62
+ The returned paths are of type :class:`~sage.quivers.paths.QuiverPath`, which
63
+ are elements in the path semigroup that is associated with the quiver (a
64
+ partial semigroup, which does not generally have a neutral element). You can
65
+ specify a :class:`~sage.quivers.paths.QuiverPath` by giving an edge or a
66
+ list of edges, passed as arguments to the path semigroup containing this path.
67
+ Here an edge is a tuple of the form ``(i, j, l)``, where ``i`` and ``j``
68
+ are vertices and ``l`` is the label of an edge from i to j::
69
+
70
+ sage: p = Q.path_semigroup()([(1, 2, 'a'), (2, 3, 'd')])
71
+ sage: p
72
+ a*d
73
+
74
+ Trivial paths are indicated by passing a list containing the tuple ``(vertex, vertex)``::
75
+
76
+ sage: Q.path_semigroup()([(3, 3)])
77
+ e_3
78
+
79
+ Here is an alternative way to define a path::
80
+
81
+ sage: PQ = Q.path_semigroup()
82
+ sage: q = PQ(['a', 'd'])
83
+ sage: p == q
84
+ True
85
+
86
+ If the vertices along the path do not match, a value error is raised::
87
+
88
+ sage: inv1 = PQ([(2, 3, 'd'), (1, 2, 'a')])
89
+ Traceback (most recent call last):
90
+ ...
91
+ ValueError: edge d ends at 3, but edge a starts at 1
92
+ sage: inv2 = PQ([(1, 2, 'a'), (1, 2, 'a')])
93
+ Traceback (most recent call last):
94
+ ...
95
+ ValueError: edge a ends at 2, but edge a starts at 1
96
+ sage: inv3 = PQ([(1, 2, 'x')])
97
+ Traceback (most recent call last):
98
+ ...
99
+ ValueError: (1, 2, 'x') is not an edge
100
+
101
+ The ``*`` operator is concatenation of paths. If the two paths do not compose,
102
+ then the result is ``None`` (whence the "partial" in "partial semigroup"). ::
103
+
104
+ sage: print(p*q)
105
+ None
106
+
107
+ Let us now construct a larger quiver::
108
+
109
+ sage: Qbig = DiGraph({1:{2:['a','b'], 3:['c']}, 2:{3:['d']}, 3:{4:['e']}, 4:{5:['f']}, 5:{1:['g']} })
110
+ sage: Pbig = Qbig.path_semigroup()
111
+
112
+ Since ``Q`` is a sub-digraph of ``Qbig``, we have a coercion of the associated
113
+ path semigroups::
114
+
115
+ sage: Pbig.has_coerce_map_from(PQ)
116
+ True
117
+
118
+ In particular, ``p`` is considered to be an element of ``Pbig``, and can be
119
+ composed with paths that were defined for the larger quiver::
120
+
121
+ sage: p in Pbig
122
+ True
123
+ sage: p*Pbig([(3, 4, 'e')])
124
+ a*d*e
125
+ sage: Pbig([(4, 5, 'f'), (5, 1, 'g')])*p
126
+ f*g*a*d
127
+
128
+ The length of a path is the number of edges in that path::
129
+
130
+ sage: len(p)
131
+ 2
132
+ sage: triv = PQ([(1, 1)])
133
+ sage: len(triv)
134
+ 0
135
+
136
+ List index and slice notation can be used to access the edges in a path.
137
+ QuiverPaths can also be iterated over. Trivial paths have no elements::
138
+
139
+ sage: for x in p: print(x)
140
+ (1, 2, 'a')
141
+ (2, 3, 'd')
142
+ sage: triv[:]
143
+ e_1
144
+
145
+ There are methods giving the initial and terminal vertex of a path::
146
+
147
+ sage: p.initial_vertex()
148
+ 1
149
+ sage: p.terminal_vertex()
150
+ 3
151
+
152
+ :class:`~sage.quivers.paths.QuiverPath` form the basis of the quiver
153
+ algebra of a quiver. Given a field `k` and a quiver `Q`, the quiver
154
+ algebra `kQ` is, as a vector space, the free `k`-vector space whose basis
155
+ is the set of all paths in `Q`. Multiplication is defined on this basis
156
+ and extended bilinearly. The product of two basis elements is given by
157
+ path composition when it makes sense and is set to be zero otherwise.
158
+ Specifically, if the terminal vertex of the left path equals the initial
159
+ vertex of the right path, then their product is the concatenation of the
160
+ two paths, and otherwise their product is zero. In sage, quiver algebras
161
+ are handled by the :class:`~sage.quivers.algebra.QuiverAlgebra` class::
162
+
163
+ sage: A = PQ.algebra(GF(7))
164
+ sage: A
165
+ Path algebra of Multi-digraph on 3 vertices over Finite Field of size 7
166
+
167
+ Quivers have a method that creates their algebra over a given field (or,
168
+ more generally, commutative ring). Note that
169
+ :class:`~sage.quivers.algebra.QuiverAlgebras` are uniquely defined by
170
+ their quiver and field, and play nicely with coercions of the underlying
171
+ path semigroups::
172
+
173
+ sage: A is PQ.algebra(GF(7))
174
+ True
175
+ sage: A is PQ.algebra(RR)
176
+ False
177
+ sage: Q1 = Q.copy()
178
+ sage: Q1.add_vertex(4)
179
+ sage: PQ1 = Q1.path_semigroup()
180
+ sage: A is PQ1.algebra(GF(7))
181
+ False
182
+ sage: Pbig.algebra(GF(7)).has_coerce_map_from(A)
183
+ True
184
+
185
+ The :class:`~sage.quivers.algebra.QuiverAlgebra` can create elements
186
+ from :class:`~sage.quivers.paths.QuiverPaths` or from elements of the
187
+ base ring::
188
+
189
+ sage: A(5)
190
+ 5*e_1 + 5*e_2 + 5*e_3
191
+ sage: r = PQ([(1, 2, 'b'), (2, 3, 'd')])
192
+ sage: e2 = PQ([(2, 2)])
193
+ sage: x = A(p) + A(e2)
194
+ sage: x
195
+ a*d + e_2
196
+ sage: y = A(p) + A(r)
197
+ sage: y
198
+ b*d + a*d
199
+
200
+ :class:`~sage.quivers.algebra.QuiverAlgebras` are `\NN`-graded algebras.
201
+ The grading is given by assigning to each basis element the length of the
202
+ path corresponding to that basis element::
203
+
204
+ sage: x.is_homogeneous()
205
+ False
206
+ sage: x.degree()
207
+ Traceback (most recent call last):
208
+ ...
209
+ ValueError: element is not homogeneous
210
+ sage: y.is_homogeneous()
211
+ True
212
+ sage: y.degree()
213
+ 2
214
+ sage: A[1]
215
+ Free module spanned by [a, b, c, d] over Finite Field of size 7
216
+ sage: A[2]
217
+ Free module spanned by [a*d, b*d] over Finite Field of size 7
218
+
219
+ The category of right modules over a given quiver algebra is equivalent to the
220
+ category of representations of that quiver. A quiver representation is a
221
+ diagram in the category of vector spaces whose underlying graph is the quiver.
222
+ So to each vertex of the quiver we assign a vector space and to each edge of
223
+ the quiver a linear map between the vector spaces assigned to the start and end
224
+ vertices of that edge. To create the zero representation we just specify the
225
+ base ring and the path semigroup::
226
+
227
+ sage: Z = Q1.path_semigroup().representation(GF(5))
228
+ sage: Z.is_zero()
229
+ True
230
+
231
+ To each vertex of a quiver there is associated a simple module, an
232
+ indecomposable projective, and an indecomposable injective, and these can
233
+ be created from the quiver::
234
+
235
+ sage: S = PQ.S(GF(3), 1)
236
+ sage: I = PQ.I(QQ, 2)
237
+ sage: P = PQ.P(GF(3), 1)
238
+
239
+ Radicals, socles, tops, and quotients can all be computed and we can test if
240
+ modules are simple or semisimple, get their dimension, and test for equality.
241
+ Like quivers, :class:`~sage.quivers.representation.QuiverRep` objects
242
+ are unique and therefore equal if and only if they are identical::
243
+
244
+ sage: P.is_simple()
245
+ False
246
+ sage: P.dimension()
247
+ 6
248
+ sage: R = P.radical()
249
+ sage: P.socle()
250
+ Representation with dimension vector (0, 0, 3)
251
+ sage: (P/R).is_simple()
252
+ True
253
+ sage: P == R
254
+ False
255
+ sage: P.top() is P/R
256
+ True
257
+
258
+ There are special methods to deal with modules that are given as right
259
+ ideals in the quiver algebra. To create such a module pass the keyword
260
+ ``option='paths'`` along with a path or list of paths that generate the
261
+ desired ideal::
262
+
263
+ sage: M = PQ.representation(QQ, [[(1, 1)], [(1, 2, 'a')]], option='paths')
264
+ sage: M.dimension_vector()
265
+ (1, 2, 3)
266
+
267
+ There are also special methods to deal with modules that are given as the
268
+ linear dual of a right ideal in the quiver algebra. To create such a
269
+ module, pass the keyword ``option='dual paths'`` to the constructor along
270
+ with a path or list of paths. The module returned is the dual of the
271
+ ideal created in the opposite quiver by the reverses of the given paths::
272
+
273
+ sage: D = PQ.representation(QQ, [[(1, 1)], [(1, 2, 'a')]], option='dual paths')
274
+ sage: D.dimension_vector()
275
+ (2, 0, 0)
276
+
277
+ For modules that are not a standard module or an ideal of the quiver algebra
278
+ :class:`~sage.quivers.representation.QuiverRep` can take as input two
279
+ dictionaries. The first associates to each vertex a vector space or an
280
+ integer (the desired dimension of the vector space), the second associates to
281
+ each edge a map or a matrix or something from which sage can construct a map::
282
+
283
+ sage: PQ2 = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
284
+ sage: M2 = PQ2.representation(QQ, {1: QQ^2, 2: QQ^1}, {(1, 2, 'a'): [1, 0], (1, 2, 'b'): [0, 1]})
285
+ sage: M.get_space(2)
286
+ Vector space of dimension 2 over Rational Field
287
+ sage: M2.get_space(2)
288
+ Vector space of dimension 1 over Rational Field
289
+ sage: M.get_map((1, 2, 'a'))
290
+ Vector space morphism represented by the matrix:
291
+ [1 0]
292
+ Domain: Vector space of dimension 1 over Rational Field
293
+ Codomain: Vector space of dimension 2 over Rational Field
294
+
295
+ A homomorphism between two quiver representations is given by homomorphisms
296
+ between the spaces assigned to the vertices of those representations such that
297
+ those homomorphisms commute with the edge maps of the representations. The
298
+ homomorphisms are created in the usual Sage syntax, the defining data given by
299
+ a dictionary associating maps to vertices::
300
+
301
+ sage: P2 = PQ2.P(QQ, 1)
302
+ sage: f = P2.hom({1:[1, 1], 2:[[1], [1]]}, M2)
303
+
304
+ When the domain is given as a right ideal in the quiver algebra we can also
305
+ create a homomorphism by just giving a single element in the codomain.
306
+ The map is then induced by acting on that element::
307
+
308
+ sage: x = P2.gens('x')[0]
309
+ sage: x
310
+ x_0
311
+ sage: f == P2.hom(f(x), M2)
312
+ True
313
+
314
+ As you can see, the above homomorphisms can be applied to elements. Just
315
+ like elements, addition is defined via the ``+`` operator. On elements scalar
316
+ multiplication is defined via the ``*`` operator but on homomorphisms ``*``
317
+ defines composition, so scalar multiplication is done using a method::
318
+
319
+ sage: g = f + f
320
+ sage: g == f.scalar_mult(2)
321
+ True
322
+ sage: g == 2*f # This multiplies the map with the scalar 2
323
+ True
324
+ sage: g(x) == 2*f(x) # This applies the map, then multiplies by the scalar
325
+ True
326
+
327
+ The ``direct_sum`` method for modules returns only the resulting module by
328
+ default. But can also return the projection and inclusion homomorphisms into
329
+ the various factors::
330
+
331
+ sage: N2, inclusions, projections = M2.direct_sum([P2], return_maps=True)
332
+ sage: inclusions[0].domain() is M2
333
+ True
334
+ sage: projections[0].codomain() is M2
335
+ True
336
+ sage: (projections[0]*inclusions[0]).is_isomorphism()
337
+ True
338
+
339
+ As you see above we can determine if a given map is an isomorphism. Testing
340
+ for injectivity and surjectivity works as well::
341
+
342
+ sage: f.is_injective()
343
+ False
344
+ sage: f.is_surjective()
345
+ False
346
+
347
+ We can create all the standard modules associated to maps::
348
+
349
+ sage: f.kernel()
350
+ Representation with dimension vector (0, 1)
351
+ sage: f.cokernel()
352
+ Representation with dimension vector (1, 0)
353
+ sage: im = f.image()
354
+ sage: im
355
+ Representation with dimension vector (1, 1)
356
+
357
+ These methods, as well as the ``submodule`` and ``quotient`` methods that are
358
+ defined for representations, return only the resulting representation. To get
359
+ the inclusion map of a submodule or the factor homomorphism of a quotient use
360
+ ``coerce_map_from``::
361
+
362
+ sage: incl = M2.coerce_map_from(im)
363
+ sage: incl.domain() is im
364
+ True
365
+ sage: incl.codomain() is M2
366
+ True
367
+ sage: incl.is_injective()
368
+ True
369
+
370
+ Both :class:`~sage.quivers.representation.QuiverRep` objects and
371
+ :class:`~sage.quivers.homspace.QuiverRepHom` objects have ``linear_dual`` and
372
+ ``algebraic_dual`` methods. The ``linear_dual`` method applies the functor
373
+ `Hom_k(..., k)` where `k` is the base ring of the representation, and the
374
+ ``algebraic_dual`` method applies the functor `Hom_Q(..., kQ)` where `kQ`
375
+ is the quiver algebra. Both these functors yield left modules. A left
376
+ module is equivalent to a right module over the opposite algebra, and the
377
+ opposite of a quiver algebra is the algebra of the opposite quiver, so both
378
+ these methods yield modules and representations of the opposite quiver::
379
+
380
+ sage: f.linear_dual()
381
+ Homomorphism of representations of Reverse of (): Multi-digraph on 2 vertices
382
+ sage: D = M2.algebraic_dual()
383
+ sage: D.quiver() is PQ2.reverse().quiver()
384
+ True
385
+
386
+ .. TODO::
387
+
388
+ Change the wording ``Reverse of ()`` into something more meaningful.
389
+
390
+ There is a method returning the projective cover of any module. Note that
391
+ this method returns the homomorphism; to get the module take the domain of
392
+ the homomorphism::
393
+
394
+ sage: cov = M2.projective_cover()
395
+ sage: cov
396
+ Homomorphism of representations of Multi-digraph on 2 vertices
397
+ sage: cov.domain()
398
+ Representation with dimension vector (2, 4)
399
+
400
+ As projective covers are computable, so are the transpose and Auslander-Reiten
401
+ translates of modules::
402
+
403
+ sage: M2.transpose()
404
+ Representation with dimension vector (4, 3)
405
+ sage: PQ2.I(QQ, 1).AR_translate()
406
+ Representation with dimension vector (3, 2)
407
+
408
+ We have already used the ``gens`` method above to get an element of a quiver
409
+ representation. An element of a quiver representation is simply a choice of
410
+ element from each of the spaces assigned to the vertices of the quiver.
411
+ Addition, subtraction, and scalar multiplication are performed pointwise and
412
+ implemented by the usual operators::
413
+
414
+ sage: M2.dimension_vector()
415
+ (2, 1)
416
+ sage: x, y, z = M2.gens('xyz')
417
+ sage: 2*x + y != x + 2*y
418
+ True
419
+
420
+ To create a specific element of a given representation we just specify the
421
+ representation and a dictionary associating to each vertex an element of the
422
+ space associated to that vertex in the representation::
423
+
424
+ sage: w = M2({1:(1, -1), 2:(3,)})
425
+ sage: w.get_element(1)
426
+ (1, -1)
427
+
428
+ The right action of a quiver algebra on an element is implemented via
429
+ the ``*`` operator::
430
+
431
+ sage: A2 = x.quiver().path_semigroup().algebra(QQ)
432
+ sage: a = A2('a')
433
+ sage: x*a == z
434
+ True
435
+ """
436
+
437
+ # ****************************************************************************
438
+ # Copyright (C) 2012 Jim Stark <jstarx@gmail.com>
439
+ # 2013 Simon King <simon.king@uni-jena.de>
440
+ #
441
+ # Distributed under the terms of the GNU General Public License (GPL)
442
+ #
443
+ # This code is distributed in the hope that it will be useful,
444
+ # but WITHOUT ANY WARRANTY; without even the implied warranty
445
+ # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
446
+ #
447
+ # See the GNU General Public License for more details; the full text
448
+ # is available at:
449
+ #
450
+ # https://www.gnu.org/licenses/
451
+ # ****************************************************************************
452
+ from __future__ import annotations
453
+
454
+ from sage.misc.cachefunc import cached_method
455
+ from sage.misc.fast_methods import WithEqualityById
456
+ from sage.modules.module import Module
457
+ from sage.structure.element import ModuleElement
458
+ from sage.structure.factory import UniqueFactory
459
+
460
+
461
+ class QuiverRepFactory(UniqueFactory):
462
+ r"""
463
+ A quiver representation is a diagram in the category of vector spaces whose
464
+ underlying graph is the quiver. Giving a finite dimensional representation
465
+ is equivalent to giving a finite dimensional right module for the path
466
+ algebra of the quiver.
467
+
468
+ INPUT:
469
+
470
+ The first two arguments specify the base ring and the quiver,
471
+ and they are always required:
472
+
473
+ - ``k`` -- ring, the base ring of the representation
474
+
475
+ - ``P`` -- the partial semigroup formed by the paths of the quiver of the
476
+ representation
477
+
478
+ Then to specify the spaces and maps associated to the quiver
479
+ there are three possible options. The first is the ``'values'`` option,
480
+ where the next two arguments give the data to be assigned. The following
481
+ can either be the next two entries in the argument list or they can be
482
+ passed by keyword. If the argument list is long enough the keywords
483
+ are ignored; the keywords are only checked in the event that the argument
484
+ list does not have enough entries after ``P``.
485
+
486
+ - ``spaces`` -- dictionary (default: empty) associating to each vertex a
487
+ free module over the base ring `k`. Not all vertices must be specified;
488
+ unspecified vertices are automatically set to `k^0`. Keys of the
489
+ dictionary that don't correspond to vertices are ignored.
490
+
491
+ - ``maps`` -- dictionary (default: empty) associating to each edge a map
492
+ whose domain and codomain are the spaces associated to the initial and
493
+ terminal vertex of the edge respectively. Not all edges must be
494
+ specified; unspecified edges are automatically set to the zero map. Keys
495
+ of the dictionary that don't correspond to edges are ignored.
496
+
497
+ The second option is the ``paths`` option which creates a module by
498
+ generating a right ideal from a list of paths. Thus the basis elements
499
+ of this module correspond to paths of the quiver and the maps are given
500
+ by right multiplication by the corresponding edge. As above this can be
501
+ passed either as the next entry in the argument list or as a keyword.
502
+ The keyword is only checked if there is no entry in the argument list
503
+ after ``Q``.
504
+
505
+ - ``basis`` -- list; a nonempty list of paths in the quiver ``Q``.
506
+ Entries that do not represent valid paths are ignored and duplicate
507
+ paths are deleted. There must be at least one valid path in the list
508
+ or a :exc:`ValueError` is raised. The closure of this list under right
509
+ multiplication forms the basis of the resulting representation.
510
+
511
+ The third option is the ``dual paths`` option which creates the dual of
512
+ a left ideal in the quiver algebra. Thus the basis elements of this
513
+ module correspond to paths of the quiver and the maps are given by
514
+ deleting the corresponding edge from the start of the path (the edge map
515
+ is zero on a path if that edge is not the initial edge of the path).
516
+ As above this can be passed either as the next entry in the argument
517
+ list or as a keyword.
518
+
519
+ - ``basis`` -- list; a nonempty list of paths in the quiver ``Q``.
520
+ Entries that do not represent valid paths are ignored and duplicate
521
+ paths are deleted. There must be at least one valid path in the list
522
+ or a :exc:`ValueError` is raised. The closure of this list under left
523
+ multiplication of edges forms the basis of the resulting representation.
524
+
525
+ Using the second and third options requires that the following keyword be
526
+ passed to the constructor. This must be passed as a keyword.
527
+
528
+ - ``option`` -- string (default: ``None``); either ``'values'`` or
529
+ ``'paths'`` or ``'dual paths'``. ``None`` is equivalent to ``'values'``
530
+
531
+ OUTPUT: :class:`QuiverRep`
532
+
533
+ EXAMPLES::
534
+
535
+ sage: Q1 = DiGraph({1:{2:['a']}}).path_semigroup()
536
+
537
+ When the ``option`` keyword is not supplied the constructor uses the
538
+ ``'values'`` option and expects the spaces and maps to be specified.
539
+ If no maps or spaces are given the zero module is created::
540
+
541
+ sage: M = Q1.representation(GF(5))
542
+ sage: M.is_zero()
543
+ True
544
+
545
+ The simple modules, indecomposable projectives, and indecomposable
546
+ injectives are examples of quiver representations::
547
+
548
+ sage: S = Q1.S(GF(3), 1)
549
+ sage: I = Q1.I(QQ, 2)
550
+ sage: P = Q1.P(GF(3), 1)
551
+
552
+ Various standard submodules can be computed, such as radicals and socles.
553
+ We can also form quotients and test for certain attributes such as
554
+ semisimplicity::
555
+
556
+ sage: R = P.radical()
557
+ sage: R.is_zero()
558
+ False
559
+ sage: (P/R).is_simple()
560
+ True
561
+ sage: P == R
562
+ False
563
+
564
+ With the option ``'paths'`` the input data should be a list of
565
+ :class:`QuiverPaths` or things that :class:`QuiverPaths` can be
566
+ constructed from. The resulting module is the submodule generated by
567
+ these paths in the quiver algebra, when considered as a right module
568
+ over itself::
569
+
570
+ sage: P1 = Q1.representation(QQ, [[(1, 1)]], option='paths')
571
+ sage: P1.dimension()
572
+ 2
573
+
574
+ In the following example, the 3rd and 4th paths are actually the same,
575
+ so the duplicate is removed::
576
+
577
+ sage: N = Q1.representation(QQ, [[(1, 1)], [(2, 2)], [(1, 2, 'a')],
578
+ ....: [(1, 2, 'a')]], option='paths')
579
+ sage: N.dimension()
580
+ 3
581
+
582
+ The dimension at each vertex equals the number of paths in the closed
583
+ basis whose terminal point is that vertex::
584
+
585
+ sage: Q2 = DiGraph({1:{2:['a'], 3:['b', 'c']}, 2:{3:['d']}}).path_semigroup()
586
+ sage: M = Q2.representation(QQ, [[(2, 2)], [(1, 2, 'a')]], option='paths')
587
+ sage: M.dimension_vector()
588
+ (0, 2, 2)
589
+ sage: N = Q2.representation(QQ, [[(2, 2)], [(1, 2, 'a'), (2, 3, 'd')]], option='paths')
590
+ sage: N.dimension_vector()
591
+ (0, 1, 2)
592
+ """
593
+ def create_key(self, k, P, *args, **kwds):
594
+ """
595
+ Return a key for the specified module.
596
+
597
+ The key is a tuple. The first and second entries are the base ring
598
+ ``k`` and the partial semigroup ``P`` formed by the paths of a quiver.
599
+ The third entry is the ``option`` and the remaining entries depend on
600
+ that option. If the option is ``'values'`` and the quiver
601
+ has `n` vertices then the next `n` entries are the vector spaces
602
+ to be assigned to those vertices. After that are the matrices of
603
+ the maps assigned to edges, listed in the same order that
604
+ ``Q.edges(sort=True)`` uses. If the option is ``'paths'`` or ``'dual paths'``
605
+ then the next entry is a tuple containing a sorted list of the
606
+ paths that form a basis of the quiver.
607
+
608
+ INPUT:
609
+
610
+ See the class documentation.
611
+
612
+ OUTPUT: tuple
613
+
614
+ EXAMPLES::
615
+
616
+ sage: P = DiGraph({1:{2:['a']}}).path_semigroup()
617
+ sage: from sage.quivers.representation import QuiverRep
618
+ sage: QuiverRep.create_key(GF(5), P)
619
+ (Finite Field of size 5,
620
+ Partial semigroup formed by the directed paths of Multi-digraph on 2 vertices,
621
+ 'values',
622
+ Vector space of dimension 0 over Finite Field of size 5,
623
+ Vector space of dimension 0 over Finite Field of size 5,
624
+ [])
625
+ """
626
+ key = [k, P]
627
+ Q = P.quiver()
628
+ if 'option' in kwds and (kwds['option'] == 'paths' or kwds['option'] == 'dual paths'):
629
+ # Follow the 'paths' specification for the input
630
+ key.append(kwds['option'])
631
+ if args:
632
+ basis = args[0]
633
+ else:
634
+ basis = kwds['basis']
635
+
636
+ # Add as QuiverPaths to a set
637
+ paths = set()
638
+ for p in basis:
639
+ paths.add(P(p))
640
+
641
+ if kwds['option'] == 'paths':
642
+ # Close the set under right mult by edges
643
+ edges = list(P.arrows())
644
+ just_added = paths
645
+ while just_added:
646
+ to_be_added = []
647
+ for e in edges:
648
+ for p in just_added:
649
+ pe = p * e
650
+ if pe is not None and pe not in paths:
651
+ to_be_added.append(pe)
652
+
653
+ paths.update(to_be_added)
654
+ just_added = to_be_added
655
+
656
+ if kwds['option'] == 'dual paths':
657
+ # Close the set under left mult by edges
658
+ edges = list(P.arrows())
659
+ just_added = paths
660
+ while just_added:
661
+ to_be_added = []
662
+ for e in edges:
663
+ for p in just_added:
664
+ ep = e * p
665
+ if ep is not None and ep not in paths:
666
+ to_be_added.append(ep)
667
+
668
+ paths.update(to_be_added)
669
+ just_added = to_be_added
670
+
671
+ # Add to the key
672
+ key.append(tuple(sorted(paths)))
673
+
674
+ else:
675
+ # Assume the input type the 'values' option
676
+ key.append('values')
677
+ if args:
678
+ spaces = args[0]
679
+ elif 'spaces' in kwds:
680
+ spaces = kwds['spaces']
681
+ else:
682
+ spaces = {}
683
+ if len(args) > 1:
684
+ maps = args[1]
685
+ elif 'maps' in kwds:
686
+ maps = kwds['maps']
687
+ else:
688
+ maps = {}
689
+
690
+ # If the vertex is not specified set it as a free module of rank 0, if
691
+ # an integer is given set it as a free module of that rank, otherwise
692
+ # assume the object is a module and assign it to the vertex.
693
+ from sage.rings.finite_rings.integer_mod_ring import Integers
694
+ verts = Q.vertices(sort=True)
695
+ for x in verts:
696
+ if x not in spaces:
697
+ key.append(k**0)
698
+ elif spaces[x] in Integers():
699
+ key.append(k**spaces[x])
700
+ else:
701
+ key.append(spaces[x])
702
+
703
+ # The preferred method of specifying an edge is as a tuple
704
+ # (i, t, l) where i is the initial vertex, t is the terminal
705
+ # vertex, and l is the label. This is the form in which
706
+ # quiver.edges(sort=True) and other such functions give the edge. But here
707
+ # edges can be specified by giving only the two vertices or giving
708
+ # only the edge label.
709
+ #
710
+ # Note that the first space is assigned to key[3] and the first
711
+ # vertex is 1 so the space assigned to vertex v is key[2 + v]
712
+ from sage.categories.morphism import Morphism
713
+ from sage.matrix.constructor import Matrix
714
+ for x in P._sorted_edges:
715
+ if x in maps:
716
+ e = maps[x]
717
+ elif (x[0], x[1]) in maps:
718
+ e = maps[(x[0], x[1])]
719
+ elif x[2] in maps:
720
+ e = maps[x[2]]
721
+ else:
722
+ e = Matrix(k, key[3 + verts.index(x[0])].dimension(), key[3 + verts.index(x[1])].dimension())
723
+
724
+ # If a morphism is specified take it's matrix. Create one if
725
+ # needed. Otherwise assume the Matrix function can convert the
726
+ # object to a Matrix.
727
+ if isinstance(e, Morphism):
728
+ if hasattr(e, 'matrix'):
729
+ key.append(e.matrix())
730
+ else:
731
+ gens_images = [key[3 + verts.index(x[1])].coordinate_vector(e(x))
732
+ for x in key[3 + verts.index(x[0])].gens()]
733
+ key.append(Matrix(k, key[3 + verts.index(x[0])].dimension(),
734
+ key[3 + verts.index(x[1])].dimension(), gens_images))
735
+ else:
736
+ key.append(Matrix(k, key[3 + verts.index(x[0])].dimension(),
737
+ key[3 + verts.index(x[1])].dimension(), e))
738
+
739
+ # Make sure the matrix is immutable so it hashes
740
+ key[-1].set_immutable()
741
+
742
+ # Wrap as a tuple and return
743
+ return tuple(key)
744
+
745
+ def create_object(self, version, key, **extra_args):
746
+ """
747
+ Create a :class:`QuiverRep_generic` or
748
+ :class:`QuiverRep_with_path_basis` object from the key.
749
+
750
+ The key is a tuple. The first and second entries are the base ring
751
+ ``k`` and the quiver ``Q``. The third entry is the
752
+ ``'option'`` and the remaining entries depend on that option.
753
+ If the option is ``'values'`` and the quiver has `n`
754
+ vertices then the next `n` entries are the vector spaces to be
755
+ assigned to those vertices. After that are the matrices
756
+ of the maps assigned to edges, listed in the same order that
757
+ ``Q.edges(sort=True)`` uses. If the option is ``'paths'`` or ``'dual paths'``
758
+ then the next entry is a tuple containing a sorted list of the
759
+ paths that form a basis of the quiver.
760
+
761
+ INPUT:
762
+
763
+ - ``version`` -- the version of sage, this is currently ignored
764
+ - ``key`` -- tuple
765
+
766
+ OUTPUT: :class:`QuiverRep_generic` or :class:`QuiverRep_with_path_basis`
767
+
768
+ EXAMPLES::
769
+
770
+ sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
771
+ sage: from sage.quivers.representation import QuiverRep
772
+ sage: key = QuiverRep.create_key(GF(5), Q)
773
+ sage: QuiverRep.create_object(0, key)
774
+ Representation with dimension vector (0, 0)
775
+ """
776
+ if len(key) < 4:
777
+ raise ValueError("invalid key used in QuiverRepFactory")
778
+
779
+ # Get the quiver
780
+ P = key[1]
781
+ Q = P.quiver()
782
+
783
+ if key[2] == 'values':
784
+ # Get the spaces
785
+ spaces = {}
786
+ i = 3
787
+ for v in Q:
788
+ spaces[v] = key[i]
789
+ i += 1
790
+
791
+ # Get the maps
792
+ maps = {}
793
+ for e in P._sorted_edges:
794
+ maps[e] = key[i]
795
+ i += 1
796
+
797
+ # Create and return the module
798
+ return QuiverRep_generic(key[0], P, spaces, maps)
799
+
800
+ elif key[2] == 'paths':
801
+ # Create and return the module
802
+ return QuiverRep_with_path_basis(key[0], P, key[3])
803
+
804
+ elif key[2] == 'dual paths':
805
+ # Create and return the module
806
+ return QuiverRep_with_dual_path_basis(key[0], P, key[3])
807
+
808
+ raise ValueError("invalid key used in QuiverRepFactory")
809
+
810
+
811
+ QuiverRep = QuiverRepFactory("sage.quivers.representation.QuiverRep")
812
+
813
+ #########################################################################
814
+ # Elements
815
+
816
+
817
+ class QuiverRepElement(ModuleElement):
818
+ r"""
819
+ An element of a quiver representation is a choice of element from each
820
+ of the spaces assigned to the vertices of the quiver. Addition,
821
+ subtraction, and scalar multiplication of these elements is done
822
+ pointwise within these spaces.
823
+
824
+ INPUT:
825
+
826
+ - ``module`` -- :class:`QuiverRep` (default: ``None``); the module to
827
+ which the element belongs
828
+
829
+ - ``elements`` -- dictionary (default: empty) associating to each vertex a
830
+ vector or an object from which sage can create a vector. Not all vertices
831
+ must be specified, unspecified vertices will be assigned the zero vector
832
+ of the space associated to that vertex in the given module. Keys that do
833
+ not correspond to a vertex are ignored.
834
+
835
+ - ``name`` -- string (default: ``None``); the name of the element
836
+
837
+ OUTPUT: :class:`QuiverRepElement`
838
+
839
+ .. NOTE::
840
+
841
+ The constructor needs to know the quiver in order to create an
842
+ element of a representation over that quiver. The default is to
843
+ read this information from ``module`` as well as to fill in
844
+ unspecified vectors with the zeros of the spaces in ``module``.
845
+ If ``module`` is ``None`` then ``quiver`` *MUST* be a quiver and each
846
+ vertex *MUST* be specified or an error will result. If both
847
+ ``module`` and ``quiver`` are given then ``quiver`` is ignored.
848
+
849
+ EXAMPLES::
850
+
851
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
852
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
853
+ sage: M = Q.representation(GF(3), spaces)
854
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
855
+ sage: M(elems)
856
+ Element of quiver representation
857
+ sage: v = M(elems, 'v')
858
+ sage: v
859
+ v
860
+ sage: (v + v + v).is_zero()
861
+ True
862
+ """
863
+
864
+ ###########################################################################
865
+ # #
866
+ # PRIVATE FUNCTIONS #
867
+ # These functions are not meant to be seen by the end user. #
868
+ # #
869
+ ###########################################################################
870
+
871
+ def __init__(self, parent, elements=None, name=None):
872
+ """
873
+ Initialize ``self``. Type ``QuiverRepElement?`` for more information.
874
+
875
+ TESTS::
876
+
877
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
878
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
879
+ sage: M = Q.representation(GF(3), spaces)
880
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
881
+ sage: v = M(elems, 'v')
882
+ sage: TestSuite(v).run()
883
+ """
884
+ # In the default call method, the default value of the first argument is zero
885
+ if not elements:
886
+ elements = {}
887
+ # The data describing an element is held in the following private
888
+ # variables:
889
+ #
890
+ # * _elems
891
+ # A dictionary that assigns to each vertex of the quiver a choice
892
+ # of element from the space assigned to that vertex in the parent
893
+ # representation.
894
+ # * _quiver
895
+ # The quiver of the representation.
896
+
897
+ super().__init__(parent)
898
+
899
+ self._elems = {}
900
+ self._quiver = parent._quiver
901
+ for v in self._quiver:
902
+ if v in elements:
903
+ self._elems[v] = parent._spaces[v](elements[v])
904
+ else:
905
+ self._elems[v] = parent._spaces[v].zero()
906
+
907
+ # Assign a name if supplied
908
+ if name is not None:
909
+ self.rename(name)
910
+
911
+ def _repr_(self):
912
+ """
913
+ Default string representation.
914
+
915
+ TESTS::
916
+
917
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
918
+ sage: Q.P(QQ, 3).an_element() # indirect doctest
919
+ Element of quiver representation
920
+ """
921
+ return "Element of quiver representation"
922
+
923
+ def _add_(left, right):
924
+ """
925
+ This overrides the ``+`` operator.
926
+
927
+ TESTS::
928
+
929
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
930
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
931
+ sage: M = Q.representation(GF(3), spaces)
932
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
933
+ sage: v = M(elems)
934
+ sage: (v + v + v).is_zero() # indirect doctest
935
+ True
936
+ """
937
+ elements = {}
938
+ for v in left._quiver:
939
+ elements[v] = left._elems[v] + right._elems[v]
940
+
941
+ return left.parent()(elements)
942
+
943
+ def _sub_(left, right):
944
+ """
945
+ This overrides the ``-`` operator.
946
+
947
+ TESTS::
948
+
949
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
950
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
951
+ sage: M = Q.representation(GF(3), spaces)
952
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
953
+ sage: v = M(elems)
954
+ sage: (v - v).is_zero() # indirect doctest
955
+ True
956
+ """
957
+ elements = {}
958
+ for v in left._quiver:
959
+ elements[v] = left._elems[v] - right._elems[v]
960
+
961
+ return left.parent()(elements)
962
+
963
+ def _neg_(self):
964
+ """
965
+ This overrides the unary ``-`` operator.
966
+
967
+ TESTS::
968
+
969
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
970
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
971
+ sage: M = Q.representation(GF(3), spaces)
972
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
973
+ sage: v = M(elems)
974
+ sage: v == -v # indirect doctest
975
+ False
976
+ """
977
+ elements = {}
978
+ for v in self._quiver:
979
+ elements[v] = -self._elems[v]
980
+
981
+ return self.parent()(elements)
982
+
983
+ def __mul__(self, other):
984
+ """
985
+ Implement ``*`` for right multiplication by quiver algebra elements.
986
+
987
+ TESTS::
988
+
989
+ sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
990
+ sage: P = Q.P(QQ, 1)
991
+ sage: A = Q.algebra(QQ)
992
+ sage: m = P.an_element()
993
+ sage: a = A('a')
994
+ sage: e1 = A([(1, 1)])
995
+ sage: m.support()
996
+ [1, 2]
997
+ sage: (m*a).support()
998
+ [2]
999
+ sage: (m*e1).support()
1000
+ [1]
1001
+ sage: (m*(a + e1)).support()
1002
+ [1, 2]
1003
+ """
1004
+ # Make sure the input is an element of the quiver algebra and get the
1005
+ # coefficients of the monomials in it
1006
+ parent = self.parent()
1007
+ mons = parent._actor(other).monomial_coefficients()
1008
+
1009
+ # this must not be the cached parent.zero(),
1010
+ # since otherwise it gets changed in place!!
1011
+ result = parent()
1012
+
1013
+ for path in mons:
1014
+ # Multiply by the scalar
1015
+ x = mons[path] * self._elems[path.initial_vertex()]
1016
+
1017
+ # If the edge isn't trivial apply the corresponding maps
1018
+ if path:
1019
+ for edge in path:
1020
+ x = parent.get_map(edge)(x)
1021
+
1022
+ # Sum the results of acting by each monomial
1023
+ result._elems[path.terminal_vertex()] += x
1024
+
1025
+ return result
1026
+
1027
+ @cached_method
1028
+ def __hash__(self):
1029
+ """
1030
+ The hash only depends on the elements assigned to each vertex of the
1031
+ underlying quiver.
1032
+
1033
+ .. NOTE::
1034
+
1035
+ The default hash inherited from
1036
+ :class:`~sage.structure.element.Element` would depend on
1037
+ the name of the element and would thus be mutable.
1038
+
1039
+ EXAMPLES::
1040
+
1041
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{4:['c']}, 3:{4:['d']}}).path_semigroup()
1042
+ sage: P = Q.P(QQ, 2)
1043
+ sage: v = P() # let's not muddy P.zero(), which is cached
1044
+ sage: h1 = hash(v)
1045
+ sage: v.rename('foobar')
1046
+ sage: h1 == hash(v)
1047
+ True
1048
+ """
1049
+ return hash(frozenset((v, tuple(self._elems[v]))
1050
+ for v in self._quiver))
1051
+
1052
+ def __eq__(self, other):
1053
+ """
1054
+ This overrides the ``==`` operator.
1055
+
1056
+ TESTS::
1057
+
1058
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
1059
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
1060
+ sage: M = Q.representation(GF(3), spaces)
1061
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
1062
+ sage: v = M(elems)
1063
+ sage: w = M(elems)
1064
+ sage: v == w
1065
+ True
1066
+ sage: v += w
1067
+ sage: v == w
1068
+ False
1069
+ """
1070
+ # Return False if being compared to something other than a
1071
+ # QuiverRepElement or if comparing two elements from representations
1072
+ # with different quivers
1073
+ if not isinstance(other, QuiverRepElement) or self._quiver != other._quiver:
1074
+ return False
1075
+
1076
+ # Return False if the elements differ at any vertex
1077
+ for v in self._quiver:
1078
+ if self._elems[v] != other._elems[v]:
1079
+ return False
1080
+
1081
+ return True
1082
+
1083
+ def __ne__(self, other):
1084
+ """
1085
+ This overrides the ``!=`` operator.
1086
+
1087
+ TESTS::
1088
+
1089
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
1090
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
1091
+ sage: M = Q.representation(GF(3), spaces)
1092
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
1093
+ sage: v = M(elems)
1094
+ sage: w = M(elems)
1095
+ sage: v != w
1096
+ False
1097
+ sage: v += w
1098
+ sage: v != w
1099
+ True
1100
+ """
1101
+ # Return True if being compared to something other than a
1102
+ # QuiverRepElement or if comparing two elements from representations
1103
+ # with different quivers
1104
+ if not isinstance(other, QuiverRepElement) or self._quiver != other._quiver:
1105
+ return True
1106
+
1107
+ # Return True if the elements differ at any vertex
1108
+ for v in self._quiver:
1109
+ if self._elems[v] != other._elems[v]:
1110
+ return True
1111
+
1112
+ return False
1113
+
1114
+ ###########################################################################
1115
+ # #
1116
+ # ACCESS FUNCTIONS #
1117
+ # These functions are used to view and modify the representation data. #
1118
+ # #
1119
+ ###########################################################################
1120
+
1121
+ def quiver(self):
1122
+ """
1123
+ Return the quiver of the representation.
1124
+
1125
+ OUTPUT: :class:`DiGraph`, the quiver of the representation
1126
+
1127
+ EXAMPLES::
1128
+
1129
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
1130
+ sage: P = Q.P(QQ, 1)
1131
+ sage: v = P.an_element()
1132
+ sage: v.quiver() is Q.quiver()
1133
+ True
1134
+ """
1135
+ return self._quiver
1136
+
1137
+ def get_element(self, vertex):
1138
+ """
1139
+ Return the element at the given vertex.
1140
+
1141
+ INPUT:
1142
+
1143
+ - ``vertex`` -- integer; a vertex of the quiver
1144
+
1145
+ OUTPUT: the vector assigned to the given vertex
1146
+
1147
+ EXAMPLES::
1148
+
1149
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
1150
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
1151
+ sage: M = Q.representation(GF(3), spaces)
1152
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
1153
+ sage: v = M(elems)
1154
+ sage: v.get_element(1)
1155
+ (1, 0)
1156
+ sage: v.get_element(3)
1157
+ (2, 1)
1158
+ """
1159
+
1160
+ return self._elems[vertex]
1161
+
1162
+ def _set_element(self, vector, vertex):
1163
+ r"""
1164
+ Set the value of the element ``self`` at the given vertex
1165
+ ``vertex`` to ``vector`` (while the values at all other vertices
1166
+ remain unchanged).
1167
+
1168
+ INPUT:
1169
+
1170
+ - ``vector`` -- a vector or an object from which the space
1171
+ associated to the given vertex in the parent can create a vector
1172
+
1173
+ - ``vertex`` -- integer; a vertex of the quiver
1174
+
1175
+ .. WARNING::
1176
+
1177
+ Only use this method if you know what you are doing. In particular,
1178
+ do not apply it to an element that is cached somewhere (such as
1179
+ :meth:`zero`).
1180
+
1181
+ EXAMPLES::
1182
+
1183
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
1184
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
1185
+ sage: M = Q.representation(GF(3), spaces)
1186
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
1187
+ sage: v = M(elems)
1188
+ sage: v.get_element(1)
1189
+ (1, 0)
1190
+ sage: v._set_element((1, 1), 1)
1191
+ sage: v.get_element(1)
1192
+ (1, 1)
1193
+ """
1194
+ self._elems[vertex] = self.parent()._spaces[vertex](vector)
1195
+
1196
+ ###########################################################################
1197
+ # #
1198
+ # DATA FUNCTIONS #
1199
+ # These functions return data collected from the homomorphism. #
1200
+ # #
1201
+ ###########################################################################
1202
+
1203
+ def is_zero(self) -> bool:
1204
+ """
1205
+ Test whether ``self`` is zero.
1206
+
1207
+ OUTPUT: boolean, ``True`` if the element is the zero element, ``False``
1208
+ otherwise
1209
+
1210
+ EXAMPLES::
1211
+
1212
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
1213
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
1214
+ sage: M = Q.representation(GF(3), spaces)
1215
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
1216
+ sage: v = M(elems)
1217
+ sage: v.is_zero()
1218
+ False
1219
+ sage: w = M()
1220
+ sage: w.is_zero()
1221
+ True
1222
+
1223
+ TESTS::
1224
+
1225
+ sage: M = Q.P(QQ, 1)
1226
+ sage: M.zero().is_zero()
1227
+ True
1228
+ """
1229
+ for v in self._quiver:
1230
+ if not self._elems[v].is_zero():
1231
+ return False
1232
+
1233
+ return True
1234
+
1235
+ def support(self):
1236
+ """
1237
+ Return the support of ``self`` as a list.
1238
+
1239
+ The support is the set of vertices to which a nonzero vector is
1240
+ associated.
1241
+
1242
+ OUTPUT: list; the support
1243
+
1244
+ EXAMPLES::
1245
+
1246
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
1247
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
1248
+ sage: M = Q.representation(GF(3), spaces)
1249
+ sage: elems = {1: (1, 0), 2: (0, 0), 3: (2, 1)}
1250
+ sage: v = M(elems)
1251
+ sage: v.support()
1252
+ [1, 3]
1253
+ """
1254
+
1255
+ sup = []
1256
+ for v in self._quiver:
1257
+ if not self._elems[v].is_zero():
1258
+ sup.append(v)
1259
+
1260
+ return sup
1261
+
1262
+ ###########################################################################
1263
+ # #
1264
+ # ADDITIONAL OPERATIONS #
1265
+ # These functions operations that are not implemented via binary #
1266
+ # operators. #
1267
+ # #
1268
+ ###########################################################################
1269
+
1270
+ def copy(self):
1271
+ """
1272
+ Return a copy of ``self``.
1273
+
1274
+ EXAMPLES::
1275
+
1276
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{3:['c']}}).path_semigroup()
1277
+ sage: spaces = dict((v, GF(3)^2) for v in Q.quiver())
1278
+ sage: M = Q.representation(GF(3), spaces)
1279
+ sage: elems = {1: (1, 0), 2: (0, 1), 3: (2, 1)}
1280
+ sage: v = M(elems)
1281
+ sage: w = v.copy()
1282
+ sage: w._set_element((0, 0), 1)
1283
+ sage: w.get_element(1)
1284
+ (0, 0)
1285
+ sage: v.get_element(1)
1286
+ (1, 0)
1287
+ """
1288
+ name = self.get_custom_name()
1289
+ return self.parent()(self._elems.copy(), name)
1290
+
1291
+ ####################################################################
1292
+ # The representations
1293
+
1294
+
1295
+ class QuiverRep_generic(WithEqualityById, Module):
1296
+ """
1297
+ A generic quiver representation.
1298
+
1299
+ This class should not be called by the user.
1300
+
1301
+ Call :class:`QuiverRep` with ``option='values'`` (which is the default)
1302
+ instead.
1303
+
1304
+ INPUT:
1305
+
1306
+ - ``k`` -- ring, the base ring of the representation
1307
+
1308
+ - ``P`` -- the path semigroup of the quiver `Q` of the representation
1309
+
1310
+ - ``spaces`` -- dictionary (default: empty) associating to each vertex a
1311
+ free module over the base ring `k`. Not all vertices need to be
1312
+ specified, unspecified vertices are automatically set to `k^0`. Keys of
1313
+ the dictionary that don't correspond to vertices are ignored.
1314
+
1315
+ - ``maps`` -- dictionary (default: empty) associating to each edge a map
1316
+ whose domain and codomain are the spaces associated to the initial and
1317
+ terminal vertex of the edge respectively. Not all edges need to be
1318
+ specified, unspecified edges are automatically set to the zero map. Keys
1319
+ of the dictionary that don't correspond to edges are ignored.
1320
+
1321
+ OUTPUT: :class:`QuiverRep`
1322
+
1323
+ EXAMPLES::
1324
+
1325
+ sage: Q = DiGraph({1:{3:['a']}, 2:{3:['b']}}).path_semigroup()
1326
+ sage: spaces = {1: QQ^2, 2: QQ^3, 3: QQ^2}
1327
+ sage: maps = {(1, 3, 'a'): (QQ^2).Hom(QQ^2).identity(), (2, 3, 'b'): [[1, 0], [0, 0], [0, 0]]}
1328
+ sage: M = Q.representation(QQ, spaces, maps)
1329
+
1330
+ ::
1331
+
1332
+ sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
1333
+ sage: P = Q.P(GF(3), 1)
1334
+ sage: I = Q.I(QQ, 1)
1335
+ sage: P.an_element() in P
1336
+ True
1337
+ sage: I.an_element() in P
1338
+ False
1339
+
1340
+ TESTS::
1341
+
1342
+ sage: TestSuite(M).run()
1343
+ sage: TestSuite(P).run()
1344
+ sage: TestSuite(I).run()
1345
+ sage: TestSuite(Q.S(ZZ,2)).run()
1346
+ """
1347
+ Element = QuiverRepElement
1348
+
1349
+ ###########################################################################
1350
+ # #
1351
+ # PRIVATE FUNCTIONS #
1352
+ # These functions are not meant to be seen by the end user. #
1353
+ # #
1354
+ ###########################################################################
1355
+
1356
+ def __init__(self, k, P, spaces, maps):
1357
+ """
1358
+ Initialize ``self``. Type ``QuiverRep?`` for more information.
1359
+
1360
+ .. NOTE::
1361
+
1362
+ Use :meth:`~sage.quivers.quiver.Quiver.representation` to create a
1363
+ representation. The following is just a test, but it is not the
1364
+ recommended way of creating a representation.
1365
+
1366
+ TESTS::
1367
+
1368
+ sage: from sage.quivers.representation import QuiverRep_generic
1369
+ sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
1370
+ sage: QuiverRep_generic(GF(5), Q, {1: GF(5)^2, 2: GF(5)^3}, {})
1371
+ Representation with dimension vector (2, 3)
1372
+ """
1373
+ # This class can handle representations over
1374
+ # an arbitrary base ring, not necessarily a field, so long as sage can
1375
+ # construct free modules over that ring. The data of a representation is held
1376
+ # in the following private variables:
1377
+ #
1378
+ # * _quiver
1379
+ # The quiver of the representation.
1380
+ # * _base
1381
+ # The quiver algebra of _quiver over _base_ring
1382
+ # * _base_ring
1383
+ # The base ring of the representation.
1384
+ # * _spaces
1385
+ # A dictionary which associates to each vertex of the quiver a free
1386
+ # module over the base ring.
1387
+ # * _maps
1388
+ # A dictionary which associates to each edge of the quiver a homomorphism
1389
+ # whose domain and codomain equal the initial and terminal vertex of the
1390
+ # edge.
1391
+ Q = P.quiver()
1392
+ self._semigroup = P
1393
+ self._actor = P.algebra(k)
1394
+ self._quiver = Q
1395
+ self._spaces = {}
1396
+ self._maps = {}
1397
+
1398
+ # If the vertex is not specified set it as a free module of rank 0, if
1399
+ # an integer is given set it as a free module of that rank, otherwise
1400
+ # assume the object is a module and assign it to the vertex.
1401
+ from sage.rings.finite_rings.integer_mod_ring import Integers
1402
+ for x in Q:
1403
+ if x not in spaces:
1404
+ self._spaces[x] = k**0
1405
+ elif spaces[x] in Integers():
1406
+ self._spaces[x] = k**spaces[x]
1407
+ else:
1408
+ self._spaces[x] = spaces[x]
1409
+
1410
+ # The preferred method of specifying an edge is as a tuple (i, t, l)
1411
+ # where i is the initial vertex, t is the terminal vertex, and l is the
1412
+ # label. This is the form in which quiver.edges(sort=True) and other such
1413
+ # functions give the edge. But here edges can be specified by giving
1414
+ # only the two vertices or giving only the edge label.
1415
+ for x in P._sorted_edges:
1416
+ if x in maps:
1417
+ e = maps[x]
1418
+ elif (x[0], x[1]) in maps:
1419
+ e = maps[(x[0], x[1])]
1420
+ elif x[2] in maps:
1421
+ e = maps[x[2]]
1422
+ else:
1423
+ e = self._spaces[x[0]].Hom(self._spaces[x[1]]).zero()
1424
+
1425
+ # If a morphism is specified use it, otherwise assume the hom
1426
+ # function can convert the object to a morphism. Matrices and the
1427
+ # zero and one of the base ring are valid inputs (one is valid only
1428
+ # when the domain and codomain are equal).
1429
+ from sage.categories.morphism import Morphism
1430
+ if isinstance(e, Morphism):
1431
+ self._maps[x] = e
1432
+ else:
1433
+ self._maps[x] = self._spaces[x[0]].hom(e, self._spaces[x[1]])
1434
+
1435
+ self._assert_valid_quiverrep()
1436
+
1437
+ super().__init__(k) # Or explicitly Module.__init__(self, k)?
1438
+
1439
+ def _assert_valid_quiverrep(self):
1440
+ r"""
1441
+ Raise an error if the representation is not well defined.
1442
+
1443
+ Specifically it checks the map assigned to each edge. The domain
1444
+ and codomain must equal the modules assigned to the initial and
1445
+ terminal vertices of the edge.
1446
+
1447
+ TESTS::
1448
+
1449
+ sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
1450
+ sage: M = Q.P(GF(3), 2) # indirect doctest
1451
+
1452
+ Due to unique representation, we will cause bugs in later code if
1453
+ we modify ``M`` to be an invalid representation. So we make sure
1454
+ to store the original values and replace them after testing::
1455
+
1456
+ sage: sv = M._spaces[1]
1457
+ sage: M._spaces[1] = 0
1458
+ sage: M._assert_valid_quiverrep()
1459
+ Traceback (most recent call last):
1460
+ ...
1461
+ ValueError: domain of map at edge 'a' does not match
1462
+ sage: M._spaces[1] = sv
1463
+ sage: M = Q.P(GF(3), 2)
1464
+ sage: sv = M._maps[(1, 2, 'a')]
1465
+ sage: M._maps[(1, 2, 'a')] = (QQ^2).Hom(QQ^1).zero()
1466
+ sage: M._assert_valid_quiverrep()
1467
+ Traceback (most recent call last):
1468
+ ...
1469
+ ValueError: domain of map at edge 'a' does not match
1470
+ sage: M._maps[(1, 2, 'a')] = sv
1471
+ """
1472
+
1473
+ for x in self._semigroup._sorted_edges:
1474
+ if self._maps[x].domain() != self._spaces[x[0]]:
1475
+ raise ValueError("domain of map at edge '{}' does not match".format(x[2]))
1476
+ if self._maps[x].codomain() != self._spaces[x[1]]:
1477
+ raise ValueError("codomain of map at edge '{}' does not match".format(x[2]))
1478
+
1479
+ def _repr_(self):
1480
+ """
1481
+ Default string representation.
1482
+
1483
+ TESTS::
1484
+
1485
+ sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
1486
+ sage: Q.P(GF(3), 2) # indirect doctest
1487
+ Representation with dimension vector (0, 1)
1488
+ """
1489
+ return "Representation with dimension vector {}".format(self.dimension_vector())
1490
+
1491
+ def __truediv__(self, sub):
1492
+ """
1493
+ Overload the ``/`` operator.
1494
+
1495
+ TESTS::
1496
+
1497
+ sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
1498
+ sage: P = Q.P(GF(3), 1)
1499
+ sage: R = P.radical()
1500
+ sage: (P/R).is_simple()
1501
+ True
1502
+ """
1503
+ return self.quotient(sub)
1504
+
1505
+ def _submodule(self, spaces=None):
1506
+ """
1507
+ Return the submodule specified by the data.
1508
+
1509
+ This differs from ``self.submodule`` in that it assumes the data
1510
+ correctly specifies a submodule whereas ``self.submodule`` returns
1511
+ the smallest submodule containing the data.
1512
+
1513
+ TESTS::
1514
+
1515
+ sage: Q = DiGraph({1:{3:['a']}, 2:{3:['b']}}).path_semigroup()
1516
+ sage: spaces = {1: QQ^2, 2: QQ^3, 3: QQ^2}
1517
+ sage: maps = {(1, 3, 'a'): (QQ^2).Hom(QQ^2).identity(), (2, 3, 'b'): [[1, 0], [0, 0], [0, 0]]}
1518
+ sage: M = Q.representation(QQ, spaces, maps)
1519
+ sage: v = M.an_element()
1520
+ sage: M.submodule([v]) # indirect doctest
1521
+ Representation with dimension vector (1, 1, 1)
1522
+ sage: M.submodule(spaces={1: QQ^2}) # indirect doctest
1523
+ Representation with dimension vector (2, 0, 2)
1524
+ sage: M.submodule(spaces={2: QQ^3}) # indirect doctest
1525
+ Representation with dimension vector (0, 3, 1)
1526
+ sage: v.support()
1527
+ [1, 2, 3]
1528
+ sage: M.submodule([v], {2: QQ^3}) # indirect doctest
1529
+ Representation with dimension vector (1, 3, 1)
1530
+ sage: M.submodule().is_zero() # indirect doctest
1531
+ True
1532
+ sage: M.submodule(M.gens()) is M # indirect doctest
1533
+ True
1534
+ """
1535
+ if spaces is None:
1536
+ spaces = {}
1537
+ # Add zero submodules
1538
+ for v in self._quiver:
1539
+ if v not in spaces:
1540
+ spaces[v] = self._spaces[v].zero_submodule()
1541
+
1542
+ # Create edge homomorphisms restricted to the new domains and codomains
1543
+ maps = {}
1544
+ for e in self._semigroup._sorted_edges:
1545
+ maps[e] = self._maps[e].restrict_domain(spaces[e[0]]).restrict_codomain(spaces[e[1]])
1546
+
1547
+ return self._semigroup.representation(self.base_ring(), spaces, maps)
1548
+
1549
+ def _coerce_map_from_(self, domain):
1550
+ """
1551
+ Return either a QuiverRepHom from ``domain`` to ``self``, or
1552
+ ``False``.
1553
+
1554
+ .. NOTE::
1555
+
1556
+ This function simply tries to coerce a map at each vertex and
1557
+ then check if the result is a valid homomorphism. If it is,
1558
+ then that homomorphism is returned. If it is not or if no
1559
+ coercion was possible then it returns ``False``.
1560
+
1561
+ INPUT:
1562
+
1563
+ - ``domain`` -- a Sage object
1564
+
1565
+ OUTPUT: :class:`QuiverRepHom` or boolean
1566
+
1567
+ TESTS::
1568
+
1569
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup()
1570
+ sage: M = Q.P(QQ, 1)
1571
+ sage: S = M.radical()
1572
+ sage: M.coerce_map_from(S) # indirect doctest
1573
+ Homomorphism of representations of Multi-digraph on 3 vertices
1574
+ sage: (M/S).coerce_map_from(M) # indirect doctest
1575
+ Homomorphism of representations of Multi-digraph on 3 vertices
1576
+
1577
+ Here sage coerces a map but the result is not a homomorphism::
1578
+
1579
+ sage: S.coerce_map_from(M) # indirect doctest
1580
+
1581
+ Here sage cannot coerce a map::
1582
+
1583
+ sage: N = Q.P(QQ, 3)
1584
+ sage: N.coerce_map_from(M) # indirect doctest
1585
+ """
1586
+
1587
+ # Domain must be a QuiverRep
1588
+ if not isinstance(domain, QuiverRep_generic):
1589
+ return False
1590
+
1591
+ # Coerce a map at each vertex, return false if it fails
1592
+ maps = {}
1593
+ for v in self._quiver:
1594
+ maps[v] = self._spaces[v].coerce_map_from(domain._spaces[v])
1595
+ if maps[v] is None or maps[v] is False:
1596
+ return False
1597
+
1598
+ # Create and return the hom, return False if it wasn't valid
1599
+ try:
1600
+ return domain.hom(maps, self)
1601
+ except ValueError:
1602
+ return False
1603
+
1604
+ def _Hom_(self, codomain, category):
1605
+ """
1606
+ This function is used by the coercion model.
1607
+
1608
+ INPUT:
1609
+
1610
+ - ``codomain`` -- :class:`QuiverRepHom`
1611
+
1612
+ - ``category`` -- this input is (currently) ignored
1613
+
1614
+ EXAMPLES::
1615
+
1616
+ sage: from sage.categories.homset import Hom
1617
+ sage: Q = DiGraph({1:{2:['a', 'b']}, 2:{3:['c', 'd']}}).path_semigroup()
1618
+ sage: P = Q.P(GF(3), 2)
1619
+ sage: S = P/P.radical()
1620
+ sage: Hom(P, S) # indirect doctest
1621
+ Dimension 1 QuiverHomSpace
1622
+ """
1623
+ from sage.quivers.homspace import QuiverHomSpace
1624
+
1625
+ if not isinstance(codomain, QuiverRep_generic):
1626
+ raise TypeError("codomain must be of type QuiverRep_generic")
1627
+
1628
+ return QuiverHomSpace(self, codomain)
1629
+
1630
+ ###########################################################################
1631
+ # #
1632
+ # ACCESS FUNCTIONS #
1633
+ # These functions are used to view the representation data. #
1634
+ # #
1635
+ ###########################################################################
1636
+
1637
+ def get_space(self, vertex):
1638
+ """
1639
+ Return the module associated to the given vertex ``vertex``.
1640
+
1641
+ INPUT:
1642
+
1643
+ - ``vertex`` -- integer; a vertex of the quiver of the module
1644
+
1645
+ EXAMPLES::
1646
+
1647
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}}).path_semigroup()
1648
+ sage: Q.P(QQ, 1).get_space(1)
1649
+ Vector space of dimension 1 over Rational Field
1650
+ """
1651
+ return self._spaces[vertex]
1652
+
1653
+ def get_map(self, edge):
1654
+ """
1655
+ Return the map associated to the given edge ``edge``.
1656
+
1657
+ INPUT:
1658
+
1659
+ - ``edge`` -- tuple of the form
1660
+ (initial vertex, terminal vertex, label) specifying the edge
1661
+ whose map is returned
1662
+
1663
+ EXAMPLES::
1664
+
1665
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
1666
+ sage: Q.P(ZZ, 1).get_map((1, 2, 'a'))
1667
+ Free module morphism defined by the matrix
1668
+ [1 0]
1669
+ Domain: Ambient free module of rank 1 over the principal ideal domain Integer Ring
1670
+ Codomain: Ambient free module of rank 2 over the principal ideal domain Integer Ring
1671
+ """
1672
+
1673
+ return self._maps[edge]
1674
+
1675
+ def quiver(self):
1676
+ """
1677
+ Return the quiver of the representation.
1678
+
1679
+ OUTPUT: :class:`DiGraph`
1680
+
1681
+ EXAMPLES::
1682
+
1683
+ sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
1684
+ sage: M = Q.representation(GF(5))
1685
+ sage: M.quiver() is Q.quiver()
1686
+ True
1687
+ """
1688
+ return self._quiver
1689
+
1690
+ def actor(self):
1691
+ r"""
1692
+ Return the quiver path algebra acting on this representation.
1693
+
1694
+ OUTPUT: a quiver path algebra
1695
+
1696
+ EXAMPLES::
1697
+
1698
+ sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
1699
+ sage: M = Q.representation(GF(5))
1700
+ sage: M.base_ring()
1701
+ Finite Field of size 5
1702
+ sage: M.actor()
1703
+ Path algebra of Multi-digraph on 2 vertices over Finite Field of size 5
1704
+ """
1705
+ return self._actor
1706
+
1707
+ ###########################################################################
1708
+ # #
1709
+ # DATA FUNCTIONS #
1710
+ # These functions return data collected from the representation. #
1711
+ # #
1712
+ ###########################################################################
1713
+
1714
+ def dimension(self, vertex=None):
1715
+ """
1716
+ Return the dimension of the space associated to the given vertex
1717
+ ``vertex``.
1718
+
1719
+ INPUT:
1720
+
1721
+ - ``vertex`` -- integer or ``None`` (default: ``None``), the given
1722
+ vertex
1723
+
1724
+ OUTPUT:
1725
+
1726
+ - integer, the dimension over the base ring of the space
1727
+ associated to the given vertex. If ``vertex=None`` then the
1728
+ dimension over the base ring of the module is returned
1729
+
1730
+ EXAMPLES::
1731
+
1732
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
1733
+ sage: P = Q.P(GF(2), 1)
1734
+ sage: P.dimension(1)
1735
+ 1
1736
+ sage: P.dimension(2)
1737
+ 2
1738
+
1739
+ The total dimension of the module is the sum of the dimensions
1740
+ at each vertex::
1741
+
1742
+ sage: P.dimension()
1743
+ 3
1744
+ """
1745
+ if vertex is None:
1746
+ # Sum the dimensions of each vertex
1747
+ dim = 0
1748
+ for x in self._quiver:
1749
+ dim += self._spaces[x].dimension()
1750
+ return dim
1751
+ else:
1752
+ # Return the dimension of just the one vertex
1753
+ return self._spaces[vertex].dimension()
1754
+
1755
+ def dimension_vector(self):
1756
+ """
1757
+ Return the dimension vector of the representation.
1758
+
1759
+ OUTPUT: tuple
1760
+
1761
+ .. NOTE::
1762
+
1763
+ The order of the entries in the tuple matches the order given
1764
+ by calling the ``vertices()`` method on the quiver.
1765
+
1766
+ EXAMPLES::
1767
+
1768
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
1769
+ sage: P = Q.P(GF(2), 1)
1770
+ sage: P.dimension_vector()
1771
+ (1, 2)
1772
+
1773
+ Each coordinate of the dimension vector is the dimension of the space
1774
+ associated to that coordinate::
1775
+
1776
+ sage: P.get_space(2).dimension()
1777
+ 2
1778
+ """
1779
+ return tuple(self._spaces[x].dimension() for x in self._quiver)
1780
+
1781
+ def is_zero(self) -> bool:
1782
+ """
1783
+ Test whether the representation is zero.
1784
+
1785
+ OUTPUT: boolean
1786
+
1787
+ EXAMPLES::
1788
+
1789
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
1790
+ sage: M = Q.representation(ZZ)
1791
+ sage: N = Q.representation(ZZ, {1: 1})
1792
+ sage: M
1793
+ Representation with dimension vector (0, 0)
1794
+ sage: N
1795
+ Representation with dimension vector (1, 0)
1796
+ sage: M.is_zero()
1797
+ True
1798
+ sage: N.is_zero()
1799
+ False
1800
+ """
1801
+ return self.dimension() == 0
1802
+
1803
+ def is_simple(self) -> bool:
1804
+ """
1805
+ Test whether the representation is simple.
1806
+
1807
+ OUTPUT: boolean
1808
+
1809
+ EXAMPLES::
1810
+
1811
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
1812
+ sage: Q.P(RR, 1).is_simple()
1813
+ False
1814
+ sage: Q.S(RR, 1).is_simple()
1815
+ True
1816
+ """
1817
+ # A module for an acyclic quiver is simple if and only if it has total
1818
+ # dimension 1.
1819
+ return self.dimension() == 1
1820
+
1821
+ def is_semisimple(self) -> bool:
1822
+ """
1823
+ Test whether the representation is semisimple.
1824
+
1825
+ OUTPUT: boolean
1826
+
1827
+ EXAMPLES::
1828
+
1829
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
1830
+ sage: M = Q.P(QQ, 1)
1831
+ sage: (M/M.radical()).is_semisimple()
1832
+ True
1833
+ """
1834
+ # A quiver representation is semisimple if and only if the zero map is
1835
+ # assigned to each edge.
1836
+ for x in self._semigroup._sorted_edges:
1837
+ if not self._maps[x].is_zero():
1838
+ return False
1839
+ return True
1840
+
1841
+ def an_element(self):
1842
+ """
1843
+ Return an element of ``self``.
1844
+
1845
+ OUTPUT: :class:`QuiverRepElement`
1846
+
1847
+ EXAMPLES::
1848
+
1849
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
1850
+ sage: M = Q.P(QQ, 1)
1851
+ sage: M.an_element()
1852
+ Element of quiver representation
1853
+ """
1854
+ # Here we just use the an_element function from each space.
1855
+ elements = {v: self._spaces[v].an_element() for v in self._quiver}
1856
+ return self(elements)
1857
+
1858
+ def support(self):
1859
+ """
1860
+ Return the support of ``self`` as a list.
1861
+
1862
+ OUTPUT:
1863
+
1864
+ - list, the vertices of the representation that have nonzero
1865
+ spaces associated to them
1866
+
1867
+ EXAMPLES::
1868
+
1869
+ sage: Q = DiGraph({1:{2:['a']}, 3:{2:['b'], 4:['c']}}).path_semigroup()
1870
+ sage: M = Q.P(QQ, 3)
1871
+ sage: M
1872
+ Representation with dimension vector (0, 1, 1, 1)
1873
+ sage: M.support()
1874
+ [2, 3, 4]
1875
+ """
1876
+ sup = []
1877
+ for v in self._quiver:
1878
+ if self._spaces[v].dimension() != 0:
1879
+ sup.append(v)
1880
+
1881
+ return sup
1882
+
1883
+ def gens(self, names='v') -> tuple:
1884
+ """
1885
+ Return a tuple of generators of ``self`` as a `k`-module.
1886
+
1887
+ INPUT:
1888
+
1889
+ - ``names`` -- an iterable variable of length equal to the number
1890
+ of generators, or a string (default: ``'v'``); gives the names of
1891
+ the generators either by giving a name to each generator or by
1892
+ giving a name to which an index will be appended
1893
+
1894
+ OUTPUT:
1895
+
1896
+ - tuple of :class:`QuiverRepElement` objects, the linear generators
1897
+ of the module (over the base ring)
1898
+
1899
+ .. NOTE::
1900
+
1901
+ The generators are ordered first by vertex and then by the order
1902
+ given by the ``gens()`` method of the space associated to
1903
+ that vertex.
1904
+
1905
+ EXAMPLES::
1906
+
1907
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
1908
+ sage: M = Q.P(QQ, 1)
1909
+ sage: M.gens()
1910
+ (v_0, v_1, v_2)
1911
+
1912
+ If a string is given then it is used as the name of each generator,
1913
+ with the index of the generator appended in order to differentiate
1914
+ them::
1915
+
1916
+ sage: M.gens('generator')
1917
+ (generator_0, generator_1, generator_2)
1918
+
1919
+ If a list or other iterable variable is given then each generator
1920
+ is named using the appropriate entry. The length of the variable
1921
+ must equal the number of generators (the dimension of the module)::
1922
+
1923
+ sage: M.gens(['w', 'x', 'y', 'z'])
1924
+ Traceback (most recent call last):
1925
+ ...
1926
+ TypeError: can only concatenate list (not "str") to list
1927
+ sage: M.gens(['x', 'y', 'z'])
1928
+ (x, y, z)
1929
+
1930
+ Strings are iterable, so if the length of the string is equal to the
1931
+ number of generators then the characters of the string will be used
1932
+ as the names::
1933
+
1934
+ sage: M.gens('xyz')
1935
+ (x, y, z)
1936
+ """
1937
+ # Use names as a list if and only if it is the correct length
1938
+ uselist = (len(names) == self.dimension())
1939
+ i = 0
1940
+
1941
+ # Create bases for each space and construct QuiverRepElements from
1942
+ # them. Other functions depend on the ordering of generators produced
1943
+ # by this code. Make sure you know which they are before you change
1944
+ # anything
1945
+ basis = []
1946
+ for v in self._quiver:
1947
+ for m in self._spaces[v].gens():
1948
+ if uselist:
1949
+ basis.append(self({v: m}, names[i]))
1950
+ else:
1951
+ basis.append(self({v: m}, names + "_" + str(i)))
1952
+ i += 1
1953
+
1954
+ return tuple(basis)
1955
+
1956
+ def coordinates(self, vector):
1957
+ """
1958
+ Return the coordinates when ``vector`` is expressed in terms of
1959
+ the gens.
1960
+
1961
+ INPUT:
1962
+
1963
+ - ``vector`` -- :class:`QuiverRepElement`
1964
+
1965
+ OUTPUT:
1966
+
1967
+ - list, the coefficients when the vector is expressed as a linear
1968
+ combination of the generators of the module
1969
+
1970
+ EXAMPLES::
1971
+
1972
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
1973
+ sage: M = Q.P(QQ, 1)
1974
+ sage: x, y, z = M.gens('xyz')
1975
+ sage: M.coordinates(x - y + z)
1976
+ [1, -1, 1]
1977
+ sage: M.coordinates(M.an_element())
1978
+ [1, 1, 0]
1979
+ sage: M.an_element() == x + y
1980
+ True
1981
+ """
1982
+ # Just use the coordinates functions on each space
1983
+ coords = []
1984
+ for v in self._quiver:
1985
+ coords += self._spaces[v].coordinates(vector._elems[v])
1986
+
1987
+ return coords
1988
+
1989
+ def linear_combination_of_basis(self, coordinates):
1990
+ """
1991
+ Return the linear combination of the basis for ``self`` given
1992
+ by ``coordinates``.
1993
+
1994
+ INPUT:
1995
+
1996
+ - ``coordinates`` -- list; a list whose length is the dimension of
1997
+ ``self``. The `i`-th element of this list defines the
1998
+ coefficient of the `i`-th basis vector in the linear
1999
+ combination.
2000
+
2001
+ OUTPUT: :class:`QuiverRepElement`
2002
+
2003
+ EXAMPLES::
2004
+
2005
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
2006
+ sage: M = Q.P(QQ, 1)
2007
+ sage: x, y, z = M.gens('xyz')
2008
+ sage: e = x - y + z
2009
+ sage: M.coordinates(e)
2010
+ [1, -1, 1]
2011
+ sage: M.linear_combination_of_basis([1, -1, 1]) == e
2012
+ True
2013
+ """
2014
+ # Make sure the input is valid
2015
+ gens = self.gens()
2016
+ if len(gens) != len(coordinates):
2017
+ raise ValueError("the coordinates do not match the dimension of the module")
2018
+ return self.sum(ci * gi for ci, gi in zip(coordinates, gens))
2019
+
2020
+ ###########################################################################
2021
+ # #
2022
+ # CONSTRUCTION FUNCTIONS #
2023
+ # These functions create and return submodules and homomorphisms. #
2024
+ # #
2025
+ ###########################################################################
2026
+
2027
+ def submodule(self, elements=[], spaces=None):
2028
+ """
2029
+ Return the submodule generated by the data.
2030
+
2031
+ INPUT:
2032
+
2033
+ - ``elements`` -- a collection of QuiverRepElements (default:
2034
+ empty list), each should be an element of ``self``
2035
+
2036
+ - ``spaces`` -- dictionary (default: empty); should contain entries of
2037
+ the form ``{v: S}`` where `v` is a vertex of the quiver and `S` is a
2038
+ subspace of the vector space associated to `v`
2039
+
2040
+ OUTPUT:
2041
+
2042
+ - :class:`QuiverRep`, the smallest subrepresentation of ``self``
2043
+ containing the given elements and the given subspaces
2044
+
2045
+ .. NOTE::
2046
+
2047
+ This function returns only a :class:`QuiverRep` object ``sub``.
2048
+ The inclusion map of ``sub`` into ``M = self`` can be obtained
2049
+ by calling ``M.coerce_map_from(sub)``.
2050
+
2051
+ EXAMPLES::
2052
+
2053
+ sage: Q = DiGraph({1:{3:['a']}, 2:{3:['b']}}).path_semigroup()
2054
+ sage: spaces = {1: QQ^2, 2: QQ^3, 3: QQ^2}
2055
+ sage: maps = {(1, 3, 'a'): (QQ^2).Hom(QQ^2).identity(), (2, 3, 'b'): [[1, 0], [0, 0], [0, 0]]}
2056
+ sage: M = Q.representation(QQ, spaces, maps)
2057
+ sage: v = M.an_element()
2058
+ sage: M.submodule([v])
2059
+ Representation with dimension vector (1, 1, 1)
2060
+
2061
+ The smallest submodule containing the vector space at vertex 1
2062
+ also contains the entire vector space associated to vertex 3
2063
+ because there is an isomorphism associated to the edge
2064
+ ``(1, 3, 'a')``::
2065
+
2066
+ sage: M.submodule(spaces={1: QQ^2})
2067
+ Representation with dimension vector (2, 0, 2)
2068
+
2069
+ The smallest submodule containing the vector space at vertex 2
2070
+ also contains the image of the rank 1 homomorphism associated to
2071
+ the edge ``(2, 3, 'b')``::
2072
+
2073
+ sage: M.submodule(spaces={2: QQ^3})
2074
+ Representation with dimension vector (0, 3, 1)
2075
+
2076
+ As ``v`` is not already contained in this submodule, adding it as
2077
+ a generator yields a larger submodule::
2078
+
2079
+ sage: v.support()
2080
+ [1, 2, 3]
2081
+ sage: M.submodule([v], {2: QQ^3})
2082
+ Representation with dimension vector (1, 3, 1)
2083
+
2084
+ Giving no generating data yields the zero submodule::
2085
+
2086
+ sage: M.submodule().is_zero()
2087
+ True
2088
+
2089
+ If the given data generates all of M then the result is M::
2090
+
2091
+ sage: M.submodule(M.gens()) is M
2092
+ True
2093
+ """
2094
+ if spaces is None:
2095
+ spaces = {}
2096
+
2097
+ # For each vertex generate a submodule from the given data
2098
+ dim = old_dim = 0
2099
+ for v in self._quiver:
2100
+ # Start with the zero submodule if no space is specified
2101
+ if v not in spaces:
2102
+ spaces[v] = self._spaces[v].zero_submodule()
2103
+
2104
+ # Sum this with the submodule generated by the given elements.
2105
+ # Note that we are only taking the part of the element at the
2106
+ # vertex v. We can always multiply an element of a quiver
2107
+ # representation by a constant path so we don't need to worry about
2108
+ # subspaces being embedded diagonally across multiple vertices.
2109
+ spaces[v] += self._spaces[v].submodule([m._elems[v] for m in elements])
2110
+ dim += spaces[v].dimension()
2111
+
2112
+ # Now to enlarge the subspace to a submodule we sum a subspace at a
2113
+ # vertex with the images of the subspaces at adjacent vertices. The
2114
+ # dimension of the subspace will strictly increase until we generate a
2115
+ # submodule. At that point the dimension stabilizes and we can exit
2116
+ # the loop.
2117
+ while old_dim != dim:
2118
+ old_dim, dim = dim, 0
2119
+
2120
+ # First sum the subspaces
2121
+ for e in self._semigroup._sorted_edges:
2122
+ spaces[e[1]] += self._maps[e](spaces[e[0]])
2123
+
2124
+ # Then get the resulting dimensions
2125
+ for v in self._quiver:
2126
+ dim += spaces[v].dimension()
2127
+
2128
+ # Return self if the entire module was generated, otherwise return a
2129
+ # submodule
2130
+ if dim == self.dimension():
2131
+ return self
2132
+ else:
2133
+ return self._submodule(spaces)
2134
+
2135
+ def quotient(self, sub, check=True):
2136
+ """
2137
+ Return the quotient of ``self`` by the submodule ``sub``.
2138
+
2139
+ INPUT:
2140
+
2141
+ - ``sub`` -- :class:`QuiverRep`; this must be a submodule of ``self``,
2142
+ meaning the space associated to each vertex `v` of ``sub`` is a
2143
+ subspace of the space associated to `v` in ``self`` and the map
2144
+ associated to each edge `e` of ``sub`` is the restriction of
2145
+ the map associated to `e` in ``self``
2146
+
2147
+ - ``check`` -- boolean; if ``True`` then ``sub`` is checked to verify
2148
+ that it is indeed a submodule of ``self`` and an error is raised
2149
+ if it is not
2150
+
2151
+ OUTPUT: :class:`QuiverRep`, the quotient module ``self / sub``
2152
+
2153
+ .. NOTE::
2154
+
2155
+ This function returns only a QuiverRep object ``quot``. The
2156
+ projection map from ``self`` to ``quot`` can be obtained by
2157
+ calling ``quot.coerce_map_from(self)``.
2158
+
2159
+ EXAMPLES::
2160
+
2161
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup()
2162
+ sage: M = Q.I(GF(3), 3)
2163
+ sage: N = Q.S(GF(3), 3)
2164
+ sage: M.quotient(N)
2165
+ Representation with dimension vector (2, 1, 0)
2166
+ sage: M.quotient(M.radical())
2167
+ Representation with dimension vector (2, 0, 0)
2168
+ sage: M.quotient(M)
2169
+ Representation with dimension vector (0, 0, 0)
2170
+ """
2171
+
2172
+ # First form the quotient space at each vertex
2173
+ spaces = {}
2174
+ for v in self._quiver:
2175
+ spaces[v] = self._spaces[v].quotient(sub._spaces[v], check)
2176
+
2177
+ # Check the maps of sub if desired
2178
+ if check:
2179
+ for e in self._semigroup._sorted_edges:
2180
+ for x in sub._spaces[e[0]].gens():
2181
+ if sub._maps[e](x) != self._maps[e](x):
2182
+ raise ValueError("the quotient method was not passed a submodule")
2183
+
2184
+ # Then pass the edge maps to the quotient
2185
+ maps = {}
2186
+ for e in self._semigroup._sorted_edges:
2187
+ # Sage can automatically coerce an element of a module to an
2188
+ # element of a quotient of that module but not the other way
2189
+ # around. So in order to pass a map to the quotient we need to
2190
+ # construct the quotient map for the domain so that we can take
2191
+ # inverse images to lift elements. As sage can coerce to a quotient
2192
+ # this is easy, we just send generators to themselves and set the
2193
+ # domain to be the quotient.
2194
+
2195
+ # TODO: This 'if' shouldn't need to be here, but sage crashes when
2196
+ # coercing elements into a quotient that is zero. Once Github issue
2197
+ # 12413 gets fixed only the else should need to execute.
2198
+ # NOTE: This is no longer necessary. Keep around for speed or
2199
+ # remove? -- darij, 16 Feb 2014
2200
+ if spaces[e[1]].dimension() == 0:
2201
+ maps[e] = spaces[e[0]].Hom(spaces[e[1]]).zero()
2202
+ else:
2203
+ factor = self._spaces[e[0]].hom(self._spaces[e[0]].gens(), spaces[e[0]])
2204
+ # Now we create a homomorphism by specifying the images of
2205
+ # generators. Each generator is lifted to the original domain and
2206
+ # mapped over using the original map. The codomain is set as the
2207
+ # quotient so sage will take care of pushing the result to the
2208
+ # quotient in the codomain.
2209
+ maps[e] = spaces[e[0]].hom([self._maps[e](factor.lift(x))
2210
+ for x in spaces[e[0]].gens()], spaces[e[1]])
2211
+
2212
+ return self._semigroup.representation(self.base_ring(), spaces, maps)
2213
+
2214
+ def socle(self):
2215
+ """
2216
+ The socle of ``self``.
2217
+
2218
+ OUTPUT: :class:`QuiverRep`; the socle
2219
+
2220
+ EXAMPLES::
2221
+
2222
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup()
2223
+ sage: M = Q.P(QQ, 1)
2224
+ sage: M.socle()
2225
+ Representation with dimension vector (0, 0, 2)
2226
+ """
2227
+ # The socle of a representation is the intersection of the kernels of
2228
+ # all the edge maps. The empty intersection is defined to be the
2229
+ # entire space so this is what we start with.
2230
+ spaces = self._spaces.copy()
2231
+ for e in self._semigroup._sorted_edges:
2232
+ spaces[e[0]] = spaces[e[0]].intersection(self._maps[e].kernel())
2233
+
2234
+ return self._submodule(spaces)
2235
+
2236
+ def radical(self):
2237
+ """
2238
+ Return the Jacobson radical of ``self``.
2239
+
2240
+ OUTPUT: :class:`QuiverRep`; the Jacobson radical
2241
+
2242
+ EXAMPLES::
2243
+
2244
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup()
2245
+ sage: M = Q.P(QQ, 1)
2246
+ sage: M.radical()
2247
+ Representation with dimension vector (0, 2, 2)
2248
+ """
2249
+ # The Jacobson radical of a representation is the sum of the images of
2250
+ # all of the edge maps. The empty sum is defined to be zero so this is
2251
+ # what we start with.
2252
+ spaces = {v: self._spaces[v].zero_submodule() for v in self._quiver}
2253
+ for e in self._semigroup._sorted_edges:
2254
+ spaces[e[1]] += self._maps[e].image()
2255
+
2256
+ return self._submodule(spaces)
2257
+
2258
+ def top(self):
2259
+ """
2260
+ Return the top of ``self``.
2261
+
2262
+ OUTPUT: :class:`QuiverRep`; the quotient of ``self`` by its radical
2263
+
2264
+ EXAMPLES::
2265
+
2266
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup()
2267
+ sage: M = Q.P(QQ, 1)
2268
+ sage: M.top()
2269
+ Representation with dimension vector (1, 0, 0)
2270
+ sage: M.top() == M/M.radical()
2271
+ True
2272
+ """
2273
+ return self.quotient(self.radical())
2274
+
2275
+ def zero_submodule(self):
2276
+ """
2277
+ Return the zero submodule of ``self``.
2278
+
2279
+ OUTPUT: :class:`QuiverRep`; the zero submodule of ``self``
2280
+
2281
+ EXAMPLES::
2282
+
2283
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup()
2284
+ sage: M = Q.P(QQ, 1)
2285
+ sage: M.zero_submodule()
2286
+ Representation with dimension vector (0, 0, 0)
2287
+ sage: M.zero_submodule().is_zero()
2288
+ True
2289
+ """
2290
+ # When no data is specified this constructor automatically returns the
2291
+ # zero submodule
2292
+ return self._submodule()
2293
+
2294
+ def linear_dual(self):
2295
+ """
2296
+ Compute the linear dual `Hom_k(M, k)` of the module
2297
+ `M =` ``self`` over the base ring `k`.
2298
+
2299
+ OUTPUT: :class:`QuiverRep`; the dual representation
2300
+
2301
+ .. NOTE::
2302
+
2303
+ If `e` is an edge of the quiver `Q` then we let
2304
+ `(fe)(m) = f(me)`. This gives `Hom_k(M, k)` a module
2305
+ structure over the opposite quiver ``Q.reverse()``.
2306
+
2307
+ EXAMPLES::
2308
+
2309
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup()
2310
+ sage: M = Q.P(QQ, 1)
2311
+ sage: M.linear_dual()
2312
+ Representation with dimension vector (1, 2, 2)
2313
+ sage: M.linear_dual().quiver() is Q.reverse().quiver()
2314
+ True
2315
+ """
2316
+ # This module is formed by taking the transpose of the edge maps.
2317
+ spaces = self._spaces.copy()
2318
+ maps = {(e[1], e[0], e[2]):
2319
+ self._spaces[e[1]].hom(self._maps[e].matrix().transpose(),
2320
+ self._spaces[e[0]])
2321
+ for e in self._semigroup._sorted_edges}
2322
+
2323
+ # Reverse the bases if present
2324
+ if hasattr(self, '_bases'):
2325
+ bases = {}
2326
+ basis = []
2327
+ for v in self._bases:
2328
+ bases[v] = [p.reversal() for p in self._bases[v]]
2329
+ basis.extend(bases[v])
2330
+
2331
+ if isinstance(self, QuiverRep_with_path_basis):
2332
+ result = self._semigroup.reverse().representation(self.base_ring(), basis, option='dual paths')
2333
+ result._maps = maps
2334
+ result._bases = bases
2335
+ elif isinstance(self, QuiverRep_with_dual_path_basis):
2336
+ result = self._semigroup.reverse().representation(self.base_ring(), basis, option='paths')
2337
+ result._maps = maps
2338
+ result._bases = bases
2339
+ else:
2340
+ result = self._semigroup.reverse().representation(self.base_ring(), spaces, maps)
2341
+
2342
+ return result
2343
+
2344
+ def algebraic_dual(self, basis=False):
2345
+ """
2346
+ Compute the algebraic dual `Hom_Q(M, kQ)` of the module
2347
+ `M` = ``self``.
2348
+
2349
+ INPUT:
2350
+
2351
+ - ``basis`` -- boolean; if ``False``, then only the module is
2352
+ returned. If ``True``, then a tuple is returned. The first
2353
+ element is the :class:`QuiverRep` and the second element is a
2354
+ dictionary which associates to each vertex a list. The elements
2355
+ of this list are the homomorphisms which correspond to the basis
2356
+ elements of that vertex in the module.
2357
+
2358
+ OUTPUT: :class:`QuiverRep` or tuple
2359
+
2360
+ .. NOTE::
2361
+
2362
+ Here `kQ` is the path algebra considered as a right module
2363
+ over itself. If `e` is an edge of the quiver `Q` then we let
2364
+ `(fe)(m) = ef(m)`. This gives `Hom_Q(M, kQ)` a module
2365
+ structure over the opposite quiver ``Q.reverse()``.
2366
+
2367
+ EXAMPLES::
2368
+
2369
+ sage: Q = DiGraph({1:{2:['a', 'b'], 3: ['c', 'd']}, 2:{3:['e']}}).path_semigroup()
2370
+ sage: Q.free_module(GF(7)).algebraic_dual().dimension_vector()
2371
+ (7, 2, 1)
2372
+ """
2373
+ from sage.quivers.homspace import QuiverHomSpace
2374
+ return QuiverHomSpace(self, self._semigroup.free_module(self.base_ring())).left_module(basis)
2375
+
2376
+ def Hom(self, codomain):
2377
+ """
2378
+ Return the hom space from ``self`` to ``codomain``.
2379
+
2380
+ For more information see the :class:`QuiverHomSpace` documentation.
2381
+
2382
+ TESTS::
2383
+
2384
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
2385
+ sage: Q.S(QQ, 2).Hom(Q.P(QQ, 1))
2386
+ Dimension 2 QuiverHomSpace
2387
+ """
2388
+ from sage.quivers.homspace import QuiverHomSpace
2389
+ return QuiverHomSpace(self, codomain)
2390
+
2391
+ def direct_sum(self, modules, return_maps=False):
2392
+ """
2393
+ Return the direct sum of ``self`` with the given modules
2394
+ ``modules``.
2395
+
2396
+ The modules must be modules over the same quiver and base ring.
2397
+
2398
+ INPUT:
2399
+
2400
+ - ``modules`` -- :class:`QuiverRep` or list of :class:`QuiverRep`'s
2401
+
2402
+ - ``return_maps`` -- boolean (default: ``False``); if ``False``, then
2403
+ the output is a single QuiverRep object which is the direct sum
2404
+ of ``self`` with the given module or modules. If ``True``, then
2405
+ the output is a list ``[sum, iota, pi]``. The first entry
2406
+ ``sum`` is the direct sum of ``self`` with the given module or
2407
+ modules. Both ``iota`` and ``pi`` are lists of QuiverRepHoms
2408
+ with one entry for each summand; ``iota[i]`` is the inclusion
2409
+ map and ``pi[i]`` is the projection map of the `i`-th summand.
2410
+ The summands are ordered as given with ``self`` being the zeroth
2411
+ summand.
2412
+
2413
+ OUTPUT: :class:`QuiverRep` or tuple
2414
+
2415
+ EXAMPLES::
2416
+
2417
+ sage: Q = DiGraph({1:{2:['a'], 3:['b']}, 2:{4:['c']}, 3:{4:['d']}}).path_semigroup()
2418
+ sage: P1 = Q.P(QQ, 1)
2419
+ sage: P2 = Q.P(QQ, 2)
2420
+ sage: S = P1.direct_sum(P2)
2421
+ sage: P1.dimension_vector()
2422
+ (1, 1, 1, 2)
2423
+ sage: P2.dimension_vector()
2424
+ (0, 1, 0, 1)
2425
+ sage: S.dimension_vector()
2426
+ (1, 2, 1, 3)
2427
+ sage: S, iota, pi = P1.direct_sum(P2, return_maps=True)
2428
+ sage: iota[0].domain() is P1
2429
+ True
2430
+ sage: iota[1].domain() is P2
2431
+ True
2432
+ sage: pi[0].codomain() is P1
2433
+ True
2434
+ sage: pi[1].codomain() is P2
2435
+ True
2436
+ sage: iota[0].codomain() is S
2437
+ True
2438
+ sage: iota[1].codomain() is S
2439
+ True
2440
+ sage: pi[0].domain() is S
2441
+ True
2442
+ sage: pi[1].domain() is S
2443
+ True
2444
+ sage: iota[0].get_matrix(4)
2445
+ [1 0 0]
2446
+ [0 1 0]
2447
+ sage: pi[0].get_matrix(4)
2448
+ [1 0]
2449
+ [0 1]
2450
+ [0 0]
2451
+ sage: P1prime = S/iota[1].image()
2452
+ sage: f = P1prime.coerce_map_from(S)
2453
+ sage: g = f*iota[0]
2454
+ sage: g.is_isomorphism()
2455
+ True
2456
+ """
2457
+ # Convert a single module into a length 1 list and check validity
2458
+ if isinstance(modules, QuiverRep_generic):
2459
+ mods = [self, modules]
2460
+ else:
2461
+ mods = [self] + list(modules)
2462
+ for i in range(1, len(mods)):
2463
+ if not isinstance(mods[i], QuiverRep_generic):
2464
+ raise ValueError("modules must be a QuiverRep or a list of QuiverReps")
2465
+ if self._quiver is not mods[i]._quiver:
2466
+ raise ValueError("cannot direct sum modules of different quivers")
2467
+ if self.base_ring() is not mods[i].base_ring():
2468
+ raise ValueError("cannot direct sum modules with different base rings")
2469
+
2470
+ # Get the dimensions of all spaces at each vertex
2471
+ dims = {v: [x._spaces[v].dimension() for x in mods]
2472
+ for v in self._quiver}
2473
+
2474
+ # Create spaces of the correct dimensions
2475
+ spaces = {v: self.base_ring()**sum(dims[v]) for v in self._quiver}
2476
+
2477
+ # Take block sums of matrices to form the maps
2478
+ from sage.matrix.constructor import block_diagonal_matrix
2479
+ maps = {}
2480
+ for e in self._semigroup._sorted_edges:
2481
+ maps[e] = block_diagonal_matrix([x._maps[e].matrix() for x in mods], subdivide=False)
2482
+
2483
+ # Create the QuiverRep, return if the maps aren't wanted
2484
+ result = self._semigroup.representation(self.base_ring(), spaces, maps)
2485
+ if not return_maps:
2486
+ return result
2487
+
2488
+ # Create the inclusions and projections
2489
+ from sage.matrix.constructor import Matrix, block_matrix
2490
+ from sage.rings.integer import Integer
2491
+ iota = []
2492
+ pi = []
2493
+ for i in range(len(mods)):
2494
+ incl_maps = {}
2495
+ proj_maps = {}
2496
+ for v in self._quiver:
2497
+ # Create the maps using block matrices
2498
+ pre_dims = sum(dims[v][:i])
2499
+ post_dims = sum(dims[v][i + 1:])
2500
+ incl_maps[v] = block_matrix(1, 3, [Matrix(dims[v][i], pre_dims),
2501
+ Matrix(dims[v][i], dims[v][i], Integer(1)),
2502
+ Matrix(dims[v][i], post_dims)])
2503
+ proj_maps[v] = block_matrix(3, 1, [Matrix(pre_dims, dims[v][i]),
2504
+ Matrix(dims[v][i], dims[v][i], Integer(1)),
2505
+ Matrix(post_dims, dims[v][i])])
2506
+ # These matrices are over the integers, and get coerced
2507
+ # into the appropriate base ring at a later stage.
2508
+ # Might make trouble if the integer 1 does not coerce to
2509
+ # the 1 of the base ring; is that a real issue?
2510
+ # -- darij, 19 Feb 2014
2511
+
2512
+ # Create and save the QuiverRepHom
2513
+
2514
+ iota.append(mods[i].hom(incl_maps, result))
2515
+ pi.append(result.hom(proj_maps, mods[i]))
2516
+
2517
+ # Return all the data
2518
+ return [result, iota, pi]
2519
+
2520
+ def projective_cover(self, return_maps=False):
2521
+ """
2522
+ Return the projective cover of ``self``.
2523
+
2524
+ EXAMPLES::
2525
+
2526
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c','d']}}).path_semigroup()
2527
+ sage: S1 = Q.S(GF(3), 1)
2528
+ sage: f1 = S1.projective_cover()
2529
+ sage: f1.is_surjective()
2530
+ True
2531
+ sage: f1._domain
2532
+ Representation with dimension vector (1, 2, 4)
2533
+ sage: Q.P(GF(3), 1)
2534
+ Representation with dimension vector (1, 2, 4)
2535
+ """
2536
+ # Deal with the zero module
2537
+ if self.dimension() == 0:
2538
+ return self.coerce_map_from(self)
2539
+
2540
+ # Get the projection onto the top and generators
2541
+ top = self.top()
2542
+ proj_to_top = top.coerce_map_from(self)
2543
+ gens = top.gens()
2544
+
2545
+ # Lift each of the generators
2546
+ lifts = [proj_to_top.lift(x) for x in gens]
2547
+
2548
+ # Get projective summands of the cover
2549
+ Ps = [self._semigroup.P(self.base_ring(), x.support()[0]) for x in gens]
2550
+
2551
+ # Factor the maps through self
2552
+ maps = [Ps[i].hom(lifts[i], self) for i in range(len(gens))]
2553
+
2554
+ # Sum them and return
2555
+ return maps[0].direct_sum(maps[1:], return_maps, 'codomain')
2556
+
2557
+ def transpose(self):
2558
+ r"""
2559
+ Return the transpose of ``self``.
2560
+
2561
+ The transpose, `\mbox{Tr} M`, of a module `M` is defined as
2562
+ follows. Let `p: P_1 \to P_2` be the second map in a minimal
2563
+ projective presentation `P_1 \to P_2 \to M \to 0` of `M`.
2564
+ If `p^t` is the algebraic dual of `p` then define
2565
+ `\mbox{Tr} M = \mbox{coker} p^t`.
2566
+
2567
+ OUTPUT: :class:`QuiverRep`
2568
+
2569
+ EXAMPLES::
2570
+
2571
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
2572
+ sage: M = Q.representation(GF(3), {1: 1, 2: 1}, {(1, 2, 'a'): 1})
2573
+ sage: M.transpose()
2574
+ Representation with dimension vector (1, 1)
2575
+ """
2576
+
2577
+ # Get the second map in the minimal projective resolution of self.
2578
+ # Note we create this map as the projective cover of a kernel so we
2579
+ # need to alter the codomain to be the projective and not the kernel.
2580
+ p1 = self.projective_cover()
2581
+ k = p1.kernel()
2582
+ p = p1.domain().coerce_map_from(k) * k.projective_cover()
2583
+
2584
+ # Return the cokernel
2585
+ return p.algebraic_dual().cokernel()
2586
+
2587
+ def AR_translate(self):
2588
+ """
2589
+ Return the Auslander-Reiten translate of ``self``.
2590
+
2591
+ EXAMPLES::
2592
+
2593
+ sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup()
2594
+ sage: M = Q.representation(GF(3), {1: 1, 2: 1}, {(1, 2, 'a'): 1})
2595
+ sage: tauM = M.AR_translate()
2596
+ sage: tauM
2597
+ Representation with dimension vector (1, 1)
2598
+ sage: tauM.get_map((1, 2, 'a')).matrix()
2599
+ [1]
2600
+ sage: tauM.get_map((1, 2, 'b')).matrix()
2601
+ [0]
2602
+
2603
+ The module ``M`` above is its own AR translate. This is not
2604
+ always true::
2605
+
2606
+ sage: Q2 = DiGraph({3:{1:['b']}, 5:{3:['a']}}).path_semigroup()
2607
+ sage: Q2.S(QQ, 5).AR_translate()
2608
+ Representation with dimension vector (0, 1, 0)
2609
+ """
2610
+
2611
+ return self.transpose().linear_dual()
2612
+
2613
+ ###########################################################################
2614
+ # #
2615
+ # ADDITIONAL OPERATIONS #
2616
+ # These functions operations that are not implemented via binary #
2617
+ # operators. #
2618
+ # #
2619
+ ###########################################################################
2620
+
2621
+ def right_edge_action(self, element, path):
2622
+ r"""
2623
+ Return the result of ``element*path``.
2624
+
2625
+ INPUT:
2626
+
2627
+ - ``element`` -- :class:`QuiverRepElement`, an element of ``self``
2628
+
2629
+ - ``path`` -- :class:`QuiverPath` or list of tuples
2630
+
2631
+ OUTPUT:
2632
+
2633
+ - :class:`QuiverRepElement`, the result of ``element*path`` when
2634
+ ``path`` is considered an element of the path algebra of the quiver
2635
+
2636
+ EXAMPLES::
2637
+
2638
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup()
2639
+ sage: M = Q.P(QQ, 1)
2640
+ sage: v = M.an_element()
2641
+ sage: v.support()
2642
+ [1, 2, 3]
2643
+ sage: M.right_edge_action(v, [(1, 1)]).support()
2644
+ [1]
2645
+ sage: M.right_edge_action(v, [(1, 1)]).support()
2646
+ [1]
2647
+ sage: M.right_edge_action(v, [(1, 2, 'a')]).support()
2648
+ [2]
2649
+ sage: M.right_edge_action(v, 'a') == M.right_edge_action(v, [(1, 2, 'a')])
2650
+ True
2651
+ """
2652
+ # Convert to a QuiverPath
2653
+ qpath = self._semigroup(path)
2654
+
2655
+ # Invalid paths are zero in the quiver algebra
2656
+ result = self() # this must not be self.zero(), which is cached
2657
+
2658
+ # Start with the element at the initial vertex
2659
+ x = element._elems[qpath.initial_vertex()]
2660
+
2661
+ # Act by each edge
2662
+ for e in qpath:
2663
+ x = self.get_map(e)(x)
2664
+
2665
+ # Assign the result to the terminal vertex and return
2666
+ result._elems[qpath.terminal_vertex()] = x
2667
+ return result
2668
+
2669
+
2670
+ class QuiverRep_with_path_basis(QuiverRep_generic):
2671
+ r"""
2672
+ The basis of the module must be closed under right multiplication by
2673
+ an edge; that is, appending any edge to the end of any path in the
2674
+ basis must result in either an invalid path or a valid path also
2675
+ contained in the basis of the module.
2676
+
2677
+ INPUT:
2678
+
2679
+ - ``k`` -- ring, the base ring of the representation
2680
+
2681
+ - ``P`` -- the path semigroup of the quiver `Q` of the representation
2682
+
2683
+ - ``basis`` -- list (default: empty); should be a list of paths (also
2684
+ lists) in the quiver `Q`. Entries that do not represent valid paths
2685
+ are ignored and duplicate paths are deleted. The closure of this
2686
+ list under right multiplication forms the basis of the resulting
2687
+ representation.
2688
+ """
2689
+ # This class implements quiver representations whose bases correspond to
2690
+ # paths in the path algebra and whose maps are path multiplication. The
2691
+ # main advantage to having such a basis is that a homomorphism can be
2692
+ # defined by giving a single element in the codomain. This class derives
2693
+ # from the QuiverRep class and the following private methods and variables
2694
+ # have been added:
2695
+ #
2696
+ # * _bases
2697
+ # A dictionary associating to each vertex a list of paths (also lists)
2698
+ # which correspond to the basis elements of the space assigned to that
2699
+ # vertex.
2700
+ #
2701
+ # If the right closure of the basis is also closed under left mult by an
2702
+ # edge then the object will have the following private variable:
2703
+ #
2704
+ # * _left_action_mats
2705
+ # A dictionary of dictionaries. If e is an edge or trivial path of
2706
+ # the quiver then _left_action_mats[e] is a dictionary that
2707
+ # associates a matrix to each vertex. The left action of e on a
2708
+ # QuiverRepElement is given by multiplying, on the left, the vector
2709
+ # associated to vertex v in the QuiverRepElement by the matrix
2710
+ # _left_action_mats[e][v]
2711
+
2712
+ def __init__(self, k, P, basis):
2713
+ """
2714
+ Initialize ``self``. Type ``QuiverRep_with_path_basis?`` for more
2715
+ information.
2716
+
2717
+ TESTS::
2718
+
2719
+ sage: Q1 = DiGraph({1:{2:['a']}}).path_semigroup()
2720
+ sage: P1 = Q1.representation(QQ, [[(1, 1)]], option='paths')
2721
+ sage: P1.dimension()
2722
+ 2
2723
+ sage: kQ = Q1.representation(QQ, [[(1, 1)], [(2, 2)], [(1, 2, 'a')], [(1, 2, 'a')]], option='paths')
2724
+ sage: kQ.dimension()
2725
+ 3
2726
+ sage: Q2 = DiGraph({1:{2:['a'], 3:['b', 'c']}, 2:{3:['d']}}).path_semigroup()
2727
+ sage: M = Q2.representation(QQ, [[(2, 2)], [(1, 2, 'a')]], option='paths')
2728
+ sage: M.dimension_vector()
2729
+ (0, 2, 2)
2730
+ sage: N = Q2.representation(QQ, [[(2, 2)], [(1, 2, 'a'), (2, 3, 'd')]], option='paths')
2731
+ sage: N.dimension_vector()
2732
+ (0, 1, 2)
2733
+ sage: TestSuite(M).run()
2734
+ """
2735
+ self._quiver = Q = P.quiver()
2736
+
2737
+ # Add the paths to the basis dictionary. The terminal vertex is the
2738
+ # key
2739
+ self._bases = {v: [] for v in Q}
2740
+ for path in basis:
2741
+ # if path:
2742
+ self._bases[path.terminal_vertex()].append(path)
2743
+
2744
+ # Create the matrices of the maps
2745
+ from sage.matrix.constructor import Matrix
2746
+ maps = {}
2747
+ for e in P._sorted_edges:
2748
+ arrow = P([e], check=False)
2749
+ # Start with the zero matrix and fill in from there
2750
+ maps[e] = Matrix(k, len(self._bases[e[0]]), len(self._bases[e[1]]))
2751
+ for i in range(len(self._bases[e[0]])):
2752
+ # Add an entry to the matrix corresponding to where the new path is found
2753
+ j = self._bases[e[1]].index(self._bases[e[0]][i] * arrow)
2754
+ maps[e][i, j] = k.one()
2755
+
2756
+ # Create the spaces and then the representation
2757
+ spaces = {v: len(self._bases[v]) for v in Q}
2758
+ super().__init__(k, P, spaces, maps)
2759
+
2760
+ # Try and create the matrices for the left edge action of edges. If it
2761
+ # fails just return, there's no edge action and the construction is
2762
+ # done
2763
+ action_mats = {}
2764
+ for e in P._sorted_edges:
2765
+ action_mats[e] = {}
2766
+ for v in self._quiver:
2767
+ # Start with the zero matrix and fill in
2768
+ ell = len(self._bases[v])
2769
+ action_mats[e][v] = Matrix(k, ell, ell)
2770
+
2771
+ for j in range(ell):
2772
+ if e[1] == self._bases[v][j].initial_vertex():
2773
+ try:
2774
+ action_mats[e][v][self._bases[v].index(P([e], check=False) * self._bases[v][j]), j] = k.one()
2775
+ except ValueError:
2776
+ # There is no left action
2777
+ return
2778
+
2779
+ # If haven't returned yet then there is a left action. Create the
2780
+ # matrices for acting by trivial paths
2781
+ for vert in self._quiver:
2782
+ e = (vert, vert)
2783
+ action_mats[e] = {}
2784
+ for v in self._quiver:
2785
+ # Start with the zero matrix and fill in
2786
+ ell = len(self._bases[v])
2787
+ action_mats[e][v] = Matrix(k, ell, ell)
2788
+
2789
+ # Paths not beginning at vert are sent to zero, paths beginning
2790
+ # at vert are fixed
2791
+ for i in range(ell):
2792
+ if self._bases[v][i].initial_vertex() == vert:
2793
+ action_mats[e][v][i, i] = k.one()
2794
+
2795
+ # Define the method and save the matrices
2796
+ self.left_edge_action = self._left_edge_action
2797
+ self._left_action_mats = action_mats
2798
+
2799
+ def _left_edge_action(self, edge, element):
2800
+ r"""
2801
+ Return the result of ``edge*element``.
2802
+
2803
+ INPUT:
2804
+
2805
+ - ``element`` -- :class:`QuiverRepElement`; an element of ``self``
2806
+
2807
+ - ``edge`` -- an edge of the quiver (a tuple) or a list of edges in
2808
+ the quiver. Such a list can be empty (in which case no action
2809
+ is performed) and can contain trivial paths (tuples of the form
2810
+ `(v, v)` where `v` is a vertex of the quiver)
2811
+
2812
+ OUTPUT:
2813
+
2814
+ - :class:`QuiverRepElement`, the result of ``edge*element`` when
2815
+ ``edge`` is considered an element of the path algebra of the quiver
2816
+
2817
+ EXAMPLES::
2818
+
2819
+ sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup()
2820
+ sage: M = Q.representation(QQ, [[(1, 1)], [(2, 2)], [(3, 3)]], option='paths')
2821
+ sage: v = M.an_element()
2822
+ sage: v.support()
2823
+ [1, 2, 3]
2824
+
2825
+ The sum of all trivial paths is the identity element under
2826
+ this action::
2827
+
2828
+ sage: x = M.left_edge_action((1, 1), v) # indirect doctest
2829
+ sage: y = M.left_edge_action((2, 2), v) # indirect doctest
2830
+ sage: z = M.left_edge_action((3, 3), v) # indirect doctest
2831
+ sage: x + y + z == v
2832
+ True
2833
+
2834
+ Note that the action only depends on the element of the path algebra
2835
+ that the input specifies::
2836
+
2837
+ sage: a = M.left_edge_action([(1, 1), (1, 2, 'a'), (2, 2)], v) # indirect doctest
2838
+ sage: b = M.left_edge_action((1, 2, 'a'), v) # indirect doctest
2839
+ sage: a == b
2840
+ True
2841
+
2842
+ These two edges multiply to zero in the path algebra::
2843
+
2844
+ sage: M.left_edge_action([(1, 2, 'a'), (1, 2, 'b')], v).is_zero() # indirect doctest
2845
+ True
2846
+ """
2847
+
2848
+ # Deal with lists by calling this function recursively
2849
+ if isinstance(edge, list):
2850
+ if not edge:
2851
+ return element
2852
+ else:
2853
+ return self.left_edge_action(edge[:-1], self.left_edge_action(edge[-1], element))
2854
+
2855
+ # Now we are just acting by a single edge
2856
+ elems = {v: self._left_action_mats[edge][v] * element._elems[v]
2857
+ for v in self._quiver}
2858
+ return self(elems)
2859
+
2860
+ def is_left_module(self) -> bool:
2861
+ """
2862
+ Test whether the basis is closed under left multiplication.
2863
+
2864
+ EXAMPLES::
2865
+
2866
+ sage: Q1 = DiGraph({1:{2:['a']}}).path_semigroup()
2867
+ sage: P2 = Q1.representation(QQ, [[(2, 2)]], option='paths')
2868
+ sage: P2.is_left_module()
2869
+ False
2870
+
2871
+ The supplied basis is not closed under left multiplication, but it's
2872
+ not closed under right multiplication either. When the closure under
2873
+ right multiplication is taken the result is also closed under left
2874
+ multiplication and therefore produces a left module structure::
2875
+
2876
+ sage: kQ = Q1.representation(QQ, [[(1, 1)], [(2, 2)]], option='paths')
2877
+ sage: kQ.is_left_module()
2878
+ True
2879
+
2880
+ Taking the right closure of a left closed set produces another
2881
+ left closed set::
2882
+
2883
+ sage: Q2 = DiGraph({1:{2:['a'], 3:['b', 'c']}, 2:{3:['d']}}).path_semigroup()
2884
+ sage: M = Q2.representation(QQ, [[(2, 2)], [(1, 2, 'a')]], option='paths')
2885
+ sage: M.is_left_module()
2886
+ True
2887
+
2888
+ Note that the second path is length 2, so even though the edge (1, 2, 'a')
2889
+ appears in the input the path [(1, 2, 'a')] is not in the right closure::
2890
+
2891
+ sage: N = Q2.representation(QQ, [[(2, 2)], [(1, 2, 'a'), (2, 3, 'd')]], option='paths')
2892
+ sage: N.is_left_module()
2893
+ False
2894
+ """
2895
+ return hasattr(self, 'left_edge_action')
2896
+
2897
+
2898
+ class QuiverRep_with_dual_path_basis(QuiverRep_generic):
2899
+ r"""
2900
+ The basis of the module must be closed under left deletion of an edge; that
2901
+ is, deleting any edge from the beginning of any path in the basis must
2902
+ result in a path also contained in the basis of the module.
2903
+
2904
+ INPUT:
2905
+
2906
+ - ``k`` -- ring; the base ring of the representation
2907
+
2908
+ - ``P`` -- the path semigroup of the quiver `Q` of the representation
2909
+
2910
+ - ``basis`` -- list (default: empty); should be a list of paths (also
2911
+ lists) in the quiver `Q`. Entries that do not represent valid paths
2912
+ are ignored and duplicate paths are deleted. The closure of this
2913
+ list under left deletion forms the basis of the resulting
2914
+ representation.
2915
+ """
2916
+ # This class implements quiver representations whose bases correspond to
2917
+ # paths in the path algebra and whose maps are edge deletion. The
2918
+ # main advantage to having such a basis is that a homomorphism can be
2919
+ # defined by giving a single element in the domain. This class derives
2920
+ # from the QuiverRep class and the following methods and private variables
2921
+ # have been added:
2922
+ #
2923
+ # * _bases
2924
+ # A dictionary associating to each vertex a list of paths which
2925
+ # correspond to the basis elements of the space assigned to that
2926
+ # vertex.
2927
+
2928
+ def __init__(self, k, P, basis):
2929
+ """
2930
+ Initialize ``self``. Type ``QuiverRep_with_dual_path_basis?`` for
2931
+ more information.
2932
+
2933
+ TESTS::
2934
+
2935
+ sage: Q1 = DiGraph({1:{2:['a']}}).path_semigroup()
2936
+ sage: I2 = Q1.representation(QQ, [[(2, 2)]], option='dual paths')
2937
+ sage: I2.dimension()
2938
+ 2
2939
+ sage: kQdual = Q1.representation(QQ, [[(1, 1)], [(2, 2)], [(1, 2, 'a')], [(1, 2, 'a')]], option='dual paths')
2940
+ sage: kQdual.dimension()
2941
+ 3
2942
+ sage: Q2 = DiGraph({1:{2:['a'], 3:['b', 'c']}, 2:{3:['d']}}).path_semigroup()
2943
+ sage: M = Q2.representation(QQ, [[(1, 2, 'a'), (2, 3, 'd')], [(1, 3, 'b')]], option='dual paths')
2944
+ sage: M.dimension_vector()
2945
+ (2, 0, 0)
2946
+ sage: N = Q2.representation(QQ, [[(2, 2)], [(1, 2, 'a'), (2, 3, 'd')]], option='dual paths')
2947
+ sage: N.dimension_vector()
2948
+ (2, 1, 0)
2949
+ sage: TestSuite(N).run()
2950
+ """
2951
+ self._quiver = Q = P.quiver()
2952
+
2953
+ # Add the paths to the basis dictionary. The initial vertex is the
2954
+ # key
2955
+ self._bases = {v: [] for v in Q}
2956
+ for path in basis:
2957
+ # if path:
2958
+ self._bases[path.initial_vertex()].append(path)
2959
+
2960
+ # Create the matrices of the maps
2961
+ from sage.matrix.constructor import Matrix
2962
+ maps = {}
2963
+ for e in P._sorted_edges:
2964
+ arrow = P([e], check=False)
2965
+ # Start with the zero matrix and fill in from there
2966
+ maps[e] = Matrix(k, len(self._bases[e[0]]), len(self._bases[e[1]]))
2967
+ for i in range(len(self._bases[e[0]])):
2968
+ # Add an entry to the matrix corresponding to where the new path is found
2969
+ if self._bases[e[0]][i] % arrow in self._bases[e[1]]:
2970
+ j = self._bases[e[1]].index(self._bases[e[0]][i] % arrow)
2971
+ maps[e][i, j] = k.one()
2972
+
2973
+ # Create the spaces and then the representation
2974
+ spaces = {v: len(self._bases[v]) for v in Q}
2975
+ super().__init__(k, P, spaces, maps)