Пример #1
0
    def new_from_body(
        self,
        body: Body,
        arity: int = None,
        argument_types: Sequence[Type] = None,
        use_as_head_predicate: Predicate = None,
    ) -> Sequence[Atom]:
        """
        Constructs all possible head atoms given a body of a clause

        If use_as_head_predicate is provided, it uses that.
        Then, it check is the FillerPredicate is instantiated with a fixed arity
        Then, it check if the arity argument is provided
        """
        if use_as_head_predicate:
            return self._from_body_fixed_arity(
                body,
                arity=use_as_head_predicate.get_arity(),
                arg_types=use_as_head_predicate.get_arg_types(),
                use_as_head_predicate=use_as_head_predicate)
        elif self._arity is not None:
            # a specific arity is provided
            return self._from_body_fixed_arity(body, self._arity,
                                               argument_types)
        else:
            # min -max arity is provided
            if arity is not None:
                # specific arity is requests
                return self._from_body_fixed_arity(body, arity)
            else:
                heads = []
                for i in range(self._min_arity, self._max_arity + 1):
                    heads += self._from_body_fixed_arity(body, i)

                return heads
Пример #2
0
def _plain_extend_clause(
    clause: typing.Union[Clause, Body],
    predicate: Predicate,
    connected_clause: bool = True
) -> typing.Sequence[typing.Union[Clause, Body]]:
    """
    Extends the clause with the predicate in every possible way (no bias)

    Arguments:
        clause: a clause to be extended
        predicate: a predicate to add to the clause
    """
    if isinstance(clause, Body) and len(clause) == 0:
        head_variables = [chr(x) for x in range(ord("A"), ord("Z"))
                          ][:predicate.get_arity()]
        possible_heads = [
            Body(predicate(*list(x))) for x in combinations_with_replacement(
                head_variables, predicate.get_arity())
        ]

        return possible_heads

    clause_variables: typing.Sequence[Variable] = clause.get_variables()
    used_variables = {x for x in clause_variables}
    pred_argument_types: typing.Sequence[Type] = predicate.get_arg_types()

    argument_matches = {}
    new_variables = set()

    # create new variable for each argument of a predicate
    for arg_ind in range(len(pred_argument_types)):
        new_var = new_variable(used_variables, pred_argument_types[arg_ind])
        argument_matches[arg_ind] = [new_var]
        used_variables.add(new_var)
        new_variables.add(new_var)

    # check for potential match with other variables
    for clv_ind in range(len(clause_variables)):
        for arg_ind in range(len(pred_argument_types)):
            if clause_variables[clv_ind].get_type(
            ) == pred_argument_types[arg_ind]:
                argument_matches[arg_ind].append(clause_variables[clv_ind])

    # do cross product of matches
    base_sets = [argument_matches[x] for x in range(len(pred_argument_types))]
    candidates: typing.List[typing.Union[Clause, Body]] = []

    for arg_combo in product(*base_sets):
        new_clause = None
        if connected_clause and not all(
            [True if x in new_variables else False for x in arg_combo]):
            # check that the new literal is not disconnected from the rest of the clause
            new_clause = clause + predicate(*list(arg_combo))
        elif not connected_clause:
            new_clause = clause + predicate(*list(arg_combo))

        if new_clause is not None:
            candidates.append(new_clause)

    return candidates
def _plain_extend_negation_clause(
    clause: typing.Union[Clause, Body], predicate: Predicate
) -> typing.Sequence[typing.Union[Clause, Body]]:
    """
    Extends a clause with the negation of a predicate (no new variables allowed)
    """
    if isinstance(clause, Body):
        suitable_vars = clause.get_variables()
    else:
        suitable_vars = clause.get_body_variables()
    pred_argument_types: typing.Sequence[Type] = predicate.get_arg_types()
    argument_matches = {}

    # check for potential match with other variables
    for clv_ind in range(len(suitable_vars)):
        for arg_ind in range(len(pred_argument_types)):
            if suitable_vars[clv_ind].get_type() == pred_argument_types[arg_ind]:
                if arg_ind not in argument_matches:
                    argument_matches[arg_ind] = []
                argument_matches[arg_ind].append(suitable_vars[clv_ind])

    base_sets = [argument_matches[x] for x in range(len(pred_argument_types))]
    candidates: typing.List[typing.Union[Clause, Body]] = []

    for arg_combo in product(*base_sets):
        new_clause = clause + Not(predicate(*list(arg_combo)))
        candidates.append(new_clause)

    return candidates
Пример #4
0
    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
Пример #5
0
    def is_created_by(self, predicate: Predicate) -> bool:
        """
        checks if a given predicate is created by the FillerPredicate

        it does so by checking if the name of the predicate is in [name]_[number] format and the name is
            equal to self._prefix_name and number is <= self._instance_counter
        """
        sp = predicate.get_name().split("_")
        if len(sp) != 2:
            return False
        else:
            if sp[0] == self._prefix_name and int(
                    sp[1]) <= self._instance_counter:
                return True
            else:
                return False