Exemplo n.º 1
0
    def __classcall_private__(cls,
                              data=None,
                              index_set=None,
                              cartan_type=None,
                              cartan_type_check=True,
                              borcherds=None):
        """
        Normalize input so we can inherit from sparse integer matrix.

        .. NOTE::

            To disable the Cartan type check, use the optional argument
            ``cartan_type_check = False``.

        EXAMPLES::

            sage: C = CartanMatrix(['A',1,1])
            sage: C2 = CartanMatrix([[2, -2], [-2, 2]])
            sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1])
            sage: C == C2 and C == C3
            True

        TESTS:

        Check that :trac:`15740` is fixed::

            sage: d = DynkinDiagram()
            sage: d.add_edge('a', 'b', 2)
            sage: d.index_set()
            ('a', 'b')
            sage: cm = CartanMatrix(d)
            sage: cm.index_set()
            ('a', 'b')
        """
        # Special case with 0 args and kwds has Cartan type
        if cartan_type is not None and data is None:
            data = CartanType(cartan_type)

        if data is None:
            data = []
            n = 0
            index_set = tuple()
            cartan_type = None
            subdivisions = None
        elif isinstance(data, CartanMatrix):
            if index_set is not None:
                d = {a: index_set[i] for i, a in enumerate(data.index_set())}
                return data.relabel(d)
            return data
        else:
            dynkin_diagram = None
            subdivisions = None

            from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class
            if isinstance(data, DynkinDiagram_class):
                dynkin_diagram = data
                cartan_type = data._cartan_type
            else:
                try:
                    cartan_type = CartanType(data)
                    dynkin_diagram = cartan_type.dynkin_diagram()
                except (TypeError, ValueError):
                    pass

            if dynkin_diagram is not None:
                n = dynkin_diagram.rank()
                index_set = dynkin_diagram.index_set()
                oir = dynkin_diagram.odd_isotropic_roots()
                reverse = {a: i for i, a in enumerate(index_set)}
                if isinstance(borcherds, (list, tuple)):
                    if (len(borcherds) != len(index_set) and
                            not all(val in ZZ and (val == 2 or
                                                   (val % 2 == 0 and val < 0))
                                    for val in borcherds)):
                        raise ValueError(
                            "the input data is not a Borcherds-Cartan matrix")
                    data = {(i, i): val if index_set[i] not in oir else 0
                            for i, val in enumerate(borcherds)}
                else:
                    data = {(i, i): 2 if index_set[i] not in oir else 0
                            for i in range(n)}
                for (i, j, l) in dynkin_diagram.edge_iterator():
                    data[(reverse[j], reverse[i])] = -l
            else:
                M = matrix(data)
                if borcherds:
                    if not is_borcherds_cartan_matrix(M):
                        raise ValueError(
                            "the input matrix is not a Borcherds-Cartan matrix"
                        )
                else:
                    if not is_generalized_cartan_matrix(M):
                        raise ValueError(
                            "the input matrix is not a generalized Cartan matrix"
                        )
                n = M.ncols()
                data = M.dict()
                subdivisions = M._subdivisions

            if index_set is None:
                index_set = tuple(range(n))
            else:
                index_set = tuple(index_set)

        if len(index_set) != n and len(set(index_set)) != n:
            raise ValueError("the given index set is not valid")

        # We can do the Cartan type initialization later as this is not
        #   a unique representation
        mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, False, True)
        # FIXME: We have to initialize the CartanMatrix part separately because
        #   of the __cinit__ of the matrix. We should get rid of this workaround
        mat._CM_init(cartan_type, index_set, cartan_type_check)
        mat._subdivisions = subdivisions
        return mat
Exemplo n.º 2
0
    def __classcall_private__(cls,
                              data=None,
                              index_set=None,
                              coxeter_type=None,
                              cartan_type=None,
                              coxeter_type_check=True):
        r"""
        A Coxeter matrix can we created via a graph, a Coxeter type, or
        a matrix.

        .. NOTE::

            To disable the Coxeter type check, use the optional argument
            ``coxeter_type_check = False``.

        EXAMPLES::

            sage: C = CoxeterMatrix(['A',1,1],['a','b'])
            sage: C2 = CoxeterMatrix([[1, -1], [-1, 1]])
            sage: C3 = CoxeterMatrix(matrix([[1, -1], [-1, 1]]), [0, 1])
            sage: C == C2 and C == C3
            True

        Check with `\infty` because of the hack of using `-1` to represent
        `\infty` in the Coxeter matrix::

            sage: G = Graph([(0, 1, 3), (1, 2, oo)])
            sage: W1 = CoxeterMatrix([[1, 3, 2], [3, 1, -1], [2, -1, 1]])
            sage: W2 = CoxeterMatrix(G)
            sage: W1 == W2
            True
            sage: CoxeterMatrix(W1.coxeter_graph()) == W1
            True

        The base ring of the matrix depends on the entries given::

            sage: CoxeterMatrix([[1,-1],[-1,1]])._matrix.base_ring()
            Integer Ring
            sage: CoxeterMatrix([[1,-3/2],[-3/2,1]])._matrix.base_ring()
            Rational Field
            sage: CoxeterMatrix([[1,-1.5],[-1.5,1]])._matrix.base_ring()
            Real Field with 53 bits of precision
        """
        if not data:
            if coxeter_type:
                data = CoxeterType(coxeter_type)
            elif cartan_type:
                data = CoxeterType(CartanType(cartan_type))

        # Special cases with no arguments passed
        if not data:
            data = []
            n = 0
            index_set = tuple()
            coxeter_type = None
            base_ring = ZZ
            mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), data,
                           coxeter_type, index_set)
            mat._subdivisions = None

            return mat

        if isinstance(data, CoxeterMatrix):  # Initiate from itself
            return data

        # Initiate from a graph:
        # TODO: Check if a CoxeterDiagram once implemented
        if isinstance(data, Graph):
            return cls._from_graph(data, coxeter_type_check)

        # Get the Coxeter type
        coxeter_type = None
        from sage.combinat.root_system.cartan_type import CartanType_abstract
        if isinstance(data, CartanType_abstract):
            coxeter_type = data.coxeter_type()
        else:
            try:
                coxeter_type = CoxeterType(data)
            except (TypeError, ValueError, NotImplementedError):
                pass

        # Initiate from a Coxeter type
        if coxeter_type:
            return cls._from_coxetertype(coxeter_type)

        # TODO:: remove when oo is possible in matrices.
        n = len(data[0])
        data = [x if x != infinity else -1 for r in data for x in r]
        data = matrix(n, n, data)
        # until here

        # Get the index set
        if index_set:
            index_set = tuple(index_set)
        else:
            index_set = tuple(range(1, n + 1))
        if len(set(index_set)) != n:
            raise ValueError("the given index set is not valid")

        return cls._from_matrix(data, coxeter_type, index_set,
                                coxeter_type_check)
Exemplo n.º 3
0
def find_cartan_type_from_matrix(CM):
    r"""
    Find a Cartan type by direct comparison of Dynkin diagrams given from
    the generalized Cartan matrix ``CM`` and return ``None`` if not found.

    INPUT:

    - ``CM`` -- a generalized Cartan matrix

    EXAMPLES::

        sage: from sage.combinat.root_system.cartan_matrix import find_cartan_type_from_matrix
        sage: CM = CartanMatrix([[2,-1,-1], [-1,2,-1], [-1,-1,2]])
        sage: find_cartan_type_from_matrix(CM)
        ['A', 2, 1]
        sage: CM = CartanMatrix([[2,-1,0], [-1,2,-2], [0,-1,2]])
        sage: find_cartan_type_from_matrix(CM)
        ['C', 3] relabelled by {1: 0, 2: 1, 3: 2}
        sage: CM = CartanMatrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]])
        sage: find_cartan_type_from_matrix(CM)
    """
    types = []
    for S in CM.dynkin_diagram().connected_components_subgraphs():
        S = DiGraph(S)  # We need a simple digraph here
        n = S.num_verts()
        # Build the list to test based upon rank
        if n == 1:
            types.append(CartanType(['A', 1]))
            continue

        test = [['A', n]]
        if n >= 2:
            if n == 2:
                test += [['G', 2], ['A', 2, 2]]
            test += [['B', n], ['A', n - 1, 1]]
        if n >= 3:
            if n == 3:
                test.append(['G', 2, 1])
            test += [['C', n], ['BC', n - 1, 2], ['C', n - 1, 1]]
        if n >= 4:
            if n == 4:
                test.append(['F', 4])
            test += [['D', n], ['B', n - 1, 1]]
        if n >= 5:
            if n == 5:
                test.append(['F', 4, 1])
            test.append(['D', n - 1, 1])
        if n == 6:
            test.append(['E', 6])
        elif n == 7:
            test += [['E', 7], ['E', 6, 1]]
        elif n == 8:
            test += [['E', 8], ['E', 7, 1]]
        elif n == 9:
            test.append(['E', 8, 1])

        # Test every possible Cartan type and its dual
        found = False
        for x in test:
            ct = CartanType(x)
            T = DiGraph(ct.dynkin_diagram())  # We need a simple digraph here
            iso, match = T.is_isomorphic(S, certificate=True, edge_labels=True)
            if iso:
                types.append(ct.relabel(match))
                found = True
                break

            if ct == ct.dual():
                continue  # self-dual, so nothing more to test

            ct = ct.dual()
            T = DiGraph(ct.dynkin_diagram())  # We need a simple digraph here
            iso, match = T.is_isomorphic(S, certificate=True, edge_labels=True)
            if iso:
                types.append(ct.relabel(match))
                found = True
                break
        if not found:
            return None

    return CartanType(types)
