Cluster algebras¶
This file constructs cluster algebras using the ParentElement framework. The implementation mainly utilizes structural theorems from [FZ2007].
The key points being used here are these:
 cluster variables are parametrized by their gvectors;
 gvectors (together with cvectors) provide a selfstanding model for the combinatorics behind any cluster algebra;
 each cluster variable in any cluster algebra can be computed, by the separation of additions formula, from its gvector and Fpolynomial.
Accordingly this file provides three classes:
ClusterAlgebra
, constructed as a subobject of
sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_generic
,
is the frontend of this implementation. It provides all the algebraic
features (like ring morphisms), it computes cluster variables, it is
responsible for controlling the exploration of the exchange graph and
serves as the repository for all the data recursively computed so far.
In particular, all gvectors and all Fpolynomials of known cluster
variables as well as a mutation path by which they can be obtained
are recorded. In the optic of efficiency, this implementation does not
store directly the exchange graph nor the exchange relations. Both of
these could be added to ClusterAlgebra
with minimal effort.
ClusterAlgebraSeed
provides the combinatorial backbone
for ClusterAlgebra
. It is an auxiliary class and therefore its
instances should not be directly created by the user. Rather it
should be accessed via ClusterAlgebra.current_seed()
and ClusterAlgebra.initial_seed()
. The task of performing current
seed mutations is delegated to this class. Seeds are considered equal if
they have the same parent cluster algebra and they can be obtained from
each other by a permutation of their data (i.e. if they coincide as
unlabelled seeds). Cluster algebras whose initial seeds are equal in the
above sense are not considered equal but are endowed with coercion maps
to each other. More generally, a cluster algebra is endowed with coercion
maps from any cluster algebra which is obtained by freezing a collection
of initial cluster variables and/or permuting both cluster variables
and coefficients.
ClusterAlgebraElement
is a thin wrapper around
sage.rings.polynomial.laurent_polynomial.LaurentPolynomial
providing all the functions specific to cluster variables.
Elements of a cluster algebra with principal coefficients have special methods
and these are grouped in the subclass PrincipalClusterAlgebraElement
.
One more remark about this implementation. Instances of
ClusterAlgebra
are built by identifying the initial cluster variables
with the generators of ClusterAlgebra.ambient()
. In particular, this
forces a specific embedding into the ambient field of rational expressions. In
view of this, although cluster algebras themselves are independent of the
choice of initial seed, ClusterAlgebra.mutate_initial()
is forced to
return a different instance of ClusterAlgebra
. At the moment there
is no coercion implemented among the two instances but this could in
principle be added to ClusterAlgebra.mutate_initial()
.
REFERENCES:
AUTHORS:
 Dylan Rupel (20150615): initial version
 Salvatore Stella (20150615): initial version
