def endless_recursion_exists(head: Atom, body: Body) -> bool: for literal in body.get_literals(): if head.get_predicate() == literal.get_predicate(): if literal.get_variables()[0] == head.get_variables()[0]: return True return False return False
def get_recursive_calls_amount(head: Atom, body: Body) -> int: rec_count = 0 for predicate in _get_body_predicates_list(body): if head.get_predicate() == predicate: rec_count += 1 return rec_count
def max_var(head: Atom, body: Body, max_count: int) -> bool: """ Return True if there are no more than max_count variables in the clause """ vars = body.get_variables() for v in head.get_variables(): if v not in vars: vars += [v] return True if len(vars) <= max_count else False
def all_possible_atoms(self) -> Sequence[Atom]: """ Creates all possible argument configurations for the atom """ head_variables = [c_var(chr(x)) for x in range(ord("A"), ord("Z"))][:self._arity] if self._arity is not None: return [ Atom(self.new(), list(x)) for x in product(head_variables, repeat=self._arity) ] else: combos = [] for i in range(self._min_arity, self._max_arity): combos += [ Atom(self.new(arity=i), list(x)) for x in product(head_variables, repeat=i) ] return combos
def _from_body_fixed_arity( self, body: Body, arity: int = None, arg_types: Sequence[Type] = None, use_as_head_predicate: Predicate = None, ) -> Sequence[Atom]: """ Creates a head atom given the body of the clause :param body: :param arity: (optional) desired arity if specified with min/max when constructing the FillerPredicate :param arg_types: (optional) argument types to use :return: """ assert bool(arity) != bool(arg_types) vars = body.get_variables() if use_as_head_predicate and arg_types is None: arg_types = use_as_head_predicate.get_arg_types() if arg_types is None: base = [vars] * arity else: matches = {} for t_ind in range(len(arg_types)): matches[t_ind] = [] for v_ind in range(len(vars)): if vars[v_ind].get_type() == arg_types[t_ind]: matches[t_ind].append(vars[v_ind]) base = [matches[x] for x in range(arity)] heads = [] for comb in product(*base): self._instance_counter += 1 if use_as_head_predicate is not None: pred = use_as_head_predicate elif arg_types is None: pred = c_pred(f"{self._prefix_name}_{self._instance_counter}", arity) else: pred = c_pred( f"{self._prefix_name}_{self._instance_counter}", len(arg_types), arg_types, ) heads.append(Atom(pred, list(comb))) return heads
def _create_possible_heads( self, body: Body, use_as_head_predicate: Predicate = None) -> typing.Sequence[Atom]: """ Creates possible heads for a given body if the _head_constructor is Predicate, it makes all possible combinations that matches the types in the head """ vars = body.get_variables() if isinstance(self._head_constructor, Predicate): arg_types = self._head_constructor.get_arg_types() # matches_vars = [] # for i in range(len(arg_types)): # matches_vars[i] = [] # for var_ind in range(len(vars)): # if arg_types[i] == vars[var_ind].get_type(): # matches_vars[i].append(vars[var_ind]) # # bases = [matches_vars[x] for x in range(self._head_constructor.get_arity())] # heads = [] # # for comb in product(*bases): # heads.append(Atom(self._head_constructor, list(comb))) heads = [] for comb in combinations(vars, self._head_constructor.get_arity()): if [x.get_type() for x in comb] == arg_types: heads.append(Atom(self._head_constructor, list(comb))) return heads elif isinstance(self._head_constructor, FillerPredicate): return self._head_constructor.new_from_body( body, use_as_head_predicate=use_as_head_predicate) else: raise Exception( f"Unknown head constructor {self._head_constructor}")
def has_singleton_vars(head: Atom, body: Body) -> bool: """ Returns True is the clause has a singleton variable (appears only once) """ if len(body) == 0: return False vars = {} head_vars = head.get_variables() for ind in range(len(head_vars)): if head_vars[ind] not in vars: vars[head_vars[ind]] = head_vars.count(head_vars[ind]) bvars = body.get_variables() body_vars_flat = reduce(lambda x, y: x + y, [x.get_variables() for x in body.get_literals()], []) for ind in range(len(bvars)): if bvars[ind] in vars: vars[bvars[ind]] += body_vars_flat.count(bvars[ind]) else: vars[bvars[ind]] = body_vars_flat.count(bvars[ind]) return True if any([k for k, v in vars.items() if v == 1]) else False
def head_first(head: Atom, body: Body) -> bool: return len( set(body.get_literals()[0].get_variables()).intersection( set(head.get_variables()))) != 0
# define the Variables H = c_var("H") Ta = c_var("Ta") Tb = c_var("Tb") A = c_var("A") B = c_var("B") C = c_var("C") D = c_var("D") E = c_var("E") H1 = c_var("H1") H2 = c_var("H2") Z = c_var("Z") O = c_var("O") N = c_var("N") # create clauses head = Atom(not_space, [A]) body = Atom(is_space, [A]) clause1 = Clause(head, Body(Not(body))) head = Atom(is_uppercase, [Structure(s, [Pair(H, Z), O])]) body = Atom(is_uppercase_aux, [H]) clause2 = Clause(head, Body(body)) head = Atom(not_uppercase, [A]) body = Atom(is_uppercase, [A]) clause3 = Clause(head, Body(Not(body))) head = Atom(is_lowercase, [Structure(s, [Pair(H, Z), O])]) body = Atom(is_lowercase_aux, [H]) clause4 = Clause(head, Body(body)) head = Atom(not_lowercase, [A]) body = Atom(is_lowercase, [A]) clause5 = Clause(head, Body(Not(body))) head = Atom(is_letter, [Structure(s, [Pair(H, Z), O])])
def _get_recursions(self, node: Body) -> typing.Sequence[Recursion]: """ Prepares the valid recursions """ pointer_name = self._hypothesis_space.nodes[node]["partner"] init_pointer_value = self._pointers[pointer_name] last_pointer_value = None valid_heads = list(self._hypothesis_space.nodes[node]["heads"].keys()) recursions = [] # for each valid head for h_ind in range(len(valid_heads)): c_head: Atom = valid_heads[h_ind] recursive_clause = Clause(c_head, node) frontier = [self._pointers[pointer_name]] while len(frontier) > 0: focus_node = frontier[0] frontier = frontier[1:] # find matching heads focus_node_heads: typing.Sequence[Atom] = list( self._hypothesis_space.nodes[focus_node]["heads"].keys()) focus_node_heads = [ x for x in focus_node_heads if x.get_predicate().get_arg_types() == c_head.get_predicate().get_arg_types() ] # prepare recursion for bcl_ind in range(len(focus_node_heads)): if isinstance(self._head_constructor, Predicate): recursions.append( Recursion([ Clause(focus_node_heads[bcl_ind], focus_node), recursive_clause, ])) else: # if the filler predicate is used to construct heads, make sure the same head predicate is used head_args = focus_node_heads[bcl_ind].get_arguments() recursions.append( Recursion([ Clause( Atom(c_head.get_predicate(), head_args), focus_node, ), recursive_clause, ])) # extend the frontier - exclude recursive nodes to_add = [ x for x in self._hypothesis_space.successors(focus_node) if "partner" not in self._hypothesis_space.nodes[x] ] frontier += to_add last_pointer_value = focus_node # reset the pointer value for next valid head self.reset_pointer(pointer_name, init_pointer_value) # set the pointer to the last explored clause self.reset_pointer(pointer_name, last_pointer_value) return recursions