def random_element(self): r""" Return a uniformly random element of ``self``. ALGORITHM: This uses the :meth:`~sage.combinat.posets.posets.FinitePoset.random_order_ideal` method and the natural bijection with plane partitions. EXAMPLES:: sage: P = PlanePartitions((4,3,5)) sage: P.random_element() Plane partition [[4, 3, 3], [4, 0, 0], [2, 0, 0], [0, 0, 0]] """ def leq(thing1, thing2): return all(thing1[i] <= thing2[i] for i in range(len(thing1))) elem = [(i,j,k) for i in range(self._box[0]) for j in range(self._box[1]) for k in range(self._box[2])] myposet = Poset((elem, leq)) R = myposet.random_order_ideal() Z = [[0 for i in range(self._box[1])] for j in range(self._box[0])] for C in R: Z[C[0]][C[1]] += 1 return self.element_class(self, Z, check=False)
def LatticePoset(data, *args, **options): r""" Construct a lattice from various forms of input data. INPUT: - ``data``, ``*args``, ``**options`` -- data and options that will be passed down to :func:`Poset` to construct a poset that is also a lattice. OUTPUT: FiniteLatticePoset -- an instance of :class:`FiniteLatticePoset` .. seealso:: :class:`Posets`, :class:`FiniteLatticePosets`, :func:`JoinSemiLattice`, :func:`MeetSemiLattice` EXAMPLES: Using data that defines a poset:: sage: LatticePoset([[1,2],[3],[3]]) Finite lattice containing 4 elements sage: LatticePoset([[1,2],[3],[3]], cover_relations = True) Finite lattice containing 4 elements Using a previously constructed poset:: sage: P = Poset([[1,2],[3],[3]]) sage: L = LatticePoset(P); L Finite lattice containing 4 elements sage: type(L) <class 'sage.combinat.posets.lattices.FiniteLatticePoset_with_category'> If the data is not a lattice, then an error is raised:: sage: elms = [1,2,3,4,5,6,7] sage: rels = [[1,2],[3,4],[4,5],[2,5]] sage: LatticePoset((elms, rels)) Traceback (most recent call last): ... ValueError: Not a lattice. Creating a facade lattice:: sage: L = LatticePoset([[1,2],[3],[3]], facade = True) sage: L.category() Category of facade finite lattice posets sage: parent(L[0]) Integer Ring sage: TestSuite(L).run(skip = ['_test_an_element']) # is_parent_of is not yet implemented """ if isinstance(data,FiniteLatticePoset) and len(args) == 0 and len(options) == 0: return data P = Poset(data, *args, **options) if not P.is_lattice(): raise ValueError, "Not a lattice." return FiniteLatticePoset(P, category = FiniteLatticePosets(), facade = P._is_facade)
def green_classes(self, side = "twosided"): r""" INPUT: - ``side`` -- "left", "right", or "twosided" Depending on the value of ``side``, returns respectively the `L`-classes, `R`-classes, or `J`-classes of ``self``, sorted decreasingly along a linear extension of respectively `L`, `R` or `J`-order. EXAMPLES:: sage: M = Semigroups().Finite().example(('a','b')); M An example of a finite semigroup: the left regular band generated by ('a', 'b') sage: M.green_classes() [{'a'}, {'b'}, {'ab', 'ba'}] sage: M.green_classes(side="left") [{'a'}, {'b'}, {'ab', 'ba'}] sage: M.green_classes(side="right") [{'b'}, {'a'}, {'ab'}, {'ba'}] """ G = self.cayley_graph_cached(side=side, simple=True).strongly_connected_components_digraph() from sage.combinat.posets.posets import Poset P = Poset(G, facade = True) return P.linear_extension()
def composition_series_poset(self, side = 'right'): """ Experimental, and apparently broken ... EXAMPLES:: sage: S = Monoids().Aperiodic().Finite().example(5); S The finite H-trivial monoid of order preserving maps on {1, 2, 3, 4, 5} sage: P = S.composition_series_poset(side = 'right') sage: list(P) [4, 3, 2, 1, 0] sage: P.cover_relations() [] sage: P = S.composition_series_poset(side = 'left') sage: list(P) [4, 3, 2, 1, 0] sage: P.cover_relations() """ from sage.combinat.posets.posets import Poset Js = self.regular_j_classes_keys() principal_order_filters = {} for J in Js: R = self.lr_regular_class_module(J, side=side) principal_order_filters[J] = R.composition_series() import time print "%s %s: %s %s %s"%(time.strftime("%H:%M:%S"), J, self.simple_module_dimension(J), R.dimension(), principal_order_filters[J]) P = Poset( ( Js, lambda J1, J2: J2 in principal_order_filters[J1] ), facade = True ) from sage.sets.set import Set assert all( Set( P.principal_order_filter(J) ) == principal_order_filters[J] for J in Js ) return P
def to_poset(self, root_to_leaf = False): r""" Return the poset obtained by interpreting the tree as a hasse diagram. The default orientation is from leaves to root but you can pass ``root_to_leaf=True`` to obtain the inverse orientation. INPUT: - ``root_to_leaf`` -- boolean, true if the poset orientation should be from root to leaves. It is false by default. EXAMPLES:: sage: t = OrderedTree([]) sage: t.to_poset() Finite poset containing 1 elements sage: p = OrderedTree([[[]],[],[]]).to_poset() sage: p.cover_relations() [[3, 4], [2, 4], [0, 1], [1, 4]] sage: p = OrderedTree([[[]],[],[]]).to_poset(root_to_leaf=True) sage: p.cover_relations() [[0, 1], [0, 2], [0, 3], [3, 4]] If the tree is labelled, we use its labelling to label the poset. Otherwise, we use the poset canonical labelling:: sage: t = OrderedTree([[[]],[],[]]).canonical_labelling() sage: t 1[2[3[]], 4[], 5[]] sage: t.to_poset().cover_relations() [[5, 1], [4, 1], [3, 2], [2, 1]] """ if self in LabelledOrderedTrees(): relabel = False else: self = self.canonical_labelling() relabel = True relations = [] elements = [self.label()] roots = [self] while len(roots)!=0: node = roots.pop() for child in node: elements.append(child.label()) relations.append((node.label(),child.label()) if root_to_leaf else (child.label(),node.label())) roots.append(child) from sage.combinat.posets.posets import Poset p = Poset([elements, relations]) if relabel: p = p.canonical_label() return p
def MeetSemilattice(data, *args, **options): r""" Construct a meet semi-lattice from various forms of input data. INPUT: - ``data``, ``*args``, ``**options`` -- data and options that will be passed down to :func:`Poset` to construct a poset that is also a meet semilattice. .. seealso:: :func:`Poset`, :func:`JoinSemilattice`, :func:`LatticePoset` EXAMPLES: Using data that defines a poset:: sage: MeetSemilattice([[1,2],[3],[3]]) Finite meet-semilattice containing 4 elements sage: MeetSemilattice([[1,2],[3],[3]], cover_relations = True) Finite meet-semilattice containing 4 elements Using a previously constructed poset:: sage: P = Poset([[1,2],[3],[3]]) sage: L = MeetSemilattice(P); L Finite meet-semilattice containing 4 elements sage: type(L) <class 'sage.combinat.posets.lattices.FiniteMeetSemilattice_with_category'> If the data is not a lattice, then an error is raised:: sage: elms = [1,2,3,4,5,6,7] sage: rels = [[1,2],[3,4],[4,5],[2,5]] sage: MeetSemilattice((elms, rels)) Traceback (most recent call last): ... ValueError: Not a meet semilattice. """ if isinstance(data,FiniteMeetSemilattice) and len(args) == 0 and len(options) == 0: return data P = Poset(data, *args, **options) if not P.is_meet_semilattice(): raise ValueError, "Not a meet semilattice." return FiniteMeetSemilattice(P)
def __init__(self): r""" Container for all possible analytic types of forms and/or spaces. This class is supposed to be used as a Singleton. It first creates a ``Poset`` that contains all basic analytic properties to be modeled by the AnalyticType. Then the order ideals lattice of that Poset is taken as the underlying FiniteLatticePoset of ``self``. In particular elements of ``self`` describe what basic analytic properties are contained/included in that element. EXAMPLES:: sage: AT = AnalyticType() sage: AT Analytic Type sage: isinstance(AT, FiniteLatticePoset) True sage: AT.is_lattice() True sage: AT.is_finite() True sage: AT.cardinality() 10 sage: AT.is_modular() True sage: AT.is_bounded() True sage: AT.is_distributive() True sage: AT.list() [zero, zero, cuspidal, modular, weakly holomorphic modular, quasi cuspidal, quasi modular, quasi weakly holomorphic modular, meromorphic modular, quasi meromorphic modular] sage: len(AT.relations()) 45 sage: AT.cover_relations() [[zero, zero], [zero, cuspidal], [zero, quasi cuspidal], [cuspidal, modular], [cuspidal, quasi cuspidal], [modular, weakly holomorphic modular], [modular, quasi modular], [weakly holomorphic modular, quasi weakly holomorphic modular], [weakly holomorphic modular, meromorphic modular], [quasi cuspidal, quasi modular], [quasi modular, quasi weakly holomorphic modular], [quasi weakly holomorphic modular, quasi meromorphic modular], [meromorphic modular, quasi meromorphic modular]] sage: AT.has_top() True sage: AT.has_bottom() True sage: AT.top() quasi meromorphic modular sage: AT.bottom() zero """ # We (arbitrarily) choose to model by inclusion instead of restriction P_elements = [ "cusp", "holo", "weak", "mero", "quasi"] P_relations = [["cusp", "holo"], ["holo", "weak"], ["weak", "mero"]] self._base_poset = Poset([P_elements, P_relations], cover_relations=True, facade=False) L = self._base_poset.order_ideals_lattice() L = FiniteLatticePoset(L, facade=False) FiniteLatticePoset.__init__(self, hasse_diagram=L._hasse_diagram, elements=L._elements, category=L.category(), facade=L._is_facade, key=None)
class AnalyticType(FiniteLatticePoset): r""" Container for all possible analytic types of forms and/or spaces The ``analytic type`` of forms spaces or rings describes all possible occuring basic ``analytic properties`` of elements in the space/ring (or more). For ambient spaces/rings this means that all elements with those properties (and the restrictions of the space/ring) are contained in the space/ring. The analytic type of an element is the analytic type of its minimal ambient space/ring. The basic ``analytic properties`` are: - ``quasi`` - Whether the element is quasi modular (and not modular) or modular. - ``mero`` - ``meromorphic``: If the element is meromorphic and meromorphic at infinity. - ``weak`` - ``weakly holomorphic``: If the element is holomorphic and meromorphic at infinity. - ``holo`` - ``holomorphic``: If the element is holomorphic and holomorphic at infinity. - ``cusp`` - ``cuspidal``: If the element additionally has a positive order at infinity. The ``zero`` elements/property have no analytic properties (or only ``quasi``). For ring elements the property describes whether one of its homogeneous components satisfies that property and the "union" of those properties is returned as the ``analytic type``. Similarly for quasi forms the property describes whether one of its quasi components satisfies that property. There is a (natural) partial order between the basic properties (and analytic types) given by "inclusion". We name the analytic type according to its maximal analytic properties. EXAMPLES:: For n=3 the quasi form ``el = E6 - E2^3`` has the quasi components ``E6`` which is ``holomorphic`` and ``E2^3`` which is ``quasi holomorphic``. So the analytic type of ``el`` is ``quasi holomorphic`` despite the fact that the sum (``el``) describes a function which is zero at infinity. sage: from space import QModularForms sage: x,y,z,d = var("x,y,z,d") sage: el = QModularForms(group=3, k=6, ep=-1)(y-z^3) sage: el.analytic_type() quasi modular Similarly the type of the ring element ``el2 = E4/Delta - E6/Delta`` is ``weakly holomorphic`` despite the fact that the sum (``el2``) describes a function which is holomorphic at infinity. sage: from graded_ring import WeakModularFormsRing sage: x,y,z,d = var("x,y,z,d") sage: el2 = WeakModularFormsRing(group=3)(x/(x^3-y^2)-y/(x^3-y^2)) sage: el2.analytic_type() weakly holomorphic modular """ Element = AnalyticTypeElement @staticmethod def __classcall__(cls): r""" Directly return the classcall of UniqueRepresentation (skipping the classcalls of the other superclasses). That's because ``self`` is supposed to be used as a Singleton. It initializes the FinitelatticePoset with the proper arguments by itself in ``self.__init__()``. EXAMPLES:: sage: AT = AnalyticType() sage: AT2 = AnalyticType() sage: AT == AT2 True """ return super(FinitePoset, cls).__classcall__(cls) def __init__(self): r""" Container for all possible analytic types of forms and/or spaces. This class is supposed to be used as a Singleton. It first creates a ``Poset`` that contains all basic analytic properties to be modeled by the AnalyticType. Then the order ideals lattice of that Poset is taken as the underlying FiniteLatticePoset of ``self``. In particular elements of ``self`` describe what basic analytic properties are contained/included in that element. EXAMPLES:: sage: AT = AnalyticType() sage: AT Analytic Type sage: isinstance(AT, FiniteLatticePoset) True sage: AT.is_lattice() True sage: AT.is_finite() True sage: AT.cardinality() 10 sage: AT.is_modular() True sage: AT.is_bounded() True sage: AT.is_distributive() True sage: AT.list() [zero, zero, cuspidal, modular, weakly holomorphic modular, quasi cuspidal, quasi modular, quasi weakly holomorphic modular, meromorphic modular, quasi meromorphic modular] sage: len(AT.relations()) 45 sage: AT.cover_relations() [[zero, zero], [zero, cuspidal], [zero, quasi cuspidal], [cuspidal, modular], [cuspidal, quasi cuspidal], [modular, weakly holomorphic modular], [modular, quasi modular], [weakly holomorphic modular, quasi weakly holomorphic modular], [weakly holomorphic modular, meromorphic modular], [quasi cuspidal, quasi modular], [quasi modular, quasi weakly holomorphic modular], [quasi weakly holomorphic modular, quasi meromorphic modular], [meromorphic modular, quasi meromorphic modular]] sage: AT.has_top() True sage: AT.has_bottom() True sage: AT.top() quasi meromorphic modular sage: AT.bottom() zero """ # We (arbitrarily) choose to model by inclusion instead of restriction P_elements = [ "cusp", "holo", "weak", "mero", "quasi"] P_relations = [["cusp", "holo"], ["holo", "weak"], ["weak", "mero"]] self._base_poset = Poset([P_elements, P_relations], cover_relations=True, facade=False) L = self._base_poset.order_ideals_lattice() L = FiniteLatticePoset(L, facade=False) FiniteLatticePoset.__init__(self, hasse_diagram=L._hasse_diagram, elements=L._elements, category=L.category(), facade=L._is_facade, key=None) def _repr_(self): r""" Return the string representation of ``self``. EXAMPLES:: sage: AnalyticType() Analytic Type """ return "Analytic Type" def __call__(self, *args, **kwargs): r""" Return the result of the corresponding call function of ``FiniteLatticePoset``. If more than one argument is given it is called with the list of those arguments instead. EXAMPLES:: sage: AT = AnalyticType() sage: AT("holo", "quasi") == AT(["holo", "quasi"]) True """ if len(args)>1: return super(AnalyticType,self).__call__([arg for arg in args], **kwargs) else: return super(AnalyticType,self).__call__(*args, **kwargs) def _element_constructor_(self, element): r""" Return ``element`` coerced into an element of ``self``. INPUT: - ``element`` - Either something which coerces in the ``FiniteLatticePoset`` of ``self`` or a string or a list of strings of basic properties that should be contained in the new element. OUTPUT: An element of ``self`` corresponding to ``element`` (resp. containing all specified basic analytic properties). EXAMPLES:: sage: AT = AnalyticType() sage: AT("holo") == AT(["holo"]) True sage: el = AT(["quasi", "holo"]) sage: el quasi modular sage: el == AT(("holo", "quasi")) True sage: el.parent() == AT True sage: isinstance(el, AnalyticTypeElement) True sage: el.element {holo, cusp, quasi} """ if type(element)==str: element=[element] if isinstance(element,list) or isinstance(element,tuple): element = Set(self._base_poset.order_ideal([self._base_poset(s) for s in element])) return super(AnalyticType, self)._element_constructor_(element) #res = self.first() #for element in args: # if type(element)==str: # element=[element] # if isinstance(element,list) or isinstance(element,tuple): # element = Set(self._base_poset.order_ideal([self._base_poset(s) for s in element])) # element = super(AnalyticType,self)._element_constructor_(element) # res += element #return res def base_poset(self): r""" Return the base poset from which everything of ``self`` was constructed. Elements of the base poset correspond to the basic ``analytic properties``. EXAMPLES:: sage: AT = AnalyticType() sage: P = AT.base_poset() sage: P Finite poset containing 5 elements sage: isinstance(P, FinitePoset) True sage: P.is_lattice() False sage: P.is_finite() True sage: P.cardinality() 5 sage: P.is_bounded() False sage: P.list() [quasi, cusp, holo, weak, mero] sage: len(P.relations()) 11 sage: P.cover_relations() [[cusp, holo], [holo, weak], [weak, mero]] sage: P.has_top() False sage: P.has_bottom() False """ return self._base_poset def lattice_poset(self): r""" Return the underlying lattice poset of ``self``. EXAMPLES:: sage: AnalyticType().lattice_poset() Finite lattice containing 10 elements """ return FiniteLatticePoset(self._base_poset.order_ideals_lattice(), facade=False)
def RandomPoset(n, p): r""" Generate a random poset on ``n`` vertices according to a probability ``p``. INPUT: - ``n`` - number of vertices, a non-negative integer - ``p`` - a probability, a real number between 0 and 1 (inclusive) OUTPUT: A poset on ``n`` vertices. The construction decides to make an ordered pair of vertices comparable in the poset with probability ``p``, however a pair is not made comparable if it would violate the defining properties of a poset, such as transitivity. So in practice, once the probability exceeds a small number the generated posets may be very similar to a chain. So to create interesting examples, keep the probability small, perhaps on the order of `1/n`. EXAMPLES:: sage: Posets.RandomPoset(17,.15) Finite poset containing 17 elements TESTS:: sage: Posets.RandomPoset('junk', 0.5) Traceback (most recent call last): ... TypeError: number of elements must be an integer, not junk sage: Posets.RandomPoset(-6, 0.5) Traceback (most recent call last): ... ValueError: number of elements must be non-negative, not -6 sage: Posets.RandomPoset(6, 'garbage') Traceback (most recent call last): ... TypeError: probability must be a real number, not garbage sage: Posets.RandomPoset(6, -0.5) Traceback (most recent call last): ... ValueError: probability must be between 0 and 1, not -0.5 """ try: n = Integer(n) except TypeError: raise TypeError( "number of elements must be an integer, not {0}".format(n)) if n < 0: raise ValueError( "number of elements must be non-negative, not {0}".format(n)) try: p = float(p) except Exception: raise TypeError( "probability must be a real number, not {0}".format(p)) if p < 0 or p > 1: raise ValueError( "probability must be between 0 and 1, not {0}".format(p)) D = DiGraph(loops=False, multiedges=False) D.add_vertices(range(n)) for i in range(n): for j in range(n): if random.random() < p: D.add_edge(i, j) if not D.is_directed_acyclic(): D.delete_edge(i, j) return Poset(D, cover_relations=False)
def weak_poset(self, side="right", facade=False): """ INPUT: - ``side`` -- "left", "right", or "twosided" (default: "right") - ``facade`` -- a boolean (default: ``False``) Returns the left (resp. right) poset for weak order. In this poset, `u` is smaller than `v` if some reduced word of `u` is a right (resp. left) factor of some reduced word of `v`. EXAMPLES:: sage: W = WeylGroup(["A", 2]) sage: P = W.weak_poset() sage: P Finite lattice containing 6 elements sage: P.show() This poset is in fact a lattice:: sage: W = WeylGroup(["B", 3]) sage: P = W.weak_poset(side = "left") sage: P.is_lattice() True so this method has an alias :meth:`weak_lattice`:: sage: W.weak_lattice(side = "left") is W.weak_poset(side = "left") True As a bonus feature, one can create the left-right weak poset:: sage: W = WeylGroup(["A",2]) sage: P = W.weak_poset(side = "twosided") sage: P.show() sage: len(P.hasse_diagram().edges()) 8 This is the transitive closure of the union of left and right order. In this poset, `u` is smaller than `v` if some reduced word of `u` is a factor of some reduced word of `v`. Note that this is not a lattice:: sage: P.is_lattice() False By default, the elements of `P` are aware of that they belong to `P`:: sage: P.an_element().parent() Finite poset containing 6 elements If instead one wants the elements to be plain elements of the Coxeter group, one can use the ``facade`` option:: sage: P = W.weak_poset(facade = True) sage: P.an_element().parent() Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) .. see also:: :func:`Poset` for more on posets and facade posets. TESTS:: sage: [len(WeylGroup(["A", n]).weak_poset(side = "right").cover_relations()) for n in [1,2,3]] [1, 6, 36] sage: [len(WeylGroup(["A", n]).weak_poset(side = "left" ).cover_relations()) for n in [1,2,3]] [1, 6, 36] .. todo:: - Use the symmetric group in the examples (for nicer output), and print the edges for a stronger test. - The constructed poset should be lazy, in order to handle large / infinite Coxeter groups. """ from sage.combinat.posets.posets import Poset from sage.combinat.posets.lattices import LatticePoset if side == "twosided": covers = tuple([u, v] for u in self for v in u.upper_covers(side="left") + u.upper_covers(side="right")) return Poset((self, covers), cover_relations=True, facade=facade) else: covers = tuple([u, v] for u in self for v in u.upper_covers(side=side)) return LatticePoset((self, covers), cover_relations=True, facade=facade)