Exemplo n.º 4
0
def Associahedron(cartan_type, backend='ppl'):
    r"""
    Construct an associahedron.

    The generalized associahedron is a polytopal complex with vertices in
    one-to-one correspondence with clusters in the cluster complex, and with
    edges between two vertices if and only if the associated two clusters
    intersect in codimension 1.

    The associahedron of type `A_n` is one way to realize the classical
    associahedron as defined in the :wikipedia:`Associahedron`.

    A polytopal realization of the associahedron can be found in [CFZ2002]_. The
    implementation is based on [CFZ2002]_, Theorem 1.5, Remark 1.6, and Corollary
    1.9.

    INPUT:

    - ``cartan_type`` -- a cartan type according to
      :class:`sage.combinat.root_system.cartan_type.CartanTypeFactory`

    - ``backend`` -- string (``'ppl'``); the backend to use;
      see :meth:`sage.geometry.polyhedron.constructor.Polyhedron`

    EXAMPLES::

        sage: Asso = polytopes.associahedron(['A',2]); Asso
        Generalized associahedron of type ['A', 2] with 5 vertices

        sage: sorted(Asso.Hrepresentation(), key=repr)
        [An inequality (-1, 0) x + 1 >= 0,
         An inequality (0, -1) x + 1 >= 0,
         An inequality (0, 1) x + 1 >= 0,
         An inequality (1, 0) x + 1 >= 0,
         An inequality (1, 1) x + 1 >= 0]

        sage: Asso.Vrepresentation()
        (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1),
         A vertex at (-1, 0), A vertex at (0, -1))

        sage: polytopes.associahedron(['B',2])
        Generalized associahedron of type ['B', 2] with 6 vertices

    The two pictures of [CFZ2002]_ can be recovered with::

        sage: Asso = polytopes.associahedron(['A',3]); Asso
        Generalized associahedron of type ['A', 3] with 14 vertices
        sage: Asso.plot()  # long time
        Graphics3d Object

        sage: Asso = polytopes.associahedron(['B',3]); Asso
        Generalized associahedron of type ['B', 3] with 20 vertices
        sage: Asso.plot()  # long time
        Graphics3d Object

    TESTS::

        sage: sorted(polytopes.associahedron(['A',3]).vertices())
        [A vertex at (-3/2, 0, -1/2), A vertex at (-3/2, 0, 3/2),
         A vertex at (-3/2, 1, -3/2), A vertex at (-3/2, 2, -3/2),
         A vertex at (-3/2, 2, 3/2), A vertex at (-1/2, -1, -1/2),
         A vertex at (-1/2, 0, -3/2), A vertex at (1/2, -2, 1/2),
         A vertex at (1/2, -2, 3/2), A vertex at (3/2, -2, 1/2),
         A vertex at (3/2, -2, 3/2), A vertex at (3/2, 0, -3/2),
         A vertex at (3/2, 2, -3/2), A vertex at (3/2, 2, 3/2)]

        sage: sorted(polytopes.associahedron(['B',3]).vertices())
        [A vertex at (-3, 0, 0), A vertex at (-3, 0, 3),
         A vertex at (-3, 2, -2), A vertex at (-3, 4, -3),
         A vertex at (-3, 5, -3), A vertex at (-3, 5, 3),
         A vertex at (-2, 1, -2), A vertex at (-2, 3, -3),
         A vertex at (-1, -2, 0), A vertex at (-1, -1, -1),
         A vertex at (1, -4, 1), A vertex at (1, -3, 0),
         A vertex at (2, -5, 2), A vertex at (2, -5, 3),
         A vertex at (3, -5, 2), A vertex at (3, -5, 3),
         A vertex at (3, -3, 0), A vertex at (3, 3, -3),
         A vertex at (3, 5, -3), A vertex at (3, 5, 3)]

        sage: polytopes.associahedron(['A',4]).f_vector()
        (1, 42, 84, 56, 14, 1)
        sage: polytopes.associahedron(['B',4]).f_vector()
        (1, 70, 140, 90, 20, 1)

        sage: p1 = polytopes.associahedron(['A',4], backend='normaliz')   # optional - pynormaliz
        sage: TestSuite(p1).run(skip='_test_pickling')                    # optional - pynormaliz
        sage: p2 = polytopes.associahedron(['A',4], backend='cdd')
        sage: TestSuite(p2).run()
        sage: p3 = polytopes.associahedron(['A',4], backend='field')
        sage: TestSuite(p3).run()
    """
    cartan_type = CartanType(cartan_type)
    parent = Associahedra(QQ, cartan_type.rank(), backend)
    return parent(cartan_type)
Exemplo n.º 5
0
def DynkinDiagram(*args, **kwds):
    r"""
    Return the Dynkin diagram corresponding to the input.

    INPUT:

    The input can be one of the following:

    - empty to obtain an empty Dynkin diagram
    - a Cartan type
    - a Cartan matrix
    - a Cartan matrix and an indexing set

    Also one can input an index_set by

    The edge multiplicities are encoded as edge labels. This uses the
    convention in Hong and Kang, Kac, Fulton Harris, and crystals. This is the
    **opposite** convention in Bourbaki and Wikipedia's Dynkin diagram
    (:wikipedia:`Dynkin_diagram`). That is for `i \neq j`::

       i <--k-- j <==> a_ij = -k
                  <==> -scalar(coroot[i], root[j]) = k
                  <==> multiple arrows point from the longer root
                       to the shorter one

    For example, in type `C_2`, we have::

        sage: C2 = DynkinDiagram(['C',2]); C2
        O=<=O
        1   2
        C2
        sage: C2.cartan_matrix()
        [ 2 -2]
        [-1  2]

    However Bourbaki would have the Cartan matrix as:

    .. MATH::

        \begin{bmatrix}
        2 & -1 \\
        -2 & 2
        \end{bmatrix}.

    EXAMPLES::

        sage: DynkinDiagram(['A', 4])
        O---O---O---O
        1   2   3   4
        A4

        sage: DynkinDiagram(['A',1],['A',1])
        O
        1
        O
        2
        A1xA1

        sage: R = RootSystem("A2xB2xF4")
        sage: DynkinDiagram(R)
        O---O
        1   2
        O=>=O
        3   4
        O---O=>=O---O
        5   6   7   8
        A2xB2xF4

        sage: R = RootSystem("A2xB2xF4")
        sage: CM = R.cartan_matrix(); CM
        [ 2 -1| 0  0| 0  0  0  0]
        [-1  2| 0  0| 0  0  0  0]
        [-----+-----+-----------]
        [ 0  0| 2 -1| 0  0  0  0]
        [ 0  0|-2  2| 0  0  0  0]
        [-----+-----+-----------]
        [ 0  0| 0  0| 2 -1  0  0]
        [ 0  0| 0  0|-1  2 -1  0]
        [ 0  0| 0  0| 0 -2  2 -1]
        [ 0  0| 0  0| 0  0 -1  2]
        sage: DD = DynkinDiagram(CM); DD
        O---O
        1   2
        O=>=O
        3   4
        O---O=>=O---O
        5   6   7   8
        A2xB2xF4
        sage: DD.cartan_matrix()
        [ 2 -1  0  0  0  0  0  0]
        [-1  2  0  0  0  0  0  0]
        [ 0  0  2 -1  0  0  0  0]
        [ 0  0 -2  2  0  0  0  0]
        [ 0  0  0  0  2 -1  0  0]
        [ 0  0  0  0 -1  2 -1  0]
        [ 0  0  0  0  0 -2  2 -1]
        [ 0  0  0  0  0  0 -1  2]

    We can also create Dynkin diagrams from arbitrary Cartan matrices::

        sage: C = CartanMatrix([[2, -3], [-4, 2]])
        sage: DynkinDiagram(C)
        Dynkin diagram of rank 2
        sage: C.index_set()
        (0, 1)
        sage: CI = CartanMatrix([[2, -3], [-4, 2]], [3, 5])
        sage: DI = DynkinDiagram(CI)
        sage: DI.index_set()
        (3, 5)
        sage: CII = CartanMatrix([[2, -3], [-4, 2]])
        sage: DII = DynkinDiagram(CII, ('y', 'x'))
        sage: DII.index_set()
        ('x', 'y')

    .. SEEALSO::

        :func:`CartanType` for a general discussion on Cartan
        types and in particular node labeling conventions.

    TESTS:

    Check that :trac:`15277` is fixed by not having edges from 0's::

        sage: CM = CartanMatrix([[2,-1,0,0],[-3,2,-2,-2],[0,-1,2,-1],[0,-1,-1,2]])
        sage: CM
        [ 2 -1  0  0]
        [-3  2 -2 -2]
        [ 0 -1  2 -1]
        [ 0 -1 -1  2]
        sage: CM.dynkin_diagram().edges()
        [(0, 1, 3),
         (1, 0, 1),
         (1, 2, 1),
         (1, 3, 1),
         (2, 1, 2),
         (2, 3, 1),
         (3, 1, 2),
         (3, 2, 1)]
    """
    if len(args) == 0:
        return DynkinDiagram_class()
    mat = args[0]
    if is_Matrix(mat):
        mat = CartanMatrix(*args)
    if isinstance(mat, CartanMatrix):
        if mat.cartan_type() is not mat:
            try:
                return mat.cartan_type().dynkin_diagram()
            except AttributeError:
                ct = CartanType(*args)
                raise ValueError(
                    "Dynkin diagram data not yet hardcoded for type %s" % ct)
        if len(args) > 1:
            index_set = tuple(args[1])
        elif "index_set" in kwds:
            index_set = tuple(kwds["index_set"])
        else:
            index_set = mat.index_set()
        D = DynkinDiagram_class(index_set=index_set)
        for (i, j) in mat.nonzero_positions():
            if i != j:
                D.add_edge(index_set[i], index_set[j], -mat[j, i])
        return D
    ct = CartanType(*args)
    try:
        return ct.dynkin_diagram()
    except AttributeError:
        raise ValueError("Dynkin diagram data not yet hardcoded for type %s" %
                         ct)
