def big_intersect(set1: 'PP( M )', _checked=True) -> 'P( M )': """Return the intersection of all members of ``set1``. :return: The :term:`intersection` of all members of ``set1`` or `Undef()` if ``set1`` or any of its members are not instances of :class:`~.Set`. Example code: .. code:: from algebraixlib.mathobjects import Set from algebraixlib.algebras.sets import big_intersect big_intersect(Set(Set('a', 'b'), Set('b', 'c'))) # Output: Set(Atom('b')) big_intersect(Set(Set('a', 'b'), 'a')) # Output: <algebraixlib.undef.Undef at 0x4004978> """ if _checked: if not isinstance(set1, _mo.Set): return _make_or_raise_undef() for element in set1: if not is_member(element): return _make_or_raise_undef() else: assert isinstance(set1, _mo.Set) return _extend_binary_operation(set1, partial(intersect, _checked=False))
def union(set1: 'P( M )', set2: 'P( M )', _checked=True) -> 'P( M )': """Return the union of ``set1`` with ``set2``. :return: The :term:`binary union` of ``set1`` and ``set2`` or `Undef()` if ``set1`` or ``set2`` are not :term:`set`\s (that is, instances of :class:`~.Set`). """ if _checked: if not is_member(set1): return _make_or_raise_undef() if not is_member(set2): return _make_or_raise_undef() else: assert is_member(set1) assert is_member(set2) values = set1.data.union(set2.data) ret = _mo.Set(values, direct_load=True) if not ret.is_empty: # Relay relation flags if set1.cached_is_relation and set2.cached_is_relation: ret.cache_is_relation(True) elif set1.cached_is_not_relation or set2.cached_is_not_relation: ret.cache_is_relation(False) # Relay clan flags if set1.cached_is_clan and set2.cached_is_clan: ret.cache_is_clan(True) elif set1.cached_is_not_clan or set2.cached_is_not_clan: ret.cache_is_clan(False) return ret
def get_left(rel: 'P(M x M)', right: '( M )', _checked=True) -> '( M )': """Return the single :term:`left component` associated with the :term:`right component` ``right``. In general, use with :term:`right-functional` :term:`relation`\s; that is, relations where all right components appear at most once. :return: The single :term:`left component` associated with the :term:`right component` ``right``, or `Undef()` if there is not exactly one element with the right component ``right`` in ``rel`` or ``rel`` is not a :term:`relation`. """ if _checked: if not is_member(rel): return _make_or_raise_undef() else: assert is_member(rel) right = _mo.auto_convert(right) result = None for elem in rel: assert isinstance(elem, _mo.Couplet) if elem.right == right: if result is not None: return _make_or_raise_undef() # Early Undef() exit if more than one found. result = elem.left if result is None: return _make_or_raise_undef() # Undef() exit if none found. return result
def lhs_functional_cross_union(lhs: 'PP( MxM )', rhs: 'PP( MxM )', _checked=True): """This data manipulations preforms a left functional cross union, then unions the left hand side elements that were not cross unioned. :param lhs: The priority left hand clan for this operation :param rhs: The right hand clan to preform the cross union with :return: PP(MxM) resulting math object """ if _checked: if not is_member(lhs): return _make_or_raise_undef() if not is_member(rhs): return _make_or_raise_undef() else: assert is_member(lhs) assert is_member(rhs) def _functional_cross_union(clan1: 'PP(M x M)', clan2: 'PP(M x M)') -> 'PP(M x M)': """Return the :term:`left-functional cross-union` of ``clan1`` and ``clan2``.""" assert is_member(clan1) assert is_member(clan2) return _extension.binary_extend( clan1, clan2, partial(_relations.functional_union, _checked=False), _checked=False).cache_is_clan(True) return _sets.union( _functional_cross_union(lhs, rhs), _mo.Set(lhs_elem for lhs_elem in lhs if _functional_cross_union( _mo.Set(lhs_elem, direct_load=True), rhs).is_empty), _checked=False)
def single(set1: _mo.Set): """Return the single element of ``set1``. :return: Return the single element of ``set1``, or `Undef()` if ``set1`` has not exactly one element or is not a :term:`set` (that is, an instance of :class:`~.Set`). """ if not is_member(set1): return _make_or_raise_undef() if set1.cardinality == 1: return next(iter(set1)) return _make_or_raise_undef(2)
def add_atom(e1, e2): if type(e1) != Atom: return _make_or_raise_undef() if type(e2) != Atom: return _make_or_raise_undef() if not isinstance(e1.value, Number): return _make_or_raise_undef() if not isinstance(e2.value, Number): return _make_or_raise_undef() try: # noinspection PyUnresolvedReferences result = e1.value + e2.value except TypeError: result = Undef() return Atom(result) if result is not Undef() else result
def big_intersect(multisets: 'PP( M x N )', _checked=True) -> 'P( M x N )': """Return the :term:`intersection` of all members of ``multiset``. :return: The :term:`intersection` of all members of ``multiset`` or `Undef()` if ``multiset`` or any of its members are not instances of :class:`~.Multiset`. """ if _checked: if not isinstance(multisets, _mo.Set): return _make_or_raise_undef() for element in multisets: if not is_member(element): return _make_or_raise_undef() else: assert isinstance(multisets, _mo.Set) return _extend_binary_operation(multisets, partial(intersect, _checked=False))
def is_superset_of(set1: 'P( M )', set2: 'P( M )', _checked=True) -> bool: """Return whether ``set1`` is a superset of ``set2``. :return: ``True`` if ``set1`` is a :term:`superset` of ``set2``, ``False`` if not. Return `Undef()` if ``set1`` or ``set2`` are not :term:`set`\s (that is, instances of :class:`~.Set`). """ if _checked: if not is_member(set1): return _make_or_raise_undef() if not is_member(set2): return _make_or_raise_undef() else: assert is_member(set1) assert is_member(set2) return set1.data.issuperset(set2.data)
def is_left_regular(clan, _checked=True) -> bool: """Return ``True`` if ``clan`` is :term:`left-regular`. :return: ``True`` if ``clan`` is :term:`left-regular` or `Undef()` if ``clan`` is not a :term:`clan`. """ if _checked: if not is_member(clan): return _make_or_raise_undef() else: assert is_member(clan) if not clan.cached_is_left_regular and not clan.cached_is_not_left_regular: # NOTE: The empty case is handled in Set().__init__ via flags initialization if clan.cached_is_not_left_functional: clan.cache_is_left_regular(False) return False itr = iter(clan) rel = next(itr) if not rel.is_left_functional(): clan.cache_is_left_regular(False) return False left_set = rel.get_left_set() regular = all(rel.is_left_functional() and left_set == rel.get_left_set() for rel in itr) clan.cache_is_left_regular(regular) return clan.cached_is_left_regular
def addition(multiset1: 'P( M x N )', multiset2: 'P( M x N )', _checked=True) -> 'P( M x N )': """Return the :term:`addition` of ``multiset1`` and ``multiset2``. :return: The addition of ``multiset1`` and ``multiset2`` or `Undef()` if ``multiset1`` or ``multiset2`` are not instances of :class:`~.Multiset`. """ if _checked: if not is_member(multiset1): return _make_or_raise_undef() if not is_member(multiset2): return _make_or_raise_undef() else: assert is_member(multiset1) assert is_member(multiset2) values = multiset1.data + multiset2.data return _mo.Multiset(values)
def demultify(multiset: 'P( M x N )', _checked=True) -> 'P( M )': if _checked: if not is_member(multiset): return _make_or_raise_undef() else: assert is_member(multiset) return _mo.Set(multiset.data.keys(), direct_load=True)
def functional_add(rel: 'P(M x M)', element: 'M x M') -> 'P(M x M)': """Add ``element`` to ``rel`` and return the new :term:`relation`. :param rel: The source data. Must be a :term:`relation`. It must not contain a :term:`couplet` with the same :term:`left component` as ``element``. :param element: The element to be added to ``rel``. Must be a :class:`~.Couplet` and its :term:`left component` must not be a left component in ``rel``. :return: The new relation, composed of ``rel`` and ``element``. """ if not is_member(rel): return _make_or_raise_undef() if not isinstance(element, _mo.Couplet): return _make_or_raise_undef() if _sets.is_subset_of(_mo.Set(element.left), get_lefts(rel)): return _make_or_raise_undef(2) result_relation = _sets.union(rel, _mo.Set(element)) return result_relation
def compose(rel1: 'P(M x M)', rel2: 'P(M x M)', _checked=True) -> 'P(M x M)': """Return the composition of ``rel1`` with ``rel2``. :return: The :term:`binary extension` of :term:`composition` from the :term:`algebra of couplets` to the :term:`algebra of relations`, applied to the :term:`relation`\s ``rel1`` and ``rel2``, or `Undef()` if ``rel1`` or ``rel2`` are not relations. """ if _checked: if not is_member(rel1): return _make_or_raise_undef() if not is_member(rel2): return _make_or_raise_undef() else: assert is_member(rel1) assert is_member(rel2) return _extension.binary_extend(rel1, rel2, partial( _couplets.compose, _checked=False), _checked=False).cache_is_relation(True)
def compose(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the :term:`composition` of ``clan1`` with ``clan2``. :return: The :term:`binary extension` of :term:`composition` from the :term:`algebra of relations` to the :term:`algebra of clans`, applied to ``clan1`` and ``clan2``, or `Undef()` if ``clan1`` or ``clan2`` are not :term:`clan`\s. """ if _checked: if not is_member(clan1): return _make_or_raise_undef() if not is_member(clan2): return _make_or_raise_undef() else: assert is_member(clan1) assert is_member(clan2) return _extension.binary_extend(clan1, clan2, partial(_relations.compose, _checked=False), _checked=False).cache_is_clan(True)
def multify(set1: 'P( M )', _checked=True) -> 'P( M x N )': """Return a :term:`multiset` based on ``set1`` where all multiples are set to 1.""" if _checked: if not is_member(set1): return _make_or_raise_undef() else: assert is_member(set1) return _mo.Multiset(set1.data, direct_load=True)
def substrict(set1: 'P( M )', set2: 'P( M )', _checked=True) -> 'P( M )': """Return ``set1`` if it is a subset of ``set2``, otherwise return `Undef()`. :return: Return the :term:`substriction` of ``set1`` and ``set1``; that is, return ``set1`` if it is a :term:`subset` of ``set2`` or `Undef()` if not. Also return `Undef()` if ``set1`` or ``set2`` are not :term:`set`\s (that is, instances of :class:`~.Set`). """ if _checked: if not is_member(set1): return _make_or_raise_undef() if not is_member(set2): return _make_or_raise_undef() else: assert is_member(set1) assert is_member(set2) if not is_subset_of(set1, set2, _checked=False): return _make_or_raise_undef(2) return set1
def cross_union(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the :term:`cross-union` of ``clan1`` and ``clan2``. :return: The :term:`binary extension` of :term:`union` from the :term:`algebra of relations` (which inherits it from the :term:`algebra of sets`) to the :term:`algebra of clans` applied to ``clan1`` and ``clan2``, or `Undef()` if ``clan1`` or ``clan2`` are not :term:`clan`\s. """ if _checked: if not is_member(clan1): return _make_or_raise_undef() if not is_member(clan2): return _make_or_raise_undef() else: assert is_member(clan1) assert is_member(clan2) return _extension.binary_extend(clan1, clan2, partial(_sets.union, _checked=False), _checked=False).cache_is_clan(True)
def superstrict(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return a Set of every element of clan1 that is a superset of any element of clan2. :return: The :term:`binary extension` of :term:`superstriction` from the :term:`algebra of relations` (which inherits it from the :term:`algebra of sets`) to the :term:`algebra of clans` applied to ``clan1`` and ``clan2``, or `Undef()` if ``clan1`` or ``clan2`` are not :term:`clan`\s. """ if _checked: if not is_member(clan1): return _make_or_raise_undef() if not is_member(clan2): return _make_or_raise_undef() else: assert is_member(clan1) assert is_member(clan2) return _extension.binary_extend(clan1, clan2, partial( _sets.superstrict, _checked=False)).cache_is_clan(True)
def is_subset_of(multiset1: 'P( M x N )', multiset2: 'P( M x N )', _checked=True) -> bool: """Return whether ``multiset1`` is a :term:`subset` of ``multiset2``. :return: ``True`` if ``multiset1`` is a subset of ``multiset2``, ``False`` if not. Return `Undef()` if ``multiset1`` or ``multiset2`` are not instances of :class:`~.Multiset`. """ if _checked: if not is_member(multiset1): return _make_or_raise_undef() if not is_member(multiset2): return _make_or_raise_undef() else: assert is_member(multiset1) assert is_member(multiset2) for key in multiset1.data.keys(): if not multiset1.data[key] <= multiset2.data[key]: return False return True
def substrict(multiset1: 'P( M x N )', multiset2: 'P( M x N )', _checked=True) -> 'P( M x N )': """Return the :term:`substriction` of ``multiset1`` and ``multiset2``. :return: ``multiset1`` if ``multiset1`` is a :term:`subset` of ``multiset2`` or `Undef()` if not. Also return `Undef()` if ``multiset1`` or ``multiset2`` are not instances of :class:`~.Set`. """ if _checked: if not is_member(multiset1): return _make_or_raise_undef() if not is_member(multiset2): return _make_or_raise_undef() else: assert is_member(multiset1) assert is_member(multiset2) if not is_subset_of(multiset1, multiset2, _checked=False): return _make_or_raise_undef(2) return multiset1
def swap(rel: 'P(M x M)', swaps: 'P(M x M)', _checked=True) -> 'P(M x M)': """Return a :term:`relation` where components in ``rel`` are swapped according to ``swaps``. :param rel: The relation with the left components to swap. :param swaps: A relation where both right components and left components are current left components in ``rel``. These left components are swapped. :return: A version of ``rel`` where the left components of the member couplets are swapped. """ if _checked: if not is_member(rel): return _make_or_raise_undef() if not is_member(swaps): return _make_or_raise_undef() else: assert is_member(rel) assert is_member(swaps) renames = _sets.union(swaps, transpose(swaps, _checked=False), _checked=False) return rename(rel, renames, _checked=False)
def compose(couplet1: '(M x M)', couplet2: '(M x M)', _checked=True) -> '(M x M)': """Return the :term:`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 _make_or_raise_undef() if not is_member(couplet2): return _make_or_raise_undef() else: assert is_member(couplet1) assert is_member(couplet2) if couplet1.left != couplet2.right: return _make_or_raise_undef(2) return _mo.Couplet(left=couplet2.left, right=couplet1.right, direct_load=True)
def cross_intersect(multiclan1: 'P(P(M x M) x N)', multiclan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the :term:`cross-intersection` of ``multiclan1`` and ``multiclan2``. :return: The :term:`binary multi-extension` of :term:`intersection` from the :term:`algebra of relations` (which inherits it from the :term:`algebra of sets`) to the :term:`algebra of multiclans` applied to ``multiclan1`` and ``multiclan2``, or `Undef()` if ``multiclan1`` or ``multiclan2`` are not :term:`multiclan`\s. """ if _checked: if not is_member(multiclan1): return _make_or_raise_undef() if not is_member(multiclan2): return _make_or_raise_undef() else: assert is_member(multiclan1) assert is_member(multiclan2) return _extension.binary_multi_extend(multiclan1, multiclan2, partial( _sets.intersect, _checked=False), _checked=False)
def functional_union(rel1: 'P(M x M)', rel2: 'P(M x M)', _checked=True) -> 'P(M x M)': """Return the union of ``rel1`` and ``rel2`` if it is a function, otherwise `Undef()`. :return: The :term:`left-functional union` of the :term:`relation`\s ``rel1`` and ``rel2``; that is, the :term:`union` if the result is :term:`left-functional`, otherwise `Undef()`. Also return `Undef()` if ``rel1`` or ``rel2`` are not relations. """ if _checked: if not is_member(rel1): return _make_or_raise_undef() if not is_member(rel2): return _make_or_raise_undef() else: assert is_member(rel1) assert is_member(rel2) rel_union = _sets.union(rel1, rel2, _checked=False).cache_is_relation(True) if not is_left_functional(rel_union, _checked=False): return _make_or_raise_undef(2) return rel_union
def functional_cross_union(multiclan1: 'P(P(M x M) x N)', multiclan2: 'P(P(M x M) x N)', _checked=True) -> 'P(P(M x M) x N)': r"""Return the :term:`left-functional cross-union` of ``multiclan1`` and ``multiclan2``. :return: The :term:`binary multi-extension` of the :term:`left-functional union` from the :term:`algebra of relations` to the :term:`algebra of multiclans`, applied to ``multiclan1`` and ``multiclan2``, or `Undef()` if ``multiclan1`` or ``multiclan2`` are not :term:`multiclan`\s. """ if _checked: if not is_member(multiclan1): return _make_or_raise_undef() if not is_member(multiclan2): return _make_or_raise_undef() else: assert is_member(multiclan1) assert is_member(multiclan2) return _extension.binary_multi_extend(multiclan1, multiclan2, partial( _relations.functional_union, _checked=False), _checked=False)
def some(set1: _mo.Set): """Return 'some' element of ``set1``. Use with caution - may be non-deterministic. :return: Some element of ``set1``, or `Undef()` if ``set1`` is empty or is not a :term:`set` (that is, an instance of :class:`~.Set`). .. note:: This function should only be used in contexts where the way the return value will be utilized by the calling function is invariant of the particular element returned; the element of ``set1`` that is returned is non-deterministic. This function is only intended to be used in (mostly implementation) scenarios where it does not matter which element of ``set1`` is retrieved, because the expressions that consume that value will be invariant w.r.t. some of ``set1``. """ if not is_member(set1): return _make_or_raise_undef() if len(set1) > 0: return next(iter(set1)) return _make_or_raise_undef()
def rename(rel: 'P(M x M)', renames: 'P(M x M)', _checked=True) -> 'P(M x M)': """Return a :term:`relation` where left components in ``rel`` are renamed according to ``renames``. :param rel: The relation with the left components to rename. :param renames: A relation where the right components are the current left components in ``rel`` and the left components are the new left components to use in ``rel``. :return: A version of ``rel`` where the left components of the member couplets are renamed. """ if _checked: if not is_member(rel): return _make_or_raise_undef() if not is_member(renames): return _make_or_raise_undef() else: assert is_member(rel) assert is_member(renames) renames_complete = fill_lefts(rel, renames, _checked=False) result = compose(rel, renames_complete, _checked=False) return result
def right_functional_cross_union(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the :term:`right-functional cross-union` of ``clan1`` and ``clan2``. :return: The :term:`binary extension` of the :term:`right-functional union` from the :term:`algebra of relations` to the :term:`algebra of clans`, applied to ``clan1`` and ``clan2``, or `Undef()` if ``clan1`` or ``clan2`` are not :term:`clan`\s. """ if _checked: if not is_member(clan1): return _make_or_raise_undef() if not is_member(clan2): return _make_or_raise_undef() else: assert is_member(clan1) assert is_member(clan2) return _extension.binary_extend(clan1, clan2, partial(_relations.right_functional_union, _checked=False), _checked=False).cache_is_clan(True)
def __getitem__(self, left) -> 'P( M )': """With the syntax ``mo[left]``, return a set of rights associated with ``left``. :param left: The :term:`left` of the :term:`couplet`\(s) of which the :term:`right`\(s) are returned. :return: If ``self`` is a :term:`relation`, return a :term:`set` that contains the right(s) of the couplet(s) that have a left that matches ``left``. (This set may be empty if no couplet with the given left exists.) Return `Undef()` if ``self`` is not a relation. """ return _make_or_raise_undef()
def is_superset_of(multiset1: 'P( M x N )', multiset2: 'P( M x N )', _checked=True) -> bool: """Return whether ``multiset1`` is a :term:`superset` of ``multiset2``. :return: ``True`` if ``multiset1`` is a superset of ``multiset2``, ``False`` if not. Return `Undef()` if ``multiset1`` or ``multiset2`` are not instances of :class:`~.Multiset`. .. note:: Reasonably up to date up to here. I haven't yet worked on the rest. """ if _checked: if not is_member(multiset1): return _make_or_raise_undef() if not is_member(multiset2): return _make_or_raise_undef() else: assert is_member(multiset1) assert is_member(multiset2) for key in multiset2.data.keys(): if not multiset1.data[key] >= multiset2.data[key]: return False return True