def lattice_poset(self): r""" Return the underlying lattice poset of ``self``. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.analytic_type import AnalyticType sage: AnalyticType().lattice_poset() Finite lattice containing 10 elements """ return FiniteLatticePoset(self._base_poset.order_ideals_lattice(), facade=False)
def subsets_lattice(self): """ Return the lattice of subsets ordered by containment. EXAMPLES:: sage: X = Set([1,2,3]) sage: X.subsets_lattice() Finite lattice containing 8 elements sage: Y = Set() sage: Y.subsets_lattice() Finite lattice containing 1 elements """ if not self.is_finite(): raise NotImplementedError( "this method is only implemented for finite sets") from sage.combinat.posets.lattices import FiniteLatticePoset from sage.graphs.graph import DiGraph from sage.rings.integer import Integer n = self.cardinality() # list, contains at position 0 <= i < 2^n # the i-th subset of self subset_of_index = [ Set([self[i] for i in range(n) if v & (1 << i)]) for v in range(2**n) ] # list, contains at position 0 <= i < 2^n # the list of indices of all immediate supersets upper_covers = [[ Integer(x | (1 << y)) for y in range(n) if not x & (1 << y) ] for x in range(2**n)] # DiGraph, every subset points to all immediate supersets D = DiGraph({ subset_of_index[v]: [subset_of_index[w] for w in upper_covers[v]] for v in range(2**n) }) # Lattice poset, defined by hasse diagram D L = FiniteLatticePoset(hasse_diagram=D) return L
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 __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: from sage.modular.modform_hecketriangle.analytic_type import AnalyticType sage: from sage.combinat.posets.lattices import FiniteLatticePoset 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, cuspidal, zero, modular, weakly holomorphic modular, meromorphic modular, quasi cuspidal, quasi modular, quasi weakly holomorphic modular, quasi meromorphic modular] sage: len(AT.relations()) 45 sage: AT.cover_relations() [[zero, cuspidal], [zero, zero], [cuspidal, modular], [cuspidal, quasi cuspidal], [zero, quasi cuspidal], [modular, weakly holomorphic modular], [modular, quasi modular], [weakly holomorphic modular, meromorphic modular], [weakly holomorphic modular, quasi weakly holomorphic modular], [meromorphic modular, quasi meromorphic modular], [quasi cuspidal, quasi modular], [quasi modular, quasi weakly holomorphic modular], [quasi weakly holomorphic 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, linear_extension=True, facade=False) L = self._base_poset.order_ideals_lattice() H = L._hasse_diagram.relabel({i: x for i, x in enumerate(L._elements)}, inplace=False) FiniteLatticePoset.__init__(self, hasse_diagram=H, elements=L._elements, category=L.category(), facade=False, key=None)
def lattice_from_incidences(atom_to_coatoms, coatom_to_atoms, face_constructor=None, required_atoms=None, key=None, **kwds): r""" Compute an atomic and coatomic lattice from the incidence between atoms and coatoms. INPUT: - ``atom_to_coatoms`` -- list, ``atom_to_coatom[i]`` should list all coatoms over the ``i``-th atom; - ``coatom_to_atoms`` -- list, ``coatom_to_atom[i]`` should list all atoms under the ``i``-th coatom; - ``face_constructor`` -- function or class taking as the first two arguments sorted :class:`tuple` of integers and any keyword arguments. It will be called to construct a face over atoms passed as the first argument and under coatoms passed as the second argument. Default implementation will just return these two tuples as a tuple; - ``required_atoms`` -- list of atoms (default:None). Each non-empty "face" requires at least one of the specified atoms present. Used to ensure that each face has a vertex. - ``key`` -- any hashable value (default: None). It is passed down to :class:`~sage.combinat.posets.posets.FinitePoset`. - all other keyword arguments will be passed to ``face_constructor`` on each call. OUTPUT: - :class:`finite poset <sage.combinat.posets.posets.FinitePoset>` with elements constructed by ``face_constructor``. .. NOTE:: In addition to the specified partial order, finite posets in Sage have internal total linear order of elements which extends the partial one. This function will try to make this internal order to start with the bottom and atoms in the order corresponding to ``atom_to_coatoms`` and to finish with coatoms in the order corresponding to ``coatom_to_atoms`` and the top. This may not be possible if atoms and coatoms are the same, in which case the preference is given to the first list. ALGORITHM: The detailed description of the used algorithm is given in [KP2002]_. The code of this function follows the pseudo-code description in the section 2.5 of the paper, although it is mostly based on frozen sets instead of sorted lists - this makes the implementation easier and should not cost a big performance penalty. (If one wants to make this function faster, it should be probably written in Cython.) While the title of the paper mentions only polytopes, the algorithm (and the implementation provided here) is applicable to any atomic and coatomic lattice if both incidences are given, see Section 3.4. In particular, this function can be used for strictly convex cones and complete fans. REFERENCES: [KP2002]_ AUTHORS: - Andrey Novoseltsev (2010-05-13) with thanks to Marshall Hampton for the reference. EXAMPLES: Let us construct the lattice of subsets of {0, 1, 2}. Our atoms are {0}, {1}, and {2}, while our coatoms are {0,1}, {0,2}, and {1,2}. Then incidences are :: sage: atom_to_coatoms = [(0,1), (0,2), (1,2)] sage: coatom_to_atoms = [(0,1), (0,2), (1,2)] and we can compute the lattice as :: sage: from sage.geometry.cone import lattice_from_incidences sage: L = lattice_from_incidences( ....: atom_to_coatoms, coatom_to_atoms) sage: L Finite lattice containing 8 elements with distinguished linear extension sage: for level in L.level_sets(): print(level) [((), (0, 1, 2))] [((0,), (0, 1)), ((1,), (0, 2)), ((2,), (1, 2))] [((0, 1), (0,)), ((0, 2), (1,)), ((1, 2), (2,))] [((0, 1, 2), ())] For more involved examples see the *source code* of :meth:`sage.geometry.cone.ConvexRationalPolyhedralCone.face_lattice` and :meth:`sage.geometry.fan.RationalPolyhedralFan._compute_cone_lattice`. """ def default_face_constructor(atoms, coatoms, **kwds): return (atoms, coatoms) if face_constructor is None: face_constructor = default_face_constructor atom_to_coatoms = [frozenset(atc) for atc in atom_to_coatoms] A = frozenset(range(len(atom_to_coatoms))) # All atoms coatom_to_atoms = [frozenset(cta) for cta in coatom_to_atoms] C = frozenset(range(len(coatom_to_atoms))) # All coatoms # Comments with numbers correspond to steps in Section 2.5 of the article L = DiGraph(1) # 3: initialize L faces = {} atoms = frozenset() coatoms = C faces[atoms, coatoms] = 0 next_index = 1 Q = [(atoms, coatoms)] # 4: initialize Q with the empty face while Q: # 5 q_atoms, q_coatoms = Q.pop() # 6: remove some q from Q q = faces[q_atoms, q_coatoms] # 7: compute H = {closure(q+atom) : atom not in atoms of q} H = {} candidates = set(A.difference(q_atoms)) for atom in candidates: coatoms = q_coatoms.intersection(atom_to_coatoms[atom]) atoms = A for coatom in coatoms: atoms = atoms.intersection(coatom_to_atoms[coatom]) H[atom] = (atoms, coatoms) # 8: compute the set G of minimal sets in H minimals = set([]) while candidates: candidate = candidates.pop() atoms = H[candidate][0] if atoms.isdisjoint(candidates) and atoms.isdisjoint(minimals): minimals.add(candidate) # Now G == {H[atom] : atom in minimals} for atom in minimals: # 9: for g in G: g_atoms, g_coatoms = H[atom] if required_atoms is not None: if g_atoms.isdisjoint(required_atoms): continue if (g_atoms, g_coatoms) in faces: g = faces[g_atoms, g_coatoms] else: # 11: if g was newly created g = next_index faces[g_atoms, g_coatoms] = g next_index += 1 Q.append((g_atoms, g_coatoms)) # 12 L.add_edge(q, g) # 14 # End of algorithm, now construct a FiniteLatticePoset. # In principle, it is recommended to use Poset or in this case perhaps # even LatticePoset, but it seems to take several times more time # than the above computation, makes unnecessary copies, and crashes. # So for now we will mimic the relevant code from Poset. # Enumeration of graph vertices must be a linear extension of the poset new_order = L.topological_sort() # Make sure that coatoms are in the end in proper order tail = [ faces[atomes, frozenset([coatom])] for coatom, atomes in enumerate(coatom_to_atoms) ] tail.append(faces[A, frozenset()]) new_order = [n for n in new_order if n not in tail] + tail # Make sure that atoms are in the beginning in proper order head = [0] # We know that the empty face has index 0 head.extend(faces[frozenset([atom]), coatoms] for atom, coatoms in enumerate(atom_to_coatoms) if required_atoms is None or atom in required_atoms) new_order = head + [n for n in new_order if n not in head] # "Invert" this list to a dictionary labels = {} for new, old in enumerate(new_order): labels[old] = new L.relabel(labels) # Construct the actual poset elements elements = [None] * next_index for face, index in faces.items(): atoms, coatoms = face elements[labels[index]] = face_constructor(tuple(sorted(atoms)), tuple(sorted(coatoms)), **kwds) D = {i: f for i, f in enumerate(elements)} L.relabel(D) return FiniteLatticePoset(L, elements, key=key)