def make_labeled_partition(set_or_mset, class_invariant_func): r"""Return a 'labeled' partition of ``set_or_mset``, partitioned according to ``class_invariant_func``. :param set_or_mset: The :term:`set` or :term:`multiset` that is to be partitioned. :param class_invariant_func: A function from elements of ``set_or_mset`` to `MathObject`\s. It defines an :term:`equivalence relation` on ``set_or_mset`` such that .. math:: x, y \in set\_or\_mset : x \equiv y \iff class\_invariant\_func(x) = class\_invariant\_func(y) :return: A :term:`function` with structure :math:`P(range(class\_invariant\_func) \times P(set\_or\_mset.ground\_set))` that maps the range of ``class_invariant_func`` when applied to ``set_or_mset`` to sets of elements of ``set_or_mset`` that belong to the given equivalence class. """ if set_or_mset.is_set: partition_dict = _create_partition_dict_from_set(set_or_mset, class_invariant_func) return _mo.Set((_mo.Couplet(label, _mo.Set(components, direct_load=True) .cache_clan(set_or_mset.cached_clan), direct_load=True) for label, components in partition_dict.items()), direct_load=True) elif set_or_mset.is_multiset: partition_dict = _create_partition_dict_from_multiset(set_or_mset, class_invariant_func) return _mo.Set((_mo.Couplet(label, _mo.Multiset(counter, direct_load=True) .cache_multiclan(set_or_mset.cached_multiclan), direct_load=True) for label, counter in partition_dict.items()), direct_load=True) else: raise AssertionError('First argument must be Set or Multiset')
def _process_nodes(nodes): for node in nodes: if node.nodeType == node.ELEMENT_NODE: # attributes and children are sets of Couplets. attributes = set(_process_attributes(node)) children = set(_process_nodes( node.childNodes)) # May include text (text_left). children = children.union(attributes) if len(children) == 1 and _contains_text_node(children): # We have a single child that is a text node. Remove one layer of couplets. yield _mo.Couplet( left=_util.get_left_cached(node.tagName), right=_misc.get_single_iter_elem(children).right, direct_load=True) else: yield _mo.Couplet(left=_util.get_left_cached(node.tagName), right=_mo.Set(children, direct_load=True), direct_load=True) elif node.nodeType == node.TEXT_NODE: text_node_text = node.data.strip() if len(text_node_text) > 0: yield _mo.Couplet(left=text_left, right=_mo.Atom( _get_atom_value(text_node_text), direct_load=True), direct_load=True) else: assert False # Node type not supported.
def make_triple(subject: '( M )', predicate: '( M )', object_: '( M )') -> 'P(A x M)': """Return an RDF `triple`, created from ``subject``, ``predicate`` and ``object_``. Each of the arguments must be an instance of `MathObject` or a Python type that automatically converts to an :class:`~.Atom` in the :class:`~.Couplet` constructor. """ return _mo.Set([ _mo.Couplet(left='s', right=subject), _mo.Couplet(left='p', right=predicate), _mo.Couplet(left='o', right=object_), ])
def object_hook_f(obj): """``obj`` is a representation of a straightforward translation of JSON into Python. For a known special construct (must be a ``dict``), convert it into its correct object representation and return it. Otherwise return ``obj`` as-is. (May be used as ``object_hook`` function for the various JSON decoder APIs.) """ if len(obj) == 2 and '__cls__' in obj and '__val__' in obj: if obj['__cls__'] == 'builtin.bytes': return bytes(elem for elem in obj['__val__']) if obj['__cls__'] == 'builtin.complex': return complex(obj['__val__']) if obj['__cls__'] == 'builtin.frozenset': return frozenset(decode(elem) for elem in obj['__val__']) if obj['__cls__'] == 'builtin.list': return list(decode(elem) for elem in obj['__val__']) if obj['__cls__'] == 'builtin.range': return range(decode(obj['__val__'][0]), decode(obj['__val__'][1]), decode(obj['__val__'][2])) if obj['__cls__'] == 'builtin.tuple': return tuple(decode(elem) for elem in obj['__val__']) if obj['__cls__'] == 'Atom': return _mo.Atom(decode(obj['__val__']), direct_load=True) if obj['__cls__'] == 'Couplet': return _mo.Couplet(left=decode(obj['__val__'][0]), right=decode(obj['__val__'][1]), direct_load=True) if obj['__cls__'] == 'Set': return _mo.Set((decode(elem) for elem in obj['__val__']), direct_load=True) if obj['__cls__'] == 'Multiset': return _mo.Multiset( {decode(val): mult for val, mult in obj['__val__']}, direct_load=True) return obj
def diag(*args, _checked=True) -> 'P(M x M)': """Return the :term:`diagonal` of the set comprising the elements in ``*args``.""" for element in args: if element is _undef.Undef(): return _undef.make_or_raise_undef(2) rel = _mo.Set((_mo.Couplet(el, direct_load=not _checked) for el in args), direct_load=True) rel.cache_relation(CacheStatus.IS) rel.cache_functional(CacheStatus.IS).cache_right_functional(CacheStatus.IS) rel.cache_reflexive(CacheStatus.IS).cache_symmetric(CacheStatus.IS) return rel
def from_dict(dict1: dict) -> 'PP(M x M)': r"""Return a :term:`clan` with a single :term:`relation` where the :term:`couplet`\s are the elements of ``dict1``.""" rel = _mo.Set((_mo.Couplet(left, right) for left, right in dict1.items()), direct_load=True) rel.cache_relation(_mo.CacheStatus.IS) rel.cache_functional(_mo.CacheStatus.IS) clan = _mo.Set(rel, direct_load=True) clan.cache_clan(_mo.CacheStatus.IS) clan.cache_functional(_mo.CacheStatus.IS) clan.cache_regular(_mo.CacheStatus.IS) return clan
def _process_nodes(nodes): if isinstance(nodes, list): for list_data in nodes: yield _mo.Set(*list(_process_nodes(list_data))) else: for key, value in nodes.items(): if isinstance(value, list): for list_data in value: child = _process_nodes(list_data) yield _mo.Couplet(_mo.Atom(key), _mo.Set(child), direct_load=True) elif isinstance(value, dict): children = _process_nodes(value) yield _mo.Couplet(_mo.Atom(key), _mo.Set(children), direct_load=True) elif isinstance(value, (str, int)): yield _mo.Couplet(_mo.Atom(key), _mo.Atom(value), direct_load=True) else: assert False # Node type not supported.
def transpose(couplet: '(M x M)', _checked=True) -> '(M x M)': """Return the transposition of ``couplet`` (right and left components swapped). :return: The :term:`transposition` of ``couplet`` or `Undef()` if ``couplet`` is not an instance of :class:`~.Couplet`. """ if _checked: if not is_member(couplet): return _undef.make_or_raise_undef2(couplet) else: assert is_member_or_undef(couplet) if couplet is _undef.Undef(): return _undef.make_or_raise_undef(2) result = _mo.Couplet(left=couplet.right, right=couplet.left, direct_load=True) result.cache_absolute(couplet.cached_absolute).cache_reflexive(couplet.cached_reflexive) return result
def _import_csv(csv_file): for _ in range(0, skip_rows): next(csv_file) reader = _csv.DictReader(csv_file, fieldnames=columns) _index = 0 for row in reader: filtered_row = {key: val for key, val in _filter_row(row)} if import_csv.regular and len(row) != len(filtered_row): import_csv.regular = False for key, val in types.items(): if key in filtered_row: filtered_row[key] = val(filtered_row[key]) if index_column is not None: filtered_row[index_column] = _index _index += 1 yield _mo.Set( (_mo.Couplet(left=_util.get_left_cached(left), right=_mo.Atom(right), direct_load=True) for left, right in filtered_row.items()), direct_load=True)\ .cache_relation(_mo.CacheStatus.IS).cache_functional(_mo.CacheStatus.IS)
def compose(couplet1: '(M x M)', couplet2: '(M x M)', _checked=True) -> '(M x M)': """Return the composition of ``couplet1`` with ``couplet2``. :return: The :term:`composition` of ``couplet1`` with ``couplet2`` (which may be undefined, in which case the result is `Undef()`) or `Undef()` if ``couplet1`` or ``couplet2`` are not instances of :class:`~.Couplet`. """ if _checked: if not is_member(couplet1): return _undef.make_or_raise_undef2(couplet1) if not is_member(couplet2): return _undef.make_or_raise_undef2(couplet2) else: assert is_member_or_undef(couplet1) assert is_member_or_undef(couplet2) if couplet1 is _undef.Undef() or couplet2 is _undef.Undef(): return _undef.make_or_raise_undef(2) if couplet1.left != couplet2.right: return _undef.make_or_raise_undef(2) return _mo.Couplet(left=couplet2.left, right=couplet1.right, direct_load=True)
def from_set(left: '( M )', *values: '( M )') -> 'PP(M x M)': r"""Return a clan where all relations contain a single couplet with the same left component. :param left: The :term:`left component` of all :term:`couplet`\s in the returned :term:`clan`. :param values: The :term:`right component`\s of the couplets in the returned clan. (If you want to pass in an iterable, you need to prefix it with an asterisk ``*``.) :return: A clan where every :term:`relation` consists of a single couplet with a left component of ``left`` and a right component from ``values``. """ left_mo = _mo.auto_convert(left) clan = _mo.Set((_mo.Set( _mo.Couplet(left_mo, _mo.auto_convert(right), direct_load=True), direct_load=True).cache_relation(CacheStatus.IS).cache_functional( CacheStatus.IS).cache_right_functional(CacheStatus.IS) for right in values), direct_load=True) clan.cache_clan(CacheStatus.IS) clan.cache_functional(CacheStatus.IS).cache_right_functional( CacheStatus.IS) clan.cache_regular(CacheStatus.IS).cache_right_regular(CacheStatus.IS) return clan
def is_transitive(rel, _checked=True) -> bool: """Return whether ``rel`` is transitive. :return: ``True`` if ``rel`` is :term:`transitive`, ``False`` if it is not, or `Undef()` if ``rel`` is not a :term:`relation`. """ if _checked: if not is_member(rel): return _undef.make_or_raise_undef2(rel) else: assert is_member_or_undef(rel) if rel is _undef.Undef(): return _undef.make_or_raise_undef(2) if rel.cached_transitive == _mo.CacheStatus.UNKNOWN: transitive = True for couplet1 in rel: for couplet2 in rel: if couplet1.left == couplet2.right: if not rel.has_element( _mo.Couplet(couplet2.left, couplet1.right)): transitive = False break rel.cache_transitive(_mo.CacheStatus.from_bool(transitive)) return rel.cached_transitive == _mo.CacheStatus.IS
def _process_attributes(node): for (name, value) in node.attributes.items(): yield _mo.Couplet(left=_util.get_left_cached(name), right=_mo.Atom(_get_atom_value(value), True), direct_load=True)
"result multiset.\n") # Multiset Intersect Operation Example simple_minus = _multisets.minus(ms_1, ms_2) print(str(ms_1) + ' MINUS ' + str(ms_2)) print('=> EVALUATES TO ' + str(simple_minus)) ms_6 = _mo.Multiset({'a': 3, 'b': 1}) if ms_6 == simple_minus: print("multiset's minus subtracts all the rhs multiples from the lhs.\n") # Moving on to multiclan examples now # Setting up multiclan relations rel_1 = _mo.Set(_mo.Couplet('x', 'y'), _mo.Couplet('w', 'y')) rel_2 = _mo.Set(_mo.Couplet('a', 'x'), _mo.Couplet('b', 'w')) rel_3 = _mo.Set(_mo.Couplet('x', 'z'), _mo.Couplet('v', 'y')) rel_4 = _mo.Set(_mo.Couplet('c', 'z'), _mo.Couplet('a', 'v')) rel_5 = _mo.Set(_mo.Couplet('b', 'w'), _mo.Couplet('w', 'y')) rel_6 = _mo.Set(_mo.Couplet('a', 'x'), _mo.Couplet('x', 'y')) # Creating multiclans (multisets of relations) mc_1 = _mo.Multiset({rel_1: 2, rel_3: 3}) mc_2 = _mo.Multiset({rel_2: 5, rel_4: 1}) mc_3 = _mo.Multiset({rel_1: 2, rel_6: 7}) mc_4 = _mo.Multiset({rel_2: 5, rel_5: 11}) # Multiset Transpose Operation Example simple_transpose = _multiclans.transpose(mc_1)
def from_dict(dict1: dict) -> 'P(M x M)': r"""Return a :term:`relation` where the :term:`couplet`\s are the elements of ``dict1``.""" return _mo.Set((_mo.Couplet(left, right) for left, right in dict1.items()), direct_load=True)\ .cache_relation(_mo.CacheStatus.IS).cache_functional(_mo.CacheStatus.IS)