Example #1
0
def invokeRule(priorAnswers,
               bodyLiteralIterator,
               sip,
               otherargs,
               priorBooleanGoalSuccess=False,
               step=None,
               debug=False,
               buildProof=False):
    """
    Continue invokation of rule using (given) prior answers and list of remaining
    body literals (& rule sip).  If prior answers is a list, computation is split 
    disjunctively
    
    [..] By combining the answers to all these subqueries, we generate
    answers for the original query involving the rule head
    
    Can also takes a PML step and updates it as it navigates the top-down proof
    tree (passing it on and updating it where necessary)

    """
    assert not buildProof or step is not None
    proofLevel, memoizeMemory, sipCollection, factGraph, derivedPreds, processedRules = otherargs
    remainingBodyList = [i for i in bodyLiteralIterator]
    lazyGenerator = lazyGeneratorPeek(priorAnswers, 2)
    if lazyGenerator.successful:
        #There are multiple answers in this step, we need to call invokeRule
        #recursively for each answer, returning the first positive attempt
        success = False
        rt = None
        _step = None
        ansNo = 0
        for priorAns in lazyGenerator:
            ansNo += 1
            try:
                if buildProof:
                    newStep = InferenceStep(step.parent,
                                            step.rule,
                                            source=step.source)
                    newStep.antecedents = [ant for ant in step.antecedents]
                else:
                    newStep = None
                for rt,_step in\
                   invokeRule([priorAns],
                              iter([i for i in remainingBodyList]),
                              sip,
                              otherargs,
                              priorBooleanGoalSuccess,
                              newStep,
                              debug = debug,
                              buildProof = buildProof):
                    if rt:
                        yield rt, _step
            except RuleFailure, e:
                pass
        if not success:
            #None of prior answers were successful
            #indicate termination of rule processing
            raise RuleFailure(
                "Unable to solve either of %s against remainder of rule: %s" %
                (ansNo, remainingBodyList))