Exemplo n.º 6
0
def find_cartan_type_from_matrix(CM):
    """
    Find a Cartan type by direct comparison of matrices given from the
    generalized Cartan matrix ``CM`` and return ``None`` if not found.

    INPUT:

    - ``CM`` -- A generalized Cartan matrix

    EXAMPLES::

        sage: from sage.combinat.root_system.cartan_matrix import find_cartan_type_from_matrix
        sage: M = matrix([[2,-1,-1], [-1,2,-1], [-1,-1,2]])
        sage: find_cartan_type_from_matrix(M)
        ['A', 2, 1]
        sage: M = matrix([[2,-1,0], [-1,2,-2], [0,-1,2]])
        sage: find_cartan_type_from_matrix(M)
        ['C', 3]
        sage: M = matrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]])
        sage: find_cartan_type_from_matrix(M)
    """
    n = CM.ncols()
    # Build the list to test based upon rank
    if n == 1:
        return CartanType(['A', 1])

    test = [['A', n]]
    if n >= 2:
        if n == 2:
            test += [['G', 2], ['A', 2, 2]]
        test += [['B', n], ['A', n - 1, 1]]
    if n >= 3:
        if n == 3:
            test += [['G', 2, 1], ['D', 4, 3]]
        test += [['C', n], ['BC', n - 1, 2], ['C', n - 1, 1]]
    if n >= 4:
        if n == 4:
            test += [['F', 4], ['G', 2, 1], ['D', 4, 3]]
        test += [['D', n], ['B', n - 1, 1]]
    if n == 5:
        test += [['F', 4, 1], ['D', n - 1, 1]]
    elif n == 6:
        test.append(['E', 6])
    elif n == 7:
        test += [['E', 7], ['E', 6, 1]]
    elif n == 8:
        test += [['E', 8], ['E', 7, 1]]
    elif n == 9:
        test.append(['E', 8, 1])

    # Test every possible Cartan type and its dual
    for x in test:
        ct = CartanType(x)
        if ct.cartan_matrix() == CM:
            return ct
        if ct == ct.dual():
            continue
        ct = ct.dual()
        if ct.cartan_matrix() == CM:
            return ct
    return None
Exemplo n.º 7
0
def HighestWeightCrystal(dominant_weight):
    r"""
    Returns an implementation of the highest weight crystal of highest weight `dominant_weight`.

    This is currently only implemented for crystals of type `E_6` and `E_7`.

    TODO: implement highest weight crystals for classical types `A_n`, `B_n`, `C_n`, `D_n` using tableaux.

    EXAMPLES::

        sage: C=CartanType(['E',6])
        sage: La=C.root_system().weight_lattice().fundamental_weights()
        sage: T = HighestWeightCrystal(La[1])
        sage: T.cardinality()
        27
        sage: T = HighestWeightCrystal(La[6])
        sage: T.cardinality()
        27
        sage: T = HighestWeightCrystal(La[2])
        sage: T.cardinality()
        78
        sage: T = HighestWeightCrystal(La[4])
        sage: T.cardinality()
        2925
        sage: T = HighestWeightCrystal(La[3])
        sage: T.cardinality()
        351
        sage: T = HighestWeightCrystal(La[5])
        sage: T.cardinality()
        351

        sage: C=CartanType(['E',7])
        sage: La=C.root_system().weight_lattice().fundamental_weights()
        sage: T = HighestWeightCrystal(La[1])
        sage: T.cardinality()
        133
        sage: T = HighestWeightCrystal(La[2])
        sage: T.cardinality()
        912
        sage: T = HighestWeightCrystal(La[3])
        sage: T.cardinality()
        8645
        sage: T = HighestWeightCrystal(La[4])
        sage: T.cardinality()
        365750
        sage: T = HighestWeightCrystal(La[5])
        sage: T.cardinality()
        27664
        sage: T = HighestWeightCrystal(La[6])
        sage: T.cardinality()
        1539
        sage: T = HighestWeightCrystal(La[7])
        sage: T.cardinality()
        56

        sage: C = CartanType(['C',2,1])
        sage: La = C.root_system().weight_lattice().fundamental_weights()
        sage: T = HighestWeightCrystal(La[1])
        sage: [p for p in T.subcrystal(max_depth=3)]
        [(Lambda[1],), (Lambda[0] - Lambda[1] + Lambda[2],), (-Lambda[0] + Lambda[1] + Lambda[2] - delta,),
        (Lambda[0] + Lambda[1] - Lambda[2],), (-Lambda[0] + 3*Lambda[1] - Lambda[2] - delta,), (2*Lambda[0] - Lambda[1],),
        (-Lambda[1] + 2*Lambda[2] - delta,)]
    """
    cartan_type = dominant_weight.parent().cartan_type()
    if cartan_type.is_finite() and cartan_type.type() in ['A','B','C','D']:
        raise NotImplementedError
    elif cartan_type == CartanType(['E',6]):
        return FiniteDimensionalHighestWeightCrystal_TypeE6(dominant_weight)
    elif cartan_type == CartanType(['E',7]):
        return FiniteDimensionalHighestWeightCrystal_TypeE7(dominant_weight)
    elif cartan_type.is_affine():
        return CrystalOfLSPaths(cartan_type,[dominant_weight[i] for i in cartan_type.index_set()])
    else:
        raise NotImplementedError
Exemplo n.º 8
0
def TensorProductOfCrystals(*crystals, **options):
    r"""
    Tensor product of crystals.

    Given two crystals `B` and `B'` of the same type,
    one can form the tensor product `B \otimes B'`. As a set
    `B \otimes B'` is the Cartesian product
    `B \times B'`. The crystal operators `f_i` and
    `e_i` act on `b \otimes b' \in B \otimes B'` as
    follows:

    .. math::

      f_i(b \otimes b') = \begin{cases}
      f_i(b) \otimes b' & \text{if $\varepsilon_i(b) \ge \varphi_i(b')$}\\
      b \otimes f_i(b') & \text{otherwise}
      \end{cases}

    and

    .. math::

      e_i(b \otimes b') = \begin{cases}
      b \otimes e_i(b') & \text{if $\varepsilon_i(b) \le \varphi_i(b')$}\\
      e_i(b) \otimes b' & \text{otherwise.}
      \end{cases}

    Note that this is the opposite of Kashiwara's convention for tensor
    products of crystals.

    EXAMPLES:

    We construct the type `A_2`-crystal generated by `2 \otimes 1 \otimes 1`::

        sage: C = CrystalOfLetters(['A',2])
        sage: T = TensorProductOfCrystals(C,C,C,generators=[[C(2),C(1),C(1)]])

    It has `8` elements::

        sage: T.list()
        [[2, 1, 1], [2, 1, 2], [2, 1, 3], [3, 1, 3], [3, 2, 3], [3, 1, 1], [3, 1, 2], [3, 2, 2]]

    One can also check the Cartan type of the crystal::

        sage: T.cartan_type()
        ['A', 2]

    Other examples include crystals of tableaux (which internally are represented as tensor products
    obtained by reading the tableaux columnwise)::

        sage: C = CrystalOfTableaux(['A',3], shape=[1,1,0])
        sage: D = CrystalOfTableaux(['A',3], shape=[1,0,0])
        sage: T = TensorProductOfCrystals(C,D, generators=[[C(rows=[[1], [2]]), D(rows=[[1]])], [C(rows=[[2], [3]]), D(rows=[[1]])]])
        sage: T.cardinality()
        24
        sage: TestSuite(T).run()
        sage: T.module_generators
        [[[[1], [2]], [[1]]], [[[2], [3]], [[1]]]]
        sage: [x.weight() for x in T.module_generators]
        [(2, 1, 0, 0), (1, 1, 1, 0)]

    If no module generators are specified, we obtain the full tensor
    product::

        sage: C=CrystalOfLetters(['A',2])
        sage: T=TensorProductOfCrystals(C,C)
        sage: T.list()
        [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
        sage: T.cardinality()
        9

    For a tensor product of crystals without module generators, the
    default implementation of module_generators contains all elements
    in the tensor product of the crystals. If there is a subset of
    elements in the tensor product that still generates the crystal,
    this needs to be implemented for the specific crystal separately::

        sage: T.module_generators.list()
        [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]

    For classical highest weight crystals, it is also possible to list
    all highest weight elements::

        sage: C = CrystalOfLetters(['A',2])
        sage: T = TensorProductOfCrystals(C,C,C,generators=[[C(2),C(1),C(1)],[C(1),C(2),C(1)]])
        sage: T.highest_weight_vectors()
        [[2, 1, 1], [1, 2, 1]]
    """
    crystals = tuple(crystals)
    if "cartan_type" in options:
        cartan_type = CartanType(options["cartan_type"])
    else:
        if len(crystals) == 0:
            raise ValueError, "you need to specify the Cartan type if the tensor product list is empty"
        else:
            cartan_type = crystals[0].cartan_type()

    if "generators" in options:
        generators = tuple(tuple(x) if isinstance(x, list) else x for x in options["generators"])
        return TensorProductOfCrystalsWithGenerators(crystals, generators=generators, cartan_type = cartan_type)
    else:
        return FullTensorProductOfCrystals(crystals, cartan_type = cartan_type)
