Ticket #15283: trac_15283-additions-dg.patch

File trac_15283-additions-dg.patch, 6.6 KB (added by Darij Grinberg, 9 years ago)
  • sage/categories/posets.py

    # HG changeset patch
    # User darij grinberg <darijgrinberg@gmail.com>
    # Date 1382537755 25200
    # Node ID b51993495c9cb024335f907d2b49085838b1345d
    # Parent  404bc6de9738465c4be02b312815b502cdbf1f0d
    trac #15283: tests for antichains and chains
    
    diff --git a/sage/categories/posets.py b/sage/categories/posets.py
    a b class Posets(Category): 
    491491            """
    492492            return all((u in self and all(x in o for x in self.upper_covers(u))) for u in o)
    493493
     494        def is_chain_of_poset(self, o, ordered=False):
     495            """
     496            Return whether an iterable ``o`` is a chain of ``self``,
     497            including a check for ``o`` being ordered from smallest
     498            to largest element if the keyword ``ordered`` is set to
     499            ``True``.
     500
     501            INPUT:
     502
     503            - ``o`` -- an iterable (e. g., list, set, or tuple)
     504              containing some elements of ``self``
     505
     506            - ``ordered`` -- a Boolean (default: ``False``) which
     507              decides whether the notion of a chain includes being
     508              ordered
     509
     510            OUTPUT:
     511
     512            If ``ordered`` is set to ``False``, the truth value of
     513            the following assertion is returned: The subset of ``self``
     514            formed by the elements of ``o`` is a chain in ``self``.
     515
     516            If ``ordered`` is set to ``True``, the truth value of
     517            the following assertion is returned: Every element of the
     518            list ``o`` is (strictly!) smaller than its successor in
     519            ``self``. (This makes no sense if ``ordered`` is a set.)
     520
     521            EXAMPLES::
     522
     523                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
     524                sage: P.list()
     525                [1, 2, 3, 4, 6, 12]
     526                sage: P.is_chain_of_poset([1, 3])
     527                True
     528                sage: P.is_chain_of_poset([3, 1])
     529                True
     530                sage: P.is_chain_of_poset([1, 3], ordered=True)
     531                True
     532                sage: P.is_chain_of_poset([3, 1], ordered=True)
     533                False
     534                sage: P.is_chain_of_poset([])
     535                True
     536                sage: P.is_chain_of_poset([], ordered=True)
     537                True
     538                sage: P.is_chain_of_poset([])
     539                True
     540                sage: P.is_chain_of_poset((2, 12, 6))
     541                True
     542                sage: P.is_chain_of_poset((2, 6, 12), ordered=True)
     543                True
     544                sage: P.is_chain_of_poset((2, 12, 6), ordered=True)
     545                False
     546                sage: P.is_chain_of_poset((2, 12, 6, 3))
     547                False
     548                sage: P.is_chain_of_poset((2, 3))
     549                False
     550
     551                sage: Q = Poset({2: [3, 1], 3: [4], 1: [4]})
     552                sage: Q.is_chain_of_poset([1, 2], ordered=True)
     553                False
     554                sage: Q.is_chain_of_poset([1, 2])
     555                True
     556                sage: Q.is_chain_of_poset([2, 1], ordered=True)
     557                True
     558                sage: Q.is_chain_of_poset([3])
     559                True
     560                sage: Q.is_chain_of_poset([4, 2, 3])
     561                True
     562                sage: Q.is_chain_of_poset([4, 2, 3], ordered=True)
     563                False
     564                sage: Q.is_chain_of_poset([2, 3, 4], ordered=True)
     565                True
     566            """
     567            def hack_cmp(x, y):
     568                # Comparison function for elements of self that always returns
     569                # -1, 0 or 1 even when the elements are indistinguishable
     570                # (because sorted won't work otherwise):
     571                comparison = self.compare_elements(x, y)
     572                if comparison is None:
     573                    if x < y:
     574                        return -1
     575                    elif x == y:
     576                        return 0
     577                    elif x > y:
     578                        return 1
     579                return comparison
     580            if ordered:
     581                sorted_o = o
     582            else:
     583                sorted_o = sorted(o, cmp=hack_cmp)
     584            return all(self.lt(a, b) for a, b in zip(sorted_o, sorted_o[1:]))
     585
     586        def is_antichain_of_poset(self, o):
     587            """
     588            Return whether an iterable ``o`` is an antichain of
     589            ``self``.
     590
     591            INPUT:
     592
     593            - ``o`` -- an iterable (e. g., list, set, or tuple)
     594              containing some elements of ``self``
     595
     596            OUTPUT:
     597
     598            ``True`` if the subset of ``self`` consisting of the entries
     599            of ``o`` is an antichain of ``self``, and ``False`` otherwise.
     600
     601            EXAMPLES::
     602
     603                sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
     604                sage: P.list()
     605                [1, 2, 3, 4, 6, 12]
     606                sage: P.is_antichain_of_poset([1, 3])
     607                False
     608                sage: P.is_antichain_of_poset([3, 1])
     609                False
     610                sage: P.is_antichain_of_poset([1, 1, 3])
     611                False
     612                sage: P.is_antichain_of_poset([])
     613                True
     614                sage: P.is_antichain_of_poset([1])
     615                True
     616                sage: P.is_antichain_of_poset([1, 1])
     617                True
     618                sage: P.is_antichain_of_poset([3, 4])
     619                True
     620                sage: P.is_antichain_of_poset([3, 4, 12])
     621                False
     622                sage: P.is_antichain_of_poset([6, 4])
     623                True
     624                sage: P.is_antichain_of_poset(i for i in divisors(12) if (2 < i and i < 6))
     625                True
     626                sage: P.is_antichain_of_poset(i for i in divisors(12) if (2 <= i and i < 6))
     627                False
     628
     629                sage: Q = Poset({2: [3, 1], 3: [4], 1: [4]})
     630                sage: Q.is_antichain_of_poset((1, 2))
     631                False
     632                sage: Q.is_antichain_of_poset((2, 4))
     633                False
     634                sage: Q.is_antichain_of_poset((3, 4))
     635                False
     636                sage: Q.is_antichain_of_poset((3, 1))
     637                True
     638                sage: Q.is_antichain_of_poset((1, ))
     639                True
     640                sage: Q.is_antichain_of_poset(())
     641                True
     642            """
     643            list_o = list(o)
     644            for (i, x) in enumerate(list_o):
     645                for y in list_o[:x]:
     646                    if self.lt(x, y) or self.gt(x, y):
     647                        return False
     648            return True
     649
    494650    class ElementMethods:
    495651        pass
    496652        # TODO: implement x<y, x<=y, x>y, x>=y appropriately once #10130 is resolved