EXAMPLES:
We begin by creating a simple cluster algebra and printing its initial exchange matrix:
sage: A = ClusterAlgebra(['A', 2]); A
A Cluster Algebra with cluster variables x0, x1 and no coefficients over Integer Ring
sage: A.b_matrix()
[ 0 1]
[1 0]
A
is of finite type so we can explore all its exchange graph:
sage: A.explore_to_depth(infinity)
and get all its gvectors, Fpolynomials, and cluster variables:
sage: sorted(A.g_vectors_so_far())
[(1, 0), (1, 1), (0, 1), (0, 1), (1, 0)]
sage: sorted(A.F_polynomials_so_far(), key=str)
[1, 1, u0 + 1, u0*u1 + u0 + 1, u1 + 1]
sage: sorted(A.cluster_variables_so_far(), key=str)
[(x0 + 1)/x1, (x0 + x1 + 1)/(x0*x1), (x1 + 1)/x0, x0, x1]
Simple operations among cluster variables behave as expected:
sage: s = A.cluster_variable((0, 1)); s
(x0 + 1)/x1
sage: t = A.cluster_variable((1, 1)); t
(x1 + 1)/x0
sage: t + s
(x0^2 + x1^2 + x0 + x1)/(x0*x1)
sage: _.parent() == A
True
sage: t  s
(x0^2 + x1^2  x0 + x1)/(x0*x1)
sage: _.parent() == A
True
sage: t*s
(x0*x1 + x0 + x1 + 1)/(x0*x1)
sage: _.parent() == A
True
sage: t/s
(x1^2 + x1)/(x0^2 + x0)
sage: _.parent() == A
False
Division is not guaranteed to yield an element of A
so it returns an
element of A.ambient().fraction_field()
instead:
sage: (t/s).parent() == A.ambient().fraction_field()
True
We can compute denominator vectors of any element of A
:
sage: (t*s).d_vector()
(1, 1)
Since we are in rank 2 and we do not have coefficients we can compute the greedy element associated to any denominator vector:
sage: A.rank() == 2 and A.coefficients() == ()
True
sage: A.greedy_element((1, 1))
(x0 + x1 + 1)/(x0*x1)
sage: _ == t*s
False
not surprising since there is no cluster in A
containing
both t
and s
:
sage: seeds = A.seeds(mutating_F=false)
sage: [ S for S in seeds if (0, 1) in S and (1, 1) in S ]
[]
indeed:
sage: A.greedy_element((1, 1)) == A.cluster_variable((1, 0))
True
Disabling Fpolynomials in the computation just done was redundant because we already explored the whole exchange graph before. Though in different circumstances it could have saved us considerable time.
gvectors and Fpolynomials can be computed from elements of A
only if
A
has principal coefficients at the initial seed:
sage: (t*s).g_vector()
Traceback (most recent call last):
...
AttributeError: 'ClusterAlgebra_with_category.element_class' object has no attribute 'g_vector'
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True)
sage: A.explore_to_depth(infinity)
sage: s = A.cluster_variable((0, 1)); s
(x0*y1 + 1)/x1
sage: t = A.cluster_variable((1, 1)); t
(x1 + y0)/x0
sage: (t*s).g_vector()
(1, 0)
sage: (t*s).F_polynomial()
u0*u1 + u0 + u1 + 1
sage: (t*s).is_homogeneous()
True
sage: (t+s).is_homogeneous()
False
sage: (t+s).homogeneous_components()
{(1, 1): (x1 + y0)/x0, (0, 1): (x0*y1 + 1)/x1}
Each cluster algebra is endowed with a reference to a current seed; it could be useful to assign a name to it:
sage: A = ClusterAlgebra(['F', 4])
sage: len(A.g_vectors_so_far())
4
sage: A.current_seed()
The initial seed of a Cluster Algebra with cluster variables x0, x1, x2, x3
and no coefficients over Integer Ring
sage: A.current_seed() == A.initial_seed()
True
sage: S = A.current_seed()
sage: S.b_matrix()
[ 0 1 0 0]
[1 0 1 0]
[ 0 2 0 1]
[ 0 0 1 0]
sage: S.g_matrix()
[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[0 0 0 1]
sage: S.cluster_variables()
[x0, x1, x2, x3]
and use S
to walk around the exchange graph of A
:
sage: S.mutate(0); S
The seed of a Cluster Algebra with cluster variables x0, x1, x2, x3
and no coefficients over Integer Ring obtained from the initial
by mutating in direction 0
sage: S.b_matrix()
[ 0 1 0 0]
[ 1 0 1 0]
[ 0 2 0 1]
[ 0 0 1 0]
sage: S.g_matrix()
[1 0 0 0]
[ 1 1 0 0]
[ 0 0 1 0]
[ 0 0 0 1]
sage: S.cluster_variables()
[(x1 + 1)/x0, x1, x2, x3]
sage: S.mutate('sinks'); S
The seed of a Cluster Algebra with cluster variables x0, x1, x2, x3
and no coefficients over Integer Ring obtained from the initial
by mutating along the sequence [0, 2]
sage: S.mutate([2, 3, 2, 1, 0]); S
The seed of a Cluster Algebra with cluster variables x0, x1, x2, x3
and no coefficients over Integer Ring obtained from the initial
by mutating along the sequence [0, 3, 2, 1, 0]
sage: S.g_vectors()
[(0, 1, 2, 0), (1, 2, 2, 0), (0, 1, 1, 0), (0, 0, 0, 1)]
sage: S.cluster_variable(3)
(x2 + 1)/x3
Walking around by mutating S
updates the informations stored in A
:
sage: len(A.g_vectors_so_far())
10
sage: A.current_seed().path_from_initial_seed()
[0, 3, 2, 1, 0]
sage: A.current_seed() == S
True
Starting from A.initial_seed()
still records data in A
but does not
update A.current_seed()
:
sage: S1 = A.initial_seed()
sage: S1.mutate([2, 1, 3])
sage: len(A.g_vectors_so_far())
11
sage: S1 == A.current_seed()
False
Since ClusterAlgebra
inherits from UniqueRepresentation
,
computed data is shared across instances:
sage: A1 = ClusterAlgebra(['F', 4])
sage: A1 is A
True
sage: len(A1.g_vectors_so_far())
11
It can be useful, at times to forget all computed data. Because of
UniqueRepresentation
this cannot be achieved by simply creating a
new instance; instead it has to be manually triggered by:
sage: A.clear_computed_data()
sage: len(A.g_vectors_so_far())
4
Given a cluster algebra A
we may be looking for a specific cluster
variable:
sage: A = ClusterAlgebra(['E', 8, 1])
sage: v = (1, 1, 1, 1, 1, 1, 0, 0, 1)
sage: A.find_g_vector(v, depth=2)
sage: seq = A.find_g_vector(v); seq # random
[0, 1, 2, 4, 3]
sage: v in A.initial_seed().mutate(seq, inplace=False).g_vectors()
True
This also performs mutations of Fpolynomials:
sage: A.F_polynomial((1, 1, 1, 1, 1, 1, 0, 0, 1))
u0*u1*u2*u3*u4 + u0*u1*u2*u4 + u0*u2*u3*u4 + u0*u1*u2 + u0*u2*u4
+ u2*u3*u4 + u0*u2 + u0*u4 + u2*u4 + u0 + u2 + u4 + 1
which might not be a good idea in algebras that are too big. One workaround is to first disable Fpolynomials and then recompute only the desired mutations:
sage: A.reset_exploring_iterator(mutating_F=False) # long time
sage: v = (1, 1, 2, 2, 1, 1, 1, 1, 1) # long time
sage: seq = A.find_g_vector(v); seq # long time random
[1, 0, 2, 6, 5, 4, 3, 8, 1]
sage: S = A.initial_seed().mutate(seq, inplace=False) # long time
sage: v in S.g_vectors() # long time
True
sage: A.current_seed().mutate(seq) # long time
sage: A.F_polynomial((1, 1, 2, 2, 1, 1, 1, 1, 1)) # long time
u0*u1^2*u2^2*u3*u4*u5*u6*u8 +
...
2*u2 + u4 + u6 + 1
We can manually freeze cluster variables and get coercions in between the two algebras:
sage: A = ClusterAlgebra(['F', 4]); A
A Cluster Algebra with cluster variables x0, x1, x2, x3 and no coefficients
over Integer Ring
sage: A1 = ClusterAlgebra(A.b_matrix().matrix_from_columns([0, 1, 2]), coefficient_prefix='x'); A1
A Cluster Algebra with cluster variables x0, x1, x2 and coefficient x3
over Integer Ring
sage: A.has_coerce_map_from(A1)
True
and we also have an immersion of A.base()
into A
and of A
into A.ambient()
:
sage: A.has_coerce_map_from(A.base())
True
sage: A.ambient().has_coerce_map_from(A)
True
but there is currently no coercion in between algebras obtained by mutating at the initial seed:
sage: A1 = A.mutate_initial(0); A1
A Cluster Algebra with cluster variables x4, x1, x2, x3 and no coefficients
over Integer Ring
sage: A.b_matrix() == A1.b_matrix()
False
sage: [X.has_coerce_map_from(Y) for X, Y in [(A, A1), (A1, A)]]
[False, False]

class
sage.algebras.cluster_algebra.
ClusterAlgebra
(B, **kwargs)¶ Bases:
sage.structure.parent.Parent
,sage.structure.unique_representation.UniqueRepresentation
A Cluster Algebra.
INPUT:
data
– some data defining a cluster algebra; it can be anything that can be parsed byClusterQuiver
scalars
– a ring (default \(\ZZ\)); the scalars over which the cluster algebra is definedcluster_variable_prefix
– string (default'x'
); it needs to be a valid variable namecluster_variable_names
– a list of strings; each element needs to be a valid variable name; supersedescluster_variable_prefix
coefficient_prefix
– string (default'y'
); it needs to be a valid variable name.coefficient_names
– a list of strings; each element needs to be a valid variable name; supersedescluster_variable_prefix
principal_coefficients
– bool (defaultFalse
); supersedes any coefficient defined bydata
ALGORITHM:
The implementation is mainly based on [FZ2007] and [NZ2012].
EXAMPLES:
sage: B = matrix([(0, 1, 0, 0), (1, 0, 1, 0), (0, 1, 0, 1), (0, 0, 2, 0), (1, 0, 0, 0), (0, 1, 0, 0)]) sage: A = ClusterAlgebra(B); A A Cluster Algebra with cluster variables x0, x1, x2, x3 and coefficients y0, y1 over Integer Ring sage: A.gens() (x0, x1, x2, x3, y0, y1) sage: A = ClusterAlgebra(['A', 2]); A A Cluster Algebra with cluster variables x0, x1 and no coefficients over Integer Ring sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True); A.gens() (x0, x1, y0, y1) sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True, coefficient_prefix='x'); A.gens() (x0, x1, x2, x3) sage: A = ClusterAlgebra(['A', 3], principal_coefficients=True, cluster_variable_names=['a', 'b', 'c']); A.gens() (a, b, c, y0, y1, y2) sage: A = ClusterAlgebra(['A', 3], principal_coefficients=True, cluster_variable_names=['a', 'b']) Traceback (most recent call last): ... ValueError: cluster_variable_names should be an iterable of 3 valid variable names sage: A = ClusterAlgebra(['A', 3], principal_coefficients=True, coefficient_names=['a', 'b', 'c']); A.gens() (x0, x1, x2, a, b, c) sage: A = ClusterAlgebra(['A', 3], principal_coefficients=True, coefficient_names=['a', 'b']) Traceback (most recent call last): ... ValueError: coefficient_names should be an iterable of 3 valid variable names

