Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*- ClusterSeed
A *cluster seed* is a pair `(B,\mathbf{x})` with `B` being a *skew-symmetrizable* `(n+m \times n)` *-matrix* and with `\mathbf{x}` being an `n`-tuple of *independent elements* in the field of rational functions in `n` variables.
For the compendium on the cluster algebra and quiver package see [MS2011]_.
AUTHORS:
- Gregg Musiker: Initial Version - Christian Stump: Initial Version - Aram Dermenjian (2015-07-01): Updating ability to not rely solely on clusters - Jesse Levitt (2015-07-01): Updating ability to not rely solely on clusters
REFERENCES:
- [FZ2007]_
- [BDP2013]_
.. SEEALSO:: For mutation types of cluster seeds, see :meth:`sage.combinat.cluster_algebra_quiver.quiver_mutation_type.QuiverMutationType`. Cluster seeds are closely related to :meth:`sage.combinat.cluster_algebra_quiver.quiver.ClusterQuiver`. """
#***************************************************************************** # Copyright (C) 2011 Gregg Musiker <musiker@math.mit.edu> # Christian Stump <christian.stump@univie.ac.at> # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ #*****************************************************************************
r""" The *cluster seed* associated to an *exchange matrix*.
INPUT:
- ``data`` -- can be any of the following::
* QuiverMutationType * str - a string representing a QuiverMutationType or a common quiver type (see Examples) * ClusterQuiver * Matrix - a skew-symmetrizable matrix * DiGraph - must be the input data for a quiver * List of edges - must be the edge list of a digraph for a quiver
EXAMPLES::
sage: S = ClusterSeed(['A',5]); S A seed for a cluster algebra of rank 5 of type ['A', 5]
sage: S = ClusterSeed(['A',[2,5],1]); S A seed for a cluster algebra of rank 7 of type ['A', [2, 5], 1]
sage: T = ClusterSeed( S ); T A seed for a cluster algebra of rank 7 of type ['A', [2, 5], 1]
sage: T = ClusterSeed( S._M ); T A seed for a cluster algebra of rank 7
sage: T = ClusterSeed( S.quiver()._digraph ); T A seed for a cluster algebra of rank 7
sage: T = ClusterSeed( S.quiver()._digraph.edges() ); T A seed for a cluster algebra of rank 7
sage: S = ClusterSeed(['B',2]); S A seed for a cluster algebra of rank 2 of type ['B', 2]
sage: S = ClusterSeed(['C',2]); S A seed for a cluster algebra of rank 2 of type ['B', 2]
sage: S = ClusterSeed(['A', [5,0],1]); S A seed for a cluster algebra of rank 5 of type ['D', 5]
sage: S = ClusterSeed(['GR',[3,7]]); S A seed for a cluster algebra of rank 6 of type ['E', 6]
sage: S = ClusterSeed(['F', 4, [2,1]]); S A seed for a cluster algebra of rank 6 of type ['F', 4, [1, 2]]
sage: S = ClusterSeed(['A',4]); S._use_fpolys True
sage: S._use_d_vec True
sage: S._use_g_vec True
sage: S._use_c_vec True
sage: S = ClusterSeed(['A', 4]); S.use_fpolys(False); S._use_fpolys False
sage: S = ClusterSeed(DiGraph([['a', 'b'], ['c', 'b'], ['c', 'd'], ['e', 'd']]), frozen = \ ['c']); S A seed for a cluster algebra of rank 4 with 1 frozen variable
sage: S = ClusterSeed(['D', 4],user_labels = [-1, 0, 1, 2]);S A seed for a cluster algebra of rank 4 of type ['D', 4] """ r"""
Initializes the ClusterSeed ``self`` with the following range of possible attributes:
* self._n - the number of mutable elements of the cluster seed. * self._m - the number of immutable elements of the cluster seed. * self._nlist - a list of mutable elements of the cluster seed. * self._mlist - a list of immutable elements of the cluster seed. * self._M - the 'n + m' x 'n' exchange matrix associated to the cluster seed. * self._B - the mutable part of self._M. * self._b_initial - the initial exchange matrix * self._description - the description of the ClusterSeed * self._use_fpolys - a boolean tracking whether F-polynomials and cluster variables will be tracked as part of every mutation. * self._cluster - a list tracking the current names of cluster elements. * self._user_labels_prefix - the prefix for every named cluster element. Defaults to 'x'. * self._user_labels - an optional dictionary or list of user defined names for all cluster elements. Defaults to ``'x_i'`` for mutable elements and ``'y_i'`` for immutable elements. All labels should be integers or alphanumeric strings. * self._init_vars - an internal list for defining ambient the algebraic setting and naming quiver vertices. * self._init_exch - the dictionary storing the initial mutable cluster variable names. * self._U - the coefficient tuple of the initial cluster seed. * self._F - the dictionary of F-polynomials. * self._R - the ambient polynomial ring. * self._y - the coefficient tuple for the current cluster seed. * self._yhat - the mixed coefficient tuple appearing in Proposition 3.9 of [FZ2007] * self._use_g_vec - a boolean stating if g-vectors for the cluster seed are being tracked. User input overridden as needed. * self._G - the matrix containing all g-vectors. * self._use_d_vec - a boolean stating if d-vectors for the cluster seed are being tracked. * self._D - the matrix containing all d-vectors. * self._bot_is_c - a boolean stating if the c-vectors are stored on the bottom of the exchange matrix M. * self._use_c_vec - a boolean stating if c-vectors for the cluster seed are being tracked. User input overridden as needed. * self._C - the matrix containing all c-vectors. * self._BC - an extended matrix involving the B and C matrices used for simplifying mutation calculations. * self._is_principal - a boolean tracking whether the ClusterSeed contains immutable elements coming from a principal extension of the mutable vertices. To be deprecated in future versions.
* self._quiver - the ClusterQuiver corresponding to the exchange matrix self._M . * self._mutation_type - the mutation type of self._quiver .
* self._track_mut - a boolean tracking whether the a ClusterSeed's mutation path is being recorded. * self._mut_path - the list of integers recording the mutation path of a seed - with consecutive repeats deleted since mutations is an involution.
TESTS::
sage: S = ClusterSeed(['A',4]) sage: TestSuite(S).run() """ #initialize a null state ClusterSeed object so all tests run and fail as appropriate. # numerous doctests if this null state is not first initialized.
# ensures user_labels are immutable
# constructs a cluster seed from a cluster seed print("The input \'frozen\' is ignored")
# Copy the following attributes from data
# initialize matrix of g-vectors if desired and possible
# initialize matrix of c-vectors if desired and possible else: self._BC = copy(self._M)
# initialize matrix of d-vectors if desired and possible
# copy all previous booleans
# copy all previous dictionaries, names and data
# constructs a cluster seed from a quiver
# If initializing from a ClusterQuiver rather than a ClusterSeed, the initial B-matrix is reset to be the input B-matrix.
# Sets ``user_labels`` to existing vertex labels else: # Sanitizes our ``user_labels`` to use Integers instead of ints raise ValueError('user_labels conflict with both the given' ' vertex labels and the default labels')
# We are now updating labels from user's most recent choice.
# initialize the rest
else:
#self._cluster = None
# in all other cases, we construct the corresponding ClusterQuiver first else: is_principal=is_principal, user_labels=user_labels, user_labels_prefix=user_labels_prefix)
r""" Reconstruct c vectors from other data or initialize if no usable data exists.
Warning: Initialization may lead to inconsistent data.
INPUT:
- ``use`` -- (default:True) If True, will use c vectors - ``bot_is_c`` -- (default:False) If True and ClusterSeed self has self._m == self._n, then will assume bottom half of the extended exchange matrix is the c-matrix. If true, lets the ClusterSeed know c-vectors can be calculated.
EXAMPLES::
sage: S = ClusterSeed(['A',4]); sage: S.use_c_vectors(False); S.use_g_vectors(False); S.use_fpolys(False); S.track_mutations(False) sage: S.use_c_vectors(True) Warning: Initializing c-vectors at this point could lead to inconsistent seed data.
sage: S.use_c_vectors(True, force=True) sage: S.c_matrix() [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]
sage: S = ClusterSeed(['A',4]); sage: S.use_c_vectors(False); S.use_g_vectors(False); S.use_fpolys(False); S.track_mutations(False) sage: S.mutate(1); sage: S.use_c_vectors(True, force=True) sage: S.c_matrix() [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]
""" #self._C = matrix.identity(self._n) else: except AttributeError: if not force: print("Warning: Initializing c-vectors at this point could lead to inconsistent seed data.") else: self._use_c_vec = True self._C = matrix.identity(self._n) self._BC = copy(self._M).stack(self.c_matrix()) else: else: # self._n != self._m raise ValueError('There are immutable elements not in the c-matrix. Storing the c-matrix separately.') self._C = copy(self._M[self._m:(self._n+self._m),:self._n]) self._BC = copy(self._M) self._M = self._M[:self._m:self._n] self._M.set_immutable() self._bot_is_c = False
r""" Reconstruct g vectors from other data or initialize if no usable data exists.
Warning: Initialization may lead to inconsistent data.
INPUT:
- ``use`` -- (default:True) If True, will use g vectors
EXAMPLES::
sage: S = ClusterSeed(['A',4]); sage: S.use_g_vectors(False); S.use_fpolys(False) sage: S.use_g_vectors(True) sage: S.g_matrix() [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]
sage: S = ClusterSeed(['A',4]); sage: S.use_g_vectors(False); S.use_fpolys(False) sage: S.mutate(1); sage: S.use_g_vectors(True) sage: S.g_matrix() [ 1 0 0 0] [ 0 -1 0 0] [ 0 0 1 0] [ 0 0 0 1]
sage: S = ClusterSeed(['A',4]); sage: S.use_g_vectors(False); S.use_fpolys(False); S.track_mutations(False) sage: S.mutate(1); sage: S.use_c_vectors(False) sage: S.g_matrix() Traceback (most recent call last): ... ValueError: Unable to calculate g-vectors. Need to use g vectors.
sage: S = ClusterSeed(['A',4]); sage: S.use_g_vectors(False); S.use_fpolys(False); S.track_mutations(False) sage: S.mutate(1); sage: S.use_c_vectors(False) sage: S.use_g_vectors(True) Warning: Initializing g-vectors at this point could lead to inconsistent seed data.
sage: S.use_g_vectors(True, force=True) sage: S.g_matrix() [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] """ #self._G = matrix.identity(self._n) if self._use_g_vec else None else: except AttributeError: if not force: print("Warning: Initializing g-vectors at this point could lead to inconsistent seed data.") else: self._use_g_vec = True self._G = matrix.identity(self._n) else:
# Initially coded so c_vectors would be turned back on but now each of these boolean flags are independent #if self._use_g_vec and not self._use_c_vec: # self.use_c_vectors(True)
r""" Reconstruct d vectors from other data or initialize if no usable data exists.
Warning: Initialization may lead to inconsistent data.
INPUT:
- ``use`` -- (default:True) If True, will use d vectors
EXAMPLES::
sage: S = ClusterSeed(['A',4]); sage: S.use_d_vectors(True) sage: S.d_matrix() [-1 0 0 0] [ 0 -1 0 0] [ 0 0 -1 0] [ 0 0 0 -1]
sage: S = ClusterSeed(['A',4]); S.use_d_vectors(False); S.track_mutations(False); S.mutate(1); S.d_matrix() [-1 0 0 0] [ 0 1 0 0] [ 0 0 -1 0] [ 0 0 0 -1] sage: S.use_fpolys(False) sage: S.d_matrix() Traceback (most recent call last): ... ValueError: Unable to calculate d-vectors. Need to use d vectors.
sage: S = ClusterSeed(['A',4]); S.use_d_vectors(False); S.track_mutations(False); S.mutate(1); S.d_matrix() [-1 0 0 0] [ 0 1 0 0] [ 0 0 -1 0] [ 0 0 0 -1] sage: S.use_fpolys(False) sage: S.use_d_vectors(True) Warning: Initializing d-vectors at this point could lead to inconsistent seed data.
sage: S.use_d_vectors(True, force=True) sage: S.d_matrix() [-1 0 0 0] [ 0 -1 0 0] [ 0 0 -1 0] [ 0 0 0 -1]
sage: S = ClusterSeed(['A',4]); S.mutate(1); S.d_matrix() [-1 0 0 0] [ 0 1 0 0] [ 0 0 -1 0] [ 0 0 0 -1] sage: S = ClusterSeed(['A',4]); S.use_d_vectors(True); S.mutate(1); S.d_matrix() [-1 0 0 0] [ 0 1 0 0] [ 0 0 -1 0] [ 0 0 0 -1] """ else: except AttributeError: if not force: print("Warning: Initializing d-vectors at this point could lead to inconsistent seed data.") else: self._use_d_vec = True # if not just sets it to be negative identity matrix, i.e. reinitialized. self._D = -matrix.identity(self._n) else:
r""" Use F-polynomials in our Cluster Seed
Note: This will automatically try to recompute the cluster variables if possible
INPUT:
- ``use`` -- (default:True) If True, will use F-polynomials - ``user_labels`` -- (default:None) If set will overwrite the default cluster variable labels - ``user_labels_prefix`` -- (default:None) If set will overwrite the default
EXAMPLES::
sage: S = ClusterSeed(['A',4]); S.use_fpolys(False); S._cluster sage: S.use_fpolys(True) sage: S.cluster() [x0, x1, x2, x3]
sage: S = ClusterSeed(['A',4]); S.use_fpolys(False); S.track_mutations(False); S.mutate(1) sage: S.use_fpolys(True) Traceback (most recent call last): ... ValueError: F-polynomials and Cluster Variables cannot be reconstructed from given data. sage: S.cluster() Traceback (most recent call last): ... ValueError: Clusters not being tracked
""" self._user_labels = user_labels self._user_labels_prefix = user_labels_prefix
self._sanitize_init_vars(user_labels, user_labels_prefix) else:
self.use_g_vectors(True) raise ValueError("should not be possible to have cluster variables without f-polynomials") # added this as a sanity check. This error should never appear however. if not self._use_g_vec: self.use_g_vectors(True) catchup = ClusterSeed(self._b_initial, user_labels=user_labels, user_labels_prefix=user_labels_prefix) catchup.use_c_vectors(use=self._use_c_vec,bot_is_c=self._bot_is_c) catchup.mutate(self.mutations())
self._init_exch = catchup._init_exch self._U = catchup._U self._F = catchup._F self._R = catchup._R self._y = catchup._y self._yhat = catchup._yhat else:
# since we have F polynomials, set up clusters properly else: print("Warning: since 'use_fpolys' is False, the parameter 'user_labels' is ignored.")
r""" Begins tracking the mutation path.
Warning: May initialize all other data to ensure that all c, d, and g vectors agree on the start of mutations.
INPUT:
- ``use`` -- (default:True) If True, will begin filling the mutation path
EXAMPLES::
sage: S = ClusterSeed(['A',4]); S.track_mutations(False) sage: S.mutate(0) sage: S.mutations() Traceback (most recent call last): ... ValueError: Not recording mutation sequence. Need to track mutations. sage: S.track_mutations(True) sage: S.g_matrix() [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]
sage: S.mutate([0,1]) sage: S.mutations() [0, 1] """
# use_f = self._use_fpolys #### also reinitialize F polynomials? -J # if use_f: # self.use_fpolys(False) # if use_f: # self.use_fpolys() else:
r""" Rewrite a user-given set of cluster variable names into a format that Sage can utilize.
INPUT:
- ``user_labels`` -- The labels that need sanitizing - ``user_labels_prefix`` -- (default:'x') The prefix to use for labels if integers given for labels
EXAMPLES::
sage: S = ClusterSeed(['A', 4]); S._init_vars {0: 'x0', 1: 'x1', 2: 'x2', 3: 'x3', 4: 'y0', 5: 'y1', 6: 'y2', 7: 'y3'} sage: S._sanitize_init_vars([1, 2, 3, 4], 'z') sage: S._init_vars {0: 'z1', 1: 'z2', 2: 'z3', 3: 'z4'}
sage: S = ClusterSeed(['A', 4]); S._init_vars {0: 'x0', 1: 'x1', 2: 'x2', 3: 'x3', 4: 'y0', 5: 'y1', 6: 'y2', 7: 'y3'} sage: S._sanitize_init_vars(['a', 'b', 'c', 'd']) sage: S._init_vars {0: 'a', 1: 'b', 2: 'c', 3: 'd'} """ else: else: strng = strng + "_" + 'neg' + (-j).str() else: strng = strng + "_" + j else: self._user_labels_prefix = user_labels_prefix strng = self._user_labels_prefix for j in user_labels[key]: if isinstance(j, Integer): if j >= 0: strng = strng + "_" + j.str() else: strng = strng + "_" + 'neg' + (-j).str() else: strng = strng + "_" + j self._init_vars[key] = strng else: else: raise ValueError("the input 'user_labels' must be a dictionary or a list")
" number of exchangeable and frozen variables")
r""" Will force set the c matrix according to a matrix, a quiver, or a seed.
INPUT:
- ``data`` -- The matrix to set the c matrix to. Also allowed to be a quiver or cluster seed, in which case the b_matrix is used.
EXAMPLES::
sage: S = ClusterSeed(['A',3]); sage: X = matrix([[0,0,1],[0,1,0],[1,0,0]]) sage: S.set_c_matrix(X) sage: S.c_matrix() [0 0 1] [0 1 0] [1 0 0]
sage: Y = matrix([[-1,0,1],[0,1,0],[1,0,0]]) sage: S.set_c_matrix(Y) C matrix does not look to be valid - there exists a column containing positive and negative entries. Continuing...
sage: Z = matrix([[1,0,1],[0,1,0],[2,0,2]]) sage: S.set_c_matrix(Z) C matrix does not look to be valid - not a linearly independent set. Continuing... """ data = data.b_matrix() data=data.b_matrix()
# Do a quick check to make sure that each column is either all # positive or all negative. # Can do this through green/red vertices
r""" Returns True iff ``self`` represent the same cluster seed as ``other`` and all tracked data agrees.
EXAMPLES::
sage: S = ClusterSeed(['A',5]) sage: T = S.mutate( 2, inplace=False ) sage: S.__eq__( T ) False
sage: T.mutate( 2 ) sage: S.__eq__( T ) True
sage: S = ClusterSeed(['A',2]) sage: T = ClusterSeed(S) sage: S.__eq__( T ) True
sage: S.mutate([0,1,0,1,0]) sage: S.__eq__( T ) False sage: S.cluster() [x1, x0] sage: T.cluster() [x0, x1]
sage: S.mutate([0,1,0,1,0]) sage: S.__eq__( T ) True sage: S.cluster() [x0, x1] """ return False elif self._use_g_vec and other._use_g_vec: g_vec = self.g_matrix() == other.g_matrix()
""" Return a hash of ``self``.
EXAMPLES::
sage: Q = ClusterSeed(['A',5]) sage: hash(Q) # indirect doctest -5649412990944896369 # 64-bit 222337679 # 32-bit """ # mat_hash = self._M.__hash__() elif self._use_g_vec: return hash(self.g_matrix()) elif self._use_c_vec: return hash(self.c_matrix()) elif self._use_d_vec: return hash(self.d_matrix())
r""" Returns the description of ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A',5]) sage: S._repr_() "A seed for a cluster algebra of rank 5 of type ['A', 5]"
sage: S=ClusterSeed(['B',2]) sage: T=S.principal_extension() sage: T._repr_() "A seed for a cluster algebra of rank 2 of type ['B', 2] with principal coefficients" """ # the following case allows description of 'undetermined finite mutation type' else: name += ' of ' + self._mutation_type
r""" Returns the plot of the quiver of ``self``.
INPUT:
- ``circular`` -- (default:False) if True, the circular plot is chosen, otherwise >>spring<< is used. - ``mark`` -- (default: None) if set to i, the vertex i is highlighted. - ``save_pos`` -- (default:False) if True, the positions of the vertices are saved. - ``force_c`` -- (default:False) if True, will show the frozen vertices even if they were never initialized - ``with_greens`` -- (default:False) if True, will display the green vertices in green - ``add_labels`` -- (default:False) if True, will use the initial variables as labels
EXAMPLES::
sage: S = ClusterSeed(['A',5]) sage: pl = S.plot() sage: pl = S.plot(circular=True) """
greens = self.green_vertices()
quiver = ClusterQuiver(self._BC) # relabelling multiple times causes errors, so we need to always do it in place quiver = self.quiver().relabel(self._init_vars, inplace=True) else:
r""" Shows the plot of the quiver of ``self``.
INPUT:
- ``fig_size`` -- (default: 1) factor by which the size of the plot is multiplied. - ``circular`` -- (default: False) if True, the circular plot is chosen, otherwise >>spring<< is used. - ``mark`` -- (default: None) if set to i, the vertex i is highlighted. - ``save_pos`` -- (default:False) if True, the positions of the vertices are saved. - ``force_c`` -- (default:False) if True, will show the frozen vertices even if they were never initialized - ``with_greens`` -- (default:False) if True, will display the green vertices in green - ``add_labels`` -- (default:False) if True, will use the initial variables as labels
TESTS::
sage: S = ClusterSeed(['A',5]) sage: S.show() # long time """
greens = [] if with_greens: greens = self.green_vertices()
if force_c: quiver = ClusterQuiver(self._BC) elif add_labels: # relabelling multiple times causes errors, so we need to always do it in place quiver = self.quiver().relabel(self._init_vars, inplace=True) else: quiver = self.quiver()
quiver.show(fig_size=fig_size, circular=circular,mark=mark,save_pos=save_pos, greens=greens)
r""" Only in *notebook mode*. Starts an interactive window for cluster seed mutations.
INPUT:
- ``fig_size`` -- (default: 1) factor by which the size of the plot is multiplied. - ``circular`` -- (default: True) if True, the circular plot is chosen, otherwise >>spring<< is used.
TESTS::
sage: S = ClusterSeed(['A',4]) sage: S.interact() # long time 'The interactive mode only runs in the Sage notebook.' """ # Also update so works in cloud and not just notebook from sage.plot.plot import EMBEDDED_MODE from sagenb.notebook.interact import interact, selector from sage.misc.all import html,latex from sage.repl.rich_output.pretty_print import pretty_print
if not EMBEDDED_MODE: return "The interactive mode only runs in the Sage notebook." else: seq = [] sft = [True] sss = [True] ssv = [True] ssm = [True] ssl = [True] @interact def player(k=selector(values=list(range(self._n)), nrows = 1, label='Mutate at: '), show_seq=("Mutation sequence:", True), show_vars=("Cluster variables:", True), show_matrix=("B-Matrix:", True), show_lastmutation=("Show last mutation:", True)): ft, ss, sv, sm, sl = sft.pop(), sss.pop(), ssv.pop(), ssm.pop(), ssl.pop() if ft: self.show(fig_size=fig_size, circular=circular) elif show_seq is not ss or show_vars is not sv or show_matrix is not sm or show_lastmutation is not sl: if seq and show_lastmutation: self.show(fig_size=fig_size, circular=circular, mark=seq[len(seq) - 1]) else: self.show(fig_size=fig_size, circular=circular ) else: self.mutate(k) seq.append(k) if not show_lastmutation: self.show(fig_size=fig_size, circular=circular) else: self.show(fig_size=fig_size, circular=circular, mark=k) sft.append(False) sss.append(show_seq) ssv.append(show_vars) ssm.append(show_matrix) ssl.append(show_lastmutation) if show_seq: pretty_print(html("Mutation sequence: $" + str( [ seq[i] for i in range(len(seq)) ] ).strip('[]') + "$")) if show_vars: pretty_print(html("Cluster variables:")) table = "$\\begin{align*}\n" for i in range(self._n): table += "\tv_{%s} &= " % i + latex(self.cluster_variable(i)) + "\\\\ \\\\\n" table += "\\end{align*}$" pretty_print(html("$ $")) pretty_print(html(table)) pretty_print(html("$ $")) if show_matrix: pretty_print(html("B-Matrix:")) pretty_print(html(self._M)) pretty_print(html("$ $"))
r""" Saves the plot of the underlying digraph of the quiver of ``self``.
INPUT:
- ``filename`` -- the filename the image is saved to. - ``circular`` -- (default: False) if True, the circular plot is chosen, otherwise >>spring<< is used. - ``mark`` -- (default: None) if set to i, the vertex i is highlighted. - ``save_pos`` -- (default:False) if True, the positions of the vertices are saved.
EXAMPLES::
sage: S = ClusterSeed(['F',4,[1,2]]) sage: S.save_image(os.path.join(SAGE_TMP, 'sage.png')) """
r""" Returns the `B` *-matrix* of ``self``.
EXAMPLES::
sage: ClusterSeed(['A',4]).b_matrix() [ 0 1 0 0] [-1 0 -1 0] [ 0 1 0 1] [ 0 0 -1 0]
sage: ClusterSeed(['B',4]).b_matrix() [ 0 1 0 0] [-1 0 -1 0] [ 0 1 0 1] [ 0 0 -2 0]
sage: ClusterSeed(['D',4]).b_matrix() [ 0 1 0 0] [-1 0 -1 -1] [ 0 1 0 0] [ 0 1 0 0]
sage: ClusterSeed(QuiverMutationType([['A',2],['B',2]])).b_matrix() [ 0 1 0 0] [-1 0 0 0] [ 0 0 0 1] [ 0 0 -2 0] """
r""" Returns the *ground field* of the cluster of ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S.ground_field() Multivariate Polynomial Ring in x0, x1, x2, y0, y1, y2 over Rational Field """
r""" Return the `k` *-th initial cluster variable* for the associated cluster seed, or the cluster variable of the corresponding vertex in self.quiver.
EXAMPLES::
sage: S = ClusterSeed(['A', 3]) sage: S.mutate([2, 1]) sage: S.x(0) x0
sage: S.x(1) x1
sage: S.x(2) x2
sage: S = ClusterSeed(DiGraph([['a', 'b'], ['b', 'c']]), frozen = ['c']) sage: S.x(0) a sage: S.x('a') a """
x.numerator(), x.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable', xdim=self._n) else: raise ValueError("The input is not in an index of a cluster variable.")
r""" Return the `k` *-th initial coefficient (frozen variable)* for the \ associated cluster seed, or the cluster variable of the corresponding \ vertex in self.quiver.
EXAMPLES::
sage: S = ClusterSeed(['A', 3]).principal_extension() sage: S.mutate([2, 1]) sage: S.y(0) y0
sage: S.y(1) y1
sage: S.y(2) y2
sage: S = ClusterSeed(DiGraph([['a', 'b'], ['b', 'c']]), frozen = ['c']) sage: S.y(0) c sage: S.y('c') c """
x.numerator(), x.denominator(), mutation_type=self._mutation_type, variable_type='frozen variable', xdim=self._n) else: raise ValueError("The input is not in an index of a frozen variable.")
r""" Return the number of *exchangeable variables* of ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A', 3]) sage: S.n() 3 """
r""" Returns the number of *frozen variables* of ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S.n() 3
sage: S.m() 0
sage: S = S.principal_extension() sage: S.m() 3 """
r""" Return the list of *exchangable vertices* of ``self``.
EXAMPLES::
sage: S = ClusterSeed(DiGraph([['a', 'b'], ['c', 'b'], ['c', 'd'], ['e', 'd']]), \ frozen = ['b', 'd']) sage: S.free_vertices() ['a', 'c', 'e']
sage: S=ClusterSeed(DiGraph([[5, 'b']])) sage: S.free_vertices() [5, 'b'] """
r""" Return the list of *frozen vertices* of ``self``.
EXAMPLES::
sage: S = ClusterSeed(DiGraph([['a', 'b'], ['c', 'b'], ['c', 'd'], ['e', 'd']]), \ frozen = ['b', 'd']) sage: S.frozen_vertices() ['b', 'd'] """
r""" Returns the list of mutations ``self`` has undergone if they are being tracked.
Examples::
sage: S = ClusterSeed(['A',3]) sage: S.mutations() []
sage: S.mutate([0,1,0,2]) sage: S.mutations() [0, 1, 0, 2]
sage: S.track_mutations(False) sage: S.mutations() Traceback (most recent call last): ... ValueError: Not recording mutation sequence. Need to track mutations. """ else:
r""" Generates a cluster variable using F-polynomials
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S.mutate([0,1]) sage: S.cluster_variable(0) (x1 + 1)/x0 sage: S.cluster_variable(1) (x0*x2 + x1 + 1)/(x0*x1) """ elif k in IE: k = IE.index(k)
else: raise ValueError('No cluster variable with index or label ' + str(k) + '.') elif self._track_mut: # if we can recreate the clusters catchup = ClusterSeed(self._b_initial, user_labels=self._user_labels, user_labels_prefix=self._user_labels_prefix) catchup.use_c_vectors(use=self._use_c_vec, bot_is_c=self._bot_is_c) catchup.mutate(self.mutations()) return catchup.cluster_variable(k) else: raise ValueError('Clusters not being tracked') return None
r""" Returns a copy of the *cluster* of ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S.cluster() [x0, x1, x2]
sage: S.mutate(1) sage: S.cluster() [x0, (x0*x2 + 1)/x1, x2]
sage: S.mutate(2) sage: S.cluster() [x0, (x0*x2 + 1)/x1, (x0*x2 + x1 + 1)/(x1*x2)]
sage: S.mutate([2,1]) sage: S.cluster() [x0, x1, x2] """
else:
r""" An internal procedure that returns ``self`` with F-polynomials mutated at k.
WARNING: This function assumes you are sending it good data
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S._f_mutate(0) sage: S.f_polynomial(0) y0 + 1 """ else: IE = []
# F-polynomials
else: else:
# can the following be improved?
r""" Return the ``k``-th *F-polynomial* of ``self``. It is obtained from the ``k``-th cluster variable by setting all `x_i` to `1`.
Warning: this method assumes the sign-coherence conjecture and that the input seed is sign-coherent (has an exchange matrix with columns of like signs). Otherwise, computational errors might arise.
EXAMPLES::
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) sage: [S.f_polynomial(k) for k in range(3)] [1, y1*y2 + y2 + 1, y1 + 1]
sage: S = ClusterSeed(Matrix([[0,1],[-1,0],[1,0],[-1,1]])); S.use_c_vectors(bot_is_c=True); S A seed for a cluster algebra of rank 2 with 2 frozen variables sage: T = ClusterSeed(Matrix([[0,1],[-1,0]])).principal_extension(); T A seed for a cluster algebra of rank 2 with principal coefficients sage: S.mutate(0) sage: T.mutate(0) sage: S.f_polynomials() [y0 + y1, 1] sage: T.f_polynomials() [y0 + 1, 1] """ elif k in IE: k = IE.index(k) else: raise ValueError("The cluster seed does not have a cluster variable of index %s."%k)
else: raise ValueError("Turn on use_fpolys to get F polynomial %s."%k)
r""" Return all *F-polynomials* of ``self``. These are obtained from the cluster variables by setting all `x_i`'s to `1`.
Warning: this method assumes the sign-coherence conjecture and that the input seed is sign-coherent (has an exchange matrix with columns of like signs). Otherwise, computational errors might arise.
EXAMPLES::
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) sage: S.f_polynomials() [1, y1*y2 + y2 + 1, y1 + 1] """
r""" Return the ``k``-th *g-vector* of ``self``. This is the degree vector of the ``k``-th cluster variable after setting all `y_i`'s to `0`.
Warning: this method assumes the sign-coherence conjecture and that the input seed is sign-coherent (has an exchange matrix with columns of like signs). Otherwise, computational errors might arise.
EXAMPLES::
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) sage: [ S.g_vector(k) for k in range(3) ] [(1, 0, 0), (0, 0, -1), (0, -1, 0)] """
raise ValueError("Unable to calculate g-vectors. Need to use g vectors.") raise ValueError("The cluster seed does not have a cluster variable of index %s."%k)
elif self._use_fpolys and self._cluster: f = copy(self.cluster_variable(k)) eval_dict = dict( [ ( self.y(i), 0 ) for i in range(self._m) ] ) f0 = f.subs(eval_dict) d1 = f0.numerator().degrees() d2 = f0.denominator().degrees() return tuple( d1[i] - d2[i] for i in range(self._n) ) else: # in the is_principal=True case try: # ensure that we cannot create a loop by calling g_matrix() here by filtering out loop causing conditions in the previous if-elif sections return self.g_matrix().column(k) except ValueError: raise ValueError("Unable to calculate g-vectors. Need to use g vectors.")
r""" Return the matrix of all *g-vectors* of ``self``. These are the degree vectors of the cluster variables after setting all `y_i`'s to `0`.
Warning: this method assumes the sign-coherence conjecture and that the input seed is sign-coherent (has an exchange matrix with columns of like signs). Otherwise, computational errors might arise.
EXAMPLES::
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) sage: S.g_matrix() [ 1 0 0] [ 0 0 -1] [ 0 -1 0]
sage: S = ClusterSeed(['A',3]) sage: S.mutate([0,1]) sage: S.g_matrix() [-1 -1 0] [ 1 0 0] [ 0 0 1]
sage: S = ClusterSeed(['A',4]); S.use_g_vectors(False); S.use_fpolys(False); S.g_matrix() [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]
sage: S = ClusterSeed(['A',4]) sage: S.use_g_vectors(False); S.use_c_vectors(False); S.use_fpolys(False); S.track_mutations(False); S.g_matrix() Traceback (most recent call last): ... ValueError: Unable to calculate g-vectors. Need to use g vectors. """
return matrix( [ self.g_vector(k) for k in range(self._n) ] ).transpose() elif self._track_mut: BC1 = copy(self._b_initial[0:self._n]) BC1 = -BC1.transpose() BC1 = BC1.stack(matrix.identity(self._n)) seq = iter(self.mutations()) for k in seq: BC1.mutate(k) return copy(BC1[self._n:2*self._n]).inverse().transpose() else: raise ValueError("Unable to calculate g-vectors. Need to use g vectors.") else: return None
r""" An internal procedure that returns ``self`` with g-vectors mutated at k.
.. WARNING::
This function assumes you are sending it good data.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S._g_mutate(0) sage: S.g_vector(0) (-1, 1, 0)
REFERENCES:
[NZ2012]_ """
else:
# G-matrix else:
r""" Return the ``k``-th *c-vector* of ``self``. It is obtained as the ``k``-th column vector of the bottom part of the ``B``-matrix of ``self``.
Warning: this method assumes the sign-coherence conjecture and that the input seed is sign-coherent (has an exchange matrix with columns of like signs). Otherwise, computational errors might arise.
EXAMPLES::
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) sage: [ S.c_vector(k) for k in range(3) ] [(1, 0, 0), (0, 0, -1), (0, -1, 0)]
sage: S = ClusterSeed(Matrix([[0,1],[-1,0],[1,0],[-1,1]])); S A seed for a cluster algebra of rank 2 with 2 frozen variables sage: S.c_vector(0) (1, 0)
sage: S = ClusterSeed(Matrix([[0,1],[-1,0],[1,0],[-1,1]])); S.use_c_vectors(bot_is_c=True); S A seed for a cluster algebra of rank 2 with 2 frozen variables sage: S.c_vector(0) (1, -1)
""" raise ValueError("The cluster seed does not have a c-vector of index %s."%k) raise ValueError("Requires C vectors to use.") else: return tuple( self._M[i,k] for i in range(self._n,self._n+self._m) )
r""" Return all *c-vectors* of ``self``.
Warning: this method assumes the sign-coherence conjecture and that the input seed is sign-coherent (has an exchange matrix with columns of like signs). Otherwise, computational errors might arise.
EXAMPLES::
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) sage: S.c_matrix() [ 1 0 0] [ 0 0 -1] [ 0 -1 0]
sage: S = ClusterSeed(['A',4]); sage: S.use_g_vectors(False); S.use_fpolys(False); S.use_c_vectors(False); S.use_d_vectors(False); S.track_mutations(False); sage: S.c_matrix() Traceback (most recent call last): ... ValueError: Unable to calculate c-vectors. Need to use c vectors. """
elif self._track_mut: BC1 = copy(self._b_initial[0:self._n]) BC1 = BC1.stack(matrix.identity(self._n)) seq = iter(self.mutations()) for k in seq: BC1.mutate(k) return copy(BC1[self._n:2*self._n]) else: raise ValueError("Unable to calculate c-vectors. Need to use c vectors.") else: return None
r""" Return the ``k``-th *d-vector* of ``self``. This is the exponent vector of the denominator of the ``k``-th cluster variable.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S.mutate([2,1,2]) sage: [ S.d_vector(k) for k in range(3) ] [(-1, 0, 0), (0, 1, 1), (0, 1, 0)] """
elif self._track_mut: catchup = ClusterSeed(self._b_initial) catchup.use_fpolys(False) catchup.use_g_vectors(False) catchup.use_c_vectors(False)
catchup.mutate(self.mutations()) return copy(catchup._D).column(k) else: raise ValueError("Unable to calculate d-vector %s. Need to use d vectors."%k)
r""" Return the matrix of *d-vectors* of ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A',4]); S.d_matrix() [-1 0 0 0] [ 0 -1 0 0] [ 0 0 -1 0] [ 0 0 0 -1] sage: S.mutate([1,2,1,0,1,3]); S.d_matrix() [1 1 0 1] [1 1 1 1] [1 0 1 1] [0 0 0 1]
""" #raise ValueError("No d-vectors initialized.") elif self._track_mut: catchup = ClusterSeed(self._b_initial) catchup.use_fpolys(False) catchup.use_g_vectors(False) catchup.use_c_vectors(False) catchup.track_mutations(False)
catchup.mutate(self.mutations()) return catchup.d_matrix() elif show_warnings: raise ValueError("No valid way to calculate d-vectors")
r""" An internal procedure that returns ``self`` with d-vectors mutated at k.
WARNING: This function assumes you are sending it good data (does not check for sanitized inputs)
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S._d_mutate(0) sage: S.d_matrix() [ 1 0 0] [ 0 -1 0] [ 0 0 -1] sage: S.d_vector(0) (1, 0, 0)
""" else:
r""" Return the *coefficient* of ``self`` at index ``k``, or vertex ``k`` if ``k`` is not an index.
EXAMPLES::
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) sage: [ S.coefficient(k) for k in range(3) ] [y0, 1/y2, 1/y1] """
raise ValueError("The cluster seed does not have a coefficient of index %s."%k) return self.x(0)**0 else: except Exception: # if not try and reconstruct them exp = self.c_matrix().column(k)
r""" Return all *coefficients* of ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutate([2,1,2]) sage: S.coefficients() [y0, 1/y2, 1/y1] """ # exceptions are caught in the subroutine.
r""" Return the *quiver* associated to ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S.quiver() Quiver on 3 vertices of type ['A', 3] """
r""" Return True iff self is acyclic (i.e., if the underlying quiver is acyclic).
EXAMPLES::
sage: ClusterSeed(['A',4]).is_acyclic() True
sage: ClusterSeed(['A',[2,1],1]).is_acyclic() True
sage: ClusterSeed([[0,1],[1,2],[2,0]]).is_acyclic() False """
r""" Return True iff self is bipartite (i.e., if the underlying quiver is bipartite).
INPUT:
- return_bipartition -- (default:False) if True, the bipartition is returned in the case of ``self`` being bipartite.
EXAMPLES::
sage: ClusterSeed(['A',[3,3],1]).is_bipartite() True
sage: ClusterSeed(['A',[4,3],1]).is_bipartite() False """
r""" Return the list of green vertices of ``self``.
A vertex is defined to be green if its c-vector has all non-positive entries. More information on green vertices can be found at [BDP2013]_
OUTPUT:
The green vertices as a list of integers.
EXAMPLES::
sage: ClusterSeed(['A',3]).principal_extension().green_vertices() [0, 1, 2]
sage: ClusterSeed(['A',[3,3],1]).principal_extension().green_vertices() [0, 1, 2, 3, 4, 5] """
# Make sure we have c vectors raise ValueError("Must use c vectors to grab the vertices.")
r""" Return the first green vertex of ``self``.
A vertex is defined to be green if its c-vector has all non-positive entries. More information on green vertices can be found at [BDP2013]_
EXAMPLES::
sage: ClusterSeed(['A',3]).principal_extension().first_green_vertex() 0
sage: ClusterSeed(['A',[3,3],1]).principal_extension().first_green_vertex() 0 """ # Make sure we have c vectors raise ValueError("Must use c vectors to grab the vertices.")
return None
r""" Return the list of red vertices of ``self``.
A vertex is defined to be red if its c-vector has all non-negative entries. More information on red vertices can be found at [BDP2013]_.
OUTPUT:
The red vertices as a list of integers.
EXAMPLES::
sage: ClusterSeed(['A',3]).principal_extension().red_vertices() []
sage: ClusterSeed(['A',[3,3],1]).principal_extension().red_vertices() []
sage: Q = ClusterSeed(['A',[3,3],1]).principal_extension(); sage: Q.mutate(1); sage: Q.red_vertices() [1]
""" # Make sure we have c vectors on raise ValueError("Must use c vectors to grab the vertices.")
r""" Return the first red vertex of ``self``.
A vertex is defined to be red if its c-vector has all non-negative entries. More information on red vertices can be found at [BDP2013]_.
EXAMPLES::
sage: ClusterSeed(['A',3]).principal_extension().first_red_vertex()
sage: ClusterSeed(['A',[3,3],1]).principal_extension().first_red_vertex()
sage: Q = ClusterSeed(['A',[3,3],1]).principal_extension(); sage: Q.mutate(1); sage: Q.first_red_vertex() 1
""" # Make sure we have c vectors raise ValueError("Must use c vectors to grab the vertices.")
r""" Return the list of the urban renewal vertices of ``self``.
An urban renewal vertex is one in which there are two arrows pointing toward the vertex and two arrows pointing away.
INPUT:
- ``return_first`` -- (default:False) if True, will return the first urban renewal
OUTPUT:
A list of vertices (as integers)
EXAMPLES::
sage: G = ClusterSeed(['GR',[4,9]]); G.urban_renewals() [5, 6] """
return None
r""" Return the first urban renewal vertex.
An urban renewal vertex is one in which there are two arrows pointing toward the vertex and two arrows pointing away.
EXAMPLES::
sage: G = ClusterSeed(['GR',[4,9]]); G.first_urban_renewal() 5 """
r""" Return the vertex of the cluster polynomial with highest degree in the denominator.
INPUT:
- ``filter`` - Filter should be a list or iterable
OUTPUT:
An integer.
EXAMPLES::
sage: B = matrix([[0,-1,0,-1,1,1],[1,0,1,0,-1,-1],[0,-1,0,-1,1,1],[1,0,1,0,-1,-1],[-1,1,-1,1,0,0],[-1,1,-1,1,0,0]]) sage: C = ClusterSeed(B).principal_extension(); C.mutate([0,1,2,4,3,2,5,4,3]) sage: C.highest_degree_denominator() 5 """
# if we have d vectors use those, else see if we have clusters elif self._use_fpolys: for i in list(enumerate(self.cluster())): if i[0] not in filter: continue vari = i[1] vertex = i[0] denom = vari.denominator() cur_vertex_degree = denom.degree() if degree == cur_vertex_degree: vertex_to_mutate.append(vertex) if degree < cur_vertex_degree: degree = cur_vertex_degree vertex_to_mutate = [vertex]
r""" Return the vertex with the smallest c vector
OUTPUT:
An integer.
EXAMPLES::
sage: B = matrix([[0,2],[-2,0]]) sage: C = ClusterSeed(B).principal_extension(); sage: C.mutate(0) sage: C.smallest_c_vector() 0
"""
vertex_to_mutate.append(vertex)
r"""
Return the vertex that will produce the least degrees after mutation
EXAMPLES::
sage: S = ClusterSeed(['A',5]) sage: S.mutate([0,2,3,1,2,3,1,2,0,2,3]) sage: S.most_decreased_edge_after_mutation() 2
"""
# if we have one vertex, return it return least_vertex[0]
# if not then do a test based on which one currently has the highest degree
r"""
Return the vertex that will produce the most decrease in denominator degrees after mutation
EXAMPLES::
sage: S = ClusterSeed(['A',5]) sage: S.mutate([0,2,3,1,2,3,1,2,0,2,3]) sage: S.most_decreased_denominator_after_mutation() 2
"""
r""" Mutate ``self`` at a vertex or a sequence of vertices.
INPUT:
- ``sequence`` -- a vertex of ``self``, an iterator of vertices of ``self``, a function which takes in the :class:`ClusterSeed` and returns a vertex or an iterator of vertices, or a string representing a type of vertices to mutate - ``inplace`` -- (default: ``True``) if ``False``, the result is returned, otherwise ``self`` is modified - ``input_type`` -- (default: ``None``) indicates the type of data contained in the sequence
Possible values for vertex types in ``sequence`` are:
- ``"first_source"``: mutates at first found source vertex, - ``"sources"``: mutates at all sources, - ``"first_sink"``: mutates at first sink, - ``"sinks"``: mutates at all sink vertices, - ``"green"``: mutates at the first green vertex, - ``"red"``: mutates at the first red vertex, - ``"urban_renewal"`` or ``"urban"``: mutates at first urban renewal vertex, - ``"all_urban_renewals"`` or ``"all_urban"``: mutates at all urban renewal vertices.
For ``input_type``, if no value is given, preference will be given to vertex names, then indices, then cluster variables. If all input is not of the same type, an error is given. Possible values for ``input_type`` are:
- ``"vertices"``: interprets the input sequence as vertices - ``"indices"``: interprets the input sequence as indices - ``"cluster_vars"``: interprets the input sequence as cluster variables this must be selected if inputing a sequence of cluster variables.
EXAMPLES::
sage: S = ClusterSeed(['A',4]); S.b_matrix() [ 0 1 0 0] [-1 0 -1 0] [ 0 1 0 1] [ 0 0 -1 0]
sage: S.mutate(0); S.b_matrix() [ 0 -1 0 0] [ 1 0 -1 0] [ 0 1 0 1] [ 0 0 -1 0]
sage: T = S.mutate(0, inplace=False); T A seed for a cluster algebra of rank 4 of type ['A', 4]
sage: S.mutate(0) sage: S == T True
sage: S.mutate([0,1,0]) sage: S.b_matrix() [ 0 -1 1 0] [ 1 0 0 0] [-1 0 0 1] [ 0 0 -1 0]
sage: S = ClusterSeed(QuiverMutationType([['A',1],['A',3]])) sage: S.b_matrix() [ 0 0 0 0] [ 0 0 1 0] [ 0 -1 0 -1] [ 0 0 1 0]
sage: T = S.mutate(0,inplace=False) sage: S == T False
sage: Q = ClusterSeed(['A',3]);Q.b_matrix() [ 0 1 0] [-1 0 -1] [ 0 1 0]
sage: Q.mutate('first_sink');Q.b_matrix() [ 0 -1 0] [ 1 0 1] [ 0 -1 0]
sage: def last_vertex(self): return self._n - 1 sage: Q.mutate(last_vertex); Q.b_matrix() [ 0 -1 0] [ 1 0 -1] [ 0 1 0]
sage: S = ClusterSeed(['A', 4], user_labels=['a', 'b', 'c', 'd']); sage: S.mutate('a'); S.mutate('(b+1)/a') sage: S.cluster() [a, b, c, d]
sage: S = ClusterSeed(['A', 4], user_labels=['a', 'b', 'c']); Traceback (most recent call last): ... ValueError: the number of user-defined labels is not the number of exchangeable and frozen variables
sage: S = ClusterSeed(['A', 4], user_labels=['x', 'y', 'w', 'z']) sage: S.mutate('x') sage: S.cluster() [(y + 1)/x, y, w, z] sage: S.mutate('(y+1)/x') sage: S.cluster() [x, y, w, z] sage: S.mutate('y') sage: S.cluster() [x, (x*w + 1)/y, w, z] sage: S.mutate('(x*w+1)/y') sage: S.cluster() [x, y, w, z]
sage: S = ClusterSeed(['A', 4], user_labels=[[1, 2], [2, 3], [4, 5], [5, 6]]); sage: S.cluster() [x_1_2, x_2_3, x_4_5, x_5_6] sage: S.mutate('[1,2]'); sage: S.cluster() [(x_2_3 + 1)/x_1_2, x_2_3, x_4_5, x_5_6]
sage: S = ClusterSeed(['A', 4], user_labels=[[1, 2], [2, 3], [4, 5], [5, 6]], ....: user_labels_prefix='P'); sage: S.cluster() [P_1_2, P_2_3, P_4_5, P_5_6] sage: S.mutate('[1,2]') sage: S.cluster() [(P_2_3 + 1)/P_1_2, P_2_3, P_4_5, P_5_6] sage: S.mutate('P_4_5') sage: S.cluster() [(P_2_3 + 1)/P_1_2, P_2_3, (P_2_3*P_5_6 + 1)/P_4_5, P_5_6]
sage: S = ClusterSeed(['A', 4]) sage: S.mutate([0, 1, 0, 1, 0, 2, 1]) sage: T = ClusterSeed(S) sage: S.use_fpolys(False) sage: S.use_g_vectors(False) sage: S.use_c_vectors(False) sage: S._C sage: S._G sage: S._F sage: S.g_matrix() [ 0 -1 0 0] [ 1 1 1 0] [ 0 0 -1 0] [ 0 0 1 1] sage: S.c_matrix() [ 1 -1 0 0] [ 1 0 0 0] [ 1 0 -1 1] [ 0 0 0 1] sage: S.f_polynomials() == T.f_polynomials() True
sage: S.cluster() == T.cluster() True sage: S._mut_path [0, 1, 0, 1, 0, 2, 1]
sage: S = ClusterSeed(DiGraph([[1, 2], [2, 'c']])) sage: S.mutate(1) Input can be ambiguously interpreted as both vertices and indices. Mutating at vertices by default. sage: S.cluster() [(x2 + 1)/x1, x2, c] sage: S.mutate(1, input_type="indices") sage: S.cluster() [(x2 + 1)/x1, (x2*c + x1 + c)/(x1*x2), c]
sage: S = ClusterSeed(DiGraph([['a', 'b'], ['c', 'b'], ['d', 'b']])) sage: S.mutate(['a', 'b', 'a', 'b', 'a']) sage: S.cluster() [b, a, c, d] sage: S.mutate('a') Input can be ambiguously interpreted as both vertices and cluster variables. Mutating at vertices by default. sage: S.cluster() [(a*c*d + 1)/b, a, c, d] sage: S.mutate('a', input_type="cluster_vars") sage: S.cluster() [(a*c*d + 1)/b, (a*c*d + b + 1)/(a*b), c, d] sage: S.mutate(['(a*c*d + 1)/b', 'd']) sage: S.cluster() [(b + 1)/a, (a*c*d + b + 1)/(a*b), c, (a*c*d + b^2 + 2*b + 1)/(a*b*d)]
sage: S=ClusterSeed(DiGraph([[5, 'b']])) sage: S.mutate(5) sage: S.cluster() [(b + 1)/x5, b] sage: S.mutate([5]) sage: S.cluster() [x5, b] sage: S.mutate(0) sage: S.cluster() [(b + 1)/x5, b]
sage: S=ClusterSeed(DiGraph([[1, 2]])) sage: S.cluster() [x1, x2] sage: S.mutate(1) Input can be ambiguously interpreted as both vertices and indices. Mutating at vertices by default. sage: S.cluster() [(x2 + 1)/x1, x2]
sage: S = ClusterSeed(DiGraph([[-1, 0], [0, 1]])) sage: S.cluster() [xneg1, x0, x1] sage: S.mutate(-1);S.cluster() [(x0 + 1)/xneg1, x0, x1] sage: S.mutate(0, input_type='vertices');S.cluster() [(x0 + 1)/xneg1, (x0*x1 + xneg1 + x1)/(xneg1*x0), x1] """
# check for sanitizable data raise ValueError("the second parameter must be boolean; to mutate" " at a sequence of length 2, input it as a list")
else:
# If we get a string, execute as a function sequence = self.first_green_vertex() sequence = self.first_red_vertex() sequence = self.first_urban_renewal() sequence = self.urban_renewals() sequence = getattr(self, sequence)() # If we are given a list in string format # convert to list
sequence = sequence + "_" + j.str() else: sequence = sequence + "_" + j
# If we get a function, execute it # function should return either integer or sequence
raise ValueError('not mutating: no vertices given')
else:
or isinstance(sequence, str) or sequence in seed._nlist): else:
seqq = list(seqq) raise ValueError("the quiver can only be mutated at a vertex" " or at a sequence of vertices")
# These boolean variables classify the input type
# Note - this does not guarantee that the sequence consists of # cluster variables, it only rules out some possibilities.
# Ensures the sequence has elements of type input_type. raise ValueError('input_type set to "vertices" but not everything' ' in the mutation sequence is a vertex.')
raise ValueError('input_type set to "indices" but not everything' ' in the mutation sequence is an index.')
raise ValueError('input_type set to "cluster_vars" but not' ' everything in the mutation sequence is a' ' cluster variable.')
raise ValueError('input_type must be either "vertices",' ' "indices", or "cluster_vars"')
# Classifies the input_type. Raises warnings if the input is ambiguous, and errors if the input is not all of the same type. else: " vertices and indices." " Mutating at vertices by default.")
" both vertices and cluster variables." " Mutating at vertices by default.")
# It should be impossible to interpret an index as a cluster variable. else: raise ValueError('mutation sequences must consist of exactly' ' one of vertices, indices, or cluster variables')
except (ValueError, TypeError): raise ValueError('input interpreted as cluster variables,' ' but the input sequence did not consist' ' of cluster variables')
mutation_seed._cluster = None mutation_seed._quiver = None return mutation_seed
raise ValueError("variable provided is not in our cluster") else: raise ValueError('Why wasnt this caught earlier? Cannot mutate in direction ' + str(k) + '.')
# delete involutive mutations else:
# a mutation invalidates the cluster although it can be recomputed by F-polys and g-vectors
r""" Return the index of a cluster if ``use_fpolys`` is on.
INPUT:
- ``cluster_str`` -- the string to look for in the cluster
OUTPUT:
An integer or ``None`` if the string is not a cluster variable
EXAMPLES::
sage: S = ClusterSeed(['A', 4], user_labels=['x', 'y', 'z', 'w']); S.mutate('x') sage: S.cluster_index('x') sage: S.cluster_index('(y+1)/x') 0
""" c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable', xdim=self._n)
fig_size=1.2, return_output='seed'): r""" Return the seeds obtained by mutating ``self`` at all vertices in ``sequence``.
INPUT:
- ``sequence`` -- an iterable of vertices of self. - ``show_sequence`` -- (default: False) if True, a png containing the associated quivers is shown. - ``fig_size`` -- (default: 1.2) factor by which the size of the plot is multiplied. - ``return_output`` -- (default: 'seed') determines what output is to be returned::
* if 'seed', outputs all the cluster seeds obtained by the ``sequence`` of mutations. * if 'matrix', outputs a list of exchange matrices. * if 'var', outputs a list of new cluster variables obtained at each step.
EXAMPLES::
sage: S = ClusterSeed(['A',2]) sage: for T in S.mutation_sequence([0,1,0]): ....: print(T.b_matrix()) [ 0 -1] [ 1 0] [ 0 1] [-1 0] [ 0 -1] [ 1 0]
sage: S = ClusterSeed(['A',2]) sage: S.mutation_sequence([0,1,0,1], return_output='var') [(x1 + 1)/x0, (x0 + x1 + 1)/(x0*x1), (x0 + 1)/x1, x0] """
self.quiver().mutation_sequence2(sequence=sequence, show_sequence=True, fig_size=fig_size )
return [ seed._M for seed in seed_sequence ] else: raise ValueError('The parameter `return_output` can only be `seed`, `matrix`, or `var`.')
r""" Runs an analysis of all potential mutation options. Note that this might take a long time on large seeds.
Notes: Edges are only returned if we have a non-valued quiver. Green and red vertices are only returned if the cluster is principal.
INPUT:
- ``options`` -- (default: ['all']) a list of mutation options. - ``filter`` -- (default: None) A vertex or interval of vertices to limit our search to
Possible options are:
- ``"all"`` - All options below - ``"edges"`` - Number of edges (works with skew-symmetric quivers) - ``"edge_diff"`` - Edges added/deleted (works with skew-symmetric quivers) - ``"green_vertices"`` - List of green vertices (works with principals) - ``"green_vertices_diff"`` - Green vertices added/removed (works with principals) - ``"red_vertices"`` - List of red vertices (works with principals) - ``"red_vertices_diff"`` - Red vertices added/removed (works with principals) - ``"urban_renewals"`` - List of urban renewal vertices - ``"urban_renewals_diff"`` - Urban renewal vertices added/removed - ``"sources"`` - List of source vertices - ``"sources_diff"`` - Source vertices added/removed - ``"sinks"`` - List of sink vertices - ``"sinks_diff"`` - Sink vertices added/removed - ``"denominators"`` - List of all denominators of the cluster variables
OUTPUT:
Outputs a dictionary indexed by the vertex numbers. Each vertex will itself also be a dictionary with each desired option included as a key in the dictionary. As an example you would get something similar to: {0: {'edges': 1}, 1: {'edges': 2}}. This represents that if you were to do a mutation at the current seed then mutating at vertex 0 would result in a quiver with 1 edge and mutating at vertex 0 would result in a quiver with 2 edges.
EXAMPLES::
sage: B = [[0, 4, 0, -1],[-4,0, 3, 0],[0, -3, 0, 1],[1, 0, -1, 0]] sage: S = ClusterSeed(matrix(B)); S.mutate([2,3,1,2,1,3,0,2]) sage: S.mutation_analysis() {0: {'d_matrix': [ 0 0 1 0] [ 0 -1 0 0] [ 0 0 0 -1] [-1 0 0 0], 'denominators': [1, 1, x0, 1], 'edge_diff': 6, 'edges': 13, 'green_vertices': [0, 1, 3], 'green_vertices_diff': {'added': [0], 'removed': []}, 'red_vertices': [2], 'red_vertices_diff': {'added': [], 'removed': [0]}, 'sinks': [], 'sinks_diff': {'added': [], 'removed': [2]}, 'sources': [], 'sources_diff': {'added': [], 'removed': []}, 'urban_renewals': [], 'urban_renewals_diff': {'added': [], 'removed': []}}, 1: {'d_matrix': [ 1 4 1 0] [ 0 1 0 0] [ 0 0 0 -1] [ 1 4 0 0], 'denominators': [x0*x3, x0^4*x1*x3^4, x0, 1], 'edge_diff': 2, 'edges': 9, 'green_vertices': [0, 3], 'green_vertices_diff': {'added': [0], 'removed': [1]}, 'red_vertices': [1, 2], 'red_vertices_diff': {'added': [1], 'removed': [0]}, 'sinks': [2], 'sinks_diff': {'added': [], 'removed': []}, 'sources': [], 'sources_diff': {'added': [], 'removed': []}, 'urban_renewals': [], 'urban_renewals_diff': {'added': [], 'removed': []}}, 2: {'d_matrix': [ 1 0 0 0] [ 0 -1 0 0] [ 0 0 0 -1] [ 1 0 1 0], 'denominators': [x0*x3, 1, x3, 1], 'edge_diff': 0, 'edges': 7, 'green_vertices': [1, 2, 3], 'green_vertices_diff': {'added': [2], 'removed': []}, 'red_vertices': [0], 'red_vertices_diff': {'added': [], 'removed': [2]}, 'sinks': [], 'sinks_diff': {'added': [], 'removed': [2]}, 'sources': [2], 'sources_diff': {'added': [2], 'removed': []}, 'urban_renewals': [], 'urban_renewals_diff': {'added': [], 'removed': []}}, 3: {'d_matrix': [ 1 0 1 1] [ 0 -1 0 0] [ 0 0 0 1] [ 1 0 0 1], 'denominators': [x0*x3, 1, x0, x0*x2*x3], 'edge_diff': -1, 'edges': 6, 'green_vertices': [1], 'green_vertices_diff': {'added': [], 'removed': [3]}, 'red_vertices': [0, 2, 3], 'red_vertices_diff': {'added': [3], 'removed': []}, 'sinks': [2], 'sinks_diff': {'added': [], 'removed': []}, 'sources': [1], 'sources_diff': {'added': [1], 'removed': []}, 'urban_renewals': [], 'urban_renewals_diff': {'added': [], 'removed': []}}}
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.mutation_analysis() {0: {'d_matrix': [ 1 0 0] [ 0 -1 0] [ 0 0 -1], 'denominators': [x0, 1, 1], 'green_vertices': [1, 2], 'green_vertices_diff': {'added': [], 'removed': [0]}, 'red_vertices': [0], 'red_vertices_diff': {'added': [0], 'removed': []}, 'sinks': [], 'sinks_diff': {'added': [], 'removed': [1]}, 'sources': [4, 5], 'sources_diff': {'added': [], 'removed': [3]}, 'urban_renewals': [], 'urban_renewals_diff': {'added': [], 'removed': []}}, 1: {'d_matrix': [-1 0 0] [ 0 1 0] [ 0 0 -1], 'denominators': [1, x1, 1], 'green_vertices': [0, 2], 'green_vertices_diff': {'added': [], 'removed': [1]}, 'red_vertices': [1], 'red_vertices_diff': {'added': [1], 'removed': []}, 'sinks': [0, 2, 4], 'sinks_diff': {'added': [0, 2, 4], 'removed': [1]}, 'sources': [1, 3, 5], 'sources_diff': {'added': [1], 'removed': [4]}, 'urban_renewals': [], 'urban_renewals_diff': {'added': [], 'removed': []}}, 2: {'d_matrix': [-1 0 0] [ 0 -1 0] [ 0 0 1], 'denominators': [1, 1, x2], 'green_vertices': [0, 1], 'green_vertices_diff': {'added': [], 'removed': [2]}, 'red_vertices': [2], 'red_vertices_diff': {'added': [2], 'removed': []}, 'sinks': [], 'sinks_diff': {'added': [], 'removed': [1]}, 'sources': [3, 4], 'sources_diff': {'added': [], 'removed': [5]}, 'urban_renewals': [], 'urban_renewals_diff': {'added': [], 'removed': []}}}
"""
filter = [filter]
# setup our initial information for differences later on
#instantiate our dictionary #instantiate our dictionary
#run mutations not in place as we just want an analysis
r""" Return the restriction to the principal part (i.e. the exchangeable variables) of ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A',4]) sage: T = ClusterSeed( S.quiver().digraph().edges(), frozen=[3] ) sage: T.quiver().digraph().edges() [(0, 1, (1, -1)), (2, 1, (1, -1)), (2, 3, (1, -1))]
sage: T.exchangeable_part().quiver().digraph().edges() [(0, 1, (1, -1)), (2, 1, (1, -1))]
""" user_labels=self._nlist, user_labels_prefix=self._user_labels_prefix, frozen=None) for k in range(self._n)]
r""" Return the universal extension of ``self``.
This is the initial seed of the associated cluster algebra with universal coefficients, as defined in section 12 of [FZ2007]_.
This method works only if ``self`` is a bipartite, finite-type seed.
Due to some limitations in the current implementation of ``CartanType``, we need to construct the set of almost positive coroots by hand. As a consequence their ordering is not the standard one (the rows of the bottom part of the exchange matrix might be a shuffling of those you would expect).
EXAMPLES::
sage: S = ClusterSeed(['A',2]) sage: T = S.universal_extension() sage: T.b_matrix() [ 0 1] [-1 0] [-1 0] [ 1 0] [ 1 -1] [ 0 1] [ 0 -1]
sage: S = ClusterSeed(['A',3]) sage: T = S.universal_extension() sage: T.b_matrix() [ 0 1 0] [-1 0 -1] [ 0 1 0] [-1 0 0] [ 1 0 0] [ 1 -1 0] [ 1 -1 1] [ 0 1 0] [ 0 -1 0] [ 0 -1 1] [ 0 0 -1] [ 0 0 1]
sage: S = ClusterSeed(['B',2]) sage: T = S.universal_extension() sage: T.b_matrix() [ 0 1] [-2 0] [-1 0] [ 1 0] [ 1 -1] [ 2 -1] [ 0 1] [ 0 -1]
sage: S = ClusterSeed(['A', 5], user_labels = [-2, -1, 0, 1 ,2]) sage: U = S.universal_extension() sage: U.b_matrix() == ClusterSeed(['A', 5]).universal_extension().b_matrix() True """ raise ValueError("To have universal coefficients we need " "to start from a coefficient-free seed") raise ValueError("Universal coefficients are defined only " "for finite type cluster algebras at a " "bipartite initial cluster")
# We give the indexing set of the Cartan matrix to be [1, 2, ..., n]
for i in range(self._n)] for alpha in almost_positive_coroots])
elif isinstance(self._user_labels,dict): new_labels = copy(self._user_labels) new_labels.update( {(i+self._n):'y%s'%i for i in range(n)} ) user_labels_prefix=self._user_labels_prefix, frozen=None)
r""" Return the principal extension of ``self``, yielding a `2n \times n` matrix.
Raises an error if the input seed has a non-square exchange matrix. In this case, the method instead adds `n` frozen variables to any previously frozen variables. I.e., the seed obtained by adding a frozen variable to every exchangeable variable of ``self``.
EXAMPLES::
sage: S = ClusterSeed([[0,1],[1,2],[2,3],[2,4]]); S A seed for a cluster algebra of rank 5
sage: T = S.principal_extension(); T A seed for a cluster algebra of rank 5 with principal coefficients
sage: T.b_matrix() [ 0 1 0 0 0] [-1 0 1 0 0] [ 0 -1 0 1 1] [ 0 0 -1 0 0] [ 0 0 -1 0 0] [ 1 0 0 0 0] [ 0 1 0 0 0] [ 0 0 1 0 0] [ 0 0 0 1 0] [ 0 0 0 0 1]
sage: S = ClusterSeed(['A', 4], user_labels=['a', 'b', 'c', 'd']) sage: T = S.principal_extension() sage: T.cluster() [a, b, c, d] sage: T.coefficients() [y0, y1, y2, y3] sage: S2 = ClusterSeed(['A', 4], user_labels={0:'a', 1:'b', 2:'c', 3:'d'}) sage: S2 == S True sage: T2 = S2.principal_extension() sage: T2 == T True """ raise ValueError("the b-matrix is not square") user_labels_prefix=self._user_labels_prefix, frozen=None)
#### This should fix principal_extension resetting boolean flags. Might need to update user labels to include new principals with y's. -G
r""" Reorients ``self`` with respect to the given total order, or with respect to an iterator of ordered pairs.
WARNING:
- This operation might change the mutation type of ``self``. - Ignores ordered pairs `(i,j)` for which neither `(i,j)` nor `(j,i)` is an edge of ``self``.
INPUT:
- ``data`` -- an iterator defining a total order on ``self.vertices()``, or an iterator of ordered pairs in ``self`` defining the new orientation of these edges.
EXAMPLES::
sage: S = ClusterSeed(['A',[2,3],1]) sage: S.mutation_type() ['A', [2, 3], 1]
sage: S.reorient([(0,1),(2,3)]) sage: S.mutation_type() ['D', 5]
sage: S.reorient([(1,0),(2,3)]) sage: S.mutation_type() ['A', [1, 4], 1]
sage: S.reorient([0,1,2,3,4]) sage: S.mutation_type() ['A', [1, 4], 1] """ self.quiver()
r""" Sets the cluster for ``self`` to ``cluster``.
Warning: Initialization may lead to inconsistent data.
INPUT:
- ``cluster`` -- an iterable defining a cluster for ``self``.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: cluster = S.cluster() sage: S.mutate([1,2,1]) sage: S.cluster() [x0, (x1 + 1)/x2, (x0*x2 + x1 + 1)/(x1*x2)] sage: cluster2 = S.cluster()
sage: S.set_cluster(cluster) Warning: using set_cluster at this point could lead to inconsistent seed data.
sage: S.set_cluster(cluster, force=True) sage: S.cluster() [x0, x1, x2] sage: S.set_cluster(cluster2, force=True) sage: S.cluster() [x0, (x1 + 1)/x2, (x0*x2 + x1 + 1)/(x1*x2)]
sage: S = ClusterSeed(['A',3]); S.use_fpolys(False) sage: S.set_cluster([1,1,1]) Warning: clusters not being tracked so this command is ignored. """
raise ValueError('The number of given cluster variables is wrong') raise ValueError('The cluster variables are not all contained in %s'%FractionField(self._R)) else: for x in cluster][0:self._n] else:
r""" Resets the cluster of ``self`` to the initial cluster.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S.mutate([1,2,1]) sage: S.cluster() [x0, (x1 + 1)/x2, (x0*x2 + x1 + 1)/(x1*x2)]
sage: S.reset_cluster() sage: S.cluster() [x0, x1, x2]
sage: T = S.principal_extension() sage: T.cluster() [x0, x1, x2] sage: T.mutate([1,2,1]) sage: T.cluster() [x0, (x1*y2 + x0)/x2, (x1*y1*y2 + x0*y1 + x2)/(x1*x2)]
sage: T.reset_cluster() sage: T.cluster() [x0, x1, x2]
sage: S = ClusterSeed(['B',3],user_labels=[[1,2],[2,3],[3,4]],user_labels_prefix='p') sage: S.mutate([0,1]) sage: S.cluster() [(p_2_3 + 1)/p_1_2, (p_1_2*p_3_4^2 + p_2_3 + 1)/(p_1_2*p_2_3), p_3_4]
sage: S.reset_cluster() sage: S.cluster() [p_1_2, p_2_3, p_3_4] sage: S.g_matrix() [1 0 0] [0 1 0] [0 0 1] sage: S.f_polynomials() [1, 1, 1] """
r""" Resets the coefficients of ``self`` to the frozen variables but keeps the current cluster. Raises an error if the number of frozen variables is different than the number of exchangeable variables.
WARNING: This command to be phased out since 'use_c_vectors() does this more effectively.
EXAMPLES::
sage: S = ClusterSeed(['A',3]).principal_extension() sage: S.b_matrix() [ 0 1 0] [-1 0 -1] [ 0 1 0] [ 1 0 0] [ 0 1 0] [ 0 0 1] sage: S.mutate([1,2,1]) sage: S.b_matrix() [ 0 1 -1] [-1 0 1] [ 1 -1 0] [ 1 0 0] [ 0 1 -1] [ 0 0 -1] sage: S.reset_coefficients() sage: S.b_matrix() [ 0 1 -1] [-1 0 1] [ 1 -1 0] [ 1 0 0] [ 0 1 0] [ 0 0 1] """ raise ValueError("The numbers of cluster variables " "and of frozen variables do not coincide.") else:
return_paths=False, up_to_equivalence=True, only_sink_source=False): r""" Return an iterator for the mutation class of ``self`` with respect to certain constrains.
INPUT:
- ``depth`` -- (default: infinity) integer or infinity, only seeds with distance at most ``depth`` from ``self`` are returned. - ``show_depth`` -- (default: False) if True, the current depth of the mutation is shown while computing. - ``return_paths`` -- (default: False) if True, a shortest path of mutations from ``self`` to the given quiver is returned as well. - ``up_to_equivalence`` -- (default: True) if True, only one seed up to simultaneous permutation of rows and columns of the exchange matrix is recorded. - ``sink_source`` -- (default: False) if True, only mutations at sinks and sources are applied.
EXAMPLES:
A standard finite type example::
sage: S = ClusterSeed(['A',3]) sage: it = S.mutation_class_iter() sage: for T in it: print(T) A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3]
A finite type example with given depth::
sage: it = S.mutation_class_iter(depth=1) sage: for T in it: print(T) A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3] A seed for a cluster algebra of rank 3 of type ['A', 3]
A finite type example where the depth is shown while computing::
sage: it = S.mutation_class_iter(show_depth=True) sage: for T in it: pass Depth: 0 found: 1 Time: ... s Depth: 1 found: 4 Time: ... s Depth: 2 found: 9 Time: ... s Depth: 3 found: 13 Time: ... s Depth: 4 found: 14 Time: ... s
A finite type example with shortest paths returned::
sage: it = S.mutation_class_iter(return_paths=True) sage: for T in it: print(T) (A seed for a cluster algebra of rank 3 of type ['A', 3], []) (A seed for a cluster algebra of rank 3 of type ['A', 3], [2]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [1]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [0]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [2, 1]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [0, 2]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [0, 1]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [1, 2]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [1, 0]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [0, 2, 1]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [0, 1, 2]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [2, 1, 0]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [1, 0, 2]) (A seed for a cluster algebra of rank 3 of type ['A', 3], [0, 1, 2, 0])
Finite type examples not considered up to equivalence::
sage: it = S.mutation_class_iter(up_to_equivalence=False) sage: len( [ T for T in it ] ) 84
sage: it = ClusterSeed(['A',2]).mutation_class_iter(return_paths=True,up_to_equivalence=False) sage: for T in it: print(T) (A seed for a cluster algebra of rank 2 of type ['A', 2], []) (A seed for a cluster algebra of rank 2 of type ['A', 2], [1]) (A seed for a cluster algebra of rank 2 of type ['A', 2], [0]) (A seed for a cluster algebra of rank 2 of type ['A', 2], [0, 1]) (A seed for a cluster algebra of rank 2 of type ['A', 2], [1, 0]) (A seed for a cluster algebra of rank 2 of type ['A', 2], [1, 0, 1]) (A seed for a cluster algebra of rank 2 of type ['A', 2], [0, 1, 0]) (A seed for a cluster algebra of rank 2 of type ['A', 2], [1, 0, 1, 0]) (A seed for a cluster algebra of rank 2 of type ['A', 2], [0, 1, 0, 1]) (A seed for a cluster algebra of rank 2 of type ['A', 2], [1, 0, 1, 0, 1])
Check that :trac:`14638` is fixed::
sage: S = ClusterSeed(['E',6]) sage: MC = S.mutation_class(depth=7); len(MC) 534
Infinite type examples::
sage: S = ClusterSeed(['A',[1,1],1]) sage: it = S.mutation_class_iter() sage: next(it) A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1] sage: next(it) A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1] sage: next(it) A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1] sage: next(it) A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1]
sage: it = S.mutation_class_iter(depth=3, return_paths=True) sage: for T in it: print(T) (A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1], []) (A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1], [1]) (A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1], [0]) (A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1], [1, 0]) (A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1], [0, 1]) (A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1], [1, 0, 1]) (A seed for a cluster algebra of rank 2 of type ['A', [1, 1], 1], [0, 1, 0]) """
# Variable to track the depth
# set up our initial cluster and grab variables else:
# If we are tracking return paths else:
# instantiate the variables
# we get bigger the first time
# If we are showing depth, show some statistics
# Each time we get bigger and we haven't hit the full depth
# set the keys
# Our keys are cluster variables, so for each cluster: # sd is the cluster data
# another way to do a for loop for each item
# If we aren't only sinking the source # do an inplace mutation on our cluster (sd[0])
# set up our new cluster variables else: else: orbits = list(range(n)) else:
else:
up_to_equivalence=True, only_sink_source=False): r""" Return the mutation class of ``self`` with respect to certain constraints.
.. NOTE::
Vertex labels are not tracked in this method.
.. SEEALSO::
:meth:`mutation_class_iter`
INPUT:
- ``depth`` -- (default: ``infinity`) integer, only seeds with distance at most depth from ``self`` are returned - ``show_depth`` -- (default: ``False``) if ``True``, the actual depth of the mutation is shown - ``return_paths`` -- (default: ``False``) if ``True``, a shortest path of mutation sequences from self to the given quiver is returned as well - ``up_to_equivalence`` -- (default: ``True``) if ``True``, only seeds up to equivalence are considered - ``sink_source`` -- (default: ``False``) if ``True``, only mutations at sinks and sources are applied
EXAMPLES:
- for examples see :meth:`mutation_class_iter`
TESTS::
sage: A = ClusterSeed(['A',3]).mutation_class() """ raise ValueError('The mutation class can - for infinite types - only be computed up to a given depth')
r""" Returns an iterator through all clusters in the mutation class of ``self``.
INPUT:
- ``depth`` -- (default: infinity) integer or infinity, only seeds with distance at most depth from self are returned - ``show_depth`` -- (default False) - if True, ignored if depth is set; returns the depth of the mutation class, i.e., the maximal distance from self of an element in the mutation class - ``up_to_equivalence`` -- (default: True) if True, only clusters up to equivalence are considered.
EXAMPLES:
A standard finite type example::
sage: S = ClusterSeed(['A',3]) sage: it = S.cluster_class_iter() sage: for T in it: print(T) [x0, x1, x2] [x0, x1, (x1 + 1)/x2] [x0, (x0*x2 + 1)/x1, x2] [(x1 + 1)/x0, x1, x2] [x0, (x0*x2 + x1 + 1)/(x1*x2), (x1 + 1)/x2] [(x1 + 1)/x0, x1, (x1 + 1)/x2] [(x1 + 1)/x0, (x0*x2 + x1 + 1)/(x0*x1), x2] [x0, (x0*x2 + 1)/x1, (x0*x2 + x1 + 1)/(x1*x2)] [(x0*x2 + x1 + 1)/(x0*x1), (x0*x2 + 1)/x1, x2] [(x1 + 1)/x0, (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2), (x1 + 1)/x2] [(x1 + 1)/x0, (x0*x2 + x1 + 1)/(x0*x1), (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2)] [(x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2), (x0*x2 + x1 + 1)/(x1*x2), (x1 + 1)/x2] [(x0*x2 + x1 + 1)/(x0*x1), (x0*x2 + 1)/x1, (x0*x2 + x1 + 1)/(x1*x2)] [(x0*x2 + x1 + 1)/(x1*x2), (x0*x2 + x1 + 1)/(x0*x1), (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2)]
A finite type example with given depth::
sage: it = S.cluster_class_iter(depth=1) sage: for T in it: print(T) [x0, x1, x2] [x0, x1, (x1 + 1)/x2] [x0, (x0*x2 + 1)/x1, x2] [(x1 + 1)/x0, x1, x2]
A finite type example where the depth is returned while computing::
sage: it = S.cluster_class_iter(show_depth=True) sage: for T in it: print(T) [x0, x1, x2] Depth: 0 found: 1 Time: ... s [x0, x1, (x1 + 1)/x2] [x0, (x0*x2 + 1)/x1, x2] [(x1 + 1)/x0, x1, x2] Depth: 1 found: 4 Time: ... s [x0, (x0*x2 + x1 + 1)/(x1*x2), (x1 + 1)/x2] [(x1 + 1)/x0, x1, (x1 + 1)/x2] [(x1 + 1)/x0, (x0*x2 + x1 + 1)/(x0*x1), x2] [x0, (x0*x2 + 1)/x1, (x0*x2 + x1 + 1)/(x1*x2)] [(x0*x2 + x1 + 1)/(x0*x1), (x0*x2 + 1)/x1, x2] Depth: 2 found: 9 Time: ... s [(x1 + 1)/x0, (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2), (x1 + 1)/x2] [(x1 + 1)/x0, (x0*x2 + x1 + 1)/(x0*x1), (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2)] [(x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2), (x0*x2 + x1 + 1)/(x1*x2), (x1 + 1)/x2] [(x0*x2 + x1 + 1)/(x0*x1), (x0*x2 + 1)/x1, (x0*x2 + x1 + 1)/(x1*x2)] Depth: 3 found: 13 Time: ... s [(x0*x2 + x1 + 1)/(x1*x2), (x0*x2 + x1 + 1)/(x0*x1), (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2)] Depth: 4 found: 14 Time: ... s
Finite type examples not considered up to equivalence::
sage: it = S.cluster_class_iter(up_to_equivalence=False) sage: len( [ T for T in it ] ) 84
sage: it = ClusterSeed(['A',2]).cluster_class_iter(up_to_equivalence=False) sage: for T in it: print(T) [x0, x1] [x0, (x0 + 1)/x1] [(x1 + 1)/x0, x1] [(x1 + 1)/x0, (x0 + x1 + 1)/(x0*x1)] [(x0 + x1 + 1)/(x0*x1), (x0 + 1)/x1] [(x0 + x1 + 1)/(x0*x1), (x1 + 1)/x0] [(x0 + 1)/x1, (x0 + x1 + 1)/(x0*x1)] [x1, (x1 + 1)/x0] [(x0 + 1)/x1, x0] [x1, x0]
Infinite type examples::
sage: S = ClusterSeed(['A',[1,1],1]) sage: it = S.cluster_class_iter() sage: next(it) [x0, x1] sage: next(it) [x0, (x0^2 + 1)/x1] sage: next(it) [(x1^2 + 1)/x0, x1] sage: next(it) [(x0^4 + 2*x0^2 + x1^2 + 1)/(x0*x1^2), (x0^2 + 1)/x1] sage: next(it) [(x1^2 + 1)/x0, (x1^4 + x0^2 + 2*x1^2 + 1)/(x0^2*x1)]
sage: it = S.cluster_class_iter(depth=3) sage: for T in it: print(T) [x0, x1] [x0, (x0^2 + 1)/x1] [(x1^2 + 1)/x0, x1] [(x0^4 + 2*x0^2 + x1^2 + 1)/(x0*x1^2), (x0^2 + 1)/x1] [(x1^2 + 1)/x0, (x1^4 + x0^2 + 2*x1^2 + 1)/(x0^2*x1)] [(x0^4 + 2*x0^2 + x1^2 + 1)/(x0*x1^2), (x0^6 + 3*x0^4 + 2*x0^2*x1^2 + x1^4 + 3*x0^2 + 2*x1^2 + 1)/(x0^2*x1^3)] [(x1^6 + x0^4 + 2*x0^2*x1^2 + 3*x1^4 + 2*x0^2 + 3*x1^2 + 1)/(x0^3*x1^2), (x1^4 + x0^2 + 2*x1^2 + 1)/(x0^2*x1)]
For a cluster seed from an arbitrarily labelled digraph::
sage: S = ClusterSeed(DiGraph([['a', 'b'], ['b', 'c']]), frozen=['b']) sage: S.cluster_class() [[a, c], [a, (b + 1)/c], [(b + 1)/a, c], [(b + 1)/a, (b + 1)/c]]
sage: S2 = ClusterSeed(DiGraph([['a', 'b'], ['b', 'c']]), frozen=[]) sage: S2.cluster_class() [[a, b, c], [a, b, (b + 1)/c], [a, (a + c)/b, c], [(b + 1)/a, b, c], [a, (a + c)/b, (a*b + a + c)/(b*c)], [(b*c + a + c)/(a*b), (a + c)/b, c], [a, (a*b + a + c)/(b*c), (b + 1)/c], [(b + 1)/a, b, (b + 1)/c], [(b + 1)/a, (b*c + a + c)/(a*b), c], [(a*b + b*c + a + c)/(a*b*c), (a*b + a + c)/(b*c), (b + 1)/c], [(b + 1)/a, (a*b + b*c + a + c)/(a*b*c), (b + 1)/c], [(b + 1)/a, (b*c + a + c)/(a*b), (a*b + b*c + a + c)/(a*b*c)], [(b*c + a + c)/(a*b), (a + c)/b, (a*b + b*c + a + c)/(a*b*c)], [(a*b + b*c + a + c)/(a*b*c), (a + c)/b, (a*b + a + c)/(b*c)]] """
r""" Return the cluster class of ``self`` with respect to certain constraints.
INPUT:
- ``depth`` -- (default: infinity) integer, only seeds with distance at most depth from self are returned - ``return_depth`` -- (default False) - if True, ignored if depth is set; returns the depth of the mutation class, i.e., the maximal distance from self of an element in the mutation class - ``up_to_equivalence`` -- (default: True) if True, only clusters up to equivalence are considered.
EXAMPLES:
- for examples see :meth:`cluster_class_iter`
TESTS::
sage: A = ClusterSeed(['A',3]).cluster_class() """ raise ValueError('The variable class can - for infinite types - only be computed up to a given depth')
r""" Returns an iterator through all `B`-matrices in the mutation class of ``self``.
INPUT:
- ``depth`` -- (default:infinity) integer or infinity, only seeds with distance at most depth from self are returned - ``up_to_equivalence`` -- (default: True) if True, only 'B'-matrices up to equivalence are considered.
EXAMPLES:
A standard finite type example::
sage: S = ClusterSeed(['A',4]) sage: it = S.b_matrix_class_iter() sage: for T in it: print(T) [ 0 0 0 1] [ 0 0 1 1] [ 0 -1 0 0] [-1 -1 0 0] [ 0 0 0 1] [ 0 0 1 0] [ 0 -1 0 1] [-1 0 -1 0] [ 0 0 1 1] [ 0 0 0 -1] [-1 0 0 0] [-1 1 0 0] [ 0 0 0 1] [ 0 0 -1 1] [ 0 1 0 -1] [-1 -1 1 0] [ 0 0 0 1] [ 0 0 -1 0] [ 0 1 0 -1] [-1 0 1 0] [ 0 0 0 -1] [ 0 0 -1 1] [ 0 1 0 -1] [ 1 -1 1 0]
A finite type example with given depth::
sage: it = S.b_matrix_class_iter(depth=1) sage: for T in it: print(T) [ 0 0 0 1] [ 0 0 1 1] [ 0 -1 0 0] [-1 -1 0 0] [ 0 0 0 1] [ 0 0 1 0] [ 0 -1 0 1] [-1 0 -1 0] [ 0 0 1 1] [ 0 0 0 -1] [-1 0 0 0] [-1 1 0 0]
Finite type example not considered up to equivalence::
sage: S = ClusterSeed(['A',3]) sage: it = S.b_matrix_class_iter(up_to_equivalence=False) sage: for T in it: print(T) [ 0 1 0] [-1 0 -1] [ 0 1 0] [ 0 1 0] [-1 0 1] [ 0 -1 0] [ 0 -1 0] [ 1 0 1] [ 0 -1 0] [ 0 -1 0] [ 1 0 -1] [ 0 1 0] [ 0 -1 1] [ 1 0 -1] [-1 1 0] [ 0 1 -1] [-1 0 1] [ 1 -1 0] [ 0 0 1] [ 0 0 -1] [-1 1 0] [ 0 -1 1] [ 1 0 0] [-1 0 0] [ 0 0 -1] [ 0 0 1] [ 1 -1 0] [ 0 1 -1] [-1 0 0] [ 1 0 0] [ 0 1 1] [-1 0 0] [-1 0 0] [ 0 -1 -1] [ 1 0 0] [ 1 0 0] [ 0 0 -1] [ 0 0 -1] [ 1 1 0] [ 0 0 1] [ 0 0 1] [-1 -1 0]
Infinite (but finite mutation) type example::
sage: S = ClusterSeed(['A',[1,2],1]) sage: it = S.b_matrix_class_iter() sage: for T in it: print(T) [ 0 1 1] [-1 0 1] [-1 -1 0] [ 0 -2 1] [ 2 0 -1] [-1 1 0]
Infinite mutation type example::
sage: S = ClusterSeed(['E',10]) sage: it = S.b_matrix_class_iter(depth=3) sage: len ( [T for T in it] ) 266
For a cluster seed from an arbitrarily labelled digraph::
sage: S = ClusterSeed(DiGraph([['a', 'b'], ['b', 'c']]), frozen=['b']) sage: S.b_matrix_class() [ [ 0 0] [ 0 0] [0 0] [ 0 0] [ 0 0] [0 0] [-1 1], [-1 -1], [1 1] ] """
r""" Returns all `B`-matrices in the mutation class of ``self``.
INPUT:
- ``depth`` -- (default:infinity) integer or infinity, only seeds with distance at most depth from self are returned - ``up_to_equivalence`` -- (default: True) if True, only 'B'-matrices up to equivalence are considered.
EXAMPLES:
- for examples see :meth:`b_matrix_class_iter`
TESTS::
sage: A = ClusterSeed(['A',3]).b_matrix_class() sage: A = ClusterSeed(['A',[2,1],1]).b_matrix_class() """ raise ValueError('The B-matrix class can - for infinite mutation types - only be computed up to a given depth')
r""" Returns an iterator for all cluster variables in the mutation class of ``self``.
INPUT:
- ``depth`` -- (default:infinity) integer, only seeds with distance at most depth from self are returned - ``ignore_bipartite_belt`` -- (default:False) if True, the algorithms does not use the bipartite belt
EXAMPLES:
A standard finite type example::
sage: S = ClusterSeed(['A',3]) sage: it = S.variable_class_iter() sage: for T in it: print(T) x0 x1 x2 (x1 + 1)/x0 (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2) (x1 + 1)/x2 (x0*x2 + x1 + 1)/(x0*x1) (x0*x2 + 1)/x1 (x0*x2 + x1 + 1)/(x1*x2)
Finite type examples with given depth::
sage: it = S.variable_class_iter(depth=1) sage: for T in it: print(T) Found a bipartite seed - restarting the depth counter at zero and constructing the variable class using its bipartite belt. x0 x1 x2 (x1 + 1)/x0 (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2) (x1 + 1)/x2 (x0*x2 + x1 + 1)/(x0*x1) (x0*x2 + 1)/x1 (x0*x2 + x1 + 1)/(x1*x2)
Note that the notion of *depth* depends on whether a bipartite seed is found or not, or if it is manually ignored::
sage: it = S.variable_class_iter(depth=1,ignore_bipartite_belt=True) sage: for T in it: print(T) x0 x1 x2 (x1 + 1)/x2 (x0*x2 + 1)/x1 (x1 + 1)/x0
sage: S.mutate([0,1]) sage: it2 = S.variable_class_iter(depth=1) sage: for T in it2: print(T) (x1 + 1)/x0 (x0*x2 + x1 + 1)/(x0*x1) x2 (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2) x1 (x0*x2 + 1)/x1
Infinite type examples::
sage: S = ClusterSeed(['A',[1,1],1]) sage: it = S.variable_class_iter(depth=2) sage: for T in it: print(T) Found a bipartite seed - restarting the depth counter at zero and constructing the variable class using its bipartite belt. x0 x1 (x1^2 + 1)/x0 (x1^4 + x0^2 + 2*x1^2 + 1)/(x0^2*x1) (x0^4 + 2*x0^2 + x1^2 + 1)/(x0*x1^2) (x0^2 + 1)/x1 (x1^6 + x0^4 + 2*x0^2*x1^2 + 3*x1^4 + 2*x0^2 + 3*x1^2 + 1)/(x0^3*x1^2) (x1^8 + x0^6 + 2*x0^4*x1^2 + 3*x0^2*x1^4 + 4*x1^6 + 3*x0^4 + 6*x0^2*x1^2 + 6*x1^4 + 3*x0^2 + 4*x1^2 + 1)/(x0^4*x1^3) (x0^8 + 4*x0^6 + 3*x0^4*x1^2 + 2*x0^2*x1^4 + x1^6 + 6*x0^4 + 6*x0^2*x1^2 + 3*x1^4 + 4*x0^2 + 3*x1^2 + 1)/(x0^3*x1^4) (x0^6 + 3*x0^4 + 2*x0^2*x1^2 + x1^4 + 3*x0^2 + 2*x1^2 + 1)/(x0^2*x1^3) """
end = True else:
r""" Returns all cluster variables in the mutation class of ``self``.
INPUT:
- ``depth`` -- (default:infinity) integer, only seeds with distance at most depth from self are returned - ``ignore_bipartite_belt`` -- (default:False) if True, the algorithms does not use the bipartite belt
EXAMPLES:
- for examples see :meth:`variable_class_iter`
TESTS::
sage: A = ClusterSeed(['A',3]).variable_class() """ raise ValueError('The variable class can - for infinite types - only be computed up to a given depth')
r""" Returns True if ``self`` is of finite type.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: S.is_finite() True
sage: S = ClusterSeed(['A',[2,2],1]) sage: S.is_finite() False """ return False else:
r""" Returns True if ``self`` is of finite mutation type.
INPUT:
- ``nr_of_checks`` -- (default: None) number of mutations applied. Standard is 500*(number of vertices of self). - ``return_path`` -- (default: False) if True, in case of self not being mutation finite, a path from self to a quiver with an edge label (a,-b) and a*b > 4 is returned.
ALGORITHM:
- A cluster seed is mutation infinite if and only if every `b_{ij}*b_{ji} > -4`. Thus, we apply random mutations in random directions
WARNING:
- Uses a non-deterministic method by random mutations in various directions. - In theory, it can return a wrong True.
EXAMPLES::
sage: S = ClusterSeed(['A',10]) sage: S._mutation_type = None sage: S.is_mutation_finite() True
sage: S = ClusterSeed([(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(2,9)]) sage: S.is_mutation_finite() False """ return is_finite, path else:
r""" Returns the mutation_type of each connected component of ``self``, if it can be determined. Otherwise, the mutation type of this component is set to be unknown.
The mutation types of the components are ordered by vertex labels.
WARNING:
- All finite types can be detected, - All affine types can be detected, EXCEPT affine type D (the algorithm is not yet implemented) - All exceptional types can be detected.
- Might fail to work if it is used within different Sage processes simultaneously (that happened in the doctesting).
EXAMPLES:
- finite types::
sage: S = ClusterSeed(['A',5]) sage: S._mutation_type = S._quiver._mutation_type = None sage: S.mutation_type() ['A', 5]
sage: S = ClusterSeed([(0,1),(1,2),(2,3),(3,4)]) sage: S.mutation_type() ['A', 5]
sage: S = ClusterSeed(DiGraph([['a','b'],['c','b'],['c','d'],['e','d']]), frozen = ['c']) sage: S.mutation_type() [ ['A', 2], ['A', 2] ]
- affine types::
sage: S = ClusterSeed(['E',8,[1,1]]); S A seed for a cluster algebra of rank 10 of type ['E', 8, [1, 1]] sage: S._mutation_type = S._quiver._mutation_type = None; S A seed for a cluster algebra of rank 10 sage: S.mutation_type() # long time ['E', 8, [1, 1]]
- the not yet working affine type D::
sage: S = ClusterSeed(['D',4,1]) sage: S._mutation_type = S._quiver._mutation_type = None sage: S.mutation_type() # todo: not implemented ['D', 4, 1]
- the exceptional types::
sage: S = ClusterSeed(['X',6]) sage: S._mutation_type = S._quiver._mutation_type = None sage: S.mutation_type() # long time ['X', 6]
- infinite types::
sage: S = ClusterSeed(['GR',[4,9]]) sage: S._mutation_type = S._quiver._mutation_type = None sage: S.mutation_type() 'undetermined infinite mutation type' """ self.quiver()
r""" Returns the greedy element `x[a_1,a_2]` assuming that self is rank two.
The third input can be 'by_recursion', 'by_combinatorics', or 'just_numbers' to specify if the user wants the element computed by the recurrence, combinatorial formula, or wants to set `x_1` and `x_2` to be one.
See [LLZ2014]_ for more details.
EXAMPLES::
sage: S = ClusterSeed(['R2', [3, 3]]) sage: S.greedy(4, 4) (x0^12 + x1^12 + 4*x0^9 + 4*x1^9 + 6*x0^6 + 4*x0^3*x1^3 + 6*x1^6 + 4*x0^3 + 4*x1^3 + 1)/(x0^4*x1^4) sage: S.greedy(4, 4, 'by_combinatorics') (x0^12 + x1^12 + 4*x0^9 + 4*x1^9 + 6*x0^6 + 4*x0^3*x1^3 + 6*x1^6 + 4*x0^3 + 4*x1^3 + 1)/(x0^4*x1^4) sage: S.greedy(4, 4, 'just_numbers') 35 sage: S = ClusterSeed(['R2', [2, 2]]) sage: S.greedy(1, 2) (x0^4 + 2*x0^2 + x1^2 + 1)/(x0*x1^2) sage: S.greedy(1, 2, 'by_combinatorics') (x0^4 + 2*x0^2 + x1^2 + 1)/(x0*x1^2)
TESTS:
We check that :trac:`23688` has been resolved::
sage: S = ClusterSeed(Matrix([[0,1],[-4,0]])); S A seed for a cluster algebra of rank 2 sage: S.greedy(1,2) (x1^4 + x0^2 + 2*x0 + 1)/(x0*x1^2) sage: S.greedy(1,2,'by_combinatorics') (x1^4 + x0^2 + 2*x0 + 1)/(x0*x1^2) """ S = ClusterSeed([['A', 1], ['A', 1]]) else: else: raise ValueError("The third input should be 'by_recursion', " "'by_combinatorics', or 'just_numbers'.") else: raise ValueError("Greedy elements are only currently " "defined for cluster seeds of rank two.")
""" Return the oriented exchange graph of ``self`` as a directed graph.
The seed must be a cluster seed for a cluster algebra of finite type with principal coefficients (the corresponding quiver must have mutable vertices 0,1,...,n-1).
EXAMPLES::
sage: S = ClusterSeed(['A', 2]).principal_extension() sage: G = S.oriented_exchange_graph(); G Digraph on 5 vertices sage: G.out_degree_sequence() [2, 1, 1, 1, 0]
sage: S = ClusterSeed(['B', 2]).principal_extension() sage: G = S.oriented_exchange_graph(); G Digraph on 6 vertices sage: G.out_degree_sequence() [2, 1, 1, 1, 1, 0]
TESTS::
sage: S = ClusterSeed(['A',[2,2],1]) sage: S.oriented_exchange_graph() Traceback (most recent call last): ... TypeError: only works for finite mutation type
sage: S = ClusterSeed(['A', 2]) sage: S.oriented_exchange_graph() Traceback (most recent call last): ... TypeError: only works for principal coefficients """
# check if green
r""" Return the upper bound of the given cluster algebra as a quotient_ring.
The upper bound is the intersection of the Laurent polynomial rings of the initial cluster and its neighboring clusters. As such, it always contains both the cluster algebra and the upper cluster algebra. This function uses the algorithm from [MM2015]_.
When the initial seed is totally coprime (for example, when the unfrozen part of the exchange matrix has full rank), the upper bound is equal to the upper cluster algebra by [BFZ2005]_.
.. WARNING::
The computation time grows rapidly with the size of the seed and the number of steps. For most seeds larger than four vertices, the algorithm may take an infeasible amount of time. Additionally, it will run forever without terminating whenever the upper bound is infinitely-generated (such as the example in [Spe2013]_).
INPUT:
- ``verbose`` -- (default: ``False``) if ``True``, prints output during the computation.
EXAMPLES:
- finite type::
sage: S = ClusterSeed(['A',3]) sage: S.find_upper_bound() Quotient of Multivariate Polynomial Ring in x0, x1, x2, x0p, x1p, x2p, z0 over Rational Field by the ideal (x0*x0p - x1 - 1, x1*x1p - x0*x2 - 1, x2*x2p - x1 - 1, x0*z0 - x2p, x1*z0 + z0 - x0p*x2p, x2*z0 - x0p, x1p*z0 + z0 - x0p*x1p*x2p + x1 + 1)
- Markov::
sage: B = matrix([[0,2,-2],[-2,0,2],[2,-2,0]]) sage: S = ClusterSeed(B) sage: S.find_upper_bound() Quotient of Multivariate Polynomial Ring in x0, x1, x2, x0p, x1p, x2p, z0 over Rational Field by the ideal (x0*x0p - x2^2 - x1^2, x1*x1p - x2^2 - x0^2, x2*x2p - x1^2 - x0^2, x0p*x1p*x2p - x0*x1*x2p - x0*x2*x1p - x1*x2*x0p - 2*x0*x1*x2, x0^3*z0 - x1p*x2p + x1*x2, x0*x1*z0 - x2p - x2, x1^3*z0 - x0p*x2p + x0*x2, x0*x2*z0 - x1p - x1, x1*x2*z0 - x0p - x0, x2^3*z0 - x0p*x1p + x0*x1)
"""
for s in range(rank))
lower_var[t + rank].numerator()) for t in range(rank)]
msg = 'Computing relations among {} generators' print(msg.format(len(gens))) msg = 'Computed {} relations in {} seconds' print(msg.format(len(ISat.gens()), spend)) print('Attempting to find a new element of the upper bound') print('Verified that there are no new elements in', spend, 'seconds') print('Returning a presentation for the upper bound') else: print('Found a new element in', spend, 'seconds!') print('')
r""" Computes an element in the upper cluster algebra of `B` corresponding to the vector `a \in \mathbb{Z}^n`.
See [LeeLiM]_ for more details.
INPUT:
- `B` -- a skew-symmetric matrix. Must have the same number of columns as the length of the vectors in `vd`. - `a` -- a vector in `\mathbb{Z}^n` where `n` is the number of columns in `B`.
OUTPUT:
Returns an element in the upper cluster algebra. Depending on the input it may or may not be irreducible.
EXAMPLES::
sage: B=matrix([[0,3,-3],[-3,0,3],[3,-3,0],[1,0,0],[0,1,0],[0,0,1]]) sage: C=ClusterSeed(B) sage: C.get_upper_cluster_algebra_element([1,1,0]) (x0^3*x2^3*x3*x4 + x2^6*x3 + x1^3*x2^3)/(x0*x1) sage: C.get_upper_cluster_algebra_element([1,1,1]) x0^2*x1^2*x2^2*x3*x4*x5 + x0^2*x1^2*x2^2
sage: B=matrix([[0,3,0],[-3,0,3],[0,-3,0]]) sage: C=ClusterSeed(B) sage: C.get_upper_cluster_algebra_element([1,1,0]) (x1^3*x2^3 + x0^3 + x2^3)/(x0*x1) sage: C.get_upper_cluster_algebra_element([1,1,1]) (x0^3*x1^3 + x1^3*x2^3 + x0^3 + x2^3)/(x0*x1*x2)
sage: B=matrix([[0,2],[-3,0],[4,-5]]) sage: C=ClusterSeed(B) sage: C.get_upper_cluster_algebra_element([1,1]) (x2^9 + x1^3*x2^5 + x0^2*x2^4)/(x0*x1)
sage: B=matrix([[0,3,-5],[-3,0,4],[5,-4,0]]) sage: C=ClusterSeed(B) sage: C.get_upper_cluster_algebra_element([1,1,1]) x0^4*x1^2*x2^3 + x0^2*x1^3*x2^4
REFERENCES:
.. [LeeLiM] Lee-Li-Mills, A combinatorial formula for certain elements in the upper cluster algebra, :arxiv:`1409.8177`
""" #Checks if the length of the raise ValueError('The length of the input vector must be the same as the number of columns of B.') #Runs helper functions.
r""" Produce a list of upper cluster algebra elements corresponding to all vectors in `\{0,1\}^n`.
INPUT:
- `B` -- a skew-symmetric matrigitx. - `size_limit` -- a limit on how many vectors you want the function to return.
OUTPUT:
An array of elements in the upper cluster algebra.
EXAMPLES::
sage: B = matrix([[0,1,0],[-1,0,1],[0,-1,0],[1,0,0],[0,1,0],[0,0,1]]) sage: C = ClusterSeed(B) sage: C.LLM_gen_set() [1, (x1 + x3)/x0, (x0*x4 + x2)/x1, (x0*x3*x4 + x1*x2 + x2*x3)/(x0*x1), (x1*x5 + 1)/x2, (x1^2*x5 + x1*x3*x5 + x1 + x3)/(x0*x2), (x0*x1*x4*x5 + x0*x4 + x2)/(x1*x2), (x0*x1*x3*x4*x5 + x0*x3*x4 + x1*x2 + x2*x3)/(x0*x1*x2)] """ break
r""" Return a list of compatible vectors of each vector in the vector decomposition `vd`.
Compatibility is defined as in [LLM]_ with respect to the matrix `B`.
INPUT:
- `B` -- a skew-symmetric matrix. Must have the same number of columns as the length of the vectors in `vd`. - `vd` -- a collection of tuples `(v,z)` with `v \in \{0,1\}^n` and `z \in \mathbb{Z}`. `n` must be the number of columns in `B`. Taken from the output of vector_decomposition.
OUTPUT:
Returns an a 2-dimensional array containing all the vectors compatible with each vector in `vd.`
NOTE:
If the vector in `vd` is negative it will not have any compatible vectors, so it does not contribute to the list.
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import _vector_decomposition
sage: B=matrix([[0,1,0,0],[-1,0,1,0],[0,-1,0,1],[0,0,-1,0]]) sage: C=ClusterSeed(B) sage: v=_vector_decomposition([3,2,3,4],4) sage: C._compute_compatible_vectors(v) [[[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1]], [[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [1, 0, 0, 0], [1, 0, 0, 1], [1, 0, 1, 1]], [[0, 0, 0, 0], [0, 0, 0, 1]]]
sage: B=matrix([[0,1,1,0],[-1,0,1,1],[-1,-1,0,0],[0,-1,0,0]]) sage: C=ClusterSeed(B) sage: v=_vector_decomposition([2,-1,3,-2],4) sage: C._compute_compatible_vectors(v) [[], [], [[0, 0, 0, 0], [0, 0, 1, 0], [1, 0, 1, 0]], [[0, 0, 0, 0], [0, 0, 1, 0]]] """ # E is the set of 'edges' in the quiver. It records the tuple # of indices `(i,j)` if `b_{ij} > 0`. # Checks the upper triangular part of the exchange graph. # Checks for edges to frozen vertices. if B[k + num_cols][j] > 0: E.append([i, j]) elif B[i][j] < 0: E.append([j, i])
# For each vector a in vd. check if a vector s in {0,1}^n is compatible.
# If the vector a in vd is non-positive it is not compatible # with any vector. 0 vector will pass this check but will be # handled later. negative = True break continue #The first possible failure for compatibility is if any entry in s is larger than the corresponding entry of a. #Only checks for the mutable vertices since all entries in a_i i>num_cols are zero. #The second possible failure is if (s_i,a_j-s_j) = (1,1).
r""" Takes the compatible vectors and uses them to produce a Laurent polynomial in the upper cluster algebra.
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import _vector_decomposition
sage: B = matrix([[0,1,0,0],[-1,0,1,1],[0,-1,0,0],[0,-1,0,0],[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]) sage: C = ClusterSeed(B) sage: v = _vector_decomposition([1,2,1,2],8) sage: c = C._compute_compatible_vectors(v) sage: C._produce_upper_cluster_algebra_element(v,c) (x0^2*x1^3*x4*x5^2*x6*x7^2 + x0*x1^2*x2*x3*x4*x5*x6*x7 + 2*x0^2*x1^2*x4*x5^2*x6*x7 + x0^2*x1^2*x4*x5^2*x7^2 + x0*x1*x2*x3*x4*x5*x6 + x0^2*x1*x4*x5^2*x6 + x0*x1^2*x2*x3*x5*x7 + 2*x0*x1*x2*x3*x4*x5*x7 + 2*x0^2*x1*x4*x5^2*x7 + x1*x2^2*x3^2 + x2^2*x3^2*x4 + x0*x1*x2*x3*x5 + 2*x0*x2*x3*x4*x5 + x0^2*x4*x5^2)/(x0*x1^2*x2*x3^2)
sage: B = matrix([[0,1,1,0],[-1,0,1,1],[-1,-1,0,0],[0,-1,0,0]]) sage: C = ClusterSeed(B) sage: v = _vector_decomposition([2,-1,3,-2],4) sage: c = C._compute_compatible_vectors(v) sage: C._produce_upper_cluster_algebra_element(v,c) (x0^3*x1^4*x3^2 + 2*x0^2*x1^4*x2*x3^2 + x0*x1^4*x2^2*x3^2 + 3*x0^2*x1^3*x3^2 + 4*x0*x1^3*x2*x3^2 + x1^3*x2^2*x3^2 + 3*x0*x1^2*x3^2 + 2*x1^2*x2*x3^2 + x1*x3^2)/(x0^2*x2^3) """ #Creates a the fraction field of a polynomial ring in which to build the Laurent polynomials. #Computes the Laurent Polynomial for each vector in the decomposition. #Laurent polynomial for each vector in {0,1}^n #If the vector in vd is negative then it did not contribute any compatible vectors. It will only contribute a Laurent monomial. This is the case when cList[i]=[] #Each compatible sequence gives a term in the numerator of the Laurent polynomial. #Calulates the monomial in the term. #The exponent is determined by the vectors a,s, and the matrix B. #Gives a numerator for the negative vector, or else the product would be zero. else:
#Uses the vectors in vd to calculates the denominator of the Laurent. #Each copy of a vector in vd contributes a factor of the Laurent polynomial calculated from it. #The UCA element for the vector a is the product of the elements produced from the vectors in its decomposition.
""" Binomial coefficient which we define as zero for negative n.
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import _bino sage: _bino(3, 2) 3 sage: _bino(-3, 2) 0 """ else:
""" Coefficients in Laurent expansion of greedy element, as defined by recursion.
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import coeff_recurs sage: coeff_recurs(1, 1, 5, 5, 3, 3) 10 """ return 0 else: for k in range(1, p+1)) else: for k in range(1, q+1))
r""" Encodes a *maximal* Dyck path from (0,0) to (n,m) (for n >= m >= 0) as a subset of {0,1,2,..., 2n-1}. The encoding is given by indexing horizontal edges by odd numbers and vertical edges by evens.
The horizontal between (i,j) and (i+1,j) is indexed by the odd number 2*i+1. The vertical between (i,j) and (i,j+1) is indexed by the even number 2*j.
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import PathSubset sage: PathSubset(4,0) {1, 3, 5, 7} sage: PathSubset(4,1) {1, 3, 5, 6, 7} sage: PathSubset(4,2) {1, 2, 3, 5, 6, 7} sage: PathSubset(4,3) {1, 2, 3, 4, 5, 6, 7} sage: PathSubset(4,4) {0, 1, 2, 3, 4, 5, 6, 7} """
r""" Rearranges the encoding for a *maximal* Dyck path (as a set) so that it is a list in the proper order of the edges.
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import PathSubset sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import SetToPath sage: SetToPath(PathSubset(4,0)) [1, 3, 5, 7] sage: SetToPath(PathSubset(4,1)) [1, 3, 5, 7, 6] sage: SetToPath(PathSubset(4,2)) [1, 3, 2, 5, 7, 6] sage: SetToPath(PathSubset(4,3)) [1, 3, 2, 5, 4, 7, 6] sage: SetToPath(PathSubset(4,4)) [1, 0, 3, 2, 5, 4, 7, 6] """
""" Check if the subset T contributes to the computation of the greedy element x[m,n] in the rank two (b,c)-cluster algebra.
This uses the conditions of Lee-Li-Zelevinsky's paper [LLZ2014]_.
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import is_LeeLiZel_allowable sage: is_LeeLiZel_allowable({1,3,2,5,7,6},4,2,6,6) False sage: is_LeeLiZel_allowable({1,2,5},3,3,1,1) True """ else:
r""" Get the green vertices from a matrix. Will go through each column and return the ones where no entry is greater than 0.
INPUT:
- ``C`` -- The C matrix to check
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import get_green_vertices sage: S = ClusterSeed(['A',4]); S.mutate([1,2,3,2,0,1,2,0,3]) sage: get_green_vertices(S.c_matrix()) [0, 3]
""" ## old code commented out #import numpy as np #max_entries = [ np.max(np.array(C.column(i))) for i in range(C.ncols()) ] #return [i for i in range(C.ncols()) if max_entries[i] > 0]
r""" Get the red vertices from a matrix.
Will go through each column and return the ones where no entry is less than 0.
INPUT:
- ``C`` -- The C matrix to check
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import get_red_vertices sage: S = ClusterSeed(['A',4]); S.mutate([1,2,3,2,0,1,2,0,3]) sage: get_red_vertices(S.c_matrix()) [1, 2] """ ## old code commented out #import numpy as np #min_entries = [ np.min(np.array(C.column(i))) for i in range(C.ncols()) ] #return [i for i in range(C.ncols()) if min_entries[i] < 0]
r""" Decomposes an integer vector.
INPUT:
- `a` -- a vector in `\mathbb{Z}^n.`
OUTPUT:
A decomposition of `a` into vectors `b_i \in \{0,1\}^n` such that `a= \sum c_i b_i` for `c_i \in \mathbb{Z}.` Returns an array of tuples `\right[b_i,c_i\left].`
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import _vector_decomposition sage: _vector_decomposition([2,-1,3,-2],4) [[(0, -1, 0, 0), 1], [(0, 0, 0, -1), 2], [(1, 0, 1, 0), 2], [(0, 0, 1, 0), 1]] sage: _vector_decomposition([3,2,3,4],4) [[(1, 1, 1, 1), 2], [(1, 0, 1, 1), 1], [(0, 0, 0, 1), 1]] """
#create a vector with i-th coordinate -1 else:
#Finds the difference between the largest and smallest entry in the vector to determine the how many vectors are in the decomposition min = a_plus[i]
#Creates a copy of a that will be edited when decomposing the vector. #Resets the counter i and puts the integer partition of the ith component of a into an array. c.append(-1) ap[i] += 1 #Converts the integer partitions into decomposition vectors. cols[i].reverse() #Adds a zero to the end of every vector for each frozen vertex. #Collects identical decomposition vectors and counts their multiplicities.
r""" Returns an array of all vectors in `\{0,1\}^n`.
INPUT:
- `n` -- an integer.
OUTPUT:
A 2-dimensional array containing all elements of `\{0,1\}^n`.
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import _power_set
sage: _power_set(2) [[0, 0], [0, 1], [1, 0], [1, 1]]
sage: _power_set(5) [[0, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 0, 1, 1], [0, 0, 1, 0, 0], [0, 0, 1, 0, 1], [0, 0, 1, 1, 0], [0, 0, 1, 1, 1], [0, 1, 0, 0, 0], [0, 1, 0, 0, 1], [0, 1, 0, 1, 0], [0, 1, 0, 1, 1], [0, 1, 1, 0, 0], [0, 1, 1, 0, 1], [0, 1, 1, 1, 0], [0, 1, 1, 1, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 1], [1, 0, 0, 1, 0], [1, 0, 0, 1, 1], [1, 0, 1, 0, 0], [1, 0, 1, 0, 1], [1, 0, 1, 1, 0], [1, 0, 1, 1, 1], [1, 1, 0, 0, 0], [1, 1, 0, 0, 1], [1, 1, 0, 1, 0], [1, 1, 0, 1, 1], [1, 1, 1, 0, 0], [1, 1, 1, 0, 1], [1, 1, 1, 1, 0], [1, 1, 1, 1, 1]]
"""
r""" Each element of `l2` gets added to the end of a copy of each array in `l1`. Used to produce the power set.
INPUT:
-`l1` -- a 2-dimensional array. -`l2` -- a single array.
OUTPUT:
A 2-dimensional array.
EXAMPLES::
sage: from sage.combinat.cluster_algebra_quiver.cluster_seed import _multi_concatenate
sage: _multi_concatenate([[0,1,2]],[3,4,5]) [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5]]
sage: _multi_concatenate([[0,1,2],[3,4,5]],[6,7,8]) [[0, 1, 2, 6], [0, 1, 2, 7], [0, 1, 2, 8], [3, 4, 5, 6], [3, 4, 5, 7], [3, 4, 5, 8]] """
r""" This class is a thin wrapper for cluster variables in cluster seeds.
It provides the extra feature to store if a variable is frozen or not.
- the associated positive root::
sage: S = ClusterSeed(['A',3]) sage: for T in S.variable_class_iter(): ....: print("{} {}".format(T, T.almost_positive_root())) x0 -alpha[1] x1 -alpha[2] x2 -alpha[3] (x1 + 1)/x0 alpha[1] (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2) alpha[1] + alpha[2] + alpha[3] (x1 + 1)/x2 alpha[3] (x0*x2 + x1 + 1)/(x0*x1) alpha[1] + alpha[2] (x0*x2 + 1)/x1 alpha[2] (x0*x2 + x1 + 1)/(x1*x2) alpha[2] + alpha[3] """ r""" Initialize a cluster variable in the same way that elements in the field of rational functions are initialized.
.. SEEALSO:: :class:`Fraction Field of Multivariate Polynomial Ring`
TESTS::
sage: S = ClusterSeed(['A',2]) sage: for f in S.cluster(): ....: print(type(f)) <class 'sage.combinat.cluster_algebra_quiver.cluster_seed.ClusterVariable'> <class 'sage.combinat.cluster_algebra_quiver.cluster_seed.ClusterVariable'>
sage: S.variable_class() [(x0 + x1 + 1)/(x0*x1), (x1 + 1)/x0, (x0 + 1)/x1, x1, x0] """
r""" Returns the *almost positive root* associated to ``self`` if ``self`` is of finite type.
EXAMPLES::
sage: S = ClusterSeed(['A',3]) sage: for T in S.variable_class_iter(): ....: print("{} {}".format(T, T.almost_positive_root())) x0 -alpha[1] x1 -alpha[2] x2 -alpha[3] (x1 + 1)/x0 alpha[1] (x1^2 + x0*x2 + 2*x1 + 1)/(x0*x1*x2) alpha[1] + alpha[2] + alpha[3] (x1 + 1)/x2 alpha[3] (x0*x2 + x1 + 1)/(x0*x1) alpha[1] + alpha[2] (x0*x2 + 1)/x1 alpha[2] (x0*x2 + x1 + 1)/(x1*x2) alpha[2] + alpha[3] """ raise ValueError('The variable is frozen.') raise ValueError('The cluster algebra for %s is not of finite type.'%self._repr_()) else: self._mutation_type = self.parent().mutation_type() # the import above is used in the line below # mt is a string of the shape "['A', 15]" # where A is a single letter and 15 is an integer
else: else: raise ValueError('The cluster algebra for %s is not of finite type.'%self._repr_()) |