Ticket #15375: trac_15375-extended_affine_weyl_groups_sd40.patch

File trac_15375-extended_affine_weyl_groups_sd40.patch, 135.2 KB (added by bump, 8 years ago)

Implements Extended Affine Iwahori Hecke Algebras

  • src/sage/combinat/root_system/all.py

    From 2ede54367afaa2a553ec70e356a59bdd35ceb0a5 Mon Sep 17 00:00:00 2001
    From: Sage-combinat <[bump@match.stanford.edu]>
    Date: Wed, 6 Nov 2013 20:37:47 +0000
    Subject: [PATCH] imported patch extended_affine_weyl_groups_sd40.patch
    
    ---
     src/sage/combinat/root_system/all.py               |    2 +
     src/sage/combinat/root_system/ambient_space.py     |   62 +
     .../root_system/extended_affine_weyl_group.py      | 2185 ++++++++++++++++++++
     src/sage/combinat/root_system/fundamental_group.py |  334 +++
     .../root_system/root_lattice_realizations.py       |  151 +-
     src/sage/combinat/root_system/root_space.py        |   44 +-
     src/sage/combinat/root_system/type_affine.py       |    8 +
     src/sage/combinat/root_system/weight_space.py      |   47 +
     src/sage/groups/group_exp.py                       |  247 +++
     src/sage/groups/group_semidirect_product.py        |  242 +++
     10 files changed, 3307 insertions(+), 15 deletions(-)
     create mode 100644 src/sage/combinat/root_system/extended_affine_weyl_group.py
     create mode 100644 src/sage/combinat/root_system/fundamental_group.py
     create mode 100644 src/sage/groups/group_exp.py
     create mode 100644 src/sage/groups/group_semidirect_product.py
    
    diff --git a/src/sage/combinat/root_system/all.py b/src/sage/combinat/root_system/all.py
    index 8839a43..5326036 100644
    a b from cartan_matrix import CartanMatrix, cartan_matrix 
    77from coxeter_matrix import coxeter_matrix
    88from root_system import RootSystem, WeylDim
    99from weyl_group import WeylGroup, WeylGroupElement
     10from extended_affine_weyl_group import ExtendedAffineWeylGroup, ExtendedAffineWeylGroup_Class
     11from fundamental_group import FundamentalGroupOfExtendedAffineWeylGroup
    1012from coxeter_group import CoxeterGroup
    1113from weyl_characters import WeylCharacterRing, branch_weyl_character, branching_rule_from_plethysm, get_branching_rule, WeightRing
    1214lazy_import('sage.combinat.root_system.non_symmetric_macdonald_polynomials', 'NonSymmetricMacdonaldPolynomials')
  • src/sage/combinat/root_system/ambient_space.py

    diff --git a/src/sage/combinat/root_system/ambient_space.py b/src/sage/combinat/root_system/ambient_space.py
    index 180a5a7..c7f8a3e 100644
    a b from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFree 
    1313from weight_lattice_realizations import WeightLatticeRealizations
    1414from sage.rings.all import ZZ, QQ
    1515from sage.misc.cachefunc import ClearCacheOnPickle
     16from sage.modules.free_module_element import vector
    1617
    1718class AmbientSpace(ClearCacheOnPickle, CombinatorialFreeModule):
    1819    r"""
    class AmbientSpace(ClearCacheOnPickle, CombinatorialFreeModule): 
    335336                x = x.coerce_to_sl()
    336337        return x
    337338
     339    def to_ambient_space_morphism(self):
     340        r"""
     341        Return the identity map on ``self``.
     342
     343        This is present for uniformity of use; the corresponding method
     344        for abstract root and weight lattices/spaces, is not trivial.
     345
     346        """
     347        def id(x):
     348            return x
     349        return id
     350
    338351class AmbientSpaceElement(CombinatorialFreeModuleElement):
    339352    def __hash__(self):
    340353        """
    class AmbientSpaceElement(CombinatorialFreeModuleElement): 
    482495        x = x - (x.inner_product(v0)/2)*v0
    483496        return  x - (x.inner_product(v1)/6)*v1
    484497
     498    def to_weight_space(self, base_ring = None):
     499        r"""
     500        Map ``self`` to the weight space.
     501
     502        ..warning::
     503
     504            Implemented for finite Cartan type.
     505
     506        EXAMPLES::
     507
     508            sage: b = CartanType(['B',2]).root_system().ambient_space().from_vector(vector([1,-2])); b
     509            (1, -2)
     510            sage: b.to_weight_space()
     511            3*Lambda[1] - 4*Lambda[2]
     512            sage: b = CartanType(['B',2]).root_system().ambient_space().from_vector(vector([1/2,0])); b
     513            (1/2, 0)
     514            sage: b.to_weight_space()
     515            1/2*Lambda[1]
     516            sage: b.to_weight_space(ZZ)
     517            Traceback (most recent call last):
     518            ...
     519            TypeError: no conversion of this rational to integer
     520            sage: b = CartanType(['G',2]).root_system().ambient_space().from_vector(vector([4,-5,1])); b
     521            (4, -5, 1)
     522            sage: b.to_weight_space()
     523            -6*Lambda[1] + 5*Lambda[2]
     524
     525        """
     526        L = self.parent()
     527        if base_ring is None:
     528            base_ring = L.base_ring()
     529        return L.root_system.weight_lattice().from_vector(vector(base_ring, [self.scalar(v) for v in L.simple_coroots()]))
     530
     531    def to_ambient(self):
     532        r"""
     533        Map ``self`` to the ambient space.
     534
     535        This exists for uniformity. Its analogue for root and weight lattice realizations,
     536        is not trivial.
     537
     538        EXAMPLES::
     539
     540            sage: v = CartanType(['C',3]).root_system().ambient_space().an_element(); v
     541            (2, 2, 3)
     542            sage: v.to_ambient()
     543            (2, 2, 3)
     544
     545        """
     546        return self
  • new file src/sage/combinat/root_system/extended_affine_weyl_group.py

    diff --git a/src/sage/combinat/root_system/extended_affine_weyl_group.py b/src/sage/combinat/root_system/extended_affine_weyl_group.py
    new file mode 100644
    index 0000000..b0d2b2a
    - +  
     1"""
     2Extended Affine Weyl Groups
     3
     4AUTHORS:
     5
     6- Daniel Bump (2012): initial version
     7- Daniel Orr (2012): initial version
     8- Anne Schilling (2012): initial version
     9- Mark Shimozono (2012): initial version
     10- Nicolas Thiery (2012): initial version
     11- Mark Shimozono (2013): twisted affine root systems, multiple realizations
     12
     13"""
     14
     15#*****************************************************************************
     16#       Copyright (C) 2012 Daniel Bump <bump at match.stanford.edu>,
     17#                     2012 Daniel Orr <danorr at live.unc.edu>
     18#                     2012 Anne Schilling <anne at math.ucdavis.edu>
     19#                     2012 Mark Shimozono <mshimo at math.vt.edu>
     20#                     2012 Nicolas Thiery <nthiery at users.sf.net>
     21#
     22#                     2013 Mark Shimozono
     23#
     24#  Distributed under the terms of the GNU General Public License (GPL)
     25#
     26#                  http://www.gnu.org/licenses/
     27#*****************************************************************************
     28
     29from sage.combinat.root_system.cartan_type import CartanType
     30from sage.combinat.root_system.weyl_group import WeylGroup
     31from sage.categories.groups import Groups
     32from sage.categories.sets_cat import Sets
     33from sage.categories.all import WeylGroups, FiniteWeylGroups, AffineWeylGroups
     34from sage.misc.cachefunc import cached_method
     35from sage.structure.element import MultiplicativeGroupElement
     36from sage.structure.parent import Parent
     37from sage.structure.unique_representation import UniqueRepresentation
     38from sage.sets.family import Family
     39from sage.categories.realizations import Category_realization_of_parent
     40from sage.misc.bindable_class import BindableClass
     41from sage.combinat.root_system.fundamental_group import FundamentalGroupOfExtendedAffineWeylGroup
     42from sage.misc.abstract_method import abstract_method
     43from sage.categories.morphism import SetMorphism
     44from sage.categories.homset import Hom
     45from sage.groups.group_exp import GroupExp
     46from sage.groups.group_semidirect_product import GroupSemidirectProduct
     47from sage.combinat.root_system.root_system import RootSystem
     48
     49def ExtendedAffineWeylGroup(cartan_type, prefix0=None, prefix=None, print_tuple = False, style="PW0"):
     50    r"""
     51    Creates an extended affine Weyl group.
     52
     53    INPUT:
     54
     55        - ``cartan_type`` -- An affine or finite Cartan type (a finite Cartan type is an abbreviation for its untwisted affinization)
     56        - ``prefix0`` -- A string (default: None) labelling the simple reflections of the classical Weyl group
     57        - ``prefix`` -- A string (default: None) labelling the simple reflections of the affine Weyl group
     58        - ``print_tuple`` -- True or False (default: False); if True the semidirect product elements are printed in the form `(x,y)` and otherwise as `x * y`
     59        - ``style`` -- one of "PW0", "W0P", "WF", "FW" (default: "PW0"); this describes the implementation.
     60
     61    The mnemonics for ``style`` are:
     62
     63    - "P" -- subgroup of translations
     64    - "W0" -- classical Weyl group
     65    - "W" -- affine Weyl group
     66    - "F" -- fundamental group of length zero elements
     67
     68    Hence "PW0" means the semidirect product of P with action from W0 with P
     69    written on the left. "W0P" is similar but with translations on the right.
     70    "WF" is the semidirect product of W under the action of F with W on the left.
     71    "FW" is similar but with W on the right.
     72
     73    OUTPUT:
     74
     75        - A realization of :class:`ExtendedAffineWeylGroup_Class`.
     76
     77    The *extended affine Weyl group* was introduced in Iwahori, Generalized Tits system
     78    (Bruhat decomposition) on p-adic semisimple groups. 1966 Algebraic Groups and Discontinuous
     79    Subgroups (AMS Proc. Symp. Pure Math.., 1965) pp. 71-83 Amer. Math. Soc.,
     80    Providence, R.I. See Kac, Bourbaki, *Lie Groups and Lie Algebras* IV.2 and
     81    Kac, *Infinite-dimensional Lie algebras*.
     82
     83    Notation:
     84
     85    - `R` -- An irreducible affine root system
     86    - `I` -- Set of nodes of the Dynkin diagram of `R`
     87    - `R_0` -- The classical subsystem of `R`
     88    - `I_0` -- Set of nodes of the Dynkin diagram of `R_0`
     89    - `E` -- Extended affine Weyl group of type `R`
     90    - `W` -- Affine Weyl group of type `R`
     91    - `W_0` -- finite (classical) Weyl group (of type `R_0`)
     92    - `M` -- translation lattice for `W`
     93    - `L` -- translation lattice for `E`
     94    - `F` -- Fundamental subgroup of `E` (the length zero elements)
     95    - `P` -- Finite weight lattice
     96    - `Q` -- Finite root lattice
     97    - `P^\vee` -- Finite coweight lattice
     98    - `Q^\vee` -- Finite coroot lattice
     99
     100    The translation lattices fall into four cases depending on `R`.
     101
     102    - Untwisted affine: `L = P^\vee`, `M = Q^\vee`
     103    - Dual of untwisted affine: `L = P`, `M = Q`
     104    - `BC_n` (`A_{2n}^{(2)}`): `L = M = P`
     105    - Dual of `BC_n` (`A_{2n}^{(2)\dagger}`): `L = M = P^\vee`
     106
     107    The group `W_0` is generated by the simple reflections `s_i` for `i \in I_0` where
     108    `s_i` is the reflection across a suitable hyperplane `H_i` through the origin in the
     109    real span `V` of the lattice `M`.
     110
     111    `R` specifies another (affine) hyperplane `H_0`. The group `W` is generated by `W_0`
     112    and the reflection `S_0` across `H_0`.
     113
     114    The complement in `V` of the set `H` of hyperplanes obtained from the `H_i` by the action of
     115    `W`, has connected components called alcoves. `W` acts freely and transitively on the set
     116    of alcoves. After the choice of a certain alcove (the fundamental alcove),
     117    there is an induced bijection from `W` to the set of alcoves under which the identity
     118    in `W` maps to the fundamental alcove.
     119
     120    Then `L` is the largest sublattice of `V` that stabilizes the set of alcoves.
     121
     122    There are isomorphisms
     123
     124    `W \cong M \rtimes W_0 \cong W_0 \ltimes M`
     125
     126    `E \cong L \rtimes W_0 \cong W_0 \ltimes L`
     127
     128    Since `L` acts on the set of alcoves, the group `F = L/M` may be viewed as a
     129    subgroup of the symmetries of the fundamental alcove or equivalently the
     130    symmetries of the affine Dynkin diagram.
     131    `F` acts on the set of alcoves and hence on `W`. Conjugation by an element of `F`
     132    acts on `W` by permuting the indices of simple reflections.
     133
     134    There are isomorphisms
     135
     136    `E \cong F \ltimes W \cong W \rtimes F`
     137
     138    An affine Dynkin node is *special* if it is conjugate to the zero node under some
     139    affine Dynkin automorphism.
     140
     141    There is a bijection `i` `\mapsto` `\pi_i` from the set of special nodes
     142    to the group `F`, where `\pi_i` is the unique element of `F` that sends `0` to `i`.
     143    When `L=P` (resp. `L=P^\vee`) the element `\pi_i` is induced
     144    (under the isomorphism `F \cong L/M`) by addition of the coset of the
     145    `i`-th fundamental weight (resp. coweight).
     146
     147    The length function of the Coxeter group `W` may be extended to `E` by
     148    `\ell(w \pi) = \ell(w)` where `w \in W` and `\pi\in F`.
     149    This is the number of hyperplanes in `H` separating the
     150    fundamental alcove from its image by `w \pi` (or equivalently `w`).
     151
     152    It is known that if `G` is the compact Lie group of adjoint type with root
     153    system `R_0` then `F` is isomorphic to the fundamental group of `G`, or
     154    to the center of its simply-connected covering group. That is why we
     155    call `F` the *fundamental group*.
     156
     157    In the future we may want to build an element of the group from an appropriate linear map f
     158    on some of the root lattice realizations for this cartan type: W.from_endomorphism(f).
     159
     160    EXAMPLES::
     161
     162        sage: PW0 = ExtendedAffineWeylGroup(["A",2,1], prefix0="s", prefix="S"); PW0
     163        Semidirect product of Multiplicative form of Coweight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice)
     164
     165    This gives the default realization, style "PW0", of
     166    :class:`~sage.combinat.root_system.extended_affine_weyl_group.ExtendedAffineWeylGroup_Class`
     167    which is stored in the variable ``E`` below.
     168
     169    ::
     170
     171        sage: E = PW0.realization_of(); E
     172        The extended affine Weyl group of type ['A', 2, 1]
     173        sage: type(E)
     174        <class 'sage.combinat.root_system.extended_affine_weyl_group.ExtendedAffineWeylGroup_Class_with_category'>
     175
     176    There are also realizations "W0P", "WF",and "FW". Each realization can be accessed
     177    from the others via ``E``.
     178
     179    ::
     180
     181        sage: W0P = E.W0P(); W0P
     182        Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) acting on Multiplicative form of Coweight lattice of the Root system of type ['A', 2]
     183
     184        sage: WF = E.WF(); WF
     185        Semidirect product of Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) acted upon by Fundamental group of type ['A', 2, 1]
     186
     187        sage: FW = E.FW(); FW
     188        Semidirect product of Fundamental group of type ['A', 2, 1] acting on Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice)
     189
     190    When the realizations are constructed from each other as above, there are built-in
     191    coercions between them.
     192
     193    ::
     194
     195        sage: x = WF.an_element(); x
     196        S0*S1*S2 * pi[2]
     197        sage: FW(x)
     198        pi[2] * S1*S2*S0
     199        sage: W0P(x)
     200        s1*s2*s1 * t[-2*Lambdacheck[1] - Lambdacheck[2]]
     201        sage: PW0(x)
     202        t[Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2*s1
     203
     204    The translation lattice and its distinguished basis are obtained from ``E``.
     205
     206    ::
     207
     208        sage: L = E.lattice(); L
     209        Coweight lattice of the Root system of type ['A', 2]
     210        sage: b = E.lattice_basis(); b
     211        Finite family {1: Lambdacheck[1], 2: Lambdacheck[2]}
     212
     213    Translation lattice elements can be coerced into any realization.
     214
     215    ::
     216
     217        sage: PW0(b[1]-b[2])
     218        t[Lambdacheck[1] - Lambdacheck[2]]
     219        sage: FW(b[1]-b[2])
     220        pi[2] * S0*S1
     221
     222    The abstract fundamental group is accessed from ``E``.
     223
     224    ::
     225
     226        sage: F = E.fundamental_group(); F
     227        Fundamental group of type ['A', 2, 1]
     228
     229    Its elements are indexed by the set of special nodes of the affine Dynkin diagram.
     230
     231    ::
     232
     233        sage: E.special_nodes()
     234        [0, 1, 2]
     235        sage: F.family()
     236        Finite family {0: pi[0], 1: pi[1], 2: pi[2]}
     237
     238    There is a coercion from the fundamental group into each realization:
     239
     240    ::
     241
     242        sage: F(2)
     243        pi[2]
     244        sage: WF(F(2))
     245        pi[2]
     246        sage: W0P(F(2))
     247        s2*s1 * t[-Lambdacheck[1]]
     248
     249    Using ``E`` one may access the classical and affine Weyl groups and their morphisms
     250    into each realization.
     251
     252    ::
     253
     254        sage: W0 = E.classical_weyl(); W0
     255        Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice)
     256        sage: v = W0.from_reduced_word([1,2,1]); v
     257        s1*s2*s1
     258        sage: PW0(v)
     259        s1*s2*s1
     260        sage: WF(v)
     261        S1*S2*S1
     262        sage: W = E.affine_weyl(); W
     263        Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice)
     264        sage: w = W.from_reduced_word([2,1,0]); w
     265        S2*S1*S0
     266        sage: WF(w)
     267        S2*S1*S0
     268        sage: PW0(w)
     269        t[Lambdacheck[1] - 2*Lambdacheck[2]] * s1
     270
     271    However it is quicker to create an element of a realization directly from a reduced word.
     272
     273    ::
     274
     275        sage: PW0.from_reduced_word([2,1,0])
     276        t[Lambdacheck[1] - 2*Lambdacheck[2]] * s1
     277
     278    .. TODO::
     279
     280        - Implement a "slow" action of `E` on any affine root or weight lattice realization.
     281        - Implement the level `m` actions of `E` and `W` on the lattices of finite type.
     282        - Implement the relevant methods from the usual affine weyl group
     283        - Implementation by matrices: style "M".
     284        - Use case: implement the Hecke algebra on top of this
     285
     286    The semidirect product construction in sage currently only
     287    admits multiplicative groups. Therefore for the styles "PW0" and "W0P" it is necessary
     288    to convert the additive group of translations `L` into a multiplicative group by
     289    applying the :class:`sage.groups.group_exp.GroupExp` functor.
     290
     291    """
     292
     293    cartan_type = CartanType(cartan_type)
     294    if cartan_type.is_reducible():
     295        raise ValueError, "Extended affine Weyl groups are only implemented for irreducible affine Cartan types"
     296    if cartan_type.is_finite(): # a finite Cartan type is an abbreviation for its untwisted affinization
     297        cartan_type = cartan_type.affine()
     298    elif not cartan_type.is_affine():
     299        raise ValueError, "Cartan type must be finite or affine"
     300
     301    if style == "PW0":
     302        return ExtendedAffineWeylGroup_Class(cartan_type, prefix0, prefix, print_tuple).PW0()
     303    elif style == "W0P":
     304        return ExtendedAffineWeylGroup_Class(cartan_type, prefix0, prefix, print_tuple).W0P()
     305    elif style == "WF":
     306        return ExtendedAffineWeylGroup_Class(cartan_type, prefix0, prefix, print_tuple).WF()
     307    elif style == "FW":
     308        return ExtendedAffineWeylGroup_Class(cartan_type, prefix0, prefix, print_tuple).FW()
     309    else:
     310        raise ValueError, "Extended affine Weyl group of style %s is not implemented"%style
     311    return None
     312
     313class ExtendedAffineWeylGroup_Class(UniqueRepresentation, Parent):
     314    r"""
     315    The parent-with-realization class of an extended affine Weyl group.
     316    """
     317
     318    def __init__(self, cartan_type, prefix0, prefix, print_tuple):
     319        if not cartan_type.is_affine():
     320            raise ValueError, "%s is not affine"%cartan_type
     321
     322        self._cartan_type = cartan_type
     323        self._prefix0 = prefix0 # prefix for the classical Weyl group
     324        self._prefix = prefix   # prefix for the affine Weyl group
     325        self._print_tuple = print_tuple
     326
     327        if not prefix:
     328            if prefix0:
     329                if prefix0.islower():
     330                    self._prefix = prefix0.upper()
     331                else:
     332                    self._prefix = prefix0.lower()
     333            else:
     334                self._prefix = "S"
     335        else:
     336            self._prefix = prefix
     337
     338        self._ct0 = cartan_type.classical()
     339        self._R0  = self._ct0.root_system()
     340        self._I0 = self._ct0.index_set()
     341
     342        # `BC` (`A_{2n}^{(2)\dagger}`) is considered untwisted and its dual is considered twisted
     343        self._untwisted = (self._cartan_type.is_untwisted_affine() or self._cartan_type.dual().type() == 'BC')
     344
     345        # fundamental group
     346        self._fundamental_group = FundamentalGroupOfExtendedAffineWeylGroup(cartan_type)
     347
     348        # lattice data
     349        if self._untwisted:
     350            self._lattice = self._R0.coweight_lattice()
     351            self._basis = self._lattice.fundamental_weights()
     352            self._basis_name = 'Lambdacheck'
     353            self._simpleR0 = self._R0.root_lattice().simple_roots()
     354            if self._cartan_type.dual().type() == 'BC':
     355                self._special_root = self._R0.coroot_lattice().highest_root()
     356                self._special_translation = self._lattice.fundamental_weight(1)
     357            else:
     358                self._special_root = self._R0.root_lattice().highest_root().associated_coroot()
     359                self._special_translation = self._special_root
     360            self._special_translation_covector = self._special_root.associated_coroot()
     361        else:
     362            self._lattice = self._R0.weight_lattice()
     363            self._basis = self._lattice.fundamental_weights()
     364            self._basis_name = 'Lambda'
     365            self._simpleR0 = self._R0.coroot_lattice().simple_roots()
     366            if self._cartan_type.type() == 'BC':
     367                self._special_root = self._R0.root_lattice().highest_root()
     368                self._special_translation = self._lattice.fundamental_weight(1)
     369                self._special_translation_covector = 2*self._special_root.associated_coroot()
     370            else:
     371                self._special_root = self._R0.coroot_lattice().highest_root().associated_coroot()
     372                self._special_translation = self._special_root
     373                self._special_translation_covector = self._special_root.associated_coroot()
     374
     375        # classical and affine Weyl groups
     376        self._W0 = WeylGroup(self._lattice, prefix=prefix0)
     377        self._W = WeylGroup(self._cartan_type.root_system().root_lattice(), prefix=prefix)
     378        self._special_reflection = self._W0.from_reduced_word(self._special_root.associated_reflection())
     379
     380        # wrap the lattice into a multiplicative group for internal use in the semidirect product
     381        self._exp_lattice = GroupExp()(self._lattice)
     382
     383        self._extended = True
     384
     385        Parent.__init__(self, category = Groups().WithRealizations())
     386
     387        # create the realizations (they are cached)
     388        PW0 = self.PW0()
     389        W0P = self.W0P()
     390        WF = self.WF()
     391        FW = self.FW()
     392
     393        # coercions between realizations
     394
     395        PW0_to_W0P = SetMorphism(Hom(PW0, W0P, Groups()),lambda x: W0P(x.to_opposite()))
     396        PW0_to_W0P.register_as_coercion()
     397
     398        W0P_to_PW0 = SetMorphism(Hom(W0P, PW0, Groups()),lambda x: PW0(x.to_opposite()))
     399        W0P_to_PW0.register_as_coercion()
     400
     401        FW_to_WF = SetMorphism(Hom(FW, WF, Groups()),lambda x: WF(x.to_opposite()))
     402        FW_to_WF.register_as_coercion()
     403
     404        WF_to_FW = SetMorphism(Hom(WF, FW, Groups()),lambda x: FW(x.to_opposite()))
     405        WF_to_FW.register_as_coercion()
     406
     407        def PW0_to_WF_func(x):
     408            r"""
     409            Coercion from style "PW0" to "WF".
     410            """
     411            E = x.parent().realization_of()
     412            assert x.parent() == E.PW0()
     413            WF = E.WF()
     414            i = x.first_descent(side='left')
     415            if i is None:
     416                t = x.to_translation_left()
     417                # t must be zero or a special fundamental basis element
     418                if t == E.lattice().zero():
     419                    ispecial = 0
     420                else:
     421                    supp = t.support()
     422                    assert len(supp) == 1
     423                    ispecial = supp[0]
     424                return WF.fundamental_group_morphism(E.fundamental_group()(ispecial))
     425            sx = x.apply_simple_reflection(i, side='left')
     426            swf = PW0_to_WF_func(sx)
     427            return swf.apply_simple_reflection(i, side='left')
     428
     429        PW0_to_WF = SetMorphism(Hom(PW0, WF, Groups()),PW0_to_WF_func)
     430        PW0_to_WF.register_as_coercion()
     431
     432        def WF_to_PW0_func(x):
     433            r"""
     434            Coercion from style "WF" to "PW0".
     435            """
     436            E = x.parent().realization_of()
     437            assert x.parent() == E.WF(), "type should be WF but it is %s"%type(x.parent())  #!!! delete?
     438            PW0 = E.PW0()
     439            w = x.summand_projection(0)
     440            f = x.summand_projection(1)
     441            i = w.first_descent(side='left')
     442            if i is None:
     443                # the element is in the fundamental group; use its known formula
     444                ispecial = f.value()
     445                if ispecial == 0:
     446                    weight = E.lattice().zero()
     447                else:
     448                    weight = E.lattice_basis()[ispecial]
     449                return PW0((weight, E.classical_weyl().from_reduced_word(E.fundamental_group().finite_action()[ispecial])))
     450            sx = x.apply_simple_reflection(i, side='left')
     451            spw0 = WF_to_PW0_func(sx)
     452            return spw0.apply_simple_reflection(i, side='left')
     453
     454        WF_to_PW0 = SetMorphism(Hom(WF, PW0, Groups()),WF_to_PW0_func)
     455        WF_to_PW0.register_as_coercion()
     456
     457        # coercions of the translation lattice into the appropriate realizations
     458        P_to_PW0 = SetMorphism(Hom(self.lattice(), PW0, Sets()), lambda x: PW0.translation_group_morphism(x))
     459        P_to_PW0.register_as_coercion()
     460
     461        P_to_W0P = SetMorphism(Hom(self.lattice(), W0P, Sets()), lambda x: W0P.translation_group_morphism(x))
     462        P_to_W0P.register_as_coercion()
     463
     464        # coercions of the classical Weyl group into the appropriate realizations
     465
     466        W0_to_PW0 = SetMorphism(Hom(self.classical_weyl(), PW0, Groups()), lambda x: PW0.classical_weyl_morphism(x))
     467        W0_to_PW0.register_as_coercion()
     468
     469        W0_to_W0P = SetMorphism(Hom(self.classical_weyl(), W0P, Groups()), lambda x: W0P.classical_weyl_morphism(x))
     470        W0_to_W0P.register_as_coercion()
     471
     472        # coercions of the fundamental group into the appropriate realizations
     473
     474        F_to_WF = SetMorphism(Hom(self.fundamental_group(), WF, Groups()), lambda x: WF.fundamental_group_morphism(x))
     475        F_to_WF.register_as_coercion()
     476        F_to_FW = SetMorphism(Hom(self.fundamental_group(), FW, Groups()), lambda x: FW.fundamental_group_morphism(x))
     477        F_to_FW.register_as_coercion()
     478
     479        # coercions of the affine Weyl group into the appropriate realizations
     480
     481        W_to_WF = SetMorphism(Hom(self.affine_weyl(), WF, Groups()), lambda x: WF.affine_weyl_morphism(x))
     482        W_to_WF.register_as_coercion()
     483
     484        W_to_FW = SetMorphism(Hom(self.affine_weyl(), FW, Groups()), lambda x: FW.affine_weyl_morphism(x))
     485        W_to_FW.register_as_coercion()
     486
     487
     488    @cached_method
     489    def PW0(self):
     490        r"""
     491        Realizes ``self`` in "PW0"-style.
     492        """
     493        return self.ExtendedAffineWeylGroupPW0()
     494
     495    @cached_method
     496    def W0P(self):
     497        r"""
     498        Realizes ``self`` in "W0P"-style.
     499        """
     500        return self.ExtendedAffineWeylGroupW0P()
     501
     502    @cached_method
     503    def WF(self):
     504        r"""
     505        Realizes ``self`` in "WF"-style.
     506        """
     507        return self.ExtendedAffineWeylGroupWF()
     508
     509    @cached_method
     510    def FW(self):
     511        r"""
     512        Realizes ``self`` in "FW"-style.
     513        """
     514        return self.ExtendedAffineWeylGroupFW()
     515
     516    def cartan_type(self):
     517        return self._cartan_type
     518
     519    def _repr_(self):
     520        r"""
     521        EXAMPLES::
     522
     523            sage: PW0 = ExtendedAffineWeylGroup(['A',2,1])
     524            sage: E = PW0.realization_of(); E
     525            The extended affine Weyl group of type ['A', 2, 1]
     526
     527        """
     528        return "The extended affine Weyl group of type %s"%self.cartan_type()
     529
     530    @cached_method
     531    def index_set(self):
     532        r"""
     533        Returns the index set of the affine Dynkin diagram.
     534
     535        EXAMPLES::
     536
     537            sage: ExtendedAffineWeylGroup("B2").realization_of().index_set()
     538            (0, 1, 2)
     539
     540        """
     541        return self.cartan_type().index_set()
     542
     543    def fundamental_group(self):
     544        r"""
     545        Returns the abstract fundamental group.
     546
     547        EXAMPLES::
     548
     549            sage: F = ExtendedAffineWeylGroup(['D',5,1]).realization_of().fundamental_group()
     550            sage: f = F.family(); f
     551            Finite family {0: pi[0], 1: pi[1], 4: pi[4], 5: pi[5]}
     552            sage: f[0]
     553            pi[0]
     554            sage: f[1]^2
     555            pi[0]
     556            sage: F(1)^2
     557            pi[0]
     558            sage: f[4]*f[4]
     559            pi[1]
     560
     561        """
     562        return self._fundamental_group
     563
     564    @cached_method
     565    def special_nodes(self):
     566        r"""
     567        Returns the set of special nodes.
     568
     569        EXAMPLES::
     570
     571            sage: ExtendedAffineWeylGroup(['D',4,2]).realization_of().special_nodes()
     572            [0, 3]
     573
     574        """
     575        return self.fundamental_group().special_nodes()
     576
     577    def is_finite(self):
     578        return False
     579
     580    def lattice(self):
     581        r"""
     582        Returns the translation lattice for ``self``.
     583
     584        EXAMPLES::
     585
     586            sage: ExtendedAffineWeylGroup(['A',2,1]).realization_of().lattice()
     587            Coweight lattice of the Root system of type ['A', 2]
     588            sage: ExtendedAffineWeylGroup(['A',5,2]).realization_of().lattice()
     589            Weight lattice of the Root system of type ['C', 3]
     590            sage: ExtendedAffineWeylGroup(['A',4,2]).realization_of().lattice()
     591            Weight lattice of the Root system of type ['C', 2]
     592            sage: ExtendedAffineWeylGroup(CartanType(['A',4,2]).dual()).realization_of().lattice()
     593            Coweight lattice of the Root system of type ['B', 2]
     594
     595        """
     596
     597        return self._lattice
     598
     599    def exp_lattice(self):
     600        r"""
     601        Returns the multiplicative version of the translation lattice for ``self``.
     602
     603        EXAMPLES::
     604
     605            sage: ExtendedAffineWeylGroup(['A',2,1]).realization_of().exp_lattice()
     606            Multiplicative form of Coweight lattice of the Root system of type ['A', 2]
     607
     608        """
     609
     610        return self._exp_lattice
     611
     612    def lattice_basis(self):
     613        r"""
     614        Returns the distinguished basis of the translation lattice for ``self``.
     615
     616        EXAMPLES::
     617
     618            sage: ExtendedAffineWeylGroup(['A',2,1]).realization_of().lattice_basis()
     619            Finite family {1: Lambdacheck[1], 2: Lambdacheck[2]}
     620            sage: ExtendedAffineWeylGroup(['A',5,2]).realization_of().lattice_basis()
     621            Finite family {1: Lambda[1], 2: Lambda[2], 3: Lambda[3]}
     622            sage: ExtendedAffineWeylGroup(['A',4,2]).realization_of().lattice_basis()
     623            Finite family {1: Lambda[1], 2: Lambda[2]}
     624            sage: ExtendedAffineWeylGroup(CartanType(['A',4,2]).dual()).realization_of().lattice_basis()
     625            Finite family {1: Lambdacheck[1], 2: Lambdacheck[2]}
     626
     627        """
     628        return self._basis
     629
     630    def classical_weyl(self):
     631        r"""
     632        Returns the classical Weyl group of ``self``.
     633
     634        EXAMPLES::
     635
     636            sage: ExtendedAffineWeylGroup(['A',2,1]).realization_of().classical_weyl()
     637            Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice)
     638            sage: ExtendedAffineWeylGroup(['A',5,2]).realization_of().classical_weyl()
     639            Weyl Group of type ['C', 3] (as a matrix group acting on the weight lattice)
     640            sage: ExtendedAffineWeylGroup(['A',4,2]).realization_of().classical_weyl()
     641            Weyl Group of type ['C', 2] (as a matrix group acting on the weight lattice)
     642            sage: ExtendedAffineWeylGroup(CartanType(['A',4,2]).dual()).realization_of().classical_weyl()
     643            Weyl Group of type ['C', 2] (as a matrix group acting on the coweight lattice)
     644
     645        """
     646
     647        return self._W0
     648
     649    def affine_weyl(self):
     650        r"""
     651        Returns the affine Weyl group of ``self``.
     652
     653        EXAMPLES::
     654
     655            sage: ExtendedAffineWeylGroup(['A',2,1]).realization_of().affine_weyl()
     656            Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice)
     657            sage: ExtendedAffineWeylGroup(['A',5,2]).realization_of().affine_weyl()
     658            Weyl Group of type ['B', 3, 1]^* (as a matrix group acting on the root lattice)
     659            sage: ExtendedAffineWeylGroup(['A',4,2]).realization_of().affine_weyl()
     660            Weyl Group of type ['BC', 2, 2] (as a matrix group acting on the root lattice)
     661            sage: ExtendedAffineWeylGroup(CartanType(['A',4,2]).dual()).realization_of().affine_weyl()
     662            Weyl Group of type ['BC', 2, 2]^* (as a matrix group acting on the root lattice)
     663
     664        """
     665        return self._W
     666
     667    def classical_weyl_to_affine_morphism(self, w):
     668        r"""
     669        The image of `w` under the homomorphism from the classical Weyl group into the affine Weyl group.
     670
     671        EXAMPLES::
     672
     673            sage: E = ExtendedAffineWeylGroup(['A',2,1],prefix0="s",prefix="S").realization_of()
     674            sage: W0 = E.classical_weyl()
     675            sage: w = W0.from_reduced_word([1,2]); w
     676            s1*s2
     677            sage: v = E.classical_weyl_to_affine_morphism(w); v
     678            S1*S2
     679
     680        """
     681        return self.affine_weyl().from_reduced_word(w.reduced_word())
     682
     683    def classical_root_system(self):
     684        r"""
     685        Returns the root system of the classical subrootsystem of ``self`` obtained by removing the affine `0` node.
     686
     687        EXAMPLES::
     688
     689            sage: ExtendedAffineWeylGroup(['A',5,2]).realization_of().classical_root_system()
     690            Root system of type ['C', 3]
     691
     692        """
     693        return self._R0
     694
     695    def cardinality(self):
     696        """
     697        Returns infinity
     698        """
     699        return Infinity
     700
     701    def a_realization(self):
     702        r"""
     703        Returns the default realization of an extended affine Weyl group.
     704
     705        EXAMPLES::
     706
     707            sage: PW0 = ExtendedAffineWeylGroup(['A',2,1],prefix0='s'); PW0
     708            Semidirect product of Multiplicative form of Coweight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice)
     709            sage: PW0 == PW0.realization_of().PW0()
     710            True
     711
     712        """
     713        return self.PW0()
     714
     715    class Realizations(Category_realization_of_parent):
     716        r"""
     717        The category of the realizations of an extended affine Weyl group
     718        """
     719
     720        def super_categories(self):
     721            r"""
     722            EXAMPLES::
     723
     724                sage: R = ExtendedAffineWeylGroup(['A',2,1]).realization_of().Realizations(); R
     725                Category of realizations of The extended affine Weyl group of type ['A', 2, 1]
     726                sage: R.super_categories()
     727                [Category of associative inverse unital realizations of magmas]
     728
     729            """
     730            return [Groups().Realizations()]
     731
     732        class ParentMethods:
     733
     734            @cached_method
     735            def one(self):
     736                r"""
     737                Returns the unit element.
     738
     739                This default implementation takes the unit in the
     740                PW0 realization and coerces it into `self`.
     741
     742                EXAMPLES::
     743
     744                    sage: ExtendedAffineWeylGroup(['A',2,1], prefix0="s").one()
     745                    1
     746
     747                .. warning::
     748
     749                    Must be implemented in style "PW0".
     750
     751                """
     752                PW0 = self.realization_of().PW0()
     753                return self(PW0.one())
     754
     755            @cached_method
     756            def fundamental_group_morphism(self, x):
     757                r"""
     758                Returns the image of `x` under the homomorphism from the fundamental group into
     759                ``self``.
     760
     761                EXAMPLES::
     762
     763                    sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s")
     764                    sage: E = PW0.realization_of()
     765                    sage: Is = E.special_nodes()
     766                    sage: F = E.fundamental_group()
     767                    sage: [(i, PW0.fundamental_group_morphism(F(i))) for i in Is]
     768                    [(0, 1), (1, t[Lambdacheck[1]] * s1*s2*s3), (2, t[Lambdacheck[2]] * s2*s3*s1*s2), (3, t[Lambdacheck[3]] * s3*s2*s1)]
     769                    sage: [(i, E.W0P().fundamental_group_morphism((F(i)))) for i in Is]
     770                    [(0, 1), (1, s1*s2*s3 * t[-Lambdacheck[3]]), (2, s2*s3*s1*s2 * t[-Lambdacheck[2]]), (3, s3*s2*s1 * t[-Lambdacheck[1]])]
     771                    sage: [(i, E.WF().fundamental_group_morphism(F(i))) for i in Is]
     772                    [(0, 1), (1, pi[1]), (2, pi[2]), (3, pi[3])]
     773
     774                .. warning::
     775
     776                    This method must be implemented by the "WF" and "FW" realizations.
     777
     778                """
     779                WF = self.realization_of().WF()
     780                return self(WF.fundamental_group_morphism(x))
     781
     782            def translation_group_morphism(self, la):
     783                r"""
     784                Returns the image of `la` under the homomorphism of the translation lattice into
     785                ``self``.
     786
     787                EXAMPLES::
     788
     789                    sage: PW0 = ExtendedAffineWeylGroup(['A',2,1],prefix0="s",prefix="S")
     790                    sage: E = PW0.realization_of()
     791                    sage: b = E.lattice_basis(); b
     792                    Finite family {1: Lambdacheck[1], 2: Lambdacheck[2]}
     793                    sage: x = PW0.translation_group_morphism(2*b[1]-b[2]); x
     794                    t[2*Lambdacheck[1] - Lambdacheck[2]]
     795                    sage: FW = E.FW()
     796                    sage: y = FW.translation_group_morphism(2*b[1]-b[2]); y
     797                    S0*S2*S0*S1
     798                    sage: FW(x) == y
     799                    True
     800
     801                Since the implementation as a semidirect product requires
     802                wrapping the lattice group to make it multiplicative,
     803                we cannot declare that this map is a morphism for
     804                sage ``Groups()``.
     805
     806                .. warning::
     807
     808                    This method must be implemented by the "PW0" and "W0P" realizations.
     809                """
     810                PW0 = self.realization_of().PW0()
     811                return self(PW0.translation_group_morphism(la))
     812
     813            @abstract_method
     814            def simple_reflections(self):
     815                r"""
     816                Returns a family from the set of affine Dynkin nodes to the simple reflections
     817                in the realization of the extended affine Weyl group.
     818
     819                EXAMPLES::
     820
     821                    sage: ExtendedAffineWeylGroup(['A',3,1],prefix0="s",style="W0P").simple_reflections()
     822                    Finite family {0: s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]], 1: s1, 2: s2, 3: s3}
     823                    sage: ExtendedAffineWeylGroup(['A',3,1],prefix="S",style="WF").simple_reflections()
     824                    Finite family {0: S0, 1: S1, 2: S2, 3: S3}
     825                    sage: ExtendedAffineWeylGroup(['A',3,1],prefix="S",print_tuple=True,style="FW").simple_reflections()
     826                    Finite family {0: (pi[0], S0), 1: (pi[0], S1), 2: (pi[0], S2), 3: (pi[0], S3)}
     827
     828                """
     829
     830            def simple_reflection(self, i):
     831                r"""
     832                Returns the `i`-th simple reflection in the realization of the extended affine
     833                Weyl group.
     834
     835                    sage: ExtendedAffineWeylGroup(['A',3,1],prefix0="s",style="PW0").simple_reflection(0)
     836                    t[Lambdacheck[1] + Lambdacheck[3]] * s1*s2*s3*s2*s1
     837                    sage: ExtendedAffineWeylGroup(['A',3,1],prefix="S",style="WF").simple_reflection(0)
     838                    S0
     839
     840                """
     841                return self.simple_reflections()[i]
     842
     843            def classical_weyl_morphism(self, w):
     844                r"""
     845                Returns the image of `w` from the finite Weyl group into ``self``.
     846
     847                EXAMPLES::
     848
     849                    sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s",prefix="S")
     850                    sage: E = PW0.realization_of()
     851                    sage: W0 = E.classical_weyl()
     852                    sage: w = W0.from_reduced_word([2,1,3])
     853                    sage: y = PW0.classical_weyl_morphism(w); y
     854                    s2*s3*s1
     855                    sage: y.parent() == PW0
     856                    True
     857                    sage: y.to_classical_weyl() == w
     858                    True
     859                    sage: W0P = E.W0P()
     860                    sage: z = W0P.classical_weyl_morphism(w); z
     861                    s2*s3*s1
     862                    sage: z.parent() == W0P
     863                    True
     864                    sage: W0P(y) == z
     865                    True
     866                    sage: FW = E.FW()
     867                    sage: x = FW.classical_weyl_morphism(w); x
     868                    S2*S3*S1
     869                    sage: x.parent() == FW
     870                    True
     871                    sage: FW(y) == x
     872                    True
     873                    sage: FW(z) == x
     874                    True
     875
     876                .. warning::
     877
     878                    Must be implemented in style "PW0" and "W0P".
     879
     880                """
     881                PW0 = self.realization_of().PW0()
     882                return self(PW0.classical_weyl_morphism(w))
     883
     884            def affine_weyl_morphism(self, w):
     885                r"""
     886                Returns the image of `w` under the homomorphism from the affine Weyl group
     887                into ``self``.
     888
     889                EXAMPLES::
     890
     891                    sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s",prefix="S")
     892                    sage: E = PW0.realization_of()
     893                    sage: W = E.affine_weyl()
     894                    sage: w = W.from_reduced_word([2,1,3,0])
     895                    sage: x = PW0.affine_weyl_morphism(w); x
     896                    t[Lambdacheck[1] - 2*Lambdacheck[2] + Lambdacheck[3]] * s3*s1
     897                    sage: FW = E.FW()
     898                    sage: y = FW.affine_weyl_morphism(w); y
     899                    S2*S3*S1*S0
     900                    sage: FW(x) == y
     901                    True
     902
     903                .. warning::
     904
     905                    Must be implemented in style "WF" and "FW".
     906
     907                """
     908                WF = self.realization_of().WF()
     909                return self(WF.affine_weyl_morphism(w))
     910
     911            def from_reduced_word(self, word):
     912                r"""
     913                Converts an affine or finite reduced word into a group element.
     914
     915                EXAMPLES::
     916
     917                    sage: PW0 = ExtendedAffineWeylGroup(['A',2,1], prefix0="s")
     918                    sage: PW0.from_reduced_word([1,0,1,2])
     919                    t[-Lambdacheck[1] + 2*Lambdacheck[2]]
     920
     921                """
     922
     923                return self.affine_weyl_morphism(self.realization_of().affine_weyl().from_reduced_word(word))
     924
     925            @cached_method
     926            def dual(self):
     927                r"""
     928                The realization of the extended affine Weyl group of dual affine type.
     929
     930                EXAMPLES::
     931
     932                    sage: W = ExtendedAffineWeylGroup(['B',3,1],prefix0="s",prefix="S")
     933                    sage: W.dual()
     934                    Semidirect product of Multiplicative form of Weight lattice of the Root system of type ['C', 3] acted upon by Weyl Group of type ['C', 3] (as a matrix group acting on the weight lattice)
     935
     936                """
     937                E = self.realization_of()
     938                DW = ExtendedAffineWeylGroup(E.cartan_type().dual(), prefix0=E._prefix0, prefix=E._prefix, print_tuple=E._print_tuple)
     939                if self == E.PW0():
     940                    return DW.realization_of().PW0()
     941                if self == E.W0P():
     942                    return DW.realization_of().W0P()
     943                if self == E.WF():
     944                    return DW.realization_of().WF()
     945                if self == E.FW():
     946                    return DW.realization_of().FW()
     947
     948        class ElementMethods:
     949
     950            @abstract_method
     951            def has_descent(self, i, side='right', positive=False):
     952                r"""
     953                Returns whether ``self`` * `s_i` < ``self`` where `s_i` is the `i`-th simple
     954                reflection in the realized group.
     955
     956                INPUT:
     957
     958                    - `i` -- An affine Dynkin node
     959                    - `side` -- 'right' or 'left' (default: 'right')
     960                    - `positive` -- True or False (default: False)
     961
     962                If ``side``='left' then the reflection acts
     963                on the left. If ``positive``=True then the inequality is reversed.
     964
     965                EXAMPLES::
     966
     967                    sage: WF = ExtendedAffineWeylGroup(['A',3,1],prefix="S",style="WF")
     968                    sage: x = WF.an_element(); x
     969                    S0*S1*S2*S3 * pi[2]
     970                    sage: I = WF.realization_of().index_set()
     971                    sage: [(i, x.has_descent(i)) for i in I]
     972                    [(0, False), (1, True), (2, False), (3, False)]
     973                    sage: [(i, x.has_descent(i,side='left')) for i in I]
     974                    [(0, True), (1, False), (2, False), (3, False)]
     975                    sage: [(i, x.has_descent(i,positive=True)) for i in I]
     976                    [(0, True), (1, False), (2, True), (3, True)]
     977
     978                .. warning::
     979
     980                    This method is abstract because it is used in the recursive coercions
     981                    between "PW0" and "WF" and other methods use this coercion.
     982
     983                """
     984
     985            def first_descent(self, side='right', positive=False, index_set=None):
     986                r"""
     987                Returns the first descent of ``self``.
     988
     989                INPUT:
     990
     991                    - ``side`` -- 'left' or 'right' (default: 'right')
     992                    - ``positive`` -- True or False (default: False)
     993                    - ``index_set`` -- an optional subset of Dynkin nodes
     994
     995                If ``index_set`` is not None, then the descent must be in the ``index_set``.
     996
     997                EXAMPLES::
     998
     999                    sage: WF = ExtendedAffineWeylGroup(['A',3,1],prefix="S",style="WF")
     1000                    sage: x = WF.an_element(); x
     1001                    S0*S1*S2*S3 * pi[2]
     1002                    sage: x.first_descent()
     1003                    1
     1004                    sage: x.first_descent(side='left')
     1005                    0
     1006                    sage: x.first_descent(positive=True)
     1007                    0
     1008                    sage: x.first_descent(side='left',positive=True)
     1009                    1
     1010
     1011                """
     1012                if index_set is None:
     1013                    index_set = self.parent().realization_of().index_set()
     1014                for i in index_set:
     1015                    if self.has_descent(i, side=side, positive=positive):
     1016                        return i
     1017                return None
     1018
     1019            def apply_simple_reflection(self, i, side='right'):
     1020                r"""
     1021                Apply the `i`-th simple reflection to ``self``.
     1022
     1023                EXAMPLES::
     1024
     1025                    sage: WF = ExtendedAffineWeylGroup(['A',3,1],prefix="S",style="WF")
     1026                    sage: x = WF.an_element(); x
     1027                    S0*S1*S2*S3 * pi[2]
     1028                    sage: x.apply_simple_reflection(1)
     1029                    S0*S1*S2 * pi[2]
     1030                    sage: x.apply_simple_reflection(1, side='left')
     1031                    S0*S1*S2*S0*S3 * pi[2]
     1032
     1033                """
     1034                s = self.parent().simple_reflection(i)
     1035                if side == 'right':
     1036                    return self*s
     1037                else:
     1038                    return s*self
     1039
     1040            def apply_simple_projection(self, i, side='right', length_increasing=True):
     1041                r"""
     1042                Returns ``self`` * `s_i` if it is greater than ``self`` and otherwise
     1043                returns ``self``.
     1044
     1045                If ``side`` = 'left' then `s_i` is multiplied on the left.
     1046                If ``positive`` = True then replace the word "greater" by "less".
     1047
     1048                EXAMPLES::
     1049
     1050                    sage: WF = ExtendedAffineWeylGroup(['A',3,1],prefix="S",style="WF")
     1051                    sage: x = WF.an_element(); x
     1052                    S0*S1*S2*S3 * pi[2]
     1053                    sage: x.apply_simple_projection(1)
     1054                    S0*S1*S2*S3 * pi[2]
     1055                    sage: x.apply_simple_projection(1, length_increasing=False)
     1056                    S0*S1*S2 * pi[2]
     1057
     1058                """
     1059                if self.has_descent(i, side=side, positive=length_increasing):
     1060                    return self.apply_simple_reflection(i, side=side)
     1061                return self
     1062
     1063            def to_fundamental_group(self):
     1064                r"""
     1065                Returns the image of ``self`` under the homomorphism to the fundamental group.
     1066
     1067                EXAMPLES::
     1068
     1069                    sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s")
     1070                    sage: b = PW0.realization_of().lattice_basis()
     1071                    sage: [(x, PW0.translation_group_morphism(x).to_fundamental_group()) for x in b]
     1072                    [(Lambdacheck[1], pi[1]), (Lambdacheck[2], pi[2]), (Lambdacheck[3], pi[3])]
     1073
     1074                .. warning::
     1075
     1076                    Must be implemented in style "WF".
     1077
     1078                """
     1079                WF = self.parent().realization_of().WF()
     1080                return WF(self).to_fundamental_group()
     1081
     1082            def to_classical_weyl(self):
     1083                r"""
     1084                Returns the image of ``self`` under the homomorphism to the classical Weyl group.
     1085
     1086                    sage: WF = ExtendedAffineWeylGroup(['A',3,1],prefix0="s", style="WF")
     1087                    sage: WF.simple_reflection(0).to_classical_weyl()
     1088                    s1*s2*s3*s2*s1
     1089
     1090                .. warning::
     1091
     1092                    Must be implemented in style "PW0".
     1093
     1094                """
     1095                PW0 = self.parent().realization_of().PW0()
     1096                return PW0(self).to_classical_weyl()
     1097
     1098            def to_affine_weyl_left(self):
     1099                r"""
     1100                Returns the projection of ``self`` to the affine Weyl group on the left,
     1101                after factorizing using the style "WF".
     1102
     1103                EXAMPLES::
     1104
     1105                    sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s",prefix="S")
     1106                    sage: b = PW0.realization_of().lattice_basis()
     1107                    sage: [(x,PW0.translation_group_morphism(x).to_affine_weyl_left()) for x in b]
     1108                    [(Lambdacheck[1], S0*S3*S2), (Lambdacheck[2], S0*S3*S1*S0), (Lambdacheck[3], S0*S1*S2)]
     1109
     1110                .. warning::
     1111                    Must be implemented in style "WF".
     1112
     1113                """
     1114                WF = self.parent().realization_of().WF()
     1115                return WF(self).to_affine_weyl_left()
     1116
     1117            def to_affine_weyl_right(self):
     1118                r"""
     1119                Returns the projection of ``self`` to the affine Weyl group on the right,
     1120                after factorizing using the style "FW".
     1121
     1122                EXAMPLES::
     1123
     1124                    sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s",prefix="S")
     1125                    sage: b = PW0.realization_of().lattice_basis()
     1126                    sage: [(x,PW0.translation_group_morphism(x).to_affine_weyl_right()) for x in b]
     1127                    [(Lambdacheck[1], S3*S2*S1), (Lambdacheck[2], S2*S3*S1*S2), (Lambdacheck[3], S1*S2*S3)]
     1128
     1129                .. warning::
     1130
     1131                    Must be implemented in style "FW".
     1132
     1133                """
     1134                FW = self.parent().realization_of().FW()
     1135                return FW(self).to_affine_weyl_right()
     1136
     1137            def to_translation_left(self):
     1138                r"""
     1139                Returns the projection of ``self`` to the translation lattice after factorizing
     1140                it to the left using the style "PW0".
     1141
     1142                EXAMPLES::
     1143
     1144                    sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s")
     1145                    sage: PW0.simple_reflection(0).to_translation_left()
     1146                    Lambdacheck[1] + Lambdacheck[3]
     1147
     1148                .. warning::
     1149
     1150                    Must be implemented in style "PW0".
     1151
     1152                """
     1153                PW0 = self.parent().realization_of().PW0()
     1154                return PW0(self).to_translation_left()
     1155
     1156            def to_translation_right(self):
     1157                r"""
     1158                Returns the projection of ``self`` to the translation lattice after factorizing
     1159                it to the right using the style "W0P".
     1160
     1161                EXAMPLES::
     1162
     1163                    sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s")
     1164                    sage: PW0.simple_reflection(0).to_translation_right()
     1165                    -Lambdacheck[1] - Lambdacheck[3]
     1166
     1167                .. warning::
     1168
     1169                    Must be implemented in style "W0P".
     1170
     1171                """
     1172                W0P = self.parent().realization_of().W0P()
     1173                return W0P(self).to_translation_right()
     1174
     1175            def length(self):
     1176                r"""
     1177                Returns the length of ``self`` in the Coxeter group sense.
     1178
     1179                EXAMPLES::
     1180
     1181                     sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s")
     1182                     sage: E = PW0.realization_of()
     1183                     sage: I0 = E.classical_root_system().index_set()
     1184                     sage: [PW0.translation_group_morphism(E.lattice_basis()[i]).length() for i in I0]
     1185                     [3, 4, 3]
     1186
     1187                 """
     1188                return self.to_affine_weyl_left().length()
     1189
     1190            def coset_representative(self, index_set, side='right'):
     1191                r"""
     1192                Returns the minimum length representative in the coset of ``self`` with respect to
     1193                the subgroup generated by the reflections given by ``index_set``. If ``side`` is
     1194                'left', the subgroup is on the left.
     1195
     1196                EXAMPLES::
     1197
     1198                     sage: WF = ExtendedAffineWeylGroup(['A',3,1],prefix0="s",style="WF")
     1199                     sage: E = WF.realization_of()
     1200                     sage: b = E.lattice_basis()
     1201                     sage: I0 = E.classical_root_system().index_set()
     1202                     sage: [WF.translation_group_morphism(x).coset_representative(index_set=I0) for x in b]
     1203                     [pi[1], pi[2], pi[3]]
     1204
     1205                """
     1206
     1207                while True:
     1208                    i = self.first_descent(index_set=index_set, side=side)
     1209                    if i is None:
     1210                        return self
     1211                    self = self.apply_simple_reflection(i,side=side)
     1212
     1213            def is_grassmannian(self, index_set, side='right'):
     1214                r"""
     1215                Returns whether ``self`` is of minimum length in its coset with respect to the
     1216                subgroup generated by the reflections of ``index_set``.
     1217
     1218                EXAMPLES::
     1219
     1220                     sage: PW0 = ExtendedAffineWeylGroup(['A',3,1],prefix0="s")
     1221                     sage: E = PW0.realization_of()
     1222                     sage: x = PW0.translation_group_morphism(E.lattice_basis()[1]); x
     1223                     t[Lambdacheck[1]]
     1224                     sage: I = E.cartan_type().index_set()
     1225                     sage: [(i, x.is_grassmannian(index_set=[i])) for i in I]
     1226                     [(0, True), (1, False), (2, True), (3, True)]
     1227                     sage: [(i, x.is_grassmannian(index_set=[i], side='left')) for i in I]
     1228                     [(0, False), (1, True), (2, True), (3, True)]
     1229
     1230                """
     1231
     1232                return self == self.coset_representative(index_set=index_set,side=side)
     1233
     1234            def to_affine_grassmannian(self):
     1235                r"""
     1236                Returns the unique affine Grassmannian element in the same coset of ``self``
     1237                with respect to the finite Weyl group acting on the right.
     1238
     1239                EXAMPLES::
     1240
     1241                     sage: PW0 = ExtendedAffineWeylGroup(['A',2,1],prefix0="s")
     1242                     sage: elts = PW0.some_elements()
     1243                     sage: [(x, x.to_affine_grassmannian()) for x in elts]
     1244                     [(t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2, t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2*s1)]
     1245
     1246                """
     1247
     1248                return self.coset_representative(index_set=self.parent().realization_of().classical_root_system().index_set())
     1249
     1250            def is_affine_grassmannian(self):
     1251                r"""
     1252                Returns whether ``self`` is affine Grassmannian.
     1253
     1254                EXAMPLES::
     1255
     1256                    sage: PW0 = ExtendedAffineWeylGroup(['A',2,1],prefix0="s")
     1257                    sage: E = PW0.realization_of()
     1258                    sage: F = E.fundamental_group().family()
     1259                    sage: [(x,PW0.fundamental_group_morphism(x).is_affine_grassmannian()) for x in F]
     1260                    [(pi[0], True), (pi[1], True), (pi[2], True)]
     1261                    sage: b = E.lattice_basis()
     1262                    sage: [(-x,PW0.translation_group_morphism(-x).is_affine_grassmannian()) for x in b]
     1263                    [(-Lambdacheck[1], True), (-Lambdacheck[2], True)]
     1264
     1265                """
     1266
     1267                return self == self.to_affine_grassmannian()
     1268
     1269            def bruhat_le(self, x):
     1270                r"""
     1271                Returns whether ``self`` <= `x` in Bruhat order.
     1272
     1273                EXAMPLES::
     1274
     1275                    sage: WF = ExtendedAffineWeylGroup(['A',2,1],prefix="S",print_tuple=True,style="WF")
     1276                    sage: E = WF.realization_of()
     1277                    sage: W = E.affine_weyl()
     1278                    sage: v = W.from_reduced_word([2,1,0])
     1279                    sage: w = W.from_reduced_word([2,0,1,0])
     1280                    sage: v.bruhat_le(w)
     1281                    True
     1282                    sage: vx = WF.affine_weyl_morphism(v); vx
     1283                    (S2*S1*S0, pi[0])
     1284                    sage: wx = WF.affine_weyl_morphism(w); wx
     1285                    (S2*S0*S1*S0, pi[0])
     1286                    sage: vx.bruhat_le(wx)
     1287                    True
     1288                    sage: F = E.fundamental_group()
     1289                    sage: f = WF.fundamental_group_morphism(F(2))
     1290                    sage: vx.bruhat_le(wx*f)
     1291                    False
     1292                    sage: (vx*f).bruhat_le(wx*f)
     1293                    True
     1294
     1295                .. warning::
     1296
     1297                    Must be implemented by "WF".
     1298
     1299                """
     1300                WF = self.parent().realization_of().WF()
     1301                return WF(self).bruhat_le(WF(x))
     1302
     1303            def is_translation(self):
     1304                r"""
     1305                Returns whether ``self`` is a translation element or not.
     1306
     1307                EXAMPLES::
     1308
     1309                    sage: FW = ExtendedAffineWeylGroup(['A',2,1],prefix="S",style="FW")
     1310                    sage: E = FW.realization_of()
     1311                    sage: F = E.fundamental_group()
     1312                    sage: FW.affine_weyl_morphism(E.affine_weyl().from_reduced_word([1,2,1,0])).is_translation()
     1313                    True
     1314                    sage: FW.translation_group_morphism(E.lattice_basis()[1]).is_translation()
     1315                    True
     1316                    sage: FW.simple_reflection(0).is_translation()
     1317                    False
     1318
     1319                """
     1320                w = self.to_classical_weyl()
     1321                return w == w.parent().one()
     1322
     1323            def action(self, la):
     1324                r"""
     1325                Action of ``self`` on a lattice element ``la``.
     1326
     1327                EXAMPLES::
     1328
     1329                    sage: FW = ExtendedAffineWeylGroup(['A',2,1],prefix="s",style="FW")
     1330                    sage: E = FW.realization_of()
     1331                    sage: x = FW.an_element(); x
     1332                    pi[2] * s0*s1*s2
     1333                    sage: la = E.lattice().an_element(); la
     1334                    2*Lambdacheck[1] + 2*Lambdacheck[2]
     1335                    sage: x.action(la)
     1336                    5*Lambdacheck[1] - 3*Lambdacheck[2]
     1337
     1338                .. warning::
     1339
     1340                    Must be implemented by style "PW0".
     1341
     1342                """
     1343                PW0 = self.parent().realization_of().PW0()
     1344                return PW0(self).action(la)
     1345
     1346            def action_on_affine_roots(self, beta):
     1347                r"""
     1348                Act by ``self`` on the affine root lattice element ``beta``.
     1349
     1350                .. warning::
     1351
     1352                    Must be implemented by style "FW".
     1353                """
     1354                WR = self.parent().realization_of()
     1355                assert beta in RootSystem(WR.cartan_type()).root_lattice()
     1356                return WR.FW()(self).action_on_affine_roots(beta)
     1357
     1358            def face_data(self, i):
     1359                r"""
     1360                Returns data for the alcove of ``self`` and the face labeled by the Dynkin node ``i``.
     1361
     1362                Let the extended affine Weyl group element ``self`` act on the affine simple root `\alpha_i`:
     1363
     1364                ..MATH::
     1365
     1366                    ``self`` `\alpha_i` = m `\delta` + `\beta`
     1367
     1368                Returns the 2-tuple `(m,\beta)` where `m` is the height of the bounding hyperplane and `\beta` is
     1369                the classical root giving the normal vector.
     1370
     1371                EXAMPLES::
     1372
     1373                    sage: We=ExtendedAffineWeylGroup(['A',2,1],prefix0="s",prefix="S")
     1374                    sage: x = We.an_element(); x
     1375                    t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2
     1376                    sage: x.face_data(0)
     1377                    (-1, alpha[1])
     1378
     1379                """
     1380                Qaf = RootSystem(self.parent().realization_of().cartan_type()).root_lattice()
     1381                gamma = self.action_on_affine_roots(Qaf.simple_root(i))
     1382                return gamma[0], Qaf.classical()(gamma)
     1383
     1384            def alcove_walk_signs(self):
     1385                r"""
     1386                Returns a signed alcove walk for ``self``.
     1387
     1388                The returned data is a 3-tuple `g`, ``rw``, ``signs``.
     1389                Let ``self`` = `g` * `w` where `g` has length zero and `w` has reduced word ``rw``.
     1390                Starting with `g` and applying simple reflections from `rw` on the right, one obtains
     1391                a sequence of extended affine Weyl group elements (that is, alcoves) and simple roots.
     1392                The signs give the sequence of sides on which the alcoves lie, relative to the face
     1393                indicated by the simple roots.
     1394
     1395                EXAMPLES::
     1396
     1397                    sage: We=ExtendedAffineWeylGroup(['A',3,1],prefix0="s",prefix="S",style="FW")
     1398                    sage: w = We.from_reduced_word([0,2,1,3,0])*We.fundamental_group_morphism(1); w
     1399                    pi[1] * S3*S1*S2*S0*S3
     1400                    sage: w.alcove_walk_signs()
     1401                    (pi[1], [3, 1, 2, 0, 3], [-1, 1, -1, -1, 1])
     1402
     1403                """
     1404                We = self.parent()
     1405                gw = We.realization_of().FW()(self)
     1406                g = gw.summand_projection(0)
     1407                w = gw.summand_projection(1)
     1408                rw = w.reduced_word()
     1409                u_curr = We.fundamental_group_morphism(g.value())
     1410                signs=[]
     1411                for i in rw:
     1412                    m, beta = u_curr.face_data(i)
     1413                    if beta.is_positive_root():
     1414                        signs = signs + [1]
     1415                    else:
     1416                        signs = signs + [-1]
     1417                    u_curr = u_curr * We.simple_reflection(i)
     1418                return g, rw, signs
     1419
     1420            @abstract_method
     1421            def to_dual(self):
     1422                r"""
     1423                Map ``self`` to the extended affine Weyl group of dual affine type.
     1424
     1425                EXAMPLES::
     1426
     1427                    sage: W = ExtendedAffineWeylGroup(['B',2,1],prefix0="s",prefix="S")
     1428                    sage: E = W.realization_of()
     1429                    sage: w = W.translation_group_morphism(3* E.lattice_basis()[1]) * W.classical_weyl_morphism(E.classical_weyl().from_reduced_word([1,2])); w
     1430                    t[3*Lambdacheck[1]] * s1*s2
     1431                    sage: w.to_dual()
     1432                    t[3*Lambda[1]] * s1*s2
     1433                    sage: w = E.W0P()(w); w
     1434                    s1*s2 * t[3*Lambdacheck[1] - 3*Lambdacheck[2]]
     1435                    sage: w.to_dual()
     1436                    s1*s2 * t[3*Lambda[1] - 3*Lambda[2]]
     1437                    sage: w = E.WF()(w); w
     1438                    S0*S2*S1*S0*S2*S1*S0 * pi[1]
     1439                    sage: w.to_dual()
     1440                    S0*S2*S1*S0*S2*S1*S0 * pi[1]
     1441                    sage: w = E.FW()(w); w
     1442                    pi[1] * S1*S2*S1*S0*S2*S1*S0
     1443                    sage: w.to_dual()
     1444                    pi[1] * S1*S2*S1*S0*S2*S1*S0
     1445
     1446                """
     1447
     1448    class ExtendedAffineWeylGroupPW0Element(GroupSemidirectProduct.Element):
     1449        r"""
     1450        The element class for the "PW0" realization.
     1451        """
     1452
     1453        def action(self, la):
     1454            r"""
     1455            Returns the action of ``self`` on an element ``la`` of the translation lattice.
     1456
     1457            EXAMPLES::
     1458
     1459                sage: PW0 = ExtendedAffineWeylGroup(['A',2,1],prefix0="s")
     1460                sage: E = PW0.realization_of()
     1461                sage: x = PW0.an_element(); x
     1462                t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2
     1463                sage: la = E.lattice().an_element(); la
     1464                2*Lambdacheck[1] + 2*Lambdacheck[2]
     1465                sage: x.action(la)
     1466                -2*Lambdacheck[1] + 4*Lambdacheck[2]
     1467
     1468            """
     1469            w = self.summand_projection(1)
     1470            assert la in w.parent().domain()
     1471            return self.summand_projection(0).value + w.action(la)
     1472
     1473        def has_descent(self, i, side='right', positive=False):
     1474            r"""
     1475            INPUT:
     1476
     1477            - `i` - an index.
     1478
     1479            OPTIONAL:
     1480
     1481            - side -- 'left' or 'right' (default: 'right')
     1482            - positive -- True or False (default: False)
     1483
     1484            EXAMPLES::
     1485
     1486                sage: We = ExtendedAffineWeylGroup(['A',4,2],prefix0="s")
     1487                sage: w = We.from_reduced_word([0,1]); w
     1488                t[Lambda[1]] * s1*s2
     1489                sage: w.has_descent(0, side='left')
     1490                True
     1491
     1492            """
     1493            E = self.parent().realization_of()
     1494            if side == 'right':
     1495                self = ~self
     1496            if positive:
     1497                return not self.has_descent(i, side='left')
     1498            la = self.summand_projection(0).value
     1499            w = self.summand_projection(1)
     1500            if i == 0:
     1501                ip = la.scalar(E._special_translation_covector)
     1502                if ip > 1:
     1503                    return True
     1504                if ip < 1:
     1505                    return False
     1506                return E._special_root.weyl_action(w, inverse=True).is_positive_root()
     1507            ip = la.scalar(E._simpleR0[i]) # test height versus simple (co)root
     1508            if ip < 0:
     1509                return True
     1510            if ip > 0:
     1511                return False
     1512            return w.has_descent(i, side='left')
     1513
     1514        def to_translation_left(self):
     1515            r"""
     1516            The image of ``self`` under the map that projects to the translation lattice
     1517            factor after factoring it to the left as in style "PW0".
     1518
     1519            EXAMPLES::
     1520
     1521                sage: PW0 = ExtendedAffineWeylGroup(['A',2,1],prefix0="s")
     1522                sage: s = PW0.S0(); s
     1523                t[Lambdacheck[1] + Lambdacheck[2]] * s1*s2*s1
     1524                sage: s.to_translation_left()
     1525                Lambdacheck[1] + Lambdacheck[2]
     1526
     1527            """
     1528            return self.summand_projection(0).value # undo the GroupExp
     1529
     1530        def to_classical_weyl(self):
     1531            r"""
     1532            Returns the image of ``self`` under the homomorphism that projects to the classical
     1533            Weyl group factor after rewriting it in either style "PW0" or "W0P".
     1534
     1535            EXAMPLES::
     1536
     1537                sage: PW0 = ExtendedAffineWeylGroup(['A',2,1],prefix0="s")
     1538                sage: s = PW0.S0(); s
     1539                t[Lambdacheck[1] + Lambdacheck[2]] * s1*s2*s1
     1540                sage: s.to_classical_weyl()
     1541                s1*s2*s1
     1542
     1543            """
     1544            return self.summand_projection(1)
     1545
     1546        def to_dual(self):
     1547            r"""
     1548            Map ``self`` to the extended affine Weyl group of dual affine type.
     1549
     1550            EXAMPLES::
     1551
     1552                sage: w = ExtendedAffineWeylGroup(['B',2,1],prefix0="s",prefix="S").an_element(); w
     1553                t[2*Lambdacheck[1] + 2*Lambdacheck[2]] * s1*s2
     1554                sage: w.to_dual()
     1555                t[2*Lambda[1] + 2*Lambda[2]] * s1*s2
     1556
     1557            """
     1558            la = self.to_translation_left()
     1559            w = self.to_classical_weyl()
     1560            DW = self.parent().dual()
     1561            return DW(la.to_dual_type_cospace()) * DW(DW.realization_of().classical_weyl().from_reduced_word(w.reduced_word()))
     1562
     1563    class ExtendedAffineWeylGroupPW0(GroupSemidirectProduct, BindableClass):
     1564        r"""
     1565        Extended affine Weyl group, realized as the semidirect product of the translation lattice
     1566        by the finite Weyl group.
     1567
     1568        INPUT:
     1569
     1570        - `E` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class`
     1571
     1572        EXAMPLES::
     1573
     1574            sage: ExtendedAffineWeylGroup(['A',2,1],style="PW0")
     1575            Semidirect product of Multiplicative form of Coweight lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice)
     1576
     1577        """
     1578
     1579        def __init__(self, E):
     1580            # note that we have to use the multiplicative version of the translation lattice
     1581            # and change the twist to deal with this
     1582            def twist(w,l):
     1583                return E.exp_lattice()(w.action(l.value))
     1584
     1585            GroupSemidirectProduct.__init__(self, E.exp_lattice(), E.classical_weyl(), twist = twist, act_to_right=False, prefix0='t', print_tuple = E._print_tuple, category=E.Realizations())
     1586            self._style = "PW0"
     1587
     1588        def translation_group_morphism(self, la):
     1589            r"""
     1590            Map the translation lattice element ``la`` into ``self``.
     1591
     1592            EXAMPLES::
     1593
     1594                sage: PW0 = ExtendedAffineWeylGroup(['A',2,1], prefix0="s", print_tuple = True, style="PW0")
     1595                sage: la = PW0.realization_of().lattice().an_element(); la
     1596                2*Lambdacheck[1] + 2*Lambdacheck[2]
     1597                sage: PW0.translation_group_morphism(la)
     1598                (t[2*Lambdacheck[1] + 2*Lambdacheck[2]], 1)
     1599
     1600            """
     1601            E = self.realization_of()
     1602            return self((E.exp_lattice()(la),self.summands()[1].one()))
     1603
     1604        @cached_method
     1605        def S0(self):
     1606            """
     1607            Returns the affine simple reflection.
     1608
     1609            EXAMPLE::
     1610
     1611                sage: ExtendedAffineWeylGroup("B2",prefix0="s").S0()
     1612                t[Lambdacheck[2]] * s2*s1*s2
     1613
     1614            """
     1615            E = self.realization_of()
     1616            return self((E.exp_lattice()(E.lattice()(E._special_translation)), E._special_reflection))
     1617
     1618        @cached_method
     1619        def simple_reflection(self, i):
     1620            r"""
     1621            Returns the `i`-th simple reflection in ``self``.
     1622
     1623            EXAMPLES::
     1624               sage: PW0 = ExtendedAffineWeylGroup("G2",prefix0="s")
     1625               sage: E = PW0.realization_of()
     1626               sage: [(i, PW0.simple_reflection(i)) for i in E.index_set()]
     1627               [(0, t[Lambdacheck[2]] * s2*s1*s2*s1*s2), (1, s1), (2, s2)]
     1628
     1629            """
     1630            if i == 0:
     1631                return self.S0()
     1632            else:
     1633                E = self.realization_of()
     1634                return self.classical_weyl_morphism(E.classical_weyl().simple_reflection(i))
     1635
     1636        @cached_method
     1637        def simple_reflections(self):
     1638            r"""
     1639            Returns a family for the simple reflections of ``self``.
     1640
     1641            EXAMPLES::
     1642
     1643                sage: ExtendedAffineWeylGroup("A3",prefix0="s").simple_reflections()
     1644                Finite family {0: t[Lambdacheck[1] + Lambdacheck[3]] * s1*s2*s3*s2*s1, 1: s1, 2: s2, 3: s3}
     1645
     1646            """
     1647            return Family(self.realization_of().index_set(), lambda i: self.simple_reflection(i))
     1648
     1649        def classical_weyl_morphism(self, w):
     1650            r"""
     1651            Returns the image of `w` under the homomorphism of the classical Weyl group into ``self``.
     1652
     1653            EXAMPLES::
     1654
     1655                sage: PW0 = ExtendedAffineWeylGroup("A3",print_tuple=True,prefix0="s")
     1656                sage: E = PW0.realization_of()
     1657                sage: PW0.classical_weyl_morphism(E.classical_weyl().from_reduced_word([1,2]))
     1658                (t[0], s1*s2)
     1659
     1660            """
     1661            return self((self.summands()[0].one(),w))
     1662
     1663    class ExtendedAffineWeylGroupW0PElement(GroupSemidirectProduct.Element):
     1664        r"""
     1665        The element class for the W0P realization.
     1666        """
     1667        def has_descent(self, i, side='right', positive=False):
     1668            r"""
     1669            INPUT:
     1670
     1671            - `i` - an index.
     1672
     1673            OPTIONAL:
     1674
     1675            - side - 'left' or 'right' (default: 'right')
     1676            - positive - True or False (default: False)
     1677
     1678            EXAMPLES::
     1679
     1680                sage: We = ExtendedAffineWeylGroup(['A',4,2],prefix0="s",style="W0P")
     1681                sage: w = We.from_reduced_word([0,1]); w
     1682                s1*s2 * t[Lambda[1] - Lambda[2]]
     1683                sage: w.has_descent(0, side='left')
     1684                True
     1685
     1686            """
     1687            E = self.parent().realization_of()
     1688            if side == 'left':
     1689                self = ~self
     1690            if positive:
     1691                return not self.has_descent(i, side='right')
     1692            w = self.summand_projection(0)
     1693            la = self.summand_projection(1).value
     1694            if i == 0:
     1695                ip = la.scalar(E._special_translation_covector)
     1696                if ip < -1:
     1697                    return True
     1698                if ip > -1:
     1699                    return False
     1700                return E._special_root.weyl_action(w).is_positive_root()
     1701            ip = l.scalar(E._simpleR0[i]) # test height versus simple (co)root
     1702            if ip > 0:
     1703                return True
     1704            if ip < 0:
     1705                return False
     1706            return w.has_descent(i, side='right')
     1707
     1708        def to_classical_weyl(self):
     1709            r"""
     1710            Project ``self`` into the classical Weyl group.
     1711
     1712            EXAMPLES::
     1713
     1714                sage: W0P = ExtendedAffineWeylGroup(['A',2,1],prefix0="s",style="W0P")
     1715                sage: x = W0P.simple_reflection(0); x
     1716                s1*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[2]]
     1717                sage: x.to_classical_weyl()
     1718                s1*s2*s1
     1719
     1720            """
     1721            return self.summand_projection(0)
     1722
     1723        def to_translation_right(self):
     1724            r"""
     1725            Project onto the right (translation) factor in the "W0P" style.
     1726
     1727            EXAMPLES::
     1728
     1729                sage: W0P = ExtendedAffineWeylGroup(['A',2,1],prefix0="s",style="W0P")
     1730                sage: x = W0P.simple_reflection(0); x
     1731                s1*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[2]]
     1732                sage: x.to_translation_right()
     1733                -Lambdacheck[1] - Lambdacheck[2]
     1734
     1735            """
     1736            return self.summand_projection(1).value
     1737
     1738        def to_dual(self):
     1739            r"""
     1740            Map ``self`` to the extended affine Weyl group of dual affine type.
     1741
     1742            EXAMPLES::
     1743
     1744                sage: w = ExtendedAffineWeylGroup(['B',2,1],prefix0="s",prefix="S",style="W0P").an_element(); w
     1745                s1*s2 * t[2*Lambdacheck[1] + 2*Lambdacheck[2]]
     1746                sage: w.to_dual()
     1747                s1*s2 * t[2*Lambda[1] + 2*Lambda[2]]
     1748
     1749            """
     1750            la = self.to_translation_right()
     1751            w = self.to_classical_weyl()
     1752            DW = self.parent().dual()
     1753            return DW(DW.realization_of().classical_weyl().from_reduced_word(w.reduced_word())) * DW(la.to_dual_type_cospace())
     1754
     1755
     1756
     1757    class ExtendedAffineWeylGroupW0P(GroupSemidirectProduct, BindableClass):
     1758        r"""
     1759        Extended affine Weyl group, realized as the semidirect product of the finite Weyl group
     1760        by the translation lattice.
     1761
     1762        INPUT:
     1763
     1764        - `E` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class`
     1765
     1766        EXAMPLES::
     1767
     1768            sage: ExtendedAffineWeylGroup(['A',2,1], prefix0="s", style="W0P")
     1769            Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the coweight lattice) acting on Multiplicative form of Coweight lattice of the Root system of type ['A', 2]
     1770
     1771        """
     1772
     1773        def __init__(self, E):
     1774            def twist(w,l):
     1775                return E.exp_lattice()(w.action(l.value))
     1776
     1777            GroupSemidirectProduct.__init__(self, E.classical_weyl(), E.exp_lattice(), twist=twist, act_to_right=True, prefix1='t', print_tuple=E._print_tuple, category=E.Realizations())
     1778            self._style = "W0P"
     1779
     1780        def S0(self):
     1781            r"""
     1782            Returns the zero-th simple reflection in style "W0P".
     1783
     1784            EXAMPLES::
     1785
     1786                sage: ExtendedAffineWeylGroup(["A",3,1],prefix0="s",style="W0P").S0()
     1787                s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]]
     1788
     1789            """
     1790            E = self.realization_of()
     1791            return self((E._special_reflection,E.exp_lattice()(E.lattice()(-E._special_translation))))
     1792
     1793        def simple_reflection(self, i):
     1794            r"""
     1795            Returns the `i`-th simple reflection in ``self``.
     1796            """
     1797            if i == 0:
     1798                return self.S0()
     1799            E = self.realization_of()
     1800            return self.classical_weyl_morphism(E.classical_weyl().simple_reflection(i))
     1801
     1802        def simple_reflections(self):
     1803            r"""
     1804            Returns the family of simple reflections.
     1805
     1806            EXAMPLES::
     1807
     1808                sage: ExtendedAffineWeylGroup(["A",3,1],prefix0="s",style="W0P").simple_reflections()
     1809                Finite family {0: s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]], 1: s1, 2: s2, 3: s3}
     1810
     1811            """
     1812
     1813            return Family(self.realization_of().index_set(), lambda i: self.simple_reflection(i))
     1814
     1815        def classical_weyl_morphism(self, w):
     1816            r"""
     1817            Returns the image of the classical Weyl group element `w` in ``self``.
     1818
     1819            EXAMPLES::
     1820
     1821                sage: W0P = ExtendedAffineWeylGroup(['A',2,1],prefix0="s",print_tuple=True,style="W0P")
     1822                sage: W0P.classical_weyl_morphism(W0P.realization_of().classical_weyl().from_reduced_word([2,1]))
     1823                (s2*s1, t[0])
     1824
     1825            """
     1826            return self((w,self.summands()[1].one()))
     1827
     1828        def translation_group_morphism(self, la):
     1829            r"""
     1830            Returns the image of the lattice element ``la`` in ``self``.
     1831
     1832            EXAMPLES::
     1833
     1834                sage: W0P = ExtendedAffineWeylGroup(['A',2,1],prefix0="s",print_tuple=True,style="W0P")
     1835                sage: W0P.translation_group_morphism(W0P.realization_of().lattice().an_element())
     1836                (1, t[2*Lambdacheck[1] + 2*Lambdacheck[2]])
     1837
     1838            """
     1839            return self((self.summands()[0].one(),self.realization_of().exp_lattice()(la)))
     1840
     1841    class ExtendedAffineWeylGroupWFElement(GroupSemidirectProduct.Element):
     1842        r"""
     1843        Element class for the "WF" realization.
     1844        """
     1845
     1846        def has_descent(self, i, side='right', positive=False):
     1847            r"""
     1848            INPUT:
     1849
     1850            - `i` -- an index.
     1851
     1852            OPTIONAL:
     1853
     1854            - ``side`` -- 'left' or 'right' (default: 'right')
     1855            - ``positive`` -- True or False (default: False)
     1856
     1857            """
     1858            E = self.parent().realization_of()
     1859            if side == 'right':
     1860                self = ~self
     1861            if positive:
     1862                return not self.has_descent(i, side='left')
     1863            return self.summand_projection(0).has_descent(i, side='left')
     1864
     1865        def to_fundamental_group(self):
     1866            r"""
     1867            Project ``self`` to the right (fundamental group) factor in the "WF" style.
     1868
     1869            EXAMPLES::
     1870
     1871                sage: WF = ExtendedAffineWeylGroup(['A',2,1],prefix="s",style="WF")
     1872                sage: E = WF.realization_of()
     1873                sage: x = WF.translation_group_morphism(E.lattice_basis()[1]); x
     1874                s0*s2 * pi[1]
     1875                sage: x.to_fundamental_group()
     1876                pi[1]
     1877
     1878            """
     1879            return self.summand_projection(1)
     1880
     1881        def to_affine_weyl_left(self):
     1882            r"""
     1883            Project ``self`` to the left (affine Weyl group) factor in the "WF" style.
     1884
     1885            EXAMPLES::
     1886
     1887                sage: WF = ExtendedAffineWeylGroup(['A',2,1],prefix="s",style="WF")
     1888                sage: E = WF.realization_of()
     1889                sage: x = WF.translation_group_morphism(E.lattice_basis()[1]); x
     1890                s0*s2 * pi[1]
     1891                sage: x.to_affine_weyl_left()
     1892                s0*s2
     1893
     1894            """
     1895            return self.summand_projection(0)
     1896
     1897        def bruhat_le(self, x):
     1898            r"""
     1899            Return whether ``self`` is less than or equal to `x` in the Bruhat order.
     1900
     1901            EXAMPLES::
     1902
     1903                sage: WF = ExtendedAffineWeylGroup(['A',2,1],prefix="s",print_tuple=True,style="WF")
     1904                sage: E = WF.realization_of()
     1905                sage: r = E.affine_weyl().from_reduced_word
     1906                sage: v = r([1,0])
     1907                sage: w = r([1,2,0])
     1908                sage: v.bruhat_le(w)
     1909                True
     1910                sage: vv = WF.affine_weyl_morphism(v); vv
     1911                (s1*s0, pi[0])
     1912                sage: ww = WF.affine_weyl_morphism(w); ww
     1913                (s1*s2*s0, pi[0])
     1914                sage: vv.bruhat_le(ww)
     1915                True
     1916                sage: f = E.fundamental_group()(2); f
     1917                pi[2]
     1918                sage: ff = WF.fundamental_group_morphism(f); ff
     1919                (1, pi[2])
     1920                sage: vv.bruhat_le(ww*ff)
     1921                False
     1922                sage: (vv*ff).bruhat_le(ww*ff)
     1923                True
     1924
     1925            """
     1926            if self.summand_projection(1) != x.summand_projection(1):
     1927                return False
     1928            return self.summand_projection(0).bruhat_le(x.summand_projection(0))
     1929
     1930        def to_dual(self):
     1931            r"""
     1932            Map ``self`` to the extended affine Weyl group of dual affine type.
     1933
     1934            EXAMPLES::
     1935
     1936                sage: w = ExtendedAffineWeylGroup(['B',2,1],prefix0="s",prefix="S",style="WF").an_element(); w
     1937                S1*S0*S2 * pi[1]
     1938                sage: w.to_dual()
     1939                S1*S0*S2 * pi[1]
     1940
     1941            """
     1942            w = self.to_affine_weyl_left()
     1943            pi = self.to_fundamental_group()
     1944            DW = self.parent().dual()
     1945            return DW.from_reduced_word(w.reduced_word()) * DW.fundamental_group_morphism(pi.value())
     1946
     1947    class ExtendedAffineWeylGroupWF(GroupSemidirectProduct, BindableClass):
     1948        r"""
     1949        Extended affine Weyl group, realized as the semidirect product of the affine Weyl group
     1950        by the fundamental group.
     1951
     1952        INPUT:
     1953
     1954        - `E` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class`
     1955
     1956        EXAMPLES::
     1957
     1958            sage: ExtendedAffineWeylGroup(['A',2,1], style="WF")
     1959            Semidirect product of Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice) acted upon by Fundamental group of type ['A', 2, 1]
     1960
     1961        """
     1962
     1963        def __init__(self, E):
     1964            def twist(g,w):
     1965                return g.act_on_affine_weyl(w)
     1966
     1967            GroupSemidirectProduct.__init__(self, E.affine_weyl(), E.fundamental_group(), twist = twist, act_to_right=False, print_tuple = E._print_tuple, category=E.Realizations())
     1968            self._style = "WF"
     1969
     1970        def affine_weyl_morphism(self, w):
     1971            r"""
     1972            Returns the image of the affine Weyl group element `w` in ``self``.
     1973
     1974            EXAMPLES::
     1975
     1976                sage: WF = ExtendedAffineWeylGroup(['C',2,1],prefix="S",print_tuple=True,style="WF")
     1977                sage: WF.affine_weyl_morphism(WF.realization_of().affine_weyl().from_reduced_word([1,2,1,0]))
     1978                (S1*S2*S1*S0, pi[0])
     1979
     1980            """
     1981            return self((w,self.summands()[1].one()))
     1982
     1983        @cached_method
     1984        def simple_reflections(self):
     1985            r"""
     1986            Returns the family of simple reflections.
     1987
     1988            EXAMPLES::
     1989
     1990                sage: ExtendedAffineWeylGroup(["A",3,1],prefix="r",style="WF").simple_reflections()
     1991                Finite family {0: r0, 1: r1, 2: r2, 3: r3}
     1992
     1993            """
     1994            E = self.realization_of()
     1995            W = E.affine_weyl()
     1996            return Family(E.index_set(), lambda i: self.affine_weyl_morphism(W.simple_reflection(i)))
     1997
     1998        @cached_method
     1999        def fundamental_group_morphism(self, f):
     2000            r"""
     2001            Returns the image of `f` under the homomorphism from the fundamental group into
     2002            the right (fundamental group) factor in "WF" style.
     2003
     2004            EXAMPLES::
     2005
     2006                sage: WF = ExtendedAffineWeylGroup(['E',6,1],prefix="S",print_tuple=True,style="WF")
     2007                sage: F = WF.realization_of().fundamental_group().family()
     2008                sage: [(x,WF.fundamental_group_morphism(x)) for x in F]
     2009                [(pi[0], (1, pi[0])), (pi[1], (1, pi[1])), (pi[6], (1, pi[6]))]
     2010
     2011            """
     2012            return self((self.summands()[0].one(),f))
     2013
     2014    class ExtendedAffineWeylGroupFWElement(GroupSemidirectProduct.Element):
     2015        r"""
     2016        The element class for the "FW" realization.
     2017        """
     2018        def has_descent(self, i, side='right', positive=False):
     2019            r"""
     2020            INPUT:
     2021
     2022            - `i` -- an index.
     2023
     2024            OPTIONAL:
     2025
     2026            - ``side`` -- 'left' or 'right' (default: 'right')
     2027            - ``positive`` -- True or False (default: False)
     2028
     2029            """
     2030            E = self.parent().realization_of()
     2031            if side == 'left':
     2032                self = ~self
     2033            if positive:
     2034                return not self.has_descent(i, side='right')
     2035            return self.summand_projection(1).has_descent(i, side='right')
     2036
     2037        def to_fundamental_group(self):
     2038            r"""
     2039            Returns the projection of ``self`` to the fundamental group in the "FW" style.
     2040
     2041            EXAMPLES::
     2042
     2043                sage: FW = ExtendedAffineWeylGroup(['A',2,1],prefix="S",style="FW")
     2044                sage: E = FW.realization_of()
     2045                sage: x = FW.translation_group_morphism(E.lattice_basis()[2]); x
     2046                pi[2] * S1*S2
     2047                sage: x.to_fundamental_group()
     2048                pi[2]
     2049
     2050            """
     2051            return self.summand_projection(0)
     2052
     2053        def to_affine_weyl_right(self):
     2054            r"""
     2055            Project ``self`` to the right (affine Weyl group) factor in the "FW" style.
     2056
     2057            EXAMPLES::
     2058
     2059                sage: FW = ExtendedAffineWeylGroup(['A',2,1],prefix="s",style="FW")
     2060                sage: E = FW.realization_of()
     2061                sage: x = FW.translation_group_morphism(E.lattice_basis()[1]); x
     2062                pi[1] * s2*s1
     2063                sage: x.to_affine_weyl_right()
     2064                s2*s1
     2065
     2066            """
     2067            return self.summand_projection(1)
     2068
     2069        def action_on_affine_roots(self, beta):
     2070            r"""
     2071            Act by ``self`` on the affine root lattice element ``beta``.
     2072
     2073            EXAMPLES::
     2074
     2075                sage: FW = ExtendedAffineWeylGroup(['A',2,1],prefix="s",style="FW")
     2076                sage: E = FW.realization_of()
     2077                sage: w = FW.an_element(); w
     2078                pi[2] * s0*s1*s2
     2079                sage: Qaf = RootSystem(['A',2,1]).root_lattice()
     2080                sage: v = Qaf.an_element(); v
     2081                2*alpha[0] + 2*alpha[1] + 3*alpha[2]
     2082                sage: w.action_on_affine_roots(v)
     2083                alpha[0] + alpha[1]
     2084
     2085            """
     2086            g = self.summand_projection(0)
     2087            w = self.summand_projection(1)
     2088            return g.act_on_affine_lattice(w.action(beta))
     2089
     2090        def to_dual(self):
     2091            r"""
     2092            Map ``self`` to the extended affine Weyl group of dual affine type.
     2093
     2094            EXAMPLES::
     2095
     2096                sage: w = ExtendedAffineWeylGroup(['B',2,1],prefix0="s",prefix="S",style="FW").an_element(); w
     2097                pi[1] * S1*S0*S2
     2098                sage: w.to_dual()
     2099                pi[1] * S1*S0*S2
     2100
     2101            """
     2102            pi = self.to_fundamental_group()
     2103            w = self.to_affine_weyl_right()
     2104            DW = self.parent().dual()
     2105            return DW.fundamental_group_morphism(pi.value()) * DW.from_reduced_word(w.reduced_word())
     2106
     2107    class ExtendedAffineWeylGroupFW(GroupSemidirectProduct, BindableClass):
     2108        r"""
     2109        Extended affine Weyl group, realized as the semidirect product of the affine Weyl group
     2110        by the fundamental group.
     2111
     2112        INPUT:
     2113
     2114        - `E` -- A parent with realization in :class:`ExtendedAffineWeylGroup_Class`
     2115
     2116        EXAMPLES::
     2117
     2118            sage: ExtendedAffineWeylGroup(['A',2,1],style="FW")
     2119            Semidirect product of Fundamental group of type ['A', 2, 1] acting on Weyl Group of type ['A', 2, 1] (as a matrix group acting on the root lattice)
     2120
     2121        """
     2122
     2123
     2124        def __init__(self, E):
     2125            def twist(g,w):
     2126                return g.act_on_affine_weyl(w)
     2127
     2128            GroupSemidirectProduct.__init__(self, E.fundamental_group(), E.affine_weyl(), twist = twist, act_to_right=True, print_tuple = E._print_tuple, category=E.Realizations())
     2129            self._style = "FW"
     2130
     2131        @cached_method
     2132        def simple_reflections(self):
     2133            r"""
     2134            Returns the family of simple reflections of ``self``.
     2135
     2136            EXAMPLES::
     2137
     2138                sage: ExtendedAffineWeylGroup(['A',2,1],prefix="S",print_tuple=True,style="FW").simple_reflections()
     2139                Finite family {0: (pi[0], S0), 1: (pi[0], S1), 2: (pi[0], S2)}
     2140
     2141            """
     2142            E = self.realization_of()
     2143            W = E.affine_weyl()
     2144            return Family(E.index_set(), lambda i: self.affine_weyl_morphism(W.simple_reflection(i)))
     2145
     2146        def affine_weyl_morphism(self, w):
     2147            r"""
     2148            Returns the image of `w` under the map of the affine Weyl group into the right
     2149            (affine Weyl group) factor in the "FW" style.
     2150
     2151            EXAMPLES::
     2152
     2153                sage: FW = ExtendedAffineWeylGroup(['A',2,1],prefix="S",print_tuple=True,style="FW")
     2154                sage: E = FW.realization_of()
     2155                sage: FW.affine_weyl_morphism(E.affine_weyl().from_reduced_word([0,2,1]))
     2156                (pi[0], S0*S2*S1)
     2157
     2158            """
     2159            return self((self.summands()[0].one(),w))
     2160
     2161        @cached_method
     2162        def fundamental_group_morphism(self, f):
     2163            r"""
     2164            Returns the image of the fundamental group element `f` into ``self``.
     2165
     2166            EXAMPLES::
     2167
     2168                sage: FW = ExtendedAffineWeylGroup(['A',2,1],prefix="S",print_tuple=True,style="FW")
     2169                sage: E = FW.realization_of()
     2170                sage: FW.fundamental_group_morphism(E.fundamental_group()(2))
     2171                (pi[2], 1)
     2172
     2173            """
     2174            return self((f,self.summands()[1].one()))
     2175
     2176
     2177ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupPW0.Element = ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupPW0Element
     2178
     2179ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupW0P.Element = ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupW0PElement
     2180
     2181ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupWF.Element = ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupWFElement
     2182
     2183ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupFW.Element = ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupFWElement
     2184
     2185
  • new file src/sage/combinat/root_system/fundamental_group.py

    diff --git a/src/sage/combinat/root_system/fundamental_group.py b/src/sage/combinat/root_system/fundamental_group.py
    new file mode 100644
    index 0000000..2d0f614
    - +  
     1"""
     2Fundamental Group of an Extended Affine Weyl Group
     3
     4"""
     5
     6#*****************************************************************************
     7#       Copyright (C) 2013 Mark Shimozono <mshimo at math.vt.edu>
     8#
     9#  Distributed under the terms of the GNU General Public License (GPL)
     10#
     11#                  http://www.gnu.org/licenses/
     12#*****************************************************************************
     13
     14from sage.combinat.root_system.cartan_type import CartanType
     15from sage.categories.groups import Groups
     16from sage.misc.cachefunc import cached_method
     17from sage.structure.element import MultiplicativeGroupElement
     18from sage.structure.parent import Parent
     19from sage.structure.unique_representation import UniqueRepresentation
     20from sage.sets.family import Family
     21from sage.combinat.root_system.root_system import RootSystem
     22from sage.categories.finite_sets import FiniteSets
     23
     24def FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix='pi'):
     25    r"""
     26    Factory for the fundamental group of an extended affine Weyl group.
     27
     28    INPUTS:
     29
     30        - `cartan_type`: a Cartan type that is either affine or finite, with the latter being a
     31        shorthand for the untwisted affinization
     32        - `prefix` (default: 'pi'): string that labels the elements of the group, which are indexed
     33        by the special nodes of the affine Dynkin diagram
     34
     35    EXAMPLES::
     36
     37        sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1]); F
     38        Fundamental group of type ['A', 2, 1]
     39        sage: F.special_nodes()
     40        [0, 1, 2]
     41        sage: F(1)^2
     42        pi[2]
     43        sage: F(1)*F(2)
     44        pi[0]
     45        sage: F(2)^(-1)
     46        pi[1]
     47
     48    """
     49    cartan_type = CartanType(cartan_type)
     50    if cartan_type.is_finite():
     51        cartan_type = cartan_type.affine()
     52    if not cartan_type.is_affine():
     53        raise NotImplementedError
     54    return FundamentalGroupOfExtendedAffineWeylGroup_Class(cartan_type,prefix)
     55
     56class FundamentalGroupElement(MultiplicativeGroupElement):
     57    def __init__(self, parent, x):
     58        r"""
     59        This should not be called directly
     60        """
     61        if x not in parent.special_nodes():
     62            raise ValueError, "%s is not a special node"%x
     63        self._value = x
     64        MultiplicativeGroupElement.__init__(self, parent)
     65
     66    def value(self):
     67        r"""
     68        Returns the special node which indexes the special automorphism `self`.
     69        """
     70        return self._value
     71
     72    def _repr_(self):
     73        r"""
     74        EXAMPLES::
     75
     76            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',4,1], prefix="f")
     77            sage: F(2)^3 # indirect doctest
     78            f[1]
     79
     80        """
     81        return self.parent()._prefix + "[" + repr(self.value()) + "]"
     82
     83    def inverse(self):
     84        r"""
     85        Returns the inverse element of `self`.
     86
     87        EXAMPLES::
     88
     89            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1])
     90            sage: F(1).inverse()
     91            pi[3]
     92            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['E',6,1], prefix="f")
     93            sage: F(1).inverse()
     94            f[6]
     95
     96        """
     97        C = self.__class__
     98        par = self.parent()
     99        return C(par, par.dual_node()[self.value()])
     100
     101    __invert__ = inverse
     102
     103    def __cmp__(self, x):
     104        r"""
     105        Compare `self` with `x`.
     106        """
     107        if self.__class__  != x.__class__:
     108            return cmp(self.__class__,x.__class__)
     109        return cmp(self.value(), x.value())
     110
     111    def act_on_affine_weyl(self, w):
     112        r"""
     113        Act by `self` on the element `w` of the affine Weyl group.
     114
     115        EXAMPLES::
     116
     117            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1])
     118            sage: W = WeylGroup(F.cartan_type(),prefix="s")
     119            sage: w = W.from_reduced_word([2,3,0])
     120            sage: F(1).act_on_affine_weyl(w).reduced_word()
     121            [3, 0, 1]
     122
     123        """
     124        assert self.parent().cartan_type() == w.parent().cartan_type()
     125        if self == self.parent().one():
     126            return w
     127        self_action = self.parent().action()[self.value()]
     128        return w.parent().from_reduced_word([self_action[i] for i in w.reduced_word()])
     129
     130    def act_on_affine_lattice(self, la):
     131        r"""
     132        Act by `self` on the element `la` of an affine root/weight lattice realization.
     133
     134        EXAMPLES::
     135
     136            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1])
     137            sage: la = RootSystem(F.cartan_type()).weight_lattice().an_element(); la
     138            2*Lambda[0] + 2*Lambda[1] + 3*Lambda[2]
     139            sage: F(3).act_on_affine_lattice(la)
     140            2*Lambda[0] + 3*Lambda[1] + 2*Lambda[3]
     141
     142        warning::
     143
     144            Doesn't work on ambient lattices.
     145
     146        """
     147        assert self.parent().cartan_type() == la.parent().cartan_type()
     148        self_action = self.parent().action()[self.value()]
     149        return la.map_support(lambda i: self_action[i])
     150
     151class FundamentalGroupOfExtendedAffineWeylGroup_Class(UniqueRepresentation, Parent):
     152    r"""
     153    The group of length zero elements in the extended affine Weyl group.
     154    """
     155    Element = FundamentalGroupElement
     156
     157    def __init__(self, cartan_type, prefix):
     158        def get_the_index(beta):
     159            r"""
     160            Given a dictionary with one key, return this key
     161            """
     162            supp = beta.support()
     163            assert len(supp) == 1
     164            return supp[0]
     165
     166        self._cartan_type = cartan_type
     167        self._prefix = prefix
     168
     169        if cartan_type.dual().is_untwisted_affine():
     170            cartan_type = cartan_type.dual()
     171        if cartan_type.is_untwisted_affine():
     172            cartan_type_classical = cartan_type.classical()
     173            I = [i for i in cartan_type_classical.index_set()]
     174            Q = RootSystem(cartan_type_classical).root_lattice()
     175            alpha = Q.simple_roots()
     176            theta = Q.highest_root()
     177            self._special_nodes = [0] + [i for i in I if theta[i] == 1]
     178            om = RootSystem(cartan_type_classical).weight_lattice().fundamental_weights()
     179            W = Q.weyl_group(prefix="s")
     180            w0 = W.long_element()
     181            fg_dict = {}
     182            for j in cartan_type.index_set():
     183                fg_dict[0,j] = j
     184            inverse_dict = {}
     185            inverse_dict[0] = 0
     186            finite_action_dict = {}
     187            finite_action_dict[0] = tuple([])
     188            for i in self._special_nodes:
     189                if i == 0:
     190                    continue
     191                antiwt, red = om[i].to_dominant_chamber(reduced_word=True, positive=False)
     192                finite_action_dict[i] = tuple(red)
     193                w0i = W.from_reduced_word(red)
     194                idual = get_the_index(-antiwt)
     195                inverse_dict[i] = idual
     196                fg_dict[i,0] = i
     197                for j in I:
     198                    if j != idual:
     199                        fg_dict[i,j] = get_the_index(w0i.action(alpha[j]))
     200                    else:
     201                        fg_dict[i,j] = 0
     202            self._action = Family(self._special_nodes, lambda i: Family(cartan_type.index_set(), lambda j: fg_dict[i,j]))
     203            self._dual_node = Family(self._special_nodes, lambda i: inverse_dict[i])
     204            self._finite_action = Family(self._special_nodes, lambda i: finite_action_dict[i])
     205
     206        if cartan_type.type() == "BC" or cartan_type.dual().type() == "BC":
     207            self._special_nodes = [0]
     208            self._action = Family({0:Family(cartan_type.index_set(), lambda i: i)})
     209            self._dual_node = Family({0:0})
     210            self._finite_action = Family({0:tuple([])})
     211
     212        Parent.__init__(self, category = Groups())
     213
     214    def _element_constructor_(self, x):
     215        if isinstance(x, self.element_class) and x.parent() is self:
     216            return x
     217        return self.element_class(self, x)
     218
     219    def one(self):
     220        r"""
     221        Returns the identity element of the fundamental group.
     222
     223        EXAMPLES::
     224
     225            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1])
     226            sage: F.one()
     227            pi[0]
     228
     229        """
     230        return self._element_constructor_(0)
     231
     232    def product(self, x, y):
     233        r"""
     234        Returns the product of `x` and `y`.
     235
     236        EXAMPLES::
     237
     238            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1])
     239            sage: F.special_nodes()
     240            [0, 1, 2, 3]
     241            sage: F(2)*F(3)
     242            pi[1]
     243            sage: F(1)*F(3)^(-1)
     244            pi[2]
     245
     246        """
     247        return self(self.action()[x.value()][y.value()])
     248
     249    def cartan_type(self):
     250        return self._cartan_type
     251
     252    def _repr_(self):
     253        return "Fundamental group of type %s"%self.cartan_type()
     254
     255    def special_nodes(self):
     256        return self._special_nodes
     257
     258    def family(self):
     259        r"""
     260        Returns a family indexed by special nodes whose values are the corresponding fundamental
     261        group elements.
     262
     263        EXAMPLES::
     264
     265            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['E',6,1],prefix="f")
     266            sage: fam = F.family(); fam
     267            Finite family {0: f[0], 1: f[1], 6: f[6]}
     268            sage: fam[0] == F(0)
     269            True
     270            sage: fam[6]^2
     271            f[1]
     272
     273        """
     274        return Family(self.special_nodes(), lambda i: self(i))
     275
     276    @cached_method
     277    def index_set(self):
     278        return self.cartan_type().index_set()
     279
     280    def action(self):
     281        r"""
     282        Returns the family of families that describes the action of each special automorphism
     283        on the set of affine Dynkin nodes
     284
     285        EXAMPLES::
     286
     287            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1])
     288            sage: F.action()
     289            Finite family {0: Finite family {0: 0, 1: 1, 2: 2}, 1: Finite family {0: 1, 1: 2, 2: 0}, 2: Finite family {0: 2, 1: 0, 2: 1}}
     290            sage: G = FundamentalGroupOfExtendedAffineWeylGroup(['D',4,1])
     291            sage: G.action()
     292            Finite family {0: Finite family {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}, 1: Finite family {0: 1, 1: 0, 2: 2, 3: 4, 4: 3}, 3: Finite family {0: 3, 1: 4, 2: 2, 3: 0, 4: 1}, 4: Finite family {0: 4, 1: 3, 2: 2, 3: 1, 4: 0}}
     293
     294        """
     295        return self._action
     296
     297    def dual_node(self):
     298        r"""
     299        Returns the family which, given a special node, returns the special node whose special
     300        automorphism is inverse.
     301
     302        EXAMPLES::
     303
     304            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',4,1])
     305            sage: F.dual_node()
     306            Finite family {0: 0, 1: 4, 2: 3, 3: 2, 4: 1}
     307            sage: G = FundamentalGroupOfExtendedAffineWeylGroup(['E',6,1])
     308            sage: G.dual_node()
     309            Finite family {0: 0, 1: 6, 6: 1}
     310            sage: H = FundamentalGroupOfExtendedAffineWeylGroup(['D',5,1])
     311            sage: H.dual_node()
     312            Finite family {0: 0, 1: 1, 4: 5, 5: 4}
     313
     314        """
     315        return self._dual_node
     316
     317    def finite_action(self):
     318        r"""
     319        Returns a family indexed by special nodes, for the projection into the finite Weyl group
     320        of a special automorphism.
     321
     322        More precisely, for each special node `i`, `self.finite_action()[i]` is a reduced word for
     323        the element `v` in the finite Weyl group such that in the extended affine Weyl group,
     324        the `i`-th special automorphism is equal to `t v` where `t` is a translation element.
     325
     326        EXAMPLES::
     327
     328            sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1])
     329            sage: F.finite_action()
     330            Finite family {0: (), 1: (1, 2, 3), 2: (2, 1, 3, 2), 3: (3, 2, 1)}
     331
     332        """
     333        return self._finite_action
     334
  • src/sage/combinat/root_system/root_lattice_realizations.py

    diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py
    index f7e782d..0efac28 100644
    a b class RootLatticeRealizations(Category_over_base_ring): 
    153153
    154154    Algebras = LazyImport('sage.combinat.root_system.root_lattice_realization_algebras', 'Algebras')
    155155
     156    Algebras = LazyImport('sage.combinat.root_system.root_lattice_realization_algebras', 'Algebras')
     157
    156158    class ParentMethods:
    157159
    158160        def __init_extra__(self):
    class RootLatticeRealizations(Category_over_base_ring): 
    653655            EXAMPLES::
    654656
    655657                sage: RootSystem(['C',2]).root_lattice().positive_roots_by_height()
    656                 [alpha[1], alpha[2], alpha[1] + alpha[2], 2*alpha[1] + alpha[2]]
     658                [alpha[2], alpha[1], alpha[1] + alpha[2], 2*alpha[1] + alpha[2]]
    657659                sage: RootSystem(['C',2]).root_lattice().positive_roots_by_height(increasing = False)
    658                 [2*alpha[1] + alpha[2], alpha[1] + alpha[2], alpha[1], alpha[2]]
     660                [2*alpha[1] + alpha[2], alpha[1] + alpha[2], alpha[2], alpha[1]]
    659661                sage: RootSystem(['A',2,1]).root_lattice().positive_roots_by_height()
    660662                Traceback (most recent call last):
    661663                ...
    class RootLatticeRealizations(Category_over_base_ring): 
    695697                sage: Phi = RootSystem(['A',2]).root_poset(); Phi
    696698                Finite poset containing 3 elements
    697699                sage: Phi.cover_relations()
    698                 [[alpha[1], alpha[1] + alpha[2]], [alpha[2], alpha[1] + alpha[2]]]
     700                [[alpha[2], alpha[1] + alpha[2]], [alpha[1], alpha[1] + alpha[2]]]
    699701
    700702                sage: Phi = RootSystem(['A',3]).root_poset(restricted=True); Phi
    701703                Finite poset containing 3 elements
    702704                sage: Phi.cover_relations()
    703                 [[alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3]], [alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[3]]]
     705                [[alpha[2] + alpha[3], alpha[1] + alpha[2] + alpha[3]], [alpha[1] + alpha[2], alpha[1] + alpha[2] + alpha[3]]]
    704706
    705707                sage: Phi = RootSystem(['B',2]).root_poset(); Phi
    706708                Finite poset containing 4 elements
    707709                sage: Phi.cover_relations()
    708                 [[alpha[1], alpha[1] + alpha[2]], [alpha[2], alpha[1] + alpha[2]], [alpha[1] + alpha[2], alpha[1] + 2*alpha[2]]]
     710                [[alpha[2], alpha[1] + alpha[2]], [alpha[1], alpha[1] + alpha[2]], [alpha[1] + alpha[2], alpha[1] + 2*alpha[2]]]
     711
    709712            """
    710713            from sage.combinat.posets.posets import Poset
    711714            rels = []
    class RootLatticeRealizations(Category_over_base_ring): 
    19641967            TESTS::
    19651968
    19661969                sage: list(RootSystem(["A",2]).weight_lattice().plot_fundamental_weights())
    1967                 [Arrow from (0.0,0.0) to (0.0,1.0),
    1968                  Text '$\Lambda_{2}$' at the point (0.0,1.05),
    1969                  Arrow from (0.0,0.0) to (1.0,0.0),
    1970                  Text '$\Lambda_{1}$' at the point (1.05,0.0)]
     1970                [Arrow from (0.0,0.0) to (1.0,0.0), Text '$\Lambda_{1}$' at the point (1.05,0.0), Arrow from (0.0,0.0) to (0.0,1.0), Text '$\Lambda_{2}$' at the point (0.0,1.05)]
     1971                sage: list(RootSystem(["A",2]).ambient_lattice().plot_fundamental_weights())
     1972                [Arrow from (0.0,0.0) to (0.5,0.866024518389), Text '$\Lambda_{1}$' at the point (0.525,0.909325744308), Arrow from (0.0,0.0) to (-0.5,0.866024518389), Text '$\Lambda_{2}$' at the point (-0.525,0.909325744308)]
    19711973
    1972                  sage: list(RootSystem(["A",2]).ambient_lattice().plot_fundamental_weights())
    1973                  [Arrow from (0.0,0.0) to (-0.5,0.86...),
    1974                   Text '$\Lambda_{2}$' at the point (-0.525,0.90...),
    1975                   Arrow from (0.0,0.0) to (0.5,0.86...),
    1976                   Text '$\Lambda_{1}$' at the point (0.525,0.90...)]
    19771974            """
    19781975            plot_options = self.plot_parse_options(**options)
    19791976            # We build the family of fundamental weights in this space,
    class RootLatticeRealizations(Category_over_base_ring): 
    25172514            L = self.root_system.ambient_space() # uses peculiarities of ambient embedding
    25182515            return max([root.scalar(root) for root in L.simple_roots()])
    25192516
     2517        @cached_method
     2518        def dual_type_cospace(self):
     2519            r"""
     2520            Returns the cospace of dual type.
     2521
     2522            For example, if invoked on the root lattice of type `['B',2]`, returns the
     2523            coroot lattice of type `['C',2]`.
     2524
     2525            ..warning::
     2526
     2527                Not implemented for ambient spaces.
     2528
     2529            EXAMPLES::
     2530
     2531                sage: CartanType(['B',2]).root_system().root_lattice().dual_type_cospace()
     2532                Coroot lattice of the Root system of type ['C', 2]
     2533                sage: CartanType(['F',4]).root_system().coweight_lattice().dual_type_cospace()
     2534                Weight lattice of the Root system of type ['F', 4] relabelled by {1: 4, 2: 3, 3: 2, 4: 1}
     2535
     2536            """
     2537            from root_space import RootSpace
     2538            from weight_space import WeightSpace
     2539
     2540            if isinstance(self, RootSpace):
     2541                if self.root_system.dual_side:
     2542                    return self.cartan_type().root_system().root_space(self.base_ring())
     2543                else:
     2544                    return self.cartan_type().dual().root_system().coroot_space(self.base_ring())
     2545            if isinstance(self, WeightSpace):
     2546                if self.root_system.dual_side:
     2547                    return self.cartan_type().root_system().weight_space(self.base_ring())
     2548                else:
     2549                    return self.cartan_type().dual().root_system().coweight_space(self.base_ring())
     2550            raise TypeError, "Not implemented for %s"%self
     2551
     2552        @abstract_method(optional=True)
     2553        def to_ambient_space_morphism(self):
     2554            r"""
     2555            Return the morphism to the ambient space.
     2556
     2557            EXAMPLES::
     2558
     2559                sage: CartanType(['B',2]).root_system().root_lattice().to_ambient_space_morphism()
     2560                Generic morphism:
     2561                From: Root lattice of the Root system of type ['B', 2]
     2562                To:   Ambient space of the Root system of type ['B', 2]
     2563                sage: CartanType(['B',2]).root_system().coroot_lattice().to_ambient_space_morphism()
     2564                Generic morphism:
     2565                From: Coroot lattice of the Root system of type ['B', 2]
     2566                To:   Ambient space of the Root system of type ['B', 2]
     2567                sage: CartanType(['B',2]).root_system().weight_lattice().to_ambient_space_morphism()
     2568                Generic morphism:
     2569                From: Weight lattice of the Root system of type ['B', 2]
     2570                To:   Ambient space of the Root system of type ['B', 2]
     2571
     2572            """
     2573
    25202574    ##########################################################################
    25212575
    25222576    class ElementMethods:
    class RootLatticeRealizations(Category_over_base_ring): 
    30213075            """
    30223076            return [x for x in TransitiveIdeal(attrcall('pred'), [self])]
    30233077
     3078        def to_dual_type_cospace(self):
     3079            r"""
     3080            Map ``self`` to the dual type cospace.
     3081
     3082            For example, if ``self`` is in the root lattice of type `['B',2]`, send it to
     3083            the coroot lattice of type `['C',2]`.
     3084
     3085            EXAMPLES::
     3086
     3087                sage: v = CartanType(['C',3]).root_system().weight_lattice().an_element(); v
     3088                2*Lambda[1] + 2*Lambda[2] + 3*Lambda[3]
     3089                sage: w = v.to_dual_type_cospace(); w
     3090                2*Lambdacheck[1] + 2*Lambdacheck[2] + 3*Lambdacheck[3]
     3091                sage: w.parent()
     3092                Coweight lattice of the Root system of type ['B', 3]
     3093
     3094            """
     3095            return self.parent().dual_type_cospace().from_vector(self.to_vector())
     3096
     3097        def to_classical(self):
     3098            r"""
     3099            Map ``self`` to the classical lattice/space.
     3100
     3101            Only makes sense for affine type.
     3102
     3103            EXAMPLES::
     3104
     3105                sage: R = CartanType(['A',3,1]).root_system()
     3106                sage: alpha = R.root_lattice().an_element(); alpha
     3107                2*alpha[0] + 2*alpha[1] + 3*alpha[2]
     3108                sage: alb = alpha.to_classical(); alb
     3109                alpha[2] - 2*alpha[3]
     3110                sage: alb.parent()
     3111                Root lattice of the Root system of type ['A', 3]
     3112                sage: v = R.ambient_space().an_element(); v
     3113                2*e[0] + 2*e[1] + 3*e[2]
     3114                sage: v.to_classical()
     3115                (2, 2, 3, 0)
     3116
     3117            """
     3118            return self.parent().classical()(self)
     3119
     3120        @abstract_method(optional=True)
     3121        def to_ambient(self):
     3122            r"""
     3123            Map ``self`` to the ambient space.
     3124
     3125            EXAMPLES::
     3126
     3127                sage: alpha = CartanType(['B',4]).root_system().root_lattice().an_element(); alpha
     3128                2*alpha[1] + 2*alpha[2] + 3*alpha[3]
     3129                sage: alpha.to_ambient()
     3130                (2, 0, 1, -3)
     3131                sage: mu = CartanType(['B',4]).root_system().weight_lattice().an_element(); mu
     3132                2*Lambda[1] + 2*Lambda[2] + 3*Lambda[3]
     3133                sage: mu.to_ambient()
     3134                (7, 5, 3, 0)
     3135                sage: v = CartanType(['B',4]).root_system().ambient_space().an_element(); v
     3136                (2, 2, 3, 0)
     3137                sage: v.to_ambient()
     3138                (2, 2, 3, 0)
     3139                sage: alphavee = CartanType(['B',4]).root_system().coroot_lattice().an_element(); alphavee
     3140                2*alphacheck[1] + 2*alphacheck[2] + 3*alphacheck[3]
     3141                sage: alphavee.to_ambient()
     3142                (2, 0, 1, -3)
     3143
     3144            """
     3145
     3146
    30243147        ##########################################################################
    30253148        # Level
    30263149        ##########################################################################
  • src/sage/combinat/root_system/root_space.py

    diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py
    index aaf4a0b..3b9373b 100644
    a b from sage.rings.all import ZZ 
    1313from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
    1414from root_lattice_realizations import RootLatticeRealizations
    1515from sage.misc.cachefunc import cached_in_parent_method
     16import functools
    1617
    1718# TODO: inheriting from ClearCacheOnPickle is a technical detail unrelated to root spaces
    1819# could we abstract this somewhere higher?
    class RootSpace(ClearCacheOnPickle, CombinatorialFreeModule): 
    209210        else:
    210211            return self.classical().simple_root(i)
    211212
     213    @cached_method
     214    def to_ambient_space_morphism(self):
     215        r"""
     216        The morphism from ``self`` to its associated ambient space.
     217
     218        EXAMPLES::
     219
     220            sage: CartanType(['A',2]).root_system().root_lattice().to_ambient_space_morphism()
     221            Generic morphism:
     222            From: Root lattice of the Root system of type ['A', 2]
     223            To:   Ambient space of the Root system of type ['A', 2]
     224
     225        """
     226        if self.root_system.dual_side:
     227            L = self.cartan_type().dual().root_system().ambient_space()
     228            basis = L.simple_coroots()
     229        else:
     230            L = self.cartan_type().root_system().ambient_space()
     231            basis = L.simple_roots()
     232        def basis_value(basis, i):
     233            return basis[i]
     234        return self.module_morphism(on_basis = functools.partial(basis_value, basis) , codomain=L)
     235
    212236class RootSpaceElement(CombinatorialFreeModuleElement):
    213237    def scalar(self, lambdacheck):
    214238        """
    class RootSpaceElement(CombinatorialFreeModuleElement): 
    322346
    323347            sage: Q = RootSystem(['C',2]).root_lattice()
    324348            sage: [[x, x.quantum_root()] for x in Q.positive_roots_by_height()]
    325             [[alpha[1], True], [alpha[2], True], [alpha[1] + alpha[2], False], [2*alpha[1] + alpha[2], True]]
     349            [[alpha[2], True], [alpha[1], True], [alpha[1] + alpha[2], False], [2*alpha[1] + alpha[2], True]]
    326350
    327351        """
    328352
    class RootSpaceElement(CombinatorialFreeModuleElement): 
    416440        W = self.parent().weyl_group()
    417441        return (W.demazure_product(word)).reduced_word()
    418442
     443    def to_ambient(self):
     444        r"""
     445        Map ``self`` to the ambient space.
     446
     447        EXAMPLES::
     448
     449            sage: alpha = CartanType(['B',2]).root_system().root_lattice().an_element(); alpha
     450            2*alpha[1] + 2*alpha[2]
     451            sage: alpha.to_ambient()
     452            (2, 0)
     453            sage: alphavee = CartanType(['B',2]).root_system().coroot_lattice().an_element(); alphavee
     454            2*alphacheck[1] + 2*alphacheck[2]
     455            sage: alphavee.to_ambient()
     456            (2, 2)
     457
     458        """
     459        return self.parent().to_ambient_space_morphism()(self)
     460
    419461RootSpace.Element = RootSpaceElement
  • src/sage/combinat/root_system/type_affine.py

    diff --git a/src/sage/combinat/root_system/type_affine.py b/src/sage/combinat/root_system/type_affine.py
    index 141727b..8d1dd31 100644
    a b class AmbientSpace(CombinatorialFreeModule): 
    419419        return vector(list(vector(classical._plot_projection(classical(x)))) +
    420420                      [x["deltacheck"]])
    421421
     422    def from_vector_notation(self, weight, style="lattice"):
     423        """
     424        ..TODO:: CHECK THIS STUPID DEFAULT IMPLEMENTATION WITH DAN
     425
     426        This is in particular used to compute demazure-lusztig characters
     427        """
     428        return weight
     429
    422430    class Element(CombinatorialFreeModule.Element):
    423431
    424432        def inner_product(self, other):
  • src/sage/combinat/root_system/weight_space.py

    diff --git a/src/sage/combinat/root_system/weight_space.py b/src/sage/combinat/root_system/weight_space.py
    index 989679b..2ed49b0 100644
    a b from sage.misc.cachefunc import cached_method 
    1212from sage.sets.family import Family
    1313from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
    1414from weight_lattice_realizations import WeightLatticeRealizations
     15import functools
    1516
    1617class WeightSpace(CombinatorialFreeModule):
    1718    r"""
    class WeightSpace(CombinatorialFreeModule): 
    418419        else:
    419420            return self.classical().monomial(i)
    420421
     422    @cached_method
     423    def to_ambient_space_morphism(self):
     424        r"""
     425        The morphism from ``self`` to its associated ambient space.
     426
     427        EXAMPLES::
     428
     429            sage: CartanType(['A',2]).root_system().weight_lattice().to_ambient_space_morphism()
     430            Generic morphism:
     431            From: Weight lattice of the Root system of type ['A', 2]
     432            To:   Ambient space of the Root system of type ['A', 2]
     433
     434        ..warning::
     435
     436            Implemented only for finite Cartan type.
     437
     438        """
     439
     440        if self.root_system.dual_side:
     441            raise TypeError, "No implemented map from the coweight space to the ambient space"
     442        L = self.cartan_type().root_system().ambient_space()
     443        basis = L.fundamental_weights()
     444        def basis_value(basis, i):
     445            return basis[i]
     446        return self.module_morphism(on_basis = functools.partial(basis_value, basis) , codomain=L)
    421447
    422448class WeightSpaceElement(CombinatorialFreeModuleElement):
    423449
    class WeightSpaceElement(CombinatorialFreeModuleElement): 
    493519        """
    494520        return all(c >= 0 for c in self.coefficients())
    495521
     522    def to_ambient(self):
     523        r"""
     524        Maps ``self`` to the ambient space.
     525
     526        EXAMPLES::
     527
     528            sage: mu = CartanType(['B',2]).root_system().weight_lattice().an_element(); mu
     529            2*Lambda[1] + 2*Lambda[2]
     530            sage: mu.to_ambient()
     531            (3, 1)
     532
     533        ..warning::
     534
     535            Only implemented in finite Cartan type.
     536            Does not work for coweight lattices because there is no implemented map
     537            from the coweight lattice to the ambient space.
     538
     539        """
     540        return self.parent().to_ambient_space_morphism()(self)
     541
     542
    496543WeightSpace.Element = WeightSpaceElement
  • new file src/sage/groups/group_exp.py

    diff --git a/src/sage/groups/group_exp.py b/src/sage/groups/group_exp.py
    new file mode 100644
    index 0000000..7acfdc3
    - +  
     1from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups
     2from sage.categories.groups import Groups
     3from sage.structure.element import MultiplicativeGroupElement
     4from sage.structure.unique_representation import UniqueRepresentation
     5from sage.structure.parent import Parent
     6from sage.categories.morphism import SetMorphism
     7from sage.categories.functor import Functor
     8from sage.categories.homset import Hom
     9from sage.structure.element_wrapper import ElementWrapper
     10
     11class GroupExp(Functor):
     12    r"""
     13    A functor that wraps a commutative additive group to become a multiplicative group.
     14
     15    EXAMPLES::
     16
     17        sage: E = GroupExp(); E
     18        Functor from Category of commutative additive groups to Category of groups
     19        sage: EZ = E(ZZ); EZ
     20        Multiplicative form of Integer Ring
     21        sage: x = EZ(-3); x
     22        -3
     23        sage: x.parent()
     24        Multiplicative form of Integer Ring
     25        sage: EZ(-1)*EZ(6) == EZ(5)
     26        True
     27        sage: EZ(3)^(-1)
     28        -3
     29        sage: EZ.one()
     30        0
     31        sage: L = RootSystem(['A',2]).ambient_space()
     32        sage: EL = E(L)
     33        sage: W = L.weyl_group(prefix="s")
     34        sage: s2 = W.simple_reflection(2)
     35        sage: def my_action(mu):
     36        ...       return s2.action(mu)
     37        sage: from sage.categories.morphism import SetMorphism
     38        sage: from sage.categories.homset import Hom
     39        sage: f = SetMorphism(Hom(L,L,CommutativeAdditiveGroups()), my_action)
     40        sage: F = E(f); F
     41        Generic endomorphism of Multiplicative form of Ambient space of the Root system of type ['A', 2]
     42        sage: v = L.an_element(); v
     43        (2, 2, 3)
     44        sage: y = F(EL(v)); y
     45        (2, 3, 2)
     46        sage: y.parent()
     47        Multiplicative form of Ambient space of the Root system of type ['A', 2]
     48
     49    """
     50
     51    def __init__(self):
     52        Functor.__init__(self, CommutativeAdditiveGroups(), Groups())
     53
     54    def _apply_functor(self, x):
     55        r"""
     56        Given a commutative additive group `x`, returns the isomorphic multiplicative group.
     57
     58        EXAMPLES::
     59
     60            sage: EQ2 = GroupExp()(QQ^2)
     61            sage: x = EQ2(vector(QQ,(-2,1))); x
     62            (-2, 1)
     63            sage: x^(-1)
     64            (2, -1)
     65            sage: x*x
     66            (-4, 2)
     67            sage: EQ2(vector(QQ,(-1,1)))*EQ2(vector(QQ,(3,4))) == EQ2(vector(QQ,(2,5)))
     68            True
     69            sage: EQ2.one()
     70            (0, 0)
     71
     72    """
     73        return GroupExp_Class(x)
     74
     75    def _apply_functor_to_morphism(self, f):
     76        r"""
     77        Given a morphism of commutative additive groups, returns the corresponding morphism
     78        of multiplicative groups.
     79
     80        EXAMPLES::
     81
     82            sage: def double(x):
     83            ...       return x + x
     84            sage: from sage.categories.morphism import SetMorphism
     85            sage: from sage.categories.homset import Hom
     86            sage: f = SetMorphism(Hom(ZZ,ZZ,CommutativeAdditiveGroups()),double)
     87            sage: E = GroupExp()
     88            sage: EZ = E._apply_functor(ZZ)
     89            sage: F = E._apply_functor_to_morphism(f)
     90            sage: F.domain() == EZ
     91            True
     92            sage: F.codomain() == EZ
     93            True
     94            sage: F(EZ(3)) == EZ(3)*EZ(3)
     95            True
     96
     97        """
     98        new_domain = self._apply_functor(f.domain())
     99        new_codomain = self._apply_functor(f.codomain())
     100        new_f = lambda a: new_codomain(f(a.value))
     101        return SetMorphism(Hom(new_domain, new_codomain, Groups()), new_f)
     102
     103class GroupExpElement(ElementWrapper, MultiplicativeGroupElement):
     104    r"""
     105    The Element class for a GroupExp_Class object.
     106
     107    INPUT:
     108
     109    - ``self`` -- the instance being created
     110    - ``parent`` -- the parent of ``self``
     111    - ``x`` -- the additive group element being wrapped
     112
     113    EXAMPLES::
     114
     115        sage: G = QQ^2
     116        sage: EG = GroupExp()(G)
     117        sage: x = GroupExpElement(EG, vector(QQ, (1,-3))); x
     118        (1, -3)
     119        sage: x.parent()
     120        Multiplicative form of Vector space of dimension 2 over Rational Field
     121
     122    """
     123
     124    def __init__(self, parent, x):
     125        if x not in parent._G:
     126            return ValueError, "%s is not an element of %s"%(x,parent._G)
     127        ElementWrapper.__init__(self, parent, x)
     128
     129    def inverse(self):
     130        r"""
     131        Returns the inverse of the element `self`.
     132
     133        EXAMPLES::
     134
     135            sage: EZ = GroupExp()(ZZ)
     136            sage: EZ(-3)^(-1)
     137            3
     138
     139        """
     140        return GroupExpElement(self.parent(), -self.value)
     141
     142    __invert__ = inverse
     143
     144    def __mul__(self, x):
     145        r"""
     146        Returns the product of `self` and `x`.
     147
     148        EXAMPLES::
     149
     150            sage: G = GroupExp()(ZZ)
     151            sage: x = G(2)
     152            sage: x.__mul__(G(3))
     153            5
     154            sage: G.product(G(2),G(3))
     155            5
     156
     157        """
     158        return GroupExpElement(self.parent(), self.value + x.value)
     159
     160class GroupExp_Class(UniqueRepresentation, Parent):
     161    r"""
     162    The multiplicative form of a commutative additive group.
     163
     164    INPUT:
     165
     166        - `G`: a commutative additive group
     167
     168    """
     169
     170
     171    def __init__(self, G):
     172        if not G in CommutativeAdditiveGroups():
     173            raise TypeError, "%s must be a commutative additive group"%G
     174        self._G = G
     175        Parent.__init__(self, category=Groups())
     176
     177    def _repr_(self):
     178        r"""
     179        Returns a string describing ``self``.
     180
     181        EXAMPLES::
     182
     183            sage: GroupExp()(ZZ) # indirect doctest
     184            Multiplicative form of Integer Ring
     185
     186        """
     187        return "Multiplicative form of %s"%self._G
     188
     189    def _element_constructor_(self, x):
     190        r"""
     191        Constructs the element of ``self`` that wraps the additive group element `x`.
     192
     193        EXAMPLES::
     194
     195            sage: G = GroupExp()(ZZ)
     196            sage: G(4) # indirect doctest
     197            4
     198
     199        """
     200        return GroupExpElement(self, x)
     201
     202    def one(self):
     203        r"""
     204        Returns the identity element of ``self``.
     205
     206        EXAMPLES::
     207
     208            sage: G = GroupExp()(ZZ^2)
     209            sage: G.one()
     210            (0, 0)
     211
     212        """
     213        return GroupExpElement(self, self._G.zero())
     214
     215    def an_element(self):
     216        r"""
     217        Returns an element of ``self``.
     218
     219        EXAMPLES::
     220
     221            sage: L = RootSystem(['A',2]).weight_lattice()
     222            sage: EL = GroupExp()(L)
     223            sage: x = EL.an_element(); x
     224            2*Lambda[1] + 2*Lambda[2]
     225            sage: x.parent()
     226            Multiplicative form of Weight lattice of the Root system of type ['A', 2]
     227
     228        """
     229        return GroupExpElement(self, self._G.an_element())
     230
     231    def product(self, x, y):
     232        r"""
     233        Returns the product of `x` and `y` in ``self``.
     234
     235        EXAMPLES::
     236
     237            sage: G = GroupExp()(ZZ)
     238            sage: G.product(G(2),G(7))
     239            9
     240            sage: x = G(2)
     241            sage: x.__mul__(G(7))
     242            9
     243
     244        """
     245        return GroupExpElement(self, x.value+y.value)
     246
     247GroupExp_Class.Element = GroupExpElement
  • new file src/sage/groups/group_semidirect_product.py

    diff --git a/src/sage/groups/group_semidirect_product.py b/src/sage/groups/group_semidirect_product.py
    new file mode 100644
    index 0000000..7909952
    - +  
     1from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups
     2from sage.categories.groups import Groups
     3from sage.structure.element import MultiplicativeGroupElement
     4from sage.structure.unique_representation import UniqueRepresentation
     5from sage.structure.parent import Parent
     6from sage.sets.cartesian_product import CartesianProduct
     7from sage.misc.cachefunc import cached_method
     8from sage.groups.group_exp import GroupExp
     9
     10class GroupSemidirectProductElement(CartesianProduct.Element):
     11    r"""
     12    Element class for :class:`GroupSemidirectProduct`.
     13    """
     14
     15    def _repr_(self):
     16
     17        def wrapper(prefix, s):
     18            if prefix is None:
     19                return s
     20            return "%s[%s]"%(prefix,s)
     21
     22        par = self.parent()
     23
     24        g = self.summand_projection(0)
     25        h = self.summand_projection(1)
     26        gstr = wrapper(par._prefix0, g.__repr__())
     27        hstr = wrapper(par._prefix1, h.__repr__())
     28        if par._print_tuple:
     29            return "(%s, %s)"%(gstr,hstr)
     30
     31        if self == par.one():
     32            return "1"
     33        if g == g.parent().one():
     34            return hstr
     35        if h == h.parent().one():
     36            return gstr
     37        return gstr + " * " + hstr
     38
     39    def inverse(self):
     40        par = self.parent()
     41        g = self.summand_projection(0)
     42        h = self.summand_projection(1)
     43
     44        if par.act_to_right():
     45            return self.__class__(par,(~g, par._twist(g,~h)))
     46        else:
     47            hi = ~h
     48            return self.__class__(par,(par._twist(hi,~g),hi))
     49
     50    __invert__ = inverse
     51
     52    def to_opposite(self):
     53        r"""
     54        Send an element to its image in the opposite semidirect product.
     55
     56        EXAMPLES::
     57
     58            sage: L = RootSystem(['A',2]).root_lattice(); L
     59            Root lattice of the Root system of type ['A', 2]
     60            sage: from sage.groups.group_exp import GroupExp
     61            sage: EL = GroupExp()(L)
     62            sage: W = L.weyl_group(prefix="s"); W
     63            Weyl Group of type ['A', 2] (as a matrix group acting on the root lattice)
     64            sage: def twist(w,v):
     65            ...       return EL(w.action(v.value))
     66            sage: G = GroupSemidirectProduct(W, EL, twist, prefix1='t'); G
     67            Semidirect product of Weyl Group of type ['A', 2] (as a matrix group acting on the root lattice) acting on Multiplicative form of Root lattice of the Root system of type ['A', 2]
     68            sage: mu = L.an_element(); mu
     69            2*alpha[1] + 2*alpha[2]
     70            sage: w = W.an_element(); w
     71            s1*s2
     72            sage: g = G((w,EL(mu))); g
     73            s1*s2 * t[2*alpha[1] + 2*alpha[2]]
     74            sage: g.to_opposite()
     75            t[-2*alpha[1]] * s1*s2
     76            sage: g.to_opposite().parent()
     77            Semidirect product of Multiplicative form of Root lattice of the Root system of type ['A', 2] acted upon by Weyl Group of type ['A', 2] (as a matrix group acting on the root lattice)
     78
     79        """
     80        par = self.parent()
     81        Gop = par.opposite_semidirect_product()
     82        g = self.summand_projection(0)
     83        h = self.summand_projection(1)
     84        if par.act_to_right():
     85            return Gop((par._twist(g,h),g))
     86        return Gop((h,par._twist(~h,g)))
     87
     88class GroupSemidirectProduct(CartesianProduct):
     89
     90    r"""
     91    Returns the semidirect product of the groups ``G`` and ``H`` using the homomorphism ``twist``.
     92
     93    INPUT:
     94
     95        - ``G`` and ``H`` -- multiplicative groups
     96        - ``twist`` -- (default: None) a group homomorphism (see below)
     97        - ``act_to_right`` -- True or False (default: True)
     98        - ``prefix0`` -- (default: None) optional string
     99        - ``prefix1`` -- (default: None) optional string
     100        - ``print_tuple`` -- True or False (default: False)
     101        - ``category`` -- A category (default: Groups())
     102
     103    If ``act_to_right`` is True, ``twist`` is an element of ``Hom(G, Aut(H))``. Syntactically
     104    ``twist(g,h)`` is in ``H`` for all `g\in G` and `h\in H`.
     105    If ``act_to_right`` is False, ``twist`` is an element of ``Hom(H, Aut(G))``
     106    and ``twist(h,g)`` is in ``G`` for all `g\in G` and `h\in H`.
     107    If ``prefix0`` (resp. ``prefixl``) is not None then it is used as a wrapper for
     108    printing elements of ``G`` (resp. ``H``). If ``print_tuple`` is True then elements are printed
     109    in the style `(g,h)` and otherwise in the style `g * h`.
     110
     111
     112    EXAMPLES::
     113
     114        sage: G = GL(2,QQ)
     115        sage: V = QQ^2
     116        sage: EV = GroupExp()(V) # make a multiplicative version of V
     117        sage: def twist(g,v):
     118        ...       return EV(g*v.value)
     119        sage: H = GroupSemidirectProduct(G, EV, twist=twist, prefix1 = 't'); H
     120        Semidirect product of General Linear Group of degree 2 over Rational Field acting on Multiplicative form of Vector space of dimension 2 over Rational Field
     121        sage: x = H.an_element(); x
     122        t[(1, 0)]
     123        sage: x^2
     124        t[(2, 0)]
     125        sage: cartan_type = CartanType(['A',2])
     126        sage: W = WeylGroup(cartan_type, prefix="s")
     127        sage: def twist(w,v):
     128        ...       return w*v*(~w)
     129        sage: WW = GroupSemidirectProduct(W,W, twist=twist, print_tuple=True)
     130        sage: s = Family(cartan_type.index_set(), lambda i: W.simple_reflection(i))
     131        sage: y = WW((s[1],s[2])); y
     132        (s1, s2)
     133        sage: y^2
     134        (1, s2*s1)
     135        sage: y.inverse()
     136        (s1, s1*s2*s1)
     137
     138    TODO: Functorial constructor for semidirect products for various categories
     139    Twofold Direct product as a special case of semidirect product
     140
     141    """
     142
     143    def __init__(self, G, H, twist=None, act_to_right=True, prefix0=None, prefix1=None, print_tuple=False,category=Groups()):
     144        self._act_to_right = act_to_right
     145        def check_implemented_group(x):
     146            if x in Groups():
     147                return
     148            error = "The semidirect product construction for groups is implemented only for multiplicative groups"
     149            if x in CommutativeAdditiveGroups():
     150                error = error + ". Please change the commutative additive group %s into a multiplicative group using the functor sage.groups.group_exp.GroupExp"%x
     151            raise TypeError, error
     152
     153        check_implemented_group(G)
     154        check_implemented_group(H)
     155
     156        if twist is None:
     157            self._twist = lambda g,h: h # use the trivial twist
     158        else:
     159            self._twist = twist
     160
     161        self._prefix0 = prefix0
     162        self._prefix1 = prefix1
     163        self._print_tuple = print_tuple
     164        self._category = category
     165        CartesianProduct.__init__(self, (G,H), category=category)
     166
     167    def act_to_right(self):
     168        return self._act_to_right
     169
     170    def _repr_(self):
     171        summands = self.summands()
     172        if self.act_to_right():
     173            act_string = "acting on"
     174        else:
     175            act_string = "acted upon by"
     176        return "Semidirect product of %s %s %s"%(summands[0],act_string, summands[1])
     177
     178    def _element_constructor_(self, x):
     179        def type_error():
     180            raise TypeError, "%s cannot be converted into an element of %s"%(x,self)
     181
     182        if isinstance(x, self.element_class) and x.parent() == self:
     183            return x
     184        if not isinstance(x, GroupSemidirectProductElement):
     185            if not isinstance(x, tuple):
     186                type_error()
     187            if len(x) != 2:
     188                type_error()
     189            g, h = x
     190        else:
     191            g = x.summand_projection(0)
     192            h = x.summand_projection(1)
     193        gg = self.summands()[0](g)
     194        hh = self.summands()[1](h)
     195        return self._cartesian_product_of_elements((gg,hh))
     196
     197    @cached_method
     198    def one(self):
     199        return self((self.summands()[0].one(), self.summands()[1].one()))
     200
     201    def product(self, x, y):
     202        xg = x.summand_projection(0)
     203        xh = x.summand_projection(1)
     204        yg = y.summand_projection(0)
     205        yh = y.summand_projection(1)
     206        if self.act_to_right():
     207            g = xg * yg
     208            h = self._twist(~yg,xh) * yh
     209        else:
     210            h = xh * yh
     211            g = xg * self._twist(xh,yg)
     212        return self((g,h))
     213
     214    @cached_method
     215    def opposite_semidirect_product(self):
     216        r"""
     217        Create the same semidirect product but with the positions of the groups exchanged.
     218
     219        EXAMPLES::
     220
     221            sage: G = GL(2,QQ)
     222            sage: L = QQ^2
     223            sage: EL = GroupExp()(L)
     224            sage: H = GroupSemidirectProduct(G, EL, twist = lambda g,v: EL(g*v.value), prefix1 = 't'); H
     225            Semidirect product of General Linear Group of degree 2 over Rational Field acting on Multiplicative form of Vector space of dimension 2 over Rational Field
     226            sage: h = H((Matrix([[0,1],[1,0]]), EL.an_element())); h
     227            [0 1]
     228            [1 0] * t[(1, 0)]
     229            sage: Hop = H.opposite_semidirect_product(); Hop
     230            Semidirect product of Multiplicative form of Vector space of dimension 2 over Rational Field acted upon by General Linear Group of degree 2 over Rational Field
     231            sage: hop = h.to_opposite(); hop
     232            t[(0, 1)] * [0 1]
     233            [1 0]
     234            sage: hop in Hop
     235            True
     236
     237        """
     238
     239        return GroupSemidirectProduct(self.summands()[1], self.summands()[0], twist=self._twist, act_to_right = not self.act_to_right(), prefix0 = self._prefix1, prefix1 = self._prefix0, print_tuple = self._print_tuple, category=self._category)
     240
     241GroupSemidirectProduct.Element = GroupSemidirectProductElement
     242