F_polynomial
(g_vector)¶ Return the Fpolynomial with gvector
g_vector
if it has been found.INPUT:
g_vector
– tuple; the gvector of the Fpolynomial to return
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.clear_computed_data() sage: A.F_polynomial((1, 1)) Traceback (most recent call last): ... KeyError: 'the gvector (1, 1) has not been found yet' sage: A.initial_seed().mutate(0, mutating_F=False) sage: A.F_polynomial((1, 1)) Traceback (most recent call last): ... KeyError: 'the Fpolynomial with gvector (1, 1) has not been computed yet; you can compute it by mutating from the initial seed along the sequence [0]' sage: A.initial_seed().mutate(0) sage: A.F_polynomial((1, 1)) u0 + 1

F_polynomials
()¶ Return an iterator producing all the F_polynomials of
self
.ALGORITHM:
This method does not use the caching framework provided by
self
, but recomputes all the Fpolynomials from scratch. On the other hand it stores the results so that other methods likeF_polynomials_so_far()
can access them afterwards.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: len(list(A.F_polynomials())) 9

F_polynomials_so_far
()¶ Return a list of the Fpolynomials encountered so far.
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.clear_computed_data() sage: A.current_seed().mutate(0) sage: sorted(A.F_polynomials_so_far(), key=str) [1, 1, u0 + 1]

