def max_var_occurrences(head: Atom, body: Body, max_occurrence: int) -> bool: """ Returns True if the predicate pred does not appear more than max_occurrence times in the clause """ if len(body.get_variables()) > 0: counter = Counter(body.get_variables()) if (body.get_literals()[-1].get_predicate().get_name() == 'copy1'): print(counter) return counter.most_common()[0][1] >= max_occurrence else: return False
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 _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 initialise(self, initial_clause: typing.Union[Clause, Body]) -> None: """ Initialises the search space. It is possible to provide an initial clause to initialize the hypothesis space with (instead of :-). """ if isinstance(self._head_constructor, (Predicate, FillerPredicate)): if isinstance(self._head_constructor, Predicate): # create possible heads head_variables = [chr(x) for x in range(ord("A"), ord("Z")) ][:self._head_constructor.get_arity()] possible_heads = [ self._head_constructor(*list(x)) for x in combinations_with_replacement( head_variables, self._head_constructor.get_arity()) ] else: possible_heads = self._head_constructor.all_possible_atoms() # create empty clause or use initial clause if initial_clause: clause = initial_clause if isinstance( initial_clause, Body) else initial_clause.get_body() else: clause = Body() if len(clause.get_literals()) > 0 and len(clause.get_variables( )) < self._head_constructor.get_arity(): raise AssertionError( "Cannot provide an initial clause with fewer distinct variables than the head predicate!" ) init_head_dict = { "ignored": False, "blocked": False, "visited": False } self._hypothesis_space.add_node(clause) self._hypothesis_space.nodes[clause]["heads"] = dict([ (x, init_head_dict.copy()) for x in possible_heads ]) self._hypothesis_space.nodes[clause]["visited"] = False self._pointers["main"] = clause self._root_node = clause else: raise Exception( f"Unknown head constructor ({self._head_constructor}")
def _add_to_body_fixed_arity(self, body: Body, arity: int) -> Sequence[Body]: new_pred_stash = {} # arg_types tuple -> pred vars = body.get_variables() bodies = [] args = list(combinations(vars, arity)) for ind in range(len(args)): arg_types = (x.get_type() for x in args[ind]) if arg_types in new_pred_stash: pred = new_pred_stash[arg_types] else: self._instance_counter += 1 pred = c_pred(f"{self._prefix_name}{self._instance_counter}", arity, arg_types) new_pred_stash[arg_types] = pred bodies.append(body + pred(*args[ind])) return bodies
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