def chains(self, element_class=list): """ Returns all chains of ``self``, organized as a prefix tree INPUT: - ``element_class`` -- (default:list) an iterable type EXAMPLES:: sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram sage: A = H.chains() sage: list(A) [[], [0], [0, 1], [0, 1, 4], [0, 2], [0, 2, 3], [0, 2, 3, 4], [0, 2, 4], [0, 3], [0, 3, 4], [0, 4], [1], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]] sage: A.cardinality() 20 sage: [1,3] in A False sage: [1,4] in A True .. seealso:: :meth:`antichains` """ from sage.combinat.subsets_pairwise import PairwiseCompatibleSubsets return PairwiseCompatibleSubsets(self.vertices(), self.are_comparable, element_class=element_class)
def chains(self, element_class=list, exclude=None): """ Return all chains of ``self``, organized as a prefix tree. INPUT: - ``element_class`` -- (default: ``list``) an iterable type - ``exclude`` -- elements of the poset to be excluded (default: ``None``) OUTPUT: The enumerated set (with a forest structure given by prefix ordering) consisting of all chains of ``self``, each of which is given as an ``element_class``. EXAMPLES:: sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram sage: A = H.chains() sage: list(A) [[], [0], [0, 1], [0, 1, 4], [0, 2], [0, 2, 3], [0, 2, 3, 4], [0, 2, 4], [0, 3], [0, 3, 4], [0, 4], [1], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]] sage: A.cardinality() 20 sage: [1,3] in A False sage: [1,4] in A True One can exclude some vertices:: sage: list(H.chains(exclude=[4, 3])) [[], [0], [0, 1], [0, 2], [1], [2]] The ``element_class`` keyword determines how the chains are being returned: sage: P = Poset({1: [2, 3], 2: [4]}) sage: list(P._hasse_diagram.chains(element_class=tuple)) [(), (0,), (0, 1), (0, 1, 2), (0, 2), (0, 3), (1,), (1, 2), (2,), (3,)] sage: list(P._hasse_diagram.chains()) [[], [0], [0, 1], [0, 1, 2], [0, 2], [0, 3], [1], [1, 2], [2], [3]] (Note that taking the Hasse diagram has renamed the vertices.) sage: list(P._hasse_diagram.chains(element_class=tuple, exclude=[0])) [(), (1,), (1, 2), (2,), (3,)] .. seealso:: :meth:`antichains` """ from sage.combinat.subsets_pairwise import PairwiseCompatibleSubsets if not (exclude is None): vertices = [u for u in self.vertices() if not u in exclude] else: vertices = self.vertices() return PairwiseCompatibleSubsets(vertices, self.are_comparable, element_class=element_class)
def antichains(self, element_class=list): """ Returns all antichains of ``self``, organized as a prefix tree INPUT: - ``element_class`` -- (default:list) an iterable type EXAMPLES:: sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram sage: A = H.antichains() sage: list(A) [[], [0], [1], [1, 2], [1, 3], [2], [3], [4]] sage: A.cardinality() 8 sage: [1,3] in A True sage: [1,4] in A False TESTS:: sage: TestSuite(A).run(skip = "_test_pickling") .. note:: It's actually the pickling of the cached method :meth:`coxeter_transformation` that fails ... TESTS:: sage: A = Poset()._hasse_diagram.antichains() sage: list(A) [[]] sage: TestSuite(A).run() """ from sage.combinat.subsets_pairwise import PairwiseCompatibleSubsets return PairwiseCompatibleSubsets(self.vertices(), self.are_incomparable, element_class=element_class)
def breadth(self, certificate=False): r""" Return the breadth of the lattice. The breadth of a lattice is the largest integer `n` such that any join of elements `x_1, x_2, \ldots, x_{n+1}` is join of a proper subset of `x_i`. INPUT: - ``certificate`` -- (boolean; default: ``False``) -- whether to return an integer (the breadth) or a certificate, i.e. a biggest set whose join differs from the join of any subset. EXAMPLES:: sage: D10 = Posets.DiamondPoset(10) sage: D10.breadth() 2 sage: B3 = Posets.BooleanLattice(3) sage: B3.breadth() 3 sage: B3.breadth(certificate=True) [1, 2, 4] Smallest example of a lattice with breadth 4:: sage: L = LatticePoset(DiGraph('O]???w?K_@S?E_??Q?@_?D??I??W?B??@??C??O?@???')) sage: L.breadth() 4 ALGORITHM: For a lattice to have breadth at least `n`, it must have an `n`-element antichain `A` with join `j`. Element `j` must cover at least `n` elements. There must also be `n-2` levels of elements between `A` and `j`. So we start by searching elements that could be our `j` and then just check possible antichains `A`. TESTS:: sage: Posets.ChainPoset(0).breadth() 0 sage: Posets.ChainPoset(1).breadth() 1 """ # A place for optimization: Adding a doubly irreducible element to # a lattice does not change the breadth, except from 1 to 2. # Hence we could start by removing double irreducibles. from sage.combinat.subsets_pairwise import PairwiseCompatibleSubsets # First check if breadth is zero (empty lattice) or one (a chain). n = self.cardinality() if n == 0: return [] if certificate else 0 if self.is_chain(): return [self.bottom()] if certificate else 1 # Breadth is at least two. # Work directly with the Hasse diagram H = self._hasse_diagram # Helper function: Join of elements in the list L. jn = H._join def join(L): j = 0 for i in L: j = jn[i, j] return j indegs = [H.in_degree(i) for i in range(n)] max_breadth = max(indegs) for B in range(max_breadth, 1, -1): for j in H: if indegs[j] < B: continue # Get elements more than B levels below it. too_close = set(H.breadth_first_search(j, neighbors=H.neighbors_in, distance=B-2)) elems = [e for e in H.order_ideal([j]) if e not in too_close] achains = PairwiseCompatibleSubsets(elems, lambda x,y: H.are_incomparable(x,y)) achains_n = achains.elements_of_depth_iterator(B) for A in achains_n: if join(A) == j: if all(join(A[:i]+A[i+1:]) != j for i in range(B)): if certificate: return [self._vertex_to_element(e) for e in A] else: return B assert False, "BUG: breadth() in lattices.py have an error."