ambient
()¶ Return the Laurent polynomial ring containing
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True) sage: A.ambient() Multivariate Laurent Polynomial Ring in x0, x1, y0, y1 over Integer Ring

b_matrix
()¶ Return the initial exchange matrix of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.b_matrix() [ 0 1] [1 0]

clear_computed_data
()¶ Clear the cache of computed gvectors and Fpolynomials and reset both the current seed and the exploring iterator.
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.clear_computed_data() sage: sorted(A.g_vectors_so_far()) [(0, 1), (1, 0)] sage: A.current_seed().mutate([1, 0]) sage: sorted(A.g_vectors_so_far()) [(1, 0), (0, 1), (0, 1), (1, 0)] sage: A.clear_computed_data() sage: sorted(A.g_vectors_so_far()) [(0, 1), (1, 0)]

cluster_fan
(depth=+Infinity)¶ Return the cluster fan (the fan of gvectors) of
self
.INPUT:
depth
– a positive integer or infinity (defaultinfinity
); the maximum depth at which to compute
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.cluster_fan() Rational polyhedral fan in 2d lattice N

cluster_variable
(g_vector)¶ Return the cluster variable with gvector
g_vector
if it has been found.INPUT:
g_vector
– tuple; the gvector of the cluster variable to return
ALGORITHM:
This function computes cluster variables from their gvectors and Fpolynomials using the “separation of additions” formula of Theorem 3.7 in [FZ2007].
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.initial_seed().mutate(0) sage: A.cluster_variable((1, 1)) (x1 + 1)/x0

cluster_variables
()¶ Return an iterator producing all the cluster variables of
self
.ALGORITHM:
This method does not use the caching framework provided by
self
, but recomputes all the cluster variables from scratch. On the other hand it stores the results so that other methods likecluster_variables_so_far()
can access them afterwards.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: len(list(A.cluster_variables())) 9

cluster_variables_so_far
()¶ Return a list of the cluster variables encountered so far.
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.clear_computed_data() sage: A.current_seed().mutate(0) sage: sorted(A.cluster_variables_so_far(), key=str) [(x1 + 1)/x0, x0, x1]

coefficient
(j)¶ Return the
j
th coefficient ofself
.INPUT:
j
– an integer inrange(self.parent().rank())
; the index of the coefficient to return
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True) sage: A.coefficient(0) y0

coefficient_names
()¶ Return the list of coefficient names.
EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: A.coefficient_names() () sage: A1 = ClusterAlgebra(['B', 2], principal_coefficients=True) sage: A1.coefficient_names() ('y0', 'y1') sage: A2 = ClusterAlgebra(['C', 3], principal_coefficients=True, coefficient_prefix='x') sage: A2.coefficient_names() ('x3', 'x4', 'x5')

coefficients
()¶ Return the list of coefficients of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True) sage: A.coefficients() (y0, y1) sage: A1 = ClusterAlgebra(['B', 2]) sage: A1.coefficients() ()