Exemplo n.º 9
0
def CoxeterGroup(cartan_type, implementation=None):
    """
    INPUT:

     - ``cartan_type`` -- a cartan type (or coercible into; see :class:`CartanType`)
     - ``implementation`` -- "permutation", "matrix", "coxeter3", or None (default: None)

    Returns an implementation of the Coxeter group of type
    ``cartan_type``.

    EXAMPLES:

    If ``implementation`` is not specified, a permutation
    representation is returned whenever possible (finite irreducible
    Cartan type, with the GAP3 Chevie package available)::

        sage: W = CoxeterGroup(["A",2])
        sage: W                                   # optional - chevie
        Permutation Group with generators [(1,3)(2,5)(4,6), (1,4)(2,3)(5,6)]

    Otherwise, a Weyl group is returned::

        sage: W = CoxeterGroup(["A",3,1])
        sage: W
        Weyl Group of type ['A', 3, 1] (as a matrix group acting on the root space)

    We now use the ``implementation`` option::

        sage: W = CoxeterGroup(["A",2], implementation = "permutation") # optional - chevie
        sage: W                                                         # optional - chevie
        Permutation Group with generators [(1,3)(2,5)(4,6), (1,4)(2,3)(5,6)]
        sage: W.category()                       # optional - chevie
        Join of Category of finite permutation groups and Category of finite coxeter groups

        sage: W = CoxeterGroup(["A",2], implementation = "matrix")
        sage: W
        Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space)

        sage: W = CoxeterGroup(["H",3], implementation = "matrix")
        Traceback (most recent call last):
        ...
        NotImplementedError: Coxeter group of type ['H', 3] as matrix group not implemented

        sage: W = CoxeterGroup(["A",4,1], implementation = "permutation")
        Traceback (most recent call last):
        ...
        NotImplementedError: Coxeter group of type ['A', 4, 1] as permutation group not implemented

    """
    assert implementation in ["permutation", "matrix", "coxeter3", None]
    cartan_type = CartanType(cartan_type)

    if implementation is None:
        if cartan_type.is_finite() and cartan_type.is_irreducible(
        ) and is_chevie_available():
            implementation = "permutation"
        else:
            implementation = "matrix"

    if implementation == "coxeter3":
        try:
            from sage.libs.coxeter3.coxeter_group import CoxeterGroup
        except ImportError:
            raise RuntimeError, "coxeter3 must be installed"
        else:
            return CoxeterGroup(cartan_type)
    if implementation == "permutation" and is_chevie_available() and \
       cartan_type.is_finite() and cartan_type.is_irreducible():
        return CoxeterGroupAsPermutationGroup(cartan_type)
    elif implementation == "matrix" and cartan_type.is_crystalographic():
        return WeylGroup(cartan_type)
    else:
        raise NotImplementedError, "Coxeter group of type %s as %s group not implemented " % (
            cartan_type, implementation)
Exemplo n.º 10
0
    def __classcall_private__(cls, *crystals, **options):
        """
        Create the correct parent object.

        EXAMPLES::

            sage: C = crystals.Letters(['A',2])
            sage: T = crystals.TensorProduct(C, C)
            sage: T2 = crystals.TensorProduct(C, C, cartan_type=['A',2])
            sage: T is T2
            True
            sage: T.category()
            Category of tensor products of classical crystals

            sage: T3 = crystals.TensorProduct(C, C, C)
            sage: T3p = crystals.TensorProduct(T, C)
            sage: T3 is T3p
            True
            sage: B1 = crystals.TensorProduct(T, C)
            sage: B2 = crystals.TensorProduct(C, T)
            sage: B3 = crystals.TensorProduct(C, C, C)
            sage: B1 is B2 and B2 is B3
            True

            sage: B = crystals.infinity.Tableaux(['A',2])
            sage: T = crystals.TensorProduct(B, B)
            sage: T.category()
            Category of infinite tensor products of highest weight crystals

        TESTS:

        Check that mismatched Cartan types raise an error::

            sage: A2 = crystals.Letters(['A', 2])
            sage: A3 = crystals.Letters(['A', 3])
            sage: crystals.TensorProduct(A2, A3)
            Traceback (most recent call last):
            ...
            ValueError: all crystals must be of the same Cartan type
        """
        crystals = tuple(crystals)
        if "cartan_type" in options:
            cartan_type = CartanType(options.pop("cartan_type"))
        else:
            if not crystals:
                raise ValueError(
                    "you need to specify the Cartan type if the tensor product list is empty"
                )
            else:
                cartan_type = crystals[0].cartan_type()

        if any(c.cartan_type() != cartan_type for c in crystals):
            raise ValueError("all crystals must be of the same Cartan type")

        if "generators" in options:
            generators = tuple(
                tuple(x) if isinstance(x, list) else x
                for x in options["generators"])

            if all(c in RegularCrystals() for c in crystals):
                return TensorProductOfRegularCrystalsWithGenerators(
                    crystals, generators, cartan_type)
            return TensorProductOfCrystalsWithGenerators(
                crystals, generators, cartan_type)

        # Flatten out tensor products
        tp = sum([
            B.crystals if isinstance(B, FullTensorProductOfCrystals) else (B, )
            for B in crystals
        ], ())

        if all(c in RegularCrystals() for c in crystals):
            return FullTensorProductOfRegularCrystals(tp,
                                                      cartan_type=cartan_type)
        return FullTensorProductOfCrystals(tp, cartan_type=cartan_type)
Exemplo n.º 11
0
    def __classcall_private__(cls, cartan_type, shapes=None, shape=None):
        """
        Normalizes the input arguments to ensure unique representation,
        and to delegate the construction of spin tableaux.

        EXAMPLES::

            sage: T1 = crystals.Tableaux(CartanType(['A',3]), shape  = [2,2])
            sage: T2 = crystals.Tableaux(['A',3],             shape  = (2,2))
            sage: T3 = crystals.Tableaux(['A',3],             shapes = ([2,2],))
            sage: T2 is T1, T3 is T1
            (True, True)

            sage: T1 = crystals.Tableaux(['A', [1,1]], shape=[3,1,1,1])
            sage: T1
            Crystal of BKK tableaux of shape [3, 1, 1, 1] of gl(2|2)
            sage: T2 = crystals.Tableaux(['A', [1,1]], [3,1,1,1])
            sage: T1 is T2
            True
        """
        cartan_type = CartanType(cartan_type)
        if cartan_type.letter == 'A' and isinstance(cartan_type,
                                                    SuperCartanType_standard):
            if shape is None:
                shape = shapes
            from sage.combinat.crystals.bkk_crystals import CrystalOfBKKTableaux
            return CrystalOfBKKTableaux(cartan_type, shape=shape)
        n = cartan_type.rank()
        # standardize shape/shapes input into a tuple of tuples
        assert operator.xor(shape is not None, shapes is not None)
        if shape is not None:
            shapes = (shape, )
        spin_shapes = tuple(tuple(shape) for shape in shapes)
        try:
            shapes = tuple(
                tuple(trunc(i) for i in shape) for shape in spin_shapes)
        except Exception:
            raise ValueError(
                "shapes should all be partitions or half-integer partitions")
        if spin_shapes == shapes:
            return super(CrystalOfTableaux,
                         cls).__classcall__(cls, cartan_type, shapes)

        # Handle the construction of a crystals of spin tableaux
        # Caveat: this currently only supports all shapes being half
        # integer partitions of length the rank for type B and D. In
        # particular, for type D, the spins all have to be plus or all
        # minus spins
        if any(len(sh) != n for sh in shapes):
            raise ValueError(
                "the length of all half-integer partition shapes should be the rank"
            )
        if any(2 * i % 2 != 1 for shape in spin_shapes for i in shape):
            raise ValueError(
                "shapes should be either all partitions or all half-integer partitions"
            )
        if cartan_type.type() == 'D':
            if all(i >= 0 for shape in spin_shapes for i in shape):
                S = CrystalOfSpinsPlus(cartan_type)
            elif all(shape[-1] < 0 for shape in spin_shapes):
                S = CrystalOfSpinsMinus(cartan_type)
            else:
                raise ValueError(
                    "in type D spins should all be positive or negative")
        else:
            if any(i < 0 for shape in spin_shapes for i in shape):
                raise ValueError("shapes should all be partitions")
            S = CrystalOfSpins(cartan_type)
        B = CrystalOfTableaux(cartan_type, shapes=shapes)
        T = TensorProductOfCrystals(S,
                                    B,
                                    generators=[[S.module_generators[0], x]
                                                for x in B.module_generators])
        T.rename("The crystal of tableaux of type %s and shape(s) %s" %
                 (cartan_type, list(list(shape) for shape in spin_shapes)))
        T.shapes = spin_shapes
        return T
Exemplo n.º 12
0
    def __classcall_private__(cls,
                              R=None,
                              arg0=None,
                              arg1=None,
                              names=None,
                              index_set=None,
                              abelian=False,
                              **kwds):
        """
        Select the correct parent based upon input.

        TESTS::

            sage: LieAlgebra(QQ, abelian=True, names='x,y,z')
            Abelian Lie algebra on 3 generators (x, y, z) over Rational Field
            sage: LieAlgebra(QQ, {('e','h'): {'e':-2}, ('f','h'): {'f':2},
            ....:                 ('e','f'): {'h':1}}, names='e,f,h')
            Lie algebra on 3 generators (e, f, h) over Rational Field
        """
        # Parse associative algebra input
        # -----

        assoc = kwds.get("associative", None)
        if assoc is not None:
            return LieAlgebraFromAssociative(assoc,
                                             names=names,
                                             index_set=index_set)

        # Parse input as a Cartan type
        # -----

        ct = kwds.get("cartan_type", None)
        if ct is not None:
            from sage.combinat.root_system.cartan_type import CartanType
            ct = CartanType(ct)
            if ct.is_affine():
                from sage.algebras.lie_algebras.affine_lie_algebra import AffineLieAlgebra
                return AffineLieAlgebra(R,
                                        cartan_type=ct,
                                        kac_moody=kwds.get("kac_moody", True))
            if not ct.is_finite():
                raise NotImplementedError(
                    "non-finite types are not implemented yet, see trac #14901 for details"
                )
            rep = kwds.get("representation", "bracket")
            if rep == 'bracket':
                from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis
                return LieAlgebraChevalleyBasis(R, ct)
            if rep == 'matrix':
                from sage.algebras.lie_algebras.classical_lie_algebra import ClassicalMatrixLieAlgebra
                return ClassicalMatrixLieAlgebra(R, ct)
            raise ValueError("invalid representation")

        # Parse the remaining arguments
        # -----

        if R is None:
            raise ValueError("invalid arguments")

        check_assoc = lambda A: (isinstance(A, (Ring, MatrixSpace)) or A in
                                 Rings() or A in Algebras(R).Associative())
        if arg0 in ZZ or check_assoc(arg1):
            # Check if we need to swap the arguments
            arg0, arg1 = arg1, arg0

        # Parse the first argument
        # -----

        if isinstance(arg0, dict):
            if not arg0:
                from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra
                return AbelianLieAlgebra(R, names, index_set)
            elif isinstance(arg0.keys()[0], (list, tuple)):
                # We assume it is some structure coefficients
                arg1, arg0 = arg0, arg1

        if isinstance(arg0, (list, tuple)):
            if all(isinstance(x, str) for x in arg0):
                # If they are all strings, then it is a list of variables
                names = tuple(arg0)

        if isinstance(arg0, str):
            names = tuple(arg0.split(','))
        elif isinstance(names, str):
            names = tuple(names.split(','))

        # Parse the second argument

        if isinstance(arg1, dict):
            # Assume it is some structure coefficients
            from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients
            return LieAlgebraWithStructureCoefficients(R, arg1, names,
                                                       index_set, **kwds)

        # Otherwise it must be either a free or abelian Lie algebra

        if arg1 in ZZ:
            if isinstance(arg0, str):
                names = arg0
            if names is None:
                index_set = list(range(arg1))
            else:
                if isinstance(names, str):
                    names = tuple(names.split(','))
                    if arg1 != 1 and len(names) == 1:
                        names = tuple('{}{}'.format(names[0], i)
                                      for i in range(arg1))
                if arg1 != len(names):
                    raise ValueError("the number of names must equal the"
                                     " number of generators")

        if abelian:
            from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra
            return AbelianLieAlgebra(R, names, index_set)

        # Otherwise it is the free Lie algebra
        rep = kwds.get("representation", "bracket")
        if rep == "polynomial":
            # Construct the free Lie algebra from polynomials in the
            #   free (associative unital) algebra
            # TODO: Change this to accept an index set once FreeAlgebra accepts one
            from sage.algebras.free_algebra import FreeAlgebra
            F = FreeAlgebra(R, names)
            if index_set is None:
                index_set = F.variable_names()
            # TODO: As part of #16823, this should instead construct a
            #   subclass with specialized methods for the free Lie algebra
            return LieAlgebraFromAssociative(F,
                                             F.gens(),
                                             names=names,
                                             index_set=index_set)

        raise NotImplementedError("the free Lie algebra has only been"
                                  " implemented using polynomials in the"
                                  " free algebra, see trac ticket #16823")
