def conjunctiveSipStrategy(self, goalsRemaining, factGraph, bindings=None): """ Given a conjunctive set of triples, invoke sip-strategy passing on intermediate solutions to facilitate 'join' behavior """ bindings = bindings if bindings else {} try: tp = goalsRemaining.next() assert isinstance(bindings, dict) dPred = self.derivedPredicateFromTriple(tp) if dPred is None: baseEDBQuery = EDBQuery([BuildUnitermFromTuple(tp)], self.edb, bindings=bindings) if self.DEBUG: print >>sys.stderr,"Evaluating TP against EDB: ",\ baseEDBQuery.asSPARQL() query, rt = baseEDBQuery.evaluate() if isinstance(rt, bool) and rt: yield bindings elif not isinstance(rt, bool): rt = list(rt) remaining_goals = itertools.tee(goalsRemaining, len(rt)) for idx in range(len(rt)): item = {} item.update(rt[idx]) item.update(bindings) if self.DEBUG: print >> sys.stderr, "Solution from EDB query: ", item for ansDict in self.conjunctiveSipStrategy( remaining_goals[idx], factGraph, item): yield ansDict else: queryLit = BuildUnitermFromTuple(tp) currentOp = GetOp(queryLit) queryLit.setOperator(currentOp) query = EDBQuery([queryLit], self.edb, bindings=bindings) if bindings: tp = first(query.formulae).toRDFTuple() if self.DEBUG: print >> sys.stderr, "Goal/Query: ", query.asSPARQL() tp = self.hybridPredQueryPreparation(tp) SetupDDLAndAdornProgram(self.edb, self.idb, [tp], derivedPreds=self.derivedPredicates, ignoreUnboundDPreds=True, nsBindings=self.nsBindings) sipCollection = PrepareSipCollection(self.edb.adornedProgram) if self.DEBUG and sipCollection: for sip in SIPRepresentation(sipCollection): print >> sys.stderr, sip pprint(list(self.edb.adornedProgram), sys.stderr) elif self.DEBUG: print >> sys.stderr, "No SIP graph!" for nextAnswer, ns in self.invokeDecisionProcedure( tp, factGraph, bindings, self.DEBUG, sipCollection): if isinstance(nextAnswer, dict): #Recieved solutions to 'open' query, merge with given bindings #and continue for ansDict in self.conjunctiveSipStrategy( goalsRemaining, factGraph, mergeMappings1To2(bindings, nextAnswer)): yield ansDict elif nextAnswer: #we (successfully) proved a ground query, pass on bindings assert isinstance(nextAnswer, bool) for ansDict in self.conjunctiveSipStrategy( goalsRemaining, factGraph, bindings): yield ansDict except StopIteration: yield bindings
def sparql_query(self, queryString, queryObj, graph, dataSetBase, extensionFunctions, initBindings={}, initNs={}, DEBUG=False): """ The default 'native' SPARQL implementation is based on sparql-p's expansion trees layered on top of the read-only RDF APIs of the underlying store """ from rdflib.sparql.Algebra import TopEvaluate from rdflib.QueryResult import QueryResult from rdflib import plugin from rdflib.sparql.bison.Query import AskQuery _expr = self.isaBaseQuery(None, queryObj) if isinstance(queryObj.query,AskQuery) and \ isinstance(_expr,BasicGraphPattern): #This is a ground, BGP, involving IDB and can be solved directly #using top-down decision procedure #First separate out conjunct into EDB and IDB predicates #(solving the former first) from FuXi.SPARQL import EDBQuery groundConjunct = [] derivedConjunct = [] for s, p, o, func in _expr.patterns: if self.derivedPredicateFromTriple((s, p, o)) is None: groundConjunct.append(BuildUnitermFromTuple((s, p, o))) else: derivedConjunct.append(BuildUnitermFromTuple((s, p, o))) if groundConjunct: baseEDBQuery = EDBQuery(groundConjunct, self.edb) subQuery, ans = baseEDBQuery.evaluate(DEBUG) assert isinstance(ans, bool), ans if groundConjunct and not ans: askResult = False else: askResult = True for derivedLiteral in derivedConjunct: goal = derivedLiteral.toRDFTuple() #Solve ground, derived goal directly goal = self.hybridPredQueryPreparation(goal) SetupDDLAndAdornProgram( self.edb, self.idb, [goal], derivedPreds=self.derivedPredicates, ignoreUnboundDPreds=True) sipCollection = PrepareSipCollection( self.edb.adornedProgram) if self.DEBUG and sipCollection: for sip in SIPRepresentation(sipCollection): print >> sys.stderr, sip pprint(list(self.edb.adornedProgram), sys.stderr) elif self.DEBUG: print >> sys.stderr, "No SIP graph!" rt, node = first( self.invokeDecisionProcedure(goal, self.edb, {}, self.DEBUG, sipCollection)) if not rt: askResult = False break return plugin.get('SPARQLQueryResult', QueryResult)(askResult) else: rt = TopEvaluate(queryObj, graph, initBindings, DEBUG=self.DEBUG, dataSetBase=dataSetBase, extensionFunctions=extensionFunctions) return plugin.get('SPARQLQueryResult', QueryResult)(rt)
def sparql_query(self, queryString, queryObj, graph, dataSetBase, extensionFunctions, initBindings={}, initNs={}, DEBUG=False): """ The default 'native' SPARQL implementation is based on sparql-p's expansion trees layered on top of the read-only RDF APIs of the underlying store """ from rdflib.sparql.Algebra import TopEvaluate from rdflib.QueryResult import QueryResult from rdflib import plugin from rdflib.sparql.bison.Query import AskQuery _expr = self.isaBaseQuery(None,queryObj) if isinstance(queryObj.query,AskQuery) and \ isinstance(_expr,BasicGraphPattern): #This is a ground, BGP, involving IDB and can be solved directly #using top-down decision procedure #First separate out conjunct into EDB and IDB predicates #(solving the former first) from FuXi.SPARQL import EDBQuery groundConjunct = [] derivedConjunct = [] for s,p,o,func in _expr.patterns: if self.derivedPredicateFromTriple((s,p,o)) is None: groundConjunct.append(BuildUnitermFromTuple((s,p,o))) else: derivedConjunct.append(BuildUnitermFromTuple((s,p,o))) if groundConjunct: baseEDBQuery = EDBQuery(groundConjunct,self.edb) subQuery,ans = baseEDBQuery.evaluate(DEBUG) assert isinstance(ans,bool),ans if groundConjunct and not ans: askResult = False else: askResult = True for derivedLiteral in derivedConjunct: goal = derivedLiteral.toRDFTuple() #Solve ground, derived goal directly SetupDDLAndAdornProgram( self.edb, self.idb, [goal], derivedPreds=self.derivedPredicates, ignoreUnboundDPreds = True, hybridPreds2Replace=self.hybridPredicates) if self.hybridPredicates: lit = BuildUnitermFromTuple(goal) op = GetOp(lit) if op in self.hybridPredicates: lit.setOperator(URIRef(op+u'_derived')) goal = lit.toRDFTuple() sipCollection=PrepareSipCollection(self.edb.adornedProgram) if self.DEBUG and sipCollection: for sip in SIPRepresentation(sipCollection): print >>sys.stderr,sip pprint(list(self.edb.adornedProgram),sys.stderr) elif self.DEBUG: print >> sys.stderr, "No SIP graph!" rt,node = first(self.invokeDecisionProcedure( goal, self.edb, {}, self.DEBUG, sipCollection)) if not rt: askResult = False break return plugin.get('SPARQLQueryResult',QueryResult)(askResult) else: rt = TopEvaluate(queryObj, graph, initBindings, DEBUG=self.DEBUG, dataSetBase=dataSetBase, extensionFunctions=extensionFunctions) return plugin.get('SPARQLQueryResult',QueryResult)(rt)
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")
def conjunctiveSipStrategy(self,goalsRemaining,factGraph,bindings=None): """ Given a conjunctive set of triples, invoke sip-strategy passing on intermediate solutions to facilitate 'join' behavior """ bindings = bindings if bindings else {} try: tp = goalsRemaining.next() assert isinstance(bindings,dict) dPred = self.derivedPredicateFromTriple(tp) if dPred is None: baseEDBQuery = EDBQuery([BuildUnitermFromTuple(tp)], self.edb, bindings=bindings) if self.DEBUG: print >>sys.stderr,"Evaluating TP against EDB: ",\ baseEDBQuery.asSPARQL() query,rt = baseEDBQuery.evaluate() # _vars = baseEDBQuery.returnVars for item in rt: bindings.update(item) for ansDict in self.conjunctiveSipStrategy( goalsRemaining, factGraph, bindings): yield ansDict else: queryLit = BuildUnitermFromTuple(tp) currentOp = GetOp(queryLit) queryLit.setOperator(currentOp) query=EDBQuery([queryLit], self.edb, bindings=bindings) if bindings: tp=first(query.formulae).toRDFTuple() if self.DEBUG: print >>sys.stderr,"Goal/Query: ", query.asSPARQL() SetupDDLAndAdornProgram( self.edb, self.idb, [tp], derivedPreds=self.derivedPredicates, ignoreUnboundDPreds = True, hybridPreds2Replace=self.hybridPredicates) if self.hybridPredicates: lit = BuildUnitermFromTuple(tp) op = GetOp(lit) if op in self.hybridPredicates: lit.setOperator(URIRef(op+u'_derived')) tp = lit.toRDFTuple() sipCollection=PrepareSipCollection(self.edb.adornedProgram) if self.DEBUG and sipCollection: for sip in SIPRepresentation(sipCollection): print >>sys.stderr,sip pprint(list(self.edb.adornedProgram),sys.stderr) elif self.DEBUG: print >> sys.stderr, "No SIP graph!" for nextAnswer,ns in self.invokeDecisionProcedure( tp, factGraph, bindings, self.DEBUG, sipCollection): nonGroundGoal = isinstance(nextAnswer,dict) if nonGroundGoal or nextAnswer: #Either we recieved bindings from top-down evaluation #or we (successfully) proved a ground query if not nonGroundGoal: #Attempt to prove a ground query, return the response rt = nextAnswer else: #Recieved solutions to 'open' query, merge with given bindings #and continue rt = mergeMappings1To2(bindings,nextAnswer) #either answers were provided (the goal wasn't grounded) or #the goal was ground and successfully proved for ansDict in self.conjunctiveSipStrategy( goalsRemaining, factGraph, rt): yield ansDict except StopIteration: yield bindings
#builtins to SPARQL FILTER templates .. basePredicateVars = set( reduce( lambda x, y: x + y, map(lambda arg: list(GetVariables(arg, secondOrder=True)), 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:
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")
def conjunctiveSipStrategy(self, goalsRemaining, factGraph, bindings=None): """ Given a conjunctive set of triples, invoke sip-strategy passing on intermediate solutions to facilitate 'join' behavior """ bindings = bindings if bindings else {} try: tp = next(goalsRemaining) assert isinstance(bindings, dict) dPred = self.derivedPredicateFromTriple(tp) if dPred is None: baseEDBQuery = EDBQuery([BuildUnitermFromTuple(tp)], self.edb, bindings=bindings) if self.DEBUG: _debug( "Evaluating TP against EDB: %s" % baseEDBQuery.asSPARQL()) query, rt = baseEDBQuery.evaluate() if isinstance(rt, bool) and rt: yield bindings elif not isinstance(rt, bool): rt = list(rt) remaining_goals = itertools.tee(goalsRemaining, len(rt)) for idx in range(len(rt)): item = {} item.update(rt[idx]) item.update(bindings) if self.DEBUG: _debug("Solution from EDB query: %s" % item) for ansDict in self.conjunctiveSipStrategy( remaining_goals[idx], factGraph, item): yield ansDict else: queryLit = BuildUnitermFromTuple(tp) currentOp = GetOp(queryLit) queryLit.setOperator(currentOp) query = EDBQuery([queryLit], self.edb, bindings=bindings) if bindings: tp = first(query.formulae).toRDFTuple() if self.DEBUG: _debug("Goal/Query: %s" % query.asSPARQL()) tp = self.hybridPredQueryPreparation(tp) SetupDDLAndAdornProgram( self.edb, self.idb, [tp], derivedPreds=self.derivedPredicates, ignoreUnboundDPreds=True) sipCollection = PrepareSipCollection(self.edb.adornedProgram) if self.DEBUG and sipCollection: for sip in SIPRepresentation(sipCollection): _debug(sip) _debug(pformat(list(self.edb.adornedProgram))) elif self.DEBUG: _debug("No SIP graph.") for nextAnswer, ns in self.invokeDecisionProcedure( tp, factGraph, bindings, self.DEBUG, sipCollection): if isinstance(nextAnswer, dict): # Received solutions to 'open' query, merge with given # bindings and continue for ansDict in self.conjunctiveSipStrategy( goalsRemaining, factGraph, mergeMappings1To2(bindings, nextAnswer)): yield ansDict elif nextAnswer: # we (successfully) proved a ground query, pass on # bindings assert isinstance(nextAnswer, bool) for ansDict in self.conjunctiveSipStrategy( goalsRemaining, factGraph, bindings): yield ansDict except StopIteration: yield bindings
def conjunctiveSipStrategy(self, goalsRemaining, factGraph, bindings=None): """ Given a conjunctive set of triples, invoke sip-strategy passing on intermediate solutions to facilitate 'join' behavior """ bindings = bindings if bindings else {} try: tp = next(goalsRemaining) assert isinstance(bindings, dict) dPred = self.derivedPredicateFromTriple(tp) if dPred is None: baseEDBQuery = EDBQuery([BuildUnitermFromTuple(tp)], self.edb, bindings=bindings) if self.DEBUG: print("Evaluating TP against EDB:%s" % baseEDBQuery.asSPARQL()) query, rt = baseEDBQuery.evaluate() # _vars = baseEDBQuery.returnVars for item in rt: bindings.update(item) for ansDict in self.conjunctiveSipStrategy( goalsRemaining, factGraph, bindings): yield ansDict else: queryLit = BuildUnitermFromTuple(tp) currentOp = GetOp(queryLit) queryLit.setOperator(currentOp) query = EDBQuery([queryLit], self.edb, bindings=bindings) if bindings: tp = first(query.formulae).toRDFTuple() if self.DEBUG: print("Goal/Query: ", query.asSPARQL()) SetupDDLAndAdornProgram( self.edb, self.idb, [tp], derivedPreds=self.derivedPredicates, ignoreUnboundDPreds=True, hybridPreds2Replace=self.hybridPredicates) if self.hybridPredicates: lit = BuildUnitermFromTuple(tp) op = GetOp(lit) if op in self.hybridPredicates: lit.setOperator(URIRef(op + u'_derived')) tp = lit.toRDFTuple() sipCollection = PrepareSipCollection(self.edb.adornedProgram) if self.DEBUG and sipCollection: for sip in SIPRepresentation(sipCollection): print(sip) pprint(list(self.edb.adornedProgram), sys.stderr) elif self.DEBUG: print("No SIP graph.") for nextAnswer, ns in self.invokeDecisionProcedure( tp, factGraph, bindings, self.DEBUG, sipCollection): nonGroundGoal = isinstance(nextAnswer, dict) if nonGroundGoal or nextAnswer: #Either we recieved bindings from top-down evaluation #or we (successfully) proved a ground query if not nonGroundGoal: #Attempt to prove a ground query, return the response rt = nextAnswer else: #Recieved solutions to 'open' query, merge with given bindings #and continue rt = mergeMappings1To2(bindings, nextAnswer) #either answers were provided (the goal wasn't grounded) or #the goal was ground and successfully proved for ansDict in self.conjunctiveSipStrategy( goalsRemaining, factGraph, rt): yield ansDict except StopIteration: yield bindings