contains_seed
(seed)¶ Test if
seed
is a seed ofself
.INPUT:
seed
– aClusterAlgebraSeed
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True); A A Cluster Algebra with cluster variables x0, x1 and coefficients y0, y1 over Integer Ring sage: S = copy(A.current_seed()) sage: A.contains_seed(S) True

current_seed
()¶ Return the current seed of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.clear_computed_data() sage: A.current_seed() The initial seed of a Cluster Algebra with cluster variables x0, x1 and no coefficients over Integer Ring

explore_to_depth
(depth)¶ Explore the exchange graph of
self
up to distancedepth
from the initial seed.INPUT:
depth
– a positive integer or infinity; the maximum depth at which to stop searching
EXAMPLES:
sage: A = ClusterAlgebra(['A', 4]) sage: A.explore_to_depth(infinity) sage: len(A.g_vectors_so_far()) 14

find_g_vector
(g_vector, depth=+Infinity)¶ Return a mutation sequence to obtain a seed containing the gvector
g_vector
from the initial seed.INPUT:
g_vector
– a tuple: the gvector to finddepth
– a positive integer or infinity (defaultinfinity
); the maximum distance fromself.current_seed
to reach
OUTPUT:
This function returns a list of integers if it can find
g_vector
, otherwise it returnsNone
. If the exploring iterator stops, it means that the algebra is of finite type andg_vector
is not the gvector of any cluster variable. In this case the function resets the iterator and raises an error.EXAMPLES:
sage: A = ClusterAlgebra(['G', 2], principal_coefficients=True) sage: A.clear_computed_data() sage: A.find_g_vector((2, 3), depth=2) sage: A.find_g_vector((2, 3), depth=3) [0, 1, 0] sage: A.find_g_vector((1, 1), depth=3) sage: A.find_g_vector((1, 1), depth=4) Traceback (most recent call last): ... ValueError: (1, 1) is not the gvector of any cluster variable of a Cluster Algebra with cluster variables x0, x1 and coefficients y0, y1 over Integer Ring

g_vectors
(mutating_F=True)¶ Return an iterator producing all the gvectors of
self
.INPUT:
mutating_F
– bool (defaultTrue
); whether to compute Fpolynomials; disable this for speed considerations
ALGORITHM:
This method does not use the caching framework provided by
self
, but recomputes all the gvectors from scratch. On the other hand it stores the results so that other methods likeg_vectors_so_far()
can access them afterwards.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: len(list(A.g_vectors())) 9

g_vectors_so_far
()¶ Return a list of the gvectors of cluster variables encountered so far.
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.clear_computed_data() sage: A.current_seed().mutate(0) sage: sorted(A.g_vectors_so_far()) [(1, 1), (0, 1), (1, 0)]

gens
()¶ Return the list of initial cluster variables and coefficients of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True) sage: A.gens() (x0, x1, y0, y1) sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True, coefficient_prefix='x') sage: A.gens() (x0, x1, x2, x3)

greedy_element
(d_vector)¶ Return the greedy element with denominator vector
d_vector
.INPUT:
d_vector
– tuple of 2 integers; the denominator vector of the element to compute
ALGORITHM:
This implements greedy elements of a rank 2 cluster algebra using Equation (1.5) from [LLZ2014].
EXAMPLES:
sage: A = ClusterAlgebra(['A', [1, 1], 1]) sage: A.greedy_element((1, 1)) (x0^2 + x1^2 + 1)/(x0*x1)

initial_cluster_variable
(j)¶ Return the
j
th initial cluster variable ofself
.INPUT:
j
– an integer inrange(self.parent().rank())
; the index of the cluster variable to return
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True) sage: A.initial_cluster_variable(0) x0

initial_cluster_variable_names
()¶ Return the list of initial cluster variable names.
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True) sage: A.initial_cluster_variable_names() ('x0', 'x1') sage: A1 = ClusterAlgebra(['B', 2], cluster_variable_prefix='a') sage: A1.initial_cluster_variable_names() ('a0', 'a1')

initial_cluster_variables
()¶ Return the list of initial cluster variables of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True) sage: A.initial_cluster_variables() (x0, x1)

initial_seed
()¶ Return the initial seed of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.initial_seed() The initial seed of a Cluster Algebra with cluster variables x0, x1 and no coefficients over Integer Ring

lift
(x)¶ Return
x
as an element ofambient()
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True) sage: x = A.cluster_variable((1, 0)) sage: A.lift(x).parent() Multivariate Laurent Polynomial Ring in x0, x1, y0, y1 over Integer Ring

lower_bound
()¶ Return the lower bound associated to
self
.EXAMPLES:
sage: A = ClusterAlgebra(['F', 4]) sage: A.lower_bound() Traceback (most recent call last): ... NotImplementedError: not implemented yet

