passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_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 (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,2468 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # sage.doctest: needs sage.graphs
3
+ r"""
4
+ Quiver mutation types
5
+
6
+ AUTHORS:
7
+
8
+ - Gregg Musiker (2012, initial version)
9
+ - Christian Stump (2012, initial version)
10
+ - Hugh Thomas (2012, initial version)
11
+ """
12
+ # ****************************************************************************
13
+ # Copyright (C) 2011 Gregg Musiker <gmusiker@gmail.com>
14
+ # Christian Stump <christian.stump@gmail.com>
15
+ # Hugh Thomas <hugh@math.unb.ca>
16
+ #
17
+ # Distributed under the terms of the GNU General Public License (GPL)
18
+ # https://www.gnu.org/licenses/
19
+ # ***************************************************************************
20
+ from __future__ import annotations
21
+ from pathlib import Path
22
+ import pickle
23
+
24
+ from sage.structure.sage_object import SageObject
25
+ from copy import copy
26
+ from sage.structure.unique_representation import UniqueRepresentation
27
+ from sage.misc.cachefunc import cached_method
28
+ from sage.misc.lazy_import import lazy_import
29
+ from sage.rings.integer_ring import ZZ
30
+ from sage.rings.infinity import infinity
31
+ from sage.graphs.digraph import DiGraph
32
+ from sage.graphs.graph import Graph
33
+ from sage.arith.misc import binomial, euler_phi
34
+ from sage.misc.misc_c import prod
35
+
36
+ lazy_import('sage.matrix.constructor', 'matrix')
37
+
38
+
39
+ class QuiverMutationTypeFactory(SageObject):
40
+ def __call__(self, *args):
41
+ """
42
+ For a detailed description, see :meth:`QuiverMutationType`.
43
+
44
+ EXAMPLES::
45
+
46
+ sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationTypeFactory
47
+ sage: QuiverMutationTypeFactory()
48
+ QuiverMutationType
49
+ """
50
+ # get data as arguments or as list/tuple
51
+ if len(args) == 1:
52
+ data = args[0]
53
+ else:
54
+ data = args
55
+
56
+ # data is a QuiverMutationType
57
+ if isinstance(data, QuiverMutationType_Irreducible):
58
+ return data
59
+ elif isinstance(data, QuiverMutationType_Reducible):
60
+ return data
61
+
62
+ # check that data is a tuple or list
63
+ if isinstance(data, tuple) and data:
64
+ pass
65
+ elif isinstance(data, list) and data:
66
+ data = tuple(data)
67
+ else:
68
+ _mutation_type_error(data)
69
+
70
+ # check for reducible types
71
+ if all(isinstance(data_component, (list, tuple,
72
+ QuiverMutationType_Irreducible))
73
+ for data_component in data):
74
+ if len(data) == 1:
75
+ return QuiverMutationType(data[0])
76
+ else:
77
+ data = tuple(QuiverMutationType(comp) for comp in data)
78
+ return QuiverMutationType_Reducible(*data)
79
+
80
+ # check for irreducible types
81
+ if len(data) == 2:
82
+ data = (data[0], data[1], None)
83
+ elif len(data) == 3:
84
+ pass
85
+ else:
86
+ _mutation_type_error(data)
87
+
88
+ if isinstance(data[2], list):
89
+ data = (data[0], data[1], tuple(data[2]))
90
+ if isinstance(data[1], list):
91
+ data = (data[0], tuple(data[1]), data[2])
92
+
93
+ # mutation type casting
94
+ if data == ('D', 2, None):
95
+ return QuiverMutationType(('A', 1, None), ('A', 1, None))
96
+ elif data == ('D', 3, None):
97
+ data = ('A', 3, None)
98
+ elif data == ('C', 2, None):
99
+ data = ('B', 2, None)
100
+ elif data == ('E', 9, None):
101
+ data = ('E', 8, 1)
102
+ elif data[0] == 'A' and data[2] == 1 and isinstance(data[1], tuple) and len(data[1]) == 2 and min(data[1]) == 0:
103
+ if max(data[1]) == 0:
104
+ pass
105
+ elif max(data[1]) == 1:
106
+ data = ('A', 1, None)
107
+ elif max(data[1]) == 2:
108
+ return QuiverMutationType(('A', 1, None), ('A', 1, None))
109
+ elif max(data[1]) == 3:
110
+ data = ('A', 3, None)
111
+ else:
112
+ data = ('D', max(data[1]), None)
113
+ elif data[0] == 'GR' and data[2] is None and isinstance(data[1], tuple) and len(data[1]) == 2 and data[1][1] > data[1][0]:
114
+ if min(data[1]) > max(data[1]) / 2 and max(data[1]) != min(data[1]) + 1:
115
+ data = (data[0], (max(data[1]) - min(data[1]), max(data[1])), data[2])
116
+ if min(data[1]) == 2 and max(data[1]) > 3:
117
+ data = ('A', max(data[1]) - 3, None)
118
+ elif data[1] == (3, 6):
119
+ data = ('D', 4, None)
120
+ elif data[1] == (3, 7):
121
+ data = ('E', 6, None)
122
+ elif data[1] == (3, 8):
123
+ data = ('E', 8, None)
124
+ elif data[1] == (3, 9):
125
+ data = ('E', 8, [1, 1])
126
+ elif data[1] == (4, 8):
127
+ data = ('E', 7, [1, 1])
128
+ elif data == ('TR', 1, None):
129
+ data = ('A', 1, None)
130
+ elif data == ('TR', 2, None):
131
+ data = ('A', 3, None)
132
+ elif data == ('TR', 3, None):
133
+ data = ('D', 6, None)
134
+ elif data == ('TR', 4, None):
135
+ data = ('E', 8, (1, 1))
136
+ # mutation type casting from Kac conventions
137
+ elif data == ('A', 1, 1):
138
+ data = ('A', (1, 1), 1)
139
+ elif data[0] == 'B' and data[2] == 1:
140
+ if data[1] == 2:
141
+ data = ('CC', 2, 1)
142
+ elif data[1] > 2:
143
+ data = ('BD', data[1], 1)
144
+ elif data[0] == 'B' and data[2] == -1:
145
+ if data[1] == 2:
146
+ data = ('BB', 2, 1)
147
+ elif data[1] > 2:
148
+ data = ('CD', data[1], 1)
149
+ elif data[0] == 'C' and data[1] > 1 and data[2] == 1:
150
+ data = ('CC', data[1], 1)
151
+ elif data[0] == 'C' and data[1] > 1 and data[2] == -1:
152
+ data = ('BB', data[1], 1)
153
+ elif data == ('A', 2, 2):
154
+ data = ('BC', 1, 1)
155
+ elif data[0] == 'A' and data[1] in ZZ and data[1] > 1 and data[1] % 2 == 0 and data[2] == 2:
156
+ data = ('BC', data[1] // 2, 1)
157
+ elif data[0] == 'A' and data[1] in ZZ and data[1] > 3 and data[1] % 2 and data[2] == 2:
158
+ data = ('CD', (data[1] + 1) // 2, 1)
159
+ # We think of ('A',3, 2) as ('D',3, 2)
160
+ elif data == ('A', 3, 2):
161
+ data = ('BB', 2, 1)
162
+ elif data[0] == 'D' and data[1] in ZZ and data[1] > 2 and data[2] == 2:
163
+ data = ('BB', data[1] - 1, 1)
164
+ elif data == ('E', 6, 2):
165
+ data = ('F', 4, -1)
166
+ elif data == ('D', 4, 3):
167
+ data = ('G', 2, -1)
168
+ elif data == ('F', 4, (2, 1)):
169
+ data = ('F', 4, (1, 2))
170
+ elif data == ('G', 2, (3, 1)):
171
+ data = ('G', 2, (1, 3))
172
+ elif data[0] == 'T' and data[2] is None:
173
+ data = (data[0], tuple(sorted(data[1])), data[2])
174
+ r, p, q = data[1]
175
+ if r == 1:
176
+ data = ('A', p + q - 1, None)
177
+ elif r == p == 2:
178
+ data = ('D', q + 2, None)
179
+ elif r == 2 and p == 3:
180
+ if q in (3, 4, 5):
181
+ data = ('E', q + 3, None)
182
+ elif q == 6:
183
+ data = ('E', 8, 1)
184
+ else:
185
+ data = ('E', q + 3, None)
186
+ elif r == 2 and p == q == 4:
187
+ data = ('E', 7, 1)
188
+ elif r == p == q == 3:
189
+ data = ('E', 6, 1)
190
+ elif data[0] == 'R2' and data[2] is None and all(data[1][i] in ZZ and data[1][i] > 0 for i in [0, 1]):
191
+ data = (data[0], tuple(sorted(data[1])), data[2])
192
+ if data[1] == (1, 1):
193
+ data = ('A', 2, None)
194
+ elif data[1] == (1, 2):
195
+ data = ('B', 2, None)
196
+ elif data[1] == (1, 3):
197
+ data = ('G', 2, None)
198
+ elif data[1] == (1, 4):
199
+ data = ('BC', 1, 1)
200
+ elif data[1] == (2, 2):
201
+ data = ('A', (1, 1), 1)
202
+
203
+ # setting the parameters and returning the mutation type
204
+ letter, rank, twist = data
205
+ if not isinstance(letter, str):
206
+ _mutation_type_error(data)
207
+ if isinstance(rank, list):
208
+ rank = tuple(rank)
209
+ if isinstance(twist, list):
210
+ twist = tuple(twist)
211
+ return QuiverMutationType_Irreducible(letter, rank, twist)
212
+
213
+ def _repr_(self) -> str:
214
+ """
215
+ Return the string representation of ``self``.
216
+
217
+ EXAMPLES::
218
+
219
+ sage: QuiverMutationType # indirect doctest
220
+ QuiverMutationType
221
+ """
222
+ return "QuiverMutationType"
223
+
224
+ def samples(self, finite=None, affine=None, elliptic=None,
225
+ mutation_finite=None):
226
+ """
227
+ Return a sample of the available quiver mutations types.
228
+
229
+ INPUT:
230
+
231
+ - ``finite``
232
+
233
+ - ``affine``
234
+
235
+ - ``elliptic``
236
+
237
+ - ``mutation_finite``
238
+
239
+ All four input keywords default values are ``None``. If
240
+ set to ``True`` or ``False``, only these samples are returned.
241
+
242
+ EXAMPLES::
243
+
244
+ sage: QuiverMutationType.samples()
245
+ [['A', 1], ['A', 5], ['B', 2], ['B', 5], ['C', 3],
246
+ ['C', 5], [ ['A', 1], ['A', 1] ], ['D', 5], ['E', 6],
247
+ ['E', 7], ['E', 8], ['F', 4], ['G', 2],
248
+ ['A', [1, 1], 1], ['A', [4, 5], 1], ['D', 4, 1],
249
+ ['BB', 5, 1], ['E', 6, [1, 1]], ['E', 7, [1, 1]],
250
+ ['R2', [1, 5]], ['R2', [3, 5]], ['E', 10], ['BE', 5],
251
+ ['GR', [3, 10]], ['T', [3, 3, 4]]]
252
+
253
+ sage: QuiverMutationType.samples(finite=True)
254
+ [['A', 1], ['A', 5], ['B', 2], ['B', 5], ['C', 3],
255
+ ['C', 5], [ ['A', 1], ['A', 1] ], ['D', 5], ['E', 6],
256
+ ['E', 7], ['E', 8], ['F', 4], ['G', 2]]
257
+
258
+ sage: QuiverMutationType.samples(affine=True)
259
+ [['A', [1, 1], 1], ['A', [4, 5], 1], ['D', 4, 1], ['BB', 5, 1]]
260
+
261
+ sage: QuiverMutationType.samples(elliptic=True)
262
+ [['E', 6, [1, 1]], ['E', 7, [1, 1]]]
263
+
264
+ sage: QuiverMutationType.samples(mutation_finite=False)
265
+ [['R2', [1, 5]], ['R2', [3, 5]], ['E', 10], ['BE', 5],
266
+ ['GR', [3, 10]], ['T', [3, 3, 4]]]
267
+ """
268
+ result = self._samples()
269
+ if finite is not None:
270
+ result = [t for t in result if t.is_finite() == finite]
271
+ if affine is not None:
272
+ result = [t for t in result if t.is_affine() == affine]
273
+ if elliptic is not None:
274
+ result = [t for t in result if t.is_elliptic() == elliptic]
275
+ if mutation_finite is not None:
276
+ result = [t for t in result
277
+ if t.is_mutation_finite() == mutation_finite]
278
+ return result
279
+
280
+ @cached_method
281
+ def _samples(self):
282
+ """
283
+ Return a list of sample of available Cartan types.
284
+
285
+ EXAMPLES::
286
+
287
+ sage: X = QuiverMutationType._samples()
288
+ """
289
+ finite_types = \
290
+ [QuiverMutationType(t) for t in [['A', 1], ['A', 5], ['B', 2], ['B', 5],
291
+ ['C', 3], ['C', 5], ['D', 2], ['D', 5],
292
+ ["E", 6], ["E", 7], ["E", 8], ["F", 4],
293
+ ["G", 2]]]
294
+ affine_types = \
295
+ [QuiverMutationType(t) for t in [['A', [1, 1], 1], ['A', [4, 5], 1], ['D', 4, 1], ['BB', 5, 1]]]
296
+ elliptic_types = \
297
+ [QuiverMutationType(t) for t in [['E', 6, [1, 1]], ['E', 7, [1, 1]]]]
298
+ mutation_finite_types = \
299
+ [QuiverMutationType(t) for t in [['R2', (1, 5)], ['R2', (3, 5)]]]
300
+ mutation_infinite_types = \
301
+ [QuiverMutationType(t) for t in [['E', 10], ['BE', 5], ['GR', (3, 10)], ['T', (3, 3, 4)]]]
302
+
303
+ return finite_types + affine_types + elliptic_types + mutation_finite_types + mutation_infinite_types
304
+
305
+
306
+ QuiverMutationType = QuiverMutationTypeFactory()
307
+
308
+
309
+ QuiverMutationType.__doc__ = \
310
+ r"""
311
+
312
+ *Quiver mutation types* can be seen as a slight generalization of
313
+ *generalized Cartan types*.
314
+
315
+ Background on generalized Cartan types can be found at
316
+
317
+ :wikipedia:`Generalized_Cartan_matrix`
318
+
319
+ For the compendium on the cluster algebra and quiver package in Sage see [MS2011]_
320
+
321
+ A `B`-matrix is a skew-symmetrizable `( n \times n )`-matrix `M`.
322
+ I.e., there exists an invertible diagonal matrix `D` such that `DM` is
323
+ skew-symmetric. `M` can be encoded as a *quiver* by having a directed
324
+ edge from vertex `i` to vertex `j` with label `(a,b)` if `a = M_{i,j}
325
+ > 0` and `b = M_{j,i} < 0`. We consider quivers up to *mutation
326
+ equivalence*.
327
+
328
+ To a quiver mutation type we can associate a *generalized Cartan type*
329
+ by sending `M` to the generalized Cartan matrix `C(M)` obtained by
330
+ replacing all positive entries by their negatives and adding `2`'s on
331
+ the main diagonal.
332
+
333
+ :class:`QuiverMutationType` constructs a quiver mutation type object. For
334
+ more detail on the possible different types, please see the
335
+ compendium.
336
+
337
+ INPUT:
338
+
339
+ The input consists either of a quiver mutation type, or of a
340
+ ``letter`` (a string), a ``rank`` (one integer or a list/tuple of
341
+ integers), and an optional ``twist`` (an integer or a list of
342
+ integers). There are several different naming conventions for quiver
343
+ mutation types.
344
+
345
+ - Finite type -- ``letter`` is a Dynkin type (A-G), and ``rank`` is
346
+ the rank.
347
+
348
+ - Affine type -- there is more than one convention for naming affine
349
+ types.
350
+
351
+ * Kac's notation: ``letter`` is a Dynkin type, ``rank`` is the
352
+ rank of the associated finite Dynkin diagram, and ``twist`` is the
353
+ twist, which could be 1, 2, or 3. In the special case of affine
354
+ type A, there is more than one quiver mutation type associated to
355
+ the Cartan type. In this case only, ``rank`` is a pair of integers
356
+ (i,j), giving the number of edges pointing clockwise and the number
357
+ of edges pointing counter-clockwise. The total number of vertices
358
+ is given by i+j in this case.
359
+
360
+ * Naive notation: ``letter`` is one of 'BB', 'BC', 'BD', 'CC',
361
+ 'CD'. The name specifies the two ends of the diagram, which are
362
+ joined by a path. The total number of vertices is given by
363
+ ``rank +1`` (to match the indexing people expect because these
364
+ are affine types). In general, ``rank`` must be large enough
365
+ for the picture to make sense, but we accept ``letter`` is
366
+ ``BC`` and ``rank=1``.
367
+
368
+ * Macdonald notation: for the dual of an untwisted affine type
369
+ (such as ['C', 6, 1]), we accept a twist of -1 (i.e.,
370
+ ['C',6,-1]).
371
+
372
+ - Elliptic type -- ``letter`` is a Dynkin type, ``rank`` is the rank
373
+ of the finite Dynkin diagram, and ``twist`` is a tuple of two
374
+ integers. We follow Saito's notation.
375
+
376
+ - Other shapes:
377
+
378
+ * Rank 2: ``letter`` is 'R2', and ``rank`` is a pair of integers
379
+ specifying the label on the unique edge.
380
+
381
+ * Triangle: ``letter`` is ``TR``, and ``rank`` is the number of
382
+ vertices along a side.
383
+
384
+ * T: This defines a quiver shaped like a T. ``letter`` is 'T',
385
+ and the ``rank`` is a triple, whose entries specify the number
386
+ of vertices along each path from the branch point (counting the
387
+ branch point).
388
+
389
+ * Grassmannian: This defines the cluster algebra (without
390
+ coefficients) corresponding to the cluster algebra with
391
+ coefficients which is the coordinate ring of a Grassmannian.
392
+ ``letter`` is 'GR'. ``rank`` is a pair of integers (`k`, `n`)
393
+ with 'k' < 'n' specifying the Grassmannian of `k`-planes in
394
+ `n`-space. This defines a quiver given by a (k-1) x (n-k-1)
395
+ grid where each square is cyclically oriented.
396
+
397
+ * Exceptional mutation finite quivers: The two exceptional
398
+ mutation finite quivers, found by Derksen-Owen, have ``letter``
399
+ as 'X' and ``rank`` 6 or 7, equal to the number of vertices.
400
+
401
+ * AE, BE, CE, DE: Quivers are built of one end which looks like
402
+ type (affine A), B, C, or D, and the other end which looks like
403
+ type E (i.e., it consists of two antennae, one of length one,
404
+ and one of length two). ``letter`` is 'AE', 'BE', 'CE', or
405
+ 'DE', and ``rank`` is the total number of vertices. Note that
406
+ 'AE' is of a slightly different form and requires ``rank`` to be
407
+ a pair of integers (i,j) just as in the case of affine type A.
408
+ See Exercise 4.3 in Kac's book Infinite Dimensional Lie Algebras
409
+ for more details.
410
+
411
+ * Infinite type E: It is also possible to obtain infinite-type E
412
+ quivers by specifying ``letter`` as 'E' and ``rank`` as the
413
+ number of vertices.
414
+
415
+ REFERENCES:
416
+
417
+ - A good reference for finite and affine Dynkin diagrams, including
418
+ Kac's notation, is the :wikipedia:`Dynkin_diagram`.
419
+
420
+ - A good reference for the skew-symmetrizable elliptic diagrams is
421
+ "Cluster algebras of finite mutation type via unfolding" by
422
+ A. Felikson, M. Shapiro, and P. Tumarkin, [FST2012]_.
423
+
424
+ EXAMPLES:
425
+
426
+ Finite types::
427
+
428
+ sage: QuiverMutationType('A', 1)
429
+ ['A', 1]
430
+ sage: QuiverMutationType('A',5)
431
+ ['A', 5]
432
+
433
+ sage: QuiverMutationType('B', 2)
434
+ ['B', 2]
435
+ sage: QuiverMutationType('B',5)
436
+ ['B', 5]
437
+
438
+ sage: QuiverMutationType('C', 2)
439
+ ['B', 2]
440
+ sage: QuiverMutationType('C',5)
441
+ ['C', 5]
442
+
443
+ sage: QuiverMutationType('D', 2)
444
+ [ ['A', 1], ['A', 1] ]
445
+ sage: QuiverMutationType('D',3)
446
+ ['A', 3]
447
+ sage: QuiverMutationType('D',4)
448
+ ['D', 4]
449
+
450
+ sage: QuiverMutationType('E',6)
451
+ ['E', 6]
452
+
453
+ sage: QuiverMutationType('G', 2)
454
+ ['G', 2]
455
+
456
+ sage: QuiverMutationType('A',(1,0), 1)
457
+ ['A', 1]
458
+
459
+ sage: QuiverMutationType('A',(2,0), 1)
460
+ [ ['A', 1], ['A', 1] ]
461
+
462
+ sage: QuiverMutationType('A',(7,0), 1)
463
+ ['D', 7]
464
+
465
+ Affine types::
466
+
467
+ sage: QuiverMutationType('A',(1, 1), 1)
468
+ ['A', [1, 1], 1]
469
+ sage: QuiverMutationType('A',(2,4), 1)
470
+ ['A', [2, 4], 1]
471
+
472
+ sage: QuiverMutationType('BB', 2, 1)
473
+ ['BB', 2, 1]
474
+ sage: QuiverMutationType('BB',4, 1)
475
+ ['BB', 4, 1]
476
+
477
+ sage: QuiverMutationType('CC', 2, 1)
478
+ ['CC', 2, 1]
479
+ sage: QuiverMutationType('CC',4, 1)
480
+ ['CC', 4, 1]
481
+
482
+ sage: QuiverMutationType('BC', 1, 1)
483
+ ['BC', 1, 1]
484
+ sage: QuiverMutationType('BC',5, 1)
485
+ ['BC', 5, 1]
486
+
487
+ sage: QuiverMutationType('BD',3, 1)
488
+ ['BD', 3, 1]
489
+ sage: QuiverMutationType('BD',5, 1)
490
+ ['BD', 5, 1]
491
+
492
+ sage: QuiverMutationType('CD',3, 1)
493
+ ['CD', 3, 1]
494
+ sage: QuiverMutationType('CD',5, 1)
495
+ ['CD', 5, 1]
496
+
497
+ sage: QuiverMutationType('D',4, 1)
498
+ ['D', 4, 1]
499
+ sage: QuiverMutationType('D',6, 1)
500
+ ['D', 6, 1]
501
+
502
+ sage: QuiverMutationType('E',6, 1)
503
+ ['E', 6, 1]
504
+ sage: QuiverMutationType('E',7, 1)
505
+ ['E', 7, 1]
506
+ sage: QuiverMutationType('E',8, 1)
507
+ ['E', 8, 1]
508
+
509
+ sage: QuiverMutationType('F',4, 1)
510
+ ['F', 4, 1]
511
+ sage: QuiverMutationType('F',4,-1)
512
+ ['F', 4, -1]
513
+
514
+ sage: QuiverMutationType('G', 2, 1)
515
+ ['G', 2, 1]
516
+ sage: QuiverMutationType('G', 2,-1)
517
+ ['G', 2, -1]
518
+ sage: QuiverMutationType('A',3, 2) == QuiverMutationType('D',3, 2)
519
+ True
520
+
521
+ Affine types using Kac's Notation::
522
+
523
+ sage: QuiverMutationType('A', 1, 1)
524
+ ['A', [1, 1], 1]
525
+ sage: QuiverMutationType('B',5, 1)
526
+ ['BD', 5, 1]
527
+ sage: QuiverMutationType('C',5, 1)
528
+ ['CC', 5, 1]
529
+ sage: QuiverMutationType('A', 2, 2)
530
+ ['BC', 1, 1]
531
+ sage: QuiverMutationType('A',7, 2)
532
+ ['CD', 4, 1]
533
+ sage: QuiverMutationType('A',8, 2)
534
+ ['BC', 4, 1]
535
+ sage: QuiverMutationType('D',6, 2)
536
+ ['BB', 5, 1]
537
+ sage: QuiverMutationType('E',6, 2)
538
+ ['F', 4, -1]
539
+ sage: QuiverMutationType('D',4,3)
540
+ ['G', 2, -1]
541
+
542
+ Elliptic types::
543
+
544
+ sage: QuiverMutationType('E',6,[1, 1])
545
+ ['E', 6, [1, 1]]
546
+ sage: QuiverMutationType('F',4,[2, 1])
547
+ ['F', 4, [1, 2]]
548
+ sage: QuiverMutationType('G', 2,[3,3])
549
+ ['G', 2, [3, 3]]
550
+
551
+ Mutation finite types:
552
+
553
+ Rank 2 cases::
554
+
555
+ sage: QuiverMutationType('R2',(1, 1))
556
+ ['A', 2]
557
+ sage: QuiverMutationType('R2',(1, 2))
558
+ ['B', 2]
559
+ sage: QuiverMutationType('R2',(1,3))
560
+ ['G', 2]
561
+ sage: QuiverMutationType('R2',(1,4))
562
+ ['BC', 1, 1]
563
+ sage: QuiverMutationType('R2',(1,5))
564
+ ['R2', [1, 5]]
565
+ sage: QuiverMutationType('R2',(2, 2))
566
+ ['A', [1, 1], 1]
567
+ sage: QuiverMutationType('R2',(3,5))
568
+ ['R2', [3, 5]]
569
+
570
+ Exceptional Derksen-Owen quivers::
571
+
572
+ sage: QuiverMutationType('X',6)
573
+ ['X', 6]
574
+
575
+
576
+ (Mainly) mutation infinite types:
577
+
578
+ Infinite type E::
579
+
580
+ sage: QuiverMutationType('E',9)
581
+ ['E', 8, 1]
582
+ sage: QuiverMutationType('E', 10)
583
+ ['E', 10]
584
+ sage: QuiverMutationType('E', 12)
585
+ ['E', 12]
586
+
587
+ sage: QuiverMutationType('AE',(2,3))
588
+ ['AE', [2, 3]]
589
+ sage: QuiverMutationType('BE',5)
590
+ ['BE', 5]
591
+ sage: QuiverMutationType('CE',5)
592
+ ['CE', 5]
593
+ sage: QuiverMutationType('DE',6)
594
+ ['DE', 6]
595
+
596
+ Grassmannian types::
597
+
598
+ sage: QuiverMutationType('GR',(2,4))
599
+ ['A', 1]
600
+ sage: QuiverMutationType('GR',(2,6))
601
+ ['A', 3]
602
+ sage: QuiverMutationType('GR',(3,6))
603
+ ['D', 4]
604
+ sage: QuiverMutationType('GR',(3,7))
605
+ ['E', 6]
606
+ sage: QuiverMutationType('GR',(3,8))
607
+ ['E', 8]
608
+ sage: QuiverMutationType('GR',(3, 10))
609
+ ['GR', [3, 10]]
610
+
611
+ Triangular types::
612
+
613
+ sage: QuiverMutationType('TR', 2)
614
+ ['A', 3]
615
+ sage: QuiverMutationType('TR',3)
616
+ ['D', 6]
617
+ sage: QuiverMutationType('TR',4)
618
+ ['E', 8, [1, 1]]
619
+ sage: QuiverMutationType('TR',5)
620
+ ['TR', 5]
621
+
622
+ T types::
623
+
624
+ sage: QuiverMutationType('T',(1, 1, 1))
625
+ ['A', 1]
626
+ sage: QuiverMutationType('T',(1, 1,4))
627
+ ['A', 4]
628
+ sage: QuiverMutationType('T',(1,4,4))
629
+ ['A', 7]
630
+ sage: QuiverMutationType('T',(2, 2, 2))
631
+ ['D', 4]
632
+ sage: QuiverMutationType('T',(2, 2,4))
633
+ ['D', 6]
634
+ sage: QuiverMutationType('T',(2,3,3))
635
+ ['E', 6]
636
+ sage: QuiverMutationType('T',(2,3,4))
637
+ ['E', 7]
638
+ sage: QuiverMutationType('T',(2,3,5))
639
+ ['E', 8]
640
+ sage: QuiverMutationType('T',(2,3,6))
641
+ ['E', 8, 1]
642
+ sage: QuiverMutationType('T',(2,3,7))
643
+ ['E', 10]
644
+ sage: QuiverMutationType('T',(3,3,3))
645
+ ['E', 6, 1]
646
+ sage: QuiverMutationType('T',(3,3,4))
647
+ ['T', [3, 3, 4]]
648
+
649
+ Reducible types::
650
+
651
+ sage: QuiverMutationType(['A',3],['B',4])
652
+ [ ['A', 3], ['B', 4] ]
653
+ """
654
+
655
+
656
+ class QuiverMutationType_abstract(UniqueRepresentation, SageObject):
657
+ """
658
+ EXAMPLES::
659
+
660
+ sage: mut_type1 = QuiverMutationType('A',5)
661
+ sage: mut_type2 = QuiverMutationType('A',5)
662
+ sage: mut_type3 = QuiverMutationType('A',6)
663
+ sage: mut_type1 == mut_type2
664
+ True
665
+ sage: mut_type1 == mut_type3
666
+ False
667
+ """
668
+
669
+ def _repr_(self):
670
+ """
671
+ Return the string representation of ``self``.
672
+
673
+ EXAMPLES::
674
+
675
+ sage: QuiverMutationType(['A', 2]) # indirect doctest
676
+ ['A', 2]
677
+ """
678
+ return self._description
679
+
680
+ def plot(self, circular=False, directed=True):
681
+ """
682
+ Return the plot of the underlying graph or digraph of ``self``.
683
+
684
+ INPUT:
685
+
686
+ - ``circular`` -- boolean (default: ``False``); if ``True``, the
687
+ circular plot is chosen, otherwise >>spring<< is used
688
+
689
+ - ``directed`` -- boolean (default: ``True``); if ``True``, the
690
+ directed version is shown, otherwise the undirected
691
+
692
+ EXAMPLES::
693
+
694
+ sage: QMT = QuiverMutationType(['A',5])
695
+ sage: pl = QMT.plot() # needs sage.plot sage.symbolic
696
+ sage: pl = QMT.plot(circular=True) # needs sage.plot sage.symbolic
697
+ """
698
+ return self.standard_quiver().plot(circular=circular, directed=directed)
699
+
700
+ def show(self, circular=False, directed=True):
701
+ """
702
+ Show the plot of the underlying digraph of ``self``.
703
+
704
+ INPUT:
705
+
706
+ - ``circular`` -- boolean (default: ``False``); if ``True``, the
707
+ circular plot is chosen, otherwise >>spring<< is used
708
+
709
+ - ``directed`` -- boolean (default: ``True``); if ``True``, the
710
+ directed version is shown, otherwise the undirected
711
+
712
+ TESTS::
713
+
714
+ sage: QMT = QuiverMutationType(['A', 5])
715
+ sage: QMT.show() # long time # needs sage.plot sage.symbolic
716
+ """
717
+ self.plot(circular=circular, directed=directed).show()
718
+
719
+ def letter(self):
720
+ """
721
+ Return the classification letter of ``self``.
722
+
723
+ EXAMPLES::
724
+
725
+ sage: mut_type = QuiverMutationType( ['A',5] ); mut_type
726
+ ['A', 5]
727
+ sage: mut_type.letter()
728
+ 'A'
729
+
730
+ sage: mut_type = QuiverMutationType( ['BC',5, 1] ); mut_type
731
+ ['BC', 5, 1]
732
+ sage: mut_type.letter()
733
+ 'BC'
734
+
735
+ sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
736
+ [ ['A', 3], ['B', 3] ]
737
+ sage: mut_type.letter()
738
+ 'A x B'
739
+
740
+ sage: mut_type = QuiverMutationType(['A',3],['B',3],['X',6]); mut_type
741
+ [ ['A', 3], ['B', 3], ['X', 6] ]
742
+ sage: mut_type.letter()
743
+ 'A x B x X'
744
+ """
745
+ return self._letter
746
+
747
+ def rank(self):
748
+ """
749
+ Return the rank in the standard quiver of ``self``.
750
+
751
+ The rank is the number of vertices.
752
+
753
+ EXAMPLES::
754
+
755
+ sage: mut_type = QuiverMutationType( ['A',5] ); mut_type
756
+ ['A', 5]
757
+ sage: mut_type.rank()
758
+ 5
759
+
760
+ sage: mut_type = QuiverMutationType( ['A',[4,5], 1] ); mut_type
761
+ ['A', [4, 5], 1]
762
+ sage: mut_type.rank()
763
+ 9
764
+
765
+ sage: mut_type = QuiverMutationType( ['BC',5, 1] ); mut_type
766
+ ['BC', 5, 1]
767
+ sage: mut_type.rank()
768
+ 6
769
+
770
+ sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
771
+ [ ['A', 3], ['B', 3] ]
772
+ sage: mut_type.rank()
773
+ 6
774
+
775
+ sage: mut_type = QuiverMutationType(['A',3],['B',3],['X',6]); mut_type
776
+ [ ['A', 3], ['B', 3], ['X', 6] ]
777
+ sage: mut_type.rank()
778
+ 12
779
+ """
780
+ return self._rank
781
+
782
+ @cached_method
783
+ def b_matrix(self):
784
+ """
785
+ Return the B-matrix of the standard quiver of ``self``.
786
+
787
+ The conventions for B-matrices agree with Fomin-Zelevinsky (up
788
+ to a reordering of the simple roots).
789
+
790
+ EXAMPLES::
791
+
792
+ sage: mut_type = QuiverMutationType(['A',5]); mut_type
793
+ ['A', 5]
794
+ sage: mut_type.b_matrix() # needs sage.modules
795
+ [ 0 1 0 0 0]
796
+ [-1 0 -1 0 0]
797
+ [ 0 1 0 1 0]
798
+ [ 0 0 -1 0 -1]
799
+ [ 0 0 0 1 0]
800
+
801
+ sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
802
+ [ ['A', 3], ['B', 3] ]
803
+ sage: mut_type.b_matrix() # needs sage.modules
804
+ [ 0 1 0 0 0 0]
805
+ [-1 0 -1 0 0 0]
806
+ [ 0 1 0 0 0 0]
807
+ [ 0 0 0 0 1 0]
808
+ [ 0 0 0 -1 0 -1]
809
+ [ 0 0 0 0 2 0]
810
+ """
811
+ return _edge_list_to_matrix(self._digraph.edges(sort=True), list(range(self._rank)), [])
812
+
813
+ @cached_method
814
+ def standard_quiver(self):
815
+ """
816
+ Return the standard quiver of ``self``.
817
+
818
+ EXAMPLES::
819
+
820
+ sage: mut_type = QuiverMutationType( ['A',5] ); mut_type
821
+ ['A', 5]
822
+ sage: mut_type.standard_quiver() # needs sage.modules
823
+ Quiver on 5 vertices of type ['A', 5]
824
+
825
+ sage: mut_type = QuiverMutationType( ['A',[5,3], 1] ); mut_type
826
+ ['A', [3, 5], 1]
827
+ sage: mut_type.standard_quiver() # needs sage.modules
828
+ Quiver on 8 vertices of type ['A', [3, 5], 1]
829
+
830
+ sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
831
+ [ ['A', 3], ['B', 3] ]
832
+ sage: mut_type.standard_quiver() # needs sage.modules
833
+ Quiver on 6 vertices of type [ ['A', 3], ['B', 3] ]
834
+
835
+ sage: mut_type = QuiverMutationType(['A',3],['B',3],['X',6]); mut_type
836
+ [ ['A', 3], ['B', 3], ['X', 6] ]
837
+ sage: mut_type.standard_quiver() # needs sage.modules
838
+ Quiver on 12 vertices of type [ ['A', 3], ['B', 3], ['X', 6] ]
839
+ """
840
+ from .quiver import ClusterQuiver
841
+ Q = ClusterQuiver(self._digraph)
842
+ Q._mutation_type = self
843
+ return Q
844
+
845
+ @cached_method
846
+ def cartan_matrix(self):
847
+ """
848
+ Return the Cartan matrix of ``self``.
849
+
850
+ Note that (up to a reordering of the simple roots) the convention for
851
+ the definition of Cartan matrix, used here and elsewhere in Sage,
852
+ agrees with the conventions of Kac, Fulton-Harris, and
853
+ Fomin-Zelevinsky, but disagrees with the convention of Bourbaki.
854
+ The `(i,j)` entry is `2(\\alpha_i,\\alpha_j)/(\\alpha_i,\\alpha_i)`.
855
+
856
+ EXAMPLES::
857
+
858
+ sage: mut_type = QuiverMutationType(['A',5]); mut_type
859
+ ['A', 5]
860
+ sage: mut_type.cartan_matrix() # needs sage.modules
861
+ [ 2 -1 0 0 0]
862
+ [-1 2 -1 0 0]
863
+ [ 0 -1 2 -1 0]
864
+ [ 0 0 -1 2 -1]
865
+ [ 0 0 0 -1 2]
866
+
867
+ sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
868
+ [ ['A', 3], ['B', 3] ]
869
+ sage: mut_type.cartan_matrix() # needs sage.modules
870
+ [ 2 -1 0 0 0 0]
871
+ [-1 2 -1 0 0 0]
872
+ [ 0 -1 2 0 0 0]
873
+ [ 0 0 0 2 -1 0]
874
+ [ 0 0 0 -1 2 -1]
875
+ [ 0 0 0 0 -2 2]
876
+ """
877
+ # as soon as CartanMatrix is implemented we should use it here:
878
+ # from sage.combinat.root_system.cartan_matrix import CartanMatrix
879
+ cmat = copy(self.b_matrix())
880
+ for i, j in cmat.nonzero_positions():
881
+ a = cmat[i, j]
882
+ if a > 0:
883
+ cmat[i, j] = -a
884
+ for i in range(self._rank):
885
+ cmat[i, i] = 2
886
+ # return CartanMatrix(cmat)
887
+ return cmat
888
+
889
+ def is_irreducible(self):
890
+ """
891
+ Return ``True`` if ``self`` is irreducible.
892
+
893
+ EXAMPLES::
894
+
895
+ sage: mt = QuiverMutationType(['A', 2])
896
+ sage: mt.is_irreducible()
897
+ True
898
+ """
899
+ return self._info['irreducible']
900
+
901
+ def is_mutation_finite(self):
902
+ """
903
+ Return ``True`` if ``self`` is of finite mutation type.
904
+
905
+ This means that its mutation class has only finitely many
906
+ different B-matrices.
907
+
908
+ EXAMPLES::
909
+
910
+ sage: mt = QuiverMutationType(['D',5, 1])
911
+ sage: mt.is_mutation_finite()
912
+ True
913
+ """
914
+ return self._info['mutation_finite']
915
+
916
+ def is_simply_laced(self):
917
+ """
918
+ Return ``True`` if ``self`` is simply laced.
919
+
920
+ This means that the only arrows that appear in the quiver of
921
+ ``self`` are single unlabelled arrows.
922
+
923
+ EXAMPLES::
924
+
925
+ sage: mt = QuiverMutationType(['A', 2])
926
+ sage: mt.is_simply_laced()
927
+ True
928
+
929
+ sage: mt = QuiverMutationType(['B', 2])
930
+ sage: mt.is_simply_laced()
931
+ False
932
+
933
+ sage: mt = QuiverMutationType(['A',(1, 1), 1])
934
+ sage: mt.is_simply_laced()
935
+ False
936
+ """
937
+ return self._info['simply_laced']
938
+
939
+ def is_skew_symmetric(self):
940
+ """
941
+ Return ``True`` if the B-matrix of ``self`` is skew-symmetric.
942
+
943
+ EXAMPLES::
944
+
945
+ sage: mt = QuiverMutationType(['A', 2])
946
+ sage: mt.is_skew_symmetric()
947
+ True
948
+
949
+ sage: mt = QuiverMutationType(['B', 2])
950
+ sage: mt.is_skew_symmetric()
951
+ False
952
+
953
+ sage: mt = QuiverMutationType(['A',(1, 1), 1])
954
+ sage: mt.is_skew_symmetric()
955
+ True
956
+ """
957
+ return self._info['skew_symmetric']
958
+
959
+ def is_finite(self):
960
+ """
961
+ Return ``True`` if ``self`` is of finite type.
962
+
963
+ This means that the cluster algebra associated to ``self`` has
964
+ only a finite number of cluster variables.
965
+
966
+ EXAMPLES::
967
+
968
+ sage: mt = QuiverMutationType(['A', 2])
969
+ sage: mt.is_finite()
970
+ True
971
+
972
+ sage: mt = QuiverMutationType(['A',[4, 2], 1])
973
+ sage: mt.is_finite()
974
+ False
975
+ """
976
+ return self._info['finite']
977
+
978
+ def is_affine(self):
979
+ """
980
+ Return ``True`` if ``self`` is of affine type.
981
+
982
+ EXAMPLES::
983
+
984
+ sage: mt = QuiverMutationType(['A', 2])
985
+ sage: mt.is_affine()
986
+ False
987
+
988
+ sage: mt = QuiverMutationType(['A',[4, 2], 1])
989
+ sage: mt.is_affine()
990
+ True
991
+ """
992
+ if self.is_irreducible():
993
+ return self._info['affine']
994
+ else:
995
+ return False
996
+
997
+ def is_elliptic(self):
998
+ """
999
+ Return ``True`` if ``self`` is of elliptic type.
1000
+
1001
+ EXAMPLES::
1002
+
1003
+ sage: mt = QuiverMutationType(['A', 2])
1004
+ sage: mt.is_elliptic()
1005
+ False
1006
+
1007
+ sage: mt = QuiverMutationType(['E',6,[1, 1]])
1008
+ sage: mt.is_elliptic()
1009
+ True
1010
+ """
1011
+ if self.is_irreducible():
1012
+ return self._info['elliptic']
1013
+ else:
1014
+ return False
1015
+
1016
+ def properties(self):
1017
+ """
1018
+ Print a scheme of all properties of ``self``.
1019
+
1020
+ Most properties have natural definitions for either irreducible or
1021
+ reducible types. ``affine`` and ``elliptic`` are only defined for
1022
+ irreducible types.
1023
+
1024
+ EXAMPLES::
1025
+
1026
+ sage: mut_type = QuiverMutationType(['A',3]); mut_type
1027
+ ['A', 3]
1028
+ sage: mut_type.properties()
1029
+ ['A', 3] has rank 3 and the following properties:
1030
+ - irreducible: True
1031
+ - mutation finite: True
1032
+ - simply-laced: True
1033
+ - skew-symmetric: True
1034
+ - finite: True
1035
+ - affine: False
1036
+ - elliptic: False
1037
+
1038
+ sage: mut_type = QuiverMutationType(['B',3]); mut_type
1039
+ ['B', 3]
1040
+ sage: mut_type.properties()
1041
+ ['B', 3] has rank 3 and the following properties:
1042
+ - irreducible: True
1043
+ - mutation finite: True
1044
+ - simply-laced: False
1045
+ - skew-symmetric: False
1046
+ - finite: True
1047
+ - affine: False
1048
+ - elliptic: False
1049
+
1050
+ sage: mut_type = QuiverMutationType(['B',3, 1]); mut_type
1051
+ ['BD', 3, 1]
1052
+ sage: mut_type.properties()
1053
+ ['BD', 3, 1] has rank 4 and the following properties:
1054
+ - irreducible: True
1055
+ - mutation finite: True
1056
+ - simply-laced: False
1057
+ - skew-symmetric: False
1058
+ - finite: False
1059
+ - affine: True
1060
+ - elliptic: False
1061
+
1062
+ sage: mut_type = QuiverMutationType(['E',6,[1, 1]]); mut_type
1063
+ ['E', 6, [1, 1]]
1064
+ sage: mut_type.properties()
1065
+ ['E', 6, [1, 1]] has rank 8 and the following properties:
1066
+ - irreducible: True
1067
+ - mutation finite: True
1068
+ - simply-laced: False
1069
+ - skew-symmetric: True
1070
+ - finite: False
1071
+ - affine: False
1072
+ - elliptic: True
1073
+
1074
+ sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
1075
+ [ ['A', 3], ['B', 3] ]
1076
+ sage: mut_type.properties()
1077
+ [ ['A', 3], ['B', 3] ] has rank 6 and the following properties:
1078
+ - irreducible: False
1079
+ - mutation finite: True
1080
+ - simply-laced: False
1081
+ - skew-symmetric: False
1082
+ - finite: True
1083
+
1084
+ sage: mut_type = QuiverMutationType('GR',[4,9]); mut_type
1085
+ ['GR', [4, 9]]
1086
+ sage: mut_type.properties()
1087
+ ['GR', [4, 9]] has rank 12 and the following properties:
1088
+ - irreducible: True
1089
+ - mutation finite: False
1090
+ - simply-laced: True
1091
+ - skew-symmetric: True
1092
+ - finite: False
1093
+ - affine: False
1094
+ - elliptic: False
1095
+ """
1096
+ txt = '{} has rank {} and the following properties:'
1097
+ print(txt.format(self, self.rank()))
1098
+ s = "\t- {} {}"
1099
+ print(s.format('irreducible: ', self.is_irreducible()))
1100
+ print(s.format('mutation finite: ', self.is_mutation_finite()))
1101
+ print(s.format('simply-laced: ', self.is_simply_laced()))
1102
+ print(s.format('skew-symmetric: ', self.is_skew_symmetric()))
1103
+ print(s.format('finite: ', self.is_finite()))
1104
+ if self.is_irreducible():
1105
+ print(s.format('affine: ', self.is_affine()))
1106
+ print(s.format('elliptic: ', self.is_elliptic()))
1107
+
1108
+
1109
+ class QuiverMutationType_Irreducible(QuiverMutationType_abstract):
1110
+ """
1111
+ The mutation type for a cluster algebra or a quiver. Should not be
1112
+ called directly, but through :class:`QuiverMutationType`.
1113
+ """
1114
+
1115
+ def __init__(self, letter, rank, twist=None):
1116
+ """
1117
+ Should not be called directly but through QuiverMutationType.
1118
+
1119
+ INPUT:
1120
+
1121
+ - ``letter`` -- the letter of the mutation type
1122
+ - ``rank`` -- the rank of the mutation type
1123
+ - ``twist`` -- the twist of the mutation type
1124
+
1125
+ EXAMPLES::
1126
+
1127
+ sage: QuiverMutationType('A',5)
1128
+ ['A', 5]
1129
+
1130
+ sage: QuiverMutationType('A',[4,5], 1)
1131
+ ['A', [4, 5], 1]
1132
+
1133
+ sage: QuiverMutationType('BB',5, 1)
1134
+ ['BB', 5, 1]
1135
+
1136
+ sage: QuiverMutationType('X',6)
1137
+ ['X', 6]
1138
+ """
1139
+ # _rank and _bi_rank are initialized
1140
+ self._rank = None
1141
+ self._bi_rank = None
1142
+
1143
+ # _graph and _digraph are initialized
1144
+ self._graph = Graph()
1145
+ self._digraph = DiGraph()
1146
+
1147
+ # _info is initialized
1148
+ self._info = {}
1149
+ self._info['irreducible'] = True
1150
+ self._info['mutation_finite'] = False
1151
+ self._info['simply_laced'] = False
1152
+ self._info['skew_symmetric'] = False
1153
+ self._info['finite'] = False
1154
+ self._info['affine'] = False
1155
+ self._info['elliptic'] = False
1156
+ self._info['irreducible_components'] = False
1157
+
1158
+ if isinstance(rank, tuple):
1159
+ rank = list(rank)
1160
+ if isinstance(twist, tuple):
1161
+ twist = list(twist)
1162
+
1163
+ # _letter/twist is the input letter/twist
1164
+ self._letter = letter
1165
+ self._twist = twist
1166
+
1167
+ data = [letter, rank, twist]
1168
+
1169
+ # type A (finite and affine)
1170
+ if letter == 'A':
1171
+ if twist is None and rank in ZZ and rank > 0:
1172
+ self._rank = rank
1173
+ self._info['mutation_finite'] = True
1174
+ self._info['simply_laced'] = True
1175
+ self._info['skew_symmetric'] = True
1176
+ self._info['finite'] = True
1177
+ elif twist == 1 and isinstance(rank, list) and len(rank) == 2 and all(ri in ZZ and ri >= 0 for ri in rank) and rank != [0, 0]:
1178
+ if isinstance(rank, tuple):
1179
+ rank = list(rank)
1180
+ data[1] = rank
1181
+ rank = sorted(rank)
1182
+ self._bi_rank = rank
1183
+ self._rank = sum(self._bi_rank)
1184
+ self._info['mutation_finite'] = True
1185
+ if self._rank > 2:
1186
+ self._info['simply_laced'] = True
1187
+ self._info['skew_symmetric'] = True
1188
+ if rank[0] > 0:
1189
+ self._info['affine'] = True
1190
+ elif rank[0] == 0:
1191
+ self._info['finite'] = True
1192
+ else:
1193
+ _mutation_type_error(data)
1194
+ # types ['A', 1] and ['A',[0, 1], 1] need to be treated on
1195
+ # itself (as there is no edge)
1196
+ if twist is None and self._rank == 1 or twist == 1 and self._rank == 1:
1197
+ self._graph.add_vertex(0)
1198
+ # type ['A',[1, 1], 1] needs to be treated on itself as well
1199
+ # (as there is a double edge)
1200
+ elif twist == 1 and self._bi_rank[0] == 1 and self._bi_rank[1] == 1:
1201
+ self._graph.add_edge(0, 1, 2)
1202
+ else:
1203
+ for i in range(self._rank - 1):
1204
+ self._graph.add_edge(i, i + 1, 1)
1205
+ if twist == 1:
1206
+ self._digraph.add_edge(self._rank - 1, 0, 1)
1207
+ for i in range(self._rank - 1):
1208
+ if i < (2 * self._bi_rank[0]) and i % 2 == 0:
1209
+ self._digraph.add_edge(i + 1, i, 1)
1210
+ else:
1211
+ self._digraph.add_edge(i, i + 1, 1)
1212
+
1213
+ # type B (finite)
1214
+ elif letter == 'B':
1215
+ if twist is None and rank in ZZ and rank > 1:
1216
+ self._rank = rank
1217
+ self._info['mutation_finite'] = True
1218
+ self._info['finite'] = True
1219
+ else:
1220
+ _mutation_type_error(data)
1221
+ for i in range(rank - 2):
1222
+ self._graph.add_edge(i, i+1, 1)
1223
+ if (rank % 2 == 0):
1224
+ self._graph.add_edge(rank-2, rank-1, (1, -2))
1225
+ else:
1226
+ self._graph.add_edge(rank-2, rank-1, (2, -1))
1227
+
1228
+ # type C (finite)
1229
+ elif letter == 'C':
1230
+ if twist is None and rank in ZZ and rank > 1:
1231
+ self._rank = rank
1232
+ self._info['mutation_finite'] = True
1233
+ self._info['finite'] = True
1234
+ else:
1235
+ _mutation_type_error(data)
1236
+ for i in range(rank - 2):
1237
+ self._graph.add_edge(i, i+1, 1)
1238
+ if (rank % 2 == 0):
1239
+ self._graph.add_edge(rank-2, rank-1, (2, -1))
1240
+ else:
1241
+ self._graph.add_edge(rank-2, rank-1, (1, -2))
1242
+
1243
+ # type BB (affine)
1244
+ elif letter == 'BB':
1245
+ if twist == 1 and rank in ZZ and rank > 1:
1246
+ self._rank = rank + 1
1247
+ self._info['mutation_finite'] = True
1248
+ self._info['affine'] = True
1249
+ else:
1250
+ _mutation_type_error(data)
1251
+ for i in range(rank - 2):
1252
+ self._graph.add_edge(i, i+1, 1)
1253
+ if rank % 2 == 0:
1254
+ self._graph.add_edge(rank-2, rank-1, (1, -2))
1255
+ else:
1256
+ self._graph.add_edge(rank-2, rank-1, (2, -1))
1257
+ self._graph.add_edge(rank, 0, (1, -2))
1258
+
1259
+ # type CC (affine)
1260
+ elif letter == 'CC':
1261
+ if twist == 1 and rank in ZZ and rank > 1:
1262
+ self._rank = rank + 1
1263
+ self._info['mutation_finite'] = True
1264
+ self._info['affine'] = True
1265
+ else:
1266
+ _mutation_type_error(data)
1267
+ for i in range(rank - 2):
1268
+ self._graph.add_edge(i, i+1, 1)
1269
+ if rank % 2 == 0:
1270
+ self._graph.add_edge(rank-2, rank-1, (2, -1))
1271
+ else:
1272
+ self._graph.add_edge(rank-2, rank-1, (1, -2))
1273
+ self._graph.add_edge(rank, 0, (2, -1))
1274
+
1275
+ # type BC (affine)
1276
+ elif letter == 'BC':
1277
+ if twist == 1 and rank in ZZ and rank >= 1:
1278
+ self._rank = rank + 1
1279
+ self._info['mutation_finite'] = True
1280
+ self._info['affine'] = True
1281
+ else:
1282
+ _mutation_type_error(data)
1283
+ if rank == 1:
1284
+ self._graph.add_edge(0, 1, (1, -4))
1285
+ else:
1286
+ for i in range(rank - 2):
1287
+ self._graph.add_edge(i, i+1, 1)
1288
+ if (rank % 2 == 0):
1289
+ self._graph.add_edge(rank-2, rank-1, (2, -1))
1290
+ else:
1291
+ self._graph.add_edge(rank-2, rank-1, (1, -2))
1292
+ if twist == 1:
1293
+ self._graph.add_edge(rank, 0, (1, -2))
1294
+
1295
+ # type BD (affine)
1296
+ elif letter == 'BD':
1297
+ if twist == 1 and rank in ZZ and rank > 2:
1298
+ self._rank = rank + 1
1299
+ self._info['mutation_finite'] = True
1300
+ self._info['affine'] = True
1301
+ else:
1302
+ _mutation_type_error(data)
1303
+ for i in range(rank - 2):
1304
+ self._graph.add_edge(i, i+1, 1)
1305
+ if (rank % 2 == 0):
1306
+ self._graph.add_edge(rank-2, rank-1, (1, -2))
1307
+ else:
1308
+ self._graph.add_edge(rank-2, rank-1, (2, -1))
1309
+ if twist == 1:
1310
+ self._graph.add_edge(rank, 1, 1)
1311
+
1312
+ # type CD (affine)
1313
+ elif letter == 'CD':
1314
+ if twist == 1 and rank in ZZ and rank > 2:
1315
+ self._rank = rank + 1
1316
+ self._info['mutation_finite'] = True
1317
+ self._info['affine'] = True
1318
+ else:
1319
+ _mutation_type_error(data)
1320
+ for i in range(rank - 2):
1321
+ self._graph.add_edge(i, i+1, 1)
1322
+ if (rank % 2 == 0):
1323
+ self._graph.add_edge(rank-2, rank-1, (2, -1))
1324
+ else:
1325
+ self._graph.add_edge(rank-2, rank-1, (1, -2))
1326
+ if twist == 1:
1327
+ self._graph.add_edge(rank, 1, 1)
1328
+
1329
+ # type D (finite and affine)
1330
+ elif letter == 'D':
1331
+ if rank in ZZ and rank > 3 and twist is None:
1332
+ self._rank = rank
1333
+ self._info['mutation_finite'] = True
1334
+ self._info['simply_laced'] = True
1335
+ self._info['skew_symmetric'] = True
1336
+ self._info['finite'] = True
1337
+ elif twist == 1 and rank in ZZ and rank > 3:
1338
+ self._rank = rank + 1
1339
+ self._info['mutation_finite'] = True
1340
+ self._info['simply_laced'] = True
1341
+ self._info['skew_symmetric'] = True
1342
+ self._info['affine'] = True
1343
+ else:
1344
+ _mutation_type_error(data)
1345
+ for i in range(rank - 2):
1346
+ self._graph.add_edge(i, i+1, 1)
1347
+
1348
+ self._graph.add_edge(rank-3, rank-1, 1)
1349
+ if twist is not None:
1350
+ self._graph.add_edge(rank, 1, 1)
1351
+
1352
+ # type E (finite, affine and elliptic)
1353
+ elif letter == 'E':
1354
+ if rank in [6, 7, 8] and twist is None:
1355
+ self._rank = rank
1356
+ self._info['mutation_finite'] = True
1357
+ self._info['simply_laced'] = True
1358
+ self._info['skew_symmetric'] = True
1359
+ self._info['finite'] = True
1360
+ if rank == 6:
1361
+ self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (2, 5)])
1362
+ elif rank == 7:
1363
+ self._graph.add_edges([(0, 1), (1, 2), (2, 3),
1364
+ (3, 4), (4, 5), (2, 6)])
1365
+ elif rank == 8:
1366
+ self._graph.add_edges([(0, 1), (1, 2), (2, 3),
1367
+ (3, 4), (4, 5), (5, 6), (2, 7)])
1368
+ elif rank in [6, 7, 8] and twist == 1:
1369
+ self._rank = rank + 1
1370
+ self._info['mutation_finite'] = True
1371
+ self._info['simply_laced'] = True
1372
+ self._info['skew_symmetric'] = True
1373
+ self._info['affine'] = True
1374
+ if rank == 6:
1375
+ self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (2, 5), (5, 6)])
1376
+ elif rank == 7:
1377
+ self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (3, 7)])
1378
+ elif rank == 8:
1379
+ self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (2, 8)])
1380
+ elif rank in [6, 7, 8] and twist == [1, 1]:
1381
+ self._rank = rank + 2
1382
+ self._info['mutation_finite'] = True
1383
+ self._info['skew_symmetric'] = True
1384
+ self._info['elliptic'] = True
1385
+ if rank == 6:
1386
+ self._digraph.add_edges([(0, 1, 1), (1, 2, 1), (3, 2, 1), (3, 4, 1), (5, 6, 1), (6, 7, 1), (5, 1, 1), (2, 5, 2), (5, 3, 1), (6, 2, 1)])
1387
+ elif rank == 7:
1388
+ self._digraph.add_edges([(1, 0, 1), (1, 2, 1), (2, 3, 1), (4, 3, 1), (4, 5, 1),
1389
+ (6, 5, 1), (7, 8, 1), (3, 7, 2), (7, 2, 1), (7, 4, 1), (8, 3, 1)])
1390
+ elif rank == 8:
1391
+ self._digraph.add_edges([(0, 1, 1), (1, 9, 1), (3, 9, 1), (3, 4, 1), (2, 8, 1), (2, 1, 1),
1392
+ (9, 2, 2), (2, 3, 1), (8, 9, 1), (5, 4, 1), (5, 6, 1), (7, 6, 1)])
1393
+ # type E (mutation infinite)
1394
+ elif rank > 9 and twist is None:
1395
+ self._info['simply_laced'] = True
1396
+ self._info['skew_symmetric'] = True
1397
+ self._rank = rank
1398
+ for i in range(rank-2):
1399
+ self._graph.add_edge(i, i+1, 1)
1400
+ self._graph.add_edge(2, rank-1)
1401
+ else:
1402
+ _mutation_type_error(data)
1403
+
1404
+ # type AE (mutation infinite)
1405
+ elif letter == 'AE':
1406
+ if isinstance(rank, list) and len(rank) == 2 and all(rank[i] in ZZ and rank[i] > 0 for i in [0, 1]) and twist is None:
1407
+ if isinstance(rank, tuple):
1408
+ rank = list(rank)
1409
+ data[1] = rank
1410
+ rank = sorted(rank)
1411
+ self._bi_rank = rank
1412
+ self._rank = sum(self._bi_rank) + 1
1413
+ if self._rank > 3:
1414
+ self._info['simply_laced'] = True
1415
+ self._info['skew_symmetric'] = True
1416
+ if self._bi_rank == [1, 1]:
1417
+ self._graph.add_edges([(0, 1, 2), (1, 2, None)])
1418
+ else:
1419
+ self._digraph.add_edge(self._rank - 2, 0)
1420
+ for i in range(self._rank-2):
1421
+ if i < (2 * self._bi_rank[0]) and i % 2 == 0:
1422
+ self._digraph.add_edge(i + 1, i)
1423
+ else:
1424
+ self._digraph.add_edge(i, i + 1)
1425
+ self._digraph.add_edge(self._rank-2, self._rank-1)
1426
+ else:
1427
+ _mutation_type_error(data)
1428
+
1429
+ # type BE (mutation infinite)
1430
+ elif letter == 'BE':
1431
+ if rank > 4 and twist is None:
1432
+ self._rank = rank
1433
+ for i in range(rank-3):
1434
+ self._graph.add_edge(i, i+1)
1435
+ self._graph.add_edge(2, rank-1)
1436
+ if rank % 2 == 0:
1437
+ self._graph.add_edge(rank-3, rank-2, (2, -1))
1438
+ else:
1439
+ self._graph.add_edge(rank-3, rank-2, (1, -2))
1440
+ else:
1441
+ _mutation_type_error(data)
1442
+
1443
+ # type CE (mutation infinite)
1444
+ elif letter == 'CE':
1445
+ if rank > 4 and twist is None:
1446
+ self._rank = rank
1447
+ for i in range(rank-3):
1448
+ self._graph.add_edge(i, i+1)
1449
+ self._graph.add_edge(2, rank-1)
1450
+ if rank % 2 == 0:
1451
+ self._graph.add_edge(rank-3, rank-2, (1, -2))
1452
+ else:
1453
+ self._graph.add_edge(rank-3, rank-2, (2, -1))
1454
+ else:
1455
+ _mutation_type_error(data)
1456
+
1457
+ # type DE (mutation infinite)
1458
+ elif letter == 'DE':
1459
+ if rank > 5 and twist is None:
1460
+ self._rank = rank
1461
+ self._info['simply_laced'] = True
1462
+ self._info['skew_symmetric'] = True
1463
+ for i in range(rank-3):
1464
+ self._graph.add_edge(i, i+1)
1465
+ self._graph.add_edge(2, rank-2)
1466
+ self._graph.add_edge(rank-4, rank-1)
1467
+ else:
1468
+ _mutation_type_error(data)
1469
+
1470
+ # type F (finite, affine, and elliptic)
1471
+ elif letter == 'F':
1472
+ if rank == 4 and twist is None:
1473
+ self._rank = rank
1474
+ self._info['mutation_finite'] = True
1475
+ self._info['finite'] = True
1476
+ self._graph.add_edges([(0, 1, None), (1, 2, (2, -1)), (2, 3, None)])
1477
+ elif rank == 4 and twist == 1:
1478
+ self._rank = rank + 1
1479
+ self._info['mutation_finite'] = True
1480
+ self._info['affine'] = True
1481
+ self._graph.add_edges([(0, 1, None), (1, 2, None),
1482
+ (2, 3, (1, -2)), (3, 4, None)])
1483
+ elif rank == 4 and twist == -1:
1484
+ self._rank = rank + 1
1485
+ self._info['mutation_finite'] = True
1486
+ self._info['affine'] = True
1487
+ self._graph.add_edges([(0, 1, None), (1, 2, None),
1488
+ (2, 3, (2, -1)), (3, 4, None)])
1489
+ elif rank == 4 and (twist == [1, 2]):
1490
+ self._rank = rank + 2
1491
+ self._info['mutation_finite'] = True
1492
+ self._info['elliptic'] = True
1493
+ self._digraph.add_edges([(0, 1, None), (1, 2, None),
1494
+ (2, 3, (2, -1)), (4, 2, (1, -2)),
1495
+ (3, 4, 2), (4, 5, None), (5, 3, None)])
1496
+ elif rank == 4 and (twist == [2, 1]):
1497
+ self._rank = rank + 2
1498
+ self._info['mutation_finite'] = True
1499
+ self._info['elliptic'] = True
1500
+ self._digraph.add_edges([(0, 1, None), (1, 2, None),
1501
+ (2, 3, (1, -2)), (4, 2, (2, -1)),
1502
+ (3, 4, 2), (4, 5, None), (5, 3, None)])
1503
+ elif rank == 4 and twist == [2, 2]:
1504
+ self._rank = rank + 2
1505
+ self._info['mutation_finite'] = True
1506
+ self._info['elliptic'] = True
1507
+ self._digraph.add_edges([(0, 1, None), (1, 2, None),
1508
+ (3, 1, None), (2, 3, 2),
1509
+ (4, 2, (2, -1)), (3, 4, (1, -2)),
1510
+ (5, 4, None)])
1511
+ elif rank == 4 and twist == [1, 1]:
1512
+ self._rank = rank + 2
1513
+ self._info['mutation_finite'] = True
1514
+ self._info['elliptic'] = True
1515
+ self._digraph.add_edges([(0, 1, None), (1, 2, None),
1516
+ (3, 1, None), (2, 3, 2), (4, 2, (1, -2)),
1517
+ (3, 4, (2, -1)), (5, 4, None)])
1518
+ else:
1519
+ _mutation_type_error(data)
1520
+
1521
+ # type G (finite, affine, and elliptic)
1522
+ elif letter == 'G':
1523
+ if rank == 2 and twist is None:
1524
+ self._rank = rank
1525
+ self._info['mutation_finite'] = True
1526
+ self._info['finite'] = True
1527
+ self._graph.add_edges([(0, 1, (1, -3))])
1528
+ elif rank == 2 and twist == -1:
1529
+ self._rank = rank + 1
1530
+ self._info['mutation_finite'] = True
1531
+ self._info['affine'] = True
1532
+ self._graph.add_edges([(0, 1, None), (1, 2, (1, -3))])
1533
+ elif rank == 2 and twist == 1:
1534
+ self._rank = rank + 1
1535
+ self._info['mutation_finite'] = True
1536
+ self._info['affine'] = True
1537
+ self._graph.add_edges([(0, 1, None), (1, 2, (3, -1))])
1538
+ elif rank == 2 and (twist == [1, 3]):
1539
+ self._rank = rank + 2
1540
+ self._info['mutation_finite'] = True
1541
+ self._info['elliptic'] = True
1542
+ self._digraph.add_edges([(0, 1, None), (1, 2, (3, -1)),
1543
+ (3, 1, (1, -3)), (2, 3, 2)])
1544
+ elif rank == 2 and (twist == [3, 1]):
1545
+ self._rank = rank + 2
1546
+ self._info['mutation_finite'] = True
1547
+ self._info['elliptic'] = True
1548
+ self._digraph.add_edges([(0, 1, None), (1, 2, (1, -3)),
1549
+ (3, 1, (3, -1)), (2, 3, 2)])
1550
+ elif rank == 2 and twist == [3, 3]:
1551
+ self._rank = rank + 2
1552
+ self._info['mutation_finite'] = True
1553
+ self._info['elliptic'] = True
1554
+ self._digraph.add_edges([(1, 0, None), (0, 2, 2), (3, 0, (3, -1)),
1555
+ (2, 1, None), (2, 3, (1, -3))])
1556
+ elif rank == 2 and twist == [1, 1]:
1557
+ self._rank = rank + 2
1558
+ self._info['mutation_finite'] = True
1559
+ self._info['elliptic'] = True
1560
+ self._digraph.add_edges([(1, 0, None), (0, 2, 2), (3, 0, (1, -3)),
1561
+ (2, 1, None), (2, 3, (3, -1))])
1562
+ else:
1563
+ _mutation_type_error(data)
1564
+
1565
+ # type GR (mutation infinite)
1566
+ elif letter == 'GR':
1567
+ if twist is None and isinstance(rank, list) and len(rank) == 2 and all(rank[i] in ZZ and rank[i] > 0 for i in [0, 1]) and rank[1] - 1 > rank[0] > 1:
1568
+ gr_rank = (rank[0]-1, rank[1]-rank[0]-1)
1569
+ self._rank = prod(gr_rank)
1570
+ self._info['simply_laced'] = True
1571
+ self._info['skew_symmetric'] = True
1572
+ a, b = gr_rank
1573
+ for i in range(a):
1574
+ for j in range(b):
1575
+ if i < a-1:
1576
+ if (i+j) % 2 == 0:
1577
+ self._digraph.add_edge(i*b+j, (i+1)*b+j)
1578
+ else:
1579
+ self._digraph.add_edge((i+1)*b+j, i*b+j)
1580
+ if j < b-1:
1581
+ if (i+j) % 2 == 0:
1582
+ self._digraph.add_edge(i*b+j+1, i*b+j)
1583
+ else:
1584
+ self._digraph.add_edge(i*b+j, i*b+j+1)
1585
+ else:
1586
+ _mutation_type_error(data)
1587
+
1588
+ # type R2 (rank 2 finite mutation types)
1589
+ elif letter == 'R2':
1590
+ if twist is None and isinstance(rank, list) and len(rank) == 2 and all(rank[i] in ZZ and rank[i] > 0 for i in [0, 1]):
1591
+ rank = sorted(rank)
1592
+ b, c = rank
1593
+ self._rank = 2
1594
+ if b == c:
1595
+ self._info['skew_symmetric'] = True
1596
+ self._graph.add_edge(0, 1, (b, -c))
1597
+ else:
1598
+ _mutation_type_error(data)
1599
+
1600
+ # type T
1601
+ elif letter == 'T':
1602
+ if twist is None and isinstance(rank, list) and len(rank) == 3 and all(rank[i] in ZZ and rank[i] > 0 for i in [0, 1, 2]):
1603
+ if isinstance(rank, tuple):
1604
+ rank = list(rank)
1605
+ data[1] = rank
1606
+ rank = sorted(rank)
1607
+ self._rank = sum(rank) - 2
1608
+ self._info['simply_laced'] = True
1609
+ self._info['skew_symmetric'] = True
1610
+ r, p, q = rank
1611
+ for i in range(q-1):
1612
+ if i == 0:
1613
+ self._graph.add_edge(0, 1)
1614
+ self._graph.add_edge(0, r)
1615
+ self._graph.add_edge(0, r+p-1)
1616
+ else:
1617
+ if i < r-1:
1618
+ self._graph.add_edge(i, i+1)
1619
+ if i < p-1:
1620
+ self._graph.add_edge(i+r-1, i+r)
1621
+ self._graph.add_edge(i+r+p-2, i+r+p-1)
1622
+ else:
1623
+ _mutation_type_error(data)
1624
+
1625
+ # type TR (mutation infinite if rank > 2)
1626
+ elif letter == 'TR':
1627
+ # type ['TR', 1] needs to be treated on itself (as there is no edge)
1628
+ if twist is None and rank == 1:
1629
+ self._graph.add_vertex(0)
1630
+ elif twist is None and rank > 1:
1631
+ self._rank = rank*(rank+1)//2
1632
+ self._info['simply_laced'] = True
1633
+ self._info['skew_symmetric'] = True
1634
+ level = 0
1635
+ while level < rank:
1636
+ nr = rank*level-sum(range(level))
1637
+ for i in range(nr, nr+rank-level-1):
1638
+ self._digraph.add_edge(i, i+1)
1639
+ self._digraph.add_edge(i+rank-level, i)
1640
+ self._digraph.add_edge(i+1, i+rank-level)
1641
+ level += 1
1642
+ else:
1643
+ _mutation_type_error(data)
1644
+
1645
+ # type X
1646
+ elif letter == 'X':
1647
+ if rank in [6, 7] and twist is None:
1648
+ self._rank = rank
1649
+ self._info['mutation_finite'] = True
1650
+ self._info['skew_symmetric'] = True
1651
+ self._digraph.add_edges([(0, 1, 2), (1, 2, None), (2, 0, None),
1652
+ (2, 3, None), (3, 4, 2), (4, 2, None),
1653
+ (2, 5, None)])
1654
+ if rank == 7:
1655
+ self._digraph.add_edges([(5, 6, 2), (6, 2, None)])
1656
+ else:
1657
+ _mutation_type_error(data)
1658
+
1659
+ # otherwise, an error is raised
1660
+ else:
1661
+ _mutation_type_error(data)
1662
+
1663
+ # in the bipartite case, the digraph is constructed from the graph
1664
+ if not self._digraph:
1665
+ if self._graph.is_bipartite():
1666
+ self._digraph = _bipartite_graph_to_digraph(self._graph)
1667
+ else:
1668
+ raise ValueError('The QuiverMutationType does not have '
1669
+ 'a Coxeter diagram.')
1670
+
1671
+ # in the other cases, the graph is constructed from the digraph
1672
+ if not self._graph:
1673
+ self._graph = self._digraph.to_undirected()
1674
+
1675
+ # _description is as for CartanType
1676
+ if twist:
1677
+ self._description = str([letter, rank, twist])
1678
+ else:
1679
+ self._description = str([letter, rank])
1680
+
1681
+ def irreducible_components(self):
1682
+ """
1683
+ Return a list of all irreducible components of ``self``.
1684
+
1685
+ EXAMPLES::
1686
+
1687
+ sage: mut_type = QuiverMutationType('A',3); mut_type
1688
+ ['A', 3]
1689
+ sage: mut_type.irreducible_components()
1690
+ (['A', 3],)
1691
+ """
1692
+ return (self,)
1693
+
1694
+ @cached_method
1695
+ def class_size(self):
1696
+ r"""
1697
+ If it is known, the size of the mutation class of all quivers
1698
+ which are mutation equivalent to the standard quiver of
1699
+ ``self`` (up to isomorphism) is returned.
1700
+
1701
+ Otherwise, :obj:`NotImplemented` is returned.
1702
+
1703
+ Formula for finite type A is taken from Torkildsen - Counting
1704
+ cluster-tilted algebras of type `A_n`.
1705
+ Formulas for affine type A and finite type D are taken from Bastian,
1706
+ Prellberg, Rubey, Stump - Counting the number of elements in the
1707
+ mutation classes of `\widetilde A_n` quivers.
1708
+ Formulas for finite and affine types B and C are
1709
+ proven but not yet published.
1710
+ Conjectural formulas for several other non-simply-laced affine types
1711
+ are implemented.
1712
+ Exceptional Types (finite, affine, and elliptic) E, F, G, and X are
1713
+ hardcoded.
1714
+
1715
+ EXAMPLES::
1716
+
1717
+ sage: mut_type = QuiverMutationType( ['A',5] ); mut_type
1718
+ ['A', 5]
1719
+ sage: mut_type.class_size()
1720
+ 19
1721
+
1722
+ sage: mut_type = QuiverMutationType( ['A',[10,3], 1] ); mut_type
1723
+ ['A', [3, 10], 1]
1724
+ sage: mut_type.class_size()
1725
+ 142120
1726
+
1727
+ sage: mut_type = QuiverMutationType( ['B',6] ); mut_type
1728
+ ['B', 6]
1729
+ sage: mut_type.class_size()
1730
+ 132
1731
+
1732
+ sage: mut_type = QuiverMutationType( ['BD',6, 1] ); mut_type
1733
+ ['BD', 6, 1]
1734
+ sage: mut_type.class_size()
1735
+ Warning: This method uses a formula which has not been proved correct.
1736
+ 504
1737
+
1738
+ Check that :issue:`14048` is fixed::
1739
+
1740
+ sage: mut_type = QuiverMutationType( ['F',4,(2, 1)] )
1741
+ sage: mut_type.class_size()
1742
+ 90
1743
+ """
1744
+ if not self.is_mutation_finite():
1745
+ return infinity
1746
+
1747
+ # type A (finite and affine)
1748
+ if self._letter == 'A':
1749
+ # the formula is taken from Torkildsen - Counting
1750
+ # cluster-tilted algebras of type A
1751
+ if self.is_finite():
1752
+ n = self._rank
1753
+ a = binomial(2*(n+1), n+1) // (n+2)
1754
+ if n % 2 == 1:
1755
+ a += binomial(n+1, (n+1)//2)
1756
+ if n % 3 == 0:
1757
+ a += 2 * binomial(2*n//3, n//3)
1758
+ return a // (n+3)
1759
+ # the formula is taken from Bastian, Prellberg, Rubey, Stump
1760
+ elif self.is_affine():
1761
+ i, j = self._bi_rank
1762
+ i = ZZ(i)
1763
+ j = ZZ(j)
1764
+ n = i+j
1765
+ f = euler_phi
1766
+ if i == j:
1767
+ return (binomial(2 * i, i) +
1768
+ sum(f(k) * binomial(2 * i // k, i // k)**2
1769
+ for k in i.divisors()
1770
+ if k in j.divisors()) // n) // 4
1771
+ else:
1772
+ return sum(f(k) * binomial(2 * i // k, i // k) *
1773
+ binomial(2 * j // k, j // k)
1774
+ for k in i.divisors()
1775
+ if k in j.divisors()) // (2 * n)
1776
+
1777
+ # types B and C (finite and affine)
1778
+ elif self._letter in ['B', 'C']:
1779
+ # this formula is proven but nowhere published correctness
1780
+ # is clear enough that I don't think a warning is needed
1781
+ if self.is_finite():
1782
+ n = self._rank
1783
+ return binomial(2 * n, n) // (n + 1)
1784
+
1785
+ elif self._letter in ['BB', 'CC']:
1786
+ # these two formulas are not yet proven
1787
+ print("Warning: This method uses a formula "
1788
+ "which has not been proved correct.")
1789
+ if self.is_affine():
1790
+ if self._twist == 1:
1791
+ n = self._rank - 1
1792
+ N = binomial(2 * n - 1, n - 1)
1793
+ if n % 2:
1794
+ return N
1795
+ else:
1796
+ return N + binomial(n - 1, n // 2 - 1)
1797
+
1798
+ # type BC (affine)
1799
+ elif self._letter == 'BC':
1800
+ # this formula is not yet proven
1801
+ print("Warning: This method uses a formula "
1802
+ "which has not been proved correct.")
1803
+ if self.is_affine():
1804
+ if self._twist == 1:
1805
+ n = self._rank - 1
1806
+ return binomial(2 * n, n)
1807
+
1808
+ # types BD and CD (affine)
1809
+ elif self._letter in ['BD', 'CD']:
1810
+ # this formula is not yet proven
1811
+ print("Warning: This method uses a formula "
1812
+ "which has not been proved correct.")
1813
+ if self.is_affine():
1814
+ if self._twist == 1:
1815
+ n = self._rank - 2
1816
+ return 2 * binomial(2 * n, n)
1817
+
1818
+ # type D (finite and affine)
1819
+ elif self._letter == 'D':
1820
+ # the formula is taken from Bastian, Prellberg, Rubey, Stump
1821
+ if self.is_finite():
1822
+ if self._rank == 4:
1823
+ return 6
1824
+ else:
1825
+ f = euler_phi
1826
+ n = ZZ(self._rank)
1827
+ return sum(f(n // k) * binomial(2 * k, k)
1828
+ for k in n.divisors()) // (2 * n)
1829
+ # this formula is not yet proven
1830
+ elif self.is_affine():
1831
+ n = self._rank - 3
1832
+ if n == 2:
1833
+ return 9
1834
+ else:
1835
+ print("Warning: This method uses a formula "
1836
+ "which has not been proved correct.")
1837
+ if n % 2:
1838
+ return 2 * binomial(2 * n, n)
1839
+ else:
1840
+ return 2 * binomial(2 * n, n) + binomial(n, n // 2)
1841
+
1842
+ # the exceptional types are hard-coded
1843
+ # type E (finite, affine and elliptic)
1844
+ elif self._letter == 'E':
1845
+ if self.is_finite():
1846
+ if self._rank == 6:
1847
+ return 67
1848
+ elif self._rank == 7:
1849
+ return 416
1850
+ elif self._rank == 8:
1851
+ return 1574
1852
+ elif self.is_affine():
1853
+ if self._rank == 7:
1854
+ return 132
1855
+ elif self._rank == 8:
1856
+ return 1080
1857
+ elif self._rank == 9:
1858
+ return 7560
1859
+ elif self.is_elliptic():
1860
+ if self._rank == 8:
1861
+ return 49
1862
+ elif self._rank == 9:
1863
+ return 506
1864
+ elif self._rank == 10:
1865
+ return 5739
1866
+
1867
+ # type F
1868
+ elif self._letter == 'F':
1869
+ if self.is_finite():
1870
+ return 15
1871
+ elif self.is_affine():
1872
+ return 60
1873
+ elif self.is_elliptic():
1874
+ if self._twist == [1, 2]:
1875
+ return 90
1876
+ if self._twist == [1, 1] or self._twist == [2, 2]:
1877
+ return 35
1878
+
1879
+ # type G
1880
+ elif self._letter == 'G':
1881
+ if self.is_finite():
1882
+ return 2
1883
+ elif self.is_affine():
1884
+ return 6
1885
+ elif self.is_elliptic():
1886
+ if self._twist == [1, 3]:
1887
+ return 7
1888
+ if self._twist == [1, 1] or self._twist == [3, 3]:
1889
+ return 2
1890
+
1891
+ # type X
1892
+ elif self._letter == 'X':
1893
+ if self._rank == 6:
1894
+ return 5
1895
+ elif self._rank == 7:
1896
+ return 2
1897
+
1898
+ # otherwise the size is returned to be unknown
1899
+ else:
1900
+ print("Size unknown")
1901
+ return NotImplemented
1902
+
1903
+ def dual(self):
1904
+ """
1905
+ Return the :class:`QuiverMutationType` which is dual to ``self``.
1906
+
1907
+ EXAMPLES::
1908
+
1909
+ sage: mut_type = QuiverMutationType('A',5); mut_type
1910
+ ['A', 5]
1911
+ sage: mut_type.dual()
1912
+ ['A', 5]
1913
+
1914
+ sage: mut_type = QuiverMutationType('B',5); mut_type
1915
+ ['B', 5]
1916
+ sage: mut_type.dual()
1917
+ ['C', 5]
1918
+ sage: mut_type.dual().dual()
1919
+ ['B', 5]
1920
+ sage: mut_type.dual().dual() == mut_type
1921
+ True
1922
+ """
1923
+ letter = self.letter()
1924
+ # the self-dual cases
1925
+ if letter != 'BC' and letter[0] in ['B', 'C']:
1926
+ if letter == 'BB':
1927
+ letter = 'CC'
1928
+ elif letter == 'CC':
1929
+ letter = 'BB'
1930
+ elif letter[0] == 'B':
1931
+ letter = 'C' + letter[1:]
1932
+ elif letter[0] == 'C':
1933
+ letter = 'B' + letter[1:]
1934
+ rank = self._rank
1935
+ if self.is_affine():
1936
+ rank -= 1
1937
+ twist = self._twist
1938
+ return QuiverMutationType(letter, rank, twist)
1939
+ # the cases F and G have non-trivial duality in some cases
1940
+ elif letter in ['F', 'G']:
1941
+ if self.is_finite():
1942
+ return self
1943
+ elif self.is_affine():
1944
+ rank = self._rank - 1
1945
+ twist = - self._twist
1946
+ elif self.is_elliptic():
1947
+ twist = self._twist
1948
+ rank = self._rank - 2
1949
+ if letter == 'F':
1950
+ if self._twist == [2, 2]:
1951
+ twist == [1, 1]
1952
+ if self._twist == [1, 1]:
1953
+ twist == [2, 2]
1954
+ if letter == 'G':
1955
+ if self._twist == [3, 3]:
1956
+ twist = [1, 1]
1957
+ elif self._twist == [1, 1]:
1958
+ twist = [3, 3]
1959
+ else:
1960
+ rank = self._rank
1961
+ return QuiverMutationType(letter, rank, twist)
1962
+ else:
1963
+ return self
1964
+
1965
+
1966
+ class QuiverMutationType_Reducible(QuiverMutationType_abstract):
1967
+ """
1968
+ The mutation type for a cluster algebra or a quiver. Should not be
1969
+ called directly, but through :class:`QuiverMutationType`. Inherits from
1970
+ :class:`QuiverMutationType_abstract`.
1971
+ """
1972
+
1973
+ def __init__(self, *args):
1974
+ """
1975
+ Should not be called directly, but through QuiverMutationType.
1976
+
1977
+ INPUT:
1978
+
1979
+ - ``data`` -- list; each of whose entries is a
1980
+ :class:`QuiverMutationType_Irreducible`
1981
+
1982
+ EXAMPLES::
1983
+
1984
+ sage: QuiverMutationType(['A',4],['B',6])
1985
+ [ ['A', 4], ['B', 6] ]
1986
+ """
1987
+ data = args
1988
+ if len(data) < 2 or not all(isinstance(comp, QuiverMutationType_Irreducible) for comp in data):
1989
+ _mutation_type_error(data)
1990
+
1991
+ # _info is initialized
1992
+ self._info = {}
1993
+ self._info['irreducible'] = False
1994
+ self._info['mutation_finite'] = all(comp.is_mutation_finite()
1995
+ for comp in data)
1996
+ self._info['simply_laced'] = all(comp.is_simply_laced()
1997
+ for comp in data)
1998
+ self._info['skew_symmetric'] = all(comp.is_skew_symmetric()
1999
+ for comp in data)
2000
+ self._info['finite'] = all(comp.is_finite() for comp in data)
2001
+ self._info['irreducible_components'] = copy(data)
2002
+
2003
+ # letter and rank are initialized
2004
+ self._letter = ''
2005
+ self._rank = 0
2006
+
2007
+ # graph and digraph are initialized
2008
+ self._graph = Graph()
2009
+ self._digraph = DiGraph()
2010
+
2011
+ for comp in data:
2012
+ if self._letter:
2013
+ self._letter += ' x '
2014
+ self._letter += comp._letter
2015
+ self._rank += comp._rank
2016
+ self._graph = self._graph.disjoint_union(comp._graph,
2017
+ labels='integers')
2018
+ self._digraph = self._digraph.disjoint_union(comp._digraph,
2019
+ labels='integers')
2020
+ self._graph.name('')
2021
+ self._digraph.name('')
2022
+
2023
+ # _description is as for CartanType
2024
+ self._description = "[ "
2025
+ comps = self.irreducible_components()
2026
+ for i in range(len(comps)):
2027
+ if i > 0:
2028
+ self._description += ", "
2029
+ self._description += comps[i]._description
2030
+ self._description += " ]"
2031
+
2032
+ def irreducible_components(self):
2033
+ """
2034
+ Return a list of all irreducible components of ``self``.
2035
+
2036
+ EXAMPLES::
2037
+
2038
+ sage: mut_type = QuiverMutationType('A',3); mut_type
2039
+ ['A', 3]
2040
+ sage: mut_type.irreducible_components()
2041
+ (['A', 3],)
2042
+
2043
+ sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
2044
+ [ ['A', 3], ['B', 3] ]
2045
+ sage: mut_type.irreducible_components()
2046
+ (['A', 3], ['B', 3])
2047
+
2048
+ sage: mut_type = QuiverMutationType(['A',3],['B',3],['X',6])
2049
+ sage: mut_type
2050
+ [ ['A', 3], ['B', 3], ['X', 6] ]
2051
+ sage: mut_type.irreducible_components()
2052
+ (['A', 3], ['B', 3], ['X', 6])
2053
+ """
2054
+ return self._info['irreducible_components']
2055
+
2056
+ @cached_method
2057
+ def class_size(self):
2058
+ """
2059
+ If it is known, the size of the mutation class of all quivers
2060
+ which are mutation equivalent to the standard quiver of
2061
+ ``self`` (up to isomorphism) is returned.
2062
+
2063
+ Otherwise, :obj:`NotImplemented` is returned.
2064
+
2065
+ EXAMPLES::
2066
+
2067
+ sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
2068
+ [ ['A', 3], ['B', 3] ]
2069
+ sage: mut_type.class_size()
2070
+ 20
2071
+
2072
+ sage: mut_type = QuiverMutationType(['A',3],['B',3],['X',6])
2073
+ sage: mut_type
2074
+ [ ['A', 3], ['B', 3], ['X', 6] ]
2075
+ sage: mut_type.class_size()
2076
+ 100
2077
+ """
2078
+ if not self.is_mutation_finite():
2079
+ return infinity
2080
+
2081
+ components = []
2082
+ multiplicities = []
2083
+ for x in self.irreducible_components():
2084
+ if not components.count(x):
2085
+ components.append(x)
2086
+ multiplicities.append(1)
2087
+ else:
2088
+ y = components.index(x)
2089
+ multiplicities[y] += 1
2090
+
2091
+ sizes = [x.class_size() for x in components]
2092
+ if NotImplemented in sizes:
2093
+ print("Size unknown")
2094
+ return NotImplemented
2095
+ else:
2096
+ return prod(binomial(sizes[i] + multiplicities[i] - 1,
2097
+ multiplicities[i])
2098
+ for i in range(len(sizes)))
2099
+
2100
+ def dual(self):
2101
+ """
2102
+ Return the :class:`QuiverMutationType` which is dual to ``self``.
2103
+
2104
+ EXAMPLES::
2105
+
2106
+ sage: mut_type = QuiverMutationType(['A',5],['B',6],['C',5],['D',4]); mut_type
2107
+ [ ['A', 5], ['B', 6], ['C', 5], ['D', 4] ]
2108
+ sage: mut_type.dual()
2109
+ [ ['A', 5], ['C', 6], ['B', 5], ['D', 4] ]
2110
+ """
2111
+ comps = self.irreducible_components()
2112
+ return QuiverMutationType([comp.dual() for comp in comps])
2113
+
2114
+
2115
+ def _construct_classical_mutation_classes(n) -> dict[tuple, list | set]:
2116
+ r"""
2117
+ Return a dict with keys being tuples representing regular
2118
+ QuiverMutationTypes of the given rank, and with values being lists
2119
+ or sets containing all mutation equivalent quivers as dig6 data.
2120
+
2121
+ EXAMPLES::
2122
+
2123
+ sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _construct_classical_mutation_classes
2124
+ sage: rank_2_classes = _construct_classical_mutation_classes(2) # long time
2125
+ sage: for mut_class in sorted(rank_2_classes.keys(),key=str): # long time
2126
+ ....: print("{} {}".format(mut_class, rank_2_classes[mut_class]))
2127
+ ('A', (1, 1), 1) [('AO', (((0, 1), (2, -2)),))]
2128
+ ('A', 2) [('AO', ())]
2129
+ ('B', 2) [('AO', (((0, 1), (1, -2)),)), ('AO', (((0, 1), (2, -1)),))]
2130
+ ('BC', 1, 1) [('AO', (((0, 1), (1, -4)),)),
2131
+ ('AO', (((0, 1), (4, -1)),))]
2132
+ """
2133
+ from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver
2134
+ data: dict[tuple, set | list] = {}
2135
+
2136
+ # finite A
2137
+ data[('A', n)] = ClusterQuiver(['A', n]).mutation_class(data_type='dig6')
2138
+ # affine A
2139
+ for j in range(1, n//2+1):
2140
+ data[('A', (n-j, j), 1)] = ClusterQuiver(['A', [n-j, j], 1]).mutation_class(data_type='dig6')
2141
+ # finite B
2142
+ if n > 1:
2143
+ data[('B', n)] = ClusterQuiver(['B', n]).mutation_class(data_type='dig6')
2144
+ # affine B
2145
+ if n > 2:
2146
+ data[('BB', n-1, 1)] = ClusterQuiver(['BB', n-1, 1]).mutation_class(data_type='dig6')
2147
+ # finite C
2148
+ if n > 2:
2149
+ data[('C', n)] = ClusterQuiver(['C', n]).mutation_class(data_type='dig6')
2150
+ # affine C
2151
+ if n > 1:
2152
+ data[('BC', n-1, 1)] = ClusterQuiver(['BC', n-1, 1]).mutation_class(data_type='dig6')
2153
+ # affine CC
2154
+ if n > 2:
2155
+ data[('CC', n-1, 1)] = ClusterQuiver(['CC', n-1, 1]).mutation_class(data_type='dig6')
2156
+ # affine BD
2157
+ if n > 3:
2158
+ data[('BD', n-1, 1)] = ClusterQuiver(['BD', n-1, 1]).mutation_class(data_type='dig6')
2159
+ # affine CD
2160
+ if n > 3:
2161
+ data[('CD', n-1, 1)] = ClusterQuiver(['CD', n-1, 1]).mutation_class(data_type='dig6')
2162
+ # finite D
2163
+ if n > 3:
2164
+ data[('D', n)] = ClusterQuiver(['D', n]).mutation_class(data_type='dig6')
2165
+ # affine D
2166
+ if n > 4:
2167
+ data[('D', n-1, 1)] = ClusterQuiver(['D', n-1, 1]).mutation_class(data_type='dig6')
2168
+
2169
+ return data
2170
+
2171
+
2172
+ def _construct_exceptional_mutation_classes(n) -> dict[tuple, list | set]:
2173
+ r"""
2174
+ Return a dict with keys being tuples representing exceptional
2175
+ QuiverMutationTypes of the given rank, and with values being lists
2176
+ or sets containing all mutation equivalent quivers as dig6 data.
2177
+
2178
+ EXAMPLES::
2179
+
2180
+ sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _construct_exceptional_mutation_classes
2181
+ sage: rank_3_exceptional = _construct_exceptional_mutation_classes(3) # long time
2182
+ sage: for mut_class in sorted(rank_3_exceptional.keys(), key=str): # long time
2183
+ ....: print("{} {}".format(mut_class, rank_3_exceptional[mut_class]))
2184
+ ('G', 2, -1) [('BH?', (((1, 2), (1, -3)),)),
2185
+ ('BGO', (((2, 1), (3, -1)),)), ('BW?', (((0, 1), (3, -1)),)),
2186
+ ('BP?', (((0, 1), (1, -3)),)),
2187
+ ('BP_', (((0, 1), (1, -3)), ((2, 0), (3, -1)))),
2188
+ ('BP_', (((0, 1), (3, -1)), ((1, 2), (1, -3)), ((2, 0), (2, -2))))]
2189
+ ('G', 2, 1) [('BH?', (((1, 2), (3, -1)),)),
2190
+ ('BGO', (((2, 1), (1, -3)),)), ('BW?', (((0, 1), (1, -3)),)),
2191
+ ('BP?', (((0, 1), (3, -1)),)),
2192
+ ('BKO', (((1, 0), (3, -1)), ((2, 1), (1, -3)))),
2193
+ ('BP_', (((0, 1), (2, -2)), ((1, 2), (1, -3)), ((2, 0), (3, -1))))]
2194
+ """
2195
+ from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver
2196
+ data: dict[tuple, list | set] = {}
2197
+ # finite E
2198
+ if n in [6, 7, 8]:
2199
+ data[('E', n)] = ClusterQuiver(['E', n]).mutation_class(data_type='dig6')
2200
+ # affine E
2201
+ if n in [7, 8, 9]:
2202
+ data[('E', n - 1, 1)] = ClusterQuiver(['E', n - 1, 1]).mutation_class(data_type='dig6')
2203
+ # elliptic E
2204
+ if n in [8, 9, 10]:
2205
+ data[('E', n - 2, (1, 1))] = ClusterQuiver(['E', n - 2, [1, 1]]).mutation_class(data_type='dig6')
2206
+ # finite F
2207
+ if n == 4:
2208
+ data[('F', 4)] = ClusterQuiver(['F', 4]).mutation_class(data_type='dig6')
2209
+ # affine F
2210
+ if n == 5:
2211
+ data[('F', 4, 1)] = ClusterQuiver(['F', 4, 1]).mutation_class(data_type='dig6')
2212
+ data[('F', 4, -1)] = ClusterQuiver(['F', 4, -1]).mutation_class(data_type='dig6')
2213
+ # finite G
2214
+ if n == 2:
2215
+ data[('G', 2)] = ClusterQuiver(['G', 2]).mutation_class(data_type='dig6')
2216
+ # affine G
2217
+ if n == 3:
2218
+ data[('G', 2, 1)] = ClusterQuiver(['G', 2, 1]).mutation_class(data_type='dig6')
2219
+ data[('G', 2, -1)] = ClusterQuiver(['G', 2, -1]).mutation_class(data_type='dig6')
2220
+ # elliptic G
2221
+ if n == 4:
2222
+ data[('G', 2, (1, 3))] = ClusterQuiver(['G', 2, (1, 3)]).mutation_class(data_type='dig6')
2223
+ data[('G', 2, (1, 1))] = ClusterQuiver(['G', 2, (1, 1)]).mutation_class(data_type='dig6')
2224
+ data[('G', 2, (3, 3))] = ClusterQuiver(['G', 2, (3, 3)]).mutation_class(data_type='dig6')
2225
+ # X
2226
+ if n in [6, 7]:
2227
+ data[('X', n)] = ClusterQuiver(['X', n]).mutation_class(data_type='dig6')
2228
+ # elliptic F
2229
+ if n == 6:
2230
+ data[('F', 4, (1, 2))] = ClusterQuiver(['F', 4, (1, 2)]).mutation_class(data_type='dig6')
2231
+ data[('F', 4, (1, 1))] = ClusterQuiver(['F', 4, (1, 1)]).mutation_class(data_type='dig6')
2232
+ data[('F', 4, (2, 2))] = ClusterQuiver(['F', 4, (2, 2)]).mutation_class(data_type='dig6')
2233
+
2234
+ return data
2235
+
2236
+
2237
+ def _save_data_dig6(n, types='ClassicalExceptional', verbose=False):
2238
+ """
2239
+ Save all exceptional mutation classes as dig6 data into the file ``exc_classes_n.dig6`` in the folder ``DOT_SAGE``.
2240
+
2241
+ TESTS::
2242
+
2243
+ sage: # needs sage.modules
2244
+ sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import save_quiver_data
2245
+ sage: save_quiver_data(2) # indirect doctest
2246
+ <BLANKLINE>
2247
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2248
+ [('A', 1)]
2249
+ <BLANKLINE>
2250
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2251
+ [('A', (1, 1), 1), ('A', 2), ('B', 2), ('BC', 1, 1), ('G', 2)]
2252
+ sage: save_quiver_data(2, up_to=False) # indirect doctest
2253
+ <BLANKLINE>
2254
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2255
+ [('A', (1, 1), 1), ('A', 2), ('B', 2), ('BC', 1, 1), ('G', 2)]
2256
+ sage: save_quiver_data(2, up_to=False, types='Classical') # indirect doctest
2257
+ <BLANKLINE>
2258
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2259
+ [('A', (1, 1), 1), ('A', 2), ('B', 2), ('BC', 1, 1)]
2260
+ sage: save_quiver_data(2, up_to=False, types='Exceptional') # indirect doctest
2261
+ <BLANKLINE>
2262
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2263
+ [('G', 2)]
2264
+ sage: save_quiver_data(2, up_to=False, verbose=False) # indirect doctest
2265
+ """
2266
+ data = {}
2267
+ possible_types = ['Classical', 'ClassicalExceptional', 'Exceptional']
2268
+ if types not in possible_types:
2269
+ raise ValueError('The third input must be either ClassicalExceptional'
2270
+ ' (default), Classical, or Exceptional.')
2271
+
2272
+ if types in possible_types[:2]:
2273
+ data.update(_construct_classical_mutation_classes(n))
2274
+ if types in possible_types[1:]:
2275
+ data.update(_construct_exceptional_mutation_classes(n))
2276
+
2277
+ from sage.env import DOT_SAGE
2278
+ types_path = Path(DOT_SAGE) / 'cluster_algebra_quiver'
2279
+ types_path.mkdir(exist_ok=True)
2280
+ types_file = types_path / f'mutation_classes_{n}.dig6'
2281
+ from sage.misc.temporary_file import atomic_write
2282
+ with atomic_write(types_file, binary=True) as f:
2283
+ pickle.dump(data, f)
2284
+ if verbose:
2285
+ keys = sorted(data, key=str)
2286
+ print("\nThe following types are saved to file", types_file, "and will now be used to determine quiver mutation types:")
2287
+ print(keys)
2288
+
2289
+
2290
+ def save_quiver_data(n, up_to=True, types='ClassicalExceptional', verbose=True):
2291
+ r"""
2292
+ Save mutation classes of certain quivers of ranks up to and equal
2293
+ to `n` or equal to `n` to
2294
+ ``DOT_SAGE/cluster_algebra_quiver/mutation_classes_n.dig6``.
2295
+
2296
+ This data will then be used to determine quiver mutation types.
2297
+
2298
+ INPUT:
2299
+
2300
+ - ``n`` -- the rank (or the upper limit on the rank) of the mutation
2301
+ classes that are being saved
2302
+
2303
+ - ``up_to`` -- (default: ``True``) if ``True``, saves data for
2304
+ ranks smaller than or equal to `n`; if ``False``, saves data
2305
+ for rank exactly `n`
2306
+
2307
+ - ``types`` -- (default: ``'ClassicalExceptional'``) if all, saves data
2308
+ for both exceptional mutation-finite quivers and for classical
2309
+ quiver; the input 'Exceptional' or 'Classical' is also allowed
2310
+ to save only part of this data
2311
+
2312
+ TESTS::
2313
+
2314
+ sage: # needs sage.modules
2315
+ sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import save_quiver_data
2316
+ sage: save_quiver_data(2)
2317
+ <BLANKLINE>
2318
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2319
+ [('A', 1)]
2320
+ <BLANKLINE>
2321
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2322
+ [('A', (1, 1), 1), ('A', 2), ('B', 2), ('BC', 1, 1), ('G', 2)]
2323
+ sage: save_quiver_data(2,up_to=False)
2324
+ <BLANKLINE>
2325
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2326
+ [('A', (1, 1), 1), ('A', 2), ('B', 2), ('BC', 1, 1), ('G', 2)]
2327
+ sage: save_quiver_data(2,up_to=False, types='Classical')
2328
+ <BLANKLINE>
2329
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2330
+ [('A', (1, 1), 1), ('A', 2), ('B', 2), ('BC', 1, 1)]
2331
+ sage: save_quiver_data(2,up_to=False, types='Exceptional')
2332
+ <BLANKLINE>
2333
+ The following types are saved to file ... and will now be used to determine quiver mutation types:
2334
+ [('G', 2)]
2335
+ sage: save_quiver_data(2,up_to=False, verbose=False)
2336
+ """
2337
+ from sage.combinat.cluster_algebra_quiver.mutation_type import load_data
2338
+ if up_to is True:
2339
+ ranks = range(1, n + 1)
2340
+ elif up_to is False:
2341
+ ranks = [n]
2342
+ for i in ranks:
2343
+ _save_data_dig6(i, types=types, verbose=verbose)
2344
+ # we finally clear the load_data
2345
+ load_data.clear_cache()
2346
+
2347
+
2348
+ def _bipartite_graph_to_digraph(g) -> DiGraph:
2349
+ """
2350
+ Return a digraph obtained from a bipartite graph ``g`` by choosing one
2351
+ set of the bipartition to be the set of sinks and the other to be the
2352
+ set of sources.
2353
+
2354
+ EXAMPLES::
2355
+
2356
+ sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _bipartite_graph_to_digraph
2357
+ sage: G = Graph([(1, 2)])
2358
+ sage: _bipartite_graph_to_digraph(G)
2359
+ Digraph on 2 vertices
2360
+ """
2361
+ sources = g.bipartite_sets()[0]
2362
+ dg = DiGraph()
2363
+ dg.add_vertices(g)
2364
+ for a, b, c in g.edge_iterator():
2365
+ if a in sources:
2366
+ dg.add_edge(a, b, c)
2367
+ else:
2368
+ dg.add_edge(b, a, c)
2369
+ return dg
2370
+
2371
+
2372
+ def _is_mutation_type(data) -> bool:
2373
+ """
2374
+ Return ``True`` if ``data`` is a QuiverMutationType.
2375
+
2376
+ EXAMPLES::
2377
+
2378
+ sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _is_mutation_type
2379
+ sage: _is_mutation_type ( [ 'A', 2 ] )
2380
+ True
2381
+ sage: _is_mutation_type ( [ 'P', 1 ] )
2382
+ False
2383
+ """
2384
+ try:
2385
+ QuiverMutationType(data)
2386
+ return True
2387
+ except Exception:
2388
+ return False
2389
+
2390
+
2391
+ def _mutation_type_error(data):
2392
+ r"""
2393
+ Output an error message because data which is not a valid quiver mutation
2394
+ type has been passed to QuiverMutationType.
2395
+
2396
+ EXAMPLES::
2397
+
2398
+ sage: QuiverMutationType( 'Christian', 'Stump' ) # indirect doctest
2399
+ Traceback (most recent call last):
2400
+ ...
2401
+ ValueError: ['Christian', 'Stump'] is not a valid quiver mutation type
2402
+ Finite types have the form [ '?', n ] for type ? and rank n
2403
+ Affine type A has the form [ 'A', [ i, j ], 1 ] for rank i+j
2404
+ Affine type ? has the form [ '?', k, \pm 1 ] for rank k+1
2405
+ Elliptic type ? has the form [ '?', k, [i, j] ] (1 <= i,j <= 3) for rank k+2
2406
+ For correct syntax in other types, please consult the documentation.
2407
+ """
2408
+ if data[2] is None:
2409
+ del data[2]
2410
+ return_str = str(data) + ' is not a valid quiver mutation type'
2411
+ return_str += '\n Finite types have the form [ \'?\', n ] for type ? and rank n'
2412
+ return_str += '\n Affine type A has the form [ \'A\', [ i, j ], 1 ] for rank i+j'
2413
+ return_str += '\n Affine type ? has the form [ \'?\', k, \\pm 1 ] for rank k+1'
2414
+ return_str += '\n Elliptic type ? has the form [ \'?\', k, [i, j] ] (1 <= i,j <= 3) for rank k+2'
2415
+ return_str += '\n For correct syntax in other types, please consult the documentation.'
2416
+
2417
+ raise ValueError(return_str)
2418
+
2419
+
2420
+ def _edge_list_to_matrix(edges, nlist, mlist) -> matrix:
2421
+ r"""
2422
+ Return the matrix obtained from the edge list of a quiver.
2423
+
2424
+ INPUT:
2425
+
2426
+ - ``edges`` -- the list of edges
2427
+ - ``nlist`` -- the list of mutable vertices of the quiver
2428
+ - ``mlist`` -- the list of frozen vertices of the quiver
2429
+
2430
+ OUTPUT:
2431
+
2432
+ An `(n+m) \times n` matrix corresponding to the edge-list.
2433
+
2434
+ EXAMPLES::
2435
+
2436
+ sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _edge_list_to_matrix
2437
+ sage: G = QuiverMutationType(['A', 2])._digraph
2438
+ sage: _edge_list_to_matrix(G.edges(sort=True), [0, 1], []) # needs sage.modules
2439
+ [ 0 1]
2440
+ [-1 0]
2441
+
2442
+ sage: G2 = DiGraph([('a', 'b', 1)])
2443
+ sage: _edge_list_to_matrix(G2.edges(sort=True), ['a', 'b'], []) # needs sage.modules
2444
+ [ 0 1]
2445
+ [-1 0]
2446
+
2447
+ sage: G3 = DiGraph([('a', 'b', 1), ('b', 'c', 1)])
2448
+ sage: _edge_list_to_matrix(G3.edges(sort=True), ['a', 'b'], ['c']) # needs sage.modules
2449
+ [ 0 1]
2450
+ [-1 0]
2451
+ [ 0 -1]
2452
+ """
2453
+ n = len(nlist)
2454
+ nmlist = nlist + mlist
2455
+ nm = len(nmlist)
2456
+ M = matrix(ZZ, nm, n, sparse=True)
2457
+ for v1, v2, label in edges:
2458
+ if label is None:
2459
+ a, b = 1, -1
2460
+ elif label in ZZ:
2461
+ a, b = label, -label
2462
+ else:
2463
+ a, b = label
2464
+ if v1 in nlist:
2465
+ M[nmlist.index(v2), nmlist.index(v1)] = b
2466
+ if v2 in nlist:
2467
+ M[nmlist.index(v1), nmlist.index(v2)] = a
2468
+ return M