Example #2
0
def invokeRule(priorAnswers,
               bodyLiteralIterator,
               sip,
               otherargs,
               priorBooleanGoalSuccess=False,
               step=None,
               debug=False,
               buildProof=False):
    """
    Continue invokation of rule using (given) prior answers and list of
    remaining body literals (& rule sip).  If prior answers is a list,
    computation is split disjunctively

    [..] By combining the answers to all these subqueries, we generate
    answers for the original query involving the rule head

    Can also takes a PML step and updates it as it navigates the
    top-down proof tree (passing it on and updating it where necessary)

    """
    assert not buildProof or step is not None

    proofLevel, memoizeMemory, sipCollection, \
        factGraph, derivedPreds, processedRules = otherargs

    remainingBodyList = [i for i in bodyLiteralIterator]
    lazyGenerator = lazyGeneratorPeek(priorAnswers, 2)
    if lazyGenerator.successful:
        # There are multiple answers in this step, we need to call invokeRule
        # recursively for each answer, returning the first positive attempt
        success = False
        rt = None
        _step = None
        ansNo = 0
        for priorAns in lazyGenerator:
            ansNo += 1
            try:
                if buildProof:
                    newStep = InferenceStep(step.parent,
                                            step.rule,
                                            source=step.source)
                    newStep.antecedents = [ant for ant in step.antecedents]
                else:
                    newStep = None
                for rt, _step in\
                    invokeRule([priorAns],
                               iter([i for i in remainingBodyList]),
                               sip,
                               otherargs,
                               priorBooleanGoalSuccess,
                               newStep,
                               debug=debug,
                               buildProof=buildProof):
                    if rt:
                        yield rt, _step
            except RuleFailure:
                pass
        if not success:
            # None of prior answers were successful
            # indicate termination of rule processing
            raise RuleFailure(
                "Unable to solve either of %s against remainder of rule: %s" % (
                    ansNo, remainingBodyList))
            # yield False, _InferenceStep(step.parent, step.rule,
            # source=step.source)
    else:
        lazyGenerator = lazyGeneratorPeek(lazyGenerator)
        projectedBindings = lazyGenerator.successful and first(
            lazyGenerator) or {}

        # First we check if we can combine a large group of subsequent body literals
        # into a single query
        # if we have a template map then we use it to further
        # distinguish which builtins can be solved via
        # cumulative SPARQl query - else we solve
        # builtins one at a time
        def sparqlResolvable(literal):
            if isinstance(literal, Uniterm):
                return not literal.naf and GetOp(literal) not in derivedPreds
            else:
                return isinstance(literal, N3Builtin) and \
                    literal.uri in factGraph.templateMap

        def sparqlResolvableNoTemplates(literal):

            if isinstance(literal, Uniterm):
                return not literal.naf and GetOp(literal) not in derivedPreds
            else:
                return False

        conjGroundLiterals = list(
            itertools.takewhile(
                hasattr(factGraph, 'templateMap') and sparqlResolvable or
                sparqlResolvableNoTemplates,
                remainingBodyList))

        bodyLiteralIterator = iter(remainingBodyList)

        if len(conjGroundLiterals) > 1:
            # If there are literals to combine *and* a mapping from rule
            # builtins to SPARQL FILTER templates ..
            basePredicateVars = set(
                reduce(lambda x, y: x + y,
                       [list(GetVariables(arg, secondOrder=True)) for arg in conjGroundLiterals]))
            if projectedBindings:
                openVars = basePredicateVars.intersection(projectedBindings)
            else:
                # We don't have any given bindings, so we need to treat
                # the body as an open query
                openVars = basePredicateVars

            queryConj = EDBQuery([copy.deepcopy(lit) for lit in conjGroundLiterals],
                                 factGraph,
                                 openVars,
                                 projectedBindings)

            query, answers = queryConj.evaluate(debug)

            if isinstance(answers, bool):
                combinedAnswers = {}
                rtCheck = answers
            else:
                if projectedBindings:
                    combinedAnswers = (mergeMappings1To2(ans,
                                                         projectedBindings,
                                                         makeImmutable=True) for ans in answers)
                else:
                    combinedAnswers = (MakeImmutableDict(ans)
                                       for ans in answers)
                combinedAnsLazyGenerator = lazyGeneratorPeek(combinedAnswers)
                rtCheck = combinedAnsLazyGenerator.successful

            if not rtCheck:
                raise RuleFailure(
                    "No answers for combined SPARQL query: %s" % query)
            else:
                # We have solved the previous N body literals with a single
                # conjunctive query, now we need to make each of the literals
                # an antecedent to a 'query' step.
                if buildProof:
                    queryStep = InferenceStep(None, source='some RDF graph')
                    # FIXME: subquery undefined
                    queryStep.groundQuery = subquery
                    queryStep.bindings = {}  # combinedAnswers[-1]
                    # FIXME: subquery undefined
                    queryHash = URIRef(
                        "tag:[email protected]:Queries#" +
                        makeMD5Digest(subquery))
                    queryStep.identifier = queryHash
                    for subGoal in conjGroundLiterals:
                        subNs = NodeSet(subGoal.toRDFTuple(),
                                        identifier=BNode())
                        subNs.steps.append(queryStep)
                        step.antecedents.append(subNs)
                        queryStep.parent = subNs
                for rt, _step in invokeRule(
                        isinstance(answers, bool) and [
                            projectedBindings] or combinedAnsLazyGenerator,
                        iter(remainingBodyList[len(conjGroundLiterals):]),
                        sip,
                        otherargs,
                        isinstance(answers, bool),
                        step,
                        debug=debug,
                        buildProof=buildProof):
                    yield rt, _step

        else:
            # Continue processing rule body condition
            # one literal at a time
            try:
                bodyLiteral = next(
                    bodyLiteralIterator) if py3compat.PY3 else bodyLiteralIterator.next()
                # if a N3 builtin, execute it using given bindings for boolean answer
                # builtins are moved to end of rule when evaluating rules via
                # sip
                if isinstance(bodyLiteral, N3Builtin):
                    lhs = bodyLiteral.argument
                    rhs = bodyLiteral.result
                    lhs = isinstance(
                        lhs, Variable) and projectedBindings[lhs] or lhs
                    rhs = isinstance(
                        rhs, Variable) and projectedBindings[rhs] or rhs
                    assert lhs is not None and rhs is not None
                    if bodyLiteral.func(lhs, rhs):
                        if debug:
                            print("Invoked %s(%s, %s) -> True" % (
                                bodyLiteral.uri, lhs, rhs))
                        # positive answer means we can continue processing the
                        # rule body
                        if buildProof:
                            ns = NodeSet(bodyLiteral.toRDFTuple(),
                                         identifier=BNode())
                            step.antecedents.append(ns)
                        for rt, _step in invokeRule(
                                [projectedBindings],
                                bodyLiteralIterator,
                                sip,
                                otherargs,
                                step,
                                priorBooleanGoalSuccess,
                                debug=debug,
                                buildProof=buildProof):
                            yield rt, _step
                    else:
                        if debug:
                            print("Successfully invoked %s(%s, %s) -> False" % (
                                bodyLiteral.uri, lhs, rhs))
                        raise RuleFailure("Failed builtin invokation %s(%s, %s)" %
                                          (bodyLiteral.uri, lhs, rhs))
                else:
                    # For every body literal, subqueries are generated according
                    # to the sip
                    sipArcPred = URIRef(GetOp(bodyLiteral) +
                                        '_' + '_'.join(GetArgs(bodyLiteral)))
                    assert len(list(IncomingSIPArcs(sip, sipArcPred))) < 2
                    subquery = copy.deepcopy(bodyLiteral)
                    subquery.ground(projectedBindings)

                    for N, x in IncomingSIPArcs(sip, sipArcPred):
                        # That is, each subquery contains values for the bound arguments
                        # that are passed through the sip arcs entering the node
                        # corresponding to that literal

                        # Create query out of body literal and apply
                        # sip-provided bindings
                        subquery = copy.deepcopy(bodyLiteral)
                        subquery.ground(projectedBindings)
                    if literalIsGround(subquery):
                        # subquery is ground, so there will only be boolean answers
                        # we return the conjunction of the answers for the current
                        # subquery

                        answer = False
                        ns = None

                        answers = first(
                            itertools.dropwhile(
                                lambda item: not item[0],
                                SipStrategy(
                                    subquery.toRDFTuple(),
                                    sipCollection,
                                    factGraph,
                                    derivedPreds,
                                    MakeImmutableDict(projectedBindings),
                                    processedRules,
                                    network=step is not None and
                                    step.parent.network or None,
                                    debug=debug,
                                    buildProof=buildProof,
                                    memoizeMemory=memoizeMemory,
                                    proofLevel=proofLevel)))
                        if answers:
                            answer, ns = answers
                        if not answer and not bodyLiteral.naf or \
                                (answer and bodyLiteral.naf):
                            # negative answer means the invokation of the rule fails
                            # either because we have a positive literal and there
                            # is no answer for the subgoal or the literal is
                            # negative and there is an answer for the subgoal
                            raise RuleFailure(
                                "No solutions solving ground query %s" % subquery)
                        else:
                            if buildProof:
                                if not answer and bodyLiteral.naf:
                                    ns.naf = True
                                step.antecedents.append(ns)
                            # positive answer means we can continue processing the rule body
                            # either because we have a positive literal and answers
                            # for subgoal or a negative literal and no answers for the
                            # the goal
                            for rt, _step in invokeRule(
                                    [projectedBindings],
                                    bodyLiteralIterator,
                                    sip,
                                    otherargs,
                                    True,
                                    step,
                                    debug=debug):
                                yield rt, _step
                    else:
                        _answers = \
                            SipStrategy(
                                subquery.toRDFTuple(),
                                sipCollection,
                                factGraph,
                                derivedPreds,
                                MakeImmutableDict(
                                    projectedBindings),
                                processedRules,
                                network=step is not None and
                                step.parent.network or None,
                                debug=debug,
                                buildProof=buildProof,
                                memoizeMemory=memoizeMemory,
                                proofLevel=proofLevel)

                        # solve (non-ground) subgoal
                        def collectAnswers(_ans):
                            for ans, ns in _ans:
                                if isinstance(ans, dict):
                                    try:
                                        map = mergeMappings1To2(
                                            ans, projectedBindings,
                                            makeImmutable=True)
                                        yield map
                                    except:
                                        pass
                        combinedAnswers = collectAnswers(_answers)
                        answers = lazyGeneratorPeek(combinedAnswers)
                        if not answers.successful \
                                and not bodyLiteral.naf \
                                or (bodyLiteral.naf and answers.successful):
                            raise RuleFailure(
                                "No solutions solving ground query %s" % subquery)
                        else:
                            # Either we have a positive subgoal and answers
                            # or a negative subgoal and no answers
                            if buildProof:
                                if answers.successful:
                                    goals = set([g for a, g in answers])
                                    assert len(goals) == 1
                                    step.antecedents.append(goals.pop())
                                else:
                                    newNs = NodeSet(
                                        bodyLiteral.toRDFTuple(),
                                        network=step.parent.network,
                                        identifier=BNode(),
                                        naf=True)
                                    step.antecedents.append(newNs)
                            for rt, _step in invokeRule(
                                    answers,
                                    bodyLiteralIterator,
                                    sip,
                                    otherargs,
                                    priorBooleanGoalSuccess,
                                    step,
                                    debug=debug,
                                    buildProof=buildProof):
                                yield rt, _step
            except StopIteration:
                # Finished processing rule
                if priorBooleanGoalSuccess:
                    yield projectedBindings and projectedBindings or True, step
                elif projectedBindings:
                    # Return the most recent (cumulative) answers and the given
                    # step
                    yield projectedBindings, step
                else:
                    raise RuleFailure(
                        "Finished processing rule unsuccessfully")
