diff --git a/btypes_primitives/src/main/python_magicstack_immutable/btypes/BRelation.py b/btypes_primitives/src/main/python_magicstack_immutable/btypes/BRelation.py index d05ac35442e91bd0a328bb1c2cb32eae88460467..1c39a362029514ef78fbb8c3318bebdfcaa865e2 100644 --- a/btypes_primitives/src/main/python_magicstack_immutable/btypes/BRelation.py +++ b/btypes_primitives/src/main/python_magicstack_immutable/btypes/BRelation.py @@ -5,763 +5,717 @@ from btypes.BTuple import * from btypes.BSet import * import immutables -from copy import deepcopy from functools import reduce import random class BRelation: - def __init__(self, *args): - if len(args) == 0: - self.map = immutables.Map() - elif len(args) == 1 and type(args[0]) == immutables.Map: - self.map = args[0] - else: - self.map = immutables.Map() - for e in args: - key = e.projection1() - value = e.projection2() - _set = self.map.get(key) - if not _set: - _set = frozenset() - _set = _set.union({value}) - self.map=self.map.set(key, _set) - - @staticmethod - def fromSet(_set: 'BSet') -> 'BRelation': - result_map = immutables.Map() - for e in _set: - key = e.projection1() - value = e.projection2() - _range = result_map.get(key, None) - if _range is None: - _range = {value} - result_map = result_map.set(key, _range) - else: - _range = _range.union(frozenset([value])) - result_map = result_map.set(key, _range) - - return BRelation(result_map) - - def __eq__(self, other: 'BRelation') -> 'bool': - if self is other: - return True - if other is None or type(self) != type(other): - return False - if not self.map == other.map: - return False - return True - - def equals(self, other): - return self.__eq__(other) - - def __hash__(self): - return hash(frozenset(self.map)) - - def intersect(self, relation: 'BRelation') -> 'BRelation': - other_map = relation.map - other_domain = set(relation.map.keys()) - this_domain = set(self.map.keys()) - intersection_domain = this_domain.intersection(other_domain) - difference_domain = this_domain.difference(other_domain) - - result_map = self.map - for obj in intersection_domain: - domain_element = obj - this_range_set = self.map[domain_element] - other_range_set = other_map[domain_element] - result_map = result_map.set(domain_element, this_range_set.union(other_range_set)) - - for obj in difference_domain: - domain_element = obj - result_map = result_map.delete(domain_element) - - return BRelation(result_map) - - def difference(self, relation: 'BRelation') -> 'BRelation': - other_map = relation.map - other_domain = set(other_map.keys()) - this_domain = set(self.map.keys()) - difference_domain = this_domain.difference(other_domain) - rest_domain = this_domain.difference(difference_domain) - - result_map = self.map - for obj in difference_domain: - domain_element = obj - this_range_set = self.map[domain_element] - other_range_set = other_map[domain_element] - result_map = result_map.set(domain_element, this_range_set.difference(other_range_set)) - - for obj in rest_domain: - domain_element = obj - result_map = result_map.delete(domain_element) - - return BRelation(result_map) - - def union(self, relation: 'BRelation') -> 'BRelation': - other_map = relation.map - other_domain = other_map.keys() - - result_map = deepcopy(self.map) - for obj in other_domain: - domain_element = obj - this_range_set = self.map.get(domain_element) - other_range_set = relation.map.get(domain_element, None) - if this_range_set is None: - this_range_set = set() - result_map = result_map.set(domain_element, this_range_set.union(other_range_set)) - - return BRelation(result_map) - - def size(self) -> 'int': - size = 0 - this_domain = self.map.keys() - - for obj in this_domain: - domain_element = obj - this_range_set = self.map[domain_element] - size += len(this_range_set) - - return size - - def card(self) -> 'BInteger': - return BInteger(self.size()) - - def _size(self) -> 'BInteger': - return BInteger(self.size()) - - def equal(self, other: 'BRelation') -> 'BBoolean': - return BBoolean(self.equals(other)) - - def unequal(self, other: 'BRelation') -> 'BBoolean': - return BBoolean(not self.equals(other)) - - def elementOf(self, obj: 'BTuple') -> 'BBoolean': - prj1 = obj.projection1() - prj2 = obj.projection2() - - domain = self.map - - if prj1 not in domain: - return BBoolean(False) - - _range = self.map[prj1] - - return BBoolean(prj2 in _range) - - def notElementOf(self, obj: 'BTuple') -> 'BBoolean': - prj1 = obj.projection1() - prj2 = obj.projection2() - - domain = self.map.keys() - - if prj1 not in domain: - return BBoolean(True) - - _range = self.map[prj1] - - return BBoolean(prj2 not in _range) - - def relationImage(self, domain: 'BSet') -> 'BSet': - result_set = set() - for domain_element in domain: - this_range_set = self.map.get(domain_element) - if this_range_set is None: - continue - result_set = result_set.union(this_range_set) - return BSet(*result_set) - - def functionCall(self, arg): - _range = self.map.get(arg) - if _range is None: - raise Exception("Argument is not in the domain of this relation") - - for element in _range: - return element - raise Exception("Argument is not in the domain of this relation") - - def pow(self) -> 'BSet': - this_map = self.map - this_domain = this_map.keys() - - start = BRelation() - queue = [start] - result = BSet(start) - while not len(queue) == 0: - current_set = queue.pop(0) - - for e1 in this_domain: - domain_element = e1 - _range = this_map[domain_element] - for e2 in _range: - range_element = e2 - next_relation = current_set.union(BRelation.fromSet(BSet(BTuple(domain_element, range_element)))) - previous_size = result.size() - result = result.union(BSet(next_relation)) - if previous_size < result.size(): - queue.append(next_relation) - - return result - - def pow1(self) -> 'BSet': - return self.pow().difference(BSet(BRelation())) - - def fin(self) -> 'BSet': - return self.pow() - - def fin1(self) -> 'BSet': - return self.pow1() - - def domain(self) -> 'BSet': - this_map = self.map - _set = self.map.keys() - result_set = _set - for obj in _set: - domain_element = obj - _range = this_map[domain_element] - if len(_range) == 0: - result_set = result_set.difference([domain_element]) - return BSet(*list(result_set)) - - def _range(self) -> 'BSet': - _set = reduce(lambda a, b: a.union(b), self.map.values(), set()) - return BSet(*list(_set)) - - def inverse(self) -> 'BRelation': - this_map = self.map - keys = this_map.keys() - - result_map = immutables.Map() - for e1 in keys: - domain_element = e1 - _range = this_map[domain_element] - for e2 in _range: - range_element = e2 - current_range = result_map.get(range_element) - if current_range is None: - current_range = set() - current_range = current_range.union([domain_element]) - result_map = result_map.set(range_element, current_range) - return BRelation(result_map) - - def domainRestriction(self, arg: 'BSet') -> 'BRelation': - _set = set(self.map.keys()) - other_set = arg.getSet() - result_set = _set.difference(other_set) - result_map = self.map - for obj in result_set: - result_map = result_map.delete(obj) - return BRelation(result_map) - - def domainSubstraction(self, arg: 'BSet') -> 'BRelation': - _set = self.map.keys() - other_set = arg.getSet() - result_map = self.map - for obj in other_set: - if obj in result_map: - result_map = result_map.delete(obj) - return BRelation(result_map) - - def rangeRestriction(self, arg: 'BSet') -> 'BRelation': - other_set = arg.getSet() - this_domain = self.map.keys() - - result_map = self.map - for obj in this_domain: - domain_element = obj - this_range_set = self.map[domain_element] - result_map = result_map.set(domain_element, this_range_set.intersection(other_set)) - return BRelation(result_map) - - def rangeSubstraction(self, arg: 'BSet') -> 'BRelation': - other_set = arg.getSet() - this_domain = self.map.keys() - - result_map = self.map - for obj in this_domain: - domain_element = obj - this_range_set = self.map[domain_element] - result_map = result_map.set(domain_element, this_range_set.difference(other_set)) - return BRelation(result_map) - - def override(self, arg: 'BRelation') -> 'BRelation': - other_map = arg.map - - other_domain = other_map.keys() - - result_map = self.map - for obj in other_domain: - domain_element = obj - _range = other_map[domain_element] - result_map = result_map.set(domain_element, _range) - - return BRelation(result_map) - - def first(self): - return self.functionCall(BInteger(1)) - - def last(self): - return self.functionCall(self.card()) - - def reverse(self) -> 'BRelation': - size = self.card() - result_map = immutables.Map() - for i in map(BInteger, range(1, size.intValue() + 1)): - range_element = self.functionCall(size.minus(i).succ()) - result_map = result_map.set(i, frozenset([range_element])) - return BRelation(result_map) - - def front(self) -> 'BRelation': - return self.domainSubstraction(BSet(self.card())) - - def tail(self) -> 'BRelation': - size = self._size().intValue() - result_map = immutables.Map() - for i in map(BInteger, range(2, size+1)): - range_element = self.functionCall(i) - result_map = result_map.set(i.pred(), frozenset([range_element])) - return BRelation(result_map) - - def take(self, n: 'BInteger') -> 'BRelation': - size = self._size() - if n.greaterEqual(size).booleanValue(): - return BRelation(self.map) - result_map = self.map - # Remove sets with index greater than n - i: BInteger - for i in map(BInteger, range(n.intValue() + 1, size.intValue() + 1)): - result_map = result_map.delete(i) - return BRelation(result_map) - - def drop(self, n: 'BInteger') -> 'BRelation': - size = self._size().intValue() - this_map = self.map - result_map = immutables.Map() - for i in map(BInteger, range(n.intValue() + 1, size + 1)): - current_set = this_map[i] - result_map = result_map.set(i.minus(n), current_set) - return BRelation(result_map) - - def concat(self, arg: 'BRelation') -> 'BRelation': - result_map = self.map - other_map = arg.map - size = self.card() - i: BInteger - for i in map(BInteger, range(1, arg._size().intValue() + 1)): - result_map = result_map.set(size.plus(i), other_map[i]) - return BRelation(result_map) - - def conc(self) -> 'BRelation': - result = BRelation() - size = self.card().intValue() - for i in map(BInteger, range(1, size + 1)): - result = result.concat(self.functionCall(i)) - return result - - def append(self, arg) -> 'BRelation': - result_map = self.map - result_map = result_map.set(self.card().succ(), frozenset([arg])) - return BRelation(result_map) - - def prepend(self, arg) -> 'BRelation': - result_map = immutables.Map() - this_map = self.map - size = self._size().intValue() - for i in map(BInteger, range(1, size + 1)): - result_map = result_map.set(i.succ(), this_map.get(i)) - result_map = result_map.set(BInteger(1), frozenset([arg])) - return BRelation(result_map) - - def directProduct(self, arg: 'BRelation') -> 'BRelation': - this_map = self.map - this_domain = this_map.keys() - other_map = arg.map - - result_map = immutables.Map() - for obj in this_domain: - domain_element = obj - this_range = this_map.get(domain_element, None) - other_range = other_map.get(domain_element, None) - if other_range is None: - continue - result_range = set() - for lhs in this_range: - for rhs in other_range: - lhs_element = lhs - rhs_element = rhs - result_range = result_range.union([BTuple(lhs_element, rhs_element)]) - result_map = result_map.set(domain_element, result_range) - return BRelation(result_map) - - def parallelProduct(self, arg: 'BRelation') -> 'BRelation': - this_map = self.map - this_domain = this_map.keys() - - other_map = arg.map - other_domain = other_map.keys() - - result_map = immutables.Map() - - for domain_elementThis in this_domain: - for domaineElementOther in other_domain: - domain_element_this_element = domain_elementThis - domain_element_other_element = domaineElementOther - - this_range = this_map[domain_element_this_element] - other_range = other_map[domain_element_other_element] - - result_range = set() - for lhs in this_range: - for rhs in other_range: - lhs_element = lhs - rhs_element = rhs - result_range = result_range.union([BTuple(lhs_element, rhs_element)]) - _tuple = BTuple(domain_element_this_element, domain_element_other_element) - result_map = result_map.set(_tuple, result_range) - return BRelation(result_map) - - def composition(self, arg: 'BRelation') -> 'BRelation': - this_map = self.map - other_map = arg.map - - this_domain = this_map.keys() - - result_map = immutables.Map() - - for e1 in this_domain: - domain_element = e1 - _range = this_map[domain_element] - - _set = set() - for e2 in _range: - range_element = e2 - union_element = other_map.get(range_element) - if union_element is None: - union_element = set() - _set = _set.union(union_element) - result_map = result_map.set(domain_element, _set) - return BRelation(result_map) - - def iterate(self, n: 'BInteger') -> 'BRelation': - this_relation = self - result = self.identity(self.domain()) - for _ in map(BInteger, range(1, n.intValue() + 1)): - result = result.union(result.composition(this_relation)) - return result - - def closure(self) -> 'BRelation': - this_relation = self - result = self.identity(self.domain()) - next_result = result.composition(this_relation) - while True: - last_result = deepcopy(result) - result = result.union(next_result) - next_result = result.composition(this_relation) - if result.equal(last_result).booleanValue(): - break - return result - - def closure1(self) -> 'BRelation': - this_relation = self - result = self - next_result = result.composition(this_relation) - while True: - last_result = deepcopy(result) - result = result.union(next_result) - next_result = result.composition(this_relation) - if result.equal(last_result).booleanValue(): - break - return result - - @staticmethod - def projection1(arg1: 'BSet', arg2: 'BSet') -> 'BRelation': - arg_set_1 = arg1.getSet() - arg_set_2 = arg2.getSet() - - result_map = immutables.Map() - for e1 in arg_set_1: - for e2 in arg_set_2: - element1 = e1 - element2 = e2 - - _tuple = BTuple(element1, element2) - result_map = result_map.set(_tuple, frozenset([element1])) - return BRelation(result_map) - - @staticmethod - def projection2(arg1: 'BSet', arg2: 'BSet') -> 'BRelation': - arg_set_1 = arg1.getSet() - arg_set_2 = arg2.getSet() - - result_map = immutables.Map() - for e1 in arg_set_1: - for e2 in arg_set_2: - element1 = e1 - element2 = e2 - - _tuple = BTuple(element1, element2) - result_map = result_map.set(_tuple, frozenset([element2])) - return BRelation(result_map) - - def fnc(self) -> 'BRelation': - this_map = self.map - domain = self.domain().getSet() - - result_map = immutables.Map() - for e in domain: - domain_element = e - _range = this_map[e] - range_set = BSet(_range) - result_map = result_map.set(domain_element, frozenset([range_set])) - return BRelation(result_map) - - def rel(self) -> 'BRelation': - domain = self.domain() - - result_map = immutables.Map() - for domain_element in domain: - _range = self.functionCall(domain_element) - range_set = _range.getSet() - result_map = result_map.set(domain_element, range_set) - return BRelation(result_map) - - @staticmethod - def identity(arg: 'BSet') -> 'BRelation': - result_map = immutables.Map() - for e in arg: - result_map = result_map.set(e, frozenset([e])) - return BRelation(result_map) - - @staticmethod - def cartesianProduct(arg1: 'BSet', arg2: 'BSet') -> 'BRelation': - result_map = immutables.Map() - for e1 in arg1: - result_map = result_map.set(e1, arg2.getSet()) - return BRelation(result_map) - - def nondeterminism(self) -> 'BTuple': - domain = self.map.keys() - - index = random.choice(range(len(domain))) - i = 0 - domain_element = None - for obj in domain: - if i == index: - domain_element = obj - break - i = i + 1 - - _range = self.map[domain_element] - index = random.choice(range(_range.size())) - i = 0 - for obj in _range: - if i == index: - return BTuple(domain_element, obj) - i = i + 1 - return None - - def isTotal(self, domain: 'BSet'): - return self.domain().equal(domain) - - def isTotalInteger(self) -> 'BBoolean': - return BBoolean(False) - - def isTotalNatural(self) -> 'BBoolean': - return BBoolean(False) - - def isTotalNatural1(self) -> 'BBoolean': - return BBoolean(False) - - def isTotalString(self) -> 'BBoolean': - return BBoolean(False) - - def isTotalStruct(self) -> 'BBoolean': - return BBoolean(False) - - def isPartial(self, domain: 'BSet'): - return self.domain().strictSubset(domain) - - def isPartialInteger(self): - for e in self.domain(): - if(isinstance(e, BInteger)): - return BBoolean(True) - else: - return BBoolean(False) - return BBoolean(True) - - def isPartialNatural(self): - for e in self.domain(): - if(isinstance(e, BInteger) and not e.isNatural().booleanValue()): - return BBoolean(False) - return BBoolean(True) - - def isPartialNatural1(self): - for e in self.domain(): - if isinstance(e, BInteger) and not e.isNatural1().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def isPartialString(self): - for e in self.domain(): - if isinstance(e, BString) and not e.isString().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def isPartialStruct(self): - for e in self.domain(): - if isinstance(e, BStruct) and not e.isRecord().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def checkDomain(self, domain: 'BSet'): - return self.domain().subset(domain) - - def checkDomainInteger(self): - for e in self.domain(): - if isinstance(e, BInteger): - return BBoolean(True) - else: - return BBoolean(False) - return BBoolean(True) - - def checkDomainNatural(self): - for e in self.domain(): - if isinstance(e, BInteger) and not e.isNatural().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def checkDomainNatural1(self): - for e in self.domain(): - if isinstance(e, BInteger) and not e.isNatural1().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def checkDomainString(self): - for e in self.domain(): - if isinstance(e, BString) and not e.isString().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def checkDomainStruct(self): - for e in self.domain(): - if isinstance(e, BStruct) and not e.isRecord().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def checkRange(self, _range: 'BSet'): - return self._range().subset(_range) - - def checkRangeInteger(self): - for e in self._range(): - if isinstance(e, BInteger): - return BBoolean(True) - else: - return BBoolean(False) - return BBoolean(True) - - def checkRangeNatural(self): - for e in self._range(): - if isinstance(e, BInteger) and not e.isNatural().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def checkRangeNatural1(self): - for e in self._range(): - if isinstance(e, BInteger) and not e.isNatural1().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def checkRangeString(self): - for e in self._range(): - if isinstance(e, BString) and not e.isString().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def checkRangeStruct(self) -> 'BBoolean': - for e in self._range(): - if isinstance(e, BStruct) and not e.isRecord().booleanValue(): - return BBoolean(False) - return BBoolean(True) - - def isRelation(self) -> 'BBoolean': - return BBoolean(True) - - def isFunction(self) -> 'BBoolean': - for element in self.domain(): - _range = self.map[element] - if _range.size() > 1: - return BBoolean(False) - return BBoolean(True) - - def isSurjection(self, _range: 'BSet'): - return self._range().equal(_range) - - def isSurjectionInteger(self) -> 'BBoolean': - return BBoolean(False) - - def isSurjectionNatural(self) -> 'BBoolean': - return BBoolean(False) - - def isSurjectionNatural1(self) -> 'BBoolean': - return BBoolean(False) - - def isSurjectionString(self) -> 'BBoolean': - return BBoolean(False) - - def isSurjectionStruct(self) -> 'BBoolean': - return BBoolean(False) - - def isInjection(self) -> 'BBoolean': - visited = set() - for element in self.domain(): - _range = self.map[element] - for e in _range: - range_element = e - if range_element in visited: - return BBoolean(False) - visited = visited.union([range_element]) - return BBoolean(True) - - def isBijection(self, _range: 'BSet'): - return self.isSurjection(_range) and self.isInjection() - - def isBijectionInteger(self) -> 'BBoolean': - return BBoolean(False) - - def isBijectionNatural(self) -> 'BBoolean': - return BBoolean(False) - - def isBijectionNatural1(self) -> 'BBoolean': - return BBoolean(False) - - def isBijectionString(self) -> 'BBoolean': - return BBoolean(False) - - def isBijectionStruct(self) -> 'BBoolean': - return BBoolean(False) - - def __str__(self) -> 'str': - - this_map = self.map - domain = this_map.keys() - - size = self.size() - i = 0 - - sb = "{" - for e1 in domain: - domain_element = e1 - _range = this_map[domain_element] - for e2 in _range: - range_element = e2 - sb += "(" - sb += str(domain_element) - sb += " |-> " - sb += str(range_element) - sb += ")" - if i+1 < size: - sb += ", " - i = i + 1 - sb += "}" - return sb + def __init__(self, *args): + if len(args) == 0: + self.map = immutables.Map() + elif len(args) == 1 and type(args[0]) == immutables.Map: + self.map = args[0] + else: + self.map = immutables.Map() + for e in args: + key = e.projection1() + value = e.projection2() + _set = self.map.get(key) + if not _set: + _set = immutables.Map() + _set = _set.set(value, value) + self.map = self.map.set(key, _set) + + @staticmethod + def fromSet(_set: 'BSet') -> 'BRelation': + result_map = immutables.Map() + for e in _set: + key = e.projection1() + value = e.projection2() + _range = result_map.get(key, None) + if _range is None: + _range = immutables.Map({value: value}) + result_map = result_map.set(key, _range) + else: + _range = _range.set(value, value) + result_map = result_map.set(key, _range) + + return BRelation(result_map) + + def __eq__(self, other: 'BRelation') -> 'bool': + if self is other: + return True + if other is None or type(self) != type(other): + return False + if not self.map == other.map: + return False + return True + + def equals(self, other): + return self.__eq__(other) + + def __hash__(self): + return hash(self.map) + + def intersect(self, relation: 'BRelation') -> 'BRelation': + this_map = self.map + other_map = relation.map + # Remove all elements not in other domain + result_map = reduce(lambda current_map, el: current_map.delete(el) if el not in other_map else current_map, + this_map, this_map) + # Trim range for all elements to match other range + for obj in result_map: + this_range = result_map[obj] + other_range = other_map[obj] + result_map = result_map.set(obj, reduce( + lambda current_range, el: current_range.delete(el) if el not in other_range else current_range, + this_range, this_range)) + return BRelation(result_map) + + def difference(self, relation: 'BRelation') -> 'BRelation': + this_map = self.map + other_map = relation.map + # Remove all elements not in other domain + result_map = reduce(lambda current_map, el: current_map.delete(el) if el not in other_map else current_map, + this_map, this_map) + # Remove all elements in other range + for obj in result_map: + this_range = result_map[obj] + other_range = other_map[obj] + result_map = result_map.set(obj, reduce( + lambda current_range, el: current_range.delete(el) if el in other_range else current_range, + this_range, this_range)) + return BRelation(result_map) + + def union(self, relation: 'BRelation') -> 'BRelation': + other_map = relation.map + result_map = self.map + for domain_element in other_map: + this_range_set = self.map.get(domain_element) + other_range_set = other_map.get(domain_element, None) + if other_range_set is None: + continue + if this_range_set is None: + this_range_set = immutables.Map() + for element in other_range_set: + this_range_set = this_range_set.set(element, element) + result_map = result_map.set(domain_element, this_range_set) + + return BRelation(result_map) + + def size(self) -> 'int': + size = 0 + this_map = self.map + + for domain_element in this_map: + size += len(this_map[domain_element]) + + return size + + def card(self) -> 'BInteger': + return BInteger(self.size()) + + def _size(self) -> 'BInteger': + return BInteger(self.size()) + + def equal(self, other: 'BRelation') -> 'BBoolean': + return BBoolean(self.equals(other)) + + def unequal(self, other: 'BRelation') -> 'BBoolean': + return BBoolean(not self.equals(other)) + + def elementOf(self, obj: 'BTuple') -> 'BBoolean': + prj1 = obj.projection1() + prj2 = obj.projection2() + + domain = self.map + + if prj1 not in domain: + return BBoolean(False) + + return BBoolean(prj2 in domain[prj1]) + + def notElementOf(self, obj: 'BTuple') -> 'BBoolean': + prj1 = obj.projection1() + prj2 = obj.projection2() + + domain = self.map + + if prj1 not in domain: + return BBoolean(True) + + return BBoolean(prj2 not in domain[prj1]) + + def relationImage(self, domain: 'BSet') -> 'BSet': + result_set = immutables.Map() + this_map = self.map + for domain_element in domain: + this_range_set = this_map.get(domain_element) + if this_range_set is None: + continue + for element in this_range_set: + result_set = result_set.set(element, element) + return BSet(result_set) + + def functionCall(self, arg): + _range = self.map.get(arg) + if _range is None: + raise Exception("Argument is not in the domain of this relation") + + for element in _range: + return element + raise Exception("Argument is not in the domain of this relation") + + def pow(self) -> 'BSet': + this_map = self.map + + start = BRelation() + queue = [start] + result = BSet(start) + while not len(queue) == 0: + current_set = queue.pop(0) + + for domain_element in this_map: + _range = this_map[domain_element] + for range_element in _range: + next_relation = current_set.union(BRelation.fromSet(BSet(BTuple(domain_element, range_element)))) + previous_size = result.size() + result = result.union(BSet(next_relation)) + if previous_size < result.size(): + queue.append(next_relation) + + return result + + def pow1(self) -> 'BSet': + return self.pow().difference(BSet(BRelation())) + + def fin(self) -> 'BSet': + return self.pow() + + def fin1(self) -> 'BSet': + return self.pow1() + + def domain(self) -> 'BSet': + this_map = self.map + result_map = this_map + for domain_element in this_map: + _range = this_map[domain_element] + if len(_range) == 0: + result_map = result_map.delete(domain_element) + return BSet(result_map) + + def _range(self) -> 'BSet': + _range = reduce(lambda a, b: a.update(b), self.map.values(), immutables.Map()) + return BSet(_range) + + def inverse(self) -> 'BRelation': + this_map = self.map + keys = this_map.keys() + + result_map = immutables.Map() + for e1 in keys: + domain_element = e1 + _range = this_map[domain_element] + for e2 in _range: + range_element = e2 + current_range = result_map.get(range_element) + if current_range is None: + current_range = immutables.Map() + current_range = current_range.set(domain_element, domain_element) + result_map = result_map.set(range_element, current_range) + return BRelation(result_map) + + def domainRestriction(self, arg: 'BSet') -> 'BRelation': + result_map = self.map + for obj in result_map: + if not obj in arg: + result_map = result_map.delete(obj) + return BRelation(result_map) + + def domainSubstraction(self, arg: 'BSet') -> 'BRelation': + result_map = self.map + for obj in arg: + if obj in result_map: + result_map = result_map.delete(obj) + return BRelation(result_map) + + def rangeRestriction(self, arg: 'BSet') -> 'BRelation': + other_set = arg.getSet() + this_domain = self.map + + result_map = self.map + for domain_element in this_domain: + this_range_set = self.map[domain_element] + + # Intersection of sets + this_range_set = reduce(lambda current_set, el: current_set.delete(el) if el not in other_set else current_set, this_range_set, this_range_set) + + result_map = result_map.set(domain_element, this_range_set) + return BRelation(result_map) + + def rangeSubstraction(self, arg: 'BSet') -> 'BRelation': + other_set = arg.getSet() + this_domain = self.map + + result_map = self.map + for domain_element in this_domain: + this_range_set = self.map[domain_element] + + # Difference of sets + this_range_set = reduce(lambda current_set, el: current_set.delete(el) if el in this_range_set else current_set, + other_set, this_range_set) + result_map = result_map.set(domain_element, this_range_set) + return BRelation(result_map) + + def override(self, arg: 'BRelation') -> 'BRelation': + other_map = arg.map + result_map = self.map + + for domain_element in other_map: + _range = other_map[domain_element] + result_map = result_map.set(domain_element, _range) + + return BRelation(result_map) + + def first(self): + return self.functionCall(BInteger(1)) + + def last(self): + return self.functionCall(self.card()) + + def reverse(self) -> 'BRelation': + size = self.card() + result_map = immutables.Map() + for i in map(BInteger, range(1, size.intValue() + 1)): + range_element = self.functionCall(size.minus(i).succ()) + result_map = result_map.set(i, immutables.Map({range_element: range_element})) + return BRelation(result_map) + + def front(self) -> 'BRelation': + return self.domainSubstraction(BSet(self.card())) + + def tail(self) -> 'BRelation': + size = self._size().intValue() + result_map = immutables.Map() + for i in map(BInteger, range(2, size + 1)): + range_element = self.functionCall(i) + result_map = result_map.set(i.pred(), immutables.Map({range_element: range_element})) + return BRelation(result_map) + + def take(self, n: 'BInteger') -> 'BRelation': + size = self._size() + if n.greaterEqual(size).booleanValue(): + return BRelation(self.map) + result_map = self.map + # Remove sets with index greater than n + i: BInteger + for i in map(BInteger, range(n.intValue() + 1, size.intValue() + 1)): + result_map = result_map.delete(i) + return BRelation(result_map) + + def drop(self, n: 'BInteger') -> 'BRelation': + size = self._size().intValue() + this_map = self.map + result_map = immutables.Map() + for i in map(BInteger, range(n.intValue() + 1, size + 1)): + current_set = this_map[i] + result_map = result_map.set(i.minus(n), current_set) + return BRelation(result_map) + + def concat(self, arg: 'BRelation') -> 'BRelation': + result_map = self.map + other_map = arg.map + size = self.card() + for i in map(BInteger, range(1, arg._size().intValue() + 1)): + result_map = result_map.set(size.plus(i), other_map[i]) + return BRelation(result_map) + + def conc(self) -> 'BRelation': + result = BRelation() + size = self.card().intValue() + for i in map(BInteger, range(1, size + 1)): + result = result.concat(self.functionCall(i)) + return result + + def append(self, arg) -> 'BRelation': + result_map = self.map + result_map = result_map.set(self.card().succ(), immutables.Map({arg: arg})) + return BRelation(result_map) + + def prepend(self, arg) -> 'BRelation': + result_map = immutables.Map() + this_map = self.map + size = self._size().intValue() + for i in map(BInteger, range(1, size + 1)): + result_map = result_map.set(i.succ(), this_map.get(i)) + result_map = result_map.set(BInteger(1), immutables.Map({arg: arg})) + return BRelation(result_map) + + def directProduct(self, arg: 'BRelation') -> 'BRelation': + this_map = self.map + other_map = arg.map + + result_map = immutables.Map() + for domain_element in this_map: + other_range = other_map.get(domain_element) + if other_range is None: + continue + this_range = this_map.get(domain_element) + result_range = immutables.Map() + for lhs in this_range: + for rhs in other_range: + _tuple = BTuple(lhs, rhs) + result_range = result_range.set(_tuple, _tuple) + result_map = result_map.set(domain_element, result_range) + return BRelation(result_map) + + def parallelProduct(self, arg: 'BRelation') -> 'BRelation': + this_map = self.map + other_map = arg.map + result_map = immutables.Map() + + for domain_elementThis in this_map: + for domaineElementOther in other_map: + + this_range = this_map[domain_elementThis] + other_range = other_map[domaineElementOther] + result_range = immutables.Map() + + for lhs in this_range: + for rhs in other_range: + pair_tuple = BTuple(lhs, rhs) + result_range = result_range.set(pair_tuple, pair_tuple) + _tuple = BTuple(domain_elementThis, domaineElementOther) + result_map = result_map.set(_tuple, result_range) + return BRelation(result_map) + + def composition(self, arg: 'BRelation') -> 'BRelation': + this_map = self.map + other_map = arg.map + + result_map = immutables.Map() + + for domain_element in this_map: + _range = this_map[domain_element] + + _set = immutables.Map() + for range_element in _range: + union_element = other_map.get(range_element) + if union_element is None: + continue + for element in union_element: + _set = _set.set(element, element) + result_map = result_map.set(domain_element, _set) + return BRelation(result_map) + + def iterate(self, n: 'BInteger') -> 'BRelation': + this_relation = self + result = self.identity(self.domain()) + for _ in range(1, n.intValue() + 1): + result = result.union(result.composition(this_relation)) + return result + + def closure(self) -> 'BRelation': + result = self.identity(self.domain()) + next_result = result.composition(self) + while True: + last_result = result + result = result.union(next_result) + next_result = result.composition(self) + if result.equal(last_result).booleanValue(): + break + return result + + def closure1(self) -> 'BRelation': + result = self + next_result = result.composition(self) + while True: + last_result = result + result = result.union(next_result) + next_result = result.composition(self) + if result.equal(last_result).booleanValue(): + break + return result + + @staticmethod + def projection1(arg1: 'BSet', arg2: 'BSet') -> 'BRelation': + arg_set_1 = arg1.getSet() + arg_set_2 = arg2.getSet() + + result_map = immutables.Map() + for element1 in arg_set_1: + element1_tuple = immutables.Map({element1: element1}) + for element2 in arg_set_2: + _tuple = BTuple(element1, element2) + result_map = result_map.set(_tuple, element1_tuple) + return BRelation(result_map) + + @staticmethod + def projection2(arg1: 'BSet', arg2: 'BSet') -> 'BRelation': + arg_set_1 = arg1.getSet() + arg_set_2 = arg2.getSet() + + result_map = immutables.Map() + for element2 in arg_set_2: + element2_tuple = immutables.Map({element2: element2}) + for element1 in arg_set_1: + _tuple = BTuple(element1, element2) + result_map = result_map.set(_tuple, element2_tuple) + return BRelation(result_map) + + def fnc(self) -> 'BRelation': + this_map = self.map + domain = self.domain().getSet() + + result_map = immutables.Map() + for domain_element in domain: + _range = this_map[domain_element] + range_set = BSet(_range) + result_map = result_map.set(domain_element, immutables.Map({range_set: range_set})) + return BRelation(result_map) + + def rel(self) -> 'BRelation': + domain = self.domain() + + result_map = immutables.Map() + for domain_element in domain: + _range = self.functionCall(domain_element) + range_set = _range.getSet() + result_map = result_map.set(domain_element, range_set) + return BRelation(result_map) + + @staticmethod + def identity(arg: 'BSet') -> 'BRelation': + result_map = immutables.Map() + for e in arg: + result_map = result_map.set(e, immutables.Map({e: e})) + return BRelation(result_map) + + @staticmethod + def cartesianProduct(arg1: 'BSet', arg2: 'BSet') -> 'BRelation': + result_map = immutables.Map() + for e1 in arg1: + result_map = result_map.set(e1, arg2.getSet()) + return BRelation(result_map) + + def nondeterminism(self) -> 'BTuple': + index = random.choice(range(len(self.map))) + i = 0 + domain_element = None + for obj in self.map: + if i == index: + domain_element = obj + break + i = i + 1 + + _range = self.map[domain_element] + index = random.choice(range(_range.size())) + i = 0 + for obj in _range: + if i == index: + return BTuple(domain_element, obj) + i = i + 1 + return None + + def isTotal(self, domain: 'BSet'): + return self.domain().equal(domain) + + def isTotalInteger(self) -> 'BBoolean': + return BBoolean(False) + + def isTotalNatural(self) -> 'BBoolean': + return BBoolean(False) + + def isTotalNatural1(self) -> 'BBoolean': + return BBoolean(False) + + def isTotalString(self) -> 'BBoolean': + return BBoolean(False) + + def isTotalStruct(self) -> 'BBoolean': + return BBoolean(False) + + def isPartial(self, domain: 'BSet'): + return self.domain().strictSubset(domain) + + def isPartialInteger(self): + for e in self.domain(): + if (isinstance(e, BInteger)): + return BBoolean(True) + else: + return BBoolean(False) + return BBoolean(True) + + def isPartialNatural(self): + for e in self.domain(): + if (isinstance(e, BInteger) and not e.isNatural().booleanValue()): + return BBoolean(False) + return BBoolean(True) + + def isPartialNatural1(self): + for e in self.domain(): + if isinstance(e, BInteger) and not e.isNatural1().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def isPartialString(self): + for e in self.domain(): + if isinstance(e, BString) and not e.isString().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def isPartialStruct(self): + for e in self.domain(): + if isinstance(e, BStruct) and not e.isRecord().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def checkDomain(self, domain: 'BSet'): + return self.domain().subset(domain) + + def checkDomainInteger(self): + for e in self.domain(): + if isinstance(e, BInteger): + return BBoolean(True) + else: + return BBoolean(False) + return BBoolean(True) + + def checkDomainNatural(self): + for e in self.domain(): + if isinstance(e, BInteger) and not e.isNatural().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def checkDomainNatural1(self): + for e in self.domain(): + if isinstance(e, BInteger) and not e.isNatural1().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def checkDomainString(self): + for e in self.domain(): + if isinstance(e, BString) and not e.isString().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def checkDomainStruct(self): + for e in self.domain(): + if isinstance(e, BStruct) and not e.isRecord().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def checkRange(self, _range: 'BSet'): + return self._range().subset(_range) + + def checkRangeInteger(self): + for e in self._range(): + if isinstance(e, BInteger): + return BBoolean(True) + else: + return BBoolean(False) + return BBoolean(True) + + def checkRangeNatural(self): + for e in self._range(): + if isinstance(e, BInteger) and not e.isNatural().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def checkRangeNatural1(self): + for e in self._range(): + if isinstance(e, BInteger) and not e.isNatural1().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def checkRangeString(self): + for e in self._range(): + if isinstance(e, BString) and not e.isString().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def checkRangeStruct(self) -> 'BBoolean': + for e in self._range(): + if isinstance(e, BStruct) and not e.isRecord().booleanValue(): + return BBoolean(False) + return BBoolean(True) + + def isRelation(self) -> 'BBoolean': + return BBoolean(True) + + def isFunction(self) -> 'BBoolean': + for element in self.domain(): + _range = self.map[element] + if _range.size() > 1: + return BBoolean(False) + return BBoolean(True) + + def isSurjection(self, _range: 'BSet'): + return self._range().equal(_range) + + def isSurjectionInteger(self) -> 'BBoolean': + return BBoolean(False) + + def isSurjectionNatural(self) -> 'BBoolean': + return BBoolean(False) + + def isSurjectionNatural1(self) -> 'BBoolean': + return BBoolean(False) + + def isSurjectionString(self) -> 'BBoolean': + return BBoolean(False) + + def isSurjectionStruct(self) -> 'BBoolean': + return BBoolean(False) + + def isInjection(self) -> 'BBoolean': + visited = immutables.Map() + for element in self.domain(): + _range = self.map[element] + for e in _range: + range_element = e + if range_element in visited: + return BBoolean(False) + visited = visited.set(range_element, range_element) + return BBoolean(True) + + def isBijection(self, _range: 'BSet'): + return self.isSurjection(_range) and self.isInjection() + + def isBijectionInteger(self) -> 'BBoolean': + return BBoolean(False) + + def isBijectionNatural(self) -> 'BBoolean': + return BBoolean(False) + + def isBijectionNatural1(self) -> 'BBoolean': + return BBoolean(False) + + def isBijectionString(self) -> 'BBoolean': + return BBoolean(False) + + def isBijectionStruct(self) -> 'BBoolean': + return BBoolean(False) + + def __str__(self) -> 'str': + + this_map = self.map + + size = self.size() + i = 0 + + sb = "{" + for domain_element in this_map: + _range = this_map[domain_element] + for range_element in _range: + sb += "(" + sb += str(domain_element) + sb += " |-> " + sb += str(range_element) + sb += ")" + if i + 1 < size: + sb += ", " + i = i + 1 + sb += "}" + return sb