Exemplo n.º 13
0
    def cartan_type(self):
        r"""
        Returns the Cartan type of the Cartan companion of self.b_matrix()

        Only crystallographic types are implemented

        Warning: this function is redundant but the corresonding method in
        CartanType does not recognize all the types
        """
        A = self.cartan_companion()
        n = self.rk
        degrees_dict = dict(zip(range(n), map(sum, 2 - A)))
        degrees_set = Set(degrees_dict.values())

        types_to_check = [["A", n]]
        if n > 1:
            types_to_check.append(["B", n])
        if n > 2:
            types_to_check.append(["C", n])
        if n > 3:
            types_to_check.append(["D", n])
        if n >= 6 and n <= 8:
            types_to_check.append(["E", n])
        if n == 4:
            types_to_check.append(["F", n])
        if n == 2:
            types_to_check.append(["G", n])
        if n > 1:
            types_to_check.append(["A", n - 1, 1])
            types_to_check.append(["B", n - 1, 1])
            types_to_check.append(["BC", n - 1, 2])
            types_to_check.append(["A", 2 * n - 2, 2])
            types_to_check.append(["A", 2 * n - 3, 2])
        if n > 2:
            types_to_check.append(["C", n - 1, 1])
            types_to_check.append(["D", n, 2])
        if n > 3:
            types_to_check.append(["D", n - 1, 1])
        if n >= 7 and n <= 9:
            types_to_check.append(["E", n - 1, 1])
        if n == 5:
            types_to_check.append(["F", 4, 1])
        if n == 3:
            types_to_check.append(["G", n - 1, 1])
            types_to_check.append(["D", 4, 3])
        if n == 5:
            types_to_check.append(["E", 6, 2])

        for ct_name in types_to_check:
            ct = CartanType(ct_name)
            if 0 not in ct.index_set():
                ct = ct.relabel(dict(zip(range(1, n + 1), range(n))))
            ct_matrix = ct.cartan_matrix()
            ct_degrees_dict = dict(zip(range(n), map(sum, 2 - ct_matrix)))
            if Set(ct_degrees_dict.values()) != degrees_set:
                continue
            for p in Permutations(range(n)):
                relabeling = dict(zip(range(n), p))
                ct_new = ct.relabel(relabeling)
                if ct_new.cartan_matrix() == A:
                    return copy(ct_new)
        raise ValueError("Type not recognized")
Exemplo n.º 14
0
    def __classcall_private__(cls,
                              ambient,
                              contained=None,
                              generators=None,
                              virtualization=None,
                              scaling_factors=None,
                              cartan_type=None,
                              index_set=None,
                              category=None):
        """
        Normalize arguments to ensure a (relatively) unique representation.

        EXAMPLES::

            sage: B = crystals.Tableaux(['A',4], shape=[2,1])
            sage: S1 = B.subcrystal(generators=(B(2,1,1), B(5,2,4)), index_set=[1,2])
            sage: S2 = B.subcrystal(generators=[B(2,1,1), B(5,2,4)], cartan_type=['A',4], index_set=(1,2))
            sage: S1 is S2
            True
        """
        if isinstance(contained, (list, tuple, set, frozenset)):
            contained = frozenset(contained)
        #elif contained in Sets():

        if cartan_type is None:
            cartan_type = ambient.cartan_type()
        else:
            cartan_type = CartanType(cartan_type)
        if index_set is None:
            index_set = cartan_type.index_set
        if generators is None:
            generators = ambient.module_generators

        category = Crystals().or_subcategory(category)
        if ambient in FiniteCrystals() or isinstance(contained, frozenset):
            category = category.Finite()
        if ambient in RegularSuperCrystals():
            category = category & RegularSuperCrystals()

        if virtualization is not None:
            if scaling_factors is None:
                scaling_factors = {i: 1 for i in index_set}
            from sage.combinat.crystals.virtual_crystal import VirtualCrystal
            return VirtualCrystal(ambient, virtualization, scaling_factors,
                                  contained, generators, cartan_type,
                                  index_set, category)
        if scaling_factors is not None:
            # virtualization must be None
            virtualization = {i: (i, ) for i in index_set}
            from sage.combinat.crystals.virtual_crystal import VirtualCrystal
            return VirtualCrystal(ambient, virtualization, scaling_factors,
                                  contained, generators, cartan_type,
                                  index_set, category)

        # We need to give these as optional arguments so it unpickles correctly
        return super(Subcrystal, cls).__classcall__(cls,
                                                    ambient,
                                                    contained,
                                                    tuple(generators),
                                                    cartan_type=cartan_type,
                                                    index_set=tuple(index_set),
                                                    category=category)
Exemplo n.º 15
0
def Associahedron(cartan_type):
    r"""
    Construct an associahedron.

    The generalized associahedron is a polytopal complex with vertices in
    one-to-one correspondence with clusters in the cluster complex, and with
    edges between two vertices if and only if the associated two clusters
    intersect in codimension 1.

    The associahedron of type `A_n` is one way to realize the classical
    associahedron as defined in the :wikipedia:`Associahedron`.

    A polytopal realization of the associahedron can be found in [CFZ2002]_. The
    implementation is based on [CFZ2002]_, Theorem 1.5, Remark 1.6, and Corollary
    1.9.

    EXAMPLES::

        sage: Asso = polytopes.associahedron(['A',2]); Asso
        Generalized associahedron of type ['A', 2] with 5 vertices

        sage: sorted(Asso.Hrepresentation(), key=repr)
        [An inequality (-1, 0) x + 1 >= 0,
         An inequality (0, -1) x + 1 >= 0,
         An inequality (0, 1) x + 1 >= 0,
         An inequality (1, 0) x + 1 >= 0,
         An inequality (1, 1) x + 1 >= 0]

        sage: Asso.Vrepresentation()
        (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1),
         A vertex at (-1, 0), A vertex at (0, -1))

        sage: polytopes.associahedron(['B',2])
        Generalized associahedron of type ['B', 2] with 6 vertices

    The two pictures of [CFZ2002]_ can be recovered with::

        sage: Asso = polytopes.associahedron(['A',3]); Asso
        Generalized associahedron of type ['A', 3] with 14 vertices
        sage: Asso.plot()  # long time
        Graphics3d Object

        sage: Asso = polytopes.associahedron(['B',3]); Asso
        Generalized associahedron of type ['B', 3] with 20 vertices
        sage: Asso.plot()  # long time
        Graphics3d Object

    TESTS::

        sage: sorted(polytopes.associahedron(['A',3]).vertices())
        [A vertex at (-3/2, 0, -1/2), A vertex at (-3/2, 0, 3/2),
         A vertex at (-3/2, 1, -3/2), A vertex at (-3/2, 2, -3/2),
         A vertex at (-3/2, 2, 3/2), A vertex at (-1/2, -1, -1/2),
         A vertex at (-1/2, 0, -3/2), A vertex at (1/2, -2, 1/2),
         A vertex at (1/2, -2, 3/2), A vertex at (3/2, -2, 1/2),
         A vertex at (3/2, -2, 3/2), A vertex at (3/2, 0, -3/2),
         A vertex at (3/2, 2, -3/2), A vertex at (3/2, 2, 3/2)]

        sage: sorted(polytopes.associahedron(['B',3]).vertices())
        [A vertex at (-3, 0, 0), A vertex at (-3, 0, 3),
         A vertex at (-3, 2, -2), A vertex at (-3, 4, -3),
         A vertex at (-3, 5, -3), A vertex at (-3, 5, 3),
         A vertex at (-2, 1, -2), A vertex at (-2, 3, -3),
         A vertex at (-1, -2, 0), A vertex at (-1, -1, -1),
         A vertex at (1, -4, 1), A vertex at (1, -3, 0),
         A vertex at (2, -5, 2), A vertex at (2, -5, 3),
         A vertex at (3, -5, 2), A vertex at (3, -5, 3),
         A vertex at (3, -3, 0), A vertex at (3, 3, -3),
         A vertex at (3, 5, -3), A vertex at (3, 5, 3)]

        sage: polytopes.associahedron(['A',4]).f_vector()
        (1, 42, 84, 56, 14, 1)
        sage: polytopes.associahedron(['B',4]).f_vector()
        (1, 70, 140, 90, 20, 1)
    """
    cartan_type = CartanType(cartan_type)
    parent = Associahedra(QQ, cartan_type.rank(), 'ppl')
    return parent(cartan_type)
