Ticket #15029: trac_15029-additions-similarity_class_type-ap.patch

File trac_15029-additions-similarity_class_type-ap.patch, 30.4 KB (added by amri, 6 years ago)

Added functions for similarity over principal ideal local rings of length two

  • sage/combinat/similarity_class_type.py

    # HG changeset patch
    # User Amritanshu Prasad <amri@imsc.res.in>
    # Date 1378721131 -19800
    # Node ID 3a9967b9d81071dfa0d89cd57c79bb8ba1912e7c
    # Parent  d0943a747f6dd975386c499f666609c9b1e3d8c5
    Trac 15029: implemented similarity classes for local rings of length two
    
    diff --git a/sage/combinat/similarity_class_type.py b/sage/combinat/similarity_class_type.py
    a b  
    22Similarity class types of matrices with entries in a finite field
    33
    44The notion of a matrix conjugacy class type was introduced by J. A. Green in
    5 [Green55]_, in the context of computing the irreducible charcaters of finite 
    6 general linear groups. The class types are equivalence classes of similarity 
    7 classes of square matrices with entries in a finite field which, roughly 
     5[Green55]_, in the context of computing the irreducible charcaters of finite
     6general linear groups. The class types are equivalence classes of similarity
     7classes of square matrices with entries in a finite field which, roughly
    88speaking, have the same qualitative properties.
    99
    1010For example, all similarity classes of the same class type have centralizers of
    11 the same cardinality and the same degrees of elementary divisors. Qualitative 
     11the same cardinality and the same degrees of elementary divisors. Qualitative
    1212properties of similarity classes such as semisimplicity and regularity descend
    1313to class types.
    1414
     
    3939`\mathrm{Irr}\mathbf{F}_q[t]` such that `c_2 = c_1\circ \sigma`. Thus, the type
    4040of `c` remembers only the degrees of the polynomials (and not the polynomials
    4141themselves) for which `c` takes a certain value `\lambda`. Replacing each
    42 irreducible polynomial of degree `d` for which `c` takes a non-trivial value 
     42irreducible polynomial of degree `d` for which `c` takes a non-trivial value
    4343`\lambda` by the pair `(d, \lambda)`, we obtain a multiset of such pairs.
    4444Clearly, `c_1` and `c_2` have the same type if and only if these multisets are
    4545equal. Thus a similarity class type may be viewed as a multiset of pairs of the
     
    106106    q^10 + q^8 + 2*q^7 + 2*q^6 + 2*q^5 + q^4
    107107
    108108Similarity class types can be used to calculate the coefficients of generating
    109 functions coming from the cycle index type techniques of Kung and Stong (see 
     109functions coming from the cycle index type techniques of Kung and Stong (see
    110110Morrison [Morrison06]_).
    111111
     112Along with the results of [PSS13]_, similarity class types can be used to
     113calculate the number of similarity classes of matrices of order `n` with entries
     114in a principal ideal local ring of length two with residue field of cardinality
     115`q` with centralizer of any given cardinality up to `n=4`. Among these, the
     116classes which are selftranspose can also be counted::
     117
     118    sage: from sage.combinat.similarity_class_type import matrix_centralizer_cardinalities2
     119    sage: list(matrix_centralizer_cardinalities2(3))
     120    [(q^6 - 3*q^5 + 3*q^4 - q^3, 1/6*q^6 - 1/2*q^5 + 1/3*q^4),
     121    (q^6 - 2*q^5 + q^4, q^5 - q^4),
     122    (q^8 - 3*q^7 + 3*q^6 - q^5, 1/2*q^5 - q^4 + 1/2*q^3),
     123    (q^8 - 2*q^7 + q^6, q^4 - q^3),
     124    (q^10 - 2*q^9 + 2*q^7 - q^6, q^4 - q^3),
     125    (q^8 - q^7 - q^6 + q^5, 1/2*q^5 - q^4 + 1/2*q^3),
     126    (q^6 - q^5 - q^4 + q^3, 1/2*q^6 - 1/2*q^5),
     127    (q^6 - q^5, q^4),
     128    (q^10 - 2*q^9 + q^8, q^3),
     129    (q^8 - 2*q^7 + q^6, q^4 - q^3),
     130    (q^8 - q^7, q^3 + q^2),
     131    (q^12 - 3*q^11 + 3*q^10 - q^9, 1/6*q^4 - 1/2*q^3 + 1/3*q^2),
     132    (q^12 - 2*q^11 + q^10, q^3 - q^2),
     133    (q^14 - 2*q^13 + 2*q^11 - q^10, q^3 - q^2),
     134    (q^12 - q^11 - q^10 + q^9, 1/2*q^4 - 1/2*q^3),
     135    (q^12 - q^11, q^2),
     136    (q^14 - 2*q^13 + q^12, q^2),
     137    (q^18 - q^17 - q^16 + q^14 + q^13 - q^12, q^2),
     138    (q^12 - q^9, 1/3*q^4 - 1/3*q^2),
     139    (q^6 - q^3, 1/3*q^6 - 1/3*q^4)]
    112140
    113141REFERENCES:
    114142
     
    117145   Available from: http://dx.doi.org/10.1090/S0002-9947-1955-0072878-2
    118146
    119147.. [Morrison06] Morrison, Kent E. Integer sequences and matrices over finite fields.
    120    J. Integer Seq. 9 (2006), no. 2, Article 06.2.1, 28 pp. 
     148   J. Integer Seq. 9 (2006), no. 2, Article 06.2.1, 28 pp.
    121149   Available from: https://cs.uwaterloo.ca/journals/JIS/VOL9/Morrison/morrison37.html
    122    
     150
     151.. [PSS13] Prasad, A., Singla, P., and Spallone, S., Similarity of matrices over
     152   local rings of length two. arxiv.org:1212.6157
     153
    123154AUTHOR:
    124155
    125 - Amritanshu Prasad (2013-07-18)
     156- Amritanshu Prasad (2013-07-18): initial implementation
     157
     158- Amritanshu Prasad (2013-09-09): added functions for similarity classes over
     159  rings of length two
    126160
    127161"""
    128162#*****************************************************************************
     
    154188from sage.combinat.partition import Partitions, Partition
    155189from sage.rings.all import ZZ, QQ, FractionField, divisors
    156190from sage.misc.cachefunc import cached_in_parent_method, cached_function
     191from sage.combinat.cartesian_product import CartesianProduct
     192from sage.combinat.misc import IterableFunctionCall
    157193
    158194@cached_function
    159195def fq(n, q = None):
    160     """ 
     196    """
    161197    Return `(1-q^{-1}) (1-q^{-2}) \cdots (1-q^{-n})`.
    162198
    163199    INPUT:
     
    171207    A rational function in ``q``.
    172208
    173209    EXAMPLES::
    174    
     210
    175211        sage: from sage.combinat.similarity_class_type import fq
    176212        sage: fq(0)
    177213        1
     
    185221@cached_function
    186222def primitives(n, invertible = False, q = None):
    187223    """
    188     Return the number of similarity classes of simple matrices 
     224    Return the number of similarity classes of simple matrices
    189225    of order n with entries in a finite field of order ``q``.
    190     This is the same as the number of irreducible polynomials 
     226    This is the same as the number of irreducible polynomials
    191227    of degree d.
    192228
    193229    If ``invertible`` is ``True``, then only the number of
     
    200236    INPUT:
    201237
    202238    - ``n`` -- a positive integer
    203    
     239
    204240    - ``invertible`` -- boolean; if set, only number of non-zero classes is returned
    205241
    206242    - ``q`` -- an integer or an indeterminate
     
    321357    def __classcall_private__(cls, deg, par):
    322358        r"""
    323359        Create a primary similarity class type.
    324        
     360
    325361        EXAMPLES::
    326362
    327363            sage: PrimarySimilarityClassType(2, [3, 2, 1])
     
    341377    def __init__(self, parent, deg, par):
    342378        """
    343379        Initialize ``self``.
    344        
     380
    345381        EXAMPLES::
    346382
    347383            sage: elt =  PrimarySimilarityClassType(2, [3, 2, 1])
     
    356392        Return string representation of ``self``.
    357393
    358394        EXAMPLES::
    359        
     395
    360396            sage: PrimarySimilarityClassType(2, [3, 2, 1])
    361397            [2, [3, 2, 1]]
    362398        """
     
    401437    def degree(self):
    402438        """
    403439        Return degree of ``self``.
    404        
     440
    405441        EXAMPLES::
    406442
    407443            sage: PT = PrimarySimilarityClassType(2, [3, 2, 1])
     
    413449    def partition(self):
    414450        """
    415451        Return partition corresponding to ``self``.
    416        
     452
    417453        EXAMPLES::
    418454
    419455            sage: PT = PrimarySimilarityClassType(2, [3, 2, 1])
     
    427463        Return the dimension of the algebra of matrices which commute with a
    428464        matrix of type ``self``.
    429465
    430         For a partition `(d, \lambda)` this dimension is given by 
     466        For a partition `(d, \lambda)` this dimension is given by
    431467        `d(\lambda_1 + 3\lambda_2 + 5\lambda_3 + \cdots)`.
    432468
    433469        EXAMPLES::
     
    460496        """
    461497        Return the cardinality of the centralizer group of a matrix of type
    462498        ``self`` in a field of order ``q``.
    463        
     499
    464500        INPUT:
    465501
    466502        ``q`` -- an integer or an indeterminate
     
    484520class PrimarySimilarityClassTypes(Parent, UniqueRepresentation):
    485521    r"""
    486522    All primary similarity class types of size ``n`` whose degree is greater
    487     than that of ``min`` or whose degree is that of ``min`` and  whose partition 
     523    than that of ``min`` or whose degree is that of ``min`` and  whose partition
    488524    is less than of ``min`` in lexicographic order.
    489525
    490     A primary similarity class type of size `n` is a pair `(\lambda, d)` 
     526    A primary similarity class type of size `n` is a pair `(\lambda, d)`
    491527    consisting of a partition `\lambda` and a positive integer `d` such that
    492528    `|\lambda|d = n`.
    493529
     
    508544        [1, [1, 1]]
    509545        [2, [1]]
    510546
    511     If ``min`` is specified, then the class consists of only those primary 
     547    If ``min`` is specified, then the class consists of only those primary
    512548    similarity class types whose degree is greater than that of ``min`` or whose
    513     degree is that of ``min`` and  whose partition is less than of ``min`` in 
     549    degree is that of ``min`` and  whose partition is less than of ``min`` in
    514550    lexicographic order::
    515551
    516552        sage: PTC = PrimarySimilarityClassTypes(2, min = PrimarySimilarityClassType(1, [1, 1]))
     
    522558    @staticmethod
    523559    def __classcall_private__(cls, n, min = None):
    524560        r"""
    525         Create the class of vector partitions of ``vec`` where all parts 
     561        Create the class of vector partitions of ``vec`` where all parts
    526562        are greater than or equal to the vector ``min``.
    527563
    528564        EXAMPLES::
     
    566602        - ``par`` -- a partition
    567603
    568604        EXAMPLES::
    569        
     605
    570606            sage: PTC = PrimarySimilarityClassTypes(2)
    571607            sage: elt = PTC(1, [1, 1]); elt
    572608            [1, [1, 1]]
     
    599635        """
    600636        Return size of elements of ``self``.
    601637
    602         The size of a primary similarity class type `(d, \lambda)` is 
     638        The size of a primary similarity class type `(d, \lambda)` is
    603639        `d |\lambda|`.
    604640
    605641        EXAMPLES::
     
    633669    def __classcall_private__(cls, tau):
    634670        """
    635671        Create a similarity class type.
    636        
     672
    637673        EXAMPLES:
    638674
    639         The input can be a list of lists or a list of primary similarity class 
     675        The input can be a list of lists or a list of primary similarity class
    640676        types, and the order in which this list is given does not matter::
    641            
     677
    642678            sage: tau1 = SimilarityClassType([[3, [3, 2, 1]], [2, [2, 1]]]); tau1
    643679            [[2, [2, 1]], [3, [3, 2, 1]]]
    644680            sage: tau2 = SimilarityClassType([PrimarySimilarityClassType(2, [2, 1]), PrimarySimilarityClassType(3, [3, 2, 1])])
    645681            sage: tau1 == tau2
    646682            True
    647            
    648         The parent class is the class of similarity class types of the sum of 
     683
     684        The parent class is the class of similarity class types of the sum of
    649685        the sizes of the primary matrix types in ``tau``::
    650686
    651687            sage: tau = SimilarityClassType([[3, [3, 2, 1]], [2, [2, 1]]])
     
    698734            2
    699735        """
    700736        return sum([PT.centralizer_algebra_dim() for PT in self])
    701    
     737
    702738    def centralizer_group_card(self, q = None):
    703739        """
    704740        Return the cardinality of the group of matrices in `GL_n(\mathbf{F}_q)`
     
    709745        - ``q`` -- an integer or an indeterminate
    710746
    711747        EXAMPLES::
    712            
     748
    713749            sage: tau = SimilarityClassType([[1, [1]], [1, [1]]])
    714750            sage: tau.centralizer_group_card()
    715751            q^2 - 2*q + 1
     
    735771            else:
    736772                D[PT.partition()] = Partition([PT.degree()])
    737773        return D
    738    
     774
    739775    def number_of_classes(self, invertible = False, q = None):
    740776        """
    741777        Return the number of similarity classes of matrices of type ``self``.
     
    908944
    909945    EXAMPLES:
    910946
    911     If ``min`` is not specified, then the class of all matrix types of size 
     947    If ``min`` is not specified, then the class of all matrix types of size
    912948    ``n`` is constructed::
    913949
    914950        sage: M = SimilarityClassTypes(2)
     
    920956        [[2, [1]]]
    921957
    922958    If ``min`` is specified, then the class consists of only those similarity
    923     class types which are multisets of primary matrix types which either have 
    924     size greater than that of ``min``, or if they have size equal to that of 
     959    class types which are multisets of primary matrix types which either have
     960    size greater than that of ``min``, or if they have size equal to that of
    925961    ``min``, then they occur after ``min`` in the iterator for
    926962    ``PrimarySimilarityClassTypes(n)``, where ``n`` is the size of ``min``::
    927963
     
    9741010        - ``tau`` -- a list of primary similarity class types
    9751011
    9761012        EXAMPLES::
    977        
     1013
    9781014            sage: M = SimilarityClassTypes(2)
    9791015            sage: elt = M([[1, [1]], [1, [1]]]); elt
    9801016            [[1, [1]], [1, [1]]]
     
    10001036            sage: SimilarityClassTypes(3).cardinality()
    10011037            8
    10021038
    1003         A good test of the iterator is to see that all elements of 
     1039        A good test of the iterator is to see that all elements of
    10041040        `M_n(\mathbf{F}_q)` or `GL_n(\mathbf{F}_q` are enumerated through
    10051041        types::
    10061042
     
    10311067    def size(self):
    10321068        """
    10331069        Return size of ``self``
    1034            
     1070
    10351071        EXAMPLES::
    1036            
     1072
    10371073            sage: tau = SimilarityClassType([[3, [3, 2, 1]], [2, [2, 1]]])
    10381074            sage: tau.parent().size()
    10391075            24
     
    10461082
    10471083        Given a set of functions `n_\lambda(q)` (these could be polynomials or
    10481084        rational functions in `q`, for each similarity class type `\tau` define
    1049        
     1085
    10501086        .. MATH::
    10511087
    10521088            n_\tau(q) = \prod_{(d,\lambda)\in \tau} n_\lambda(q^d).
     
    10601096        where `tau(g)` denotes the type of a matrix `g`, and the sum is over
    10611097        all `n\times n` matrices if ``sumover`` is set to "matrices", is over
    10621098        all `n\times n` similarity classes if ``sumover`` is set to "classes",
    1063         and over all `n\times n` types if ``sumover`` is set to types. If 
     1099        and over all `n\times n` types if ``sumover`` is set to types. If
    10641100        ``invertible`` is set to ``True``, then the sum is only over invertible
    10651101        matrices or classes.
    10661102
     
    10761112        A function of ``q``.
    10771113
    10781114        EXAMPLES::
    1079        
     1115
    10801116            sage: M = SimilarityClassTypes(2)
    10811117            sage: M.sum(lambda la:1)
    10821118            q^4
     
    11021138        elif sumover == "types":
    11031139            return sum([tau.statistic(stat, invertible = invertible, q = q) for tau in self])
    11041140        else:
    1105             raise ValueError("invalid parameter %s"%(sumover))
     1141            raise ValueError("invalid parameter %s"%(sumover))
     1142
     1143################################################################################
     1144#                 Similarity over rings of length two                          #
     1145################################################################################
     1146
     1147def dictionary_from_generator(gen):
     1148    r"""
     1149    Given a generator for a list of pairs `(c,f)` construct a dictionary whose
     1150    keys are the distinct values for `c` and whose value at `c` is the sum of
     1151    `f` over all pairs of the form `(c',f)` such that `c=c'`.
     1152
     1153    EXAMPLES::
     1154
     1155        sage: from sage.combinat.similarity_class_type import dictionary_from_generator
     1156        sage: dictionary_from_generator(((floor(x/2), x) for x in xrange(10)))
     1157        {0: 1, 1: 5, 2: 9, 3: 13, 4: 17}
     1158
     1159    It also works with lists::
     1160
     1161        sage: dictionary_from_generator([(floor(x/2),x) for x in range(10)])
     1162        {0: 1, 1: 5, 2: 9, 3: 13, 4: 17}
     1163
     1164    .. NOTE::
     1165
     1166        Since the generator is first converted to a list, memory usage could be
     1167        high.
     1168    """
     1169    L = list(gen)
     1170    setofkeys = list(set([item[0] for item in L]))
     1171    return dict([(key, sum([entry[1] for entry in filter(lambda pair: pair[0] == key, L)])) for key in setofkeys])
     1172
     1173def matrix_similarity_classes(n, q = None, invertible = False):
     1174    r"""
     1175    Return the number of matrix similarity classes over a finite field of order
     1176    ``q``.
     1177
     1178    TESTS::
     1179
     1180        sage: from sage.combinat.similarity_class_type import matrix_similarity_classes
     1181        sage: matrix_similarity_classes(2)
     1182        q^2 + q
     1183        sage: matrix_similarity_classes(2, invertible = True)
     1184        q^2 - 1
     1185        sage: matrix_similarity_classes(2, invertible = True, q = 4)
     1186        15
     1187    """
     1188    if q is None:
     1189        q = FractionField(QQ['q']).gen()
     1190    if n == 0:
     1191        return 1
     1192    if invertible:
     1193        return sum([q**max(la)*((1-q**(-1))**map(lambda x: x>0, la.to_exp()).count(True)) for la in Partitions(n)])
     1194    else:
     1195        return sum([q**max(la) for la in Partitions(n)])
     1196
     1197def matrix_centralizer_cardinalities(n, q = None, invertible = False):
     1198    """
     1199    Generate pairs consisting of centralizer cardinalities of matrices over a
     1200    finite field and their frequencies.
     1201
     1202    TESTS::
     1203
     1204        sage: from sage.combinat.similarity_class_type import matrix_centralizer_cardinalities
     1205        sage: list(matrix_centralizer_cardinalities(1))
     1206        [(q - 1, q)]
     1207        sage: list(matrix_centralizer_cardinalities(2))
     1208        [(q^2 - 2*q + 1, 1/2*q^2 - 1/2*q),
     1209        (q^2 - q, q),
     1210        (q^4 - q^3 - q^2 + q, q),
     1211        (q^2 - 1, 1/2*q^2 - 1/2*q)]
     1212        sage: list(matrix_centralizer_cardinalities(2, invertible = True))
     1213        [(q^2 - 2*q + 1, 1/2*q^2 - 3/2*q + 1),
     1214        (q^2 - q, q - 1),
     1215        (q^4 - q^3 - q^2 + q, q - 1),
     1216        (q^2 - 1, 1/2*q^2 - 1/2*q)]
     1217
     1218    """
     1219    for tau in SimilarityClassTypes(n):
     1220        yield (tau.centralizer_group_card(q = q), tau.number_of_classes(invertible = invertible, q = q))
     1221
     1222def input_parsing(data):
     1223    """
     1224    Recognize and return the intended type of ``input``
     1225
     1226    TESTS::
     1227
     1228        sage: from sage.combinat.similarity_class_type import input_parsing
     1229        sage: input_parsing(Partition([2, 1]))
     1230        ('par', [2, 1])
     1231        sage: input_parsing(PrimarySimilarityClassType(2, [2, 1]))
     1232        ('pri', [2, [2, 1]])
     1233        sage: input_parsing(SimilarityClassType([[2, [2, 1]]]))
     1234        ('sim', [[2, [2, 1]]])
     1235        sage: input_parsing([2, 1])
     1236        ('par', [2, 1])
     1237        sage: input_parsing([2, [2, 1]])
     1238        ('pri', [2, [2, 1]])
     1239        sage: input_parsing([[2, [2, 1]]])
     1240        ('sim', [[2, [2, 1]]])
     1241    """
     1242    if isinstance(data, SimilarityClassType):
     1243        case = 'sim'
     1244        output = data
     1245    elif isinstance(data, PrimarySimilarityClassType):
     1246        case = 'pri'
     1247        output = data
     1248    elif isinstance(data, Partition):
     1249        case = 'par'
     1250        output = data
     1251    else:
     1252        try:
     1253            data = Partition(data)
     1254            case = 'par'
     1255            output = data
     1256        except(TypeError, ValueError):
     1257            try:
     1258                data = SimilarityClassType(data)
     1259                case = 'sim'
     1260                output = data
     1261            except(TypeError, ValueError):
     1262                try:
     1263                    data = PrimarySimilarityClassType(*data)
     1264                    case = 'pri'
     1265                    output = data
     1266                except(TypeError, ValueError):
     1267                    raise ValueError("Expected a Partition, a SimiliarityClassType or a PrimarySimilarityClassType, got a %s"%(type(data)))
     1268    return case, data
     1269
     1270def ext_orbits(input, q = None, selftranspose = False):
     1271    r"""
     1272    Return the number of orbits in `\mathrm{Ext}^1(M, M)` for the action of
     1273    `\mathrm{Aut}(M, M)`, where `M` is the `\mathbf F_q[t]`-module constructed
     1274    from ``input``.
     1275
     1276    TESTS::
     1277
     1278        sage: from sage.combinat.similarity_class_type import ext_orbits
     1279        sage: ext_orbits([6, 1])
     1280        q^7 + q^6 + q^5
     1281        sage: ext_orbits([6, 1], selftranspose = True)
     1282        q^7 + q^6 - q^5
     1283        sage: ext_orbits([6, 1, 1])
     1284        q^8 + 2*q^7 + 2*q^6 + 2*q^5
     1285        sage: ext_orbits ([6, 1, 1], selftranspose = True)
     1286        q^8 + 2*q^7
     1287        sage: ext_orbits([2, 2])
     1288        q^4 + q^3 + q^2
     1289        sage: ext_orbits([2, 2], selftranspose = True)
     1290        q^4 + q^3 + q^2
     1291        sage: ext_orbits([2, 2, 2])
     1292        q^6 + q^5 + 2*q^4 + q^3 + 2*q^2
     1293        sage: ext_orbits([2, 2, 2], selftranspose = True)
     1294        q^6 + q^5 + 2*q^4 + q^3
     1295        sage: ext_orbits([2, 2, 2, 2])
     1296        q^8 + q^7 + 3*q^6 + 3*q^5 + 5*q^4 + 3*q^3 + 3*q^2
     1297        sage: ext_orbits([2, 2, 2, 2], selftranspose = True)
     1298        q^8 + q^7 + 3*q^6 + 3*q^5 + 3*q^4 + q^3 + q^2
     1299        sage: ext_orbits([2, [6, 1]])
     1300        q^14 + q^12 + q^10
     1301        sage: ext_orbits([[2, [6, 1]]])
     1302        q^14 + q^12 + q^10
     1303    """
     1304    # Comments cite items in the paper "Similarity over rings of length two" by
     1305    # Prasad, Singla, and Spallone.
     1306    if q is None:
     1307        q = FractionField(QQ['q']).gen()
     1308    case, data = input_parsing(input)
     1309    if case == 'par':
     1310        la = data
     1311        if la.size() == 0:
     1312            return q.parent()(1)
     1313        if max(la) == 1:
     1314            return matrix_similarity_classes(len(la), q = q)
     1315        elif len(la) == 1:
     1316            return q**la.size()
     1317        elif len(la) == 2 and list(la).count(1) == 1: # see Table 3
     1318            m = max(la) - 1
     1319            if selftranspose:
     1320                return q**(m + 2) + q**(m + 1) - q**m
     1321            else:
     1322                return q**(m + 2) + q**(m + 1) + q**m
     1323        elif len(la) == 3 and list(la).count(1) == 2: # see Table 4
     1324            m = max(la) - 1
     1325            if not selftranspose:
     1326                return q**m*(q**3 + 2*q**2 + 2*q + 2)
     1327            else:
     1328                return q**m*(q**3 + 2*q**2)
     1329        elif min(la) == 2 and max(la) == 2:
     1330            return matrix_similarity_classes2(len(la), q = q, selftranspose = selftranspose)
     1331        else:
     1332            raise ValueError('partition %s not implemented for ExtOrbitClasses.orbits'%(la))
     1333    elif case == 'pri':
     1334        tau = data
     1335        return ext_orbits(tau.partition(), q = q, selftranspose = selftranspose).substitute(q = q**tau.degree())
     1336    elif case == 'sim':
     1337        tau = data
     1338        return prod([ext_orbits(PT, q = q, selftranspose = selftranspose) for PT in tau])
     1339
     1340def matrix_similarity_classes2(n, q = None, selftranspose = False, invertible = False):
     1341    """
     1342    Return the number of similarity classes of matrices of order ``n`` with
     1343    entries in a principal ideal local ring of length two.
     1344
     1345    EXAMPLES:
     1346
     1347    We can generate Table 6 of [PSS13]_::
     1348
     1349        sage: from sage.combinat.similarity_class_type import matrix_similarity_classes2
     1350        sage: matrix_similarity_classes2(2)
     1351        q^4 + q^3 + q^2
     1352        sage: matrix_similarity_classes2(2, invertible = True)
     1353        q^4 - q
     1354        sage: matrix_similarity_classes2(3)
     1355        q^6 + q^5 + 2*q^4 + q^3 + 2*q^2
     1356        sage: matrix_similarity_classes2(3, invertible = true)
     1357        q^6 - q^3 + 2*q^2 - 2*q
     1358        sage: matrix_similarity_classes2(4)
     1359        q^8 + q^7 + 3*q^6 + 3*q^5 + 5*q^4 + 3*q^3 + 3*q^2
     1360        sage: matrix_similarity_classes2(4, invertible = True)
     1361        q^8 + q^6 - q^5 + 2*q^4 - 2*q^3 + 2*q^2 - 3*q
     1362
     1363    And also Table 7::
     1364
     1365        sage: matrix_similarity_classes2(2, selftranspose = True)
     1366        q^4 + q^3 + q^2
     1367        sage: matrix_similarity_classes2(2, selftranspose = True, invertible = True)
     1368        q^4 - q
     1369        sage: matrix_similarity_classes2(3, selftranspose = True)
     1370        q^6 + q^5 + 2*q^4 + q^3
     1371        sage: matrix_similarity_classes2(3, selftranspose = True, invertible = True)
     1372        q^6 - q^3
     1373        sage: matrix_similarity_classes2(4, selftranspose = True)
     1374        q^8 + q^7 + 3*q^6 + 3*q^5 + 3*q^4 + q^3 + q^2
     1375        sage: matrix_similarity_classes2(4, selftranspose = True, invertible = True)
     1376        q^8 + q^6 - q^5 - q
     1377    """
     1378    if q is None:
     1379        q = FractionField(QQ['q']).gen()
     1380    return sum([tau.number_of_classes(invertible = invertible, q = q)*ext_orbits(tau, q = q, selftranspose = selftranspose) for tau in SimilarityClassTypes(n)])
     1381
     1382def ext_orbit_centralizers(input, q = None, selftranspose = False):
     1383    r"""
     1384    Generate pairs consisting of centralizer cardinalities of orbits in
     1385    `\mathrm{Ext}^1(M, M)` for the action of `\mathrm{Aut}(M, M)`, where `M` is
     1386    the `\mathbf F_q[t]`-module constructed from ``input`` and their frequencies.
     1387
     1388    TESTS::
     1389
     1390        sage: from sage.combinat.similarity_class_type import ext_orbit_centralizers
     1391        sage: list(ext_orbit_centralizers([6, 1]))
     1392        [(q^9 - 2*q^8 + q^7, q^6),
     1393        (q^7 - 2*q^6 + q^5, q^7 - q^6),
     1394        (q^7 - q^6, q^6 + q^5)]
     1395        sage: list(ext_orbit_centralizers([6, 1], selftranspose = True))
     1396        [(q^9 - 2*q^8 + q^7, q^6),
     1397        (q^7 - 2*q^6 + q^5, q^7 - q^6),
     1398        (q^7 - q^6, q^6 - q^5)]
     1399        sage: list(ext_orbit_centralizers([6, 1, 1]))
     1400        [(q^12 - 3*q^11 + 3*q^10 - q^9, 1/2*q^7 - 1/2*q^6),
     1401        (q^8 - 3*q^7 + 3*q^6 - q^5, 1/2*q^8 - q^7 + 1/2*q^6),
     1402        (q^12 - 2*q^11 + q^10, q^6),
     1403        (q^8 - 2*q^7 + q^6, q^7 - q^6),
     1404        (q^14 - 2*q^13 + 2*q^11 - q^10, q^6),
     1405        (q^10 - 2*q^9 + 2*q^7 - q^6, q^7 - q^6),
     1406        (q^12 - q^11 - q^10 + q^9, 1/2*q^7 - 1/2*q^6),
     1407        (q^8 - q^7 - q^6 + q^5, 1/2*q^8 - q^7 + 1/2*q^6),
     1408        (q^8 - 2*q^7 + q^6, q^7 - q^6),
     1409        (q^8 - q^7, q^6 + 2*q^5),
     1410        (q^10 - 2*q^9 + q^8, 2*q^6)]
     1411        sage: list(ext_orbit_centralizers([6, 1, 1], selftranspose = True))
     1412        [(q^12 - 3*q^11 + 3*q^10 - q^9, 1/2*q^7 - 1/2*q^6),
     1413        (q^8 - 3*q^7 + 3*q^6 - q^5, 1/2*q^8 - q^7 + 1/2*q^6),
     1414        (q^12 - 2*q^11 + q^10, q^6),
     1415        (q^8 - 2*q^7 + q^6, q^7 - q^6),
     1416        (q^14 - 2*q^13 + 2*q^11 - q^10, q^6),
     1417        (q^10 - 2*q^9 + 2*q^7 - q^6, q^7 - q^6),
     1418        (q^12 - q^11 - q^10 + q^9, 1/2*q^7 - 1/2*q^6),
     1419        (q^8 - q^7 - q^6 + q^5, 1/2*q^8 - q^7 + 1/2*q^6),
     1420        (q^8 - 2*q^7 + q^6, q^7 - q^6),
     1421        (q^8 - q^7, q^6)]
     1422        sage: list(ext_orbit_centralizers([2, [6, 1, 1]], selftranspose = True))
     1423        [(q^24 - 3*q^22 + 3*q^20 - q^18, 1/2*q^14 - 1/2*q^12),
     1424        (q^16 - 3*q^14 + 3*q^12 - q^10, 1/2*q^16 - q^14 + 1/2*q^12),
     1425        (q^24 - 2*q^22 + q^20, q^12),
     1426        (q^16 - 2*q^14 + q^12, q^14 - q^12),
     1427        (q^28 - 2*q^26 + 2*q^22 - q^20, q^12),
     1428        (q^20 - 2*q^18 + 2*q^14 - q^12, q^14 - q^12),
     1429        (q^24 - q^22 - q^20 + q^18, 1/2*q^14 - 1/2*q^12),
     1430        (q^16 - q^14 - q^12 + q^10, 1/2*q^16 - q^14 + 1/2*q^12),
     1431        (q^16 - 2*q^14 + q^12, q^14 - q^12),
     1432        (q^16 - q^14, q^12)]
     1433        sage: list(ext_orbit_centralizers([[2, [6, 1, 1]]], selftranspose = True))
     1434        [(q^24 - 3*q^22 + 3*q^20 - q^18, 1/2*q^14 - 1/2*q^12),
     1435        (q^16 - 3*q^14 + 3*q^12 - q^10, 1/2*q^16 - q^14 + 1/2*q^12),
     1436        (q^24 - 2*q^22 + q^20, q^12),
     1437        (q^16 - 2*q^14 + q^12, q^14 - q^12),
     1438        (q^28 - 2*q^26 + 2*q^22 - q^20, q^12),
     1439        (q^20 - 2*q^18 + 2*q^14 - q^12, q^14 - q^12),
     1440        (q^24 - q^22 - q^20 + q^18, 1/2*q^14 - 1/2*q^12),
     1441        (q^16 - q^14 - q^12 + q^10, 1/2*q^16 - q^14 + 1/2*q^12),
     1442        (q^16 - 2*q^14 + q^12, q^14 - q^12),
     1443        (q^16 - q^14, q^12)]
     1444
     1445    """
     1446    # Comments cite items in the paper "Similarity over rings of length two" by
     1447    # Prasad, Singla, and Spallone.
     1448    if q is None:
     1449        q = FractionField(QQ['q']).gen()
     1450    case, data = input_parsing(input)
     1451    if case == 'par':
     1452        la = data
     1453        if len(la) == 0:
     1454            yield (1, 1)
     1455            return
     1456        elif max(la) == 1:
     1457            for item in matrix_centralizer_cardinalities(len(la), q = q):
     1458                yield item
     1459            return
     1460        elif len(la) == 1:
     1461            yield (q**la[0] - q**(la[0]-1), q**la[0])
     1462            return
     1463        elif len(la) == 2 and list(la).count(1) == 1: # see Table 3
     1464            m = max(la) - 1
     1465            yield (q**(m + 4) - 2*q**(m + 3) + q**(m + 2), q**(m + 1)) # (8.5.1)
     1466            yield (q**(m + 2) - 2*q**(m + 1) + q**m, q**(m + 2) - q**(m + 1)) # (8.5.2)
     1467            if selftranspose:
     1468                yield (q**(m + 2) - q**(m + 1), q**(m+1) - q**m) # (8.5.3) and (8.5.4)
     1469            else:
     1470                yield (q**(m + 2) - q**(m + 1), q**(m + 1) + q**m) # (8.5.3) and (8.5.4)
     1471            return
     1472        elif len(la) == 3 and list(la).count(1) == 2: # see Table 4
     1473            m = max(la) - 1
     1474            for item in matrix_centralizer_cardinalities(2, q = q):
     1475                yield (item[0]*(q**(m + 5) - q**(m + 4)), item[1]*q**m) # (8.6.1)
     1476                yield (item[0]*(q**(m + 1) - q**m), item[1]*(q**(m + 1) - q**m)) # (8.6.2)
     1477            yield (q**(m + 3) - 2*q**(m + 2) + q**(m+1), q**(m + 2) - q**(m + 1)) # (8.6.3)
     1478            if selftranspose:
     1479                yield (q**(m + 3) - q**(m+2), q**(m+1)) #(8.6.4), (8.6.5) and (8.6.7)
     1480            else:
     1481                yield (q**(m + 3) - q**(m+2), q**(m + 1) + 2*q**m) # (8.6.4), (8.6.5) and (8.6.7)
     1482                yield (q**(m + 5) - 2*q**(m + 4) + q**(m + 3), 2*q**(m + 1)) # (8.6.6) and (8.6.8)
     1483            return
     1484        elif max(la) == 2 and min(la) == 2:
     1485            for item in matrix_centralizer_cardinalities2(len(la), q = q, selftranspose = selftranspose):
     1486                yield item
     1487        else:
     1488            raise ValueError('partition %s not implemented for ExtOrbitClasses.orbit_centralizers'%(la))
     1489    elif case == 'pri':
     1490        tau = data
     1491        for item in ext_orbit_centralizers(tau.partition(), selftranspose = selftranspose):
     1492            yield (item[0].substitute(q = q**tau.degree()), item[1].substitute(q = q**tau.degree()))
     1493    elif case == 'sim':
     1494        tau = data
     1495        for item in CartesianProduct(*[IterableFunctionCall(lambda x: ext_orbit_centralizers(x, q = q, selftranspose = selftranspose), PT) for PT in tau]):
     1496                size = prod([list(entry)[0] for entry in item])
     1497                freq = prod([list(entry)[1] for entry in item])
     1498                yield(size, freq)
     1499
     1500
     1501def matrix_centralizer_cardinalities2(n, q = None, selftranspose = False, invertible = False):
     1502    r"""
     1503    Generate  pairs consisting of centralizer cardinalities of matrices over a
     1504    principal ideal local ring of length two with residue field of order ``q``
     1505    and their frequencies.
     1506
     1507    TESTS::
     1508
     1509        sage: from sage.combinat.similarity_class_type import matrix_centralizer_cardinalities2
     1510        sage: list(matrix_centralizer_cardinalities2(1))
     1511        [(q^2 - q, q^2)]
     1512        sage: list(matrix_centralizer_cardinalities2(2))
     1513        [(q^4 - 2*q^3 + q^2, 1/2*q^4 - 1/2*q^3),
     1514        (q^4 - q^3, q^3),
     1515        (q^6 - 2*q^5 + q^4, 1/2*q^3 - 1/2*q^2),
     1516        (q^6 - q^5, q^2),
     1517        (q^8 - q^7 - q^6 + q^5, q^2),
     1518        (q^6 - q^4, 1/2*q^3 - 1/2*q^2),
     1519        (q^4 - q^2, 1/2*q^4 - 1/2*q^3)]
     1520        sage: from sage.combinat.similarity_class_type import dictionary_from_generator
     1521        sage: dictionary_from_generator(matrix_centralizer_cardinalities2(2, q = 2))
     1522        {96: 4, 32: 4, 4: 4, 16: 2, 8: 8, 12: 4, 48: 2}
     1523    """
     1524    if q is None:
     1525        q = FractionField(QQ['q']).gen()
     1526    for tau in SimilarityClassTypes(n):
     1527        for pair in ext_orbit_centralizers(tau, q = q, selftranspose = selftranspose):
     1528            yield (q**tau.centralizer_algebra_dim()*pair[0], tau.number_of_classes(invertible = invertible, q = q)*pair[1])