def argspec(): argspec = sage_getargspec(func) args = ((argspec.args if not argspec.args is None else []) + list(self.options)) defaults = (argspec.defaults or ()) + tuple(self.options.values()) # Note: argspec.defaults is not always a tuple for some reason return ArgSpec(args, argspec.varargs, argspec.keywords, defaults)
def __init__(self, dep_var, indep_vars): """ INPUT: - ``dep_var`` - The dependent variable (the function value will be substituted for this). - ``indep_vars`` - A list of independent variables (the parameters will be substituted for these). TESTS: Because the base :class:`_Coordinates` class automatically checks the initializing variables with the transform method, :class:`_Coordinates` cannot be instantiated by itself. We test a subclass. sage: from sage.plot.plot3d.plot3d import _ArbitraryCoordinates as arb sage: x,y,z=var('x,y,z') sage: arb((x+z,y*z,z), z, (x,y)) Arbitrary Coordinates coordinate transform (z in terms of x, y) """ all_vars = sage_getargspec(self.transform).args[1:] if set(all_vars) != set(indep_vars + [dep_var]): raise ValueError('variables were specified incorrectly for this coordinate system; incorrect variables were %s'%list(set(all_vars).symmetric_difference(set(indep_vars+[dep_var])))) self.dep_var = dep_var self.indep_vars = indep_vars
def argspec(): from sageinspect import sage_getargspec argspec = sage_getargspec(func) args = (argspec.args if not argspec.args is None else []) + self.options.keys() defaults = tuple(argspec.defaults if not argspec.defaults is None else ()) \ + tuple(self.options.values()) #Note: argspec.defaults is not always a tuple for some reason return ArgSpec(args, argspec.varargs, argspec.keywords, defaults)
def f(wrapper): update_wrapper(wrapper, wrapped, assigned=assigned, updated=updated) wrapper._sage_src_ = lambda: sage_getsource(wrapped) wrapper._sage_src_lines_ = lambda: sage_getsourcelines(wrapped) #Getting the signature right in documentation by Sphinx (Trac 9976) #The attribute _sage_argspec_() is read by Sphinx if present and used #as the argspec of the function instead of using reflection. wrapper._sage_argspec_ = lambda: sage_getargspec(wrapped) return wrapper
def _explain_constructor(cl): r""" Internal function for use error messages when constructing encoders and decoders. EXAMPLES:: sage: from sage.coding.linear_code import LinearCodeSyndromeDecoder sage: from sage.coding.abstract_code import _explain_constructor sage: cl = LinearCodeSyndromeDecoder sage: _explain_constructor(cl) "The constructor requires no arguments.\nIt takes the optional arguments ['maximum_error_weight'].\nSee the documentation of sage.coding.linear_code.LinearCodeSyndromeDecoder for more details." sage: from sage.coding.information_set_decoder import LinearCodeInformationSetDecoder sage: cl = LinearCodeInformationSetDecoder sage: _explain_constructor(cl) "The constructor requires the arguments ['number_errors'].\nIt takes the optional arguments ['algorithm'].\nIt accepts unspecified arguments as well.\nSee the documentation of sage.coding.information_set_decoder.LinearCodeInformationSetDecoder for more details." """ if inspect.isclass(cl): argspec = sage_getargspec(cl.__init__) skip = 2 # skip the self and code arguments else: # Not a class, assume it's a factory function posing as a class argspec = sage_getargspec(cl) skip = 1 # skip code argument if argspec.defaults: args = argspec.args[skip:-len(argspec.defaults)] kwargs = argspec.args[-len(argspec.defaults):] opts = "It takes the optional arguments {}.".format(kwargs) else: args = argspec.args[skip:] opts = "It takes no optional arguments." if args: reqs = "The constructor requires the arguments {}.".format(args) else: reqs = "The constructor requires no arguments." if argspec.varargs or argspec.keywords: var = "It accepts unspecified arguments as well.\n" else: var = "" return("{}\n{}\n{}See the documentation of {}.{} for more details."\ .format(reqs, opts, var, cl.__module__, cl.__name__))
def argspec(): argspec = sage_getargspec(func) def listForNone(l): return l if not l is None else [] newArgs = [self.name + opt for opt in self.options.keys()] args = (argspec.args if not argspec.args is None else []) + newArgs defaults = (argspec.defaults if not argspec.defaults is None else ()) \ + tuple(self.options.values()) #Note: argspec.defaults is not always a tuple for some reason return ArgSpec(args, argspec.varargs, argspec.keywords, defaults)
def format_args(self): # for classes, the relevant signature is the __init__ method's initmeth = self.get_attr(self.object, '__init__', None) # classes without __init__ method, default __init__ or # __init__ written in C? if initmeth is None or initmeth is object.__init__ or not \ (inspect.ismethod(initmeth) or inspect.isfunction(initmeth)): return None argspec = sage_getargspec(initmeth) if argspec[0] and argspec[0][0] in ('cls', 'self'): del argspec[0][0] return inspect.formatargspec(*argspec)
def f(wrapper, assigned=assigned, updated=updated): update_wrapper(wrapper, wrapped, assigned=assigned, updated=updated) # For backwards-compatibility with old versions of sage_wraps wrapper.f = wrapped # For forwards-compatibility with functools.wraps on Python 3 wrapper.__wrapped__ = wrapped wrapper._sage_src_ = lambda: sage_getsource(wrapped) wrapper._sage_src_lines_ = lambda: sage_getsourcelines(wrapped) #Getting the signature right in documentation by Sphinx (Trac 9976) #The attribute _sage_argspec_() is read by Sphinx if present and used #as the argspec of the function instead of using reflection. wrapper._sage_argspec_ = lambda: sage_getargspec(wrapped) return wrapper
def _sage_argspec_(self): """ Return the argument specification of the wrapped function or method. TESTS:: sage: from sage.misc.sageinspect import sage_getargspec sage: from sage.sets.set_from_iterator import Decorator sage: d = Decorator() sage: d.f = find_local_minimum sage: sage_getargspec(d) # indirect doctest ArgSpec(args=['f', 'a', 'b', 'tol', 'maxfun'], varargs=None, keywords=None, defaults=(1.48e-08, 500)) """ from sage.misc.sageinspect import sage_getargspec return sage_getargspec(self.f)
def args_on_obj(self, obj): if hasattr(obj, "_sage_argspec_"): argspec = obj._sage_argspec_() elif inspect.isbuiltin(obj) or inspect.ismethoddescriptor(obj): # can never get arguments of a C function or method unless # a function to do so is supplied if self.env.config.autodoc_builtin_argspec: argspec = self.env.config.autodoc_builtin_argspec(obj) else: return None else: # The check above misses ordinary Python methods in Cython # files. argspec = sage_getargspec(obj) if argspec is not None and argspec[0] and argspec[0][0] in ('cls', 'self'): del argspec[0][0] return argspec
def args_on_obj(obj): if hasattr(obj, "_sage_argspec_"): argspec = obj._sage_argspec_() elif inspect.isbuiltin(obj) or inspect.ismethoddescriptor(obj): # can never get arguments of a C function or method unless # a function to do so is supplied if self.env.config.autodoc_builtin_argspec: argspec = self.env.config.autodoc_builtin_argspec(obj) else: return None else: # The check above misses ordinary Python methods in Cython # files. argspec = sage_getargspec(obj) #inspect.getargspec(obj) #if isclassinstance(obj) or inspect.isclass(obj): if argspec is not None and argspec[0] and argspec[0][0] in ('cls', 'self'): del argspec[0][0] return argspec
def _find_arguments_for_callable(func): """ Find the names of arguments (that do not have default values) for a callable function, taking care of several special cases in Sage. If the parameters cannot be found, then return ``[]``. EXAMPLES:: sage: from sage.plot.plot3d.plot3d import _find_arguments_for_callable sage: _find_arguments_for_callable(lambda x,y: x+y) ['x', 'y'] sage: def f(a,b,c): return a+b+c sage: _find_arguments_for_callable(f) ['a', 'b', 'c'] sage: _find_arguments_for_callable(lambda x,y,z=2: x+y+z) ['x', 'y'] sage: def f(a,b,c,d=2,e=1): return a+b+c+d+e sage: _find_arguments_for_callable(f) ['a', 'b', 'c'] sage: g(w,r,t)=w+r+t sage: _find_arguments_for_callable(g) ['w', 'r', 't'] sage: a,b = var('a,b') sage: _find_arguments_for_callable(a+b) ['a', 'b'] sage: _find_arguments_for_callable(operator.add) [] """ if inspect.isfunction(func): pass elif hasattr(func, 'arguments'): # Might be a symbolic function with arguments return [repr(s) for s in func.arguments()] else: func = func.__call__ f_args = sage_getargspec(func) if f_args.defaults is None: params = f_args.args else: params = f_args.args[:-len(f_args.defaults)] return params
def _sage_argspec_(self): """ Returns the argument specification for this object, which is just the argument specification for the underlying function. See :module:`sage.misc.sageinspect` for more information on this convention. EXAMPLES:: sage: from sage.parallel.decorate import Parallel sage: p = Parallel(2) sage: def f(x, y): ....: return x + y sage: from sage.misc.sageinspect import sage_getargspec sage: sage_getargspec(p(f)) ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=None) """ from sage.misc.sageinspect import sage_getargspec return sage_getargspec(self.func)
def _sage_argspec_(self): """ Returns the argument specification for this object, which is just the argument specification for the underlying function. See :module:`sage.misc.sageinspect` for more information on this convention. EXAMPLES:: sage: from sage.parallel.decorate import Parallel sage: p = Parallel(2) sage: def f(x, y): ... return x + y sage: from sage.misc.sageinspect import sage_getargspec sage: sage_getargspec(p(f)) ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=None) """ from sage.misc.sageinspect import sage_getargspec return sage_getargspec(self.func)
def args_on_obj(obj): if hasattr(obj, "_sage_argspec_"): return obj._sage_argspec_() if inspect.isbuiltin(obj) or \ inspect.ismethoddescriptor(obj): # can never get arguments of a C function or method unless # a function to do so is supplied if self.env.config.autodoc_builtin_argspec: argspec = self.env.config.autodoc_builtin_argspec(obj) return argspec else: return None argspec = sage_getargspec(obj) #inspect.getargspec(obj) if isclassinstance(obj) or inspect.isclass(obj): # if a class should be documented as function, we try # to use the constructor signature as function # signature without the first argument. if argspec is not None and argspec[0]: del argspec[0][0] return argspec
def harvest_function(self, method, semantic={}, store=True): """ Harvest metadata about a single function/method, including stuff in `semantic` INPUT: - ``store`` -- a boolean (default: True): whether to store the harvested information, or just return it Storing is meant for global functions, non storing for methods of classes whose data will be stored in the class EXAMPLES:: sage: def f(x,y): pass sage: Exporter().harvest_method(f, {"gap":"coucou"}, store=False) {'__doc__': None, 'args': ['x', 'y'], 'argspec': ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=None), 'gap': 'coucou', 'name': 'f'} """ if isinstance(method, AbstractMethod): method = method._f try: argspec = sage_getargspec(method) result = { "__doc__": method.__doc__, "args": argspec.args, "argspec": argspec # TODO: add code } except TypeError: result = {} result.update(semantic) if store: result['name'] = class_name(method) self._database['functions'][result['name']] = result return result
def __classcall__(cls, constructor=None, default_values=None, names=None, ignore_special_args=('cls', 'self'), option_only_args=('conditioncheck', 'field', 'merge', 'condition_according_to_literature')): # For classes, sage_getargspec uses the argspec of __call__, which is not useful for us. if isinstance(constructor, ParametricFamily_base): if default_values is None and names is None: return constructor arg_default_dict = copy(constructor.default_values()) args = constructor.names() cls = constructor._reduction[0] # FIXME else: if constructor is None: c = cls._construct_function else: c = constructor args, varargs, keywords, defaults = sage_getargspec(c) #import pdb; pdb.set_trace() args = [ name for name in args if name not in ignore_special_args ] # cls and self do not appear in the default list, remove them first if defaults: arg_default_dict = OrderedDict(zip(args, defaults)) else: arg_default_dict = OrderedDict.fromkeys(args) if default_values is not None: default_values = dict(default_values) arg_default_dict.update(default_values) if names is None: names = [name for name in args if name not in option_only_args] arg_default_dict = tuple( (name, value) for name, value in arg_default_dict.items()) return super(ParametricFamily, cls).__classcall__(cls, constructor, arg_default_dict, tuple(names))
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.misc 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 type(res) != type((1, 2)) 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 len(L_.complements(b)) > 0: 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")