mutate_initial
(direction, **kwargs)¶ Return the cluster algebra obtained by mutating
self
at the initial seed.Warning
This method is significantly slower than
ClusterAlgebraSeed.mutate()
. It is therefore advisable to use the latter for exploration purposes.INPUT:
direction
– in which direction(s) to mutate, it can be: an integer in
range(self.rank())
to mutate in one direction only  an iterable of such integers to mutate along a sequence
 a string “sinks” or “sources” to mutate at all sinks or sources simultaneously
 an integer in
mutating_F
– bool (defaultTrue
); whether to compute Fpolynomials while mutating
Note
While knowing Fpolynomials is essential to computing cluster variables, the process of mutating them is quite slow. If you care only about combinatorial data like gvectors and cvectors, setting
mutating_F=False
yields significant benefits in terms of speed.ALGORITHM:
This function computes data for the new algebra from known data for the old algebra using Equation (4.2) from [NZ2012] for gvectors, and Equation (6.21) from [FZ2007] for Fpolynomials. The exponent \(h\) in the formula for Fpolynomials is
min(0, old_g_vect[k])
due to [NZ2012] Proposition 4.2.EXAMPLES:
sage: A = ClusterAlgebra(['F', 4]) sage: A.explore_to_depth(infinity) sage: B = A.b_matrix() sage: B.mutate(0) sage: A1 = ClusterAlgebra(B) sage: A1.explore_to_depth(infinity) sage: A2 = A1.mutate_initial(0) sage: A2._F_poly_dict == A._F_poly_dict True
Check that we did not mess up the original algebra because of
UniqueRepresentation
:sage: A = ClusterAlgebra(['A',2]) sage: A.mutate_initial(0) is A False
A faster example without recomputing Fpolynomials:
sage: A = ClusterAlgebra(matrix([[0,5],[5,0]])) sage: A.mutate_initial([0,1]*10, mutating_F=False) A Cluster Algebra with cluster variables x20, x21 and no coefficients over Integer Ring
Check that trac ticket #28176 is fixed:
sage: A = ClusterAlgebra( matrix(5,[0,1,1,1,1]), cluster_variable_names=['p13'], coefficient_names=['p12','p23','p34','p41']); A A Cluster Algebra with cluster variable p13 and coefficients p12, p23, p34, p41 over Integer Ring sage: A.mutate_initial(0) A Cluster Algebra with cluster variable x0 and coefficients p12, p23, p34, p41 over Integer Ring sage: A1 = ClusterAlgebra(['A',[2,1],1]) sage: A2 = A1.mutate_initial([0,1,0]) sage: len(A2.g_vectors_so_far()) == len(A2.F_polynomials_so_far()) True sage: all(parent(f) == A2._U for f in A2.F_polynomials_so_far()) True sage: A2.find_g_vector((0,0,1)) == [] True

rank
()¶ Return the rank of
self
, i.e. the number of cluster variables in any seed.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True); A A Cluster Algebra with cluster variables x0, x1 and coefficients y0, y1 over Integer Ring sage: A.rank() 2

reset_current_seed
()¶ Reset the value reported by
current_seed()
toinitial_seed()
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.clear_computed_data() sage: A.current_seed().mutate([1, 0]) sage: A.current_seed() == A.initial_seed() False sage: A.reset_current_seed() sage: A.current_seed() == A.initial_seed() True

reset_exploring_iterator
(mutating_F=True)¶ Reset the iterator used to explore
self
.INPUT:
mutating_F
– bool (defaultTrue
); whether to also compute Fpolynomials; disable this for speed considerations
EXAMPLES:
sage: A = ClusterAlgebra(['A', 4]) sage: A.clear_computed_data() sage: A.reset_exploring_iterator(mutating_F=False) sage: A.explore_to_depth(infinity) sage: len(A.g_vectors_so_far()) 14 sage: len(A.F_polynomials_so_far()) 4

retract
(x)¶ Return
x
as an element ofself
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2], principal_coefficients=True) sage: L = A.ambient() sage: x = L.gen(0) sage: A.retract(x).parent() A Cluster Algebra with cluster variables x0, x1 and coefficients y0, y1 over Integer Ring

scalars
()¶ Return the ring of scalars over which
self
is defined.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.scalars() Integer Ring

