def cartesian_projection(self, i): """ Return the natural projection onto the `i`-th Cartesian factor of ``self`` as per :meth:`Sets.CartesianProducts.ParentMethods.cartesian_projection() <sage.categories.sets_cat.Sets.CartesianProducts.ParentMethods.cartesian_projection>`. INPUT: - ``i`` -- the index of a Cartesian factor of ``self`` EXAMPLES:: sage: C = Sets().CartesianProducts().example(); C The Cartesian product of (Set of prime numbers (basic implementation), An example of an infinite enumerated set: the non negative integers, An example of a finite enumerated set: {1,2,3}) sage: x = C.an_element(); x (47, 42, 1) sage: pi = C.cartesian_projection(1) sage: pi(x) 42 sage: C.cartesian_projection('hey') Traceback (most recent call last): ... ValueError: i (=hey) must be in {0, 1, 2} """ if i not in self._sets_keys(): raise ValueError("i (={}) must be in {}".format(i, self._sets_keys())) return attrcall("cartesian_projection", i)
def test_attrcall(name, L): """ Return a function by name. This is a helper function for test_finite_lattice(). This will unify all Boolean-valued functions to a function without parameters. EXAMPLES:: sage: from sage.tests.finite_poset import test_attrcall sage: N5 = posets.PentagonPoset() sage: N5.is_modular() == test_attrcall('is_modular', N5) True sage: N5.is_constructible_by_doublings('convex') == test_attrcall('is_doubling_convex', N5) True """ if name == 'is_doubling_any': return L.is_constructible_by_doublings('any') if name == 'is_doubling_lower': return L.is_constructible_by_doublings('upper') if name == 'is_doubling_upper': return L.is_constructible_by_doublings('lower') if name == 'is_doubling_convex': return L.is_constructible_by_doublings('convex') if name == 'is_doubling_interval': return L.is_constructible_by_doublings('interval') if name == 'is_uniq_orthocomplemented': return L.is_orthocomplemented(unique=True) return attrcall(name)(L)
def __reduce__(self): """ TESTS:: sage: CartanType(['F', 4, 1]).dual().__reduce__() (*.dual(), (['F', 4, 1],)) """ return (attrcall("dual"), (self._type, ))
def j_classes_of_idempotents(self): r""" Returns all the idempotents of self, grouped by J-class. OUTPUT: a list of lists. EXAMPLES:: sage: S = FiniteSemigroups().example(alphabet=('a','b', 'c')) sage: sorted(map(sorted, S.j_classes_of_idempotents())) [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']] """ return [ l for l in ([x for x in cl if attrcall('is_idempotent')(x)] for cl in self.j_classes()) if len(l) > 0 ]
def test_finite_poset(P): """ Test several functions on a given finite poset. The function contains tests of different kinds, for example - Numerical properties jump number, dimension etc. can't be a bigger in a subposet with one element less. - "Dual tests", for example the dual of meet-semilattice must be a join-semilattice. - Random tries: for example if the dimension of a poset is `k`, then it can't be the intersection of `k-1` random linear extensions. EXAMPLES:: sage: from sage.tests.finite_poset import test_finite_poset sage: P = posets.RandomPoset(10, 0.15) sage: test_finite_poset(P) is None # Long time True """ from sage.combinat.posets.posets import Poset from sage.combinat.subset import Subsets from sage.misc.prandom import shuffle from sage.misc.call import attrcall e = P.random_element() P_one_less = P.subposet([x for x in P if x != e]) # Cardinality if len(P) != P.cardinality(): raise ValueError("error 1 in cardinality") if P.cardinality() - 1 != P_one_less.cardinality(): raise ValueError("error 5 in cardinality") # Height h1 = P.height() h2, chain = P.height(certificate=True) if h1 != h2: raise ValueError("error 1 in height") if h1 != len(chain): raise ValueError("error 2 in height") if not P.is_chain_of_poset(chain): raise ValueError("error 3 in height") if len(P.random_maximal_chain()) > h1: raise ValueError("error 4 in height") if h1 - P_one_less.height() not in [0, 1]: raise ValueError("error 5 in height") # Width w1 = P.width() w2, antichain = P.width(certificate=True) if w1 != w2: raise ValueError("error 1 in width") if w1 != len(antichain): raise ValueError("error 2 in width") if not P.is_antichain_of_poset(antichain): raise ValueError("error 3 in width") if len(P.random_maximal_antichain()) > w1: raise ValueError("error 4 in width") if w1 - P_one_less.width() not in [0, 1]: raise ValueError("error 5 in width") # Dimension dim1 = P.dimension() dim2, linexts = P.dimension(certificate=True) if dim1 != dim2: raise ValueError("error 1 in dimension") if dim1 != len(linexts): raise ValueError("error 2 in dimension") P_ = Poset((P.list(), lambda a, b: all( linext.index(a) < linext.index(b) for linext in linexts))) if P_ != Poset(P.hasse_diagram()): raise ValueError("error 3 in dimension") x = [P.random_linear_extension() for _ in range(dim1 - 1)] P_ = Poset( (P.list(), lambda a, b: all(linext.index(a) < linext.index(b) for linext in x))) if P_ == Poset(P.hasse_diagram()): raise ValueError("error 4 in dimension") if dim1 - P_one_less.dimension() < 0: raise ValueError("error 5 in dimension") # Jump number j1 = P.jump_number() j2, linext = P.jump_number(certificate=True) if j1 != j2: raise ValueError("error 1 in jump number") if P.linear_extension(linext).jump_count() != j1: raise ValueError("error 2 in jump number") if not P.is_linear_extension(linext): raise ValueError("error 3 in jump number") if P.linear_extension(P.random_linear_extension()).jump_count() < j1: raise ValueError("error 4 in jump number") if j1 - P_one_less.jump_number() not in [0, 1]: raise ValueError("error 5 in jump number") P_dual = P.dual() selfdual_properties = [ 'chain', 'bounded', 'connected', 'graded', 'ranked', 'series_parallel', 'slender', 'lattice' ] for prop in selfdual_properties: f = attrcall('is_' + prop) if f(P) != f(P_dual): raise ValueError("error in self-dual property %s" % prop) if P.is_graded(): if P.is_bounded(): if P.is_eulerian() != P_dual.is_eulerian(): raise ValueError("error in self-dual property eulerian") if P.is_eulerian(): P_ = P.star_product(P) if not P_.is_eulerian(): raise ("error in star product / eulerian") chain1 = P.random_maximal_chain() if len(chain1) != h1: raise ValueError("error in is_graded") if not P.is_ranked(): raise ValueError("error in is_ranked / is_graded") if P.is_meet_semilattice() != P_dual.is_join_semilattice(): raise ValueError("error in meet/join semilattice") if set(P.minimal_elements()) != set(P_dual.maximal_elements()): raise ValueError("error in min/max elements") if P.top() != P_dual.bottom(): raise ValueError("error in top/bottom element") parts = P.connected_components() P_ = Poset() for part in parts: P_ = P_.disjoint_union(part) if not P.is_isomorphic(P_): raise ValueError("error in connected components / disjoint union") parts = P.ordinal_summands() P_ = Poset() for part in parts: P_ = P_.ordinal_sum(part) if not P.is_isomorphic(P_): raise ValueError("error in ordinal summands / ordinal sum") P_ = P.with_bounds().without_bounds() if not P.is_isomorphic(P_): raise ValueError("error in with bounds / without bounds") P_ = P.completion_by_cuts().irreducibles_poset() if not P.has_isomorphic_subposet(P_): raise ValueError("error in completion by cuts / irreducibles poset") P_ = P.subposet(Subsets(P).random_element()) if not P_.is_induced_subposet(P): raise ValueError("error in subposet / is induced subposet") if not P.is_linear_extension(P.random_linear_extension()): raise ValueError("error in is linear extension") x = list(P) shuffle(x) if not P.is_linear_extension(P.sorted(x)): raise ValueError("error in sorted") dil = P.dilworth_decomposition() chain = dil[randint(0, len(dil) - 1)] if not P.is_chain_of_poset(chain): raise ValueError("error in Dilworth decomposition") lev = P.level_sets() level = lev[randint(0, len(lev) - 1)] if not P.is_antichain_of_poset(level): raise ValueError("error in level sets") # certificate=True must return a pair bool_with_cert = [ 'eulerian', 'greedy', 'join_semilattice', 'jump_critical', 'meet_semilattice', 'slender' ] for p in bool_with_cert: try: # some properties are not always defined for all posets res1 = attrcall('is_' + p)(P) except ValueError: continue res2 = attrcall('is_' + p, certificate=True)(P) if not isinstance(res2, tuple) or len(res2) != 2: raise ValueError( "certificate-option does not return a pair in %s" % p) if res1 != res2[0]: raise ValueError("certificate-option changes result in %s" % p)
def test_finite_lattice(L): """ Test several functions on a given finite lattice. The function contains tests of different kinds: - Implications of Boolean properties. Examples: a distributive lattice is modular, a dismantlable and distributive lattice is planar, a simple lattice can not be constructible by Day's doublings. - Dual and self-dual properties. Examples: Dual of a modular lattice is modular, dual of an atomic lattice is co-atomic. - Certificate tests. Example: certificate for a non-complemented lattice must be an element without a complement. - Verification of some property by known property or by a random test. Examples: A lattice is distributive iff join-primes are exactly join-irreducibles and an interval of a relatively complemented lattice is complemented. - Set inclusions. Example: Every co-atom must be meet-irreducible. - And several other tests. Example: The skeleton of a pseudocomplemented lattice must be Boolean. EXAMPLES:: sage: from sage.tests.finite_poset import test_finite_lattice sage: L = posets.RandomLattice(10, 0.98) sage: test_finite_lattice(L) is None # Long time True """ from sage.combinat.posets.lattices import LatticePoset from sage.sets.set import Set from sage.combinat.subset import Subsets from sage.misc.prandom import randint from sage.misc.flatten import flatten from sage.misc.call import attrcall from sage.misc.sageinspect import sage_getargspec if L.cardinality() < 4: # Special cases should be tested in specific TESTS-sections. return None all_props = set(list(implications) + flatten(implications.values())) P = {x: test_attrcall('is_' + x, L) for x in all_props} ### Relations between boolean-valued properties ### # Direct one-property implications for prop1 in implications: if P[prop1]: for prop2 in implications[prop1]: if not P[prop2]: raise ValueError("error: %s should implicate %s" % (prop1, prop2)) # Impossible combinations for p1, p2 in mutually_exclusive: if P[p1] and P[p2]: raise ValueError( "error: %s and %s should be impossible combination" % (p1, p2)) # Two-property implications for p1, p2, p3 in two_to_one: if P[p1] and P[p2] and not P[p3]: raise ValueError("error: %s and %s, so should be %s" % (p1, p2, p3)) Ldual = L.dual() # Selfdual properties for p in selfdual_properties: if P[p] != test_attrcall('is_' + p, Ldual): raise ValueError("selfdual property %s error" % p) # Dual properties and elements for p1, p2 in dual_properties: if P[p1] != test_attrcall('is_' + p2, Ldual): raise ValueError("dual properties error %s" % p1) for e1, e2 in dual_elements: if set(attrcall(e1)(L)) != set(attrcall(e2)(Ldual)): raise ValueError("dual elements error %s" % e1) ### Certificates ### # Return value must be a pair with correct result as first element. for p_ in all_props: # Dirty fix first if p_[:9] == 'doubling_' or p_[:5] == 'uniq_': continue p = "is_" + p_ if 'certificate' in sage_getargspec(getattr(L, p)).args: res = attrcall(p, certificate=True)(L) if not isinstance(res, tuple) or len(res) != 2: raise ValueError( "certificate-option does not return a pair in %s" % p) if P[p_] != res[0]: raise ValueError("certificate-option changes result in %s" % p) # Test for "yes"-certificates if P['supersolvable']: a = L.is_supersolvable(certificate=True)[1] S = Subsets(L).random_element() if L.is_chain_of_poset(S): if not L.sublattice(a + list(S)).is_distributive(): raise ValueError("certificate error in is_supersolvable") if P['dismantlable']: elms = L.is_dismantlable(certificate=True)[1] if len(elms) != L.cardinality(): raise ValueError("certificate error 1 in is_dismantlable") elms = elms[:randint(0, len(elms) - 1)] L_ = L.sublattice([x for x in L if x not in elms]) if L_.cardinality() != L.cardinality() - len(elms): raise ValueError("certificate error 2 in is_dismantlable") if P['vertically_decomposable']: c = L.is_vertically_decomposable(certificate=True)[1] if c == L.bottom() or c == L.top(): raise ValueError( "certificate error 1 in is_vertically_decomposable") e = L.random_element() if L.compare_elements(c, e) is None: raise ValueError( "certificate error 2 in is_vertically_decomposable") # Test for "no"-certificates if not P['atomic']: a = L.is_atomic(certificate=True)[1] if a in L.atoms() or a not in L.join_irreducibles(): raise ValueError("certificate error in is_atomic") if not P['coatomic']: a = L.is_coatomic(certificate=True)[1] if a in L.coatoms() or a not in L.meet_irreducibles(): raise ValueError("certificate error in is_coatomic") if not P['complemented']: a = L.is_complemented(certificate=True)[1] if L.complements(a): raise ValueError("compl. error 1") if not P['sectionally_complemented']: a, b = L.is_sectionally_complemented(certificate=True)[1] L_ = L.sublattice(L.interval(L.bottom(), a)) if L_.is_complemented(): raise ValueError("sec. compl. error 1") if len(L_.complements(b)) > 0: raise ValueError("sec. compl. error 2") if not P['cosectionally_complemented']: a, b = L.is_cosectionally_complemented(certificate=True)[1] L_ = L.sublattice(L.interval(a, L.top())) if L_.is_complemented(): raise ValueError("cosec. compl. error 1") if L_.complements(b): raise ValueError("cosec. compl. error 2") if not P['relatively_complemented']: a, b, c = L.is_relatively_complemented(certificate=True)[1] I = L.interval(a, c) if len(I) != 3 or b not in I: raise ValueError("rel. compl. error 1") if not P['upper_semimodular']: a, b = L.is_upper_semimodular(certificate=True)[1] if not set(L.lower_covers(a)).intersection(set( L.lower_covers(b))) or set(L.upper_covers(a)).intersection( set(L.upper_covers(b))): raise ValueError("certificate error in is_upper_semimodular") if not P['lower_semimodular']: a, b = L.is_lower_semimodular(certificate=True)[1] if set(L.lower_covers(a)).intersection(set( L.lower_covers(b))) or not set(L.upper_covers(a)).intersection( set(L.upper_covers(b))): raise ValueError("certificate error in is_lower_semimodular") if not P['distributive']: x, y, z = L.is_distributive(certificate=True)[1] if L.meet(x, L.join(y, z)) == L.join(L.meet(x, y), L.meet(x, z)): raise ValueError("certificate error in is_distributive") if not P['modular']: x, a, b = L.is_modular(certificate=True)[1] if not L.is_less_than(x, b) or L.join(x, L.meet(a, b)) == L.meet( L.join(x, a), b): raise ValueError("certificate error in is_modular") if not P['pseudocomplemented']: a = L.is_pseudocomplemented(certificate=True)[1] L_ = L.subposet([e for e in L if L.meet(e, a) == L.bottom()]) if L_.has_top(): raise ValueError("certificate error in is_pseudocomplemented") if not P['join_pseudocomplemented']: a = L.is_join_pseudocomplemented(certificate=True)[1] L_ = L.subposet([e for e in L if L.join(e, a) == L.top()]) if L_.has_bottom(): raise ValueError("certificate error in is_join_pseudocomplemented") if not P['join_semidistributive']: e, x, y = L.is_join_semidistributive(certificate=True)[1] if L.join(e, x) != L.join(e, y) or L.join(e, x) == L.join( e, L.meet(x, y)): raise ValueError("certificate error in is_join_semidistributive") if not P['meet_semidistributive']: e, x, y = L.is_meet_semidistributive(certificate=True)[1] if L.meet(e, x) != L.meet(e, y) or L.meet(e, x) == L.meet( e, L.join(x, y)): raise ValueError("certificate error in is_meet_semidistributive") if not P['simple']: c = L.is_simple(certificate=True)[1] if len(L.congruence([c[randint(0, len(c) - 1)]])) == 1: raise ValueError("certificate error in is_simple") if not P['isoform']: c = L.is_isoform(certificate=True)[1] if len(c) == 1: raise ValueError("certificate error in is_isoform") if all( L.subposet(c[i]).is_isomorphic(L.subposet(c[i + 1])) for i in range(len(c) - 1)): raise ValueError("certificate error in is_isoform") if not P['uniform']: c = L.is_uniform(certificate=True)[1] if len(c) == 1: raise ValueError("certificate error in is_uniform") if all(len(c[i]) == len(c[i + 1]) for i in range(len(c) - 1)): raise ValueError("certificate error in is_uniform") if not P['regular']: c = L.is_regular(certificate=True)[1] if len(c[0]) == 1: raise ValueError("certificate error 1 in is_regular") if Set(c[1]) not in c[0]: raise ValueError("certificate error 2 in is_regular") if L.congruence([c[1]]) == c[0]: raise ValueError("certificate error 3 in is_regular") if not P['subdirectly_reducible']: x, y = L.is_subdirectly_reducible(certificate=True)[1] a = L.random_element() b = L.random_element() c = L.congruence([[a, b]]) if len(c) != L.cardinality(): for c_ in c: if x in c_: if y not in c_: raise ValueError( "certificate error 1 in is_subdirectly_reducible") break else: raise ValueError( "certificate error 2 in is_subdirectly_reducible") if not P['join_distributive']: a = L.is_join_distributive(certificate=True)[1] L_ = L.sublattice(L.interval(a, L.join(L.upper_covers(a)))) if L_.is_distributive(): raise ValueError("certificate error in is_join_distributive") if not P['meet_distributive']: a = L.is_meet_distributive(certificate=True)[1] L_ = L.sublattice(L.interval(L.meet(L.lower_covers(a)), a)) if L_.is_distributive(): raise ValueError("certificate error in is_meet_distributive") ### Other ### # Other ways to recognize some boolean property if P['distributive'] != (set(L.join_primes()) == set( L.join_irreducibles())): raise ValueError( "every join-irreducible of a distributive lattice should be join-prime" ) if P['distributive'] != (set(L.meet_primes()) == set( L.meet_irreducibles())): raise ValueError( "every meet-irreducible of a distributive lattice should be meet-prime" ) if P['join_semidistributive'] != all( L.canonical_joinands(e) is not None for e in L): raise ValueError( "every element of join-semidistributive lattice should have canonical joinands" ) if P['meet_semidistributive'] != all( L.canonical_meetands(e) is not None for e in L): raise ValueError( "every element of meet-semidistributive lattice should have canonical meetands" ) # Random verification of a Boolean property if P['relatively_complemented']: a = L.random_element() b = L.random_element() if not L.sublattice(L.interval(a, b)).is_complemented(): raise ValueError("rel. compl. error 3") if P['sectionally_complemented']: a = L.random_element() if not L.sublattice(L.interval(L.bottom(), a)).is_complemented(): raise ValueError("sec. compl. error 3") if P['cosectionally_complemented']: a = L.random_element() if not L.sublattice(L.interval(a, L.top())).is_complemented(): raise ValueError("cosec. compl. error 2") # Element set inclusions for s1, s2 in set_inclusions: if not set(attrcall(s1)(L)).issubset(set(attrcall(s2)(L))): raise ValueError("%s should be a subset of %s" % (s1, s2)) # Sublattice-closed properties L_ = L.sublattice(Subsets(L).random_element()) for p in sublattice_closed: if P[p] and not test_attrcall('is_' + p, L_): raise ValueError("property %s should apply to sublattices" % p) # Some sublattices L_ = L.center() # Center is a Boolean lattice if not L_.is_atomic() or not L_.is_distributive(): raise ValueError("error in center") if P['pseudocomplemented']: L_ = L.skeleton() # Skeleton is a Boolean lattice if not L_.is_atomic() or not L_.is_distributive(): raise ValueError("error in skeleton") L_ = L.frattini_sublattice() S = Subsets(L).random_element() if L.sublattice(S) == L and L.sublattice([e for e in S if e not in L_]) != L: raise ValueError("error in Frattini sublattice") L_ = L.maximal_sublattices() L_ = L_[randint(0, len(L_) - 1)] e = L.random_element() if e not in L_ and L.sublattice(list(L_) + [e]) != L: raise ValueError("error in maximal_sublattices") # Reverse functions: vertical composition and decomposition L_ = reduce(lambda a, b: a.vertical_composition(b), L.vertical_decomposition(), LatticePoset()) if not L.is_isomorphic(L_): raise ValueError("error in vertical [de]composition") # Meet and join a = L.random_element() b = L.random_element() m = L.meet(a, b) j = L.join(a, b) m_ = L.subposet([ e for e in L.principal_lower_set(a) if e in L.principal_lower_set(b) ]).top() j_ = L.subposet([ e for e in L.principal_upper_set(a) if e in L.principal_upper_set(b) ]).bottom() if m != m_ or m != Ldual.join(a, b): raise ValueError("error in meet") if j != j_ or j != Ldual.meet(a, b): raise ValueError("error in join") # Misc misc e = L.neutral_elements() e = e[randint(0, len(e) - 1)] a = L.random_element() b = L.random_element() if not L.sublattice([e, a, b]).is_distributive(): raise ValueError("error in neutral_elements")