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.misc 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 type(res2) != type((1, 2)) 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)