seeds
(**kwargs)¶ Return an iterator running over seeds of
self
.INPUT:
from_current_seed
– bool (defaultFalse
); whether to start the iterator fromcurrent_seed()
orinitial_seed()
mutating_F
– bool (defaultTrue
); whether to compute Fpolynomials also; disable this for speed considerationsallowed_directions
– iterable of integers (defaultrange(self.rank())
); the directions in which to mutatedepth
– a positive integer or infinity (defaultinfinity
); the maximum depth at which to stop searchingcatch_KeyboardInterrupt
– bool (defaultFalse
); whether to catchKeyboardInterrupt
and return it rather then raising an exception – this allows the iterator returned by this method to be resumed after being interrupted
ALGORITHM:
This function traverses the exchange graph in a breadthfirst search.
EXAMPLES:
sage: A = ClusterAlgebra(['A', 4]) sage: A.clear_computed_data() sage: seeds = A.seeds(allowed_directions=[3, 0, 1]) sage: _ = list(seeds) sage: sorted(A.g_vectors_so_far()) [(1, 0, 0, 0), (1, 1, 0, 0), (0, 1, 0, 0), (0, 0, 0, 1), (0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0), (1, 0, 0, 0)]

set_current_seed
(seed)¶ Set the value reported by
current_seed()
toseed
, if it makes sense.INPUT:
seed
– aClusterAlgebraSeed
EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: A.clear_computed_data() sage: S = copy(A.current_seed()) sage: S.mutate([0, 1, 0]) sage: A.current_seed() == S False sage: A.set_current_seed(S) sage: A.current_seed() == S True sage: A1 = ClusterAlgebra(['B', 2]) sage: A.set_current_seed(A1.initial_seed()) Traceback (most recent call last): ... ValueError: This is not a seed in this cluster algebra

theta_basis_element
(g_vector)¶ Return the element of the theta basis with gvector
g_vector
.EXAMPLES:
sage: A = ClusterAlgebra(['F', 4]) sage: A.theta_basis_element((1, 0, 0, 0)) Traceback (most recent call last): ... NotImplementedError: not implemented yet

upper_bound
()¶ Return the upper bound associated to
self
.EXAMPLES:
sage: A = ClusterAlgebra(['F', 4]) sage: A.upper_bound() Traceback (most recent call last): ... NotImplementedError: not implemented yet

upper_cluster_algebra
()¶ Return the upper cluster algebra associated to
self
.EXAMPLES:
sage: A = ClusterAlgebra(['F', 4]) sage: A.upper_cluster_algebra() Traceback (most recent call last): ... NotImplementedError: not implemented yet

class
sage.algebras.cluster_algebra.
ClusterAlgebraElement
¶ Bases:
sage.structure.element_wrapper.ElementWrapper
An element of a cluster algebra.

d_vector
()¶ Return the denominator vector of
self
as a tuple of integers.EXAMPLES:
sage: A = ClusterAlgebra(['F', 4], principal_coefficients=True) sage: A.current_seed().mutate([0, 2, 1]) sage: x = A.cluster_variable((1, 2, 2, 2)) * A.cluster_variable((0, 0, 0, 1))**2 sage: x.d_vector() (1, 1, 2, 2)


class
sage.algebras.cluster_algebra.
ClusterAlgebraSeed
(B, C, G, parent, **kwargs)¶ Bases:
sage.structure.sage_object.SageObject
A seed in a Cluster Algebra.
INPUT:
B
– a skewsymmetrizable integer matrixC
– the matrix of cvectors ofself
G
– the matrix of gvectors ofself
parent
–ClusterAlgebra
; the algebra to which the seed belongspath
– list (default[]
); the mutation sequence from the initial seed ofparent
toself
Warning
Seeds should not be created manually: no test is performed to assert that they are built from consistent data nor that they really are seeds of
parent
. If you create seeds with inconsistent data all sort of things can go wrong, even__eq__()
is no longer guaranteed to give correct answers. Use at your own risk.
F_polynomial
(j)¶ Return the
j
th Fpolynomial ofself
.INPUT:
j
– an integer inrange(self.parent().rank())
; the index of the Fpolynomial to return
EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.F_polynomial(0) 1

F_polynomials
()¶ Return all the Fpolynomials of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.F_polynomials() [1, 1, 1]

b_matrix
()¶ Return the exchange matrix of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.b_matrix() [ 0 1 0] [1 0 1] [ 0 1 0]

c_matrix
()¶ Return the matrix whose columns are the cvectors of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.c_matrix() [1 0 0] [0 1 0] [0 0 1]

c_vector
(j)¶ Return the
j
th cvector ofself
.INPUT:
j
– an integer inrange(self.parent().rank())
; the index of the cvector to return
EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.c_vector(0) (1, 0, 0) sage: S.mutate(0) sage: S.c_vector(0) (1, 0, 0) sage: S.c_vector(1) (1, 1, 0)

c_vectors
()¶ Return all the cvectors of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.c_vectors() [(1, 0, 0), (0, 1, 0), (0, 0, 1)]

cluster_variable
(j)¶ Return the
j
th cluster variable ofself
.INPUT:
j
– an integer inrange(self.parent().rank())
; the index of the cluster variable to return
EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.cluster_variable(0) x0 sage: S.mutate(0) sage: S.cluster_variable(0) (x1 + 1)/x0

