Ticket #15272: trac_15272_parabolic_bruhat_posets.patch

File trac_15272_parabolic_bruhat_posets.patch, 7.3 KB (added by vittucek, 9 years ago)
  • sage/combinat/root_system/weyl_group.py

    # HG changeset patch
    # User vit.tucek <vit.tucek@gmail.com>
    # Date 1381615538 -7200
    #      Sun Oct 13 00:05:38 2013 +0200
    # Node ID b2d1a28b844ad732aba76ab13ec828deae6ff0da
    # Parent  f0ee3538887fe739601babb54e177ec5e1133b7a
    Trac 15272: parabolic Bruhat posets
    
    diff --git a/sage/combinat/root_system/weyl_group.py b/sage/combinat/root_system/weyl_group.py
    a b  
    518518        for x in g:
    519519            d[x] = [y for y in g if x.length() < y.length() and ref.has_key(x*y.inverse())]
    520520        return DiGraph(d)
     521   
     522    def parabolic_bruhat_graph(self, index_set = None, side="right"):
     523        """
     524        Returns the Hasse graph of the poset ``self.bruhat_poset(index_set,side)`` with edges labeled by the cover relation.
     525        """
     526        elements = minimal_representatives(index_set, side)
     527        covers =[(x,y)  for y in elements for x in y.bruhat_lower_covers() if x in elements]
     528        res = DiGraph()
     529        for u,v in covers:
     530            res.add_edge(u,v,v.inverse()*u)
     531        return res
     532
     533   
     534    def minimal_representatives(self, index_set = None, side="right"):
     535        """
     536        Returns the set of minimal coset representatives of ``self`` by a parabolic subgroup.
     537
     538        INPUT:
     539
     540        - ``index_set`` - a subset (or iterable) of the nodes of the dynkin diagram, empty by default
     541        - ``side`` - 'left' or 'right' (default)
     542
     543        See documentation of ``self.bruhat_poset`` for more details.
     544
     545        The output is equivalent to ``set(w.coset_representative(index_set,side))``
     546           
     547        but this routine is much faster. For explanation of the algorithm see e.g. Cap, Slovak:
     548        Parabolic geometries, p. 332
     549
     550        EXAMPLES::
     551           
     552            sage: G = WeylGroup(CartanType("A4"),prefix="s")
     553            sage: index_set = [1,3,4]
     554            sage: side = "left"
     555            sage: a = set(w for w in G.minimal_representatives(index_set,side))
     556            sage: b = set(w.coset_representative(index_set,side) for w in G)
     557            sage: print a.difference(b)
     558            set([])
     559        """
     560        from sage.combinat.root_system.root_system import RootSystem
     561        from copy import copy
     562       
     563        if side != 'right' and side != 'left':
     564            raise ValueError, "%s is neither 'right' nor 'left'"%(side)
     565       
     566        weight_space = RootSystem(self.cartan_type()).weight_space()
     567        if index_set == None:
     568            crossed_nodes = set(self.index_set())
     569        else:
     570            crossed_nodes = set(self.index_set()).difference(index_set)
     571        # the characteristic vector
     572        rhop = sum([weight_space.fundamental_weight(i) for i in  crossed_nodes])
     573        '''
     574       
     575        The varibale "todo" serves for traversing the orbit of rhop, while the directory "known" serves as a memory to keep the visited elements. Its keys
     576are elements in the orbit of rhop while known[vec] are paths of simple reflections from rhop to vec.
     577       
     578        '''
     579        todo = [rhop]
     580        known = dict()
     581        known[rhop] = []
     582        if rhop == 0:
     583            return set( [self.one()] )
     584        else:
     585            while len(todo) > 0:
     586                vec = todo.pop()
     587                nonzero_coeffs = [i for i in self.index_set() if vec.coefficient(i) > 0]
     588                for i in nonzero_coeffs:
     589                    new_vec = vec.simple_reflection(i)
     590                    new_reflections = copy(known[vec])
     591                    new_reflections.append(i)
     592                    todo.append(new_vec)
     593                    known[new_vec] = new_reflections
     594            if side =='left':
     595                return set(self.from_reduced_word(w) for w in known.values())
     596            else:
     597                #here we could just take the inverses of w but reversing the list of simple reflections is slightly more efficient
     598                return set(self.from_reduced_word(w[::-1]) for w in known.values())
     599   
     600    def bruhat_poset(self, index_set = None, side="right", facade = False):
     601        """
     602        Returns the Bruhat poset of minimal coset representatives of ``self`` by a parabolic
     603        subgroup.
     604       
     605        INPUT:
     606       
     607        - ``index_set`` - a subset (or iterable) of the nodes of the dynkin diagram, empty by default
     608        - ``side`` - 'left' or 'right' (default)
     609       
     610        Let W_S be the subgroup of W (``self`` ) that is generated by the simple reflections
     611        corresponding to the set S (``index_set``). Then the cosets W / W_S have representatives of
     612        minimal length which are ordered by the Bruhat order of W.
     613       
     614        The ``index_set`` is the set of simple roots that generates the subgroup W_S of self.
     615        If the ``index_set`` is empty (which is the default), then we get the whole Weyl group.
     616       
     617        The parameter ``side`` (which defaults to "right") determines whether the result is the
     618        set of right coset representatives of W_S \ W or the set of left coset
     619        representatives W / W_S.
     620       
     621       
     622        EXAMPLES::
     623
     624            sage: W = WeylGroup(["A", 2])
     625            sage: P = W.bruhat_poset()
     626            sage: P
     627            Finite poset containing 6 elements
     628            sage: P.show()
     629
     630        Here are some typical operations on this poset::
     631
     632            sage: W = WeylGroup(["A", 3])
     633            sage: P = W.bruhat_poset()
     634            sage: u = W.from_reduced_word([3,1])
     635            sage: v = W.from_reduced_word([3,2,1,2,3])
     636            sage: P(u) <= P(v)
     637            True
     638            sage: len(P.interval(P(u), P(v)))
     639            10
     640            sage: P.is_join_semilattice()
     641            False
     642
     643        By default, the elements of `P` are aware that they belong
     644        to `P`::
     645
     646            sage: P.an_element().parent()
     647            Finite poset containing 24 elements
     648
     649        If instead one wants the elements to be plain elements of
     650        the Coxeter group, one can use the ``facade`` option::
     651
     652            sage: P = W.bruhat_poset(facade = True)
     653            sage: P.an_element().parent()
     654            Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space)
     655
     656        .. see also:: :func:`Poset` for more on posets and facade posets.
     657
     658        TESTS::
     659
     660            sage: [len(WeylGroup(["A", n]).bruhat_poset().cover_relations()) for n in [1,2,3]]
     661            [1, 8, 58]
     662
     663        .. todo::
     664
     665            - Use the symmetric group in the examples (for nicer
     666                output), and print the edges for a stronger test.
     667            - The constructed poset should be lazy, in order to
     668                handle large / infinite Coxeter groups.
     669        """
     670        from sage.combinat.posets.posets import Poset
     671        elements = self.minimal_representatives(index_set, side)
     672        # Since our Weyl elements should be already reduced (?), we could
     673        # optimize this step by constructing the cover relations directly (see Cap, Slovak: Parabolic geometries, p. 332),
     674        # thus reducing quadratic complexity of the next step to linear. On the other hand, we would have to introduce saturated subsets.
     675        covers = tuple([x,y] for y in elements for x in  y.bruhat_lower_covers()
     676                        if x in elements)
     677        return Poset((self, covers), cover_relations = True, facade=facade)
    521678
    522679
    523680class ClassicalWeylSubgroup(WeylGroup_gens):