def from_set(left: '( M )', *values: '( M )') -> 'PP(M x M)': """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. :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_is_relation(True) for right in values), direct_load=True).cache_is_clan(True) return clan
def get_rights_for_left(mclan: 'P(P(M x M) x N)', left: '( M )', _checked=True) -> 'P(M x N)': """Return the multiset of the right components of all couplets in the multiclan ``mclan`` associated with the left component ``left``. :return: The :term:`right multiset` of the :term:`multiclan` ``mclan`` associated with the :term:`left component` ``left`` or `Undef()` if ``mclan`` is not a multiclan. """ if _checked: if not is_member(mclan): return _undef.make_or_raise_undef2(mclan) if left is _undef.Undef(): return _mo.Set() left = _mo.auto_convert(left) else: assert is_member_or_undef(mclan) assert _mo.is_mathobject_or_undef(left) if mclan is _undef.Undef(): return _undef.make_or_raise_undef(2) if left is _undef.Undef(): return _mo.Set() clan_itr = iter(mclan) rights = _sets.multify(_relations.get_rights_for_left(next(clan_itr), left, _checked=False)) for rel in clan_itr: rights = _multisets.add( _sets.multify(_relations.get_rights_for_left(rel, left, _checked=False)), rights, _checked=False) if not rights.is_empty: if mclan.cached_is_absolute: rights.cache_absolute(_mo.CacheStatus.IS) return rights
def get_left(rel: 'P(M x M)', right: '( M )', _checked=True) -> '( M )': r"""Return the left component of the couplet that has a right component of ``right``. In general, use with :term:`right-functional` :term:`relation`\s; that is, relations where all :term:`right component`\s appear at most once. :return: The :term:`left component` of the :term:`couplet` that has a :term:`right component` of ``right``, or `Undef()` if there is not exactly one couplet with the right component ``right`` in ``rel`` or ``rel`` is not a :term:`relation`. """ if _checked: if not is_member(rel): return _undef.make_or_raise_undef2(rel) if right is _undef.Undef(): return _undef.make_or_raise_undef(2) right = _mo.auto_convert(right) else: assert is_member_or_undef(rel) assert _mo.is_mathobject_or_undef(right) if right is _undef.Undef() or rel is _undef.Undef(): return _undef.make_or_raise_undef(2) result = None for elem in rel: assert elem.is_couplet if elem.right == right: if result is not None: return _undef.make_or_raise_undef() # Early Undef() exit if more than one found. result = elem.left if result is None: return _undef.make_or_raise_undef() # Undef() exit if none found. return result
def get_rights_for_left(rel: 'P(M x M)', left: '( M )', _checked=True) -> 'P( M )': """Return the set of the right components of all couplets in the relation ``rel`` associated with the :term:`left component` ``left``. :return: The :term:`right set` of the :term:`relation` ``rel`` associated with the :term:`left component` or `Undef()` if ``rel`` is not a :term:`relation`. """ if _checked: if not is_member(rel): return _undef.make_or_raise_undef2(rel) if left is _undef.Undef(): return _mo.Set() left = _mo.auto_convert(left) else: assert is_member_or_undef(rel) assert _mo.is_mathobject_or_undef(left) if rel is _undef.Undef(): return _undef.make_or_raise_undef(2) if left is _undef.Undef(): return _mo.Set() result = _mo.Set((elem.right for elem in rel if elem.left == left), direct_load=True) if not result.is_empty: if rel.cached_is_absolute: result.cache_absolute(_mo.CacheStatus.IS) return result
def get_rights_for_left(mclan: 'P(P(M x M) x N)', left: '( M )', _checked=True) -> 'P(M x N)': """Return the multiset of the right components of all couplets in the multiclan ``mclan`` associated with the left component ``left``. :return: The :term:`right multiset` of the :term:`multiclan` ``mclan`` associated with the :term:`left component` ``left`` or `Undef()` if ``mclan`` is not a multiclan. """ if _checked: if not is_member(mclan): return _undef.make_or_raise_undef2(mclan) if left is _undef.Undef(): return _mo.Set() left = _mo.auto_convert(left) else: assert is_member_or_undef(mclan) assert _mo.is_mathobject_or_undef(left) if mclan is _undef.Undef(): return _undef.make_or_raise_undef(2) if left is _undef.Undef(): return _mo.Set() clan_itr = iter(mclan) rights = _sets.multify( _relations.get_rights_for_left(next(clan_itr), left, _checked=False)) for rel in clan_itr: rights = _multisets.add(_sets.multify( _relations.get_rights_for_left(rel, left, _checked=False)), rights, _checked=False) if not rights.is_empty: if mclan.cached_is_absolute: rights.cache_absolute(_mo.CacheStatus.IS) return rights
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 get_left(rel: 'P(M x M)', right: '( M )', _checked=True) -> '( M )': r"""Return the left component of the couplet that has a right component of ``right``. In general, use with :term:`right-functional` :term:`relation`\s; that is, relations where all :term:`right component`\s appear at most once. :return: The :term:`left component` of the :term:`couplet` that has a :term:`right component` of ``right``, or `Undef()` if there is not exactly one couplet with the right component ``right`` in ``rel`` or ``rel`` is not a :term:`relation`. """ if _checked: if not is_member(rel): return _undef.make_or_raise_undef2(rel) if right is _undef.Undef(): return _undef.make_or_raise_undef(2) right = _mo.auto_convert(right) else: assert is_member_or_undef(rel) assert _mo.is_mathobject_or_undef(right) if right is _undef.Undef() or rel is _undef.Undef(): return _undef.make_or_raise_undef(2) result = None for elem in rel: assert elem.is_couplet if elem.right == right: if result is not None: return _undef.make_or_raise_undef( ) # Early Undef() exit if more than one found. result = elem.left if result is None: return _undef.make_or_raise_undef() # Undef() exit if none found. return result
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(_mo.CacheStatus.IS) .cache_functional(_mo.CacheStatus.IS).cache_right_functional(_mo.CacheStatus.IS) for right in values), direct_load=True) clan.cache_clan(_mo.CacheStatus.IS) clan.cache_functional(_mo.CacheStatus.IS).cache_right_functional(_mo.CacheStatus.IS) clan.cache_regular(_mo.CacheStatus.IS).cache_right_regular(_mo.CacheStatus.IS) return clan
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 _create_partition_dict_from_set(set_, class_invariant_func): r"""Return the data of a partition defined by ``class_invariant_func`` on ``set_``. :param set_: The :term:`set` to be partitioned. :param class_invariant_func: A function from ``set_`` to :term:`set M`. :return: A ``dict`` of ``set``\s, where the keys of the ``dict`` are the range of the equivalence relation implemented by ``class_invariant_func`` and the ``set``\s are the members of ``set_`` that are associated with each given key. Both the keys and the members of the value ``set``\s are `MathObject`\s. """ # Collect the data of the partition in a dictionary of sets. partition_dict = {} for element in set_: # equivalence_class must be a MathObject. equivalence_class = _mo.auto_convert(class_invariant_func(element)) # equivalence_class is a MathObject, so it is hashable and can be used as dict key. if equivalence_class not in partition_dict: partition_dict[equivalence_class] = set() partition_dict[equivalence_class].add(element) return partition_dict
def _create_partition_dict_from_multiset(mset, class_invariant_func): r"""Return the data of a partition defined by ``class_invariant_func`` on ``mset``. :param mset: The :term:`multiset` to be partitioned. :param class_invariant_func: A function from ``mset`` to :term:`set M`. :return: A ``dict`` of :class:`~collection.Counter`\s, where the keys of the ``dict`` are the range of the equivalence relation implemented by ``class_invariant_func`` and the ``Counter``\s are the members of ``mset`` that are associated with each given key. Both the keys and the value members of the ``Counter``\s are `MathObject`\s. """ # Collect the data of the partition in a dictionary of Counters. partition_dict = {} for element, count in mset.data.items(): # equivalence_class must be a MathObject. equivalence_class = _mo.auto_convert(class_invariant_func(element)) # equivalence_class is a MathObject, so it is hashable and can be used as dict key. if equivalence_class not in partition_dict: partition_dict[equivalence_class] = _collections.Counter() partition_dict[equivalence_class][element] = count return partition_dict
def _create_partition_dict(set1, equivalence_relation): """Return the data of a partition defined by ``equivalence_relation`` on ``set1``. :param set1: The :term:`set` to be partitioned. :param equivalence_relation: A function from ``set1`` to :term:`set M`. :return: A ``dict`` of ``set``\s, where the keys of the ``dict`` are the range of the equivalence relation implemented by ``equivalence_relation`` and the ``set``\s are the members of ``set1`` that are associated with each given key. """ # Collect the data of the partition in a dictionary of lists, which later is converted into a # Set of Sets. partition_dict = {} for element in set1: # equivalence_class must be a MathObject. equivalence_class = _mo.auto_convert(equivalence_relation(element)) # equivalence_class is a MathObject, so it is hashable and can be used as dict key. if equivalence_class not in partition_dict: partition_dict[equivalence_class] = set() partition_dict[equivalence_class].add(element) return partition_dict