cluster_variables
()¶ Return all the cluster variables of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.cluster_variables() [x0, x1, x2]

depth
()¶  Return the length of a mutation sequence from the initial seed
 of
parent()
toself
.
Warning
This is the length of the mutation sequence returned by
path_from_initial_seed()
, which need not be the shortest possible.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: S1 = A.initial_seed() sage: S1.mutate([0, 1, 0, 1]) sage: S1.depth() 4 sage: S2 = A.initial_seed() sage: S2.mutate(1) sage: S2.depth() 1 sage: S1 == S2 True

g_matrix
()¶ Return the matrix whose columns are the gvectors of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.g_matrix() [1 0 0] [0 1 0] [0 0 1]

g_vector
(j)¶ Return the
j
th gvector ofself
.INPUT:
j
– an integer inrange(self.parent().rank())
; the index of the gvector to return
EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.g_vector(0) (1, 0, 0)

g_vectors
()¶ Return all the gvectors of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['A', 3]) sage: S = A.initial_seed() sage: S.g_vectors() [(1, 0, 0), (0, 1, 0), (0, 0, 1)]

mutate
(direction, **kwargs)¶ Mutate
self
.INPUT:
direction
– in which direction(s) to mutate, it can be: an integer in
range(self.rank())
to mutate in one direction only  an iterable of such integers to mutate along a sequence
 a string “sinks” or “sources” to mutate at all sinks or sources simultaneously
 an integer in
inplace
– bool (defaultTrue
); whether to mutate in place or to return a new objectmutating_F
– bool (defaultTrue
); whether to compute Fpolynomials while mutating
Note
While knowing Fpolynomials is essential to computing cluster variables, the process of mutating them is quite slow. If you care only about combinatorial data like gvectors and cvectors, setting
mutating_F=False
yields significant benefits in terms of speed.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: S = A.initial_seed() sage: S.mutate(0); S The seed of a Cluster Algebra with cluster variables x0, x1 and no coefficients over Integer Ring obtained from the initial by mutating in direction 0 sage: S.mutate(5) Traceback (most recent call last): ... ValueError: cannot mutate in direction 5

parent
()¶ Return the parent of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['B', 3]) sage: A.current_seed().parent() == A True

path_from_initial_seed
()¶ Return a mutation sequence from the initial seed of
parent()
toself
.Warning
This is the path used to compute
self
and it does not have to be the shortest possible.EXAMPLES:
sage: A = ClusterAlgebra(['A', 2]) sage: S1 = A.initial_seed() sage: S1.mutate([0, 1, 0, 1]) sage: S1.path_from_initial_seed() [0, 1, 0, 1] sage: S2 = A.initial_seed() sage: S2.mutate(1) sage: S2.path_from_initial_seed() [1] sage: S1 == S2 True

class
sage.algebras.cluster_algebra.
PrincipalClusterAlgebraElement
¶ Bases:
sage.algebras.cluster_algebra.ClusterAlgebraElement
An element in a cluster algebra with principle coefficients.

F_polynomial
()¶ Return the Fpolynomial of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['B', 2], principal_coefficients=True) sage: S = A.initial_seed() sage: S.mutate([0, 1, 0]) sage: S.cluster_variable(0).F_polynomial() == S.F_polynomial(0) True sage: sum(A.initial_cluster_variables()).F_polynomial() Traceback (most recent call last): ... ValueError: this element is not homogeneous

g_vector
()¶ Return the gvector of
self
.EXAMPLES:
sage: A = ClusterAlgebra(['B', 2], principal_coefficients=True) sage: A.cluster_variable((1, 0)).g_vector() == (1, 0) True sage: sum(A.initial_cluster_variables()).g_vector() Traceback (most recent call last): ... ValueError: this element is not homogeneous

homogeneous_components
()¶ Return a dictionary of the homogeneous components of
self
.OUTPUT:
A dictionary whose keys are homogeneous degrees and whose values are the summands of
self
of the given degree.EXAMPLES:
sage: A = ClusterAlgebra(['B', 2], principal_coefficients=True) sage: x = A.cluster_variable((1, 0)) + A.cluster_variable((0, 1)) sage: x.homogeneous_components() {(0, 1): x1, (1, 0): x0}

is_homogeneous
()¶ Return
True
ifself
is a homogeneous element ofself.parent()
.EXAMPLES:
sage: A = ClusterAlgebra(['B', 2], principal_coefficients=True) sage: A.cluster_variable((1, 0)).is_homogeneous() True sage: x = A.cluster_variable((1, 0)) + A.cluster_variable((0, 1)) sage: x.is_homogeneous() False
