Ticket #15428: trac_15428-partition-posets-dg.patch

File trac_15428-partition-posets-dg.patch, 14.8 KB (added by darij, 7 years ago)

updated version

  • sage/combinat/partition.py

    # HG changeset patch
    # User darij grinberg <darijgrinberg@gmail.com>
    # Date 1386341511 28800
    # Node ID ea57dc7a6a8d01de503b8de2e4e763e8fed9068a
    # Parent  d54cbe14f5be80106485d1c7cae772f65efb1f26
    trac #15428: partitions to posets
    
    diff --git a/sage/combinat/partition.py b/sage/combinat/partition.py
    a b class Partition(CombinatorialObject, Ele 
    14031403        """
    14041404        return [p for p in self.down()]
    14051405
     1406    def cell_poset(self, orientation="SE"):
     1407        """
     1408        Return the Young diagram of ``self`` as a poset. The optional
     1409        keyword variable ``orientation`` determines the order relation
     1410        of the poset.
     1411
     1412        The poset always uses the set of cells of the Young diagram
     1413        of ``self`` as its ground set. The order relation of the poset
     1414        depends on the ``orientation`` variable (which defaults to
     1415        ``"SE"``). Concretely, ``orientation`` has to be specified to
     1416        one of the strings ``"NW"``, ``"NE"``, ``"SW"``, and ``"SE"``,
     1417        standing for "northwest", "northeast", "southwest" and
     1418        "southeast", respectively. If ``orientation`` is ``"SE"``, then
     1419        the order relation of the poset is such that a cell `u` is
     1420        greater or equal to a cell `v` in the poset if and only if `u`
     1421        lies weakly southeast of `v` (this means that `u` can be
     1422        reached from `v` by a sequence of south and east steps; the
     1423        sequence is allowed to consist of south steps only, or of east
     1424        steps only, or even be empty). Similarly the order relation is
     1425        defined for the other three orientations. The Young diagram is
     1426        supposed to be drawn in English notation.
     1427
     1428        The elements of the poset are the cells of the Young diagram
     1429        of ``self``, written as tuples of zero-based coordinates (so
     1430        that `(3, 7)` stands for the `8`-th cell of the `4`-th row,
     1431        etc.).
     1432
     1433        EXAMPLES::
     1434
     1435            sage: p = Partition([3,3,1])
     1436            sage: Q = p.cell_poset(); Q
     1437            Finite poset containing 7 elements
     1438            sage: sorted(Q)
     1439            [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0)]
     1440            sage: sorted(Q.maximal_elements())
     1441            [(1, 2), (2, 0)]
     1442            sage: Q.minimal_elements()
     1443            [(0, 0)]
     1444            sage: sorted(Q.upper_covers((1, 0)))
     1445            [(1, 1), (2, 0)]
     1446            sage: Q.upper_covers((1, 1))
     1447            [(1, 2)]
     1448
     1449            sage: P = p.cell_poset(orientation="NW"); P
     1450            Finite poset containing 7 elements
     1451            sage: sorted(P)
     1452            [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0)]
     1453            sage: sorted(P.minimal_elements())
     1454            [(1, 2), (2, 0)]
     1455            sage: P.maximal_elements()
     1456            [(0, 0)]
     1457            sage: P.upper_covers((2, 0))
     1458            [(1, 0)]
     1459            sage: sorted(P.upper_covers((1, 2)))
     1460            [(0, 2), (1, 1)]
     1461            sage: sorted(P.upper_covers((1, 1)))
     1462            [(0, 1), (1, 0)]
     1463            sage: sorted([len(P.upper_covers(v)) for v in P])
     1464            [0, 1, 1, 1, 1, 2, 2]
     1465
     1466            sage: R = p.cell_poset(orientation="NE"); R
     1467            Finite poset containing 7 elements
     1468            sage: sorted(R)
     1469            [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0)]
     1470            sage: R.maximal_elements()
     1471            [(0, 2)]
     1472            sage: R.minimal_elements()
     1473            [(2, 0)]
     1474            sage: sorted([len(R.upper_covers(v)) for v in R])
     1475            [0, 1, 1, 1, 1, 2, 2]
     1476            sage: R.is_isomorphic(P)
     1477            False
     1478            sage: R.is_isomorphic(P.dual())
     1479            False
     1480
     1481        Linear extensions of ``p.cell_poset()`` are in 1-to-1 correspondence
     1482        with standard Young tableaux of shape `p`::
     1483
     1484            sage: all( len(p.cell_poset().linear_extensions())
     1485            ....:      == len(p.standard_tableaux())
     1486            ....:      for n in range(8) for p in Partitions(n) )
     1487            True
     1488
     1489        This is not the case for northeast orientation::
     1490
     1491            sage: q = Partition([3, 1])
     1492            sage: q.cell_poset(orientation="NE").is_chain()
     1493            True
     1494
     1495        TESTS:
     1496
     1497        We check that the posets are really what they should be for size
     1498        up to `7`::
     1499
     1500            sage: def check_NW(n):
     1501            ....:     for p in Partitions(n):
     1502            ....:         P = p.cell_poset(orientation="NW")
     1503            ....:         for c in p.cells():
     1504            ....:             for d in p.cells():
     1505            ....:                 if P.le(c, d) != (c[0] >= d[0]
     1506            ....:                                   and c[1] >= d[1]):
     1507            ....:                     return False
     1508            ....:     return True
     1509            sage: all( check_NW(n) for n in range(8) )
     1510            True
     1511
     1512            sage: def check_NE(n):
     1513            ....:     for p in Partitions(n):
     1514            ....:         P = p.cell_poset(orientation="NE")
     1515            ....:         for c in p.cells():
     1516            ....:             for d in p.cells():
     1517            ....:                 if P.le(c, d) != (c[0] >= d[0]
     1518            ....:                                   and c[1] <= d[1]):
     1519            ....:                     return False
     1520            ....:     return True
     1521            sage: all( check_NE(n) for n in range(8) )
     1522            True
     1523
     1524            sage: def test_duality(n, ori1, ori2):
     1525            ....:     for p in Partitions(n):
     1526            ....:         P = p.cell_poset(orientation=ori1)
     1527            ....:         Q = p.cell_poset(orientation=ori2)
     1528            ....:         for c in p.cells():
     1529            ....:             for d in p.cells():
     1530            ....:                 if P.lt(c, d) != Q.lt(d, c):
     1531            ....:                     return False
     1532            ....:     return True
     1533            sage: all( test_duality(n, "NW", "SE") for n in range(8) )
     1534            True
     1535            sage: all( test_duality(n, "NE", "SW") for n in range(8) )
     1536            True
     1537            sage: all( test_duality(n, "NE", "SE") for n in range(4) )
     1538            False
     1539        """
     1540        from sage.combinat.posets.posets import Poset
     1541        covers = {}
     1542        if orientation == "NW":
     1543            for i, row in enumerate(self):
     1544                if i == 0:
     1545                    covers[(0, 0)] = []
     1546                    for j in range(1, row):
     1547                        covers[(0, j)] = [(0, j - 1)]
     1548                else:
     1549                    covers[(i, 0)] = [(i - 1, 0)]
     1550                    for j in range(1, row):
     1551                        covers[(i, j)] = [(i - 1, j), (i, j - 1)]
     1552        elif orientation == "NE":
     1553            for i, row in enumerate(self):
     1554                if i == 0:
     1555                    covers[(0, row - 1)] = []
     1556                    for j in range(row - 1):
     1557                        covers[(0, j)] = [(0, j + 1)]
     1558                else:
     1559                    covers[(i, row - 1)] = [(i - 1, row - 1)]
     1560                    for j in range(row - 1):
     1561                        covers[(i, j)] = [(i - 1, j), (i, j + 1)]
     1562        elif orientation == "SE":
     1563            l = len(self) - 1
     1564            for i, row in enumerate(self):
     1565                if i == l:
     1566                    covers[(i, row - 1)] = []
     1567                    for j in range(row - 1):
     1568                        covers[(i, j)] = [(i, j + 1)]
     1569                else:
     1570                    next_row = self[i + 1]
     1571                    if row == next_row:
     1572                        covers[(i, row - 1)] = [(i + 1, row - 1)]
     1573                        for j in range(row - 1):
     1574                            covers[(i, j)] = [(i + 1, j), (i, j + 1)]
     1575                    else:
     1576                        covers[(i, row - 1)] = []
     1577                        for j in range(next_row):
     1578                            covers[(i, j)] = [(i + 1, j), (i, j + 1)]
     1579                        for j in range(next_row, row - 1):
     1580                            covers[(i, j)] = [(i, j + 1)]
     1581        elif orientation == "SW":
     1582            l = len(self) - 1
     1583            for i, row in enumerate(self):
     1584                if i == l:
     1585                    covers[(i, 0)] = []
     1586                    for j in range(1, row):
     1587                        covers[(i, j)] = [(i, j - 1)]
     1588                else:
     1589                    covers[(i, 0)] = [(i + 1, 0)]
     1590                    next_row = self[i + 1]
     1591                    for j in range(1, next_row):
     1592                        covers[(i, j)] = [(i + 1, j), (i, j - 1)]
     1593                    for j in range(next_row, row):
     1594                        covers[(i, j)] = [(i, j - 1)]
     1595        return Poset(covers)
     1596
    14061597    def frobenius_coordinates(self):
    14071598        """
    14081599        Return a pair of sequences of Frobenius coordinates aka beta numbers
    class Partitions_n(Partitions): 
    51505341        TESTS::
    51515342
    51525343            sage: all(Part.random_element_uniform() in Part
    5153             ...       for Part in map(Partitions, range(10)))
     5344            ....:     for Part in map(Partitions, range(10)))
    51545345            True
    51555346
    51565347        ALGORITHM:
  • sage/combinat/skew_partition.py

    diff --git a/sage/combinat/skew_partition.py b/sage/combinat/skew_partition.py
    a b class SkewPartition(CombinatorialObject, 
    709709        icorners += [(nn, 0)]
    710710        return icorners
    711711
     712    def cell_poset(self, orientation="SE"):
     713        """
     714        Return the Young diagram of ``self`` as a poset. The optional
     715        keyword variable ``orientation`` determines the order relation
     716        of the poset.
     717
     718        The poset always uses the set of cells of the Young diagram
     719        of ``self`` as its ground set. The order relation of the poset
     720        depends on the ``orientation`` variable (which defaults to
     721        ``"SE"``). Concretely, ``orientation`` has to be specified to
     722        one of the strings ``"NW"``, ``"NE"``, ``"SW"``, and ``"SE"``,
     723        standing for "northwest", "northeast", "southwest" and
     724        "southeast", respectively. If ``orientation`` is ``"SE"``, then
     725        the order relation of the poset is such that a cell `u` is
     726        greater or equal to a cell `v` in the poset if and only if `u`
     727        lies weakly southeast of `v` (this means that `u` can be
     728        reached from `v` by a sequence of south and east steps; the
     729        sequence is allowed to consist of south steps only, or of east
     730        steps only, or even be empty). Similarly the order relation is
     731        defined for the other three orientations. The Young diagram is
     732        supposed to be drawn in English notation.
     733
     734        The elements of the poset are the cells of the Young diagram
     735        of ``self``, written as tuples of zero-based coordinates (so
     736        that `(3, 7)` stands for the `8`-th cell of the `4`-th row,
     737        etc.).
     738
     739        EXAMPLES::
     740
     741            sage: p = SkewPartition([[3,3,1], [2,1]])
     742            sage: Q = p.cell_poset(); Q
     743            Finite poset containing 4 elements
     744            sage: sorted(Q)
     745            [(0, 2), (1, 1), (1, 2), (2, 0)]
     746            sage: sorted(Q.maximal_elements())
     747            [(1, 2), (2, 0)]
     748            sage: sorted(Q.minimal_elements())
     749            [(0, 2), (1, 1), (2, 0)]
     750            sage: sorted(Q.upper_covers((1, 1)))
     751            [(1, 2)]
     752            sage: sorted(Q.upper_covers((0, 2)))
     753            [(1, 2)]
     754
     755            sage: P = p.cell_poset(orientation="NW"); P
     756            Finite poset containing 4 elements
     757            sage: sorted(P)
     758            [(0, 2), (1, 1), (1, 2), (2, 0)]
     759            sage: sorted(P.minimal_elements())
     760            [(1, 2), (2, 0)]
     761            sage: sorted(P.maximal_elements())
     762            [(0, 2), (1, 1), (2, 0)]
     763            sage: sorted(P.upper_covers((1, 2)))
     764            [(0, 2), (1, 1)]
     765
     766            sage: R = p.cell_poset(orientation="NE"); R
     767            Finite poset containing 4 elements
     768            sage: sorted(R)
     769            [(0, 2), (1, 1), (1, 2), (2, 0)]
     770            sage: R.maximal_elements()
     771            [(0, 2)]
     772            sage: R.minimal_elements()
     773            [(2, 0)]
     774            sage: R.upper_covers((2, 0))
     775            [(1, 1)]
     776            sage: sorted([len(R.upper_covers(v)) for v in R])
     777            [0, 1, 1, 1]
     778
     779        TESTS:
     780
     781        We check that the posets are really what they should be for size
     782        up to `6`::
     783
     784            sage: def check_NW(n):
     785            ....:     for p in SkewPartitions(n):
     786            ....:         P = p.cell_poset(orientation="NW")
     787            ....:         for c in p.cells():
     788            ....:             for d in p.cells():
     789            ....:                 if P.le(c, d) != (c[0] >= d[0]
     790            ....:                                   and c[1] >= d[1]):
     791            ....:                     return False
     792            ....:     return True
     793            sage: all( check_NW(n) for n in range(7) )
     794            True
     795
     796            sage: def check_NE(n):
     797            ....:     for p in SkewPartitions(n):
     798            ....:         P = p.cell_poset(orientation="NE")
     799            ....:         for c in p.cells():
     800            ....:             for d in p.cells():
     801            ....:                 if P.le(c, d) != (c[0] >= d[0]
     802            ....:                                   and c[1] <= d[1]):
     803            ....:                     return False
     804            ....:     return True
     805            sage: all( check_NE(n) for n in range(7) )
     806            True
     807
     808            sage: def test_duality(n, ori1, ori2):
     809            ....:     for p in SkewPartitions(n):
     810            ....:         P = p.cell_poset(orientation=ori1)
     811            ....:         Q = p.cell_poset(orientation=ori2)
     812            ....:         for c in p.cells():
     813            ....:             for d in p.cells():
     814            ....:                 if P.lt(c, d) != Q.lt(d, c):
     815            ....:                     return False
     816            ....:     return True
     817            sage: all( test_duality(n, "NW", "SE") for n in range(7) )
     818            True
     819            sage: all( test_duality(n, "NE", "SW") for n in range(7) )
     820            True
     821            sage: all( test_duality(n, "NE", "SE") for n in range(4) )
     822            False
     823        """
     824        from sage.combinat.posets.posets import Poset
     825        # Getting the cover relations seems hard, so let's just compute
     826        # the comparison function.
     827        if orientation == "NW":
     828            def poset_le(u, v):
     829                return u[0] >= v[0] and u[1] >= v[1]
     830        elif orientation == "NE":
     831            def poset_le(u, v):
     832                return u[0] >= v[0] and u[1] <= v[1]
     833        elif orientation == "SE":
     834            def poset_le(u, v):
     835                return u[0] <= v[0] and u[1] <= v[1]
     836        elif orientation == "SW":
     837            def poset_le(u, v):
     838                return u[0] <= v[0] and u[1] >= v[1]
     839        return Poset((self.cells(), poset_le))
     840
    712841    def frobenius_rank(self):
    713842        r"""
    714843        Return the Frobenius rank of the skew partition ``self``.