Exemplo n.º 16
0
def FundamentalGroupOfExtendedAffineWeylGroup(cartan_type,
                                              prefix='pi',
                                              general_linear=None):
    r"""
    Factory for the fundamental group of an extended affine Weyl group.

    INPUT:

    - ``cartan_type`` -- a Cartan type that is either affine or finite, with the latter being a
      shorthand for the untwisted affinization
    - ``prefix`` (default: 'pi') -- string that labels the elements of the group
    - ``general_linear`` -- (default: None, meaning False) In untwisted type A, if True, use the
      universal central extension

    .. RUBRIC:: Fundamental group

    Associated to each affine Cartan type `\tilde{X}` is an extended affine Weyl group `E`.
    Its subgroup of length-zero elements is called the fundamental group `F`.
    The group `F` can be identified with a subgroup of the group of automorphisms of the
    affine Dynkin diagram. As such, every element of `F` can be viewed as a permutation of the
    set `I` of affine Dynkin nodes.

    Let `0 \in I` be the distinguished affine node; it is the one whose removal produces the
    associated finite Cartan type (call it `X`). A node `i \in I` is called *special*
    if some automorphism of the affine Dynkin diagram, sends `0` to `i`.
    The node `0` is always special due to the identity automorphism.
    There is a bijection of the set of special nodes with the fundamental group. We denote the
    image of `i` by `\pi_i`. The structure of `F` is determined as follows.

    - `\tilde{X}` is untwisted -- `F` is isomorphic to `P^\vee/Q^\vee` where `P^\vee` and `Q^\vee` are the
      coweight and coroot lattices of type `X`. The group `P^\vee/Q^\vee` consists of the cosets `\omega_i^\vee + Q^\vee`
      for special nodes `i`, where `\omega_0^\vee = 0` by convention. In this case the special nodes `i`
      are the *cominuscule* nodes, the ones such that `\omega_i^\vee(\alpha_j)` is `0` or `1` for all `j\in I_0 = I \setminus \{0\}`.
      For `i` special, addition by `\omega_i^\vee+Q^\vee` permutes `P^\vee/Q^\vee` and therefore permutes the set of special nodes.
      This permutation extends uniquely to an automorphism of the affine Dynkin diagram.
    - `\tilde{X}` is dual untwisted -- (that is, the dual of `\tilde{X}` is untwisted) `F` is isomorphic to `P/Q`
      where `P` and `Q` are the weight and root lattices of type `X`. The group `P/Q` consists of the cosets
      `\omega_i + Q` for special nodes `i`, where `\omega_0 = 0` by convention. In this case the special nodes `i`
      are the *minuscule* nodes, the ones such that `\alpha_j^\vee(\omega_i)` is `0` or `1` for all `j \in I_0`.
      For `i` special, addition by `\omega_i+Q` permutes `P/Q` and therefore permutes the set of special nodes.
      This permutation extends uniquely to an automorphism of the affine Dynkin diagram.
    - `\tilde{X}` is mixed -- (that is, not of the above two types) `F` is the trivial group.

    EXAMPLES::

        sage: from sage.combinat.root_system.fundamental_group import FundamentalGroupOfExtendedAffineWeylGroup
        sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1]); F
        Fundamental group of type ['A', 3, 1]
        sage: F.cartan_type().dynkin_diagram()
        0
        O-------+
        |       |
        |       |
        O---O---O
        1   2   3
        A3~
        sage: F.special_nodes()
        (0, 1, 2, 3)
        sage: F(1)^2
        pi[2]
        sage: F(1)*F(2)
        pi[3]
        sage: F(3)^(-1)
        pi[1]

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("B3"); F
        Fundamental group of type ['B', 3, 1]
        sage: F.cartan_type().dynkin_diagram()
            O 0
            |
            |
        O---O=>=O
        1   2   3
        B3~
        sage: F.special_nodes()
        (0, 1)

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("C2"); F
        Fundamental group of type ['C', 2, 1]
        sage: F.cartan_type().dynkin_diagram()
        O=>=O=<=O
        0   1   2
        C2~
        sage: F.special_nodes()
        (0, 2)

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("D4"); F
        Fundamental group of type ['D', 4, 1]
        sage: F.cartan_type().dynkin_diagram()
            O 4
            |
            |
        O---O---O
        1   |2  3
            |
            O 0
        D4~
        sage: F.special_nodes()
        (0, 1, 3, 4)
        sage: (F(4), F(4)^2)
        (pi[4], pi[0])

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("D5"); F
        Fundamental group of type ['D', 5, 1]
        sage: F.cartan_type().dynkin_diagram()
          0 O   O 5
            |   |
            |   |
        O---O---O---O
        1   2   3   4
        D5~
        sage: F.special_nodes()
        (0, 1, 4, 5)
        sage: (F(5), F(5)^2, F(5)^3, F(5)^4)
        (pi[5], pi[1], pi[4], pi[0])
        sage: F = FundamentalGroupOfExtendedAffineWeylGroup("E6"); F
        Fundamental group of type ['E', 6, 1]
        sage: F.cartan_type().dynkin_diagram()
                O 0
                |
                |
                O 2
                |
                |
        O---O---O---O---O
        1   3   4   5   6
        E6~
        sage: F.special_nodes()
        (0, 1, 6)
        sage: F(1)^2
        pi[6]

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['D',4,2]); F
        Fundamental group of type ['C', 3, 1]^*
        sage: F.cartan_type().dynkin_diagram()
        O=<=O---O=>=O
        0   1   2   3
        C3~*
        sage: F.special_nodes()
        (0, 3)

    We also implement a fundamental group for `GL_n`. It is defined to be the group of integers, which is the
    covering group of the fundamental group Z/nZ for affine `SL_n`::

        sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1], general_linear=True); F
        Fundamental group of GL(3)
        sage: x = F.an_element(); x
        pi[5]
        sage: x*x
        pi[10]
        sage: x.inverse()
        pi[-5]
        sage: wt = F.cartan_type().classical().root_system().ambient_space().an_element(); wt
        (2, 2, 3)
        sage: x.act_on_classical_ambient(wt)
        (2, 3, 2)
        sage: w = WeylGroup(F.cartan_type(),prefix="s").an_element(); w
        s0*s1*s2
        sage: x.act_on_affine_weyl(w)
        s2*s0*s1
    """
    cartan_type = CartanType(cartan_type)
    if cartan_type.is_finite():
        cartan_type = cartan_type.affine()
    if not cartan_type.is_affine():
        raise NotImplementedError("Cartan type is not affine")
    if general_linear is True:
        if cartan_type.is_untwisted_affine() and cartan_type.type() == "A":
            return FundamentalGroupGL(cartan_type, prefix)
        else:
            raise ValueError(
                "General Linear Fundamental group is untwisted type A")
    return FundamentalGroupOfExtendedAffineWeylGroup_Class(cartan_type,
                                                           prefix,
                                                           finite=True)
Exemplo n.º 17
0
    def __classcall_private__(cls, *args, **kwds):
        """
        Normalize input so we can inherit from spare integer matrix.

        .. NOTE::

            To disable the Cartan type check, use the optional argument
            ``cartan_type_check = False``.

        EXAMPLES::

            sage: C = CartanMatrix(['A',1,1])
            sage: C2 = CartanMatrix([[2, -2], [-2, 2]])
            sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1])
            sage: C == C2 and C == C3
            True

        TESTS:

        Check that :trac:`15740` is fixed::

            sage: d = DynkinDiagram()
            sage: d.add_edge('a', 'b', 2)
            sage: d.index_set()
            ('a', 'b')
            sage: cm = CartanMatrix(d)
            sage: cm.index_set()
            ('a', 'b')
        """
        # Special case with 0 args and kwds has Cartan type
        if "cartan_type" in kwds and len(args) == 0:
            args = (CartanType(kwds["cartan_type"]), )
        if len(args) == 0:
            data = []
            n = 0
            index_set = tuple()
            cartan_type = None
            subdivisions = None
        elif len(args) == 4 and isinstance(args[0],
                                           MatrixSpace):  # For pickling
            return typecall(cls, args[0], args[1], args[2], args[3])
        elif isinstance(args[0], CartanMatrix):
            return args[0]
        else:
            cartan_type = None
            dynkin_diagram = None
            subdivisions = None

            from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class
            if isinstance(args[0], DynkinDiagram_class):
                dynkin_diagram = args[0]
                cartan_type = args[0]._cartan_type
            else:
                try:
                    cartan_type = CartanType(args[0])
                    dynkin_diagram = cartan_type.dynkin_diagram()
                except (TypeError, ValueError):
                    pass

            if dynkin_diagram is not None:
                n = dynkin_diagram.rank()
                index_set = dynkin_diagram.index_set()
                reverse = dict(
                    (index_set[i], i) for i in range(len(index_set)))
                data = {(i, i): 2 for i in range(n)}
                for (i, j, l) in dynkin_diagram.edge_iterator():
                    data[(reverse[j], reverse[i])] = -l
            else:
                M = matrix(args[0])
                if not is_generalized_cartan_matrix(M):
                    raise ValueError(
                        "the input matrix is not a generalized Cartan matrix")
                n = M.ncols()
                if "cartan_type" in kwds:
                    cartan_type = CartanType(kwds["cartan_type"])
                elif n == 1:
                    cartan_type = CartanType(['A', 1])
                elif kwds.get("cartan_type_check", True):
                    cartan_type = find_cartan_type_from_matrix(M)
                data = M.dict()
                subdivisions = M._subdivisions

            if len(args) == 1:
                if cartan_type is not None:
                    index_set = tuple(cartan_type.index_set())
                elif dynkin_diagram is None:
                    index_set = tuple(range(n))
            elif len(args) == 2:
                index_set = tuple(args[1])
                if len(index_set) != n and len(set(index_set)) != n:
                    raise ValueError("the given index set is not valid")
            else:
                raise ValueError("too many arguments")

        mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, cartan_type,
                       index_set)
        mat._subdivisions = subdivisions
        return mat
