예제 #1
0
    def successors(self, node):
        """
        Successor nodes are possible next pattern elements that can be unified.
        """
        sub = dict(node.state)
        terms, f_terms, index = node.extra

        # Figure out best term to match (only need to choose 1 and don't need
        # to backtrack over choice).

        for term in [t for necessary in terms if
                     meets_requirements(necessary, sub)
                     for t in terms[necessary] if not is_negated_term(t)]:

            # Pretty sure this is ok AND faster.
            key = index_key(subst(sub, term))
            # key = index_key(term)
            if key not in index:
                return

            facts = [f for f in index[key]]
            # shuffle(facts)

            for fact in facts:
                new_sub = unify(term, fact, sub)
                if new_sub is None:
                    continue

                new_terms = update_terms(terms, f_terms, new_sub, index,
                                         partial=True)
                if new_terms is None:
                    continue

                yield Node(frozenset(new_sub.items()), node, None, 0,
                           (new_terms, f_terms, index))
예제 #2
0
def update_neg_pattern(neg_pattern, sub, index, free_vars=None):
    if free_vars is None:
        free_vars = set()

    new_neg_pattern = []
    bound_set = set(sub).union(free_vars)

    for term in neg_pattern:
        args = set(e for e in extract_strings(term) if is_variable(e))
        if args.issubset(bound_set):
            bterm = execute_functions(subst(sub, term))

            if bterm is False:
                continue
            if bterm is True:
                return None

            key = index_key(bterm)

            if key in index and len(index[key]) > 0:
                for fact in index[key]:
                    if unify(bterm, fact, sub, index):
                        return None
        else:
            new_neg_pattern.append(term)

    return new_neg_pattern
예제 #3
0
def test_term_unification():
    # Base Terms
    assert unify('A', 'B') is None
    assert unify('A', 'A') == {}

    # Relations
    assert unify(('on', 'A'), ('on', 'B')) is None
    assert unify(('on', 'A'), ('on', 'A')) == {}
    assert unify(('on', 'A'), ('on', '?x')) == {'?x': 'A'}
    assert unify(('on', 'A'), ('?rel', 'A')) == {'?rel': 'on'}
    assert unify(('on', 'A'), ('?rel', '?x')) == {'?rel': 'on', '?x': 'A'}
    assert unify(('on', '?x'), ('?rel', 'B')) == {'?rel': 'on', '?x': 'B'}
    assert unify(('on', '?x'), ('?rel', 'B')) == {'?rel': 'on', '?x': 'B'}
예제 #4
0
    def successors(self, node):
        """
        Successor nodes are possible next pattern elements that can be unified.
        """
        sub = dict(node.state)
        terms, f_terms, index = node.extra

        # Figure out best term to match (only need to choose 1 and don't need
        # to backtrack over choice).
        p_terms = [(len(index[subst(sub, t)]) if t in index else 0,
                    len(necessary), random(), t) for necessary in terms
                   if meets_requirements(necessary, sub) for t in
                   terms[necessary] if not is_negated_term(t)]
        if len(p_terms) == 0:
            return

        p_terms.sort()
        term = p_terms[0][3]

        # TODO need to figure out how to handle positiver terms with functional

        # Pretty sure this is ok AND faster.
        key = index_key(subst(sub, term))
        # key = index_key(term)
        if key not in index:
            return

        facts = [f for f in index[key]]

        # could do something here where I pick the fact that yields
        # substitutions that are the LEAST constraining.
        # I'm not sure if it is worth the time though.
        shuffle(facts)

        for fact in facts:
            # TODO what do we do when the term contains a functional?
            new_sub = unify(term, fact, sub)
            if new_sub is None:
                continue

            new_terms = update_terms(terms, f_terms, new_sub, index)
            if new_terms is None:
                continue

            yield Node(frozenset(new_sub.items()), node, None, 0,
                       (new_terms, f_terms, index))
예제 #5
0
def update_terms(terms, f_terms, sub, index, partial=False):
    new_terms = {}

    for necessary in terms:
        # if necessary.issubset(sub):
        if meets_requirements(necessary, sub):
            for term in terms[necessary]:
                bterm = subst(sub, term)
                if term in f_terms:
                    bterm = execute_functions(bterm)
                    if is_negated_term(bterm):
                        if bterm is False:
                            continue
                        if bterm is True:
                            return None
                    else:
                        if bterm is False:
                            return None
                        if bterm is True:
                            continue

                if is_negated_term(bterm):
                    key = index_key(bterm[1])

                    if key in index and len(index[key]) > 0:
                        for fact in index[key]:
                            if unify(bterm[1], fact, sub, index):
                                # if partial:
                                #     continue
                                return None
                else:
                    key = index_key(bterm)

                    if key not in index:
                        if partial:
                            continue
                        return None

                    if bterm not in index[key]:
                        if necessary not in new_terms:
                            new_terms[necessary] = []
                        new_terms[necessary].append(term)
        else:
            new_terms[necessary] = terms[necessary]

    return new_terms