Ticket #12667: trac_12667_root_lattice_ms.patch

File trac_12667_root_lattice_ms.patch, 13.5 KB (added by mshimo, 6 years ago)
  • sage/combinat/root_system/root_lattice_realizations.py

    # HG changeset patch
    # User "sage-combinat script"
    # Date 1332184082 14400
    # Node ID ae0d10e786e1f0deb05a71a83734e51b957f4673
    # Parent  c926249cc2998594adb9d10c5d6e9771fc6cf1be
    #12667: Root system bug fix and enhancement.
    modified
    sage/combinat/root_system/root_lattice_realizations.py
    
    For elements of a root lattice realization:
    1. Added method reflect which reflects across a hyperplane orthogonal
    to a (co)root.
    2. Renamed to_positive_chamber to to_dominant_chamber, and added case checking
    for affine root systems which prevents infinite looping. Root systems
    that are not finite and not affine are not checked.
    3. Added method weyl_action which acts on a vector by a Weyl group element.
    4. Added method weyl_stabilizer which returns indices of simple reflections
    fixing a weight.
    
    diff --git a/sage/combinat/root_system/root_lattice_realizations.py b/sage/combinat/root_system/root_lattice_realizations.py
    a b from sage.categories.modules_with_basis  
    2727from sage.sets.family import Family
    2828from sage.rings.all import ZZ, QQ
    2929from sage.combinat.backtrack import TransitiveIdeal
     30from sage.misc.misc import deprecated_function_alias
     31from copy import copy
    3032
    3133class RootLatticeRealizations(Category_over_base_ring):
    3234    r"""
    class RootLatticeRealizations(Category_o 
    349351            """
    350352            assert(self.root_system.is_finite())
    351353            assert(self.root_system.is_irreducible())
    352             return self.a_long_simple_root().to_positive_chamber()
     354            return self.a_long_simple_root().to_dominant_chamber()
    353355
    354356        @cached_method
    355357        def a_long_simple_root(self):
    class RootLatticeRealizations(Category_o 
    12631265                alphacheck[1]
    12641266            """
    12651267
     1268        def reflection(self, root, use_coroot = False):
     1269            r"""
     1270            Reflects ``self`` across the hyperplane orthogonal to ``root``.
     1271
     1272            If ``use_coroot`` is True, ``root`` is interpreted as a coroot.
     1273
     1274            EXAMPLES::
     1275
     1276                sage: R = RootSystem(['C',4])
     1277                sage: weight_lattice = R.weight_lattice()
     1278                sage: mu = weight_lattice.from_vector(vector([0,0,1,2]))
     1279                sage: coroot_lattice = R.coroot_lattice()
     1280                sage: alphavee = coroot_lattice.from_vector(vector([0,0,1,1]))
     1281                sage: mu.reflection(alphavee, use_coroot=True)
     1282                6*Lambda[2] - 5*Lambda[3] + 2*Lambda[4]
     1283                sage: root_lattice = R.root_lattice()
     1284                sage: beta = root_lattice.from_vector(vector([0,1,1,0]))
     1285                sage: mu.reflection(beta)
     1286                Lambda[1] - Lambda[2] + 3*Lambda[4]
     1287            """
     1288            if use_coroot:
     1289                return self - self.scalar(root) * root.associated_coroot()
     1290            else:
     1291                return self - self.scalar(root.associated_coroot()) * root
     1292
     1293
    12661294        ##########################################################################
    12671295        # Descents
    12681296        ##########################################################################
    class RootLatticeRealizations(Category_o 
    13411369                index_set=self.parent().index_set()
    13421370            return [ i for i in index_set if self.has_descent(i, positive) ]
    13431371
    1344         def to_positive_chamber(self, index_set = None, positive = True):
    1345             """
    1346             Returns the unique element of the orbit of pt in the positive
    1347             chamber.
     1372        def to_dominant_chamber(self, index_set = None, positive = True, get_direction = False):
     1373            r"""
     1374            Returns the unique dominant element in the Weyl group orbit of the vector ``self``.
    13481375
    1349             With the index_set optional parameter, this is done with
    1350             respect to the corresponding parbolic subgroup
     1376            If ``positive`` is False, returns the antidominant orbit element.
    13511377
    1352             With positive = False, returns the unique element in the
    1353             negative chamber instead
     1378            With the ``index_set`` optional parameter, this is done with
     1379            respect to the corresponding parabolic subgroup.
    13541380
     1381            If ``get_direction`` is True, returns the 2-tuple (``weight``, ``direction``)
     1382            where ``weight`` is the (anti)dominant orbit element and ``direction`` is a reduced word
     1383            for the Weyl group element sending ``weight`` to ``self``.
     1384
     1385            .. warning::
     1386
     1387                In infinite type, an orbit may not contain a dominant element.
     1388                In this case the function may go into an infinite loop.
     1389
     1390                For affine root systems, assertion errors are generated if
     1391                the orbit does not contain the requested kind of representative.
     1392                If the input vector is of positive (resp. negative)
     1393                level, then there is a dominant (resp. antidominant) element in its orbit
     1394                but not an antidominant (resp. dominant) one. If the vector is of level zero,
     1395                then there are neither dominant nor antidominant orbit representatives, except
     1396                for multiples of the null root, which are themselves both dominant and antidominant
     1397                orbit representatives.
    13551398
    13561399            EXAMPLES::
    13571400
    13581401                sage: space=RootSystem(['A',5]).weight_space()
    13591402                sage: alpha=RootSystem(['A',5]).weight_space().simple_roots()
    1360                 sage: alpha[1].to_positive_chamber()
     1403                sage: alpha[1].to_dominant_chamber()
    13611404                Lambda[1] + Lambda[5]
    1362                 sage: alpha[1].to_positive_chamber([1,2])
     1405                sage: alpha[1].to_dominant_chamber([1,2])
    13631406                Lambda[1] + Lambda[2] - Lambda[3]
     1407                sage: wl=RootSystem(['A',2,1]).weight_lattice(extended=True)
     1408                sage: mu=wl.from_vector(vector([1,-3,0]))
     1409                sage: mu.to_dominant_chamber(positive=False, get_direction = True)
     1410                (-Lambda[1] - Lambda[2] - delta, [0, 2])
     1411
     1412                sage: R = RootSystem(['A',1,1])
     1413                sage: rl = R.root_lattice()
     1414                sage: mu = rl.from_vector(vector([0,1]))
     1415                sage: mu.to_dominant_chamber()
     1416                Traceback (most recent call last):
     1417                ...
     1418                AssertionError: This element is not in the orbit of the fundamental chamber
     1419
    13641420            """
     1421
    13651422            if index_set is None:
    1366                 index_set=self.parent().index_set()
     1423                # default index set is the entire Dynkin node set
     1424                index_set = self.parent().index_set()
     1425            cartan_type = self.parent().cartan_type()
     1426            # generate assertion errors for infinite loop cases in affine type
     1427            if cartan_type.is_affine():
     1428                if index_set == self.parent().index_set():
     1429                    # If the full affine Weyl group is being used
     1430                    level = self.level()
     1431                    if level > 0:
     1432                        assert positive, "This element is not in the orbit of the fundamental chamber"
     1433                    elif level < 0:
     1434                        assert not positive, "This element is not in the orbit of the negative of the fundamental chamber"
     1435                    else:
     1436                        # level zero
     1437                        if positive:
     1438                            assert self.is_dominant(), "This element is not in the orbit of the fundamental chamber"
     1439                        else:
     1440                            assert self.is_dominant(), "This element is not in the orbit of the negative of the fundamental chamber"
     1441            if get_direction:
     1442                direction = []
    13671443            while True:
    13681444                # The first index where it is *not* yet on the positive side
    13691445                i = self.first_descent(index_set, positive=(not positive))
    13701446                if i is None:
    1371                     return self
     1447                    if get_direction:
     1448                        return self, direction
     1449                    else:
     1450                        return self
    13721451                else:
     1452                    if get_direction:
     1453                        direction.append(i)
    13731454                    self = self.simple_reflection(i)
     1455 
     1456        to_positive_chamber = deprecated_function_alias(to_dominant_chamber, "Sage 4.8")
    13741457
    13751458        def reduced_word(self, index_set = None, positive = True):
    1376             """
    1377             Returns a shortest sequence of simple reflections mapping self
    1378             to the unique element `o` of its orbit in the positive
    1379             chamber. Alternatively this is a reduced word for the smallest
    1380             element of the group mapping `o` to self (recall that, by
    1381             convention, Weyl groups act on the left).
     1459            r"""
     1460            Returns a reduced word for the inverse of the shortest Weyl group element that sends the vector ``self`` into the dominant chamber.
     1461 
     1462            With the ``index_set`` optional parameter, this is done with
     1463            respect to the corresponding parabolic subgroup.
    13821464
    1383             With the index_set optional parameter, this is done with
    1384             respect to the corresponding parabolic subgroup
    1385 
    1386             With positive = False, returns the shortest sequence to the
    1387             negative chamber instead
    1388 
    1389             FIXME: better name?
     1465            If ``positive`` is False, use the antidominant chamber instead.
    13901466
    13911467            EXAMPLES::
    1392 
     1468 
    13931469                sage: space=RootSystem(['A',5]).weight_space()
    13941470                sage: alpha=RootSystem(['A',5]).weight_space().simple_roots()
    13951471                sage: alpha[1].reduced_word()
    13961472                [2, 3, 4, 5]
    13971473                sage: alpha[1].reduced_word([1,2])
    13981474                [2]
     1475
    13991476            """
    1400             result = []
    1401             if index_set is None:
    1402                 index_set=self.parent().index_set()
    1403             while True:
    1404                 # The first index where it is *not* yet on the positive side
    1405                 i = self.first_descent(index_set, positive=(not positive))
    1406                 if i is None:
    1407                     return result
    1408                 else:
    1409                     self = self.simple_reflection(i)
    1410                     result.append(i)
     1477            return self.to_dominant_chamber(index_set=index_set,positive=positive,get_direction = True)[1]
     1478
    14111479
    14121480        def is_dominant(self, index_set = None, positive = True):
    1413             """
     1481            r"""
    14141482            Returns whether self is dominant.
    14151483
    1416             INPUT:
    1417 
    1418             - ``v`` - an element of the lattice
     1484            This is done with respect to the subrootsystem indicated by the subset of Dynkin nodes
     1485            index_set. If index_set is None then the entire Dynkin node set is used.
     1486            If positive is False then the dominance condition is replaced by antidominance.
    14191487
    14201488            EXAMPLES::
    14211489
    class RootLatticeRealizations(Category_o 
    16121680            """
    16131681            assert self.level().is_zero()
    16141682            return x + x.level() * self
     1683
     1684        def weyl_action(self, w = None, reduced_word = None, inverse = False):
     1685            r"""
     1686            Acts on ``self`` by a Weyl group element.
     1687   
     1688            INPUT:
     1689            - If ``w`` is not None, use it to act.
     1690            - If ``reduced_word`` is not None, use it to act.
     1691            - Exactly one of ``w`` and ``reduced_word`` should not be None.
     1692            - If ``inverse`` is True, act by the inverse element.
     1693
     1694            EXAMPLES::
     1695           
     1696                sage: wl = RootSystem(['A',2,1]).weight_lattice(extended = True)
     1697                sage: mu = wl.from_vector(vector([1,-3,0]))
     1698                sage: mu
     1699                Lambda[0] - 3*Lambda[1]
     1700                sage: mudom, rw = mu.to_dominant_chamber(positive=False, get_direction = True)
     1701                sage: mudom, rw
     1702                (-Lambda[1] - Lambda[2] - delta, [0, 2])
     1703                sage: mudom.weyl_action(reduced_word = rw)
     1704                Lambda[0] - 3*Lambda[1]
     1705                sage: mu.weyl_action(reduced_word = rw, inverse = True)
     1706                -Lambda[1] - Lambda[2] - delta
     1707
     1708            """
     1709   
     1710            if w is None:
     1711                assert reduced_word is not None
     1712                rw = copy(reduced_word)
     1713            else:
     1714                rw = w.reduced_word()
     1715            if not inverse:
     1716                rw.reverse()
     1717            for i in rw:
     1718                self = self.simple_reflection(i)
     1719            return self
     1720
     1721        def weyl_stabilizer(self, index_set=None):
     1722            r"""
     1723            Returns the subset of Dynkin nodes whose reflections fix ``self``.
     1724
     1725            If ``index_set`` is not None, only consider nodes in this set.
     1726            Note that if ``self`` is dominant or antidominant, then its stabilizer is the
     1727            parabolic subgroup defined by the returned node set.
     1728
     1729            EXAMPLES::
     1730
     1731                sage: wl = RootSystem(['A',2,1]).weight_lattice(extended = True)
     1732                sage: al = wl.null_root()
     1733                sage: al.weyl_stabilizer()
     1734                [0, 1, 2]
     1735                sage: wl = RootSystem(['A',4]).weight_lattice()
     1736                sage: mu = wl.from_vector(vector([1,1,0,0]))
     1737                sage: mu.weyl_stabilizer()
     1738                [3, 4]
     1739                sage: mu.weyl_stabilizer(index_set = [1,2,3])
     1740                [3]
     1741
     1742            """
     1743
     1744            if index_set is None:
     1745                index_set = self.parent().cartan_type().index_set()
     1746            alphavee = self.parent().coroot_lattice().basis()
     1747            return [i for i in index_set if self.scalar(alphavee[i]) == 0]