Exemplo n.º 18
0
def CoxeterGroup(data, implementation=None, base_ring=None, index_set=None):
    """
    Return an implementation of the Coxeter group given by ``data``.

    INPUT:

    - ``data`` -- a cartan type (or coercible into; see :class:`CartanType`)
      or a Coxeter matrix or graph

    - ``implementation`` -- (default: ``None``) can be one of the following:

      * "permutation" - as a permutation representation
      * "matrix" - as a Weyl group (as a matrix group acting on the root space);
        if this is not implemented, this uses the "reflection" implementation
      * "coxeter3" - using the coxeter3 package
      * "reflection" - as elements in the reflection representation; see
        :class:`~sage.groups.matrix_gps.coxeter_groups.CoxeterMatrixGroup`
      * ``None`` - choose "permutation" representation if possible, else
        default to "matrix"

    - ``base_ring`` -- (optional) the base ring for the "reflection"
      implementation

    - ``index_set`` -- (optional) the index set for the "reflection"
      implementation

    EXAMPLES:

    Now assume that ``data`` represents a Cartan type. If
    ``implementation`` is not specified, a permutation
    representation is returned whenever possible (finite irreducible
    Cartan type, with the GAP3 Chevie package available)::

        sage: W = CoxeterGroup(["A",2])
        sage: W                                   # optional - chevie
        Permutation Group with generators [(1,3)(2,5)(4,6), (1,4)(2,3)(5,6)]

    Otherwise, a matrix representation is returned::

        sage: W = CoxeterGroup(["A",3,1])
        sage: W
        Weyl Group of type ['A', 3, 1] (as a matrix group acting on the root space)
        sage: W = CoxeterGroup(['H',3])
        sage: W
        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3 2]
        [3 1 5]
        [2 5 1]

    We now use the ``implementation`` option::

        sage: W = CoxeterGroup(["A",2], implementation = "permutation") # optional - chevie
        sage: W                                                         # optional - chevie
        Permutation Group with generators [(1,3)(2,5)(4,6), (1,4)(2,3)(5,6)]
        sage: W.category()                       # optional - chevie
        Join of Category of finite permutation groups and Category of finite coxeter groups

        sage: W = CoxeterGroup(["A",2], implementation = "matrix")
        sage: W
        Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space)

        sage: W = CoxeterGroup(["H",3], implementation = "matrix")
        sage: W
        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3 2]
        [3 1 5]
        [2 5 1]

        sage: W = CoxeterGroup(["H",3], implementation="reflection")
        sage: W
        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3 2]
        [3 1 5]
        [2 5 1]

        sage: W = CoxeterGroup(["A",4,1], implementation = "permutation")
        Traceback (most recent call last):
        ...
        NotImplementedError: Coxeter group of type ['A', 4, 1] as permutation group not implemented

    We use the different options for the "reflection" implementation::

        sage: W = CoxeterGroup(["H",3], implementation="reflection", base_ring=RR)
        sage: W
        Coxeter group over Real Field with 53 bits of precision with Coxeter matrix:
        [1 3 2]
        [3 1 5]
        [2 5 1]
        sage: W = CoxeterGroup([[1,10],[10,1]], implementation="reflection", index_set=['a','b'], base_ring=SR)
        sage: W
        Coxeter group over Symbolic Ring with Coxeter matrix:
        [ 1 10]
        [10  1]
    """
    if implementation not in [
            "permutation", "matrix", "coxeter3", "reflection", None
    ]:
        raise ValueError("invalid type implementation")

    try:
        cartan_type = CartanType(data)
    except (
            TypeError, ValueError
    ):  # If it is not a Cartan type, try to see if we can represent it as a matrix group
        return CoxeterMatrixGroup(data, base_ring, index_set)

    if implementation is None:
        if cartan_type.is_finite() and cartan_type.is_irreducible(
        ) and is_chevie_available():
            implementation = "permutation"
        else:
            implementation = "matrix"

    if implementation == "reflection":
        return CoxeterMatrixGroup(cartan_type, base_ring, index_set)
    if implementation == "coxeter3":
        try:
            from sage.libs.coxeter3.coxeter_group import CoxeterGroup
        except ImportError:
            raise RuntimeError("coxeter3 must be installed")
        else:
            return CoxeterGroup(cartan_type)
    if implementation == "permutation" and is_chevie_available() and \
       cartan_type.is_finite() and cartan_type.is_irreducible():
        return CoxeterGroupAsPermutationGroup(cartan_type)
    elif implementation == "matrix":
        if cartan_type.is_crystallographic():
            return WeylGroup(cartan_type)
        return CoxeterMatrixGroup(cartan_type, base_ring, index_set)

    raise NotImplementedError(
        "Coxeter group of type %s as %s group not implemented " %
        (cartan_type, implementation))
Exemplo n.º 19
0
def WeylGroup(x, prefix=None, implementation='matrix'):
    """
    Returns the Weyl group of the root system defined by the Cartan
    type (or matrix) ``ct``.

    INPUT:

    - ``x`` - a root system or a Cartan type (or matrix)

    OPTIONAL:

    - ``prefix`` -- changes the representation of elements from matrices
      to products of simple reflections

    - ``implementation`` -- one of the following:
      * ``'matrix'`` - as matrices acting on a root system
      * ``"permutation"`` - as a permutation group acting on the roots

    EXAMPLES:

    The following constructions yield the same result, namely
    a weight lattice and its corresponding Weyl group::

        sage: G = WeylGroup(['F',4])
        sage: L = G.domain()

    or alternatively and equivalently::

        sage: L = RootSystem(['F',4]).ambient_space()
        sage: G = L.weyl_group()
        sage: W = WeylGroup(L)

    Either produces a weight lattice, with access to its roots and
    weights.

    ::

        sage: G = WeylGroup(['F',4])
        sage: G.order()
        1152
        sage: [s1,s2,s3,s4] = G.simple_reflections()
        sage: w = s1*s2*s3*s4; w
        [ 1/2  1/2  1/2  1/2]
        [-1/2  1/2  1/2 -1/2]
        [ 1/2  1/2 -1/2 -1/2]
        [ 1/2 -1/2  1/2 -1/2]
        sage: type(w) == G.element_class
        True
        sage: w.order()
        12
        sage: w.length() # length function on Weyl group
        4

    The default representation of Weyl group elements is as matrices.
    If you prefer, you may specify a prefix, in which case the
    elements are represented as products of simple reflections.

    ::

        sage: W=WeylGroup("C3",prefix="s")
        sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output
        sage: s2*s1*s2*s3
        s1*s2*s3*s1
        sage: s2*s1*s2*s3 == s1*s2*s3*s1
        True
        sage: (s2*s3)^2==(s3*s2)^2
        True
        sage: (s1*s2*s3*s1).matrix()
        [ 0  0 -1]
        [ 0  1  0]
        [ 1  0  0]

    ::

        sage: L = G.domain()
        sage: fw = L.fundamental_weights(); fw
        Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)}
        sage: rho = sum(fw); rho
        (11/2, 5/2, 3/2, 1/2)
        sage: w.action(rho) # action of G on weight lattice
        (5, -1, 3, 2)

    We can also do the same for arbitrary Cartan matrices::

        sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]])
        sage: W = WeylGroup(cm)
        sage: W.gens()
        (
        [-1  5  0]  [ 1  0  0]  [ 1  0  0]
        [ 0  1  0]  [ 2 -1  1]  [ 0  1  0]
        [ 0  0  1], [ 0  0  1], [ 0  1 -1]
        )
        sage: s0,s1,s2 = W.gens()
        sage: s1*s2*s1
        [ 1  0  0]
        [ 2  0 -1]
        [ 2 -1  0]
        sage: s2*s1*s2
        [ 1  0  0]
        [ 2  0 -1]
        [ 2 -1  0]
        sage: s0*s1*s0*s2*s0
        [ 9  0 -5]
        [ 2  0 -1]
        [ 0  1 -1]

    Same Cartan matrix, but with a prefix to display using simple reflections::

        sage: W = WeylGroup(cm, prefix='s')
        sage: s0,s1,s2 = W.gens()
        sage: s0*s2*s1
        s2*s0*s1
        sage: (s1*s2)^3
        1
        sage: (s0*s1)^5
        s0*s1*s0*s1*s0*s1*s0*s1*s0*s1
        sage: s0*s1*s2*s1*s2
        s2*s0*s1
        sage: s0*s1*s2*s0*s2
        s0*s1*s0

    TESTS::

        sage: TestSuite(WeylGroup(["A",3])).run()
        sage: TestSuite(WeylGroup(["A",3,1])).run() # long time

        sage: W = WeylGroup(['A',3,1])
        sage: s = W.simple_reflections()
        sage: w = s[0]*s[1]*s[2]
        sage: w.reduced_word()
        [0, 1, 2]
        sage: w = s[0]*s[2]
        sage: w.reduced_word()
        [2, 0]
        sage: W = groups.misc.WeylGroup(['A',3,1])
    """
    if implementation == "permutation":
        return WeylGroup_permutation(x, prefix)
    elif implementation != "matrix":
        raise ValueError("invalid implementation")

    if x in RootLatticeRealizations:
        return WeylGroup_gens(x, prefix=prefix)

    try:
        ct = CartanType(x)
    except TypeError:
        ct = CartanMatrix(x)  # See if it is a Cartan matrix
    if ct.is_finite():
        return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix)
    return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
