def test_binary_extend_errors(self): self.assertRaises(AttributeError, lambda: extension.binary_extend(1, 2, sets.union)) self.assertRaises( AttributeError, lambda: extension.binary_extend(Set(1), 2, sets.union)) self.assertRaises( AttributeError, lambda: extension.binary_extend(1, Set(2), sets.union))
def compose(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the 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 _undef.make_or_raise_undef2(clan1) if not is_member(clan2): return _undef.make_or_raise_undef2(clan2) else: assert is_member_or_undef(clan1) assert is_member_or_undef(clan2) if clan1 is _undef.Undef() or clan2 is _undef.Undef(): return _undef.make_or_raise_undef(2) result = _extension.binary_extend( clan1, clan2, _functools.partial(_relations.compose, _checked=False), _checked=False).cache_clan(_mo.CacheStatus.IS) if not result.is_empty: result.cache_clan(_mo.CacheStatus.IS) if clan1.cached_is_absolute and clan2.cached_is_absolute: result.cache_absolute(_mo.CacheStatus.IS) if clan1.cached_is_functional and clan2.cached_is_functional: result.cache_functional(_mo.CacheStatus.IS) if clan1.cached_is_right_functional and clan2.cached_is_right_functional: result.cache_right_functional(_mo.CacheStatus.IS) return result
def cross_right_functional_union(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the cross-right-functional union of ``clan1`` and ``clan2``. The :term:`cross-right-functional union` of two :term:`clan`\s is the :term:`cross-union` of these clans, but removing all resulting :term:`relation`\s that are not :term:`right-functional`. :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 _undef.make_or_raise_undef2(clan1) if not is_member(clan2): return _undef.make_or_raise_undef2(clan2) else: assert is_member_or_undef(clan1) assert is_member_or_undef(clan2) if clan1 is _undef.Undef() or clan2 is _undef.Undef(): return _undef.make_or_raise_undef(2) result = _extension.binary_extend( clan1, clan2, _functools.partial(_relations.right_functional_union, _checked=False), _checked=False) if not result.is_empty: result.cache_clan(_mo.CacheStatus.IS) result.cache_right_functional(_mo.CacheStatus.IS) if clan1.cached_is_not_functional or clan2.cached_is_not_functional: result.cache_functional(_mo.CacheStatus.IS_NOT) return result
def compose(rel1: 'P(M x M)', rel2: 'P(M x M)', _checked=True) -> 'P(M x M)': r"""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 _undef.make_or_raise_undef2(rel1) if not is_member(rel2): return _undef.make_or_raise_undef2(rel2) else: assert is_member_or_undef(rel1) assert is_member_or_undef(rel2) if rel1 is _undef.Undef() or rel2 is _undef.Undef(): return _undef.make_or_raise_undef(2) result = _extension.binary_extend(rel1, rel2, _functools.partial(_couplets.compose, _checked=False), _checked=False) if not result.is_empty: result.cache_relation(CacheStatus.IS) if rel1.cached_is_absolute and rel2.cached_is_absolute: result.cache_absolute(CacheStatus.IS) if rel1.cached_is_functional and rel2.cached_is_functional: result.cache_functional(CacheStatus.IS) if rel1.cached_is_right_functional and rel2.cached_is_right_functional: result.cache_right_functional(CacheStatus.IS) return result
def cross_intersect(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the cross-intersection of ``clan1`` and ``clan2``. The :term:`cross-intersection` of two :term:`clan`\s is a clan that contains the result of intersecting every :term:`relation` from one clan with every relation from the other clan. :return: The :term:`binary extension` of :term:`intersection` 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 _undef.make_or_raise_undef() if not is_member(clan2): return _undef.make_or_raise_undef() else: assert is_member(clan1) assert is_member(clan2) result = _extension.binary_extend(clan1, clan2, _functools.partial( _sets.intersect, _checked=False), _checked=False) if not result.is_empty: result.cache_clan(_mo.CacheStatus.IS) if clan1.cached_is_functional or clan2.cached_is_functional: result.cache_functional(_mo.CacheStatus.IS) if clan1.cached_is_right_functional or clan2.cached_is_right_functional: result.cache_right_functional(_mo.CacheStatus.IS) return result
def cross_right_functional_union(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the cross-right-functional union of ``clan1`` and ``clan2``. The :term:`cross-right-functional union` of two :term:`clan`\s is the :term:`cross-union` of these clans, but removing all resulting :term:`relation`\s that are not :term:`right-functional`. :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 _undef.make_or_raise_undef() if not is_member(clan2): return _undef.make_or_raise_undef() else: assert is_member(clan1) assert is_member(clan2) result = _extension.binary_extend(clan1, clan2, _functools.partial( _relations.right_functional_union, _checked=False), _checked=False) if not result.is_empty: result.cache_clan(_mo.CacheStatus.IS) result.cache_right_functional(_mo.CacheStatus.IS) if clan1.cached_is_not_functional or clan2.cached_is_not_functional: result.cache_functional(_mo.CacheStatus.IS_NOT) return result
def compose(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the 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 _undef.make_or_raise_undef() if not is_member(clan2): return _undef.make_or_raise_undef() else: assert is_member(clan1) assert is_member(clan2) result = _extension.binary_extend(clan1, clan2, _functools.partial( _relations.compose, _checked=False), _checked=False).cache_clan(_mo.CacheStatus.IS) if not result.is_empty: result.cache_clan(_mo.CacheStatus.IS) if clan1.cached_is_absolute and clan2.cached_is_absolute: result.cache_absolute(_mo.CacheStatus.IS) if clan1.cached_is_functional and clan2.cached_is_functional: result.cache_functional(_mo.CacheStatus.IS) if clan1.cached_is_right_functional and clan2.cached_is_right_functional: result.cache_right_functional(_mo.CacheStatus.IS) return result
def compose(rel1: 'P(M x M)', rel2: 'P(M x M)', _checked=True) -> 'P(M x M)': r"""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 _undef.make_or_raise_undef2(rel1) if not is_member(rel2): return _undef.make_or_raise_undef2(rel2) else: assert is_member_or_undef(rel1) assert is_member_or_undef(rel2) if rel1 is _undef.Undef() or rel2 is _undef.Undef(): return _undef.make_or_raise_undef(2) result = _extension.binary_extend(rel1, rel2, _functools.partial( _couplets.compose, _checked=False), _checked=False) if not result.is_empty: result.cache_relation(_mo.CacheStatus.IS) if rel1.cached_is_absolute and rel2.cached_is_absolute: result.cache_absolute(_mo.CacheStatus.IS) if rel1.cached_is_functional and rel2.cached_is_functional: result.cache_functional(_mo.CacheStatus.IS) if rel1.cached_is_right_functional and rel2.cached_is_right_functional: result.cache_right_functional(_mo.CacheStatus.IS) return result
def cross_intersect(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the cross-intersection of ``clan1`` and ``clan2``. The :term:`cross-intersection` of two :term:`clan`\s is a clan that contains the result of intersecting every :term:`relation` from one clan with every relation from the other clan. :return: The :term:`binary extension` of :term:`intersection` 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 _undef.make_or_raise_undef2(clan1) if not is_member(clan2): return _undef.make_or_raise_undef2(clan2) else: assert is_member_or_undef(clan1) assert is_member_or_undef(clan2) if clan1 is _undef.Undef() or clan2 is _undef.Undef(): return _undef.make_or_raise_undef(2) result = _extension.binary_extend(clan1, clan2, _functools.partial(_sets.intersect, _checked=False), _checked=False) if not result.is_empty: result.cache_clan(_mo.CacheStatus.IS) if clan1.cached_is_functional or clan2.cached_is_functional: result.cache_functional(_mo.CacheStatus.IS) if clan1.cached_is_right_functional or clan2.cached_is_right_functional: result.cache_right_functional(_mo.CacheStatus.IS) return result
def test_intersect(self): self._check_wrong_argument_types_binary(intersect) result = intersect(_set1, _set2) self.assertEqual(result, _set1i2) a_c_0 = Set([Set('a'), Set('c'), Set()]) ci = _extension.binary_extend(_ab_c, _ac_a, intersect) self.assertEqual(ci, a_c_0)
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)
def check_cols(_board, try_harder=0): """Check the columns the same way rows are checked""" if VERBOSE: print("* check_cols") # Rotate the board by swapping row and col then call check_rows swaps = clans.from_dict({'row': 'col', 'band': 'stack'}) rotated = extension.binary_extend( _board, swaps, partial(relations.swap, _checked=False)).cache_clan( CacheStatus.IS).cache_functional(CacheStatus.IS) new_board = check_rows(rotated, try_harder) if rotated is not new_board: _board = extension.binary_extend( new_board, swaps, partial(relations.swap, _checked=False) ).cache_clan(CacheStatus.IS).cache_functional(CacheStatus.IS) return _board
def test_union(self): self._check_wrong_argument_types_binary(union) result = union(_set1, _set2) self.assertEqual(result, _set1u2) abc_ab_ac = Set(Set('a', 'b', 'c'), Set('a', 'b'), Set('a', 'c')) cu = _extension.binary_extend(_ab_c, _ac_a, union) self.assertEqual(cu, abc_ab_ac)
def test_union(self): self._check_wrong_argument_types_binary(union) result = union(_set1, _set2) self.assertEqual(result, _set1u2) abc_ab_ac = Set([Set('a', 'b', 'c'), Set('a', 'b'), Set('a', 'c')]) cu = _extension.binary_extend(_ab_c, _ac_a, union) self.assertEqual(cu, abc_ab_ac)
def test_intersect(self): self._check_wrong_argument_types_binary(intersect) result = intersect(_set1, _set2) self.assertEqual(result, _set1i2) a_c_0 = Set(Set('a'), Set('c'), Set()) ci = _extension.binary_extend(_ab_c, _ac_a, intersect) self.assertEqual(ci, a_c_0)
def check_cols(_board): """Check the columns the same way rows are checked""" if verbose: print("* check_cols") # Rotate the board by swapping row and col then call check_rows swaps = clans.from_dict({'row': 'col', 'band': 'stack'}) rotated = extension.binary_extend(_board, swaps, partial(relations.swap, _checked=False) ).cache_is_clan(True).cache_is_left_functional(True) for rel in rotated: rel.cache_is_left_functional(True) new_board = check_rows(rotated) if rotated != new_board: _board = extension.binary_extend(new_board, swaps, partial(relations.swap, _checked=False) ).cache_is_clan(True).cache_is_left_functional(True) for rel in _board: rel.cache_is_left_functional(True) return _board
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 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 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 the superstriction of ``clan1`` and ``clan2``. The :term:`superstriction` of two :term:`clan`\s is a clan that contains all :term:`relation`\s from ``clan1`` that are a :term:`superset` of a relation from ``clan2``. :return: The :term:`binary extension` of :term:`superstriction` 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 clans. """ if _checked: if not is_member(clan1): return _undef.make_or_raise_undef2(clan1) if not is_member(clan2): return _undef.make_or_raise_undef2(clan2) else: assert is_member_or_undef(clan1) assert is_member_or_undef(clan2) if clan1 is _undef.Undef() or clan2 is _undef.Undef(): return _undef.make_or_raise_undef(2) result = _extension.binary_extend(clan1, clan2, _functools.partial(_sets.superstrict, _checked=False), _checked=False) if not result.is_empty: result.cache_clan(_mo.CacheStatus.IS) if clan1.cached_is_functional: result.cache_functional(_mo.CacheStatus.IS) if clan1.cached_is_right_functional: result.cache_right_functional(_mo.CacheStatus.IS) if clan1.cached_is_reflexive: result.cache_reflexive(_mo.CacheStatus.IS) if clan1.cached_is_symmetric: result.cache_symmetric(_mo.CacheStatus.IS) if clan1.cached_is_transitive: result.cache_transitive(_mo.CacheStatus.IS) if clan1.cached_is_regular: result.cache_regular(_mo.CacheStatus.IS) if clan1.cached_is_right_regular: result.cache_right_regular(_mo.CacheStatus.IS) 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 superstrict(clan1: 'PP(M x M)', clan2: 'PP(M x M)', _checked=True) -> 'PP(M x M)': r"""Return the superstriction of ``clan1`` and ``clan2``. The :term:`superstriction` of two :term:`clan`\s is a clan that contains all :term:`relation`\s from ``clan1`` that are a :term:`superset` of a relation from ``clan2``. :return: The :term:`binary extension` of :term:`superstriction` 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 clans. """ if _checked: if not is_member(clan1): return _undef.make_or_raise_undef2(clan1) if not is_member(clan2): return _undef.make_or_raise_undef2(clan2) else: assert is_member_or_undef(clan1) assert is_member_or_undef(clan2) if clan1 is _undef.Undef() or clan2 is _undef.Undef(): return _undef.make_or_raise_undef(2) result = _extension.binary_extend(clan1, clan2, _functools.partial( _sets.superstrict, _checked=False), _checked=False) if not result.is_empty: result.cache_clan(_mo.CacheStatus.IS) if clan1.cached_is_functional: result.cache_functional(_mo.CacheStatus.IS) if clan1.cached_is_right_functional: result.cache_right_functional(_mo.CacheStatus.IS) if clan1.cached_is_reflexive: result.cache_reflexive(_mo.CacheStatus.IS) if clan1.cached_is_symmetric: result.cache_symmetric(_mo.CacheStatus.IS) if clan1.cached_is_transitive: result.cache_transitive(_mo.CacheStatus.IS) if clan1.cached_is_regular: result.cache_regular(_mo.CacheStatus.IS) if clan1.cached_is_right_regular: result.cache_right_regular(_mo.CacheStatus.IS) return result
# exploit this relationship by "extending" operations on Couplets up to relations to make them useful # there. To extend a unary operation such as couplets.transpose, we apply it to every Couplet in a # relation, which results in another relation. import algebraixlib.extension as extension first_relation = Set(Couplet('a', 1), Couplet('b', 2), Couplet('c', 3)) transposed_relation = extension.unary_extend(first_relation, couplets.transpose) print("transposed_relation:", transposed_relation) # Similarly, a binary operation like couplets.composition can be extended by applying to every element # of the cross product of two relations. Notice that couplets.composition is a partial binary # operation (given two legitimate Couplets, it may be undefined). When couplets.compose(a, b) is # not defined, it simply isn't included in the membership of the resulting relation. By extending, # we have turned composition into a full binary operation in the power set algebra. second_relation = Set(Couplet('one', 'a'), Couplet('won', 'a'), Couplet('four', 'd')) composed_relation = extension.binary_extend(first_relation, second_relation, couplets.compose) empty_relation = extension.binary_extend(second_relation, first_relation, couplets.compose) # empty relation; still not commutative print("composed_relation:", composed_relation) print("empty_relation:", empty_relation) # These extended operations are defined as functions in the relations module. transpose_is_same = transposed_relation == relations.transpose(first_relation) compose_is_same = composed_relation == relations.compose(first_relation, second_relation) print("transpose_is_same:", transpose_is_same) print("compose_is_same:", compose_is_same) # The following docstring specifies a CSV table of words in various languages, with their meaning # normalized to English. vocab_csv = """word,language,meaning hello,English,salutation
def test_binary_extend_errors(self): self.assertIs(extension.binary_extend(1, 2, sets.union), Undef()) self.assertIs(extension.binary_extend(Set(1), 2, sets.union), Undef()) self.assertIs(extension.binary_extend(1, Set(2), sets.union), Undef())
# Couplet in a relation, which results in another relation. import algebraixlib.extension as extension first_relation = Set(Couplet('a', 1), Couplet('b', 2), Couplet('c', 3)) transposed_relation = extension.unary_extend(first_relation, couplets.transpose) print("transposed_relation:", transposed_relation) # Similarly, a binary operation like couplets.composition can be extended by applying to every # element of the cross product of two relations. Notice that couplets.composition is a partial # binary operation (given two legitimate Couplets, it may be undefined). When couplets.compose(a, # b) is not defined, it simply isn't included in the membership of the resulting relation. By # extending, we have turned composition into a full binary operation in the power set algebra. second_relation = Set(Couplet('one', 'a'), Couplet('won', 'a'), Couplet('four', 'd')) composed_relation = extension.binary_extend(first_relation, second_relation, couplets.compose) empty_relation = extension.binary_extend( second_relation, first_relation, couplets.compose) # empty relation; still not commutative print("composed_relation:", composed_relation) print("empty_relation:", empty_relation) # These extended operations are defined as functions in the relations module. transpose_is_same = transposed_relation == relations.transpose(first_relation) compose_is_same = composed_relation == relations.compose( first_relation, second_relation) print("transpose_is_same:", transpose_is_same) print("compose_is_same:", compose_is_same) # The following docstring specifies a CSV table of words in various languages, with their meaning # normalized to English.
def test_binary_extend_errors(self): self.assertRaises(AttributeError, lambda: extension.binary_extend(1, 2, sets.union)) self.assertRaises(AttributeError, lambda: extension.binary_extend(Set(1), 2, sets.union)) self.assertRaises(AttributeError, lambda: extension.binary_extend(1, Set(2), sets.union))