Example #3
0
                              buildProof = buildProof):
                    if rt:
                        yield rt, _step
            except RuleFailure, e:
                pass
        if not success:
            #None of prior answers were successful
            #indicate termination of rule processing
            raise RuleFailure(
                "Unable to solve either of %s against remainder of rule: %s" %
                (ansNo, remainingBodyList))


#            yield False,_InferenceStep(step.parent,step.rule,source=step.source)
    else:
        lazyGenerator = lazyGeneratorPeek(lazyGenerator)
        projectedBindings = lazyGenerator.successful and first(
            lazyGenerator) or {}

        #First we check if we can combine a large group of subsequent body literals
        #into a single query
        #if we have a template map then we use it to further
        #distinguish which builtins can be solved via
        #cumulative SPARQl query - else we solve
        #builtins one at a time
        def sparqlResolvable(literal):
            if isinstance(literal, Uniterm):
                return not literal.naf and GetOp(literal) not in derivedPreds
            else:
                return isinstance(literal,N3Builtin) and \
                       literal.uri in factGraph.templateMap
Example #4
0
def invokeRule(priorAnswers,
               bodyLiteralIterator,
               sip,
               otherargs,
               priorBooleanGoalSuccess=False,
               step=None,
               debug=False,
               buildProof=False):
    """
    Continue invokation of rule using (given) prior answers and list of
    remaining body literals (& rule sip).  If prior answers is a list,
    computation is split disjunctively

    [..] By combining the answers to all these subqueries, we generate
    answers for the original query involving the rule head

    Can also takes a PML step and updates it as it navigates the
    top-down proof tree (passing it on and updating it where necessary)

    """
    assert not buildProof or step is not None

    proofLevel, memoizeMemory, sipCollection, \
        factGraph, derivedPreds, processedRules = otherargs

    remainingBodyList = [i for i in bodyLiteralIterator]
    lazyGenerator = lazyGeneratorPeek(priorAnswers, 2)
    if lazyGenerator.successful:
        # There are multiple answers in this step, we need to call invokeRule
        # recursively for each answer, returning the first positive attempt
        success = False
        rt = None
        _step = None
        ansNo = 0
        for priorAns in lazyGenerator:
            ansNo += 1
            try:
                if buildProof:
                    newStep = InferenceStep(step.parent,
                                            step.rule,
                                            source=step.source)
                    newStep.antecedents = [ant for ant in step.antecedents]
                else:
                    newStep = None
                for rt, _step in\
                   invokeRule([priorAns],
                              iter([i for i in remainingBodyList]),
                              sip,
                              otherargs,
                              priorBooleanGoalSuccess,
                              newStep,
                              debug=debug,
                              buildProof=buildProof):
                    if rt:
                        yield rt, _step
            except RuleFailure:
                pass
        if not success:
            # None of prior answers were successful
            # indicate termination of rule processing
            raise RuleFailure(
                "Unable to solve either of %s against remainder of rule: %s" %
                (ansNo, remainingBodyList))
            # yield False, _InferenceStep(step.parent, step.rule, source=step.source)
    else:
        lazyGenerator = lazyGeneratorPeek(lazyGenerator)
        projectedBindings = lazyGenerator.successful and first(
            lazyGenerator) or {}

        # First we check if we can combine a large group of subsequent body literals
        # into a single query
        # if we have a template map then we use it to further
        # distinguish which builtins can be solved via
        # cumulative SPARQl query - else we solve
        # builtins one at a time
        def sparqlResolvable(literal):
            if isinstance(literal, Uniterm):
                return not literal.naf and GetOp(literal) not in derivedPreds
            else:
                return isinstance(literal, N3Builtin) and \
                       literal.uri in factGraph.templateMap

        def sparqlResolvableNoTemplates(literal):

            if isinstance(literal, Uniterm):
                return not literal.naf and GetOp(literal) not in derivedPreds
            else:
                return False

        conjGroundLiterals = list(
                        itertools.takewhile(
                          hasattr(factGraph, 'templateMap') and sparqlResolvable or \
                          sparqlResolvableNoTemplates,
                          remainingBodyList))

        bodyLiteralIterator = iter(remainingBodyList)

        if len(conjGroundLiterals) > 1:
            # If there are literals to combine *and* a mapping from rule
            # builtins to SPARQL FILTER templates ..
            basePredicateVars = set(
                reduce(lambda x, y: x + y, [
                    list(GetVariables(arg, secondOrder=True))
                    for arg in conjGroundLiterals
                ]))
            if projectedBindings:
                openVars = basePredicateVars.intersection(projectedBindings)
            else:
                # We don't have any given bindings, so we need to treat
                # the body as an open query
                openVars = basePredicateVars

            queryConj = EDBQuery(
                [copy.deepcopy(lit) for lit in conjGroundLiterals], factGraph,
                openVars, projectedBindings)

            query, answers = queryConj.evaluate(debug)

            if isinstance(answers, bool):
                combinedAnswers = {}
                rtCheck = answers
            else:
                if projectedBindings:
                    combinedAnswers = (mergeMappings1To2(ans,
                                                         projectedBindings,
                                                         makeImmutable=True)
                                       for ans in answers)
                else:
                    combinedAnswers = (MakeImmutableDict(ans)
                                       for ans in answers)
                combinedAnsLazyGenerator = lazyGeneratorPeek(combinedAnswers)
                rtCheck = combinedAnsLazyGenerator.successful

            if not rtCheck:
                raise RuleFailure("No answers for combined SPARQL query: %s" %
                                  query)
            else:
                # We have solved the previous N body literals with a single
                # conjunctive query, now we need to make each of the literals
                # an antecedent to a 'query' step.
                if buildProof:
                    queryStep = InferenceStep(None, source='some RDF graph')
                    queryStep.groundQuery = subquery
                    queryStep.bindings = {}  # combinedAnswers[-1]
                    queryHash = URIRef(
                            "tag:[email protected]:Queries#" + \
                                                    makeMD5Digest(subquery))
                    queryStep.identifier = queryHash
                    for subGoal in conjGroundLiterals:
                        subNs = NodeSet(subGoal.toRDFTuple(),
                                        identifier=BNode())
                        subNs.steps.append(queryStep)
                        step.antecedents.append(subNs)
                        queryStep.parent = subNs
                for rt, _step in invokeRule(
                        isinstance(answers, bool) and [projectedBindings]
                        or combinedAnsLazyGenerator,
                        iter(remainingBodyList[len(conjGroundLiterals):]),
                        sip,
                        otherargs,
                        isinstance(answers, bool),
                        step,
                        debug=debug,
                        buildProof=buildProof):
                    yield rt, _step

        else:
            # Continue processing rule body condition
            # one literal at a time
            try:
                bodyLiteral = next(
                    bodyLiteralIterator
                ) if py3compat.PY3 else bodyLiteralIterator.next()
                # if a N3 builtin, execute it using given bindings for boolean answer
                # builtins are moved to end of rule when evaluating rules via sip
                if isinstance(bodyLiteral, N3Builtin):
                    lhs = bodyLiteral.argument
                    rhs = bodyLiteral.result
                    lhs = isinstance(
                        lhs, Variable) and projectedBindings[lhs] or lhs
                    rhs = isinstance(
                        rhs, Variable) and projectedBindings[rhs] or rhs
                    assert lhs is not None and rhs is not None
                    if bodyLiteral.func(lhs, rhs):
                        if debug:
                            print("Invoked %s(%s, %s) -> True" %
                                  (bodyLiteral.uri, lhs, rhs))
                        # positive answer means we can continue processing the rule body
                        if buildProof:
                            ns = NodeSet(bodyLiteral.toRDFTuple(),
                                         identifier=BNode())
                            step.antecedents.append(ns)
                        for rt, _step in invokeRule([projectedBindings],
                                                    bodyLiteralIterator,
                                                    sip,
                                                    otherargs,
                                                    step,
                                                    priorBooleanGoalSuccess,
                                                    debug=debug,
                                                    buildProof=buildProof):
                            yield rt, _step
                    else:
                        if debug:
                            print("Successfully invoked %s(%s, %s) -> False" %
                                  (bodyLiteral.uri, lhs, rhs))
                        raise RuleFailure(
                            "Failed builtin invokation %s(%s, %s)" %
                            (bodyLiteral.uri, lhs, rhs))
                else:
                    # For every body literal, subqueries are generated according
                    # to the sip
                    sipArcPred = URIRef(GetOp(bodyLiteral) + \
                                '_' + '_'.join(GetArgs(bodyLiteral)))
                    assert len(list(IncomingSIPArcs(sip, sipArcPred))) < 2
                    subquery = copy.deepcopy(bodyLiteral)
                    subquery.ground(projectedBindings)

                    for N, x in IncomingSIPArcs(sip, sipArcPred):
                        #That is, each subquery contains values for the bound arguments
                        #that are passed through the sip arcs entering the node
                        #corresponding to that literal

                        #Create query out of body literal and apply sip-provided bindings
                        subquery = copy.deepcopy(bodyLiteral)
                        subquery.ground(projectedBindings)
                    if literalIsGround(subquery):
                        #subquery is ground, so there will only be boolean answers
                        #we return the conjunction of the answers for the current
                        #subquery

                        answer = False
                        ns = None

                        answers = first(
                                    itertools.dropwhile(
                                            lambda item: not item[0],
                                            SipStrategy(
                                                    subquery.toRDFTuple(),
                                                    sipCollection,
                                                    factGraph,
                                                    derivedPreds,
                                                    MakeImmutableDict(projectedBindings),
                                                    processedRules,
                                                    network=step is not None and \
                                                            step.parent.network or None,
                                                    debug=debug,
                                                    buildProof=buildProof,
                                                    memoizeMemory=memoizeMemory,
                                                    proofLevel=proofLevel)))
                        if answers:
                            answer, ns = answers
                        if not answer and not bodyLiteral.naf or \
                            (answer and bodyLiteral.naf):
                            #negative answer means the invokation of the rule fails
                            #either because we have a positive literal and there
                            #is no answer for the subgoal or the literal is
                            #negative and there is an answer for the subgoal
                            raise RuleFailure(
                                "No solutions solving ground query %s" %
                                subquery)
                        else:
                            if buildProof:
                                if not answer and bodyLiteral.naf:
                                    ns.naf = True
                                step.antecedents.append(ns)
                            #positive answer means we can continue processing the rule body
                            #either because we have a positive literal and answers
                            #for subgoal or a negative literal and no answers for the
                            #the goal
                            for rt, _step in invokeRule([projectedBindings],
                                                        bodyLiteralIterator,
                                                        sip,
                                                        otherargs,
                                                        True,
                                                        step,
                                                        debug=debug):
                                yield rt, _step
                    else:
                        _answers = \
                                SipStrategy(subquery.toRDFTuple(),
                                            sipCollection,
                                            factGraph,
                                            derivedPreds,
                                            MakeImmutableDict(projectedBindings),
                                            processedRules,
                                            network=step is not None and \
                                                    step.parent.network or None,
                                            debug=debug,
                                            buildProof=buildProof,
                                            memoizeMemory=memoizeMemory,
                                            proofLevel=proofLevel)

                        # solve (non-ground) subgoal
                        def collectAnswers(_ans):
                            for ans, ns in _ans:
                                if isinstance(ans, dict):
                                    try:
                                        map = mergeMappings1To2(
                                            ans,
                                            projectedBindings,
                                            makeImmutable=True)
                                        yield map
                                    except:
                                        pass

                        combinedAnswers = collectAnswers(_answers)
                        answers = lazyGeneratorPeek(combinedAnswers)
                        if not answers.successful \
                            and not bodyLiteral.naf \
                            or (bodyLiteral.naf and answers.successful):
                            raise RuleFailure(
                                "No solutions solving ground query %s" %
                                subquery)
                        else:
                            # Either we have a positive subgoal and answers
                            # or a negative subgoal and no answers
                            if buildProof:
                                if answers.successful:
                                    goals = set([g for a, g in answers])
                                    assert len(goals) == 1
                                    step.antecedents.append(goals.pop())
                                else:
                                    newNs = NodeSet(
                                        bodyLiteral.toRDFTuple(),
                                        network=step.parent.network,
                                        identifier=BNode(),
                                        naf=True)
                                    step.antecedents.append(newNs)
                            for rt, _step in invokeRule(
                                    answers,
                                    bodyLiteralIterator,
                                    sip,
                                    otherargs,
                                    priorBooleanGoalSuccess,
                                    step,
                                    debug=debug,
                                    buildProof=buildProof):
                                yield rt, _step
            except StopIteration:
                #Finished processing rule
                if priorBooleanGoalSuccess:
                    yield projectedBindings and projectedBindings or True, step
                elif projectedBindings:
                    #Return the most recent (cumulative) answers and the given step
                    yield projectedBindings, step
                else:
                    raise RuleFailure(
                        "Finished processing rule unsuccessfully")