passagemath-graphs 10.5.43__cp311-cp311-macosx_14_0_arm64.whl → 10.6.1rc2__cp311-cp311-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.
- {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/METADATA +5 -6
- {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/RECORD +132 -130
- sage/combinat/abstract_tree.py +188 -17
- sage/combinat/cluster_algebra_quiver/interact.py +1 -2
- sage/combinat/cluster_algebra_quiver/mutation_type.py +518 -519
- sage/combinat/cluster_algebra_quiver/quiver.py +233 -205
- sage/combinat/designs/covering_design.py +2 -6
- sage/combinat/designs/database.py +11 -10
- sage/combinat/designs/designs_pyx.cpython-311-darwin.so +0 -0
- sage/combinat/designs/designs_pyx.pyx +2 -2
- sage/combinat/designs/evenly_distributed_sets.cpython-311-darwin.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +4 -4
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-311-darwin.so +0 -0
- sage/combinat/designs/latin_squares.py +53 -20
- sage/combinat/designs/orthogonal_arrays.py +2 -1
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-311-darwin.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +22 -21
- sage/combinat/designs/resolvable_bibd.py +191 -157
- sage/combinat/designs/subhypergraph_search.cpython-311-darwin.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +4 -4
- sage/combinat/designs/twographs.py +2 -2
- sage/combinat/finite_state_machine.py +6 -6
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/d_complete.py +3 -3
- sage/combinat/posets/elements.py +3 -3
- sage/combinat/posets/hasse_cython.cpython-311-darwin.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +1 -1
- sage/combinat/posets/hasse_diagram.py +16 -22
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +14 -16
- sage/combinat/posets/lattices.py +51 -53
- sage/combinat/posets/linear_extension_iterator.cpython-311-darwin.so +0 -0
- sage/combinat/posets/linear_extensions.py +10 -12
- sage/combinat/posets/moebius_algebra.py +4 -4
- sage/combinat/posets/poset_examples.py +70 -23
- sage/combinat/posets/posets.py +294 -103
- sage/databases/knotinfo_db.py +2 -1
- sage/graphs/asteroidal_triples.cpython-311-darwin.so +0 -0
- sage/graphs/asteroidal_triples.pyx +24 -3
- sage/graphs/base/boost_graph.cpython-311-darwin.so +0 -0
- sage/graphs/base/boost_graph.pxd +3 -3
- sage/graphs/base/c_graph.cpython-311-darwin.so +0 -0
- sage/graphs/base/c_graph.pyx +1 -1
- sage/graphs/base/dense_graph.cpython-311-darwin.so +0 -0
- sage/graphs/base/dense_graph.pxd +5 -3
- sage/graphs/base/dense_graph.pyx +44 -0
- sage/graphs/base/graph_backends.cpython-311-darwin.so +0 -0
- sage/graphs/base/sparse_graph.cpython-311-darwin.so +0 -0
- sage/graphs/base/static_dense_graph.cpython-311-darwin.so +0 -0
- sage/graphs/base/static_sparse_backend.cpython-311-darwin.so +0 -0
- sage/graphs/base/static_sparse_backend.pyx +8 -5
- sage/graphs/base/static_sparse_graph.cpython-311-darwin.so +0 -0
- sage/graphs/base/static_sparse_graph.pyx +86 -15
- sage/graphs/bipartite_graph.py +59 -36
- sage/graphs/centrality.cpython-311-darwin.so +0 -0
- sage/graphs/centrality.pyx +82 -9
- sage/graphs/cographs.py +1 -1
- sage/graphs/comparability.cpython-311-darwin.so +0 -0
- sage/graphs/comparability.pyx +64 -26
- sage/graphs/connectivity.cpython-311-darwin.so +0 -0
- sage/graphs/convexity_properties.cpython-311-darwin.so +0 -0
- sage/graphs/convexity_properties.pyx +52 -9
- sage/graphs/digraph.py +439 -95
- sage/graphs/digraph_generators.py +174 -102
- sage/graphs/distances_all_pairs.cpython-311-darwin.so +0 -0
- sage/graphs/dot2tex_utils.py +1 -1
- sage/graphs/edge_connectivity.cpython-311-darwin.so +0 -0
- sage/graphs/generators/basic.py +1 -1
- sage/graphs/generators/distance_regular.cpython-311-darwin.so +0 -0
- sage/graphs/generators/distance_regular.pyx +1 -1
- sage/graphs/generators/families.py +37 -27
- sage/graphs/generators/random.py +2 -2
- sage/graphs/generators/smallgraphs.py +3 -3
- sage/graphs/generic_graph.py +558 -86
- sage/graphs/generic_graph_pyx.cpython-311-darwin.so +0 -0
- sage/graphs/generic_graph_pyx.pyx +58 -11
- sage/graphs/genus.cpython-311-darwin.so +0 -0
- sage/graphs/genus.pyx +3 -4
- sage/graphs/graph.py +291 -8
- sage/graphs/graph_coloring.cpython-311-darwin.so +0 -0
- sage/graphs/graph_database.py +67 -12
- sage/graphs/graph_decompositions/bandwidth.cpython-311-darwin.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-311-darwin.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +24 -3
- sage/graphs/graph_decompositions/cutwidth.cpython-311-darwin.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-311-darwin.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +1 -1
- sage/graphs/graph_decompositions/graph_products.cpython-311-darwin.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +67 -21
- sage/graphs/graph_decompositions/modular_decomposition.cpython-311-darwin.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-311-darwin.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +34 -8
- sage/graphs/graph_decompositions/tree_decomposition.cpython-311-darwin.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-311-darwin.so +0 -0
- sage/graphs/graph_generators.py +45 -32
- sage/graphs/graph_generators_pyx.cpython-311-darwin.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +15 -15
- sage/graphs/graph_latex.py +1 -1
- sage/graphs/graph_list.py +52 -9
- sage/graphs/graph_plot.py +7 -0
- sage/graphs/hyperbolicity.cpython-311-darwin.so +0 -0
- sage/graphs/hyperbolicity.pyx +2 -0
- sage/graphs/independent_sets.cpython-311-darwin.so +0 -0
- sage/graphs/isoperimetric_inequalities.cpython-311-darwin.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +42 -6
- sage/graphs/line_graph.cpython-311-darwin.so +0 -0
- sage/graphs/line_graph.pyx +153 -37
- sage/graphs/matching_covered_graph.py +84 -60
- sage/graphs/orientations.py +3 -18
- sage/graphs/path_enumeration.cpython-311-darwin.so +0 -0
- sage/graphs/path_enumeration.pyx +2 -2
- sage/graphs/spanning_tree.cpython-311-darwin.so +0 -0
- sage/graphs/strongly_regular_db.cpython-311-darwin.so +0 -0
- sage/graphs/strongly_regular_db.pyx +15 -15
- sage/graphs/traversals.cpython-311-darwin.so +0 -0
- sage/graphs/traversals.pyx +13 -12
- sage/graphs/trees.cpython-311-darwin.so +0 -0
- sage/graphs/tutte_polynomial.py +1 -1
- sage/graphs/views.cpython-311-darwin.so +0 -0
- sage/graphs/weakly_chordal.cpython-311-darwin.so +0 -0
- sage/graphs/weakly_chordal.pyx +50 -8
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-311-darwin.so +0 -0
- sage/knots/free_knotinfo_monoid.py +3 -3
- sage/knots/knotinfo.py +102 -82
- sage/knots/link.py +72 -39
- sage/topology/cubical_complex.py +4 -5
- sage/topology/delta_complex.py +4 -4
- sage/topology/simplicial_complex.py +0 -1
- sage/topology/simplicial_complex_catalog.py +6 -0
- sage/topology/simplicial_complex_examples.py +4 -16
- {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/WHEEL +0 -0
- {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/top_level.txt +0 -0
@@ -28,7 +28,10 @@ AUTHORS:
|
|
28
28
|
- Gregg Musiker
|
29
29
|
- Christian Stump
|
30
30
|
|
31
|
-
.. SEEALSO::
|
31
|
+
.. SEEALSO::
|
32
|
+
|
33
|
+
For mutation types of combinatorial quivers, see :meth:`~sage.combinat.cluster_algebra_quiver.quiver_mutation_type.QuiverMutationType`.
|
34
|
+
Cluster seeds are closely related to :meth:`~sage.combinat.cluster_algebra_quiver.cluster_seed.ClusterSeed`.
|
32
35
|
"""
|
33
36
|
# ****************************************************************************
|
34
37
|
# Copyright (C) 2011 Gregg Musiker <musiker@math.mit.edu>
|
@@ -40,22 +43,21 @@ AUTHORS:
|
|
40
43
|
from copy import copy
|
41
44
|
from itertools import product
|
42
45
|
|
43
|
-
from sage.structure.sage_object import SageObject
|
44
|
-
from sage.rings.integer_ring import ZZ
|
45
|
-
from sage.rings.infinity import infinity
|
46
|
-
from sage.graphs.digraph import DiGraph
|
47
|
-
from sage.graphs.graph import Graph
|
48
|
-
from sage.graphs.views import EdgesView
|
49
46
|
from sage.arith.misc import gcd
|
50
|
-
from sage.misc.misc_c import prod
|
51
|
-
from sage.misc.lazy_import import lazy_import
|
52
|
-
from sage.rings.rational_field import QQ
|
53
|
-
from sage.rings.polynomial.polynomial_ring import polygen
|
54
47
|
from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType, QuiverMutationType_Irreducible, QuiverMutationType_Reducible, _edge_list_to_matrix
|
55
48
|
from sage.combinat.cluster_algebra_quiver.mutation_class import _principal_part, _digraph_mutate, _matrix_to_digraph, _dg_canonical_form, _mutation_class_iter, _digraph_to_dig6, _dig6_to_matrix
|
56
49
|
from sage.combinat.cluster_algebra_quiver.mutation_type import _connected_mutation_type, _mutation_type_from_data, is_mutation_finite
|
57
|
-
|
58
50
|
from sage.combinat.cluster_algebra_quiver.interact import cluster_interact
|
51
|
+
from sage.graphs.digraph import DiGraph
|
52
|
+
from sage.graphs.graph import Graph
|
53
|
+
from sage.graphs.views import EdgesView
|
54
|
+
from sage.misc.lazy_import import lazy_import
|
55
|
+
from sage.misc.misc_c import prod
|
56
|
+
from sage.rings.infinity import infinity
|
57
|
+
from sage.rings.integer_ring import ZZ
|
58
|
+
from sage.rings.polynomial.polynomial_ring import polygen
|
59
|
+
from sage.rings.rational_field import QQ
|
60
|
+
from sage.structure.sage_object import SageObject
|
59
61
|
|
60
62
|
lazy_import('sage.modules.free_module_element', 'vector')
|
61
63
|
lazy_import('sage.matrix.constructor', 'matrix')
|
@@ -69,12 +71,18 @@ class ClusterQuiver(SageObject):
|
|
69
71
|
|
70
72
|
- ``data`` -- can be any of the following::
|
71
73
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
- :class:`QuiverMutationType`
|
75
|
+
|
76
|
+
- :class:`str` -- string representing a :class:`QuiverMutationType`
|
77
|
+
or a common quiver type (see Examples)
|
78
|
+
|
79
|
+
- :class:`ClusterQuiver`
|
80
|
+
|
81
|
+
- :class:`Matrix` -- a skew-symmetrizable matrix
|
82
|
+
|
83
|
+
- :class:`DiGraph` -- must be the input data for a quiver
|
84
|
+
|
85
|
+
- List of edges -- must be the edge list of a digraph for a quiver
|
78
86
|
|
79
87
|
- ``frozen`` -- (default: ``None``) sets the list of frozen variables
|
80
88
|
if the input type is a :class:`DiGraph`, it is ignored otherwise
|
@@ -148,30 +156,30 @@ class ClusterQuiver(SageObject):
|
|
148
156
|
|
149
157
|
sage: Q = ClusterQuiver(['A',[2,5],1]); Q
|
150
158
|
Quiver on 7 vertices of type ['A', [2, 5], 1]
|
151
|
-
sage: T = ClusterQuiver(
|
159
|
+
sage: T = ClusterQuiver(Q); T
|
152
160
|
Quiver on 7 vertices of type ['A', [2, 5], 1]
|
153
161
|
|
154
162
|
From a Matrix::
|
155
163
|
|
156
164
|
sage: Q = ClusterQuiver(['A',[2,5],1]); Q
|
157
165
|
Quiver on 7 vertices of type ['A', [2, 5], 1]
|
158
|
-
sage: T = ClusterQuiver(
|
166
|
+
sage: T = ClusterQuiver(Q._M); T
|
159
167
|
Quiver on 7 vertices
|
160
168
|
|
161
|
-
sage: Q = ClusterQuiver(
|
169
|
+
sage: Q = ClusterQuiver(matrix([[0,1,-1],[-1,0,1],[1,-1,0],[1,2,3]])); Q
|
162
170
|
Quiver on 4 vertices with 1 frozen vertex
|
163
171
|
|
164
|
-
sage: Q = ClusterQuiver(
|
172
|
+
sage: Q = ClusterQuiver(matrix([])); Q
|
165
173
|
Quiver without vertices
|
166
174
|
|
167
175
|
From a DiGraph::
|
168
176
|
|
169
177
|
sage: Q = ClusterQuiver(['A',[2,5],1]); Q
|
170
178
|
Quiver on 7 vertices of type ['A', [2, 5], 1]
|
171
|
-
sage: T = ClusterQuiver(
|
179
|
+
sage: T = ClusterQuiver(Q._digraph); T
|
172
180
|
Quiver on 7 vertices
|
173
181
|
|
174
|
-
sage: Q = ClusterQuiver(
|
182
|
+
sage: Q = ClusterQuiver(DiGraph([[1,2],[2,3],[3,4],[4,1]])); Q
|
175
183
|
Quiver on 4 vertices
|
176
184
|
|
177
185
|
sage: Q = ClusterQuiver(DiGraph([['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'e']]),
|
@@ -180,13 +188,14 @@ class ClusterQuiver(SageObject):
|
|
180
188
|
sage: Q.mutation_type()
|
181
189
|
[ ['A', 2], ['A', 2] ]
|
182
190
|
sage: Q
|
183
|
-
Quiver on 5 vertices of type [ ['A', 2], ['A', 2] ]
|
191
|
+
Quiver on 5 vertices of type [ ['A', 2], ['A', 2] ]
|
192
|
+
with 1 frozen vertex
|
184
193
|
|
185
194
|
From a List of edges::
|
186
195
|
|
187
196
|
sage: Q = ClusterQuiver(['A',[2,5],1]); Q
|
188
197
|
Quiver on 7 vertices of type ['A', [2, 5], 1]
|
189
|
-
sage: T = ClusterQuiver(
|
198
|
+
sage: T = ClusterQuiver(Q._digraph.edges(sort=True)); T
|
190
199
|
Quiver on 7 vertices
|
191
200
|
|
192
201
|
sage: Q = ClusterQuiver([[1, 2], [2, 3], [3, 4], [4, 1]]); Q
|
@@ -215,7 +224,7 @@ class ClusterQuiver(SageObject):
|
|
215
224
|
ValueError: the input data was not recognized
|
216
225
|
"""
|
217
226
|
|
218
|
-
def __init__(self, data, frozen=None, user_labels=None):
|
227
|
+
def __init__(self, data, frozen=None, user_labels=None) -> None:
|
219
228
|
"""
|
220
229
|
TESTS::
|
221
230
|
|
@@ -226,11 +235,12 @@ class ClusterQuiver(SageObject):
|
|
226
235
|
from sage.structure.element import Matrix
|
227
236
|
|
228
237
|
if isinstance(user_labels, list):
|
229
|
-
user_labels = [tuple(x) if isinstance(x, list) else x
|
238
|
+
user_labels = [tuple(x) if isinstance(x, list) else x
|
239
|
+
for x in user_labels]
|
230
240
|
elif isinstance(user_labels, dict):
|
231
|
-
|
232
|
-
|
233
|
-
|
241
|
+
user_labels = {x: tuple(label) if isinstance(label, list)
|
242
|
+
else label
|
243
|
+
for x, label in user_labels.items()}
|
234
244
|
|
235
245
|
# constructs a quiver from a mutation type
|
236
246
|
if isinstance(data, (QuiverMutationType_Irreducible,
|
@@ -241,7 +251,7 @@ class ClusterQuiver(SageObject):
|
|
241
251
|
' Use set_frozen to freeze vertices.')
|
242
252
|
|
243
253
|
mutation_type = data
|
244
|
-
self.__init__(
|
254
|
+
self.__init__(mutation_type.standard_quiver())
|
245
255
|
if user_labels:
|
246
256
|
self.relabel(user_labels)
|
247
257
|
self._nlist = list(user_labels)
|
@@ -251,9 +261,10 @@ class ClusterQuiver(SageObject):
|
|
251
261
|
# NOTE: for now, any string representing a *reducible type* is
|
252
262
|
# coerced into the standard quiver, but there is now more flexibility
|
253
263
|
# in how to input a connected (irreducible) quiver.
|
254
|
-
elif (isinstance(data, (list,tuple))
|
255
|
-
and (isinstance(data[0], str) or
|
256
|
-
|
264
|
+
elif (isinstance(data, (list, tuple))
|
265
|
+
and (isinstance(data[0], str) or
|
266
|
+
all(isinstance(comp, (list, tuple))
|
267
|
+
and isinstance(comp[0], str) for comp in data))):
|
257
268
|
if frozen is not None:
|
258
269
|
print('The input specifies a mutation type, so the additional'
|
259
270
|
' parameter frozen is ignored. Use set_frozen to freeze vertices.')
|
@@ -265,50 +276,54 @@ class ClusterQuiver(SageObject):
|
|
265
276
|
# format the input appropriately. Thus we handle several
|
266
277
|
# special cases this way.
|
267
278
|
if len(data) == 2 and isinstance(data[0], str):
|
268
|
-
|
269
|
-
|
270
|
-
|
279
|
+
d0, d1 = data
|
280
|
+
if d0 == 'TR' or d0 == 'GR' or (d0 == 'C' and d1 == 2):
|
281
|
+
if d1 in ZZ:
|
282
|
+
quiv = ClusterQuiver(QuiverMutationType_Irreducible(d0, d1)._digraph)
|
271
283
|
quiv._mutation_type = mutation_type
|
272
|
-
self.__init__(
|
273
|
-
elif isinstance(
|
274
|
-
quiv = ClusterQuiver(
|
284
|
+
self.__init__(quiv)
|
285
|
+
elif isinstance(d1, list):
|
286
|
+
quiv = ClusterQuiver(QuiverMutationType_Irreducible(d0, tuple(d1))._digraph)
|
275
287
|
quiv._mutation_type = mutation_type
|
276
|
-
self.__init__(
|
288
|
+
self.__init__(quiv)
|
277
289
|
else:
|
278
|
-
self.__init__(
|
290
|
+
self.__init__(mutation_type.standard_quiver())
|
279
291
|
elif len(data) == 3 and isinstance(data[0], str):
|
280
|
-
|
281
|
-
|
292
|
+
d0, d1, d2 = data
|
293
|
+
if ((d0 == 'F' and d1 == 4 and d2 == [2, 1]) or
|
294
|
+
(d0 == 'G' and d1 == 2 and d2 == [3, 1])):
|
295
|
+
quiv = ClusterQuiver(QuiverMutationType_Irreducible(d0, d1, tuple(d2))._digraph)
|
282
296
|
quiv._mutation_type = mutation_type
|
283
|
-
self.__init__(
|
284
|
-
elif (
|
285
|
-
|
297
|
+
self.__init__(quiv)
|
298
|
+
elif ((d0 == 'F' and d1 == 4 and d2 == (2, 1)) or
|
299
|
+
(d0 == 'G' and d1 == 2 and d2 == (3, 1))):
|
300
|
+
quiv = ClusterQuiver(QuiverMutationType_Irreducible(d0, d1, d2)._digraph)
|
286
301
|
quiv._mutation_type = mutation_type
|
287
|
-
self.__init__(
|
288
|
-
elif
|
289
|
-
if len(
|
290
|
-
quiv = ClusterQuiver(
|
302
|
+
self.__init__(quiv)
|
303
|
+
elif d0 == 'A' and isinstance(d1, list) and d2 == 1:
|
304
|
+
if len(d1) == 2 and min(d1) == 0:
|
305
|
+
quiv = ClusterQuiver(QuiverMutationType_Irreducible(d0, tuple(d1), d2)._digraph)
|
291
306
|
quiv._mutation_type = mutation_type
|
292
|
-
self.__init__(
|
307
|
+
self.__init__(quiv)
|
293
308
|
else:
|
294
|
-
self.__init__(
|
309
|
+
self.__init__(mutation_type.standard_quiver())
|
295
310
|
|
296
|
-
elif
|
297
|
-
if len(
|
298
|
-
quiv = ClusterQuiver(
|
311
|
+
elif d0 == 'A' and isinstance(d1, tuple) and d2 == 1:
|
312
|
+
if len(d1) == 2 and min(d1) == 0:
|
313
|
+
quiv = ClusterQuiver(QuiverMutationType_Irreducible(d0, d1, d2)._digraph)
|
299
314
|
quiv._mutation_type = mutation_type
|
300
|
-
self.__init__(
|
315
|
+
self.__init__(quiv)
|
301
316
|
else:
|
302
|
-
self.__init__(
|
317
|
+
self.__init__(mutation_type.standard_quiver())
|
303
318
|
|
304
319
|
else:
|
305
|
-
self.__init__(
|
320
|
+
self.__init__(mutation_type.standard_quiver())
|
306
321
|
else:
|
307
|
-
self.__init__(
|
322
|
+
self.__init__(mutation_type.standard_quiver())
|
308
323
|
|
309
324
|
if user_labels:
|
310
325
|
if isinstance(user_labels, dict):
|
311
|
-
self._nlist = list(user_labels
|
326
|
+
self._nlist = list(user_labels)
|
312
327
|
else:
|
313
328
|
self._nlist = user_labels
|
314
329
|
|
@@ -316,7 +331,7 @@ class ClusterQuiver(SageObject):
|
|
316
331
|
|
317
332
|
# constructs a quiver from a cluster seed
|
318
333
|
elif isinstance(data, ClusterSeed):
|
319
|
-
self.__init__(
|
334
|
+
self.__init__(data.quiver())
|
320
335
|
|
321
336
|
# constructs a quiver from a quiver
|
322
337
|
elif isinstance(data, ClusterQuiver):
|
@@ -330,14 +345,14 @@ class ClusterQuiver(SageObject):
|
|
330
345
|
self._m = data._m
|
331
346
|
self._mlist = list(data._mlist)
|
332
347
|
self._nlist = list(data._nlist)
|
333
|
-
self._digraph = copy(
|
348
|
+
self._digraph = copy(data._digraph)
|
334
349
|
self._vertex_dictionary = data._vertex_dictionary
|
335
350
|
self._mutation_type = data._mutation_type
|
336
351
|
self._description = data._description
|
337
352
|
|
338
353
|
# constructs a quiver from a matrix
|
339
354
|
elif isinstance(data, Matrix):
|
340
|
-
if not _principal_part(data).is_skew_symmetrizable(
|
355
|
+
if not _principal_part(data).is_skew_symmetrizable(positive=True):
|
341
356
|
raise ValueError('The principal part of the matrix data must be skew-symmetrizable.')
|
342
357
|
|
343
358
|
if frozen is not None:
|
@@ -347,20 +362,20 @@ class ClusterQuiver(SageObject):
|
|
347
362
|
self._M.set_immutable()
|
348
363
|
self._n = n = self._M.ncols()
|
349
364
|
self._m = m = self._M.nrows() - self._n
|
350
|
-
self._digraph = _matrix_to_digraph(
|
365
|
+
self._digraph = _matrix_to_digraph(self._M)
|
351
366
|
self._vertex_dictionary = {}
|
352
367
|
self._mutation_type = None
|
353
368
|
|
354
369
|
if user_labels:
|
355
370
|
if isinstance(user_labels, dict):
|
356
|
-
self._nlist = list(user_labels
|
357
|
-
self._mlist = list(user_labels
|
371
|
+
self._nlist = list(user_labels)[0:n]
|
372
|
+
self._mlist = list(user_labels)[n:n+m]
|
358
373
|
elif isinstance(user_labels, list):
|
359
374
|
self._nlist = user_labels[0:n]
|
360
375
|
self._mlist = user_labels[n:n+m]
|
361
376
|
self._digraph.relabel(self._nlist + self._mlist)
|
362
377
|
else:
|
363
|
-
self._mlist = list(range(n,n+m))
|
378
|
+
self._mlist = list(range(n, n+m))
|
364
379
|
self._nlist = list(range(n))
|
365
380
|
if n+m == 0:
|
366
381
|
self._description = 'Quiver without vertices'
|
@@ -417,34 +432,34 @@ class ClusterQuiver(SageObject):
|
|
417
432
|
else:
|
418
433
|
multi_edges[(v1, v2)] = label
|
419
434
|
dg.delete_edge(v1, v2)
|
420
|
-
dg.add_edges([(v1, v2, multi_edges[(v1,v2)])
|
435
|
+
dg.add_edges([(v1, v2, multi_edges[(v1, v2)])
|
421
436
|
for v1, v2 in multi_edges])
|
422
437
|
|
423
|
-
for
|
424
|
-
if
|
438
|
+
for e0, e1, lab in dg.edge_iterator():
|
439
|
+
if e0 >= n and e1 >= n:
|
425
440
|
raise ValueError("the input digraph contains edges"
|
426
441
|
" within the frozen vertices")
|
427
|
-
if
|
428
|
-
|
429
|
-
|
430
|
-
elif
|
431
|
-
|
432
|
-
|
433
|
-
elif isinstance(
|
442
|
+
if lab is None:
|
443
|
+
lab = (1, -1)
|
444
|
+
dg.set_edge_label(e0, e1, lab)
|
445
|
+
elif lab in ZZ:
|
446
|
+
lab = (lab, -lab)
|
447
|
+
dg.set_edge_label(e0, e1, lab)
|
448
|
+
elif isinstance(lab, list) and len(lab) != 2:
|
434
449
|
raise ValueError("the input digraph contains an edge with"
|
435
450
|
" the wrong type of list as a label")
|
436
|
-
elif isinstance(
|
437
|
-
|
438
|
-
|
439
|
-
elif (
|
451
|
+
elif isinstance(lab, list) and len(lab) == 2:
|
452
|
+
lab = tuple(lab)
|
453
|
+
dg.set_edge_label(e0, e1, lab)
|
454
|
+
elif (e0 >= n or e1 >= n) and not lab[0] == -lab[1]:
|
440
455
|
raise ValueError("the input digraph contains an edge to or"
|
441
456
|
" from a frozen vertex which is not skew-symmetric")
|
442
|
-
if
|
443
|
-
raise ValueError("the input digraph contains an edge of
|
444
|
-
" form (a,-b) with negative a")
|
457
|
+
if lab[0] < 0:
|
458
|
+
raise ValueError("the input digraph contains an edge of "
|
459
|
+
"the form (a,-b) with negative a")
|
445
460
|
|
446
|
-
M = _edge_list_to_matrix(
|
447
|
-
|
461
|
+
M = _edge_list_to_matrix(dg.edge_iterator(), list(range(n)),
|
462
|
+
list(range(n, n + m)))
|
448
463
|
if not _principal_part(M).is_skew_symmetrizable(positive=True):
|
449
464
|
raise ValueError("the input digraph must be skew-symmetrizable")
|
450
465
|
|
@@ -465,7 +480,8 @@ class ClusterQuiver(SageObject):
|
|
465
480
|
|
466
481
|
# if data is a list of edges, the appropriate digraph is constructed.
|
467
482
|
|
468
|
-
elif isinstance(data, (list, EdgesView))
|
483
|
+
elif (isinstance(data, (list, EdgesView))
|
484
|
+
and all(isinstance(x, (list, tuple)) for x in data)):
|
469
485
|
dg = DiGraph(data)
|
470
486
|
self.__init__(data=dg, frozen=frozen)
|
471
487
|
|
@@ -485,16 +501,16 @@ class ClusterQuiver(SageObject):
|
|
485
501
|
EXAMPLES::
|
486
502
|
|
487
503
|
sage: Q = ClusterQuiver(['A',5])
|
488
|
-
sage: T = Q.mutate(
|
489
|
-
sage: Q.__eq__(
|
504
|
+
sage: T = Q.mutate(2, inplace=False)
|
505
|
+
sage: Q.__eq__(T)
|
490
506
|
False
|
491
|
-
sage: T.mutate(
|
492
|
-
sage: Q.__eq__(
|
507
|
+
sage: T.mutate(2)
|
508
|
+
sage: Q.__eq__(T)
|
493
509
|
True
|
494
510
|
"""
|
495
511
|
return isinstance(other, ClusterQuiver) and self._M == other._M
|
496
512
|
|
497
|
-
def __hash__(self):
|
513
|
+
def __hash__(self) -> int:
|
498
514
|
"""
|
499
515
|
Return a hash of ``self``.
|
500
516
|
|
@@ -507,7 +523,7 @@ class ClusterQuiver(SageObject):
|
|
507
523
|
"""
|
508
524
|
return hash(self._M)
|
509
525
|
|
510
|
-
def _repr_(self):
|
526
|
+
def _repr_(self) -> str:
|
511
527
|
"""
|
512
528
|
Return the description of ``self``.
|
513
529
|
|
@@ -572,7 +588,7 @@ class ClusterQuiver(SageObject):
|
|
572
588
|
g2 = graphs.CycleGraph(m).get_pos()
|
573
589
|
for i in g2:
|
574
590
|
z = CC(g2[i])*e**(-pi*I/(2*m))
|
575
|
-
g2[i] = (z.real_part(),z.imag_part())
|
591
|
+
g2[i] = (z.real_part(), z.imag_part())
|
576
592
|
for i in range(m):
|
577
593
|
g1[n+i] = [2*g2[i][0], 2*g2[i][1]]
|
578
594
|
return g1
|
@@ -582,28 +598,30 @@ class ClusterQuiver(SageObject):
|
|
582
598
|
nlist = copy(self._nlist)
|
583
599
|
mlist = copy(self._mlist)
|
584
600
|
colors = rainbow(11)
|
585
|
-
color_dict = {
|
601
|
+
color_dict = {colors[0]: [], colors[1]: [],
|
602
|
+
colors[6]: [], colors[5]: []}
|
586
603
|
|
587
|
-
# Set up our graph. If it's directed we have a digraph, else
|
604
|
+
# Set up our graph. If it's directed we have a digraph, else
|
605
|
+
# just a normal graph
|
588
606
|
if directed:
|
589
|
-
dg =
|
607
|
+
dg = self._digraph.copy(immutable=False)
|
590
608
|
else:
|
591
|
-
dg = Graph(
|
609
|
+
dg = Graph(self._digraph)
|
592
610
|
|
593
611
|
# For each edge in our graph we assign a color
|
594
|
-
for
|
595
|
-
v1,v2,(a,b) = edge
|
612
|
+
for v1, v2, ab in dg.edges(sort=True):
|
596
613
|
|
597
614
|
if v1 in nlist and v2 in nlist:
|
598
|
-
if
|
599
|
-
color_dict[
|
615
|
+
if ab == (1, -1):
|
616
|
+
color_dict[colors[0]].append((v1, v2))
|
600
617
|
else:
|
601
|
-
color_dict[
|
618
|
+
color_dict[colors[6]].append((v1, v2))
|
602
619
|
else:
|
603
|
-
if
|
604
|
-
color_dict[
|
620
|
+
if ab == (1, -1):
|
621
|
+
color_dict[colors[1]].append((v1, v2))
|
605
622
|
else:
|
606
|
-
color_dict[
|
623
|
+
color_dict[colors[5]].append((v1, v2))
|
624
|
+
a, b = ab
|
607
625
|
if a == -b:
|
608
626
|
if a == 1:
|
609
627
|
dg.set_edge_label(v1, v2, '')
|
@@ -621,7 +639,7 @@ class ClusterQuiver(SageObject):
|
|
621
639
|
mlist.remove(mark)
|
622
640
|
partition = (nlist, mlist, [mark])
|
623
641
|
else:
|
624
|
-
raise ValueError("
|
642
|
+
raise ValueError("the given mark is not a vertex of self")
|
625
643
|
else:
|
626
644
|
|
627
645
|
# Partition out the green vertices
|
@@ -644,7 +662,7 @@ class ClusterQuiver(SageObject):
|
|
644
662
|
'vertex_labels': True,
|
645
663
|
}
|
646
664
|
if circular:
|
647
|
-
pp = _graphs_concentric_circles(
|
665
|
+
pp = _graphs_concentric_circles(n, m)
|
648
666
|
options['pos'] = {}
|
649
667
|
for v in pp:
|
650
668
|
# If we're using vertex dictionary set that as key
|
@@ -652,9 +670,10 @@ class ClusterQuiver(SageObject):
|
|
652
670
|
vkey = self._vertex_dictionary[v]
|
653
671
|
else:
|
654
672
|
vkey = v
|
655
|
-
options['pos'][vkey] = (pp[v][0] + center[0],
|
673
|
+
options['pos'][vkey] = (pp[v][0] + center[0],
|
674
|
+
pp[v][1] + center[1])
|
656
675
|
|
657
|
-
return dg.plot(
|
676
|
+
return dg.plot(**options)
|
658
677
|
|
659
678
|
def show(self, fig_size=1, circular=False, directed=True, mark=None, save_pos=False, greens=[]):
|
660
679
|
"""
|
@@ -681,11 +700,12 @@ class ClusterQuiver(SageObject):
|
|
681
700
|
sage: Q.show() # long time
|
682
701
|
"""
|
683
702
|
n, m = self._n, self._m
|
684
|
-
plot = self.plot(
|
703
|
+
plot = self.plot(circular=circular, directed=directed,
|
704
|
+
mark=mark, save_pos=save_pos, greens=greens)
|
685
705
|
if circular:
|
686
|
-
plot.show(
|
706
|
+
plot.show(figsize=[fig_size*3*(n+m)/4+1, fig_size*3*(n+m)/4+1])
|
687
707
|
else:
|
688
|
-
plot.show(
|
708
|
+
plot.show(figsize=[fig_size*n+1, fig_size*n+1])
|
689
709
|
|
690
710
|
def interact(self, fig_size=1, circular=True):
|
691
711
|
r"""
|
@@ -764,7 +784,7 @@ class ClusterQuiver(SageObject):
|
|
764
784
|
if self.m():
|
765
785
|
from sage.matrix.constructor import matrix
|
766
786
|
from sage.matrix.constructor import block_matrix
|
767
|
-
M1 = M.matrix_from_rows(
|
787
|
+
M1 = M.matrix_from_rows(range(self.n()))
|
768
788
|
M2 = M.matrix_from_rows(list(range(self.n(), self.n() + self.m())))
|
769
789
|
M3 = matrix(self.m(), self.m())
|
770
790
|
M = block_matrix([[M1, -M2.transpose()], [M2, M3]])
|
@@ -877,7 +897,7 @@ class ClusterQuiver(SageObject):
|
|
877
897
|
sage: ClusterQuiver(['C', 4], user_labels = ['x', 'y', 'z', 'w']).digraph().edges(sort=True)
|
878
898
|
[('x', 'y', (1, -1)), ('z', 'w', (2, -1)), ('z', 'y', (1, -1))]
|
879
899
|
"""
|
880
|
-
return
|
900
|
+
return self._digraph.copy()
|
881
901
|
|
882
902
|
def mutation_type(self):
|
883
903
|
"""
|
@@ -952,15 +972,15 @@ class ClusterQuiver(SageObject):
|
|
952
972
|
examples from page 8 of [Ke2008]_::
|
953
973
|
|
954
974
|
sage: dg = DiGraph(); dg.add_edges([(9,0),(9,4),(4,6),(6,7),(7,8),(8,3),(3,5),(5,6),(8,1),(2,3)])
|
955
|
-
sage: ClusterQuiver(
|
975
|
+
sage: ClusterQuiver(dg).mutation_type() # long time
|
956
976
|
['E', 8, [1, 1]]
|
957
977
|
|
958
|
-
sage: dg = DiGraph(
|
959
|
-
sage: ClusterQuiver(
|
978
|
+
sage: dg = DiGraph({ 0:[3], 1:[0,4], 2:[0,6], 3:[1,2,7], 4:[3,8], 5:[2], 6:[3,5], 7:[4,6], 8:[7] })
|
979
|
+
sage: ClusterQuiver(dg).mutation_type() # long time
|
960
980
|
['E', 8, 1]
|
961
981
|
|
962
|
-
sage: dg = DiGraph(
|
963
|
-
sage: ClusterQuiver(
|
982
|
+
sage: dg = DiGraph({ 0:[3,9], 1:[0,4], 2:[0,6], 3:[1,2,7], 4:[3,8], 5:[2], 6:[3,5], 7:[4,6], 8:[7], 9:[1] })
|
983
|
+
sage: ClusterQuiver(dg).mutation_type() # long time
|
964
984
|
['E', 8, [1, 1]]
|
965
985
|
|
966
986
|
infinite types::
|
@@ -1013,7 +1033,7 @@ class ClusterQuiver(SageObject):
|
|
1013
1033
|
connected_components = sorted(dg.connected_components(sort=False))
|
1014
1034
|
for component in connected_components:
|
1015
1035
|
# constructing the digraph for this component
|
1016
|
-
dg_component = dg.subgraph(
|
1036
|
+
dg_component = dg.subgraph(component)
|
1017
1037
|
dg_component.relabel()
|
1018
1038
|
# turning dg_component into a canonical form
|
1019
1039
|
_dg_canonical_form(dg_component)
|
@@ -1028,7 +1048,7 @@ class ClusterQuiver(SageObject):
|
|
1028
1048
|
mut_type_part = 'undetermined infinite mutation type'
|
1029
1049
|
else:
|
1030
1050
|
# checking if this quiver is in the database
|
1031
|
-
mut_type_part = _mutation_type_from_data(
|
1051
|
+
mut_type_part = _mutation_type_from_data(dg_component.order(), dig6, compute_if_necessary=False)
|
1032
1052
|
# checking if the algorithm can determine the mutation type
|
1033
1053
|
if mut_type_part == 'unknown':
|
1034
1054
|
mut_type_part = _connected_mutation_type(dg_component)
|
@@ -1037,7 +1057,7 @@ class ClusterQuiver(SageObject):
|
|
1037
1057
|
mut_type_part = _mutation_type_from_data(dg_component.order(), dig6, compute_if_necessary=True)
|
1038
1058
|
if mut_type_part == 'unknown':
|
1039
1059
|
mut_type_part = 'undetermined finite mutation type'
|
1040
|
-
mutation_type.append(
|
1060
|
+
mutation_type.append(mut_type_part)
|
1041
1061
|
|
1042
1062
|
# the empty quiver case
|
1043
1063
|
if len(mutation_type) == 0:
|
@@ -1046,12 +1066,9 @@ class ClusterQuiver(SageObject):
|
|
1046
1066
|
elif len(mutation_type) == 1:
|
1047
1067
|
mutation_type = mutation_type[0]
|
1048
1068
|
# the reducible quiver case
|
1049
|
-
elif
|
1050
|
-
|
1051
|
-
|
1052
|
-
pass
|
1053
|
-
else:
|
1054
|
-
mutation_type = QuiverMutationType(mutation_type)
|
1069
|
+
elif not any(isinstance(mut_type_part, str)
|
1070
|
+
for mut_type_part in mutation_type):
|
1071
|
+
mutation_type = QuiverMutationType(mutation_type)
|
1055
1072
|
self._mutation_type = mutation_type
|
1056
1073
|
return self._mutation_type
|
1057
1074
|
|
@@ -1090,7 +1107,7 @@ class ClusterQuiver(SageObject):
|
|
1090
1107
|
"""
|
1091
1108
|
return self._m
|
1092
1109
|
|
1093
|
-
def free_vertices(self):
|
1110
|
+
def free_vertices(self) -> list:
|
1094
1111
|
"""
|
1095
1112
|
Return the list of free vertices of ``self``.
|
1096
1113
|
|
@@ -1103,7 +1120,7 @@ class ClusterQuiver(SageObject):
|
|
1103
1120
|
"""
|
1104
1121
|
return self._nlist
|
1105
1122
|
|
1106
|
-
def frozen_vertices(self):
|
1123
|
+
def frozen_vertices(self) -> list:
|
1107
1124
|
"""
|
1108
1125
|
Return the list of frozen vertices of ``self``.
|
1109
1126
|
|
@@ -1151,7 +1168,7 @@ class ClusterQuiver(SageObject):
|
|
1151
1168
|
(Quiver on 3 vertices of type [ ['A', 1], ['B', 2] ], {0: 1, 1: 2, 2: 0})
|
1152
1169
|
"""
|
1153
1170
|
# computing the canonical form respecting the frozen variables
|
1154
|
-
dg =
|
1171
|
+
dg = self._digraph.copy()
|
1155
1172
|
iso, _ = _dg_canonical_form(dg, frozen=self._mlist)
|
1156
1173
|
frozen = [iso[i] for i in self._mlist]
|
1157
1174
|
Q = ClusterQuiver(dg, frozen=frozen)
|
@@ -1164,16 +1181,15 @@ class ClusterQuiver(SageObject):
|
|
1164
1181
|
CC_new = sorted(zip([sorted(iso[i] for i in L) for L in CC],
|
1165
1182
|
range(len(CC))))
|
1166
1183
|
comp_iso = [L[1] for L in CC_new]
|
1167
|
-
Q._mutation_type = []
|
1168
|
-
|
1169
|
-
|
1170
|
-
Q._mutation_type = QuiverMutationType( Q._mutation_type )
|
1184
|
+
Q._mutation_type = [copy(self._mutation_type.irreducible_components()[comp_i])
|
1185
|
+
for comp_i in comp_iso]
|
1186
|
+
Q._mutation_type = QuiverMutationType(Q._mutation_type)
|
1171
1187
|
if certificate:
|
1172
1188
|
return Q, iso
|
1173
1189
|
else:
|
1174
1190
|
return Q
|
1175
1191
|
|
1176
|
-
def is_acyclic(self):
|
1192
|
+
def is_acyclic(self) -> bool:
|
1177
1193
|
"""
|
1178
1194
|
Return true if ``self`` is acyclic.
|
1179
1195
|
|
@@ -1202,8 +1218,8 @@ class ClusterQuiver(SageObject):
|
|
1202
1218
|
sage: ClusterQuiver(['A',[4,3],1]).is_bipartite()
|
1203
1219
|
False
|
1204
1220
|
"""
|
1205
|
-
dg =
|
1206
|
-
dg.delete_vertices(
|
1221
|
+
dg = self._digraph.copy(immutable=False)
|
1222
|
+
dg.delete_vertices(range(self._n, self._n + self._m))
|
1207
1223
|
if any(dg.in_degree(i) and dg.out_degree(i) for i in dg):
|
1208
1224
|
return False
|
1209
1225
|
if not return_bipartition:
|
@@ -1229,15 +1245,19 @@ class ClusterQuiver(SageObject):
|
|
1229
1245
|
sage: Q2.exchangeable_part() == Q3.exchangeable_part()
|
1230
1246
|
True
|
1231
1247
|
"""
|
1232
|
-
dg =
|
1233
|
-
dg.delete_vertices(
|
1234
|
-
Q = ClusterQuiver(
|
1248
|
+
dg = self._digraph.copy(immutable=False)
|
1249
|
+
dg.delete_vertices(range(self._n, self._n + self._m))
|
1250
|
+
Q = ClusterQuiver(dg)
|
1235
1251
|
Q._mutation_type = self._mutation_type
|
1236
1252
|
return Q
|
1237
1253
|
|
1238
1254
|
def principal_extension(self, inplace=False):
|
1239
1255
|
"""
|
1240
|
-
Return the principal extension of ``self``, adding n frozen vertices
|
1256
|
+
Return the principal extension of ``self``, adding n frozen vertices
|
1257
|
+
to any previously frozen vertices.
|
1258
|
+
|
1259
|
+
This is the quiver obtained by adding an outgoing edge to
|
1260
|
+
every mutable vertex of ``self``.
|
1241
1261
|
|
1242
1262
|
EXAMPLES::
|
1243
1263
|
|
@@ -1252,11 +1272,13 @@ class ClusterQuiver(SageObject):
|
|
1252
1272
|
sage: T.digraph().edges(sort=True)
|
1253
1273
|
[(0, 1, (1, -1)), (2, 0, (1, -1)), (3, 1, (1, -1))]
|
1254
1274
|
sage: T2.digraph().edges(sort=True)
|
1255
|
-
[(0, 1, (1, -1)), (2, 0, (1, -1)), (3, 1, (1, -1)),
|
1275
|
+
[(0, 1, (1, -1)), (2, 0, (1, -1)), (3, 1, (1, -1)),
|
1276
|
+
(4, 0, (1, -1)), (5, 1, (1, -1))]
|
1256
1277
|
"""
|
1257
|
-
dg =
|
1258
|
-
dg.add_edges(
|
1259
|
-
Q = ClusterQuiver(
|
1278
|
+
dg = self._digraph.copy(immutable=False)
|
1279
|
+
dg.add_edges([(self._n + self._m + i, i) for i in range(self._n)])
|
1280
|
+
Q = ClusterQuiver(dg, frozen=list(range(self._n,
|
1281
|
+
2 * self._n + self._m)))
|
1260
1282
|
Q._mutation_type = self._mutation_type
|
1261
1283
|
if inplace:
|
1262
1284
|
self.__init__(Q)
|
@@ -1280,7 +1302,7 @@ class ClusterQuiver(SageObject):
|
|
1280
1302
|
return sinks[0]
|
1281
1303
|
return None
|
1282
1304
|
|
1283
|
-
def sinks(self):
|
1305
|
+
def sinks(self) -> list:
|
1284
1306
|
r"""
|
1285
1307
|
Return all vertices of ``self`` that are sinks.
|
1286
1308
|
|
@@ -1315,7 +1337,7 @@ class ClusterQuiver(SageObject):
|
|
1315
1337
|
return sources[0]
|
1316
1338
|
return None
|
1317
1339
|
|
1318
|
-
def sources(self):
|
1340
|
+
def sources(self) -> list:
|
1319
1341
|
r"""
|
1320
1342
|
Return all vertices of ``self`` that are sources.
|
1321
1343
|
|
@@ -1335,15 +1357,15 @@ class ClusterQuiver(SageObject):
|
|
1335
1357
|
|
1336
1358
|
def mutate(self, data, inplace=True):
|
1337
1359
|
"""
|
1338
|
-
|
1360
|
+
Mutate ``self`` at a sequence of vertices.
|
1339
1361
|
|
1340
1362
|
INPUT:
|
1341
1363
|
|
1342
1364
|
- ``sequence`` -- a vertex of ``self``, an iterator of vertices of
|
1343
1365
|
``self``, a function which takes in the ClusterQuiver and returns a
|
1344
1366
|
vertex or an iterator of vertices, or a string of the parameter
|
1345
|
-
wanting to be called on ClusterQuiver that will return a vertex
|
1346
|
-
an iterator of vertices
|
1367
|
+
wanting to be called on ``ClusterQuiver`` that will return a vertex
|
1368
|
+
or an iterator of vertices
|
1347
1369
|
- ``inplace`` -- boolean (default: ``True``); if ``False``, the result
|
1348
1370
|
is returned, otherwise ``self`` is modified
|
1349
1371
|
|
@@ -1455,7 +1477,7 @@ class ClusterQuiver(SageObject):
|
|
1455
1477
|
else:
|
1456
1478
|
seq = data
|
1457
1479
|
if isinstance(seq, tuple):
|
1458
|
-
seq = list(
|
1480
|
+
seq = list(seq)
|
1459
1481
|
if not isinstance(seq, list):
|
1460
1482
|
raise ValueError('The quiver can only be mutated at a vertex or at a sequence of vertices')
|
1461
1483
|
if not isinstance(inplace, bool):
|
@@ -1476,7 +1498,7 @@ class ClusterQuiver(SageObject):
|
|
1476
1498
|
Q._mutation_type = self._mutation_type
|
1477
1499
|
return Q
|
1478
1500
|
|
1479
|
-
def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2
|
1501
|
+
def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2):
|
1480
1502
|
"""
|
1481
1503
|
Return a list containing the sequence of quivers obtained from ``self``
|
1482
1504
|
by a sequence of mutations on vertices.
|
@@ -1512,44 +1534,46 @@ class ClusterQuiver(SageObject):
|
|
1512
1534
|
else:
|
1513
1535
|
width_factor = 6
|
1514
1536
|
fig_size = fig_size*4*n/3
|
1515
|
-
V =
|
1537
|
+
V = range(n)
|
1516
1538
|
|
1517
1539
|
if isinstance(sequence, tuple):
|
1518
|
-
sequence = list(
|
1540
|
+
sequence = list(sequence)
|
1519
1541
|
if not isinstance(sequence, list):
|
1520
|
-
raise ValueError('
|
1542
|
+
raise ValueError('the quiver can only be mutated at a vertex'
|
1543
|
+
' or at a sequence of vertices')
|
1521
1544
|
if any(v not in V for v in sequence):
|
1522
1545
|
v = next(v for v in sequence if v not in V)
|
1523
|
-
raise ValueError('
|
1546
|
+
raise ValueError(f'the quiver can only be mutated at the vertex {v}')
|
1524
1547
|
|
1525
|
-
quiver = copy(
|
1548
|
+
quiver = copy(self)
|
1526
1549
|
quiver_sequence = []
|
1527
|
-
quiver_sequence.append(
|
1550
|
+
quiver_sequence.append(copy(quiver))
|
1528
1551
|
|
1529
1552
|
for v in sequence:
|
1530
|
-
quiver.mutate(
|
1531
|
-
quiver_sequence.append(
|
1553
|
+
quiver.mutate(v)
|
1554
|
+
quiver_sequence.append(copy(quiver))
|
1532
1555
|
|
1533
1556
|
if show_sequence:
|
1534
1557
|
from sage.plot.plot import Graphics
|
1535
1558
|
from sage.plot.text import text
|
1536
1559
|
|
1537
|
-
def _plot_arrow(
|
1538
|
-
return text(r"$\longleftrightarrow$",(center[0],center[1]), fontsize=25) + text(r"$\mu_"+str(v)+"$",(center[0],center[1]+0.15), fontsize=15) \
|
1539
|
-
+ text("$"+str(k)+"$",(center[0],center[1]-0.2), fontsize=15)
|
1560
|
+
def _plot_arrow(v, k, center=(0, 0)):
|
1561
|
+
return text(r"$\longleftrightarrow$", (center[0], center[1]), fontsize=25) + text(r"$\mu_"+str(v)+"$", (center[0], center[1]+0.15), fontsize=15) \
|
1562
|
+
+ text("$"+str(k)+"$", (center[0], center[1]-0.2), fontsize=15)
|
1540
1563
|
|
1541
|
-
plot_sequence = [
|
1542
|
-
arrow_sequence = [
|
1564
|
+
plot_sequence = [quiver_sequence[i].plot(circular=True, center=(i*width_factor, 0)) for i in range(len(quiver_sequence))]
|
1565
|
+
arrow_sequence = [_plot_arrow(sequence[i], i+1, center=((i+0.5)*width_factor, 0)) for i in range(len(sequence))]
|
1543
1566
|
sequence = []
|
1544
|
-
for i in range(
|
1545
|
-
if i < len(
|
1546
|
-
sequence.append(
|
1567
|
+
for i in range(len(plot_sequence)):
|
1568
|
+
if i < len(arrow_sequence):
|
1569
|
+
sequence.append(plot_sequence[i] + arrow_sequence[i])
|
1547
1570
|
else:
|
1548
|
-
sequence.append(
|
1571
|
+
sequence.append(plot_sequence[i])
|
1549
1572
|
plot_obj = Graphics()
|
1550
1573
|
for elem in sequence:
|
1551
1574
|
plot_obj += elem
|
1552
|
-
plot_obj.show(axes=False, figsize=[fig_size*len(quiver_sequence),
|
1575
|
+
plot_obj.show(axes=False, figsize=[fig_size*len(quiver_sequence),
|
1576
|
+
fig_size])
|
1553
1577
|
return quiver_sequence
|
1554
1578
|
|
1555
1579
|
def reorient(self, data):
|
@@ -1623,13 +1647,15 @@ class ClusterQuiver(SageObject):
|
|
1623
1647
|
self._M.set_immutable()
|
1624
1648
|
self._mutation_type = None
|
1625
1649
|
else:
|
1626
|
-
raise ValueError('not a total order on the vertices of the quiver
|
1650
|
+
raise ValueError('not a total order on the vertices of the quiver'
|
1651
|
+
' or a list of edges to be oriented')
|
1627
1652
|
|
1628
1653
|
def mutation_class_iter(self, depth=infinity, show_depth=False,
|
1629
1654
|
return_paths=False, data_type='quiver',
|
1630
1655
|
up_to_equivalence=True, sink_source=False):
|
1631
1656
|
"""
|
1632
|
-
Return an iterator for the mutation class of ``self``
|
1657
|
+
Return an iterator for the mutation class of ``self``
|
1658
|
+
together with certain constraints.
|
1633
1659
|
|
1634
1660
|
INPUT:
|
1635
1661
|
|
@@ -1699,7 +1725,8 @@ class ClusterQuiver(SageObject):
|
|
1699
1725
|
Quiver on 3 vertices of type ['A', 3]
|
1700
1726
|
Quiver on 3 vertices of type ['A', 3]
|
1701
1727
|
|
1702
|
-
sage: it = Q.mutation_class_iter(return_paths=True,
|
1728
|
+
sage: it = Q.mutation_class_iter(return_paths=True,
|
1729
|
+
....: up_to_equivalence=False)
|
1703
1730
|
sage: mutation_class = list(it)
|
1704
1731
|
sage: len(mutation_class)
|
1705
1732
|
14
|
@@ -1715,7 +1742,8 @@ class ClusterQuiver(SageObject):
|
|
1715
1742
|
[0, 1]
|
1716
1743
|
|
1717
1744
|
sage: Q = ClusterQuiver(['A',3])
|
1718
|
-
sage: it = Q.mutation_class_iter(return_paths=True,
|
1745
|
+
sage: it = Q.mutation_class_iter(return_paths=True,
|
1746
|
+
....: data_type='matrix')
|
1719
1747
|
sage: next(it)
|
1720
1748
|
(
|
1721
1749
|
[ 0 0 1]
|
@@ -1723,7 +1751,8 @@ class ClusterQuiver(SageObject):
|
|
1723
1751
|
[-1 -1 0], []
|
1724
1752
|
)
|
1725
1753
|
|
1726
|
-
sage: dg = DiGraph([['a', 'b'], ['b', 'c']],
|
1754
|
+
sage: dg = DiGraph([['a', 'b'], ['b', 'c']],
|
1755
|
+
....: format='list_of_edges')
|
1727
1756
|
sage: S = ClusterQuiver(dg, frozen=['b'])
|
1728
1757
|
sage: S.mutation_class()
|
1729
1758
|
[Quiver on 3 vertices with 1 frozen vertex,
|
@@ -1778,8 +1807,8 @@ class ClusterQuiver(SageObject):
|
|
1778
1807
|
- ``show_depth`` -- boolean (default: ``False``); if ``True``, the
|
1779
1808
|
actual depth of the mutation is shown
|
1780
1809
|
- ``return_paths`` -- boolean (default: ``False``); if ``True``, a
|
1781
|
-
shortest path of mutation sequences from ``self`` to the given
|
1782
|
-
returned as well
|
1810
|
+
shortest path of mutation sequences from ``self`` to the given
|
1811
|
+
quiver is returned as well
|
1783
1812
|
- ``data_type`` -- (default: ``'quiver'``) can be one of
|
1784
1813
|
the following:
|
1785
1814
|
|
@@ -1875,7 +1904,7 @@ class ClusterQuiver(SageObject):
|
|
1875
1904
|
up_to_equivalence=up_to_equivalence,
|
1876
1905
|
sink_source=sink_source))
|
1877
1906
|
|
1878
|
-
def is_finite(self):
|
1907
|
+
def is_finite(self) -> bool:
|
1879
1908
|
"""
|
1880
1909
|
Return ``True`` if ``self`` is of finite type.
|
1881
1910
|
|
@@ -1918,10 +1947,12 @@ class ClusterQuiver(SageObject):
|
|
1918
1947
|
return (type(mt) in [QuiverMutationType_Irreducible,
|
1919
1948
|
QuiverMutationType_Reducible] and mt.is_finite())
|
1920
1949
|
|
1921
|
-
def is_mutation_finite(
|
1950
|
+
def is_mutation_finite(self, nr_of_checks=None, return_path=False) -> bool:
|
1922
1951
|
"""
|
1923
|
-
|
1924
|
-
|
1952
|
+
Return whether ``self`` is mutation-finite.
|
1953
|
+
|
1954
|
+
This uses a non-deterministic method by random mutations in various
|
1955
|
+
directions. This can result in a wrong answer.
|
1925
1956
|
|
1926
1957
|
INPUT:
|
1927
1958
|
|
@@ -1933,7 +1964,8 @@ class ClusterQuiver(SageObject):
|
|
1933
1964
|
|
1934
1965
|
ALGORITHM:
|
1935
1966
|
|
1936
|
-
A quiver is mutation infinite if and only if every
|
1967
|
+
A quiver is mutation infinite if and only if every
|
1968
|
+
edge label (a,-b) satisfy a*b > 4.
|
1937
1969
|
Thus, we apply random mutations in random directions
|
1938
1970
|
|
1939
1971
|
EXAMPLES::
|
@@ -1943,7 +1975,8 @@ class ClusterQuiver(SageObject):
|
|
1943
1975
|
sage: Q.is_mutation_finite()
|
1944
1976
|
True
|
1945
1977
|
|
1946
|
-
sage: Q = ClusterQuiver([(0,1),(1,2),(2,3),(3,4),
|
1978
|
+
sage: Q = ClusterQuiver([(0,1),(1,2),(2,3),(3,4),
|
1979
|
+
....: (4,5),(5,6),(6,7),(7,8),(2,9)])
|
1947
1980
|
sage: Q.is_mutation_finite()
|
1948
1981
|
False
|
1949
1982
|
"""
|
@@ -1969,17 +2002,17 @@ class ClusterQuiver(SageObject):
|
|
1969
2002
|
M = _dig6_to_matrix(dig6)
|
1970
2003
|
|
1971
2004
|
is_finite, path = is_mutation_finite(M, nr_of_checks=nr_of_checks)
|
1972
|
-
if return_path
|
1973
|
-
return is_finite, path
|
1974
|
-
else:
|
1975
|
-
return is_finite
|
2005
|
+
return (is_finite, path) if return_path else is_finite
|
1976
2006
|
|
1977
2007
|
def number_of_edges(self):
|
1978
2008
|
r"""
|
1979
2009
|
Return the total number of edges on the quiver.
|
1980
2010
|
|
1981
|
-
|
1982
|
-
|
2011
|
+
.. NOTE::
|
2012
|
+
|
2013
|
+
This only works with non-valued quivers. If used on a
|
2014
|
+
non-valued quiver then the positive value is taken to be
|
2015
|
+
the number of edges added.
|
1983
2016
|
|
1984
2017
|
OUTPUT: integer of the number of edges
|
1985
2018
|
|
@@ -1991,13 +2024,7 @@ class ClusterQuiver(SageObject):
|
|
1991
2024
|
sage: S = ClusterQuiver(['B',4]); S.number_of_edges()
|
1992
2025
|
3
|
1993
2026
|
"""
|
1994
|
-
|
1995
|
-
|
1996
|
-
total_edges = 0
|
1997
|
-
for edge in digraph_edges:
|
1998
|
-
total_edges += edge[2][0]
|
1999
|
-
|
2000
|
-
return total_edges
|
2027
|
+
return sum(label[0] for label in self.digraph().edge_labels())
|
2001
2028
|
|
2002
2029
|
def relabel(self, relabelling, inplace=True):
|
2003
2030
|
r"""
|
@@ -2026,11 +2053,11 @@ class ClusterQuiver(SageObject):
|
|
2026
2053
|
dict_labels = {}
|
2027
2054
|
|
2028
2055
|
# Organize labels noting that for:
|
2029
|
-
# _digraph: {
|
2056
|
+
# _digraph: {old_vertex: new_vertex}
|
2030
2057
|
# _vertex_dictionary: {num: new_vertex}
|
2031
2058
|
if isinstance(relabelling, list):
|
2032
|
-
digraph_labels =
|
2033
|
-
dict_labels =
|
2059
|
+
digraph_labels = dict(zip(old_vertices, relabelling))
|
2060
|
+
dict_labels = dict(enumerate(relabelling))
|
2034
2061
|
elif isinstance(relabelling, dict):
|
2035
2062
|
# need to make sure we map correctly
|
2036
2063
|
for key in relabelling:
|
@@ -2198,11 +2225,12 @@ class ClusterQuiver(SageObject):
|
|
2198
2225
|
...
|
2199
2226
|
ValueError: only makes sense for quivers of finite type
|
2200
2227
|
"""
|
2228
|
+
from sage.geometry.fan import Fan
|
2229
|
+
|
2201
2230
|
if not self.is_finite():
|
2202
2231
|
raise ValueError('only makes sense for quivers of finite type')
|
2203
2232
|
|
2204
2233
|
from .cluster_seed import ClusterSeed
|
2205
|
-
from sage.geometry.fan import Fan
|
2206
2234
|
from sage.geometry.cone import Cone
|
2207
2235
|
|
2208
2236
|
seed = ClusterSeed(self)
|
@@ -2252,8 +2280,8 @@ class ClusterQuiver(SageObject):
|
|
2252
2280
|
ValueError: only supported for quivers of finite type
|
2253
2281
|
"""
|
2254
2282
|
from .cluster_seed import ClusterSeed
|
2255
|
-
from sage.geometry.fan import Fan
|
2256
2283
|
from sage.geometry.cone import Cone
|
2284
|
+
from sage.geometry.fan import Fan
|
2257
2285
|
|
2258
2286
|
if not (self.is_finite()):
|
2259
2287
|
raise ValueError('only supported for quivers of finite type')
|