Exemplo n.º 20
0
def WeylGroup(x, prefix=None):
    """
    Returns the Weyl group of type ct.
    
    INPUT:

    - ``ct`` - a Cartan Type.
    
    OPTIONAL:

    - ``prefix`` - changes the representation of elements from matrices
      to products of simple reflections
    
    EXAMPLES: The following constructions yield the same result, namely
    a weight lattice and its corresponding Weyl group::
    
        sage: G = WeylGroup(['F',4])
        sage: L = G.domain()
    
    or alternatively and equivalently::
    
        sage: L = RootSystem(['F',4]).ambient_space()
        sage: G = L.weyl_group()
    
    Either produces a weight lattice, with access to its roots and
    weights.
    
    ::
    
        sage: G = WeylGroup(['F',4])
        sage: G.order()
        1152
        sage: [s1,s2,s3,s4] = G.simple_reflections()
        sage: w = s1*s2*s3*s4; w
        [ 1/2  1/2  1/2  1/2]
        [-1/2  1/2  1/2 -1/2]
        [ 1/2  1/2 -1/2 -1/2]
        [ 1/2 -1/2  1/2 -1/2]
        sage: type(w) == G.element_class
        True
        sage: w.order()
        12
        sage: w.length() # length function on Weyl group
        4

    The default representation of Weyl group elements is as matrices.
    If you prefer, you may specify a prefix, in which case the
    elements are represented as products of simple reflections.

    ::

        sage: W=WeylGroup("C3",prefix="s")
        sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output
        sage: s2*s1*s2*s3
        s1*s2*s3*s1
        sage: s2*s1*s2*s3 == s1*s2*s3*s1
        True
        sage: (s2*s3)^2==(s3*s2)^2
        True
        sage: (s1*s2*s3*s1).matrix()
        [ 0  0 -1]
        [ 0  1  0]
        [ 1  0  0]

    ::

        sage: L = G.domain()
        sage: fw = L.fundamental_weights(); fw
        Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)}
        sage: rho = sum(fw); rho
        (11/2, 5/2, 3/2, 1/2)
        sage: w.action(rho) # action of G on weight lattice
        (5, -1, 3, 2)

    TESTS::

        sage: TestSuite(WeylGroup(["A",3])).run()
        sage: TestSuite(WeylGroup(["A",3, 1])).run()

        sage: W=WeylGroup(['A',3,1])
        sage: s=W.simple_reflections()
        sage: w=s[0]*s[1]*s[2]
        sage: w.reduced_word()
        [0, 1, 2]
        sage: w=s[0]*s[2]
        sage: w.reduced_word()
        [2, 0]
    """
    if x in RootLatticeRealizations:
        return WeylGroup_gens(x, prefix=prefix)

    ct = CartanType(x)
    if ct.is_affine():
        return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
    else:
        return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix)
Exemplo n.º 21
0
def CoxeterGroup(data,
                 implementation="reflection",
                 base_ring=None,
                 index_set=None):
    """
    Return an implementation of the Coxeter group given by ``data``.

    INPUT:

    - ``data`` -- a Cartan type (or coercible into; see :class:`CartanType`)
      or a Coxeter matrix or graph

    - ``implementation`` -- (default: ``'reflection'``) can be one of
      the following:

      * ``'permutation'`` - as a permutation representation
      * ``'matrix'`` - as a Weyl group (as a matrix group acting on the
        root space); if this is not implemented, this uses the "reflection"
        implementation
      * ``'coxeter3'`` - using the coxeter3 package
      * ``'reflection'`` - as elements in the reflection representation; see
        :class:`~sage.groups.matrix_gps.coxeter_groups.CoxeterMatrixGroup`

    - ``base_ring`` -- (optional) the base ring for the ``'reflection'``
      implementation

    - ``index_set`` -- (optional) the index set for the ``'reflection'``
      implementation

    EXAMPLES:

    Now assume that ``data`` represents a Cartan type. If
    ``implementation`` is not specified, the reflection representation
    is returned::

        sage: W = CoxeterGroup(["A",2])
        sage: W
        Finite Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3]
        [3 1]

        sage: W = CoxeterGroup(["A",3,1]); W
        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3 2 3]
        [3 1 3 2]
        [2 3 1 3]
        [3 2 3 1]

        sage: W = CoxeterGroup(['H',3]); W
        Finite Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3 2]
        [3 1 5]
        [2 5 1]

    We now use the ``implementation`` option::

        sage: W = CoxeterGroup(["A",2], implementation = "permutation") # optional - gap3
        sage: W                                                         # optional - gap3
        Permutation Group with generators [(1,3)(2,5)(4,6), (1,4)(2,3)(5,6)]
        sage: W.category()                       # optional - gap3
        Join of Category of finite permutation groups
             and Category of finite coxeter groups
             and Category of well generated finite irreducible complex reflection groups

        sage: W = CoxeterGroup(["A",2], implementation="matrix")
        sage: W
        Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space)

        sage: W = CoxeterGroup(["H",3], implementation="matrix")
        sage: W
        Finite Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3 2]
        [3 1 5]
        [2 5 1]

        sage: W = CoxeterGroup(["H",3], implementation="reflection")
        sage: W
        Finite Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
        [1 3 2]
        [3 1 5]
        [2 5 1]

        sage: W = CoxeterGroup(["A",4,1], implementation="permutation")
        Traceback (most recent call last):
        ...
        NotImplementedError: Coxeter group of type ['A', 4, 1] as permutation group not implemented

        sage: W = CoxeterGroup(["A",4], implementation="chevie"); W     # optional - gap3
        Irreducible real reflection group of rank 4 and type A4

    We use the different options for the "reflection" implementation::

        sage: W = CoxeterGroup(["H",3], implementation="reflection", base_ring=RR)
        sage: W
        Finite Coxeter group over Real Field with 53 bits of precision with Coxeter matrix:
        [1 3 2]
        [3 1 5]
        [2 5 1]
        sage: W = CoxeterGroup([[1,10],[10,1]], implementation="reflection", index_set=['a','b'], base_ring=SR)
        sage: W
        Finite Coxeter group over Symbolic Ring with Coxeter matrix:
        [ 1 10]
        [10  1]

    TESTS::

        sage: W = groups.misc.CoxeterGroup(["H",3])
    """
    if implementation not in [
            "permutation", "matrix", "coxeter3", "reflection", "chevie", None
    ]:
        raise ValueError("invalid type implementation")

    try:
        cartan_type = CartanType(data)
    except (
            TypeError, ValueError
    ):  # If it is not a Cartan type, try to see if we can represent it as a matrix group
        return CoxeterMatrixGroup(data, base_ring, index_set)

    if implementation is None:
        implementation = "matrix"

    if implementation == "reflection":
        return CoxeterMatrixGroup(cartan_type, base_ring, index_set)
    if implementation == "coxeter3":
        try:
            from sage.libs.coxeter3.coxeter_group import CoxeterGroup
        except ImportError:
            raise RuntimeError("coxeter3 must be installed")
        else:
            return CoxeterGroup(cartan_type)
    if implementation == "permutation" and is_chevie_available() and \
       cartan_type.is_finite() and cartan_type.is_irreducible():
        return CoxeterGroupAsPermutationGroup(cartan_type)
    elif implementation == "matrix":
        if cartan_type.is_crystallographic():
            return WeylGroup(cartan_type)
        return CoxeterMatrixGroup(cartan_type, base_ring, index_set)
    elif implementation == "chevie":
        from sage.combinat.root_system.reflection_group_real import ReflectionGroup
        return ReflectionGroup(data, index_set=index_set)

    raise NotImplementedError(
        "Coxeter group of type {} as {} group not implemented".format(
            cartan_type, implementation))
Exemplo n.º 22
0
    def __classcall_private__(cls, data, base_ring=None, index_set=None):
        """
        Normalize arguments to ensure a unique representation.

        EXAMPLES::

            sage: W1 = CoxeterGroup(['A',2], implementation="reflection", base_ring=UniversalCyclotomicField())
            sage: W2 = CoxeterGroup([[1,3],[3,1]], index_set=(1,2))
            sage: W1 is W2
            True
            sage: G1 = Graph([(1,2)])
            sage: W3 = CoxeterGroup(G1)
            sage: W1 is W3
            True
            sage: G2 = Graph([(1,2,3)])
            sage: W4 = CoxeterGroup(G2)
            sage: W1 is W4
            True

        Check with `\infty` because of the hack of using `-1` to represent
        `\infty` in the Coxeter matrix::

            sage: G = Graph([(0, 1, 3), (1, 2, oo)])
            sage: W1 = CoxeterGroup(matrix([[1, 3, 2], [3,1,-1], [2,-1,1]]))
            sage: W2 = CoxeterGroup(G)
            sage: W1 is W2
            True
            sage: CoxeterGroup(W1.coxeter_graph()) is W1
            True
        """
        if isinstance(data, CartanType_abstract):
            if index_set is None:
                index_set = data.index_set()
            data = data.coxeter_matrix()
        elif isinstance(data, Graph):
            G = data
            n = G.num_verts()

            # Setup the basis matrix as all 2 except 1 on the diagonal
            data = matrix(ZZ, [[2] * n] * n)
            for i in range(n):
                data[i, i] = ZZ.one()

            verts = G.vertices()
            for e in G.edges():
                m = e[2]
                if m is None:
                    m = 3
                elif m == infinity or m == -1:  # FIXME: Hack because there is no ZZ\cup\{\infty\}
                    m = -1
                elif m <= 1:
                    raise ValueError("invalid Coxeter graph label")
                i = verts.index(e[0])
                j = verts.index(e[1])
                data[j, i] = data[i, j] = m

            if index_set is None:
                index_set = G.vertices()
        else:
            try:
                data = matrix(data)
            except (ValueError, TypeError):
                data = CartanType(data).coxeter_matrix()
            if not data.is_symmetric():
                raise ValueError("the Coxeter matrix is not symmetric")
            if any(d != 1 for d in data.diagonal()):
                raise ValueError("the Coxeter matrix diagonal is not all 1")
            if any(val <= 1 and val != -1 for i, row in enumerate(data.rows())
                   for val in row[i + 1:]):
                raise ValueError("invalid Coxeter label")

            if index_set is None:
                index_set = range(data.nrows())

        if base_ring is None:
            base_ring = UniversalCyclotomicField()
        data.set_immutable()
        return super(CoxeterMatrixGroup,
                     cls).__classcall__(cls, data, base_ring, tuple(index_set))