Пример #1
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 = CrystalOfTableaux(CartanType(['A',3]), shape  = [2,2])
            sage: T2 = CrystalOfTableaux(['A',3],             shape  = (2,2))
            sage: T3 = CrystalOfTableaux(['A',3],             shapes = ([2,2],))
            sage: T2 is T1, T3 is T1
            (True, True)
        """
        cartan_type = CartanType(cartan_type)
        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 StandardError:
            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
        assert all(len(sh) == n for sh in shapes), \
            "the length of all half-integer partition shapes should be the rank"
        assert all(2*i % 2 == 1 for shape in spin_shapes for i in shape), \
            "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:
            assert all( i >= 0 for shape in spin_shapes for i in shape), \
                "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
Пример #2
0
    def __classcall_private__(cls, cartan_type):
        """
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: B = crystals.infinity.Tableaux(['A',4])
            sage: B2 = crystals.infinity.Tableaux(CartanType(['A',4]))
            sage: B is B2
            True
        """
        cartan_type = CartanType(cartan_type)
        if cartan_type.type() == 'D':
            return InfinityCrystalOfTableauxTypeD(cartan_type)
        if cartan_type.type() == 'Q':
            return DualInfinityQueerCrystalOfTableaux(cartan_type)
        return super(InfinityCrystalOfTableaux, cls).__classcall__(cls, cartan_type)
Пример #3
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 = CrystalOfTableaux(CartanType(['A',3]), shape  = [2,2])
            sage: T2 = CrystalOfTableaux(['A',3],             shape  = (2,2))
            sage: T3 = CrystalOfTableaux(['A',3],             shapes = ([2,2],))
            sage: T2 is T1, T3 is T1
            (True, True)
        """
        cartan_type = CartanType(cartan_type)
        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 StandardError:
            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
        assert all(len(sh) == n for sh in shapes), \
            "the length of all half-integer partition shapes should be the rank"
        assert all(2*i % 2 == 1 for shape in spin_shapes for i in shape), \
            "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:
            assert all( i >= 0 for shape in spin_shapes for i in shape), \
                "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
Пример #4
0
    def __classcall_private__(cls, cartan_type):
        """
        Normalize input to ensure a unique representation.

        EXAMPLES::

            sage: B = crystals.infinity.Tableaux(['A',4])
            sage: B2 = crystals.infinity.Tableaux(CartanType(['A',4]))
            sage: B is B2
            True
        """
        cartan_type = CartanType(cartan_type)
        if cartan_type.type() == 'D':
            return InfinityCrystalOfTableauxTypeD(cartan_type)
        return super(InfinityCrystalOfTableaux, cls).__classcall__(cls, cartan_type)
Пример #5
0
    def __classcall_private__(cls, R, cartan_type):
        """
        Return the correct parent based on input.

        EXAMPLES::

            sage: lie_algebras.ClassicalMatrix(QQ, ['A', 4])
            Special linear Lie algebra of rank 5 over Rational Field
            sage: lie_algebras.ClassicalMatrix(QQ, CartanType(['B',4]))
            Special orthogonal Lie algebra of rank 9 over Rational Field
            sage: lie_algebras.ClassicalMatrix(QQ, 'C4')
            Symplectic Lie algebra of rank 8 over Rational Field
            sage: lie_algebras.ClassicalMatrix(QQ, cartan_type=['D',4])
            Special orthogonal Lie algebra of rank 8 over Rational Field
        """
        if isinstance(cartan_type, (CartanMatrix, DynkinDiagram_class)):
            cartan_type = cartan_type.cartan_type()
        else:
            cartan_type = CartanType(cartan_type)

        if not cartan_type.is_finite():
            raise ValueError("only for finite types")

        if cartan_type.type() == 'A':
            return sl(R, cartan_type.rank() + 1)
        if cartan_type.type() == 'B':
            return so(R, 2*cartan_type.rank() + 1)
        if cartan_type.type() == 'C':
            return sp(R, 2*cartan_type.rank())
        if cartan_type.type() == 'D':
            return so(R, 2*cartan_type.rank())
        if cartan_type.type() == 'E':
            if cartan_type.rank() == 6:
                return e6(R)
            if cartan_type.rank() in [7,8]:
                raise NotImplementedError("not yet implemented")
        if cartan_type.type() == 'F' and cartan_type.rank() == 4:
            return f4(R)
        if cartan_type.type() == 'G' and cartan_type.rank() == 2:
            return g2(R)
        raise ValueError("invalid Cartan type")
Пример #6
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)
Пример #7
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
            shape = _Partitions(shape)
            from sage.combinat.crystals.bkk_crystals import CrystalOfBKKTableaux
            return CrystalOfBKKTableaux(cartan_type, shape=shape)
        if cartan_type.letter == 'Q':
            if any(shape[i] == shape[i + 1] for i in range(len(shape) - 1)):
                raise ValueError("not a strict partition")
            shape = _Partitions(shape)
            return CrystalOfQueerTableaux(cartan_type, shape=shape)
        n = cartan_type.rank()
        # standardize shape/shapes input into a tuple of tuples
        # of length n, or n+1 in type A
        assert operator.xor(shape is not None, shapes is not None)
        if shape is not None:
            shapes = (shape, )
        if cartan_type.type() == "A":
            n1 = n + 1
        else:
            n1 = n
        if not all(all(i == 0 for i in shape[n1:]) for shape in shapes):
            raise ValueError(
                "shapes should all have length at most equal to the rank or the rank + 1 in type A"
            )
        spin_shapes = tuple((tuple(shape) + (0, ) * (n1 - len(shape)))[:n1]
                            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:
            shapes = tuple(
                _Partitions(shape) if shape[n1 - 1] in NN else shape
                for shape in 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 any(
                any(i < j
                    for i, j in zip(shape, shape[1:-1] + (abs(shape[-1]), )))
                for shape in spin_shapes):
            raise ValueError("entries of each shape must be weakly decreasing")
        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
Пример #8
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)