Ticket #10527: trac_10527-quiver_mutation_type.patch

File trac_10527-quiver_mutation_type.patch, 75.8 KB (added by Jeroen Demeyer, 10 years ago)
  • doc/en/reference/combinat/index.rst

    # HG changeset patch
    # User Christian Stump <christian.stump at gmail.com>
    # Date 1336581201 14400
    # Node ID a13ad573b671e5ec14bbee348b0e579355ed89b4
    # Parent  5d6b27dc58e2eb031b6a0319a0d8278bdca7a4d8
    10527: This patch implements mutation types of quiver of various types
    
    diff --git a/doc/en/reference/combinat/index.rst b/doc/en/reference/combinat/index.rst
    a b  
    4747   ../sage/combinat/subword
    4848   ../sage/combinat/tiling
    4949   ../sage/combinat/tuple
     50   ../sage/combinat/cluster_algebra_quiver/quiver_mutation_type
    5051
    5152   algebra
    5253   tableaux
  • sage/combinat/all.py

    diff --git a/sage/combinat/all.py b/sage/combinat/all.py
    a b  
    9999from posets.all import *
    100100from backtrack import TransitiveIdeal, TransitiveIdealGraded, SearchForest
    101101
     102# Cluster Algebras and Quivers
     103from cluster_algebra_quiver.all import *
     104
    102105#import lrcalc
    103106
    104107
  • new file sage/combinat/cluster_algebra_quiver/__init__.py

    diff --git a/sage/combinat/cluster_algebra_quiver/__init__.py b/sage/combinat/cluster_algebra_quiver/__init__.py
    new file mode 100644
    - +  
     1# Initialization file for cluster algebras and quivers
  • new file sage/combinat/cluster_algebra_quiver/all.py

    diff --git a/sage/combinat/cluster_algebra_quiver/all.py b/sage/combinat/cluster_algebra_quiver/all.py
    new file mode 100644
    - +  
     1from sage.misc.lazy_import import lazy_import
     2lazy_import("sage.combinat.cluster_algebra_quiver.quiver_mutation_type", "QuiverMutationType")
  • new file sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py

    diff --git a/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py
    new file mode 100644
    - +  
     1r"""
     2Quiver mutation types
     3
     4AUTHORS:
     5
     6- Gregg Musiker (2012, initial version)
     7- Christian Stump (2012, initial version)
     8- Hugh Thomas (2012, initial version)
     9"""
     10#*****************************************************************************
     11#       Copyright (C) 2011 Gregg Musiker <gmusiker@gmail.com>
     12#                          Christian Stump <christian.stump@gmail.com>
     13#                          Hugh Thomas <hugh@math.unb.ca>
     14#
     15#  Distributed under the terms of the GNU General Public License (GPL)
     16#                  http://www.gnu.org/licenses/
     17#*****************************************************************************
     18from sage.structure.sage_object import SageObject
     19from copy import copy
     20from sage.structure.unique_representation import UniqueRepresentation
     21from sage.misc.all import cached_method
     22from sage.rings.all import ZZ, infinity
     23from sage.graphs.all import Graph, DiGraph
     24from sage.rings.all import binomial
     25from sage.all import prod
     26from sage.rings.arith import Euler_Phi
     27from sage.matrix.all import matrix
     28
     29class QuiverMutationTypeFactory(SageObject):
     30    def __call__(self, *args):
     31        """
     32        For a detailed description, see :meth:`QuiverMutationType`.
     33
     34        EXAMPLES::
     35
     36            sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationTypeFactory
     37            sage: QuiverMutationTypeFactory()
     38            QuiverMutationType
     39        """
     40        # get data as arguments or as list/tuple
     41        if len( args ) == 1:
     42            data = args[0]
     43        else:
     44            data = args
     45
     46        # data is a QuiverMutationType
     47        if type( data ) is QuiverMutationType_Irreducible:
     48            return data
     49        elif type( data ) is QuiverMutationType_Reducible:
     50            return data
     51
     52        # check that data is a tuple or list
     53        if type(data) is tuple and len( data ) > 0:
     54            pass
     55        elif type(data) is list and len( data ) > 0:
     56            data = tuple( data )
     57        else:
     58            _mutation_type_error( data )
     59
     60        # check for reducible types
     61        if all( type( data_component ) in [list,tuple,QuiverMutationType_Irreducible] for data_component in data ):
     62            if len( data ) == 1: return QuiverMutationType( data[0] )
     63            else:
     64                data = tuple( QuiverMutationType(comp) for comp in data )
     65                return QuiverMutationType_Reducible( *data )
     66
     67        # check for irreducible types
     68        if len(data) == 2: data = (data[0],data[1],None)
     69        elif len(data) == 3: pass
     70        else: _mutation_type_error(data)
     71
     72        if type(data[2]) == list: data = (data[0],data[1],tuple(data[2]))
     73        if type(data[1]) == list: data = (data[0],tuple(data[1]),data[2])
     74
     75        # mutation type casting
     76        if True:
     77            if data == ('D',2,None):
     78                return QuiverMutationType( ('A',1,None), ('A',1,None) )
     79            elif data == ('D',3,None):
     80                data = ('A',3,None)
     81            elif data == ('C',2,None):
     82                data = ('B',2,None)
     83            elif data == ('E',9,None):
     84                data = ('E',8,1)
     85            elif data[0] == 'GR' and data[2] == None and type(data[1]) == tuple and len(data[1]) == 2 and data[1][1] > data[1][0]:
     86                if min(data[1]) > max(data[1])/2 and max(data[1]) <> min(data[1])+1:
     87                    data = (data[0],(max(data[1])-min(data[1]),max(data[1])),data[2])
     88                if min(data[1]) == 2 and max(data[1]) > 3:
     89                    data = ('A',max(data[1])-3,None)
     90                elif data[1] == (3,6):
     91                    data = ('D',4,None)
     92                elif data[1] == (3,7):
     93                    data = ('E',6,None)
     94                elif data[1] == (3,8):
     95                    data = ('E',8,None)
     96                elif data[1] == (3,9):
     97                    data = ('E',8,[1,1])
     98                elif data[1] == (4,8):
     99                    data = ('E',7,[1,1])
     100            elif data == ('TR',1,None):
     101                data = ('A',1,None)
     102            elif data == ('TR',2,None):
     103                data = ('A',3,None)
     104            elif data == ('TR',3,None):
     105                data = ('D',6,None)
     106            elif data == ('TR',4,None):
     107                data = ('E',8,(1,1))
     108            # mutation type casting from Kac conventions
     109            elif data == ('A',1,1):
     110                data = ('A',(1,1),1)
     111            elif data[0] == 'B' and data[2] == 1:
     112                if data[1] == 2:
     113                    data = ('CC',2,1)
     114                elif data[1] > 2:
     115                    data = ('BD',data[1],1)
     116            elif data[0] == 'B' and data[2] == -1:
     117                if data[1] == 2:
     118                    data = ('BB',2,1)
     119                elif data[1] > 2:
     120                    data= ('CD',data[1],1)
     121            elif data[0] == 'C' and data[1] > 1 and data[2] == 1:
     122                data = ('CC',data[1],1)
     123            elif data[0] == 'C' and data[1] > 1 and data[2] == -1:
     124                data = ('BB',data[1],1)
     125            elif data == ('A',2,2):
     126                data = ('BC',1,1)
     127            elif data[0] == 'A' and data[1] in ZZ and data[1] > 1 and data[1]%2 == 0 and data[2] == 2:
     128                data = ('BC',data[1]/2,1)
     129            elif data[0] == 'A' and data[1] in ZZ and data[1] > 3 and data[1]%2 == 1 and data[2] == 2:
     130                data = ('CD',(data[1]+1)/2,1)
     131            # We think of ('A',3,2) as ('D',3,2)
     132            elif data == ('A',3,2):
     133                data = ('BB',2,1)
     134            elif data[0] == 'D' and data[1] in ZZ and data[1] > 2 and data[2] == 2:
     135                data = ('BB',data[1]-1,1)
     136            elif data == ('E',6,2):
     137                data = ('F',4,-1)
     138            elif data == ('D',4,3):
     139                data = ('G',2,-1)
     140            elif data[0] == 'T' and data[2] == None:
     141                data = (data[0],tuple(sorted(data[1])),data[2])
     142                r,p,q = data[1]
     143                if r == 1:
     144                    data = ('A',p+q-1,None)
     145                elif r == p == 2:
     146                    data = ('D',q+2,None)
     147                elif r == 2 and p == 3:
     148                    if q in (3,4,5): data = ('E',q+3,None)
     149                    elif q == 6: data = ('E',8,1)
     150                    else: data = ('E',q+3,None)
     151                elif r== 2 and p == q == 4:
     152                    data = ('E',7,1)
     153                elif r == p == q == 3:
     154                    data = ('E',6,1)
     155            elif data[0] == 'R2' and data[2] == None and all(data[1][i] in ZZ and data[1][i] > 0 for i in [0,1]):
     156                data = (data[0],tuple(sorted(data[1])),data[2])
     157                b,c = data[1]
     158                if data[1] == (1,1):
     159                    data = ('A',2,None)
     160                elif data[1] == (1,2):
     161                    data = ('B',2,None)
     162                elif data[1] == (1,3):
     163                    data = ('G',2,None)
     164                elif data[1] == (1,4):
     165                    data = ('BC',1,1)
     166                elif data[1] == (2,2):
     167                    data = ('A',(1,1),1)
     168
     169        # setting the parameters and returning the mutation type
     170        letter,rank,twist = data
     171        if type(letter) is not str:
     172            _mutation_type_error(data)
     173        if type(rank) == list:
     174            rank = tuple(rank)
     175        if type(twist) == list:
     176            twist = tuple(twist)
     177        return QuiverMutationType_Irreducible(letter,rank,twist)
     178
     179    def _repr_(self):
     180        """
     181        Returns the string representation of ``self``.
     182
     183        EXAMPLES::
     184
     185            sage: QuiverMutationType  # indirect doctest
     186            QuiverMutationType
     187        """
     188        return "QuiverMutationType"
     189
     190    def samples(self, finite=None, affine=None, elliptic=None, mutation_finite=None):
     191        """
     192        Returns a sample of the available quiver mutations types.
     193
     194        INPUT:
     195         - ``finite``, ``affine``, ``elliptic``, ``mutation_finite`` -- (default:None) if True or False, only these samples are returned.
     196
     197        EXAMPLES::
     198
     199            sage: QuiverMutationType.samples()
     200            [['A', 1], ['A', 5], ['B', 2], ['B', 5], ['C', 3],
     201             ['C', 5], [ ['A', 1], ['A', 1] ], ['D', 5], ['E', 6],
     202             ['E', 7], ['E', 8], ['F', 4], ['G', 2],
     203             ['A', [1, 1], 1], ['A', [4, 5], 1], ['D', 4, 1],
     204             ['BB', 5, 1], ['E', 6, [1, 1]], ['E', 7, [1, 1]],
     205             ['R2', [1, 5]], ['R2', [3, 5]], ['E', 10], ['BE', 5],
     206             ['GR', [3, 10]], ['T', [3, 3, 4]]]
     207
     208            sage: QuiverMutationType.samples(finite=True)
     209            [['A', 1], ['A', 5], ['B', 2], ['B', 5], ['C', 3],
     210             ['C', 5], [ ['A', 1], ['A', 1] ], ['D', 5], ['E', 6],
     211             ['E', 7], ['E', 8], ['F', 4], ['G', 2]]
     212
     213            sage: QuiverMutationType.samples(affine=True)
     214            [['A', [1, 1], 1], ['A', [4, 5], 1], ['D', 4, 1], ['BB', 5, 1]]
     215
     216            sage: QuiverMutationType.samples(elliptic=True)
     217            [['E', 6, [1, 1]], ['E', 7, [1, 1]]]
     218
     219            sage: QuiverMutationType.samples(mutation_finite=False)
     220            [['R2', [1, 5]], ['R2', [3, 5]], ['E', 10], ['BE', 5],
     221             ['GR', [3, 10]], ['T', [3, 3, 4]]]
     222        """
     223        result = self._samples()
     224        if finite is not None:
     225            result = [t for t in result if t.is_finite() == finite]
     226        if affine is not None:
     227            result = [t for t in result if t.is_affine() == affine]
     228        if elliptic is not None:
     229            result = [t for t in result if t.is_elliptic() == elliptic]
     230        if mutation_finite is not None:
     231            result = [t for t in result if t.is_mutation_finite() == mutation_finite]
     232        return result
     233
     234    @cached_method
     235    def _samples(self):
     236        """
     237        Returns a list of sample of available Cartan types.
     238
     239        EXAMPLES::
     240
     241            sage: X = QuiverMutationType._samples()
     242        """
     243        finite_types = \
     244            [QuiverMutationType(t) for t in [['A', 1], ['A', 5], ['B', 2], ['B', 5],
     245                                             ['C', 3], ['C', 5], ['D', 2], ['D', 5],
     246                                             ["E", 6], ["E", 7], ["E", 8], ["F", 4],
     247                                             ["G", 2]]]
     248        affine_types = \
     249            [QuiverMutationType(t) for t in [['A', [1,1], 1], ['A', [4,5], 1], ['D', 4, 1], ['BB', 5, 1]]]
     250        elliptic_types = \
     251            [QuiverMutationType(t) for t in [['E', 6, [1,1]], ['E', 7, [1,1]]]]
     252        mutation_finite_types = \
     253            [QuiverMutationType(t) for t in [['R2',(1,5)], ['R2',(3,5)]]]
     254        mutation_infinite_types = \
     255            [QuiverMutationType(t) for t in [['E',10], ['BE',5], ['GR',(3,10)], ['T',(3,3,4)]]]
     256
     257        return finite_types + affine_types + elliptic_types + mutation_finite_types + mutation_infinite_types
     258
     259QuiverMutationType = QuiverMutationTypeFactory()
     260QuiverMutationType.__doc__ = \
     261r"""
     262
     263*Quiver mutation types* can be seen as a slight generalization of *generalized Cartan types*.
     264
     265Background on generalized Cartan types can be found at
     266
     267        http://en.wikipedia.org/wiki/Generalized_Cartan_matrix
     268
     269For the compendium on the cluster algebra and quiver package in Sage see
     270
     271        http://arxiv.org/abs/1102.4844
     272
     273A `B`-matrix is a skew-symmetrizable `( n \times n )`-matrix `M`.
     274I.e., there exists an invertible diagonal matrix `D` such that `DM` is skew-symmetric.
     275`M` can be encoded as a *quiver* by having a directed edge from vertex `i` to vertex `j`
     276with label `(a,b)` if `a = M_{i,j} > 0` and `b = M_{j,i} < 0`.
     277We consider quivers up to *mutation equivalence*.
     278
     279To a quiver mutation type we can associate a *generalized Cartan type*
     280by sending `M` to the generalized Cartan matrix `C(M)` obtained by replacing all
     281positive entries by their negatives and adding `2`'s on the main diagonal.
     282
     283``QuiverMutationType`` constructs a quiver mutation type object. For more detail on the possible different types, please see the compendium.
     284
     285INPUT:
     286
     287The input consists either of a quiver mutation type, or of a ``letter`` (a string), a ``rank`` (one integer or a list/tuple of integers), and an optional ``twist`` (an integer or a list of integers).  There are several different naming conventions for quiver mutation types.
     288
     289- Finite type -- ``letter`` is a Dynkin type (A-G), and ``rank`` is the rank.
     290
     291- Affine type -- there is more than one convention for naming affine types.
     292    * Kac's notation: ``letter`` is a Dynkin type, ``rank`` is the rank of the associated finite Dynkin diagram, and ``twist`` is the twist, which could be 1, 2, or 3.  In the special case of affine type A, there is more than one quiver mutation type associated to the Cartan type.  In this case only, ``rank`` is a pair of integers (i,j), giving the number of edges pointing clockwise and the number of edges pointing counter-clockwise.  The total number of vertices is given by i+j in this case.
     293
     294    * Naive notation: ``letter`` is one of 'BB', 'BC', 'BD', 'CC', 'CD'.  The name specifies the two ends of the diagram, which are joined by a path.  The total number of vertices is given by ``rank +1`` (to match the indexing people expect because these are affine types).  In general, ``rank`` must be large enough for the picture to make sense, but we accept ``letter`` is ``BC`` and ``rank=1``.
     295
     296    * Macdonald notation: for the dual of an untwisted affine type (such as ['C', 6,1]), we accept a twist of -1 (i.e., ['C',6,-1]).
     297
     298- Elliptic type -- ``letter`` is a Dynkin type, ``rank`` is the rank of the finite Dynkin diagram, and ``twist`` is a tuple of two integers.  We follow Saito's notation.
     299
     300- Other shapes:
     301
     302    * Rank 2: ``letter`` is 'R2', and ``rank`` is a pair of integers specifying the label on the unique edge.
     303
     304    * Triangle: ``letter`` is ``TR``, and ``rank`` is the number of vertices along a side.
     305
     306    * T: This defines a quiver shaped like a T.  ``letter`` is 'T', and the ``rank`` is a triple, whose entries specify the number of vertices along each path from the branch point (counting the branch point).
     307
     308    * Grassmannian: This defines the cluster algebra (without coefficients) corresponding to the cluster algebra with coefficients which is the co-ordinate ring of a Grassmannian.  ``letter`` is 'GR'.  ``rank`` is a pair of integers (`k`, `n`) with 'k' < 'n' specifying the Grassmannian of `k`-planes in `n`-space.  This defines a quiver given by a (k-1) x (n-k-1) grid where each square is cyclically oriented.
     309
     310    * Exceptional mutation finite quivers: The two exceptional mutation finite quivers, found by Derksen-Owen, have ``letter`` as 'X' and ``rank`` 6 or 7, equal to the number of vertices.
     311
     312    * AE, BE, CE, DE: Quivers are built of one end which looks like type (affine A), B, C, or D, and the other end which looks like type E (i.e., it consists of two antennae, one of length one, and one of length two).  ``letter`` is 'AE', 'BE', 'CE', or 'DE', and ``rank`` is the total number of vertices.  Note that 'AE' is of a slightly different form and requires ``rank`` to be a pair of integers (i,j) just as in the case of affine type A.  See Exercise 4.3 in Kac's book Infinite Dimensional Lie Algebras for more details.
     313
     314    * Infinite type E: It is also possible to obtain infinite-type E quivers by specifying ``letter`` as 'E' and ``rank`` as the number of vertices.
     315
     316REFERENCES:
     317
     318- A good reference for finite and affine Dynkin diagrams, including Kac's notation, is the Wikipedia article on `Dynkin diagrams <http://en.wikipedia.org/wiki/Dynkin_diagram>`_.
     319
     320- A good reference for the skew-symmetrizable elliptic diagrams is "Cluster algebras of finite mutation type via unfolding" by A. Felikson, M. Shapiro, and P. Tumarkin, `arXiv:1006.4276v4 <http://arxiv.org/abs/1006.4276>`_.
     321
     322EXAMPLES:
     323
     324Finite types::
     325
     326    sage: QuiverMutationType('A',1)
     327    ['A', 1]
     328    sage: QuiverMutationType('A',5)
     329    ['A', 5]
     330
     331    sage: QuiverMutationType('B',2)
     332    ['B', 2]
     333    sage: QuiverMutationType('B',5)
     334    ['B', 5]
     335
     336    sage: QuiverMutationType('C',2)
     337    ['B', 2]
     338    sage: QuiverMutationType('C',5)
     339    ['C', 5]
     340
     341    sage: QuiverMutationType('D',2)
     342    [ ['A', 1], ['A', 1] ]
     343    sage: QuiverMutationType('D',3)
     344    ['A', 3]
     345    sage: QuiverMutationType('D',4)
     346    ['D', 4]
     347
     348    sage: QuiverMutationType('E',6)
     349    ['E', 6]
     350
     351    sage: QuiverMutationType('G',2)
     352    ['G', 2]
     353
     354Affine types::
     355
     356    sage: QuiverMutationType('A',(1,1),1)
     357    ['A', [1, 1], 1]
     358    sage: QuiverMutationType('A',(2,4),1)
     359    ['A', [2, 4], 1]
     360
     361    sage: QuiverMutationType('BB',2,1)
     362    ['BB', 2, 1]
     363    sage: QuiverMutationType('BB',4,1)
     364    ['BB', 4, 1]
     365
     366    sage: QuiverMutationType('CC',2,1)
     367    ['CC', 2, 1]
     368    sage: QuiverMutationType('CC',4,1)
     369    ['CC', 4, 1]
     370
     371    sage: QuiverMutationType('BC',1,1)
     372    ['BC', 1, 1]
     373    sage: QuiverMutationType('BC',5,1)
     374    ['BC', 5, 1]
     375
     376    sage: QuiverMutationType('BD',3,1)
     377    ['BD', 3, 1]
     378    sage: QuiverMutationType('BD',5,1)
     379    ['BD', 5, 1]
     380
     381    sage: QuiverMutationType('CD',3,1)
     382    ['CD', 3, 1]
     383    sage: QuiverMutationType('CD',5,1)
     384    ['CD', 5, 1]
     385
     386    sage: QuiverMutationType('D',4,1)
     387    ['D', 4, 1]
     388    sage: QuiverMutationType('D',6,1)
     389    ['D', 6, 1]
     390
     391    sage: QuiverMutationType('E',6,1)
     392    ['E', 6, 1]
     393    sage: QuiverMutationType('E',7,1)
     394    ['E', 7, 1]
     395    sage: QuiverMutationType('E',8,1)
     396    ['E', 8, 1]
     397
     398    sage: QuiverMutationType('F',4,1)
     399    ['F', 4, 1]
     400    sage: QuiverMutationType('F',4,-1)
     401    ['F', 4, -1]
     402
     403    sage: QuiverMutationType('G',2,1)
     404    ['G', 2, 1]
     405    sage: QuiverMutationType('G',2,-1)
     406    ['G', 2, -1]
     407    sage: QuiverMutationType('A',3,2) == QuiverMutationType('D',3,2)
     408    True
     409
     410Affine types using Kac's Notation::
     411
     412    sage: QuiverMutationType('A',1,1)
     413    ['A', [1, 1], 1]
     414    sage: QuiverMutationType('B',5,1)
     415    ['BD', 5, 1]
     416    sage: QuiverMutationType('C',5,1)
     417    ['CC', 5, 1]
     418    sage: QuiverMutationType('A',2,2)
     419    ['BC', 1, 1]
     420    sage: QuiverMutationType('A',7,2)
     421    ['CD', 4, 1]
     422    sage: QuiverMutationType('A',8,2)
     423    ['BC', 4, 1]
     424    sage: QuiverMutationType('D',6,2)
     425    ['BB', 5, 1]
     426    sage: QuiverMutationType('E',6,2)
     427    ['F', 4, -1]
     428    sage: QuiverMutationType('D',4,3)
     429    ['G', 2, -1]
     430
     431Elliptic types::
     432
     433    sage: QuiverMutationType('E',6,[1,1])
     434    ['E', 6, [1, 1]]
     435    sage: QuiverMutationType('F',4,[2,1])
     436    ['F', 4, [1, 2]]
     437    sage: QuiverMutationType('G',2,[3,3])
     438    ['G', 2, [3, 3]]
     439
     440Mutation finite types:
     441
     442    rank 2 cases::
     443
     444        sage: QuiverMutationType('R2',(1,1))
     445        ['A', 2]
     446        sage: QuiverMutationType('R2',(1,2))
     447        ['B', 2]
     448        sage: QuiverMutationType('R2',(1,3))
     449        ['G', 2]
     450        sage: QuiverMutationType('R2',(1,4))
     451        ['BC', 1, 1]
     452        sage: QuiverMutationType('R2',(1,5))
     453        ['R2', [1, 5]]
     454        sage: QuiverMutationType('R2',(2,2))
     455        ['A', [1, 1], 1]
     456        sage: QuiverMutationType('R2',(3,5))
     457        ['R2', [3, 5]]
     458
     459    Exceptional Derksen-Owen quivers::
     460
     461        sage: QuiverMutationType('X',6)
     462        ['X', 6]
     463
     464
     465(Mainly) mutation infinite types:
     466
     467    Infinite type E::
     468
     469        sage: QuiverMutationType('E',9)
     470        ['E', 8, 1]
     471        sage: QuiverMutationType('E',10)
     472        ['E', 10]
     473        sage: QuiverMutationType('E',12)
     474        ['E', 12]
     475
     476        sage: QuiverMutationType('AE',(2,3))
     477        ['AE', [2, 3]]
     478        sage: QuiverMutationType('BE',5)
     479        ['BE', 5]
     480        sage: QuiverMutationType('CE',5)
     481        ['CE', 5]
     482        sage: QuiverMutationType('DE',6)
     483        ['DE', 6]
     484
     485    Grassmannian types::
     486
     487        sage: QuiverMutationType('GR',(2,4))
     488        ['A', 1]
     489        sage: QuiverMutationType('GR',(2,6))
     490        ['A', 3]
     491        sage: QuiverMutationType('GR',(3,6))
     492        ['D', 4]
     493        sage: QuiverMutationType('GR',(3,7))
     494        ['E', 6]
     495        sage: QuiverMutationType('GR',(3,8))
     496        ['E', 8]
     497        sage: QuiverMutationType('GR',(3,10))
     498        ['GR', [3, 10]]
     499
     500    Triangular types::
     501
     502        sage: QuiverMutationType('TR',2)
     503        ['A', 3]
     504        sage: QuiverMutationType('TR',3)
     505        ['D', 6]
     506        sage: QuiverMutationType('TR',4)
     507        ['E', 8, [1, 1]]
     508        sage: QuiverMutationType('TR',5)
     509        ['TR', 5]
     510
     511    T types::
     512
     513        sage: QuiverMutationType('T',(1,1,1))
     514        ['A', 1]
     515        sage: QuiverMutationType('T',(1,1,4))
     516        ['A', 4]
     517        sage: QuiverMutationType('T',(1,4,4))
     518        ['A', 7]
     519        sage: QuiverMutationType('T',(2,2,2))
     520        ['D', 4]
     521        sage: QuiverMutationType('T',(2,2,4))
     522        ['D', 6]
     523        sage: QuiverMutationType('T',(2,3,3))
     524        ['E', 6]
     525        sage: QuiverMutationType('T',(2,3,4))
     526        ['E', 7]
     527        sage: QuiverMutationType('T',(2,3,5))
     528        ['E', 8]
     529        sage: QuiverMutationType('T',(2,3,6))
     530        ['E', 8, 1]
     531        sage: QuiverMutationType('T',(2,3,7))
     532        ['E', 10]
     533        sage: QuiverMutationType('T',(3,3,3))
     534        ['E', 6, 1]
     535        sage: QuiverMutationType('T',(3,3,4))
     536        ['T', [3, 3, 4]]
     537
     538Reducible types::
     539
     540    sage: QuiverMutationType(['A',3],['B',4])
     541    [ ['A', 3], ['B', 4] ]
     542"""
     543
     544class QuiverMutationType_abstract(UniqueRepresentation,SageObject):
     545    def __eq__(self,other):
     546        """
     547        Returns True iff self and other represent the same quiver mutation type.
     548
     549        EXAMPLES::
     550
     551            sage: mut_type1 = QuiverMutationType('A',5)
     552            sage: mut_type2 = QuiverMutationType('A',5)
     553            sage: mut_type3 = QuiverMutationType('A',6)
     554            sage: mut_type1.__eq__( mut_type2 )
     555            True
     556            sage: mut_type1.__eq__( mut_type3 )
     557            False
     558        """
     559        return self is other
     560
     561    def _repr_(self):
     562        """
     563        Returns the string representation of self.
     564
     565        EXAMPLES::
     566
     567            sage: QuiverMutationType(['A',2]) # indirect doctest
     568            ['A', 2]
     569        """
     570        return self._description
     571
     572    def letter(self):
     573        """
     574        Returns the classification letter of self.
     575
     576        EXAMPLES::
     577
     578            sage: mut_type = QuiverMutationType( ['A',5] ); mut_type
     579            ['A', 5]
     580            sage: mut_type.letter()
     581            'A'
     582
     583            sage: mut_type = QuiverMutationType( ['BC',5,1] ); mut_type
     584            ['BC', 5, 1]
     585            sage: mut_type.letter()
     586            'BC'
     587
     588            sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
     589            [ ['A', 3], ['B', 3] ]
     590            sage: mut_type.letter()
     591            'A x B'
     592
     593            sage: mut_type = QuiverMutationType(['A',3],['B',3],['X',6]); mut_type
     594            [ ['A', 3], ['B', 3], ['X', 6] ]
     595            sage: mut_type.letter()
     596            'A x B x X'
     597        """
     598        return self._letter
     599
     600    def rank(self):
     601        """
     602        Returns the rank, i.e., the number of vertices in the standard quiver of self.
     603
     604        EXAMPLES::
     605
     606            sage: mut_type = QuiverMutationType( ['A',5] ); mut_type
     607            ['A', 5]
     608            sage: mut_type.rank()
     609            5
     610
     611            sage: mut_type = QuiverMutationType( ['A',[4,5],1] ); mut_type
     612            ['A', [4, 5], 1]
     613            sage: mut_type.rank()
     614            9
     615
     616            sage: mut_type = QuiverMutationType( ['BC',5,1] ); mut_type
     617            ['BC', 5, 1]
     618            sage: mut_type.rank()
     619            6
     620
     621            sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
     622            [ ['A', 3], ['B', 3] ]
     623            sage: mut_type.rank()
     624            6
     625
     626            sage: mut_type = QuiverMutationType(['A',3],['B',3],['X',6]); mut_type
     627            [ ['A', 3], ['B', 3], ['X', 6] ]
     628            sage: mut_type.rank()
     629            12
     630        """
     631        return self._rank
     632
     633    @cached_method
     634    def b_matrix(self):
     635        """
     636        Returns the B-matrix of the standard quiver of self.  The conventions
     637        for B-matrices agree with Fomin-Zelevinsky (up to a reordering of
     638        the simple roots).
     639
     640        EXAMPLES::
     641
     642            sage: mut_type = QuiverMutationType( ['A',5] ); mut_type
     643            ['A', 5]
     644            sage: mut_type.b_matrix()
     645            [ 0  1  0  0  0]
     646            [-1  0 -1  0  0]
     647            [ 0  1  0  1  0]
     648            [ 0  0 -1  0 -1]
     649            [ 0  0  0  1  0]
     650
     651            sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
     652            [ ['A', 3], ['B', 3] ]
     653            sage: mut_type.b_matrix()
     654            [ 0  1  0  0  0  0]
     655            [-1  0 -1  0  0  0]
     656            [ 0  1  0  0  0  0]
     657            [ 0  0  0  0  1  0]
     658            [ 0  0  0 -1  0 -1]
     659            [ 0  0  0  0  2  0]
     660        """
     661        return _edge_list_to_matrix( self._digraph.edges(), self._rank, 0 )
     662
     663    @cached_method
     664    def cartan_matrix(self):
     665        """
     666        Returns the Cartan matrix of self.
     667
     668        Note that (up to a reordering of the simple roots) the convention for
     669        the definition of Cartan matrix, used here and elsewhere in Sage,
     670        agrees with the conventions of Kac, Fulton-Harris, and
     671        Fomin-Zelevinsky, but disagrees with the convention of Bourbaki.
     672        The `(i,j)` entry is `2(\\alpha_i,\\alpha_j)/(\\alpha_i,\\alpha_i)`.
     673
     674        EXAMPLES::
     675
     676            sage: mut_type = QuiverMutationType(['A',5]); mut_type
     677            ['A', 5]
     678            sage: mut_type.cartan_matrix()
     679            [ 2 -1  0  0  0]
     680            [-1  2 -1  0  0]
     681            [ 0 -1  2 -1  0]
     682            [ 0  0 -1  2 -1]
     683            [ 0  0  0 -1  2]
     684
     685            sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
     686            [ ['A', 3], ['B', 3] ]
     687            sage: mut_type.cartan_matrix()
     688            [ 2 -1  0  0  0  0]
     689            [-1  2 -1  0  0  0]
     690            [ 0 -1  2  0  0  0]
     691            [ 0  0  0  2 -1  0]
     692            [ 0  0  0 -1  2 -1]
     693            [ 0  0  0  0 -2  2]
     694        """
     695        # as soon as CartanMatrix is implemented we should use it here:
     696        # from sage.combinat.root_system.cartan_matrix import CartanMatrix
     697        cmat = copy(self.b_matrix())
     698        for i,j in cmat.nonzero_positions():
     699            a = cmat[i,j]
     700            if a > 0: cmat[i,j] = -a
     701        for i in range(self._rank):
     702            cmat[i,i] = 2
     703        # return CartanMatrix(cmat)
     704        return cmat
     705
     706    def is_irreducible(self):
     707        """
     708        Returns True if self is irreducible.
     709
     710        EXAMPLES::
     711
     712            sage: mt = QuiverMutationType(['A',2])
     713            sage: mt.is_irreducible()
     714            True
     715        """
     716        return self._info['irreducible']
     717
     718    def is_mutation_finite(self):
     719        """
     720        Returns True if self is of finite mutation type (i.e. its mutation
     721        class has only finitely many different B-matrices).
     722
     723        EXAMPLES::
     724
     725            sage: mt = QuiverMutationType(['D',5,1])
     726            sage: mt.is_mutation_finite()
     727            True
     728        """
     729        return self._info['mutation_finite']
     730
     731    def is_simply_laced(self):
     732        """
     733        Returns True if self is simply laced (i.e., the only arrows that appear         in the quiver of self are single unlabelled arrows).
     734
     735        EXAMPLES::
     736
     737            sage: mt = QuiverMutationType(['A',2])
     738            sage: mt.is_simply_laced()
     739            True
     740
     741            sage: mt = QuiverMutationType(['B',2])
     742            sage: mt.is_simply_laced()
     743            False
     744
     745            sage: mt = QuiverMutationType(['A',(1,1),1])
     746            sage: mt.is_simply_laced()
     747            False
     748        """
     749        return self._info['simply_laced']
     750
     751    def is_skew_symmetric(self):
     752        """
     753        Returns True if the B-matrix of self is skew-symmetric.
     754
     755        EXAMPLES::
     756
     757            sage: mt = QuiverMutationType(['A',2])
     758            sage: mt.is_skew_symmetric()
     759            True
     760
     761            sage: mt = QuiverMutationType(['B',2])
     762            sage: mt.is_skew_symmetric()
     763            False
     764
     765            sage: mt = QuiverMutationType(['A',(1,1),1])
     766            sage: mt.is_skew_symmetric()
     767            True
     768        """
     769        return self._info['skew_symmetric']
     770
     771    def is_finite(self):
     772        """
     773        Returns True if self is of finite type (i.e., the cluster algebra
     774        associated to self has only a finite number of cluster variables).
     775
     776        EXAMPLES::
     777
     778            sage: mt = QuiverMutationType(['A',2])
     779            sage: mt.is_finite()
     780            True
     781
     782            sage: mt = QuiverMutationType(['A',[4,2],1])
     783            sage: mt.is_finite()
     784            False
     785        """
     786        return self._info['finite']
     787
     788    def is_affine(self):
     789        """
     790        Returns True if self is of affine type.
     791
     792        EXAMPLES::
     793
     794            sage: mt = QuiverMutationType(['A',2])
     795            sage: mt.is_affine()
     796            False
     797
     798            sage: mt = QuiverMutationType(['A',[4,2],1])
     799            sage: mt.is_affine()
     800            True
     801        """
     802        if self.is_irreducible():
     803            return self._info['affine']
     804        else:
     805            return False
     806
     807    def is_elliptic(self):
     808        """
     809        Returns True if self is of elliptic type.
     810
     811        EXAMPLES::
     812
     813            sage: mt = QuiverMutationType(['A',2])
     814            sage: mt.is_elliptic()
     815            False
     816
     817            sage: mt = QuiverMutationType(['E',6,[1,1]])
     818            sage: mt.is_elliptic()
     819            True
     820        """
     821        if self.is_irreducible():
     822            return self._info['elliptic']
     823        else:
     824            return False
     825
     826    def properties(self):
     827        """
     828        Prints a scheme of all properties of self.
     829
     830        Most properties have natural definitions for either irreducible or
     831        reducible types.  ``affine`` and ``elliptic`` are only defined for
     832        irreducible types.
     833
     834        EXAMPLES::
     835
     836            sage: mut_type = QuiverMutationType(['A',3]); mut_type
     837            ['A', 3]
     838            sage: mut_type.properties()
     839            ['A', 3] has rank 3 and the following properties:
     840                - irreducible:       True
     841                - mutation finite:   True
     842                - simply-laced:      True
     843                - skew-symmetric:    True
     844                - finite:            True
     845                - affine:            False
     846                - elliptic:          False
     847
     848            sage: mut_type = QuiverMutationType(['B',3]); mut_type
     849            ['B', 3]
     850            sage: mut_type.properties()
     851            ['B', 3] has rank 3 and the following properties:
     852                - irreducible:       True
     853                - mutation finite:   True
     854                - simply-laced:      False
     855                - skew-symmetric:    False
     856                - finite:            True
     857                - affine:            False
     858                - elliptic:          False
     859
     860            sage: mut_type = QuiverMutationType(['B',3,1]); mut_type
     861            ['BD', 3, 1]
     862            sage: mut_type.properties()
     863            ['BD', 3, 1] has rank 4 and the following properties:
     864                - irreducible:       True
     865                - mutation finite:   True
     866                - simply-laced:      False
     867                - skew-symmetric:    False
     868                - finite:            False
     869                - affine:            True
     870                - elliptic:          False
     871
     872            sage: mut_type = QuiverMutationType(['E',6,[1,1]]); mut_type
     873            ['E', 6, [1, 1]]
     874            sage: mut_type.properties()
     875            ['E', 6, [1, 1]] has rank 8 and the following properties:
     876                - irreducible:       True
     877                - mutation finite:   True
     878                - simply-laced:      False
     879                - skew-symmetric:    True
     880                - finite:            False
     881                - affine:            False
     882                - elliptic:          True
     883
     884            sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
     885            [ ['A', 3], ['B', 3] ]
     886            sage: mut_type.properties()
     887            [ ['A', 3], ['B', 3] ] has rank 6 and the following properties:
     888                - irreducible:       False
     889                - mutation finite:   True
     890                - simply-laced:      False
     891                - skew-symmetric:    False
     892                - finite:            True
     893
     894            sage: mut_type = QuiverMutationType('GR',[4,9]); mut_type
     895            ['GR', [4, 9]]
     896            sage: mut_type.properties()
     897            ['GR', [4, 9]] has rank 12 and the following properties:
     898                - irreducible:       True
     899                - mutation finite:   False
     900                - simply-laced:      True
     901                - skew-symmetric:    True
     902                - finite:            False
     903                - affine:            False
     904                - elliptic:          False
     905        """
     906        print self, 'has rank', self.rank(), 'and the following properties:'
     907        print '\t- irreducible:      ', self.is_irreducible()
     908        print '\t- mutation finite:  ', self.is_mutation_finite()
     909        print '\t- simply-laced:     ', self.is_simply_laced()
     910        print '\t- skew-symmetric:   ', self.is_skew_symmetric()
     911        print '\t- finite:           ', self.is_finite()
     912        if self.is_irreducible():
     913            print '\t- affine:           ', self.is_affine()
     914            print '\t- elliptic:         ', self.is_elliptic()
     915
     916class QuiverMutationType_Irreducible(QuiverMutationType_abstract,UniqueRepresentation,SageObject):
     917    """
     918    The mutation type for a cluster algebra or a quiver. Should not be called directly, but through QuiverMutationType.
     919    """
     920    def __init__(self, letter, rank, twist=None):
     921        """
     922        Should not be called directly but through QuiverMutationType.
     923
     924        INPUT:
     925
     926        - ``letter`` -- the letter of the mutation type
     927        - ``rank`` -- the rank of the mutation type
     928        - ``twist`` -- the twist of the mutation type
     929
     930        EXAMPLES::
     931
     932            sage: QuiverMutationType('A',5)
     933            ['A', 5]
     934
     935            sage: QuiverMutationType('A',[4,5],1)
     936            ['A', [4, 5], 1]
     937
     938            sage: QuiverMutationType('BB',5,1)
     939            ['BB', 5, 1]
     940
     941            sage: QuiverMutationType('X',6)
     942            ['X', 6]
     943        """
     944        # _rank and _bi_rank are initialized
     945        self._rank = None
     946        self._bi_rank = None
     947
     948        # _graph and _digraph are initalized
     949        self._graph = Graph()
     950        self._digraph = DiGraph()
     951
     952        # _info is initialized
     953        self._info = {}
     954        self._info['irreducible'] = True
     955        self._info['mutation_finite'] = False
     956        self._info['simply_laced'] = False
     957        self._info['skew_symmetric'] = False
     958        self._info['finite'] = False
     959        self._info['affine'] = False
     960        self._info['elliptic'] = False
     961        self._info['irreducible_components'] = False
     962
     963        if type(rank) is tuple:
     964            rank = list(rank)
     965        if type(twist) is tuple:
     966            twist = list(twist)
     967
     968        # _letter/twist is the input letter/twist
     969        self._letter = letter
     970        self._twist = twist
     971
     972        data = [letter,rank,twist]
     973
     974        # type A (finite and affine)
     975        if letter == 'A':
     976            if twist is None and rank in ZZ and rank > 0:
     977                self._rank = rank
     978                self._info['mutation_finite'] = True
     979                self._info['simply_laced'] = True
     980                self._info['skew_symmetric'] = True
     981                self._info['finite'] = True
     982            elif twist==1 and type(rank) is list and len(rank) == 2 and all( rank[i] in ZZ and rank[i] > 0 for i in [0,1] ):
     983                if type( rank ) == tuple:
     984                    rank = list( rank )
     985                    data[1] = rank
     986                rank = sorted(rank)
     987                self._bi_rank = rank
     988                self._rank = sum( self._bi_rank )
     989                self._info['mutation_finite'] = True
     990                if self._rank > 2: self._info['simply_laced'] = True
     991                self._info['skew_symmetric'] = True
     992                self._info['affine'] = True
     993            else:
     994                _mutation_type_error( data )
     995            # type ['A',1] needs to be treated on itself (as there is no edge)
     996            if twist is None and self._rank == 1:
     997                self._graph.add_vertex( 0 )
     998            # type ['A',[1,1],1] needs to be treated on itself as well (as there is a double edge)
     999            elif twist == 1 and self._bi_rank[0] == 1 and self._bi_rank[1] == 1:
     1000                self._graph.add_edge( 0,1,2 )
     1001            else:
     1002                for i in range( self._rank - 1 ):
     1003                    self._graph.add_edge( i, i+1, 1 )
     1004                if twist == 1:
     1005                    self._digraph.add_edge( self._rank - 1, 0, 1 )
     1006                    for i in range( self._rank - 1 ):
     1007                        if i < ( 2 * self._bi_rank[0] ) and i%2 == 0:
     1008                            self._digraph.add_edge( i+1, i, 1 )
     1009                        else:
     1010                            self._digraph.add_edge( i, i+1, 1 )
     1011
     1012        # type B (finite)
     1013        elif letter == 'B':
     1014            if twist is None and rank in ZZ and rank > 1:
     1015                self._rank = rank
     1016                self._info['mutation_finite'] = True
     1017                self._info['finite'] = True
     1018            else:
     1019                _mutation_type_error( data )
     1020            for i in range( rank - 2 ):
     1021                self._graph.add_edge( i, i+1, 1 )
     1022            if (rank % 2 == 0):
     1023                self._graph.add_edge( rank-2, rank-1, (1,-2) )
     1024            else:
     1025                self._graph.add_edge( rank-2, rank-1, (2,-1) )
     1026
     1027        # type C (finite)
     1028        elif letter == 'C':
     1029            if twist is None and rank in ZZ and rank > 1:
     1030                self._rank = rank
     1031                self._info['mutation_finite'] = True
     1032                self._info['finite'] = True
     1033            else:
     1034                _mutation_type_error( data )
     1035            for i in range( rank - 2 ):
     1036                self._graph.add_edge( i, i+1, 1 )
     1037            if (rank % 2 == 0):
     1038                self._graph.add_edge( rank-2, rank-1, (2,-1) )
     1039            else:
     1040                self._graph.add_edge( rank-2, rank-1, (1,-2) )
     1041
     1042        # type BB (affine)
     1043        elif letter == 'BB':
     1044            if twist == 1 and rank in ZZ and rank > 1:
     1045                self._rank = rank + 1
     1046                self._info['mutation_finite'] = True
     1047                self._info['affine'] = True
     1048            else:
     1049                _mutation_type_error( data )
     1050            for i in range( rank - 2 ):
     1051                self._graph.add_edge( i, i+1, 1 )
     1052            if rank % 2 == 0:
     1053                self._graph.add_edge( rank-2, rank-1, (1,-2) )
     1054            else:
     1055                self._graph.add_edge( rank-2, rank-1, (2,-1) )
     1056            self._graph.add_edge( rank, 0 , (1,-2) )
     1057
     1058        # type CC (affine)
     1059        elif letter == 'CC':
     1060            if twist == 1 and rank in ZZ and rank > 1:
     1061                self._rank = rank + 1
     1062                self._info['mutation_finite'] = True
     1063                self._info['affine'] = True
     1064            else:
     1065                _mutation_type_error( data )
     1066            for i in range( rank - 2 ):
     1067                self._graph.add_edge( i, i+1, 1 )
     1068            if rank % 2 == 0:
     1069                self._graph.add_edge( rank-2, rank-1, (2,-1) )
     1070            else:
     1071                self._graph.add_edge( rank-2, rank-1, (1,-2) )
     1072            self._graph.add_edge( rank, 0 , (2,-1) )
     1073
     1074        # type BC (affine)
     1075        elif letter == 'BC':
     1076            if twist == 1 and rank in ZZ and rank >= 1:
     1077                self._rank = rank + 1
     1078                self._info['mutation_finite'] = True
     1079                self._info['affine'] = True
     1080            else:
     1081                _mutation_type_error( data )
     1082            if rank == 1:
     1083                self._graph.add_edge( 0,1,(1,-4) )
     1084            else:
     1085                for i in range( rank - 2 ):
     1086                    self._graph.add_edge( i, i+1, 1 )
     1087                if (rank % 2 == 0):
     1088                    self._graph.add_edge( rank-2, rank-1, (2,-1) )
     1089                else:
     1090                    self._graph.add_edge( rank-2, rank-1, (1,-2) )
     1091                if twist == 1:
     1092                    self._graph.add_edge( rank, 0 , (1,-2) )
     1093
     1094        # type BD (affine)
     1095        elif letter == 'BD':
     1096            if twist == 1 and rank in ZZ and rank > 2:
     1097                self._rank = rank + 1
     1098                self._info['mutation_finite'] = True
     1099                self._info['affine'] = True
     1100            else:
     1101                _mutation_type_error( data )
     1102            for i in range( rank - 2 ):
     1103                self._graph.add_edge( i, i+1, 1 )
     1104            if (rank % 2 == 0):
     1105                self._graph.add_edge( rank-2, rank-1, (1,-2) )
     1106            else:
     1107                self._graph.add_edge( rank-2, rank-1, (2,-1) )
     1108            if twist == 1:
     1109                self._graph.add_edge( rank, 1 , 1 )
     1110
     1111        # type CD (affine)
     1112        elif letter == 'CD':
     1113            if twist == 1 and rank in ZZ and rank > 2:
     1114                self._rank = rank + 1
     1115                self._info['mutation_finite'] = True
     1116                self._info['affine'] = True
     1117            else:
     1118                _mutation_type_error( data )
     1119            for i in range( rank - 2 ):
     1120                self._graph.add_edge( i, i+1, 1 )
     1121            if (rank % 2 == 0):
     1122                self._graph.add_edge( rank-2, rank-1, (2,-1) )
     1123            else:
     1124                self._graph.add_edge( rank-2, rank-1, (1,-2) )
     1125            if twist == 1:
     1126                self._graph.add_edge( rank, 1 , 1 )
     1127
     1128        # type D (finite and affine)
     1129        elif letter == 'D':
     1130            if rank in ZZ and rank > 3 and twist is None:
     1131                self._rank = rank
     1132                self._info['mutation_finite'] = True
     1133                self._info['simply_laced'] = True
     1134                self._info['skew_symmetric'] = True
     1135                self._info['finite'] = True
     1136            elif twist == 1 and rank in ZZ and rank > 3:
     1137                self._rank = rank + 1
     1138                self._info['mutation_finite'] = True
     1139                self._info['simply_laced'] = True
     1140                self._info['skew_symmetric'] = True
     1141                self._info['affine'] = True
     1142            else:
     1143                _mutation_type_error( data )
     1144            for i in range( rank - 2 ):
     1145                self._graph.add_edge( i, i+1, 1 )
     1146
     1147            self._graph.add_edge( rank-3, rank-1, 1 )
     1148            if twist is not None:
     1149                self._graph.add_edge( rank, 1 ,1 )
     1150
     1151        # type E (finite, affine and elliptic)
     1152        elif letter == 'E':
     1153            if rank in [6,7,8] and twist is None:
     1154                self._rank = rank
     1155                self._info['mutation_finite'] = True
     1156                self._info['simply_laced'] = True
     1157                self._info['skew_symmetric'] = True
     1158                self._info['finite'] = True
     1159                if rank == 6:
     1160                    self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(2,5) ] )
     1161                elif rank == 7:
     1162                    self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(4,5),(2,6) ] )
     1163                elif rank == 8:
     1164                    self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(2,7) ] )
     1165            elif rank in [6,7,8] and twist == 1:
     1166                self._rank = rank + 1
     1167                self._info['mutation_finite'] = True
     1168                self._info['simply_laced'] = True
     1169                self._info['skew_symmetric'] = True
     1170                self._info['affine'] = True
     1171                if rank == 6:
     1172                    self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(2,5),(5,6) ] )
     1173                elif rank == 7:
     1174                    self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(3,7) ] )
     1175                elif rank == 8:
     1176                    self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(2,8) ] )
     1177            elif rank in [6,7,8] and twist == [1,1]:
     1178                self._rank = rank + 2
     1179                self._info['mutation_finite'] = True
     1180                self._info['skew_symmetric'] = True
     1181                self._info['elliptic'] = True
     1182                if rank == 6:
     1183                    self._digraph.add_edges( [ (0,1,1),(1,2,1),(3,2,1),(3,4,1),(5,6,1),(6,7,1),(5,1,1),(2,5,2),(5,3,1),(6,2,1) ] )
     1184                elif rank == 7:
     1185                    self._digraph.add_edges( [ (1,0,1),(1,2,1),(2,3,1),(4,3,1),(4,5,1),(6,5,1),(7,8,1),(3,7,2),(7,2,1),(7,4,1),(8,3,1) ] )
     1186                elif rank == 8:
     1187                    self._digraph.add_edges( [ (0,1,1),(1,9,1),(3,9,1),(3,4,1),(2,8,1),(2,1,1),(9,2,2),(2,3,1),(8,9,1),(5,4,1),(5,6,1),(7,6,1) ] )
     1188            # type E (mutation infinite)
     1189            elif rank > 9 and twist == None:
     1190                self._info['simply_laced'] = True
     1191                self._info['skew_symmetric'] = True
     1192                self._rank = rank
     1193                for i in range(rank-2):
     1194                    self._graph.add_edge( i, i+1, 1 )
     1195                self._graph.add_edge( 2, rank-1 )
     1196            else:
     1197                _mutation_type_error(data)
     1198
     1199        # type AE (mutation infinite)
     1200        elif letter == 'AE':
     1201            if type(rank) is list and len(rank) == 2 and all( rank[i] in ZZ and rank[i] > 0 for i in [0,1] ) and twist == None:
     1202                if type( rank ) == tuple:
     1203                    rank = list( rank )
     1204                    data[1] = rank
     1205                rank = sorted(rank)
     1206                self._bi_rank = rank
     1207                self._rank = sum( self._bi_rank ) + 1
     1208                if self._rank > 3: self._info['simply_laced'] = True
     1209                self._info['skew_symmetric'] = True
     1210                if self._bi_rank == [1,1]:
     1211                    self._graph.add_edges( [(0,1,2),(1,2)] )
     1212                else:
     1213                    self._digraph.add_edge( self._rank - 2, 0 )
     1214                    for i in xrange(self._rank-2):
     1215                        if i < ( 2 * self._bi_rank[0] ) and i%2 == 0:
     1216                            self._digraph.add_edge(i+1,i)
     1217                        else:
     1218                            self._digraph.add_edge(i,i+1)
     1219                    self._digraph.add_edge(self._rank-2,self._rank-1)
     1220            else:
     1221                _mutation_type_error( data )
     1222
     1223
     1224
     1225        # type BE (mutation infinite)
     1226        elif letter == 'BE':
     1227            if rank >4 and twist == None:
     1228                self._rank = rank
     1229                for i in range(rank-3):
     1230                    self._graph.add_edge( i, i+1 )
     1231                self._graph.add_edge( 2, rank-1 )
     1232                if rank%2 == 0:
     1233                    self._graph.add_edge( rank-3,rank-2,(2,-1) )
     1234                else:
     1235                    self._graph.add_edge( rank-3,rank-2,(1,-2) )
     1236            else:
     1237                _mutation_type_error( data )
     1238
     1239        # type CE (mutation infinite)
     1240        elif letter == 'CE':
     1241            if rank >4 and twist == None:
     1242                self._rank = rank
     1243                for i in range(rank-3):
     1244                    self._graph.add_edge( i, i+1 )
     1245                self._graph.add_edge( 2, rank-1 )
     1246                if rank%2 == 0:
     1247                    self._graph.add_edge( rank-3,rank-2,(1,-2) )
     1248                else:
     1249                    self._graph.add_edge( rank-3,rank-2,(2,-1) )
     1250            else:
     1251                _mutation_type_error( data )
     1252
     1253        # type DE (mutation infinite)
     1254        elif letter == 'DE':
     1255            if rank >5 and twist == None:
     1256                self._rank = rank
     1257                self._info['simply_laced'] = True
     1258                self._info['skew_symmetric'] = True
     1259                for i in range(rank-3):
     1260                    self._graph.add_edge( i, i+1 )
     1261                self._graph.add_edge( 2, rank-2 )
     1262                self._graph.add_edge( rank-4, rank-1 )
     1263            else:
     1264                _mutation_type_error( data )
     1265
     1266        # type F (finite, affine, and elliptic)
     1267        elif letter == 'F':
     1268            if rank == 4 and twist is None:
     1269                self._rank = rank
     1270                self._info['mutation_finite'] = True
     1271                self._info['finite'] = True
     1272                self._graph.add_edges( [ (0,1),(1,2,(2,-1)),(2,3) ] )
     1273            elif rank == 4 and twist == 1:
     1274                self._rank = rank + 1
     1275                self._info['mutation_finite'] = True
     1276                self._info['affine'] = True
     1277                self._graph.add_edges( [ (0,1), (1,2),(2,3,(1,-2)),(3,4) ] )
     1278            elif rank == 4 and twist == -1:
     1279                self._rank = rank + 1
     1280                self._info['mutation_finite'] = True
     1281                self._info['affine'] = True
     1282                self._graph.add_edges( [ (0,1), (1,2),(2,3,(2,-1)),(3,4) ] )
     1283            elif rank == 4 and (twist == [1,2] or twist == [2,1]):
     1284                self._rank = rank + 2
     1285                twist = [1,2]
     1286                self._info['mutation_finite'] = True
     1287                self._info['elliptic'] = True
     1288                self._digraph.add_edges( [ (0,1), (1,2), (2,3,(2,-1)), (4,2,(1,-2)), (3,4,2), (4,5), (5,3) ])
     1289            elif rank == 4 and twist == [2,2]:
     1290                self._rank = rank + 2
     1291                self._info['mutation_finite'] = True
     1292                self._info['elliptic'] = True
     1293                self._digraph.add_edges( [ (0,1), (1,2), (3,1), (2,3,2), (4,2,(2,-1)), (3,4,(1,-2)), (5,4) ] )
     1294            elif rank == 4 and twist == [1,1]:
     1295                self._rank = rank + 2
     1296                self._info['mutation_finite'] = True
     1297                self._info['elliptic'] = True
     1298                self._digraph.add_edges( [ (0,1), (1,2), (3,1), (2,3,2), (4,2,(1,-2)), (3,4,(2,-1)), (5,4) ] )
     1299            else:
     1300                _mutation_type_error( data )
     1301
     1302        # type G (finite, affine, and elliptic)
     1303        elif letter == 'G':
     1304            if rank == 2 and twist is None:
     1305                self._rank = rank
     1306                self._info['mutation_finite'] = True
     1307                self._info['finite'] = True
     1308                self._graph.add_edges( [ (0,1,(1,-3)) ] )
     1309            elif rank == 2 and twist == -1:
     1310                self._rank = rank + 1
     1311                self._info['mutation_finite'] = True
     1312                self._info['affine'] = True
     1313                self._graph.add_edges( [ (0,1),(1,2,(1,-3)) ] )
     1314            elif rank == 2 and twist == 1:
     1315                self._rank = rank + 1
     1316                self._info['mutation_finite'] = True
     1317                self._info['affine'] = True
     1318                self._graph.add_edges( [ (0,1),(1,2,(3,-1)) ] )
     1319            elif rank == 2 and (twist == [1,3] or twist == [3,1]):
     1320                self._rank = rank + 2
     1321                twist = [1,3]
     1322                self._info['mutation_finite'] = True
     1323                self._info['elliptic'] = True
     1324                self._digraph.add_edges( [ (0,1), (1,2,(3,-1)),
     1325                                           (3,1,(1,-3)), (2,3,2)] )
     1326            elif rank == 2 and twist == [3,3]:
     1327                self._rank = rank + 2
     1328                self._info['mutation_finite'] = True
     1329                self._info['elliptic'] = True
     1330                self._digraph.add_edges( [ (1,0), (0,2,2), (3,0,(3,-1)), (2,1), (2,3, (1,-3))])
     1331            elif rank == 2 and twist == [1,1]:
     1332                self._rank = rank + 2
     1333                self._info['mutation_finite'] = True
     1334                self._info['elliptic'] = True
     1335                self._digraph.add_edges( [ (1,0), (0,2,2), (3,0,(1,-3)), (2,1), (2,3,(3,-1)) ] )
     1336            else:
     1337                _mutation_type_error( data )
     1338
     1339        # type GR (mutation infinite)
     1340        elif letter == 'GR':
     1341            if twist == None and type(rank) is list and len(rank) == 2 and all( rank[i] in ZZ and rank[i] > 0 for i in [0,1] ) and rank[1] - 1 > rank[0] > 1:
     1342                gr_rank = (rank[0]-1,rank[1]-rank[0]-1)
     1343                self._rank = prod(gr_rank)
     1344                self._info['simply_laced'] = True
     1345                self._info['skew_symmetric'] = True
     1346                a,b = gr_rank
     1347                for i in range(a):
     1348                    for j in range(b):
     1349                        if i < a-1:
     1350                            if (i+j) % 2 == 0:
     1351                                self._digraph.add_edge(i*b+j,(i+1)*b+j)
     1352                            else:
     1353                                self._digraph.add_edge((i+1)*b+j,i*b+j)
     1354                        if j < b-1:
     1355                            if (i+j) % 2 == 0:
     1356                                self._digraph.add_edge(i*b+j+1,i*b+j)
     1357                            else:
     1358                                self._digraph.add_edge(i*b+j,i*b+j+1)
     1359            else:
     1360                _mutation_type_error( data )
     1361
     1362        # type R2 (rank 2 finite mutation types)
     1363        elif letter == 'R2':
     1364            if twist == None and type(rank) is list and len(rank) == 2 and all( rank[i] in ZZ and rank[i] > 0 for i in [0,1] ):
     1365                rank = sorted(rank)
     1366                b,c = rank
     1367                self._rank = 2
     1368                if b == c: self._info['skew_symmetric'] = True
     1369                self._graph.add_edge(0,1,(b,-c))
     1370            else:
     1371                _mutation_type_error( data )
     1372
     1373        # type T
     1374        elif letter == 'T':
     1375            if twist == None and type(rank) is list and len(rank) == 3 and all( rank[i] in ZZ and rank[i] > 0 for i in [0,1,2] ):
     1376                if type( rank ) == tuple:
     1377                    rank = list( rank )
     1378                    data[1] = rank
     1379                rank = sorted( rank )
     1380                self._rank = sum( rank ) - 2
     1381                self._info['simply_laced'] = True
     1382                self._info['skew_symmetric'] = True
     1383                r,p,q = rank
     1384                for i in xrange(q-1):
     1385                    if i == 0:
     1386                        self._graph.add_edge(0,1)
     1387                        self._graph.add_edge(0,r)
     1388                        self._graph.add_edge(0,r+p-1)
     1389                    else:
     1390                        if i < r-1:
     1391                            self._graph.add_edge(i,i+1)
     1392                        if i < p-1:
     1393                            self._graph.add_edge(i+r-1,i+r)
     1394                        self._graph.add_edge(i+r+p-2,i+r+p-1)
     1395            else:
     1396                _mutation_type_error( data )
     1397
     1398        # type TR (mutation infinite)
     1399        elif letter == 'TR':
     1400            if twist == None and rank > 2:
     1401                self._rank = rank*(rank+1)/2
     1402                self._info['simply_laced'] = True
     1403                self._info['skew_symmetric'] = True
     1404                level = 0
     1405                while level < rank:
     1406                    nr = rank*level-sum(range(level))
     1407                    for i in xrange(nr,nr+rank-level-1):
     1408                        self._digraph.add_edge(i,i+1)
     1409                        self._digraph.add_edge(i+rank-level,i)
     1410                        self._digraph.add_edge(i+1,i+rank-level)
     1411                    level += 1
     1412            else:
     1413                _mutation_type_error( data )
     1414
     1415        # type X
     1416        elif letter == 'X':
     1417            if rank in [6,7] and twist == None:
     1418                self._rank = rank
     1419                self._info['mutation_finite'] = True
     1420                self._info['skew_symmetric'] = True
     1421                self._digraph.add_edges( [ (0,1,2),(1,2),(2,0),(2,3),(3,4,2),(4,2),(2,5) ] )
     1422                if rank == 7:
     1423                    self._digraph.add_edges( [ (5,6,2),(6,2) ] )
     1424            else:
     1425                _mutation_type_error( data )
     1426
     1427        # otherwise, an error is raised
     1428        else:
     1429            _mutation_type_error( data )
     1430
     1431        # in the bipartite case, the digraph is constructed from the graph
     1432        if not self._digraph:
     1433            if self._graph.is_bipartite():
     1434                self._digraph = _bipartite_graph_to_digraph( self._graph )
     1435            else:
     1436                raise ValueError, 'The QuiverMutationType does not have a Coxeter diagram.'
     1437
     1438        # in the other cases, the graph is constructed from the digraph
     1439        if not self._graph:
     1440            self._graph = self._digraph.to_undirected()
     1441
     1442        # _description is as for CartanType
     1443        if twist: self._description = str( [letter,rank,twist] )
     1444        else: self._description = str( [letter,rank] )
     1445
     1446    def irreducible_components( self ):
     1447        """
     1448        Returns a list of all irreducible components of self.
     1449
     1450        EXAMPLES::
     1451
     1452            sage: mut_type = QuiverMutationType('A',3); mut_type
     1453            ['A', 3]
     1454            sage: mut_type.irreducible_components()
     1455            (['A', 3],)
     1456        """
     1457        return tuple([self])
     1458
     1459    @cached_method
     1460    def class_size(self):
     1461        """
     1462        If it is known, the size of the mutation class of all quivers which are mutation equivalent to the standard quiver of self (up to isomorphism) is returned.
     1463        Otherwise, NotImplemented is returned.
     1464
     1465        Formula for finite type A is taken from Torkildsen - Counting
     1466        cluster-tilted algebras of type `A_n`.
     1467        Formulas for affine type A and finite type D are taken from Bastian,
     1468        Prellberg, Rubey, Stump - Counting the number of elements in the
     1469        mutation classes of `\widetilde A_n` quivers.
     1470        Formulas for finite and affine types B and C are
     1471        proven but not yet published.
     1472        Conjectural formulas for several other non-simply-laced affine types
     1473        are implemented.
     1474        Exceptional Types (finite, affine, and elliptic) E, F, G, and X are
     1475        hardcoded.
     1476
     1477        EXAMPLES::
     1478
     1479            sage: mut_type = QuiverMutationType( ['A',5] ); mut_type
     1480            ['A', 5]
     1481            sage: mut_type.class_size()
     1482            19
     1483
     1484            sage: mut_type = QuiverMutationType( ['A',[10,3],1] ); mut_type
     1485            ['A', [3, 10], 1]
     1486            sage: mut_type.class_size()
     1487            142120
     1488
     1489            sage: mut_type = QuiverMutationType( ['B',6] ); mut_type
     1490            ['B', 6]
     1491            sage: mut_type.class_size()
     1492            132
     1493
     1494            sage: mut_type = QuiverMutationType( ['BD',6,1] ); mut_type
     1495            ['BD', 6, 1]
     1496            sage: mut_type.class_size()
     1497            Warning: This method uses a formula which has not been proved correct.
     1498            504
     1499        """
     1500        if not self.is_mutation_finite():
     1501            return infinity
     1502
     1503        # type A (finite and affine)
     1504        if self._letter == 'A':
     1505            # the formula is taken from Torkildsen - Counting cluster-tilted algebras of type A
     1506            if self.is_finite():
     1507                n = self._rank
     1508                a = binomial( 2*(n+1), n+1 ) / (n+2)
     1509                if n % 2 == 1:
     1510                    a += binomial( n+1, (n+1)/2 )
     1511                if n % 3 == 0:
     1512                    a += 2 * binomial( 2*n/3, n/3 )
     1513                return a / (n+3)
     1514            # the formula is taken from Bastian, Prellberg, Rubey, Stump
     1515            elif self.is_affine():
     1516                i,j = self._bi_rank
     1517                i = ZZ(i)
     1518                j = ZZ(j)
     1519                n = i+j
     1520                f = Euler_Phi()
     1521                if i == j:
     1522                    return ( binomial( 2*i,i ) + sum( f(k) * binomial(2*i/k,i/k)**2 for k in filter( lambda k: k in j.divisors(), i.divisors() ) ) / n ) / 4
     1523                else:
     1524                    return sum( f(k) * binomial(2*i/k,i/k) * binomial(2*j/k,j/k) for k in filter( lambda k: k in j.divisors(), i.divisors() ) ) / ( 2 * n )
     1525
     1526        # types B and C (finite and affine)
     1527        elif self._letter in ['B','C']:
     1528            # this formula is proven but nowhere published
     1529            # correctness is clear enough that I don't think a warning is needed
     1530            if self.is_finite():
     1531                n = self._rank
     1532                return binomial( 2*n, n ) / (n+1)
     1533
     1534        elif self._letter in ['BB','CC']:
     1535            # these two formulas are not yet proven
     1536            print Warning ("Warning: This method uses a formula which has not been proved correct.")
     1537            if self.is_affine():
     1538                if self._twist == 1:
     1539                    n = self._rank - 1
     1540                    if n%2==1:
     1541                        return binomial( 2*n-1, n-1 )
     1542                    else:
     1543                        return binomial( 2*n-1, n-1 ) + binomial( n-1, n/2 -1 )
     1544
     1545        # type BC (affine)
     1546        elif self._letter == 'BC':
     1547            # this formula is not yet proven
     1548            print Warning ("Warning: This method uses a formula which has not been proved correct.")
     1549            if self.is_affine():
     1550                if self._twist == 1:
     1551                    n = self._rank - 1
     1552                    return binomial( 2*n, n )
     1553
     1554        # types BD and CD (affine)
     1555        elif self._letter in ['BD','CD']:
     1556            # this formula is not yet proven
     1557            print Warning ("Warning: This method uses a formula which has not been proved correct.")
     1558            if self.is_affine():
     1559                if self._twist == 1:
     1560                    n = self._rank - 2
     1561                    return 2*binomial( 2*n, n )
     1562
     1563        # type D (finite and affine)
     1564        elif self._letter == 'D':
     1565            # the formula is taken from Bastian, Prellberg, Rubey, Stump
     1566            if self.is_finite():
     1567                if self._rank == 4:
     1568                    return 6
     1569                else:
     1570                    f = Euler_Phi()
     1571                    n = ZZ( self._rank )
     1572                    return sum( f( n/k ) * binomial( 2*k, k ) for k in n.divisors() ) / (2*n)
     1573            # this formula is not yet proven
     1574            elif self.is_affine():
     1575                n = self._rank - 3
     1576                if n == 2:
     1577                    return 9
     1578                else:
     1579                    print Warning ("Warning: This method uses a formula which has not been proved correct.")
     1580                    if n%2==1:
     1581                        return 2*binomial(2*n,n)
     1582                    else:
     1583                        return 2*binomial(2*n,n) + binomial(n,n/2)
     1584
     1585        # the exceptional types are hard-coded
     1586        # type E (finite, affine and elliptic)
     1587        elif self._letter == 'E':
     1588            if self.is_finite():
     1589                if self._rank == 6:
     1590                    return 67
     1591                elif self._rank == 7:
     1592                    return 416
     1593                elif self._rank == 8:
     1594                    return 1574
     1595            elif self.is_affine():
     1596                if self._rank == 7:
     1597                    return 132
     1598                elif self._rank == 8:
     1599                    return 1080
     1600                elif self._rank == 9:
     1601                    return 7560
     1602            elif self.is_elliptic():
     1603                if self._rank == 8:
     1604                    return 49
     1605                elif self._rank == 9:
     1606                    return 506
     1607                elif self._rank == 10:
     1608                    return 5739
     1609
     1610        # type F
     1611        elif self._letter == 'F':
     1612            if self.is_finite():
     1613                return 15
     1614            elif self.is_affine():
     1615                return 60
     1616            elif self.is_elliptic():
     1617                if twist == (1,2):
     1618                    return 90
     1619                if twist == (1,1) or twist == (2,2):
     1620                    return 35
     1621
     1622        # type G
     1623        elif self._letter == 'G':
     1624            if self.is_finite():
     1625                return 2
     1626            elif self.is_affine():
     1627                return 6
     1628            elif self.is_elliptic():
     1629                if twist == (1,3):
     1630                    return 7
     1631                if twist == (1,1) or twist == (3,3):
     1632                    return 2
     1633
     1634        # type X
     1635        elif self._letter == 'X':
     1636            if self._rank == 6:
     1637                return 5
     1638            elif self._rank == 7:
     1639                return 2
     1640
     1641        # otherwise the size is returned to be unknown
     1642        else:
     1643            print "Size unknown"
     1644            return NotImplemented
     1645
     1646    def dual(self):
     1647        """
     1648        Returns the QuiverMutationType which is dual to self.
     1649
     1650        EXAMPLES::
     1651
     1652            sage: mut_type = QuiverMutationType('A',5); mut_type
     1653            ['A', 5]
     1654            sage: mut_type.dual()
     1655            ['A', 5]
     1656
     1657            sage: mut_type = QuiverMutationType('B',5); mut_type
     1658            ['B', 5]
     1659            sage: mut_type.dual()
     1660            ['C', 5]
     1661            sage: mut_type.dual().dual()
     1662            ['B', 5]
     1663            sage: mut_type.dual().dual() == mut_type
     1664            True
     1665        """
     1666        letter = self.letter()
     1667        # the self-dual cases
     1668        if letter != 'BC' and letter[0] in ['B','C']:
     1669            if letter == 'BB': letter = 'CC'
     1670            elif letter == 'CC': letter = 'BB'
     1671            elif letter[0] == 'B': letter = 'C' + letter[1:]
     1672            elif letter[0] == 'C': letter = 'B' + letter[1:]
     1673            rank = self._rank
     1674            if self.is_affine():
     1675                rank -= 1
     1676            twist = self._twist
     1677            return QuiverMutationType(letter,rank,twist)
     1678        # the cases F and G have non-trivial duality in some cases
     1679        elif letter in ['F','G']:
     1680            if self.is_finite(): return self
     1681            elif self.is_affine():
     1682                rank = self._rank - 1
     1683                twist = - self._twist
     1684            elif self.is_elliptic():
     1685                twist = self._twist
     1686                rank = self._rank - 2
     1687                if letter == 'F':
     1688                    if self._twist == [2,2]:
     1689                        twist == [1,1]
     1690                    if self._twist == [1,1]:
     1691                        twist == [2,2]
     1692                if letter == 'G':
     1693                    if self._twist == [3,3]:
     1694                        twist = [1,1]
     1695                    elif self._twist == [1,1]:
     1696                        twist = [3,3]
     1697            else: rank = self._rank
     1698            return QuiverMutationType(letter,rank,twist)
     1699        else:
     1700            return self
     1701
     1702class QuiverMutationType_Reducible(QuiverMutationType_abstract,UniqueRepresentation,SageObject):
     1703    """
     1704    The mutation type for a cluster algebra or a quiver. Should not be called
     1705    directly, but through QuiverMutationType.  Inherits from
     1706    QuiverMutationType_abstract.
     1707    """
     1708    def __init__(self, *args):
     1709        """
     1710        Should not be called directly, but through QuiverMutationType.
     1711
     1712        INPUT:
     1713
     1714        - ``data`` -- a list each of whose entries is a
     1715        QuiverMutationType_Irreducible
     1716
     1717        EXAMPLES::
     1718
     1719            sage: QuiverMutationType(['A',4],['B',6])
     1720            [ ['A', 4], ['B', 6] ]
     1721        """
     1722        data = args
     1723        if len(data) < 2 or not all( type( comp ) is QuiverMutationType_Irreducible for comp in data ):
     1724            return _mutation_type_error(data)
     1725
     1726        # _info is initialized
     1727        self._info = {}
     1728        self._info['irreducible'] = False
     1729        self._info['mutation_finite'] = all( comp.is_mutation_finite() for comp in data )
     1730        self._info['simply_laced'] = all( comp.is_simply_laced() for comp in data )
     1731        self._info['skew_symmetric'] = all( comp.is_skew_symmetric() for comp in data )
     1732        self._info['finite'] = all( comp.is_finite() for comp in data )
     1733        self._info['irreducible_components'] = copy( data )
     1734
     1735        #  letter and rank are initialized
     1736        self._letter = ''
     1737        self._rank = 0
     1738
     1739        # graph and digraph are initialized
     1740        self._graph = Graph()
     1741        self._digraph = DiGraph()
     1742
     1743        for comp in data:
     1744            if self._letter:
     1745                self._letter += ' x '
     1746            self._letter += comp._letter
     1747            self._rank += comp._rank
     1748            self._graph = self._graph.disjoint_union( comp._graph, verbose_relabel=False )
     1749            self._digraph = self._digraph.disjoint_union( comp._digraph, verbose_relabel=False )
     1750        self._graph.name('')
     1751        self._digraph.name('')
     1752
     1753        # _description is as for CartanType
     1754        self._description = "[ "
     1755        comps = self.irreducible_components()
     1756        for i in xrange(len(comps)):
     1757            if i > 0: self._description += ", "
     1758            self._description += comps[i]._description
     1759        self._description += " ]"
     1760
     1761    def irreducible_components( self ):
     1762        """
     1763        Returns a list of all irreducible components of self.
     1764
     1765        EXAMPLES::
     1766
     1767            sage: mut_type = QuiverMutationType('A',3); mut_type
     1768            ['A', 3]
     1769            sage: mut_type.irreducible_components()
     1770            (['A', 3],)
     1771
     1772            sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
     1773            [ ['A', 3], ['B', 3] ]
     1774            sage: mut_type.irreducible_components()
     1775            (['A', 3], ['B', 3])
     1776
     1777            sage: mut_type = QuiverMutationType(['A',3],['B',3],['X',6]); mut_type
     1778            [ ['A', 3], ['B', 3], ['X', 6] ]
     1779            sage: mut_type.irreducible_components()
     1780            (['A', 3], ['B', 3], ['X', 6])
     1781        """
     1782        return self._info['irreducible_components']
     1783
     1784    @cached_method
     1785    def class_size(self):
     1786        """
     1787        If it is known, the size of the mutation class of all quivers which are
     1788        mutation equivalent to the standard quiver of self (up to isomorphism)
     1789        is returned.
     1790
     1791        Otherwise, NotImplemented is returned.
     1792
     1793        EXAMPLES::
     1794
     1795            sage: mut_type = QuiverMutationType(['A',3],['B',3]); mut_type
     1796            [ ['A', 3], ['B', 3] ]
     1797            sage: mut_type.class_size()
     1798            20
     1799
     1800            sage: mut_type = QuiverMutationType(['A',3],['B',3],['X',6]); mut_type
     1801            [ ['A', 3], ['B', 3], ['X', 6] ]
     1802            sage: mut_type.class_size()
     1803            100
     1804        """
     1805        if not self.is_mutation_finite():
     1806            return infinity
     1807        else:
     1808            components = []
     1809            multiplicities = []
     1810            for x in self.irreducible_components():
     1811                if components.count(x) == 0:
     1812                    components.append(x)
     1813                    multiplicities.append(1)
     1814                else:
     1815                    y = components.index(x)
     1816                    multiplicities[y] = multiplicities[y]+1
     1817
     1818            sizes = [ x.class_size() for x in components ]
     1819            if NotImplemented in sizes:
     1820                print "Size unknown"
     1821                return NotImplemented
     1822            else:
     1823                return prod( [binomial(sizes[i]+multiplicities[i]-1,
     1824                            multiplicities[i] ) for i in range (0,len(sizes))])
     1825
     1826    def dual(self):
     1827        """
     1828        Returns the QuiverMutationType which is dual to self.
     1829
     1830        EXAMPLES::
     1831
     1832            sage: mut_type = QuiverMutationType(['A',5],['B',6],['C',5],['D',4]); mut_type
     1833            [ ['A', 5], ['B', 6], ['C', 5], ['D', 4] ]
     1834            sage: mut_type.dual()
     1835            [ ['A', 5], ['C', 6], ['B', 5], ['D', 4] ]
     1836        """
     1837        comps = self.irreducible_components()
     1838        return QuiverMutationType( [comp.dual() for comp in comps ] )
     1839
     1840def _bipartite_graph_to_digraph( g ):
     1841    """
     1842    Returns a digraph obtained from a bipartite graph g by choosing one
     1843    set of the bipartition to be the set of sinks and the other to be the
     1844    set of sources.
     1845
     1846    EXAMPLES::
     1847
     1848        sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type \
     1849              import _bipartite_graph_to_digraph
     1850        sage: G = Graph([(1,2)])
     1851        sage: _bipartite_graph_to_digraph(G)
     1852        Digraph on 2 vertices
     1853    """
     1854    if not g.is_bipartite():
     1855        raise ValueError, 'The input graph is not bipartite.'
     1856
     1857    order = g.bipartite_sets()
     1858    dg = DiGraph()
     1859    for edge in g.edges():
     1860        if edge[0] in order[0]:
     1861            dg.add_edge( edge[0],edge[1],edge[2] )
     1862        else:
     1863            dg.add_edge( edge[1],edge[0],edge[2] )
     1864    for vert in g.vertices():
     1865        if vert not in dg.vertices():
     1866            dg.add_vertex(vert)
     1867    return dg
     1868
     1869def _is_mutation_type( data ):
     1870    """
     1871    Returns True if data is a QuiverMutationType.
     1872
     1873    EXAMPLES::
     1874
     1875        sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _is_mutation_type
     1876        sage: _is_mutation_type ( [ 'A', 2 ] )
     1877        True
     1878        sage: _is_mutation_type ( [ 'P', 1 ] )
     1879        False
     1880    """
     1881    try:
     1882        QuiverMutationType( data )
     1883        return True
     1884    except:
     1885        return False
     1886
     1887def _mutation_type_error( data ):
     1888    """
     1889    Outputs an error message because data which is not a valid quiver mutation
     1890    type has been passed to QuiverMutationType.
     1891
     1892    EXAMPLES::
     1893
     1894        sage: QuiverMutationType( 'Christian', 'Stump' ) # indirect doctest
     1895        Traceback (most recent call last):
     1896        ...
     1897        ValueError: ['Christian', 'Stump'] is not a valid quiver mutation type
     1898                Finite types have the form [ '?', n ] for type ? and rank n
     1899                Affine type A has the form [ 'A', [ i, j ], 1 ] for rank i+j
     1900                Affine type ? has the form [ '?', k, \pm 1 ] for rank k+1
     1901                Elliptic type ? has the form [ '?', k, [i, j] ] (1 <= i,j <= 3) for rank k+2
     1902                For correct syntax in other types, please consult the documentation.
     1903    """
     1904    if data[2] is None:
     1905        del data[2]
     1906    return_str  = str(data) + ' is not a valid quiver mutation type'
     1907    return_str += '\n            Finite types have the form [ \'?\', n ] for type ? and rank n'
     1908    return_str += '\n            Affine type A has the form [ \'A\', [ i, j ], 1 ] for rank i+j'
     1909    return_str += '\n            Affine type ? has the form [ \'?\', k, \pm 1 ] for rank k+1'
     1910    return_str += '\n            Elliptic type ? has the form [ \'?\', k, [i, j] ] (1 <= i,j <= 3) for rank k+2'
     1911    return_str += '\n            For correct syntax in other types, please consult the documentation.'
     1912
     1913    raise ValueError, return_str
     1914
     1915def _edge_list_to_matrix( edges, n, m ):
     1916    """
     1917    Returns the matrix obtained from the edge list of a quiver.
     1918
     1919    INPUT:
     1920
     1921    - ``edges``: the list of edges.
     1922
     1923    - ``n``: the number of mutable vertices of the quiver.
     1924
     1925    - ``m``: the number of frozen vertices of the quiver.
     1926
     1927    OUTPUT:
     1928
     1929    - An `(n+m) \times n` matrix corresponding to the edge-list.
     1930
     1931    EXAMPLES::
     1932
     1933        sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _edge_list_to_matrix
     1934        sage: G = QuiverMutationType(['A',2])._digraph
     1935        sage: _edge_list_to_matrix(G.edges(),2,0)
     1936        [ 0  1]
     1937        [-1  0]
     1938    """
     1939    M = matrix(ZZ,n+m,n,sparse=True)
     1940    for edge in edges:
     1941        if edge[2] is None:
     1942            edge = (edge[0],edge[1],(1,-1))
     1943        elif edge[2] in ZZ:
     1944            edge = (edge[0],edge[1],(edge[2],-edge[2]))
     1945        v1,v2,(a,b) = edge
     1946        if v1 < n:
     1947            M[v2,v1] = b
     1948        if v2 < n:
     1949            M[v1,v2] = a
     1950    return M
  • setup.py

    diff --git a/setup.py b/setup.py
    a b  
    867867                     'sage.coding.source_coding',
    868868
    869869                     'sage.combinat',
     870                     'sage.combinat.cluster_algebra_quiver',
    870871                     'sage.combinat.crystals',
    871872                     'sage.combinat.rigged_configurations',
    872873                     'sage.combinat.designs',