passagemath-graphs 10.5.43__cp312-cp312-macosx_14_0_arm64.whl → 10.6.1rc2__cp312-cp312-macosx_14_0_arm64.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 (132) hide show
  1. {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/METADATA +5 -6
  2. {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/RECORD +132 -130
  3. sage/combinat/abstract_tree.py +188 -17
  4. sage/combinat/cluster_algebra_quiver/interact.py +1 -2
  5. sage/combinat/cluster_algebra_quiver/mutation_type.py +518 -519
  6. sage/combinat/cluster_algebra_quiver/quiver.py +233 -205
  7. sage/combinat/designs/covering_design.py +2 -6
  8. sage/combinat/designs/database.py +11 -10
  9. sage/combinat/designs/designs_pyx.cpython-312-darwin.so +0 -0
  10. sage/combinat/designs/designs_pyx.pyx +2 -2
  11. sage/combinat/designs/evenly_distributed_sets.cpython-312-darwin.so +0 -0
  12. sage/combinat/designs/evenly_distributed_sets.pyx +4 -4
  13. sage/combinat/designs/gen_quadrangles_with_spread.cpython-312-darwin.so +0 -0
  14. sage/combinat/designs/latin_squares.py +53 -20
  15. sage/combinat/designs/orthogonal_arrays.py +2 -1
  16. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-312-darwin.so +0 -0
  17. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +22 -21
  18. sage/combinat/designs/resolvable_bibd.py +191 -157
  19. sage/combinat/designs/subhypergraph_search.cpython-312-darwin.so +0 -0
  20. sage/combinat/designs/subhypergraph_search.pyx +4 -4
  21. sage/combinat/designs/twographs.py +2 -2
  22. sage/combinat/finite_state_machine.py +6 -6
  23. sage/combinat/posets/bubble_shuffle.py +247 -0
  24. sage/combinat/posets/d_complete.py +3 -3
  25. sage/combinat/posets/elements.py +3 -3
  26. sage/combinat/posets/hasse_cython.cpython-312-darwin.so +0 -0
  27. sage/combinat/posets/hasse_cython.pyx +1 -1
  28. sage/combinat/posets/hasse_diagram.py +16 -22
  29. sage/combinat/posets/hochschild_lattice.py +158 -0
  30. sage/combinat/posets/incidence_algebras.py +14 -16
  31. sage/combinat/posets/lattices.py +51 -53
  32. sage/combinat/posets/linear_extension_iterator.cpython-312-darwin.so +0 -0
  33. sage/combinat/posets/linear_extensions.py +10 -12
  34. sage/combinat/posets/moebius_algebra.py +4 -4
  35. sage/combinat/posets/poset_examples.py +70 -23
  36. sage/combinat/posets/posets.py +294 -103
  37. sage/databases/knotinfo_db.py +2 -1
  38. sage/graphs/asteroidal_triples.cpython-312-darwin.so +0 -0
  39. sage/graphs/asteroidal_triples.pyx +24 -3
  40. sage/graphs/base/boost_graph.cpython-312-darwin.so +0 -0
  41. sage/graphs/base/boost_graph.pxd +3 -3
  42. sage/graphs/base/c_graph.cpython-312-darwin.so +0 -0
  43. sage/graphs/base/c_graph.pyx +1 -1
  44. sage/graphs/base/dense_graph.cpython-312-darwin.so +0 -0
  45. sage/graphs/base/dense_graph.pxd +5 -3
  46. sage/graphs/base/dense_graph.pyx +44 -0
  47. sage/graphs/base/graph_backends.cpython-312-darwin.so +0 -0
  48. sage/graphs/base/sparse_graph.cpython-312-darwin.so +0 -0
  49. sage/graphs/base/static_dense_graph.cpython-312-darwin.so +0 -0
  50. sage/graphs/base/static_sparse_backend.cpython-312-darwin.so +0 -0
  51. sage/graphs/base/static_sparse_backend.pyx +8 -5
  52. sage/graphs/base/static_sparse_graph.cpython-312-darwin.so +0 -0
  53. sage/graphs/base/static_sparse_graph.pyx +86 -15
  54. sage/graphs/bipartite_graph.py +59 -36
  55. sage/graphs/centrality.cpython-312-darwin.so +0 -0
  56. sage/graphs/centrality.pyx +82 -9
  57. sage/graphs/cographs.py +1 -1
  58. sage/graphs/comparability.cpython-312-darwin.so +0 -0
  59. sage/graphs/comparability.pyx +64 -26
  60. sage/graphs/connectivity.cpython-312-darwin.so +0 -0
  61. sage/graphs/convexity_properties.cpython-312-darwin.so +0 -0
  62. sage/graphs/convexity_properties.pyx +52 -9
  63. sage/graphs/digraph.py +439 -95
  64. sage/graphs/digraph_generators.py +174 -102
  65. sage/graphs/distances_all_pairs.cpython-312-darwin.so +0 -0
  66. sage/graphs/dot2tex_utils.py +1 -1
  67. sage/graphs/edge_connectivity.cpython-312-darwin.so +0 -0
  68. sage/graphs/generators/basic.py +1 -1
  69. sage/graphs/generators/distance_regular.cpython-312-darwin.so +0 -0
  70. sage/graphs/generators/distance_regular.pyx +1 -1
  71. sage/graphs/generators/families.py +37 -27
  72. sage/graphs/generators/random.py +2 -2
  73. sage/graphs/generators/smallgraphs.py +3 -3
  74. sage/graphs/generic_graph.py +558 -86
  75. sage/graphs/generic_graph_pyx.cpython-312-darwin.so +0 -0
  76. sage/graphs/generic_graph_pyx.pyx +58 -11
  77. sage/graphs/genus.cpython-312-darwin.so +0 -0
  78. sage/graphs/genus.pyx +3 -4
  79. sage/graphs/graph.py +291 -8
  80. sage/graphs/graph_coloring.cpython-312-darwin.so +0 -0
  81. sage/graphs/graph_database.py +67 -12
  82. sage/graphs/graph_decompositions/bandwidth.cpython-312-darwin.so +0 -0
  83. sage/graphs/graph_decompositions/clique_separators.cpython-312-darwin.so +0 -0
  84. sage/graphs/graph_decompositions/clique_separators.pyx +24 -3
  85. sage/graphs/graph_decompositions/cutwidth.cpython-312-darwin.so +0 -0
  86. sage/graphs/graph_decompositions/fast_digraph.cpython-312-darwin.so +0 -0
  87. sage/graphs/graph_decompositions/fast_digraph.pyx +1 -1
  88. sage/graphs/graph_decompositions/graph_products.cpython-312-darwin.so +0 -0
  89. sage/graphs/graph_decompositions/graph_products.pyx +67 -21
  90. sage/graphs/graph_decompositions/modular_decomposition.cpython-312-darwin.so +0 -0
  91. sage/graphs/graph_decompositions/slice_decomposition.cpython-312-darwin.so +0 -0
  92. sage/graphs/graph_decompositions/slice_decomposition.pyx +34 -8
  93. sage/graphs/graph_decompositions/tree_decomposition.cpython-312-darwin.so +0 -0
  94. sage/graphs/graph_decompositions/vertex_separation.cpython-312-darwin.so +0 -0
  95. sage/graphs/graph_generators.py +45 -32
  96. sage/graphs/graph_generators_pyx.cpython-312-darwin.so +0 -0
  97. sage/graphs/graph_generators_pyx.pyx +15 -15
  98. sage/graphs/graph_latex.py +1 -1
  99. sage/graphs/graph_list.py +52 -9
  100. sage/graphs/graph_plot.py +7 -0
  101. sage/graphs/hyperbolicity.cpython-312-darwin.so +0 -0
  102. sage/graphs/hyperbolicity.pyx +2 -0
  103. sage/graphs/independent_sets.cpython-312-darwin.so +0 -0
  104. sage/graphs/isoperimetric_inequalities.cpython-312-darwin.so +0 -0
  105. sage/graphs/isoperimetric_inequalities.pyx +42 -6
  106. sage/graphs/line_graph.cpython-312-darwin.so +0 -0
  107. sage/graphs/line_graph.pyx +153 -37
  108. sage/graphs/matching_covered_graph.py +84 -60
  109. sage/graphs/orientations.py +3 -18
  110. sage/graphs/path_enumeration.cpython-312-darwin.so +0 -0
  111. sage/graphs/path_enumeration.pyx +2 -2
  112. sage/graphs/spanning_tree.cpython-312-darwin.so +0 -0
  113. sage/graphs/strongly_regular_db.cpython-312-darwin.so +0 -0
  114. sage/graphs/strongly_regular_db.pyx +15 -15
  115. sage/graphs/traversals.cpython-312-darwin.so +0 -0
  116. sage/graphs/traversals.pyx +13 -12
  117. sage/graphs/trees.cpython-312-darwin.so +0 -0
  118. sage/graphs/tutte_polynomial.py +1 -1
  119. sage/graphs/views.cpython-312-darwin.so +0 -0
  120. sage/graphs/weakly_chordal.cpython-312-darwin.so +0 -0
  121. sage/graphs/weakly_chordal.pyx +50 -8
  122. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-312-darwin.so +0 -0
  123. sage/knots/free_knotinfo_monoid.py +3 -3
  124. sage/knots/knotinfo.py +102 -82
  125. sage/knots/link.py +72 -39
  126. sage/topology/cubical_complex.py +4 -5
  127. sage/topology/delta_complex.py +4 -4
  128. sage/topology/simplicial_complex.py +0 -1
  129. sage/topology/simplicial_complex_catalog.py +6 -0
  130. sage/topology/simplicial_complex_examples.py +4 -16
  131. {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/WHEEL +0 -0
  132. {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/top_level.txt +0 -0
@@ -21,11 +21,11 @@ AUTHORS:
21
21
  # Distributed under the terms of the GNU General Public License (GPL)
22
22
  # https://www.gnu.org/licenses/
23
23
  # ****************************************************************************
24
-
24
+ from copy import copy
25
25
  from pathlib import Path
26
26
  import pickle
27
+ from typing import Any, Iterator
27
28
 
28
- from copy import copy
29
29
 
30
30
  from sage.misc.cachefunc import cached_function
31
31
  from sage.misc.flatten import flatten
@@ -34,7 +34,7 @@ from sage.combinat.combination import Combinations
34
34
  from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType
35
35
 
36
36
 
37
- def is_mutation_finite(M, nr_of_checks=None):
37
+ def is_mutation_finite(M, nr_of_checks=None) -> tuple[bool, Any]:
38
38
  r"""
39
39
  Use a non-deterministic method by random mutations in various
40
40
  directions. Can result in a wrong answer.
@@ -50,20 +50,20 @@ def is_mutation_finite(M, nr_of_checks=None):
50
50
 
51
51
  ALGORITHM:
52
52
 
53
- A quiver is mutation infinite if and only if every edge label (a,-b) satisfy a*b > 4.
53
+ A quiver is mutation infinite if and only if every edge label (a, -b) satisfy a*b > 4.
54
54
  Thus, we apply random mutations in random directions
55
55
 
56
56
  EXAMPLES::
57
57
 
58
58
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import is_mutation_finite
59
59
 
60
- sage: Q = ClusterQuiver(['A',10]) # needs sage.modules
60
+ sage: Q = ClusterQuiver(['A', 10]) # needs sage.modules
61
61
  sage: M = Q.b_matrix() # needs sage.modules
62
62
  sage: is_mutation_finite(M) # needs sage.modules
63
63
  (True, None)
64
64
 
65
65
  sage: # needs sage.modules
66
- sage: Q = ClusterQuiver([(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(2,9)])
66
+ sage: Q = ClusterQuiver([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (2, 9)])
67
67
  sage: M = Q.b_matrix()
68
68
  sage: is_mutation_finite(M) # random
69
69
  (False, [9, 6, 9, 8, 9, 4, 0, 4, 5, 2, 1, 0, 1, 0, 7, 1, 9, 2, 5, 7, 8, 6, 3, 0, 2, 5, 4, 2, 6, 9, 2, 7, 3, 5, 3, 7, 9, 5, 9, 0, 2, 7, 9, 2, 4, 2, 1, 6, 9, 4, 3, 5, 0, 8, 2, 9, 5, 3, 7, 0, 1, 8, 3, 7, 2, 7, 3, 4, 8, 0, 4, 9, 5, 2, 8, 4, 8, 1, 7, 8, 9, 1, 5, 0, 8, 7, 4, 8, 9, 8, 0, 7, 4, 7, 1, 2, 8, 6, 1, 3, 9, 3, 9, 1, 3, 2, 4, 9, 5, 1, 2, 9, 4, 8, 5, 3, 4, 6, 8, 9, 2, 5, 9, 4, 6, 2, 1, 4, 9, 6, 0, 9, 8, 0, 4, 7, 9, 2, 1, 6])
@@ -97,7 +97,7 @@ def is_mutation_finite(M, nr_of_checks=None):
97
97
  return True, None
98
98
 
99
99
 
100
- def _triangles(dg):
100
+ def _triangles(dg) -> list[tuple[list, bool]]:
101
101
  """
102
102
  Return a list of all oriented triangles in the digraph ``dg``.
103
103
 
@@ -105,53 +105,50 @@ def _triangles(dg):
105
105
 
106
106
  sage: # needs sage.modules
107
107
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _triangles
108
- sage: Q = ClusterQuiver(['A',3])
108
+ sage: Q = ClusterQuiver(['A', 3])
109
109
  sage: _triangles(Q.digraph())
110
110
  []
111
- sage: Q.mutate([0,1])
111
+ sage: Q.mutate([0, 1])
112
112
  sage: _triangles(Q.digraph())
113
- [([(2, 0), (0, 1), (1, 2)], True)]
114
- sage: Q2 = ClusterQuiver(['A',[1,2],1])
113
+ [([(0, 1), (1, 2), (2, 0)], True)]
114
+ sage: Q2 = ClusterQuiver(['A', [1, 2], 1])
115
115
  sage: _triangles(Q2.digraph())
116
- [([(1, 2), (1, 0), (2, 0)], False)]
116
+ [([(1, 0), (1, 2), (2, 0)], False)]
117
117
  sage: Q2.mutate(2)
118
118
  sage: _triangles(Q2.digraph())
119
- [([(1, 0), (0, 2), (2, 1)], True)]
119
+ [([(1, 0), (2, 1), (0, 2)], True)]
120
120
  """
121
- E = dg.edges(sort=True, labels=False)
122
- V = list(dg)
121
+ from itertools import combinations
123
122
  trians = []
124
- flat_trians = []
125
- for e in E:
126
- v1, v2 = e
127
- for v in V:
128
- if v not in e:
129
- if (v, v1) in E:
130
- if (v2, v) in E:
131
- flat_trian = sorted([v,v1,v2])
132
- if flat_trian not in flat_trians:
133
- flat_trians.append( flat_trian )
134
- trians.append( ( [(v,v1),(v1,v2),(v2,v)], True ) )
135
- elif (v, v2) in E:
136
- flat_trian = sorted([v,v1,v2])
137
- if flat_trian not in flat_trians:
138
- flat_trians.append( flat_trian )
139
- trians.append( ( [(v,v1),(v1,v2),(v,v2)], False ) )
140
- if (v1, v) in E:
141
- if (v2, v) in E:
142
- flat_trian = sorted([v,v1,v2])
143
- if flat_trian not in flat_trians:
144
- flat_trians.append( flat_trian )
145
- trians.append( ( [(v1,v),(v1,v2),(v2,v)], False ) )
146
- elif (v, v2) in E:
147
- flat_trian = sorted([v,v1,v2])
148
- if flat_trian not in flat_trians:
149
- flat_trians.append( flat_trian )
150
- trians.append( ( [(v1,v),(v1,v2),(v,v2)], False ) )
123
+ for x in dg.vertices(sort=True):
124
+ nx = sorted(y for y in dg.neighbor_iterator(x) if x < y)
125
+ for y, z in combinations(nx, 2):
126
+ if dg.has_edge(y, z):
127
+ if dg.has_edge(x, y):
128
+ if dg.has_edge(z, x):
129
+ trians.append(([(x, y), (y, z), (z, x)], True))
130
+ else:
131
+ trians.append(([(x, y), (y, z), (x, z)], False))
132
+ else:
133
+ if dg.has_edge(z, x):
134
+ trians.append(([(y, x), (y, z), (z, x)], False))
135
+ else:
136
+ trians.append(([(y, x), (y, z), (x, z)], False))
137
+ elif dg.has_edge(z, y):
138
+ if dg.has_edge(x, y):
139
+ if dg.has_edge(z, x):
140
+ trians.append(([(x, y), (z, y), (z, x)], False))
141
+ else:
142
+ trians.append(([(x, y), (z, y), (x, z)], False))
143
+ else:
144
+ if dg.has_edge(z, x):
145
+ trians.append(([(y, x), (z, y), (z, x)], False))
146
+ else:
147
+ trians.append(([(y, x), (z, y), (x, z)], True))
151
148
  return trians
152
149
 
153
150
 
154
- def _all_induced_cycles_iter(dg):
151
+ def _all_induced_cycles_iter(dg) -> Iterator[tuple]:
155
152
  """
156
153
  Return an iterator for all induced oriented cycles of length
157
154
  greater than or equal to 4 in the digraph ``dg``.
@@ -160,14 +157,14 @@ def _all_induced_cycles_iter(dg):
160
157
 
161
158
  sage: # needs sage.modules
162
159
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _all_induced_cycles_iter
163
- sage: Q = ClusterQuiver(['A',[6,0],1]); Q
160
+ sage: Q = ClusterQuiver(['A', [6, 0], 1]); Q
164
161
  Quiver on 6 vertices of type ['D', 6]
165
162
  sage: next(_all_induced_cycles_iter(Q.digraph()))
166
163
  ([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0)], True)
167
164
  sage: Q.mutate(0)
168
165
  sage: next(_all_induced_cycles_iter(Q.digraph()))
169
166
  ([(1, 2), (2, 3), (3, 4), (4, 5), (5, 1)], True)
170
- sage: Q2 = ClusterQuiver(['A',[2,3],1])
167
+ sage: Q2 = ClusterQuiver(['A', [2, 3], 1])
171
168
  sage: next(_all_induced_cycles_iter(Q2.digraph()))
172
169
  ([(1, 0), (1, 2), (3, 2), (3, 4), (4, 0)], False)
173
170
  """
@@ -175,7 +172,7 @@ def _all_induced_cycles_iter(dg):
175
172
  E = dg_new.edges(sort=True)
176
173
  for v1, v2, label in E:
177
174
  dg_new.add_edge((v2, v1, label))
178
- induced_sets = []
175
+ induced_sets: list[set] = []
179
176
  cycle_iter = dg_new.all_cycles_iterator(simple=True)
180
177
  for cycle in cycle_iter:
181
178
  if len(cycle) > 3:
@@ -195,7 +192,7 @@ def _all_induced_cycles_iter(dg):
195
192
  # a debug function
196
193
 
197
194
 
198
- def _false_return(s=False):
195
+ def _false_return(s=False) -> str:
199
196
  """
200
197
  Return 'unknown'.
201
198
 
@@ -213,12 +210,12 @@ def _false_return(s=False):
213
210
  return 'unknown'
214
211
 
215
212
 
216
- def _reset_dg(dg, vertices, dict_in_out, del_vertices):
213
+ def _reset_dg(dg, vertices, dict_in_out, del_vertices) -> None:
217
214
  """
218
- Delete the specified vertices (del_vertices) from the DiGraph dg,
219
- and the lists vertices and dict_in_out.
215
+ Delete the specified vertices (``del_vertices``) from the DiGraph ``dg``,
216
+ and the lists ``vertices`` and ``dict_in_out``.
220
217
 
221
- Note that vertices and dict_in_out are the vertices of dg and a
218
+ Note that ``vertices`` and ``dict_in_out`` are the vertices of ``dg`` and a
222
219
  dictionary of in- and out-degrees that depend on the digraph
223
220
  ``dg`` but they are passed through as arguments so the function
224
221
  can change their values.
@@ -227,12 +224,12 @@ def _reset_dg(dg, vertices, dict_in_out, del_vertices):
227
224
 
228
225
  sage: # needs sage.modules
229
226
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _reset_dg
230
- sage: dg = ClusterQuiver(['A',[2,2],1]).digraph(); dg
227
+ sage: dg = ClusterQuiver(['A', [2, 2], 1]).digraph(); dg
231
228
  Digraph on 4 vertices
232
229
  sage: vertices = list(dg)
233
230
  sage: dict_in_out = {}
234
231
  sage: for v in vertices: dict_in_out[v] = (dg.in_degree(v), dg.out_degree(v), dg.degree(v))
235
- sage: _reset_dg(dg,vertices, dict_in_out, [1])
232
+ sage: _reset_dg(dg, vertices, dict_in_out, [1])
236
233
  sage: dg
237
234
  Digraph on 3 vertices
238
235
  sage: vertices
@@ -274,16 +271,16 @@ def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list,
274
271
  sage: dg = DiGraph(1)
275
272
  sage: _check_special_BC_cases(dg, 3, ['BC'], [1], ['A'], [[0]])
276
273
  ['BC', 2, 1]
277
- sage: dg = DiGraph(2); dg.add_edge([0,1])
274
+ sage: dg = DiGraph(2); dg.add_edge([0, 1])
278
275
  sage: _check_special_BC_cases(dg, 4, ['BC'], [1], ['A'], [[0]])
279
276
  ['BC', 3, 1]
280
- sage: dg = DiGraph(2); dg.add_edge([0,1])
281
- sage: _check_special_BC_cases(dg, 4, ['BB'], [1], ['A'], [[0,1]])
277
+ sage: dg = DiGraph(2); dg.add_edge([0, 1])
278
+ sage: _check_special_BC_cases(dg, 4, ['BB'], [1], ['A'], [[0, 1]])
282
279
  ['BB', 3, 1]
283
- sage: _check_special_BC_cases(dg, 4, ['C', 'CD'], [None, None], ['A', 'D'], [ [], [0] ])
280
+ sage: _check_special_BC_cases(dg, 4, ['C', 'CD'], [None, None], ['A', 'D'], [[], [0]])
284
281
  ['C', 4]
285
282
  sage: dg.add_edges([[1, 2], [1, 3]])
286
- sage: _check_special_BC_cases(dg, 4, ['C', 'CD'], [None, None], ['A', 'D'], [ [], [0] ])
283
+ sage: _check_special_BC_cases(dg, 4, ['C', 'CD'], [None, None], ['A', 'D'], [[], [0]])
287
284
  ['CD', 3, 1]
288
285
  """
289
286
  # if dg is not connected, mutation type is not recognized.
@@ -291,7 +288,7 @@ def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list,
291
288
  return 'unknown'
292
289
  # divides into cases depending on whether or not a list 'conn_vert_list' of connecting vertices is given.
293
290
  if conn_vert_list:
294
- mut_type = _connected_mutation_type_AAtildeD( dg, ret_conn_vert=True )
291
+ mut_type = _connected_mutation_type_AAtildeD(dg, ret_conn_vert=True)
295
292
  # when 'conn_vert_list' is given, the output of _connected_mutation_type_AAtildeD is
296
293
  # either 'unknown' or a pair (mut_type, conn_verts). Then, it is tested if the vertices can be glued together as desired.
297
294
  if not mut_type == 'unknown':
@@ -299,11 +296,11 @@ def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list,
299
296
  else:
300
297
  # when conn_vert_list == False, the output of _connected_mutation_type _AAtildeD is simply 'unknown' or the mutation type.
301
298
  # no 'connecting vertices' need to be computed.
302
- mut_type = _connected_mutation_type_AAtildeD( dg, ret_conn_vert=False )
299
+ mut_type = _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False)
303
300
  conn_verts = []
304
301
  # when the mutation type is recognized, program now tries more specifically to figure out 'letter' and 'twist'
305
302
  if not mut_type == 'unknown':
306
- for i in range( len( check_letter_list ) ):
303
+ for i in range(len(check_letter_list)):
307
304
  check_letter = check_letter_list[i]
308
305
  check_twist = check_twist_list[i]
309
306
  hope_letter = hope_letter_list[i]
@@ -311,7 +308,7 @@ def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list,
311
308
  conn_vert = set(conn_vert_list[i])
312
309
  else:
313
310
  conn_vert = set()
314
- # Now, tries to connect up the quiver components (keeping in mind ['D',3] - ['A',3] equivalence)
311
+ # Now, tries to connect up the quiver components (keeping in mind ['D', 3] - ['A', 3] equivalence)
315
312
  if hope_letter == 'D' and mut_type._letter == 'A' and mut_type._rank == 3 and not mut_type._twist:
316
313
  hope_letter = 'A'
317
314
  if conn_vert_list:
@@ -335,74 +332,74 @@ def _connected_mutation_type(dg):
335
332
  sage: # needs sage.modules
336
333
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _connected_mutation_type
337
334
  sage: from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver
338
- sage: dg = ClusterQuiver(['A',3]).digraph(); _connected_mutation_type( dg )
335
+ sage: dg = ClusterQuiver(['A', 3]).digraph(); _connected_mutation_type(dg)
339
336
  ['A', 3]
340
- sage: dg = ClusterQuiver(['D',7]).digraph(); _connected_mutation_type( dg )
337
+ sage: dg = ClusterQuiver(['D', 7]).digraph(); _connected_mutation_type(dg)
341
338
  ['D', 7]
342
- sage: dg = ClusterQuiver(['BC',4,1]).digraph(); _connected_mutation_type( dg )
339
+ sage: dg = ClusterQuiver(['BC', 4, 1]).digraph(); _connected_mutation_type(dg)
343
340
  ['BC', 4, 1]
344
341
  """
345
- dg = DiGraph( dg )
342
+ dg = DiGraph(dg)
346
343
  # defining some shorthands
347
344
  n = dg.order()
348
345
  edges = dg.edges(sort=True)
349
346
  vertices = list(dg)
350
- # initializing lists of the edges with labels (2,-1) or (1,-2); (4,-1) or (1,-4); or (2,-2), respectively
347
+ # initializing lists of the edges with labels (2, -1) or (1, -2); (4, -1) or (1, -4); or (2, -2), respectively
351
348
  exc_labels = []
352
349
  exc_labels41 = []
353
350
  double_edges = []
354
351
  # letter = None
355
352
 
356
353
  # replacing higher labels by multiple edges. Multiple edges and acyclic is a sign that quiver is infinite mutation type with the exception of A_tilde where there might be one multiple edge with multiplicity 2. Multiple edges is at least a sign that the quiver is of 'undetermined finite mutation type'.
357
- dg.allow_multiple_edges( True )
354
+ dg.allow_multiple_edges(True)
358
355
  for edge in edges:
359
356
  label = edge[2]
360
- if label not in [(1,-1),(2,-2),(1,-2),(2,-1),(4,-1),(1,-4)]:
357
+ if label not in [(1, -1), (2, -2), (1, -2), (2, -1), (4, -1), (1, -4)]:
361
358
  # _false_return(i) is a simple function that simply returns 'unknown'. For debugging purposes, it
362
359
  # can also output 'DEBUG: error i' if desired.
363
360
  # this command is used many times in this code, something times without the argument i.
364
361
  return _false_return(2)
365
- elif label == (2,-2):
366
- dg.set_edge_label( edge[0], edge[1], 1 )
367
- dg.add_edge( edge[0], edge[1], 1 )
368
- double_edges.append( edge )
369
- if len( double_edges ) > 1:
362
+ elif label == (2, -2):
363
+ dg.set_edge_label(edge[0], edge[1], 1)
364
+ dg.add_edge(edge[0], edge[1], 1)
365
+ double_edges.append(edge)
366
+ if len(double_edges) > 1:
370
367
  return _false_return()
371
- elif label == (1,-1):
372
- dg.set_edge_label( edge[0], edge[1], 1 )
373
- elif label in [(2,-1),(1,-2)]:
374
- exc_labels.append( edge )
375
- elif label in [(1,-4),(4,-1)]:
376
- exc_labels41.append( edge )
368
+ elif label == (1, -1):
369
+ dg.set_edge_label(edge[0], edge[1], 1)
370
+ elif label in [(2, -1), (1, -2)]:
371
+ exc_labels.append(edge)
372
+ elif label in [(1, -4), (4, -1)]:
373
+ exc_labels41.append(edge)
377
374
 
378
375
  # creating a dictionary of in-, out- and total degrees
379
376
  dict_in_out = {}
380
377
  for v in vertices:
381
378
  dict_in_out[v] = (dg.in_degree(v), dg.out_degree(v), dg.degree(v))
382
379
 
383
- if len( exc_labels ) + len( exc_labels41 ) + len( double_edges ) > 4:
380
+ if len(exc_labels) + len(exc_labels41) + len(double_edges) > 4:
384
381
  return _false_return()
385
382
 
386
- # test for the labels (4,-1) and (1,-4) which can only appear in affine type BC
383
+ # test for the labels (4, -1) and (1, -4) which can only appear in affine type BC
387
384
  if exc_labels41:
388
- # tests a two-vertex quiver to see if it is of type ['BC',1,1]
385
+ # tests a two-vertex quiver to see if it is of type ['BC', 1, 1]
389
386
  if len(exc_labels41) == 1 and dict_in_out[exc_labels41[0][0]][2] == dict_in_out[exc_labels41[0][1]][2] == 1:
390
- return QuiverMutationType(['BC',1,1])
391
- # test if quiver contains a triangle T with edges [ (0, 1, (2, -1)), (2, 0, (2,-1)), (1, 2, (1, -4)) ] or [ (0, 1, (1, -2)), (2, 0, (1,-2)), (1, 2, (4, -1)) ].
387
+ return QuiverMutationType(['BC', 1, 1])
388
+ # test if quiver contains a triangle T with edges [(0, 1, (2, -1)), (2, 0, (2, -1)), (1, 2, (1, -4))] or [(0, 1, (1, -2)), (2, 0, (1, -2)), (1, 2, (4, -1))].
392
389
  if len(exc_labels41) == 1 and len(exc_labels) == 2:
393
- bool2 = exc_labels41[0][2] == (4,-1) and exc_labels[0][2] == exc_labels[1][2] == (1,-2)
394
- bool3 = exc_labels41[0][2] == (1,-4) and exc_labels[0][2] == exc_labels[1][2] == (2,-1)
390
+ bool2 = exc_labels41[0][2] == (4, -1) and exc_labels[0][2] == exc_labels[1][2] == (1, -2)
391
+ bool3 = exc_labels41[0][2] == (1, -4) and exc_labels[0][2] == exc_labels[1][2] == (2, -1)
395
392
  if bool2 or bool3:
396
393
  v1, v2, label = exc_labels41[0]
397
394
  label1, label2 = exc_labels
398
- # delete the two vertices associated to the edge with label (1,-4) or (4,-1) and test if the rest of the quiver is of type A.
395
+ # delete the two vertices associated to the edge with label (1, -4) or (4, -1) and test if the rest of the quiver is of type A.
399
396
  # the third vertex of the triangle T should be a connecting_vertex.
400
397
  if label1[1] == label2[0] and label2[1] == v1 and v2 == label1[0] and dict_in_out[v1][2] == dict_in_out[v2][2] == 2:
401
- _reset_dg( dg, vertices, dict_in_out, [v1,v2] )
402
- return _check_special_BC_cases( dg, n, ['BC'], [1], ['A'], [[label1[1]]] )
398
+ _reset_dg(dg, vertices, dict_in_out, [v1, v2])
399
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'], [[label1[1]]])
403
400
  elif label1[0] == label2[1] and label1[1] == v1 and v2 == label2[0] and dict_in_out[v1][2] == dict_in_out[v2][2] == 2:
404
- _reset_dg( dg, vertices, dict_in_out, [v1,v2] )
405
- return _check_special_BC_cases( dg, n, ['BC'], [1], ['A'], [[label1[0]]] )
401
+ _reset_dg(dg, vertices, dict_in_out, [v1, v2])
402
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'], [[label1[0]]])
406
403
  else:
407
404
  return _false_return()
408
405
  else:
@@ -410,14 +407,14 @@ def _connected_mutation_type(dg):
410
407
  else:
411
408
  return _false_return()
412
409
 
413
- # the program now performs further tests in the case that there are no edges of type (1,-4) nor (4,-1)
410
+ # the program now performs further tests in the case that there are no edges of type (1, -4) nor (4, -1)
414
411
 
415
412
  # first test for affine type C: if there are 4 exceptional labels, test if both belong to triangles with leaves
416
- if len( exc_labels ) == 4:
413
+ if len(exc_labels) == 4:
417
414
  exc_labels12 = [labl for labl in exc_labels if labl[2] == (1, -2)]
418
415
  exc_labels21 = [labl for labl in exc_labels if labl[2] == (2, -1)]
419
416
  # check that we have two labels of one kind and one label of the other
420
- if len( exc_labels12 ) != 2 or len( exc_labels21 ) != 2:
417
+ if len(exc_labels12) != 2 or len(exc_labels21) != 2:
421
418
  return _false_return()
422
419
 
423
420
  label121 = exc_labels12[0]
@@ -447,166 +444,166 @@ def _connected_mutation_type(dg):
447
444
  else:
448
445
  return _false_return()
449
446
 
450
- # tests for which configuration the two (1,-2) and two (2,-1) edges are in.
451
- bool1 = dg.has_edge(label121[1],label211[0],1) and dict_in_out[label211[1]][0] == dict_in_out[label211[1]][1] == 1
452
- bool2 = dg.has_edge(label122[1],label212[0],1) and dict_in_out[label212[1]][0] == dict_in_out[label212[1]][1] == 1
453
- bool12 = not ( label121[1] == label122[1] and label211[0] == label212[0] )
454
- bool3 = dg.has_edge(label211[1],label121[0],1) and dict_in_out[label121[1]][0] == dict_in_out[label121[1]][1] == 1
455
- bool4 = dg.has_edge(label212[1],label122[0],1) and dict_in_out[label122[1]][0] == dict_in_out[label122[1]][1] == 1
456
- bool34 = not ( label211[1] == label212[1] and label121[0] == label122[0] )
457
- bool5 = dg.has_edge(label211[1],label121[0],1) and dict_in_out[label121[1]][0] == dict_in_out[label121[1]][1] == 1
458
- bool6 = dg.has_edge(label122[1],label212[0],1) and dict_in_out[label212[1]][0] == dict_in_out[label212[1]][1] == 1
459
- bool56 = not ( label211[1] == label122[1] and label121[0] == label212[0] )
460
- bool7 = dg.has_edge(label212[1],label122[0],1) and dict_in_out[label122[1]][0] == dict_in_out[label122[1]][1] == 1
461
- bool8 = dg.has_edge(label121[1],label211[0],1) and dict_in_out[label211[1]][0] == dict_in_out[label211[1]][1] == 1
462
- bool78 = not ( label212[1] == label121[1] and label122[0] == label211[0] )
463
-
464
- nb1 = len( set(dg.neighbors(label121[1])).intersection(dg.neighbors(label211[0])) ) <= 1
465
- nb2 = len( set(dg.neighbors(label122[1])).intersection(dg.neighbors(label212[0])) ) <= 1
466
- nb3 = len( set(dg.neighbors(label211[1])).intersection(dg.neighbors(label121[0])) ) <= 1
467
- nb4 = len( set(dg.neighbors(label212[1])).intersection(dg.neighbors(label122[0])) ) <= 1
447
+ # tests for which configuration the two (1, -2) and two (2, -1) edges are in.
448
+ bool1 = dg.has_edge(label121[1], label211[0], 1) and dict_in_out[label211[1]][0] == dict_in_out[label211[1]][1] == 1
449
+ bool2 = dg.has_edge(label122[1], label212[0], 1) and dict_in_out[label212[1]][0] == dict_in_out[label212[1]][1] == 1
450
+ bool12 = not (label121[1] == label122[1] and label211[0] == label212[0])
451
+ bool3 = dg.has_edge(label211[1], label121[0], 1) and dict_in_out[label121[1]][0] == dict_in_out[label121[1]][1] == 1
452
+ bool4 = dg.has_edge(label212[1], label122[0], 1) and dict_in_out[label122[1]][0] == dict_in_out[label122[1]][1] == 1
453
+ bool34 = not (label211[1] == label212[1] and label121[0] == label122[0])
454
+ bool5 = dg.has_edge(label211[1], label121[0], 1) and dict_in_out[label121[1]][0] == dict_in_out[label121[1]][1] == 1
455
+ bool6 = dg.has_edge(label122[1], label212[0], 1) and dict_in_out[label212[1]][0] == dict_in_out[label212[1]][1] == 1
456
+ bool56 = not (label211[1] == label122[1] and label121[0] == label212[0])
457
+ bool7 = dg.has_edge(label212[1], label122[0], 1) and dict_in_out[label122[1]][0] == dict_in_out[label122[1]][1] == 1
458
+ bool8 = dg.has_edge(label121[1], label211[0], 1) and dict_in_out[label211[1]][0] == dict_in_out[label211[1]][1] == 1
459
+ bool78 = not (label212[1] == label121[1] and label122[0] == label211[0])
460
+
461
+ nb1 = len(set(dg.neighbors(label121[1])).intersection(dg.neighbors(label211[0]))) <= 1
462
+ nb2 = len(set(dg.neighbors(label122[1])).intersection(dg.neighbors(label212[0]))) <= 1
463
+ nb3 = len(set(dg.neighbors(label211[1])).intersection(dg.neighbors(label121[0]))) <= 1
464
+ nb4 = len(set(dg.neighbors(label212[1])).intersection(dg.neighbors(label122[0]))) <= 1
468
465
 
469
466
  if bool1 and bool2 and bool12 and nb1 and nb2:
470
- v1,v2 = label211[1],label212[1]
471
- _reset_dg( dg, vertices, dict_in_out, [v1,v2] )
472
- return _check_special_BC_cases( dg, n, ['CC'], [1], ['A'] )
467
+ v1, v2 = label211[1], label212[1]
468
+ _reset_dg(dg, vertices, dict_in_out, [v1, v2])
469
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'])
473
470
  if bool3 and bool4 and bool34 and nb3 and nb4:
474
- v1,v2 = label121[1],label122[1]
475
- _reset_dg( dg, vertices, dict_in_out, [v1,v2] )
476
- return _check_special_BC_cases( dg, n, ['BB'], [1], ['A'] )
471
+ v1, v2 = label121[1], label122[1]
472
+ _reset_dg(dg, vertices, dict_in_out, [v1, v2])
473
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'])
477
474
  elif bool5 and bool6 and bool56 and nb2 and nb3:
478
- v1,v2 = label121[1],label212[1]
479
- _reset_dg( dg, vertices, dict_in_out, [v1,v2] )
480
- return _check_special_BC_cases( dg, n, ['BC'], [1], ['A'] )
475
+ v1, v2 = label121[1], label212[1]
476
+ _reset_dg(dg, vertices, dict_in_out, [v1, v2])
477
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
481
478
  elif bool7 and bool8 and bool78 and nb1 and nb4:
482
- v1,v2 = label122[1],label211[1]
483
- _reset_dg( dg, vertices, dict_in_out, [v1,v2] )
484
- return _check_special_BC_cases( dg, n, ['BC'], [1], ['A'] )
479
+ v1, v2 = label122[1], label211[1]
480
+ _reset_dg(dg, vertices, dict_in_out, [v1, v2])
481
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
485
482
  else:
486
483
  return _false_return()
487
484
 
488
485
  # first test for affine type C: if there are three exceptional labels, we must be in both cases below of the same construction
489
- elif len( exc_labels ) == 3:
486
+ elif len(exc_labels) == 3:
490
487
  exc_labels12 = [labl for labl in exc_labels if labl[2] == (1, -2)]
491
488
  exc_labels21 = [labl for labl in exc_labels if labl[2] == (2, -1)]
492
489
  # check that we have two labels of one kind and one label of the other
493
490
  if exc_labels12 == [] or exc_labels21 == []:
494
491
  return _false_return()
495
- if len( exc_labels12 ) == 2:
496
- label1,label2 = exc_labels12
492
+ if len(exc_labels12) == 2:
493
+ label1, label2 = exc_labels12
497
494
  label3 = exc_labels21[0]
498
495
  if dict_in_out[label2[0]][2] == 1 or dict_in_out[label2[1]][2] == 1:
499
496
  label1, label2 = label2, label1
500
497
  if dict_in_out[label1[0]][2] == 1:
501
- if label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1],label2[0],1):
502
- v1,v2 = label3[1],label2[0]
503
- _reset_dg( dg, vertices, dict_in_out, [label2[1]] )
504
- if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0:
498
+ if label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1], label2[0], 1):
499
+ v1, v2 = label3[1], label2[0]
500
+ _reset_dg(dg, vertices, dict_in_out, [label2[1]])
501
+ if len(set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1))) > 0:
505
502
  return _false_return()
506
- elif len( set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)) ) > 0:
507
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'],[[v1,v2]] )
503
+ elif len(set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2))) > 0:
504
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'], [[v1, v2]])
508
505
  else:
509
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'] )
510
- elif label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1],label3[0],1):
511
- v1,v2 = label2[1],label3[0]
512
- _reset_dg( dg, vertices, dict_in_out, [label3[1]] )
513
- if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0:
506
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
507
+ elif label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1], label3[0], 1):
508
+ v1, v2 = label2[1], label3[0]
509
+ _reset_dg(dg, vertices, dict_in_out, [label3[1]])
510
+ if len(set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1))) > 0:
514
511
  return _false_return()
515
- elif len( set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)) ) > 0:
516
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'],[[v1,v2]] )
512
+ elif len(set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2))) > 0:
513
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'], [[v1, v2]])
517
514
  else:
518
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'] )
515
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'])
519
516
  else:
520
517
  return _false_return()
521
518
  elif dict_in_out[label1[1]][2] == 1:
522
- if label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1],label3[0],1):
523
- v1,v2 = label2[1],label3[0]
524
- _reset_dg( dg, vertices, dict_in_out, [label3[1]] )
525
- if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0:
519
+ if label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1], label3[0], 1):
520
+ v1, v2 = label2[1], label3[0]
521
+ _reset_dg(dg, vertices, dict_in_out, [label3[1]])
522
+ if len(set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1))) > 0:
526
523
  return _false_return()
527
- elif len( set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)) ) > 0:
528
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'],[[v1,v2]] )
524
+ elif len(set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2))) > 0:
525
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'], [[v1, v2]])
529
526
  else:
530
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'] )
531
- elif label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1],label2[0],1):
532
- v1,v2 = label3[1],label2[0]
533
- _reset_dg( dg, vertices, dict_in_out, [label2[1]] )
534
- if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0:
527
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
528
+ elif label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1], label2[0], 1):
529
+ v1, v2 = label3[1], label2[0]
530
+ _reset_dg(dg, vertices, dict_in_out, [label2[1]])
531
+ if len(set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1))) > 0:
535
532
  return _false_return()
536
- elif len( set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)) ) > 0:
537
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'],[[v1,v2]] )
533
+ elif len(set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2))) > 0:
534
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'], [[v1, v2]])
538
535
  else:
539
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'] )
536
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'])
540
537
  else:
541
538
  return _false_return()
542
- elif label1[1] == label2[1] == label3[0] and dict_in_out[label1[1]][2] == 3 and dg.has_edge(label3[1],label1[0],1) and dg.has_edge(label3[1],label2[0],1) and dict_in_out[label2[0]][2] == dict_in_out[label1[0]][2] == 2:
543
- _reset_dg( dg, vertices, dict_in_out, [label1[1]] )
544
- return _check_special_BC_cases( dg, n, ['BD'],[1],['D'] )
545
- elif label1[0] == label2[0] == label3[1] and dict_in_out[label1[0]][2] == 3 and dg.has_edge(label1[1],label3[0],1) and dg.has_edge(label2[1],label3[0],1) and dict_in_out[label2[1]][2] == dict_in_out[label1[1]][2] == 2:
546
- _reset_dg( dg, vertices, dict_in_out, [label1[0]] )
547
- return _check_special_BC_cases( dg, n, ['CD'],[1],['D'] )
539
+ elif label1[1] == label2[1] == label3[0] and dict_in_out[label1[1]][2] == 3 and dg.has_edge(label3[1], label1[0], 1) and dg.has_edge(label3[1], label2[0], 1) and dict_in_out[label2[0]][2] == dict_in_out[label1[0]][2] == 2:
540
+ _reset_dg(dg, vertices, dict_in_out, [label1[1]])
541
+ return _check_special_BC_cases(dg, n, ['BD'], [1], ['D'])
542
+ elif label1[0] == label2[0] == label3[1] and dict_in_out[label1[0]][2] == 3 and dg.has_edge(label1[1], label3[0], 1) and dg.has_edge(label2[1], label3[0], 1) and dict_in_out[label2[1]][2] == dict_in_out[label1[1]][2] == 2:
543
+ _reset_dg(dg, vertices, dict_in_out, [label1[0]])
544
+ return _check_special_BC_cases(dg, n, ['CD'], [1], ['D'])
548
545
  else:
549
546
  return _false_return()
550
- elif len( exc_labels21 ) == 2:
551
- label1,label2 = exc_labels21
547
+ elif len(exc_labels21) == 2:
548
+ label1, label2 = exc_labels21
552
549
  label3 = exc_labels12[0]
553
550
  if dict_in_out[label2[0]][2] == 1 or dict_in_out[label2[1]][2] == 1:
554
551
  label1, label2 = label2, label1
555
552
  if dict_in_out[label1[1]][2] == 1:
556
- if label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1],label2[0],1):
553
+ if label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1], label2[0], 1):
557
554
  v1, v2 = label3[1], label2[0]
558
- _reset_dg( dg, vertices, dict_in_out, [label2[1]] )
559
- if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0:
555
+ _reset_dg(dg, vertices, dict_in_out, [label2[1]])
556
+ if len(set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1))) > 0:
560
557
  return _false_return()
561
- elif len( set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)) ) > 0:
562
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'],[[v1,v2]] )
558
+ elif len(set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2))) > 0:
559
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'], [[v1, v2]])
563
560
  else:
564
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'] )
565
- elif label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1],label3[0],1):
561
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'])
562
+ elif label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1], label3[0], 1):
566
563
  v1, v2 = label2[1], label3[0]
567
- _reset_dg( dg, vertices, dict_in_out, [label3[1]] )
568
- if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0:
564
+ _reset_dg(dg, vertices, dict_in_out, [label3[1]])
565
+ if len(set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1))) > 0:
569
566
  return _false_return()
570
- elif len( set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)) ) > 0:
571
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'],[[v1,v2]] )
567
+ elif len(set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2))) > 0:
568
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'], [[v1, v2]])
572
569
  else:
573
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'] )
570
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
574
571
  else:
575
572
  return _false_return()
576
573
  elif dict_in_out[label1[0]][2] == 1:
577
- if label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1],label3[0],1):
574
+ if label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1], label3[0], 1):
578
575
  v1, v2 = label2[1], label3[0]
579
- _reset_dg( dg, vertices, dict_in_out, [label3[1]] )
580
- if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0:
576
+ _reset_dg(dg, vertices, dict_in_out, [label3[1]])
577
+ if len(set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1))) > 0:
581
578
  return _false_return()
582
- elif len( set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)) ) > 0:
583
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'],[[v1,v2]] )
579
+ elif len(set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2))) > 0:
580
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'], [[v1, v2]])
584
581
  else:
585
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'] )
586
- elif label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1],label2[0],1):
582
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'])
583
+ elif label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1], label2[0], 1):
587
584
  v1, v2 = label3[1], label2[0]
588
- _reset_dg( dg, vertices, dict_in_out, [label2[1]] )
589
- if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0:
585
+ _reset_dg(dg, vertices, dict_in_out, [label2[1]])
586
+ if len(set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1))) > 0:
590
587
  return _false_return()
591
- elif len( set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)) ) > 0:
592
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'],[[v1,v2]] )
588
+ elif len(set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2))) > 0:
589
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'], [[v1, v2]])
593
590
  else:
594
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'] )
591
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
595
592
  else:
596
593
  return _false_return()
597
- elif label1[0] == label2[0] == label3[1] and dict_in_out[label1[0]][2] == 3 and dg.has_edge(label1[1],label3[0],1) and dict_in_out[label1[1]][2] == 2 and dg.has_edge(label2[1],label3[0],1) and dict_in_out[label2[1]][2] == 2:
598
- _reset_dg( dg, vertices, dict_in_out, [label3[1]] )
599
- return _check_special_BC_cases( dg, n, ['BD'],[1],['D'] )
600
- elif label1[1] == label2[1] == label3[0] and dict_in_out[label3[0]][2] == 3 and dg.has_edge(label3[1],label1[0],1) and dict_in_out[label1[0]][2] == 2 and dg.has_edge(label3[1],label2[0],1) and dict_in_out[label2[0]][2] == 2:
601
- _reset_dg( dg, vertices, dict_in_out, [label3[0]] )
602
- return _check_special_BC_cases( dg, n, ['CD'],[1],['D'] )
594
+ elif label1[0] == label2[0] == label3[1] and dict_in_out[label1[0]][2] == 3 and dg.has_edge(label1[1], label3[0], 1) and dict_in_out[label1[1]][2] == 2 and dg.has_edge(label2[1], label3[0], 1) and dict_in_out[label2[1]][2] == 2:
595
+ _reset_dg(dg, vertices, dict_in_out, [label3[1]])
596
+ return _check_special_BC_cases(dg, n, ['BD'], [1], ['D'])
597
+ elif label1[1] == label2[1] == label3[0] and dict_in_out[label3[0]][2] == 3 and dg.has_edge(label3[1], label1[0], 1) and dict_in_out[label1[0]][2] == 2 and dg.has_edge(label3[1], label2[0], 1) and dict_in_out[label2[0]][2] == 2:
598
+ _reset_dg(dg, vertices, dict_in_out, [label3[0]])
599
+ return _check_special_BC_cases(dg, n, ['CD'], [1], ['D'])
603
600
  else:
604
601
  return _false_return()
605
602
 
606
603
  # first test for finite types B and C: if there are two exceptional labels, they must belong to an oriented triangle and the vertex between must be a leaf
607
604
  # first test for affine type C: if there are two exceptional labels, they must belong to leaves
608
605
  # first test for affine type B: if there are two exceptional labels, they must be...
609
- elif len( exc_labels ) == 2:
606
+ elif len(exc_labels) == 2:
610
607
  label1, label2 = exc_labels
611
608
  if label1[1] == label2[0]:
612
609
  pass
@@ -618,9 +615,9 @@ def _connected_mutation_type(dg):
618
615
  label1, label2 = label2, label1
619
616
  if label1[2] == (1, -2) and label2[2] == (2, -1):
620
617
  if label1[1] == label2[1] and dict_in_out[label1[1]][2] == 2 and dict_in_out[label1[0]][2] == 1 and dict_in_out[label2[0]][2] == 1:
621
- return QuiverMutationType(['BC',2,1])
618
+ return QuiverMutationType(['BC', 2, 1])
622
619
  elif label1[0] == label2[0] and dict_in_out[label1[0]][2] == 2 and dict_in_out[label1[1]][2] == 1 and dict_in_out[label2[1]][2] == 1:
623
- return QuiverMutationType(['BC',2,1])
620
+ return QuiverMutationType(['BC', 2, 1])
624
621
  # the cases in affine type B/C are checked where the exceptional labels connect to leaves
625
622
  v11, v12, label1 = label1
626
623
  v21, v22, label2 = label2
@@ -638,53 +635,53 @@ def _connected_mutation_type(dg):
638
635
  return _false_return()
639
636
  if label1 == label2:
640
637
  if in_out1 == in_out2 == 'in':
641
- if label1 == (1,-2):
642
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'] )
638
+ if label1 == (1, -2):
639
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'])
643
640
  else:
644
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'] )
641
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'])
645
642
  elif in_out1 == in_out2 == 'out':
646
- if label1 == (1,-2):
647
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'] )
643
+ if label1 == (1, -2):
644
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'])
648
645
  else:
649
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'] )
646
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'])
650
647
  else:
651
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'] )
648
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
652
649
  else:
653
650
  if in_out1 == in_out2:
654
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'] )
651
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
655
652
  else:
656
- if label1 == (1,-2):
653
+ if label1 == (1, -2):
657
654
  if in_out1 == 'in':
658
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'] )
655
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'])
659
656
  else:
660
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'] )
657
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'])
661
658
  else:
662
659
  if in_out1 == 'in':
663
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'] )
660
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'])
664
661
  else:
665
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'] )
662
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'])
666
663
 
667
- v1,v,label1 = label1
668
- v,v2,label2 = label2
664
+ v1, v, label1 = label1
665
+ v, v2, label2 = label2
669
666
  if dg.has_multiple_edges():
670
- if all( edge == (v2,v1,1) for edge in dg.multiple_edges() ):
667
+ if all(edge == (v2, v1, 1) for edge in dg.multiple_edges()):
671
668
  if dict_in_out[v2][2] == dict_in_out[v1][2] == 3:
672
- _reset_dg( dg, vertices, dict_in_out, [v1,v2] )
673
- if label1 == (1,-2) and label2 == (2,-1):
674
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'],[[v]] )
675
- elif label1 == (2,-1) and label2 == (1,-2):
676
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'],[[v]] )
669
+ _reset_dg(dg, vertices, dict_in_out, [v1, v2])
670
+ if label1 == (1, -2) and label2 == (2, -1):
671
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'], [[v]])
672
+ elif label1 == (2, -1) and label2 == (1, -2):
673
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'], [[v]])
677
674
  else:
678
675
  return _false_return()
679
676
  elif dict_in_out[v][0] == dict_in_out[v][1] == 1:
680
677
  dg.remove_multiple_edges()
681
- dg = DiGraph( dg )
682
- _reset_dg( dg, vertices, dict_in_out, [v] )
678
+ dg = DiGraph(dg)
679
+ _reset_dg(dg, vertices, dict_in_out, [v])
683
680
  if dict_in_out[v1][0] == dict_in_out[v1][1] == dict_in_out[v2][0] == dict_in_out[v2][1] == 1 and next(dg.neighbor_out_iterator(v1)) == next(dg.neighbor_in_iterator(v2)):
684
- if label1 == (2,-1) and label2 == (1,-2):
685
- return _check_special_BC_cases( dg, n, ['CD'],[1],['A'] )
686
- elif label1 == (1,-2) and label2 == (2,-1):
687
- return _check_special_BC_cases( dg, n, ['BD'],[1],['A'] )
681
+ if label1 == (2, -1) and label2 == (1, -2):
682
+ return _check_special_BC_cases(dg, n, ['CD'], [1], ['A'])
683
+ elif label1 == (1, -2) and label2 == (2, -1):
684
+ return _check_special_BC_cases(dg, n, ['BD'], [1], ['A'])
688
685
  else:
689
686
  return _false_return()
690
687
  else:
@@ -694,73 +691,73 @@ def _connected_mutation_type(dg):
694
691
  elif not dict_in_out[v][0] == 1 or not dict_in_out[v][1] == 1:
695
692
  return _false_return()
696
693
  else:
697
- if dg.has_edge(v2,v1,1):
698
- nr_same_neighbors = len( set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)) )
699
- nr_other_neighbors = len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) )
700
- nr_contained_cycles = len([ cycle for cycle, is_oriented in _all_induced_cycles_iter( dg ) if v1 in flatten(cycle) and v2 in flatten(cycle) ] )
694
+ if dg.has_edge(v2, v1, 1):
695
+ nr_same_neighbors = len(set(dg.neighbors_out(v1)).intersection(dg.neighbors_in(v2)))
696
+ nr_other_neighbors = len(set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)))
697
+ nr_contained_cycles = len([cycle for cycle, is_oriented in _all_induced_cycles_iter(dg) if v1 in flatten(cycle) and v2 in flatten(cycle)])
701
698
  if nr_same_neighbors + nr_other_neighbors + nr_contained_cycles > 2:
702
699
  return _false_return()
703
- if label1 == (2,-1) and label2 == (1,-2):
700
+ if label1 == (2, -1) and label2 == (1, -2):
704
701
  if n == 4 and (nr_same_neighbors == 2 or nr_other_neighbors == 1):
705
- return QuiverMutationType(['CD',n-1,1])
702
+ return QuiverMutationType(['CD', n - 1, 1])
706
703
  # checks for affine A
707
704
  if nr_same_neighbors + nr_other_neighbors > 1:
708
- mt_tmp = _check_special_BC_cases( dg, n, ['C','CD'],[None,None],['A','D'],[[],[v]] )
705
+ mt_tmp = _check_special_BC_cases(dg, n, ['C', 'CD'], [None, None], ['A', 'D'], [[], [v]])
709
706
  else:
710
- _reset_dg( dg, vertices, dict_in_out, [v] )
711
- mt_tmp = _check_special_BC_cases( dg, n, ['C','CD'],[None,None],['A','D'] )
707
+ _reset_dg(dg, vertices, dict_in_out, [v])
708
+ mt_tmp = _check_special_BC_cases(dg, n, ['C', 'CD'], [None, None], ['A', 'D'])
712
709
  if mt_tmp == 'unknown':
713
- dg.delete_edges([[v2,v1],[v1,v],[v,v2]])
714
- dg.add_edges([[v1,v2,1],[v,v1,1],[v2,v,1]])
710
+ dg.delete_edges([[v2, v1], [v1, v], [v, v2]])
711
+ dg.add_edges([[v1, v2, 1], [v, v1, 1], [v2, v, 1]])
715
712
  if nr_same_neighbors + nr_other_neighbors > 1:
716
- #_reset_dg( dg, vertices, dict_in_out, [v] )
717
- return _check_special_BC_cases( dg, n, ['CD'],[None],['D'],[[v]] )
713
+ # _reset_dg(dg, vertices, dict_in_out, [v])
714
+ return _check_special_BC_cases(dg, n, ['CD'], [None], ['D'], [[v]])
718
715
  else:
719
- return _check_special_BC_cases( dg, n, ['CD'],[None],['D'] )
716
+ return _check_special_BC_cases(dg, n, ['CD'], [None], ['D'])
720
717
  else:
721
718
  return mt_tmp
722
- elif label1 == (1,-2) and label2 == (2,-1):
719
+ elif label1 == (1, -2) and label2 == (2, -1):
723
720
  if n == 4 and (nr_same_neighbors == 2 or nr_other_neighbors == 1):
724
- return QuiverMutationType(['BD',n-1,1])
721
+ return QuiverMutationType(['BD', n - 1, 1])
725
722
  # checks for affine A
726
723
  if nr_same_neighbors + nr_other_neighbors > 1:
727
- mt_tmp = _check_special_BC_cases( dg, n, ['B','BD'],[None,None],['A','D'],[[],[v]] )
724
+ mt_tmp = _check_special_BC_cases(dg, n, ['B', 'BD'], [None, None], ['A', 'D'], [[], [v]])
728
725
  else:
729
- _reset_dg( dg, vertices, dict_in_out, [v] )
730
- mt_tmp = _check_special_BC_cases( dg, n, ['B','BD'],[None,None],['A','D'] )
726
+ _reset_dg(dg, vertices, dict_in_out, [v])
727
+ mt_tmp = _check_special_BC_cases(dg, n, ['B', 'BD'], [None, None], ['A', 'D'])
731
728
  if mt_tmp == 'unknown':
732
- dg.delete_edges([[v2,v1],[v1,v],[v,v2]])
733
- dg.add_edges([[v1,v2,1],[v,v1,1],[v2,v,1]])
729
+ dg.delete_edges([[v2, v1], [v1, v], [v, v2]])
730
+ dg.add_edges([[v1, v2, 1], [v, v1, 1], [v2, v, 1]])
734
731
  if nr_same_neighbors + nr_other_neighbors > 1:
735
- #_reset_dg( dg, vertices, dict_in_out, [v] )
736
- return _check_special_BC_cases( dg, n, ['BD'],[None],['D'],[[v]] )
732
+ # _reset_dg(dg, vertices, dict_in_out, [v])
733
+ return _check_special_BC_cases(dg, n, ['BD'], [None], ['D'], [[v]])
737
734
  else:
738
- return _check_special_BC_cases( dg, n, ['BD'],[None],['D'] )
735
+ return _check_special_BC_cases(dg, n, ['BD'], [None], ['D'])
739
736
  else:
740
737
  return mt_tmp
741
738
  else:
742
739
  return _false_return()
743
740
  elif dict_in_out[v1][2] == 1 and dict_in_out[v2][2] == 1:
744
- if label1 == (1,-2) and label2 == (1,-2):
745
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'] )
746
- elif label1 == (2,-1) and label2 == (2,-1):
747
- return _check_special_BC_cases( dg, n, ['BC'],[1],['A'] )
748
- elif label1 == (1,-2) and label2 == (2,-1):
749
- return _check_special_BC_cases( dg, n, ['CC'],[1],['A'] )
750
- elif label1 == (2,-1) and label2 == (1,-2):
751
- return _check_special_BC_cases( dg, n, ['BB'],[1],['A'] )
741
+ if label1 == (1, -2) and label2 == (1, -2):
742
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
743
+ elif label1 == (2, -1) and label2 == (2, -1):
744
+ return _check_special_BC_cases(dg, n, ['BC'], [1], ['A'])
745
+ elif label1 == (1, -2) and label2 == (2, -1):
746
+ return _check_special_BC_cases(dg, n, ['CC'], [1], ['A'])
747
+ elif label1 == (2, -1) and label2 == (1, -2):
748
+ return _check_special_BC_cases(dg, n, ['BB'], [1], ['A'])
752
749
  else:
753
750
  return _false_return()
754
751
  elif dict_in_out[v][0] == dict_in_out[v][1] == 1 and dict_in_out[v1][0] == dict_in_out[v1][1] == 1 and dict_in_out[v2][0] == dict_in_out[v2][1] == 1:
755
- _reset_dg( dg, vertices, dict_in_out, [v] )
756
- if n == 4 and ( label1, label2 ) == ( (2,-1), (1,-2) ):
757
- return _check_special_BC_cases( dg, n, ['CD'],[1],['A'] )
758
- elif n > 4 and ( label1, label2 ) == ( (2,-1), (1,-2) ):
759
- return _check_special_BC_cases( dg, n, ['CD'],[1],['D'] )
760
- elif n == 4 and ( label1, label2 ) == ( (1,-2), (2,-1) ):
761
- return _check_special_BC_cases( dg, n, ['BD'],[1],['A'] )
762
- elif n > 4 and ( label1, label2 ) == ( (1,-2), (2,-1) ):
763
- return _check_special_BC_cases( dg, n, ['BD'],[1],['D'] )
752
+ _reset_dg(dg, vertices, dict_in_out, [v])
753
+ if n == 4 and (label1, label2) == ((2, -1), (1, -2)):
754
+ return _check_special_BC_cases(dg, n, ['CD'], [1], ['A'])
755
+ elif n > 4 and (label1, label2) == ((2, -1), (1, -2)):
756
+ return _check_special_BC_cases(dg, n, ['CD'], [1], ['D'])
757
+ elif n == 4 and (label1, label2) == ((1, -2), (2, -1)):
758
+ return _check_special_BC_cases(dg, n, ['BD'], [1], ['A'])
759
+ elif n > 4 and (label1, label2) == ((1, -2), (2, -1)):
760
+ return _check_special_BC_cases(dg, n, ['BD'], [1], ['D'])
764
761
  else:
765
762
  return _false_return()
766
763
  else:
@@ -768,35 +765,35 @@ def _connected_mutation_type(dg):
768
765
 
769
766
  # second tests for finite types B and C: if there is only one exceptional label, it must belong to a leaf
770
767
  # also tests for affine type B: this exceptional label must belong to a leaf of a type D quiver
771
- elif len( exc_labels ) == 1:
768
+ elif len(exc_labels) == 1:
772
769
  label = exc_labels[0]
773
770
  v_out = label[0]
774
771
  v_in = label[1]
775
772
  label = label[2]
776
- if label == (1,-2):
777
- if dict_in_out[ v_in ][0] == 1 and dict_in_out[ v_in ][1] == 0:
778
- #_reset_dg( dg, vertices, dict_in_out, [v_in] )
779
- return _check_special_BC_cases( dg, n, ['B','BD'],[None,1],['A','D'],[[v_in],[v_in]] )
780
- elif dict_in_out[ v_out ][0] == 0 and dict_in_out[ v_out ][1] == 1:
781
- #_reset_dg( dg, vertices, dict_in_out, [v_out] )
782
- return _check_special_BC_cases( dg, n, ['C','CD'],[None,1],['A','D'],[[v_out],[v_out]] )
773
+ if label == (1, -2):
774
+ if dict_in_out[v_in][0] == 1 and dict_in_out[v_in][1] == 0:
775
+ # _reset_dg(dg, vertices, dict_in_out, [v_in])
776
+ return _check_special_BC_cases(dg, n, ['B', 'BD'], [None, 1], ['A', 'D'], [[v_in], [v_in]])
777
+ elif dict_in_out[v_out][0] == 0 and dict_in_out[v_out][1] == 1:
778
+ # _reset_dg(dg, vertices, dict_in_out, [v_out])
779
+ return _check_special_BC_cases(dg, n, ['C', 'CD'], [None, 1], ['A', 'D'], [[v_out], [v_out]])
783
780
  else:
784
781
  return _false_return()
785
- elif label == (2,-1):
786
- if dict_in_out[ v_out ][0] == 0 and dict_in_out[ v_out ][1] == 1:
787
- #_reset_dg( dg, vertices, dict_in_out, [v_out] )
788
- return _check_special_BC_cases( dg, n, ['B','BD'],[None,1],['A','D'],[[v_out],[v_out]] )
789
- elif dict_in_out[ v_in ][0] == 1 and dict_in_out[ v_in ][1] == 0:
790
- #_reset_dg( dg, vertices, dict_in_out, [v_in] )
791
- return _check_special_BC_cases( dg, n, ['C','CD'],[None,1],['A','D'],[[v_in],[v_in]] )
782
+ elif label == (2, -1):
783
+ if dict_in_out[v_out][0] == 0 and dict_in_out[v_out][1] == 1:
784
+ # _reset_dg(dg, vertices, dict_in_out, [v_out])
785
+ return _check_special_BC_cases(dg, n, ['B', 'BD'], [None, 1], ['A', 'D'], [[v_out], [v_out]])
786
+ elif dict_in_out[v_in][0] == 1 and dict_in_out[v_in][1] == 0:
787
+ # _reset_dg(dg, vertices, dict_in_out, [v_in])
788
+ return _check_special_BC_cases(dg, n, ['C', 'CD'], [None, 1], ['A', 'D'], [[v_in], [v_in]])
792
789
  else:
793
790
  return _false_return()
794
791
 
795
- # if no edges of type (1,-2) nor (2,-1), then tests for type A, affine A, or D.
792
+ # if no edges of type (1, -2) nor (2, -1), then tests for type A, affine A, or D.
796
793
  return _connected_mutation_type_AAtildeD(dg)
797
794
 
798
795
 
799
- def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
796
+ def _connected_mutation_type_AAtildeD(dg: DiGraph, ret_conn_vert=False):
800
797
  """
801
798
  Return mutation type of ClusterQuiver(dg) for DiGraph dg if it is
802
799
  of type finite A, affine A, or finite D.
@@ -829,14 +826,14 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
829
826
 
830
827
  sage: # needs sage.modules
831
828
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _connected_mutation_type_AAtildeD
832
- sage: Q = ClusterQuiver(['A',[7,0],1]); Q.mutate([0,1,4])
833
- sage: _connected_mutation_type_AAtildeD(Q.digraph(),ret_conn_vert=True)
829
+ sage: Q = ClusterQuiver(['A', [7, 0], 1]); Q.mutate([0, 1, 4])
830
+ sage: _connected_mutation_type_AAtildeD(Q.digraph(), ret_conn_vert=True)
834
831
  [['D', 7], [0, 4]]
835
- sage: Q2 = ClusterQuiver(['A',[5,2],1]); Q2.mutate([4,5])
836
- sage: _connected_mutation_type_AAtildeD(Q2.digraph() )
832
+ sage: Q2 = ClusterQuiver(['A', [5, 2], 1]); Q2.mutate([4, 5])
833
+ sage: _connected_mutation_type_AAtildeD(Q2.digraph())
837
834
  ['A', [2, 5], 1]
838
- sage: Q3 = ClusterQuiver(['E',6]); Q3.mutate([5,2,1])
839
- sage: _connected_mutation_type_AAtildeD(Q3.digraph(),ret_conn_vert=True)
835
+ sage: Q3 = ClusterQuiver(['E', 6]); Q3.mutate([5, 2, 1])
836
+ sage: _connected_mutation_type_AAtildeD(Q3.digraph(), ret_conn_vert=True)
840
837
  'unknown'
841
838
  """
842
839
  # naming the vertices
@@ -848,11 +845,11 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
848
845
  # check if any vertices have a neighborhood with two leaves. If so, prune the two leaves and retest on this smaller digraph.
849
846
  # note that this step is unnecessary for digraphs with fewer than four vertices.
850
847
  for v in vertices:
851
- dead_neighbors = [ v_n for v_n in dg.neighbors(v) if dg.degree(v_n) == 1 ]
852
- if len( dead_neighbors ) >= 2:
853
- dg_tmp = DiGraph( dg )
854
- dg_tmp.delete_vertices( dead_neighbors[:2] )
855
- type_tmp = _connected_mutation_type_AAtildeD( dg_tmp, ret_conn_vert=True )
848
+ dead_neighbors = [v_n for v_n in dg.neighbors(v) if dg.degree(v_n) == 1]
849
+ if len(dead_neighbors) >= 2:
850
+ dg_tmp = DiGraph(dg)
851
+ dg_tmp.delete_vertices(dead_neighbors[:2])
852
+ type_tmp = _connected_mutation_type_AAtildeD(dg_tmp, ret_conn_vert=True)
856
853
  if type_tmp == 'unknown':
857
854
  return _false_return()
858
855
  # if smaller digraph is of finite A type with v as a 'connecting vertex', then glueing back the two leaves yields type finite D.
@@ -862,9 +859,9 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
862
859
  if n == 4:
863
860
  type_tmp[1].extend(dead_neighbors[:2])
864
861
  if ret_conn_vert:
865
- return [ QuiverMutationType( ['D',n] ), type_tmp[1] ]
862
+ return [QuiverMutationType(['D', n]), type_tmp[1]]
866
863
  else:
867
- return QuiverMutationType( ['D',n] )
864
+ return QuiverMutationType(['D', n])
868
865
  # note that if v is not a 'connecting vertex' then we make no conclusion either way.
869
866
  else:
870
867
  return _false_return(3)
@@ -873,11 +870,11 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
873
870
 
874
871
  # Exception 1 (Type 2 of D_n)
875
872
  exception_graph1 = DiGraph()
876
- exception_graph1.add_edges([(0,1),(1,2),(2,3),(3,0)])
873
+ exception_graph1.add_edges([(0, 1), (1, 2), (2, 3), (3, 0)])
877
874
 
878
875
  # Exception 2 (Type 3 of D_n)
879
876
  exception_graph2 = DiGraph()
880
- exception_graph2.add_edges([(0,1),(1,2),(0,3),(3,2),(2,0)])
877
+ exception_graph2.add_edges([(0, 1), (1, 2), (0, 3), (3, 2), (2, 0)])
881
878
 
882
879
  # Let c_1 be a pair of 2-valent vertices and c_2 be a pair of two other vertices.
883
880
  # If together, they make an induced 4-cycle and deleting c_1 yields two connected components,
@@ -888,13 +885,13 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
888
885
  # it regardless of orientation. Then check if the digraph has exactly two connected
889
886
  # components, and again this testing method is rerun on both components.
890
887
 
891
- for c1 in Combinations( [ vertex for vertex in vertices if dg.degree(vertex) == 2], 2 ):
892
- del_vertices = list( vertices )
893
- del_vertices.remove( c1[0] )
894
- del_vertices.remove( c1[1] )
895
- for c2 in Combinations( del_vertices, 2 ):
888
+ for c1 in Combinations([vertex for vertex in vertices if dg.degree(vertex) == 2], 2):
889
+ del_vertices = list(vertices)
890
+ del_vertices.remove(c1[0])
891
+ del_vertices.remove(c1[1])
892
+ for c2 in Combinations(del_vertices, 2):
896
893
  comb = c1 + c2
897
- sg = dg.subgraph( comb )
894
+ sg = dg.subgraph(comb)
898
895
 
899
896
  # Exception 1 case (4-cycle):
900
897
  edges = sg.edges(sort=True, labels=False)
@@ -907,19 +904,19 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
907
904
  if len(components) != 2:
908
905
  return _false_return(4)
909
906
  else:
910
- dg_tmp1 = dg_tmp.subgraph( components[0] )
911
- type_tmp1 = _connected_mutation_type_AAtildeD( dg_tmp1, ret_conn_vert=True )
912
- dg_tmp2 = dg_tmp.subgraph( components[1] )
913
- type_tmp2 = _connected_mutation_type_AAtildeD( dg_tmp2, ret_conn_vert=True )
907
+ dg_tmp1 = dg_tmp.subgraph(components[0])
908
+ type_tmp1 = _connected_mutation_type_AAtildeD(dg_tmp1, ret_conn_vert=True)
909
+ dg_tmp2 = dg_tmp.subgraph(components[1])
910
+ type_tmp2 = _connected_mutation_type_AAtildeD(dg_tmp2, ret_conn_vert=True)
914
911
 
915
912
  if type_tmp1 == 'unknown' or type_tmp2 == 'unknown':
916
913
  return _false_return()
917
914
 
918
915
  # Assuming that the two components are recognized, initialize this in a format it can be returned as output
919
916
  type_tmp = []
920
- type_tmp.append( [ type_tmp1[0], type_tmp2[0] ] )
917
+ type_tmp.append([type_tmp1[0], type_tmp2[0]])
921
918
  type_tmp[0].sort(key=str)
922
- type_tmp.append( type_tmp1[1] + type_tmp2[1] )
919
+ type_tmp.append(type_tmp1[1] + type_tmp2[1])
923
920
  type_tmp[1].sort(key=str)
924
921
 
925
922
  # Need to make sure the two vertices in c2 are both 'connecting vertices'.
@@ -929,52 +926,52 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
929
926
  if type_tmp[0][0].letter() == 'A' and type_tmp[0][0].is_finite() and type_tmp[0][1].letter() == 'A' and type_tmp[0][1].is_finite():
930
927
  if ret_conn_vert:
931
928
  type_tmp[1].extend(c1)
932
- #type_tmp[1].remove(c2[0])
933
- #type_tmp[1].remove(c2[1])
934
- return [ QuiverMutationType( ['D',n] ), type_tmp[1] ]
929
+ # type_tmp[1].remove(c2[0])
930
+ # type_tmp[1].remove(c2[1])
931
+ return [QuiverMutationType(['D', n]), type_tmp[1]]
935
932
  else:
936
- return QuiverMutationType( ['D',n] )
933
+ return QuiverMutationType(['D', n])
937
934
 
938
935
  # Exception 2 case (triangulated square):
939
- if sg.is_isomorphic( exception_graph2 ):
940
- dg_tmp = DiGraph( dg )
941
- dg_tmp.delete_vertices( c1 )
942
- if tuple( c2 ) in dg_tmp.edges(sort=True, labels=False):
943
- dg_tmp.delete_edge( tuple( c2 ) )
936
+ if sg.is_isomorphic(exception_graph2):
937
+ dg_tmp = DiGraph(dg)
938
+ dg_tmp.delete_vertices(c1)
939
+ if tuple(c2) in dg_tmp.edges(sort=True, labels=False):
940
+ dg_tmp.delete_edge(tuple(c2))
944
941
  else:
945
942
  c2.reverse()
946
- dg_tmp.delete_edge( tuple( c2 ) )
943
+ dg_tmp.delete_edge(tuple(c2))
947
944
  components = dg_tmp.connected_components(sort=False)
948
945
  if len(components) != 2:
949
946
  return _false_return(7)
950
947
  else:
951
- dg_tmp1 = dg_tmp.subgraph( components[0] )
952
- type_tmp1 = _connected_mutation_type_AAtildeD( dg_tmp1, ret_conn_vert=True )
948
+ dg_tmp1 = dg_tmp.subgraph(components[0])
949
+ type_tmp1 = _connected_mutation_type_AAtildeD(dg_tmp1, ret_conn_vert=True)
953
950
 
954
951
  if type_tmp1 == 'unknown':
955
952
  return _false_return()
956
- dg_tmp2 = dg_tmp.subgraph( components[1] )
957
- type_tmp2 = _connected_mutation_type_AAtildeD( dg_tmp2, ret_conn_vert=True )
953
+ dg_tmp2 = dg_tmp.subgraph(components[1])
954
+ type_tmp2 = _connected_mutation_type_AAtildeD(dg_tmp2, ret_conn_vert=True)
958
955
 
959
956
  # Assuming that the two components are recognized, initialize this in
960
957
  # a format it can be returned as output (just as above)
961
958
  type_tmp = []
962
- type_tmp.append( [ type_tmp1[0], type_tmp2[0] ] )
959
+ type_tmp.append([type_tmp1[0], type_tmp2[0]])
963
960
  type_tmp[0].sort(key=str)
964
- type_tmp.append( type_tmp1[1] + type_tmp2[1] )
961
+ type_tmp.append(type_tmp1[1] + type_tmp2[1])
965
962
  type_tmp[1].sort(key=str)
966
963
  if type_tmp2 == 'unknown':
967
964
  return _false_return()
968
- if not set(c2).issubset(type_tmp[1]) and len( set(type_tmp[1]).intersection(c2) ) == 1:
965
+ if not set(c2).issubset(type_tmp[1]) and len(set(type_tmp[1]).intersection(c2)) == 1:
969
966
  return _false_return(5.5)
970
967
  if type_tmp[0][0].letter() == 'A' and type_tmp[0][0].is_finite() and type_tmp[0][1].letter() == 'A' and type_tmp[0][1].is_finite():
971
968
  if ret_conn_vert:
972
969
  type_tmp[1].remove(c2[0])
973
970
  type_tmp[1].remove(c2[1])
974
- #type_tmp[1].extend(c1)
975
- return [ QuiverMutationType( ['D',n] ), type_tmp[1] ]
971
+ # type_tmp[1].extend(c1)
972
+ return [QuiverMutationType(['D', n]), type_tmp[1]]
976
973
  else:
977
- return QuiverMutationType( ['D',n] )
974
+ return QuiverMutationType(['D', n])
978
975
 
979
976
  # The following tests are done regardless of the number of vertices in dg.
980
977
  # If there are 1, 2, or 3 vertices in dg, we would have skipped above tests and gone directly here.
@@ -987,7 +984,7 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
987
984
  multiple_edges = dg.multiple_edges(labels=False)
988
985
  if len(multiple_edges) > 2:
989
986
  return _false_return(14)
990
- elif len(multiple_edges) == 2:
987
+ if len(multiple_edges) == 2:
991
988
  # we think of the double-edge as a long_cycle, an unoriented 2-cycle.
992
989
  long_cycle = [multiple_edges, ['A', n - 1, 1]]
993
990
 
@@ -997,145 +994,148 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
997
994
  dict_in_out[v] = (dg.in_degree(v), dg.out_degree(v), dg.degree(v))
998
995
 
999
996
  # computing the absolute degree of dg
1000
- abs_deg = max( [ x[2] for x in list( dict_in_out.values() ) ] )
997
+ abs_deg = max([x[2] for x in list(dict_in_out.values())])
1001
998
 
1002
- # edges = dg.edges(sort=True, labels=False )
999
+ # edges = dg.edges(sort=True, labels=False)
1003
1000
 
1004
1001
  # test that no vertex has valency more than 4
1005
1002
  if abs_deg > 4:
1006
1003
  return _false_return(16)
1007
- else:
1008
- # constructing all oriented and unoriented triangles
1009
- trians = _triangles( dg )
1010
- oriented_trians = [ trian[0] for trian in trians if trian[1] ]
1011
- unoriented_trians = [ trian[0] for trian in trians if not trian[1] ]
1012
-
1013
- oriented_trian_edges = []
1014
- for oriented_trian in oriented_trians:
1015
- oriented_trian_edges.extend( oriented_trian )
1016
-
1017
- # test that no edge is in more than two oriented triangles
1018
- multiple_trian_edges = []
1019
- for edge in oriented_trian_edges:
1020
- count = oriented_trian_edges.count(edge)
1021
- if count > 2:
1022
- return _false_return(17)
1023
- elif count == 2:
1024
- multiple_trian_edges.append( edge )
1025
- multiple_trian_edges = list(set(multiple_trian_edges))
1026
-
1027
- # test that there at most three edges appearing in exactly two oriented triangles
1028
- count = len(multiple_trian_edges)
1029
- if count >= 4:
1030
- return _false_return(321)
1031
- # if two edges appearing in exactly two oriented triangles, test that the two edges together
1032
- # determine a unique triangle
1033
- elif count > 1:
1034
- test_triangles = [[tuple(trian) for trian in oriented_trians
1035
- if edge in trian]
1036
- for edge in multiple_trian_edges]
1037
- unique_triangle = set.intersection(*map(set, test_triangles))
1038
- if len(unique_triangle) != 1:
1039
- return _false_return(19)
1040
- else:
1041
- # if a long_cycle had previously been found, this unique oriented triangle is a second long_cycle, a contradiction.
1042
- if long_cycle:
1043
- return _false_return(20)
1044
- else:
1045
- unique_triangle = unique_triangle.pop()
1046
- long_cycle = [ unique_triangle, QuiverMutationType( ['D',n] ) ]
1047
- # if one edge appearing in exactly two oriented triangles, test that it is not a double-edge and then
1048
- # test that either the third or fourth vertices (from the oriented triangles) is of degree 2.
1049
- # Then initializes the long_cycle as this triangle including the degree 2 vertex, as long as no other long_cycles.
1050
- elif count == 1 and not dg.has_multiple_edges() and multiple_trian_edges[0] not in dg.multiple_edges():
1051
- multiple_trian_edge = multiple_trian_edges[0]
1052
- neighbors = list(set(dg.neighbors( multiple_trian_edge[0] )).intersection(dg.neighbors( multiple_trian_edge[1] )))
1053
- if dg.degree( neighbors[0] ) == 2:
1054
- unique_triangle = [ multiple_trian_edge, ( multiple_trian_edge[1], neighbors[0] ), ( neighbors[0], multiple_trian_edge[0] ) ]
1055
- elif dg.degree( neighbors[1] ) == 2:
1056
- unique_triangle = [ multiple_trian_edge, ( multiple_trian_edge[1], neighbors[1] ), ( neighbors[1], multiple_trian_edge[0] ) ]
1057
- else:
1058
- return _false_return(201)
1059
1004
 
1005
+ # constructing all oriented and unoriented triangles
1006
+ trians = _triangles(dg)
1007
+ oriented_trians = [trian[0] for trian in trians if trian[1]]
1008
+ unoriented_trians = [trian[0] for trian in trians if not trian[1]]
1009
+
1010
+ oriented_trian_edges = []
1011
+ for oriented_trian in oriented_trians:
1012
+ oriented_trian_edges.extend(oriented_trian)
1013
+
1014
+ # test that no edge is in more than two oriented triangles
1015
+ from collections import Counter
1016
+ edge_count = Counter(oriented_trian_edges)
1017
+ multiple_trian_edges = []
1018
+ for edge, count in edge_count.items():
1019
+ if count > 2:
1020
+ return _false_return(17)
1021
+ elif count == 2:
1022
+ multiple_trian_edges.append(edge)
1023
+ multiple_trian_edges = list(set(multiple_trian_edges))
1024
+
1025
+ # test that there at most three edges appearing in exactly two
1026
+ # oriented triangles
1027
+ count = len(multiple_trian_edges)
1028
+ if count >= 4:
1029
+ return _false_return(321)
1030
+
1031
+ # if two edges appearing in exactly two oriented triangles, test
1032
+ # that the two edges together determine a unique triangle
1033
+ if count > 1:
1034
+ test_triangles = [[tuple(trian) for trian in oriented_trians
1035
+ if edge in trian]
1036
+ for edge in multiple_trian_edges]
1037
+ unique_triangle_set = set.intersection(*map(set, test_triangles))
1038
+ if len(unique_triangle_set) != 1:
1039
+ return _false_return(19)
1040
+
1041
+ # if a long_cycle had previously been found, this unique oriented triangle is a second long_cycle, a contradiction.
1042
+ if long_cycle:
1043
+ return _false_return(20)
1044
+
1045
+ unique_triangle = unique_triangle_set.pop()
1046
+ long_cycle = [unique_triangle, QuiverMutationType(['D', n])]
1047
+ # if one edge appearing in exactly two oriented triangles, test that it is not a double-edge and then
1048
+ # test that either the third or fourth vertices (from the oriented triangles) is of degree 2.
1049
+ # Then initializes the long_cycle as this triangle including the degree 2 vertex, as long as no other long_cycles.
1050
+ elif count == 1 and not dg.has_multiple_edges() and multiple_trian_edges[0] not in dg.multiple_edges():
1051
+ multiple_trian_edge = multiple_trian_edges[0]
1052
+ neighbors = list(set(dg.neighbors(multiple_trian_edge[0])).intersection(dg.neighbors(multiple_trian_edge[1])))
1053
+ if dg.degree(neighbors[0]) == 2:
1054
+ unique_triangle = [multiple_trian_edge, (multiple_trian_edge[1], neighbors[0]), (neighbors[0], multiple_trian_edge[0])]
1055
+ elif dg.degree(neighbors[1]) == 2:
1056
+ unique_triangle = [multiple_trian_edge, (multiple_trian_edge[1], neighbors[1]), (neighbors[1], multiple_trian_edge[0])]
1057
+ else:
1058
+ return _false_return(201)
1059
+
1060
+ if long_cycle:
1061
+ # if a long_cycle had previously been found, then the specified oriented triangle is a second long_cycle, a contradiction.
1062
+ return _false_return(202)
1063
+ else:
1064
+ long_cycle = [unique_triangle, QuiverMutationType(['D', n])]
1065
+
1066
+ # there can be at most 1 unoriented triangle and this triangle is the exceptional circle of type A_tilde
1067
+ if unoriented_trians:
1068
+ if len(unoriented_trians) == 1:
1060
1069
  if long_cycle:
1061
- # if a long_cycle had previously been found, then the specified oriented triangle is a second long_cycle, a contradiction.
1062
- return _false_return(202)
1070
+ return _false_return(21)
1063
1071
  else:
1064
- long_cycle = [ unique_triangle, QuiverMutationType( ['D',n] ) ]
1072
+ long_cycle = [unoriented_trians[0], ['A', n - 1, 1]]
1073
+ else:
1074
+ return _false_return(22)
1065
1075
 
1066
- # there can be at most 1 unoriented triangle and this triangle is the exceptional circle of type A_tilde
1067
- if unoriented_trians:
1068
- if len(unoriented_trians) == 1:
1069
- if long_cycle:
1070
- return _false_return(21)
1071
- else:
1072
- long_cycle = [ unoriented_trians[0], ['A',n-1,1] ]
1076
+ for v in vertices:
1077
+ w = dict_in_out[v]
1078
+ if w[2] == 4:
1079
+ # if a vertex has valency 4 than the 4 neighboring edges must be contained in 2 oriented triangles
1080
+ if w[0] != 2:
1081
+ return _false_return(23)
1073
1082
  else:
1074
- return _false_return(22)
1075
-
1076
- for v in vertices:
1077
- w = dict_in_out[v]
1078
- if w[2] == 4:
1079
- # if a vertex has valency 4 than the 4 neighboring edges must be contained in 2 oriented triangles
1080
- if w[0] != 2:
1081
- return _false_return(23)
1083
+ in_neighbors = dg.neighbors_in(v)
1084
+ out_neighbors = dg.neighbors_out(v)
1085
+ if len(out_neighbors) == 1:
1086
+ out_neighbors.extend(out_neighbors)
1087
+ if len(in_neighbors) == 1:
1088
+ in_neighbors.extend(in_neighbors)
1089
+
1090
+ if (in_neighbors[0], v) not in oriented_trian_edges:
1091
+ return _false_return(24)
1092
+ elif (in_neighbors[1], v) not in oriented_trian_edges:
1093
+ return _false_return(25)
1094
+ elif (v, out_neighbors[0]) not in oriented_trian_edges:
1095
+ return _false_return(26)
1096
+ elif (v, out_neighbors[1]) not in oriented_trian_edges:
1097
+ return _false_return(27)
1098
+
1099
+ # if a vertex has valency 3 than 2 of its neighboring edges must be contained in an oriented triangle and the remaining must not
1100
+ elif w[2] == 3:
1101
+ if w[0] == 1:
1102
+ in_neighbors = dg.neighbors_in(v)
1103
+ out_neighbors = dg.neighbors_out(v)
1104
+ if (in_neighbors[0], v) not in oriented_trian_edges:
1105
+ return _false_return(28)
1106
+ elif len(out_neighbors) == 1:
1107
+ if (v, out_neighbors[0]) not in oriented_trian_edges:
1108
+ return _false_return(29)
1082
1109
  else:
1083
- in_neighbors = dg.neighbors_in( v )
1084
- out_neighbors = dg.neighbors_out( v )
1085
- if len( out_neighbors ) == 1:
1086
- out_neighbors.extend(out_neighbors)
1087
- if len( in_neighbors ) == 1:
1088
- in_neighbors.extend(in_neighbors)
1089
-
1110
+ if (v, out_neighbors[0]) in oriented_trian_edges and (v, out_neighbors[1]) in oriented_trian_edges:
1111
+ if not long_cycle:
1112
+ return _false_return(30)
1113
+ if not long_cycle[1] == QuiverMutationType(['D', n]):
1114
+ return _false_return(31)
1115
+ if (v, out_neighbors[0]) not in long_cycle[0] and (v, out_neighbors[1]) not in long_cycle[0]:
1116
+ return _false_return(32)
1117
+ if (v, out_neighbors[0]) not in oriented_trian_edges and (v, out_neighbors[1]) not in oriented_trian_edges:
1118
+ return _false_return(33)
1119
+ elif w[0] == 2:
1120
+ in_neighbors = dg.neighbors_in(v)
1121
+ out_neighbors = dg.neighbors_out(v)
1122
+ if (v, out_neighbors[0]) not in oriented_trian_edges:
1123
+ return _false_return(34)
1124
+ elif len(in_neighbors) == 1:
1090
1125
  if (in_neighbors[0], v) not in oriented_trian_edges:
1091
- return _false_return(24)
1092
- elif (in_neighbors[1], v) not in oriented_trian_edges:
1093
- return _false_return(25)
1094
- elif (v, out_neighbors[0]) not in oriented_trian_edges:
1095
- return _false_return(26)
1096
- elif (v, out_neighbors[1]) not in oriented_trian_edges:
1097
- return _false_return(27)
1098
-
1099
- # if a vertex has valency 3 than 2 of its neighboring edges must be contained in an oriented triangle and the remaining must not
1100
- elif w[2] == 3:
1101
- if w[0] == 1:
1102
- in_neighbors = dg.neighbors_in( v )
1103
- out_neighbors = dg.neighbors_out( v )
1104
- if (in_neighbors[0],v) not in oriented_trian_edges:
1105
- return _false_return(28)
1106
- elif len( out_neighbors ) == 1:
1107
- if (v,out_neighbors[0]) not in oriented_trian_edges:
1108
- return _false_return(29)
1109
- else:
1110
- if (v,out_neighbors[0]) in oriented_trian_edges and (v,out_neighbors[1]) in oriented_trian_edges:
1111
- if not long_cycle:
1112
- return _false_return(30)
1113
- if not long_cycle[1] == QuiverMutationType(['D',n]):
1114
- return _false_return(31)
1115
- if (v, out_neighbors[0]) not in long_cycle[0] and (v, out_neighbors[1]) not in long_cycle[0]:
1116
- return _false_return(32)
1117
- if (v,out_neighbors[0]) not in oriented_trian_edges and (v,out_neighbors[1]) not in oriented_trian_edges:
1118
- return _false_return(33)
1119
- elif w[0] == 2:
1120
- in_neighbors = dg.neighbors_in( v )
1121
- out_neighbors = dg.neighbors_out( v )
1122
- if (v, out_neighbors[0]) not in oriented_trian_edges:
1123
- return _false_return(34)
1124
- elif len( in_neighbors ) == 1:
1125
- if (in_neighbors[0],v) not in oriented_trian_edges:
1126
- return _false_return(35)
1127
- else:
1128
- if (in_neighbors[0],v) in oriented_trian_edges and (in_neighbors[1],v) in oriented_trian_edges:
1129
- if not long_cycle:
1130
- return _false_return(36)
1131
- if not long_cycle[1] == QuiverMutationType(['D',n]):
1132
- return _false_return(37)
1133
- if (in_neighbors[0], v) not in long_cycle[0] and (in_neighbors[1], v) not in long_cycle[0]:
1134
- return _false_return(38)
1135
- if (in_neighbors[0], v) not in oriented_trian_edges and (in_neighbors[1], v) not in oriented_trian_edges:
1136
- return _false_return(39)
1126
+ return _false_return(35)
1137
1127
  else:
1138
- return _false_return(40)
1128
+ if (in_neighbors[0], v) in oriented_trian_edges and (in_neighbors[1], v) in oriented_trian_edges:
1129
+ if not long_cycle:
1130
+ return _false_return(36)
1131
+ if not long_cycle[1] == QuiverMutationType(['D', n]):
1132
+ return _false_return(37)
1133
+ if (in_neighbors[0], v) not in long_cycle[0] and (in_neighbors[1], v) not in long_cycle[0]:
1134
+ return _false_return(38)
1135
+ if (in_neighbors[0], v) not in oriented_trian_edges and (in_neighbors[1], v) not in oriented_trian_edges:
1136
+ return _false_return(39)
1137
+ else:
1138
+ return _false_return(40)
1139
1139
 
1140
1140
  # there can exist at most one larger oriented or unoriented induced cycle
1141
1141
  # if it is oriented, we are in finite type D, otherwise we are in affine type A
@@ -1143,15 +1143,15 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
1143
1143
  # Above code found long_cycles would be an unoriented 2-cycle or an oriented triangle.
1144
1144
  # The method _all_induced_cycles_iter only looks for induced cycles on 4 or more vertices.
1145
1145
 
1146
- for cycle, is_oriented in _all_induced_cycles_iter( dg ):
1146
+ for cycle, is_oriented in _all_induced_cycles_iter(dg):
1147
1147
  # if there already was a long_cycle and we found another one, then have a contradiction.
1148
1148
  if long_cycle:
1149
1149
  return _false_return(41)
1150
1150
  # otherwise, we obtain cases depending on whether or not the found long_cycle is oriented.
1151
1151
  elif is_oriented:
1152
- long_cycle = [ cycle, QuiverMutationType(['D',n]) ]
1152
+ long_cycle = [cycle, QuiverMutationType(['D', n])]
1153
1153
  else:
1154
- long_cycle = [ cycle, ['A',n-1,1] ]
1154
+ long_cycle = [cycle, ['A', n - 1, 1]]
1155
1155
  # if we haven't found a "long_cycle", we are in finite type A
1156
1156
  if not long_cycle:
1157
1157
  long_cycle = [[], QuiverMutationType(['A', n])]
@@ -1161,24 +1161,24 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
1161
1161
  # this is not caught here.
1162
1162
  if ret_conn_vert:
1163
1163
  connecting_vertices = []
1164
- o_trian_verts = flatten( oriented_trian_edges )
1165
- long_cycle_verts = flatten( long_cycle[0] )
1164
+ o_trian_verts = flatten(oriented_trian_edges)
1165
+ long_cycle_verts = flatten(long_cycle[0])
1166
1166
  for v in vertices:
1167
1167
  w = dict_in_out[v]
1168
1168
  # if the quiver consists of only one vertex, it is of type A_1 and the vertex is a connecting vertex
1169
1169
  if w[2] == 0:
1170
- connecting_vertices.append( v )
1170
+ connecting_vertices.append(v)
1171
1171
  # if a vertex is a leaf in a type A quiver, it is a connecting vertex
1172
1172
  elif w[2] == 1:
1173
- connecting_vertices.append( v )
1173
+ connecting_vertices.append(v)
1174
1174
  # if a vertex is of valence two and contained in an oriented 3-cycle, it is a connecting vertex
1175
1175
  elif w[0] == 1 and w[1] == 1:
1176
1176
  if v in o_trian_verts and v not in long_cycle_verts:
1177
- connecting_vertices.append( v )
1177
+ connecting_vertices.append(v)
1178
1178
 
1179
1179
  # post-parsing 1: if we are in the affine type A case, the two parameters for the non-oriented long cycle are computed
1180
- if isinstance(long_cycle[1], list) and len( long_cycle[1] ) == 3 and long_cycle[1][0] == 'A' and long_cycle[1][2] == 1:
1181
- tmp = list( long_cycle[0] )
1180
+ if isinstance(long_cycle[1], list) and len(long_cycle[1]) == 3 and long_cycle[1][0] == 'A' and long_cycle[1][2] == 1:
1181
+ tmp = list(long_cycle[0])
1182
1182
  e = tmp.pop()
1183
1183
  cycle = [e]
1184
1184
  v = e[1]
@@ -1189,52 +1189,51 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False):
1189
1189
  v = e[1]
1190
1190
  else:
1191
1191
  v = e[0]
1192
- tmp.remove( e )
1192
+ tmp.remove(e)
1193
1193
 
1194
- tmp = list( cycle )
1195
- if len( long_cycle[0] ) == 2:
1194
+ tmp = list(cycle)
1195
+ if len(long_cycle[0]) == 2:
1196
1196
  edge = long_cycle[0][0]
1197
- sg = DiGraph( dg )
1197
+ sg = DiGraph(dg)
1198
1198
  sg. delete_vertices(edge)
1199
1199
  connected_components = sg.connected_components(sort=False)
1200
1200
  cycle = []
1201
1201
  if connected_components:
1202
- cycle.append( ( edge[0], edge[1], len( connected_components[0] ) + 1 ) )
1202
+ cycle.append((edge[0], edge[1], len(connected_components[0]) + 1))
1203
1203
  else:
1204
- cycle.append( ( edge[0], edge[1], 1 ) )
1204
+ cycle.append((edge[0], edge[1], 1))
1205
1205
  else:
1206
1206
  for edge in tmp:
1207
- sg = DiGraph( dg )
1207
+ sg = DiGraph(dg)
1208
1208
  sg. delete_vertices(edge)
1209
1209
  connected_components = sg.connected_components(sort=False)
1210
- if len( connected_components ) == 2:
1211
- #if len( list_intersection( [ connected_components[0], list_substract( long_cycle[0], [edge] )[0] ] ) ) > 0:
1212
- if len( set(connected_components[0]).intersection( set(long_cycle[0]).difference([edge]).pop() ) ) > 0:
1210
+ if len(connected_components) == 2:
1211
+ # if len(list_intersection([connected_components[0], list_substract(long_cycle[0], [edge])[0]])) > 0:
1212
+ if len(set(connected_components[0]).intersection(set(long_cycle[0]).difference([edge]).pop())) > 0:
1213
1213
  cycle.remove(edge)
1214
- cycle.append( (edge[0],edge[1], len( connected_components[1] ) + 1 ) )
1214
+ cycle.append((edge[0], edge[1], len(connected_components[1]) + 1))
1215
1215
  else:
1216
1216
  cycle.remove(edge)
1217
- cycle.append( (edge[0],edge[1], len( connected_components[0] ) + 1 ) )
1217
+ cycle.append((edge[0], edge[1], len(connected_components[0]) + 1))
1218
1218
  else:
1219
1219
  cycle.remove(edge)
1220
- cycle.append( (edge[0],edge[1], 1 ) )
1220
+ cycle.append((edge[0], edge[1], 1))
1221
1221
  r = sum(x[2] for x in cycle)
1222
1222
  r = max(r, n - r)
1223
1223
  if ret_conn_vert:
1224
- return [ QuiverMutationType( ['A',[r,n-r],1] ), connecting_vertices ]
1225
- else:
1226
- return QuiverMutationType( ['A',[r,n-r],1] )
1224
+ return [QuiverMutationType(['A', [r, n - r], 1]),
1225
+ connecting_vertices]
1226
+ return QuiverMutationType(['A', [r, n - r], 1])
1227
1227
 
1228
1228
  # post-parsing 2: if we are in another type, it is returned
1229
1229
  else:
1230
1230
  if ret_conn_vert:
1231
- return [ long_cycle[1], connecting_vertices ]
1232
- else:
1233
- return long_cycle[1]
1231
+ return [long_cycle[1], connecting_vertices]
1232
+ return long_cycle[1]
1234
1233
 
1235
1234
 
1236
1235
  @cached_function
1237
- def load_data(n, user=True):
1236
+ def load_data(n: int, user=True) -> dict:
1238
1237
  r"""
1239
1238
  Load a dict with keys being tuples representing exceptional
1240
1239
  QuiverMutationTypes, and with values being lists or sets
@@ -1254,28 +1253,28 @@ def load_data(n, user=True):
1254
1253
 
1255
1254
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import load_data
1256
1255
  sage: load_data(2) # random - depends on the data the user has stored
1257
- {('G', 2): [('AO', (((0, 1), (1, -3)),)), ('AO', (((0, 1), (3, -1)),))]}
1256
+ {('G', 2): [('AO', (((0, 1), (1, -3)), )), ('AO', (((0, 1), (3, -1)), ))]}
1258
1257
 
1259
1258
  TESTS:
1260
1259
 
1261
1260
  We test data from the ``database_mutation_class`` optional package::
1262
1261
 
1263
1262
  sage: load_data(2, user=False) # optional - database_mutation_class
1264
- {('G', 2): [('AO', (((0, 1), (1, -3)),)), ('AO', (((0, 1), (3, -1)),))]}
1263
+ {('G', 2): [('AO', (((0, 1), (1, -3)), )), ('AO', (((0, 1), (3, -1)), ))]}
1265
1264
  sage: D = load_data(3, user=False) # optional - database_mutation_class
1266
1265
  sage: sorted(D.items()) # optional - database_mutation_class
1267
1266
  [(('G', 2, -1),
1268
- [('BH?', (((1, 2), (1, -3)),)),
1269
- ('BGO', (((2, 1), (3, -1)),)),
1270
- ('BW?', (((0, 1), (3, -1)),)),
1271
- ('BP?', (((0, 1), (1, -3)),)),
1267
+ [('BH?', (((1, 2), (1, -3)), )),
1268
+ ('BGO', (((2, 1), (3, -1)), )),
1269
+ ('BW?', (((0, 1), (3, -1)), )),
1270
+ ('BP?', (((0, 1), (1, -3)), )),
1272
1271
  ('BP_', (((0, 1), (1, -3)), ((2, 0), (3, -1)))),
1273
1272
  ('BP_', (((0, 1), (3, -1)), ((1, 2), (1, -3)), ((2, 0), (2, -2))))]),
1274
1273
  (('G', 2, 1),
1275
- [('BH?', (((1, 2), (3, -1)),)),
1276
- ('BGO', (((2, 1), (1, -3)),)),
1277
- ('BW?', (((0, 1), (1, -3)),)),
1278
- ('BP?', (((0, 1), (3, -1)),)),
1274
+ [('BH?', (((1, 2), (3, -1)), )),
1275
+ ('BGO', (((2, 1), (1, -3)), )),
1276
+ ('BW?', (((0, 1), (1, -3)), )),
1277
+ ('BP?', (((0, 1), (3, -1)), )),
1279
1278
  ('BKO', (((1, 0), (3, -1)), ((2, 1), (1, -3)))),
1280
1279
  ('BP_', (((0, 1), (2, -2)), ((1, 2), (1, -3)), ((2, 0), (3, -1))))])]
1281
1280
  """
@@ -1301,10 +1300,10 @@ def load_data(n, user=True):
1301
1300
  return data
1302
1301
 
1303
1302
 
1304
- def _mutation_type_from_data(n, dig6, compute_if_necessary=True):
1303
+ def _mutation_type_from_data(n: int, dig6, compute_if_necessary=True):
1305
1304
  r"""
1306
1305
  Return the mutation type from the given dig6 data by looking into
1307
- the precomputed mutation types
1306
+ the precomputed mutation types.
1308
1307
 
1309
1308
  Attention: it is assumed that dig6 is the dig6 data of the
1310
1309
  canonical form of the given quiver!
@@ -1315,10 +1314,10 @@ def _mutation_type_from_data(n, dig6, compute_if_necessary=True):
1315
1314
  sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _digraph_to_dig6
1316
1315
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _mutation_type_from_data
1317
1316
  sage: from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver
1318
- sage: dg = ClusterQuiver(['F',4]).canonical_label().digraph()
1319
- sage: dig6 = _digraph_to_dig6(dg,hashable=True); dig6
1317
+ sage: dg = ClusterQuiver(['F', 4]).canonical_label().digraph()
1318
+ sage: dig6 = _digraph_to_dig6(dg, hashable=True); dig6
1320
1319
  ('CCo?', (((1, 3), (2, -1)),))
1321
- sage: _mutation_type_from_data(4,dig6)
1320
+ sage: _mutation_type_from_data(4, dig6)
1322
1321
  ['F', 4]
1323
1322
  """
1324
1323
  # we try to load the data from a library
@@ -1331,8 +1330,8 @@ def _mutation_type_from_data(n, dig6, compute_if_necessary=True):
1331
1330
  data = load_data(n)
1332
1331
  # finally, we check if the given quiver is in one of the exceptional mutation classes
1333
1332
  for mutation_type in data:
1334
- if dig6 in data[ mutation_type ]:
1335
- return QuiverMutationType( mutation_type )
1333
+ if dig6 in data[mutation_type]:
1334
+ return QuiverMutationType(mutation_type)
1336
1335
  return 'unknown'
1337
1336
 
1338
1337
 
@@ -1401,17 +1400,17 @@ def _mutation_type_test(n):
1401
1400
  from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _construct_classical_mutation_classes
1402
1401
  from sage.combinat.cluster_algebra_quiver.mutation_class import _dig6_to_digraph
1403
1402
  from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver
1404
- data = _construct_classical_mutation_classes( n )
1403
+ data = _construct_classical_mutation_classes(n)
1405
1404
  keys = data.keys()
1406
1405
  for mutation_type in sorted(keys, key=str):
1407
- mt = QuiverMutationType( mutation_type )
1408
- print(all( ClusterQuiver(_dig6_to_digraph(dig6)).mutation_type() == mt for dig6 in data[mutation_type]), mutation_type)
1406
+ mt = QuiverMutationType(mutation_type)
1407
+ print(all(ClusterQuiver(_dig6_to_digraph(dig6)).mutation_type() == mt for dig6 in data[mutation_type]), mutation_type)
1409
1408
  from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _construct_exceptional_mutation_classes
1410
- data = _construct_exceptional_mutation_classes( n )
1409
+ data = _construct_exceptional_mutation_classes(n)
1411
1410
  keys = data.keys()
1412
1411
  for mutation_type in sorted(keys, key=str):
1413
- mt = QuiverMutationType( mutation_type )
1414
- print(all( ClusterQuiver(_dig6_to_digraph(dig6)).mutation_type() == mt for dig6 in data[mutation_type]), mutation_type)
1412
+ mt = QuiverMutationType(mutation_type)
1413
+ print(all(ClusterQuiver(_dig6_to_digraph(dig6)).mutation_type() == mt for dig6 in data[mutation_type]), mutation_type)
1415
1414
 
1416
1415
 
1417
1416
  def _random_tests(mt, k, mut_class=None, nr_mut=5):
@@ -1436,7 +1435,7 @@ def _random_tests(mt, k, mut_class=None, nr_mut=5):
1436
1435
  TESTS::
1437
1436
 
1438
1437
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _random_tests
1439
- sage: _random_tests( ['A',3], 1) # needs sage.modules
1438
+ sage: _random_tests(['A', 3], 1) # needs sage.modules
1440
1439
  testing ['A', 3]
1441
1440
  """
1442
1441
  from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver
@@ -1446,15 +1445,15 @@ def _random_tests(mt, k, mut_class=None, nr_mut=5):
1446
1445
  mut_class = ClusterQuiver(mt).mutation_class(data_type='dig6')
1447
1446
  print("testing " + str(mt))
1448
1447
  for dig6 in mut_class:
1449
- M_const = _dig6_to_matrix( dig6 )
1450
- nz = [ (i,j) for i,j in M_const.nonzero_positions() if i > j ]
1448
+ M_const = _dig6_to_matrix(dig6)
1449
+ nz = [(i, j) for i, j in M_const.nonzero_positions() if i > j]
1451
1450
  # performing k tests on the matrix M_const
1452
1451
  for i in range(k):
1453
- M = copy( M_const )
1454
- # every pair M[i,j],M[j,i] is possibly changed
1452
+ M = copy(M_const)
1453
+ # every pair M[i, j], M[j, i] is possibly changed
1455
1454
  # while the property of being skew-symmetrizable is kept
1456
- for i,j in nz:
1457
- a,b = M[i,j],M[j,i]
1455
+ for i, j in nz:
1456
+ a, b = M[i, j], M[j, i]
1458
1457
  skew_sym = False
1459
1458
  while not skew_sym:
1460
1459
  ran = random.randint(1, 2)
@@ -1521,13 +1520,13 @@ def _random_multi_tests(n, k, nr_mut=5):
1521
1520
  TESTS::
1522
1521
 
1523
1522
  sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _random_multi_tests
1524
- sage: _random_multi_tests(2,1) # not tested
1523
+ sage: _random_multi_tests(2, 1) # not tested
1525
1524
  testing ('A', (1, 1), 1)
1526
1525
  testing ('A', 2)
1527
1526
  testing ('B', 2)
1528
1527
  testing ('BC', 1, 1)
1529
1528
 
1530
- sage: _random_multi_tests(3,1) # not tested
1529
+ sage: _random_multi_tests(3, 1) # not tested
1531
1530
  testing ('A', (2, 1), 1)
1532
1531
  testing ('A', 3)
1533
1532
  testing ('B', 3)
@@ -1536,7 +1535,7 @@ def _random_multi_tests(n, k, nr_mut=5):
1536
1535
  testing ('C', 3)
1537
1536
  testing ('CC', 2, 1)
1538
1537
 
1539
- sage: _random_multi_tests(4,1) # not tested
1538
+ sage: _random_multi_tests(4, 1) # not tested
1540
1539
  testing ('A', (2, 2), 1)
1541
1540
  testing ('A', (3, 1), 1)
1542
1541
  testing ('A', 4)