def hybridPredQueryPreparation(self, tp): lit = BuildUnitermFromTuple(tp) op = GetOp(lit) if op in self.hybridPredicates: lit.setOperator(URIRef(op + '_derived')) return lit.toRDFTuple() else: return tp
def hybridPredQueryPreparation(self, tp): lit = BuildUnitermFromTuple(tp, newNss=self.nsBindings) op = GetOp(lit) if op in self.hybridPredicates: lit.setOperator(URIRef(op + u'_derived')) return lit.toRDFTuple() else: return tp
def SetupMetaInterpreter(tBoxGraph, goal, useThingRule=True): from pprint import pprint from FuXi.LP.BackwardFixpointProcedure import BackwardFixpointProcedure from FuXi.Rete.Magic import SetupDDLAndAdornProgram # , PrettyPrintRule from FuXi.Horn.PositiveConditions import BuildUnitermFromTuple # , Exists from FuXi.Rete.TopDown import PrepareSipCollection from FuXi.DLP import LloydToporTransformation, makeRule from FuXi.Rete.SidewaysInformationPassing import GetOp owlThingAppears = False if useThingRule and OWL.Thing in tBoxGraph.all_nodes(): owlThingAppears = True completionRules = HornFromN3(StringIO(RULES)) if owlThingAppears: completionRules.formulae.extend( HornFromN3(StringIO(CONDITIONAL_THING_RULE))) reducedCompletionRules = set() for rule in completionRules: for clause in LloydToporTransformation(rule.formula): rule = makeRule(clause, {}) # _debug(rule) # PrettyPrintRule(rule) reducedCompletionRules.add(rule) network = SetupRuleStore(makeNetwork=True)[-1] SetupDDLAndAdornProgram( tBoxGraph, reducedCompletionRules, [goal], derivedPreds=derivedPredicates, ignoreUnboundDPreds=True, hybridPreds2Replace=hybridPredicates) lit = BuildUnitermFromTuple(goal) op = GetOp(lit) lit.setOperator(URIRef(op + '_derived')) goal = lit.toRDFTuple() sipCollection = PrepareSipCollection(reducedCompletionRules) tBoxGraph.templateMap = {} bfp = BackwardFixpointProcedure( tBoxGraph, network, derivedPredicates, goal, sipCollection, hybridPredicates=hybridPredicates, debug=True) bfp.createTopDownReteNetwork(True) _debug(pformat(reducedCompletionRules)) rt = bfp.answers(debug=True) _debug(pformat(rt)) _debug(bfp.metaInterpNetwork) bfp.metaInterpNetwork.reportConflictSet(True, sys.stderr) for query in bfp.edbQueries: _debug("Dispatched query against dataset: %s" % query.asSPARQL()) _debug(pformat(list(bfp.goalSolutions)))
def SetupMetaInterpreter(tBoxGraph, goal, useThingRule=True): from FuXi.LP.BackwardFixpointProcedure import BackwardFixpointProcedure from FuXi.Rete.Magic import SetupDDLAndAdornProgram from FuXi.Horn.PositiveConditions import BuildUnitermFromTuple from FuXi.Rete.TopDown import PrepareSipCollection from FuXi.DLP import LloydToporTransformation, makeRule from FuXi.Rete.SidewaysInformationPassing import GetOp owlThingAppears = False if useThingRule and OWL.Thing in tBoxGraph.all_nodes(): owlThingAppears = True completionRules = HornFromN3(StringIO(RULES)) if owlThingAppears: completionRules.formulae.extend( HornFromN3(StringIO(CONDITIONAL_THING_RULE))) reducedCompletionRules = set() for rule in completionRules: for clause in LloydToporTransformation(rule.formula): rule = makeRule(clause, {}) # log.debug(rule) # PrettyPrintRule(rule) reducedCompletionRules.add(rule) network = SetupRuleStore(makeNetwork=True)[-1] SetupDDLAndAdornProgram( tBoxGraph, reducedCompletionRules, [goal], derivedPreds=derivedPredicates, ignoreUnboundDPreds=True, hybridPreds2Replace=hybridPredicates) lit = BuildUnitermFromTuple(goal) op = GetOp(lit) lit.setOperator(URIRef(op + u'_derived')) goal = lit.toRDFTuple() sipCollection = PrepareSipCollection(reducedCompletionRules) tBoxGraph.templateMap = {} bfp = BackwardFixpointProcedure( tBoxGraph, network, derivedPredicates, goal, sipCollection, hybridPredicates=hybridPredicates, debug=True) bfp.createTopDownReteNetwork(True) log.debug(reducedCompletionRules) rt = bfp.answers(debug=True) log.debug(rt) log.debug(bfp.metaInterpNetwork) bfp.metaInterpNetwork.reportConflictSet(True, sys.stderr) for query in bfp.edbQueries: log.debug("Dispatched query against dataset: ", query.asSPARQL()) log.debug(list(bfp.goalSolutions))
def SipStrategy(query, sipCollection, factGraph, derivedPreds, bindings={}, processedRules=None, network=None, debug=False, buildProof=False, memoizeMemory=None, proofLevel=1): """ Accordingly, we define a sip-strategy for computing the answers to a query expressed using a set of Datalog rules, and a set of sips, one for each adornment of a rule head, as follows... Each evaluation uses memoization (via Python decorators) but also relies on well-formed rewrites for using semi-naive bottom up method over large SPARQL data. """ memoizeMemory = memoizeMemory and memoizeMemory or {} queryLiteral = BuildUnitermFromTuple(query) processedRules = processedRules and processedRules or set() if bindings: # There are bindings. Apply them to the terms in the query queryLiteral.ground(bindings) if debug: print("%sSolving" % ('\t' * proofLevel), queryLiteral, bindings) # Only consider ground triple pattern isomorphism with matching bindings goalRDFStatement = queryLiteral.toRDFTuple() if queryLiteral in memoizeMemory: if debug: print("%sReturning previously calculated results for " % ('\t' * proofLevel), queryLiteral) for answers in memoizeMemory[queryLiteral]: yield answers elif AlphaNode(goalRDFStatement).alphaNetworkHash( True, skolemTerms=list(bindings.values())) in \ [AlphaNode(r.toRDFTuple()).alphaNetworkHash(True, skolemTerms=list(bindings.values())) for r in processedRules if AdornLiteral(goalRDFStatement).adornment == r.adornment]: if debug: print("%s Goal already processed..." % ('\t' * proofLevel)) else: isGround = literalIsGround(queryLiteral) if buildProof: ns = NodeSet(goalRDFStatement, network=network, identifier=BNode()) else: ns = None # adornedProgram = factGraph.adornedProgram queryPred = GetOp(queryLiteral) if sipCollection is None: rules = [] else: # For every rule head matching the query, we invoke the rule, # thus determining an adornment, and selecting a sip to follow rules = sipCollection.headToRule.get(queryPred, set()) if None in sipCollection.headToRule: # If there are second order rules, we add them # since they are a 'wildcard' rules.update(sipCollection.headToRule[None]) # maintained list of rules that haven't been processed before and # match the query validRules = [] # each subquery contains values for the bound arguments that are passed # through the sip arcs entering the node corresponding to that literal. For # each subquery generated, there is a set of answers. answers = [] # variableMapping = {} # Some TBox queries can be 'joined' together into SPARQL queries against # 'base' predicates via an RDF dataset # These atomic concept inclusion axioms can be evaluated together # using a disjunctive operator at the body of a horn clause # where each item is a query of the form uniPredicate(?X): # Or( uniPredicate1(?X1), uniPredicate2(?X), uniPredicate3(?X), ..) # In this way massive, conjunctive joins can be 'mediated' # between the stated facts and the top-down solver @parameterizedPredicate([i for i in derivedPreds]) def IsAtomicInclusionAxiomRHS(rule, dPreds): """ This is an atomic inclusion axiom with a variable (or bound) RHS: uniPred(?ENTITY) """ bodyList = list(iterCondition(rule.formula.body)) body = first(bodyList) return GetOp(body) not in dPreds and \ len(bodyList) == 1 and \ body.op == RDF.type atomicInclusionAxioms = list(filter( IsAtomicInclusionAxiomRHS, rules)) if atomicInclusionAxioms and len(atomicInclusionAxioms) > 1: if debug: print("\tCombining atomic inclusion axioms: ") pprint(atomicInclusionAxioms, sys.stderr) if buildProof: factStep = InferenceStep(ns, source='some RDF graph') ns.steps.append(factStep) axioms = [rule.formula.body for rule in atomicInclusionAxioms] # attempt to exaustively apply any available substitutions # and determine if query if fully ground vars = [v for v in GetArgs(queryLiteral, secondOrder=True) if isinstance(v, Variable)] openVars, axioms, _bindings = \ normalizeBindingsAndQuery(vars, bindings, axioms) if openVars: # mappings = {} # See if we need to do any variable mappings from the query literals # to the literals in the applicable rules query, rt = EDBQuery(axioms, factGraph, openVars, _bindings).evaluate(debug, symmAtomicInclusion=True) if buildProof: # FIXME: subquery undefined factStep.groundQuery = subquery for ans in rt: if buildProof: factStep.bindings.update(ans) memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(ans), ns)) yield ans, ns else: # All the relevant derivations have been explored and the result # is a ground query we can directly execute against the facts if buildProof: factStep.bindings.update(bindings) query, rt = EDBQuery(axioms, factGraph, _bindings).evaluate(debug, symmAtomicInclusion=True) if buildProof: # FIXME: subquery undefined factStep.groundQuery = subquery memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(rt), ns)) yield rt, ns rules = filter( lambda i: not IsAtomicInclusionAxiomRHS(i), rules) for rule in rules: # An exception is the special predicate ph; it is treated as a base # predicate and the tuples in it are those supplied for qb by # unification. headBindings = getBindingsFromLiteral( goalRDFStatement, rule.formula.head) # comboBindings = dict([(k, v) for k, v in itertools.chain( # bindings.items(), # headBindings.items())]) varMap = rule.formula.head.getVarMapping(queryLiteral) if headBindings and\ [term for term in rule.formula.head.getDistinguishedVariables(True) if varMap.get(term, term) not in headBindings]: continue # subQueryAnswers = [] # dontStop = True # projectedBindings = comboBindings.copy() if debug: print("%sProcessing rule" % ('\t' * proofLevel), rule.formula) if debug and sipCollection: print( "Sideways Information Passing (sip) graph for %s: " % queryLiteral) print(sipCollection.serialize(format='n3')) for sip in SIPRepresentation(sipCollection): print(sip) try: # Invoke the rule if buildProof: step = InferenceStep(ns, rule.formula) else: step = None for rt, step in\ invokeRule([headBindings], iter(iterCondition(rule.formula.body)), rule.sip, (proofLevel + 1, memoizeMemory, sipCollection, factGraph, derivedPreds, processedRules.union([ AdornLiteral(query)])), step=step, debug=debug): if rt: if isinstance(rt, dict): # We received a mapping and must rewrite it via # correlation between the variables in the rule head # and the variables in the original query (after applying # bindings) varMap = rule.formula.head.getVarMapping( queryLiteral) if varMap: rt = MakeImmutableDict( refactorMapping(varMap, rt)) if buildProof: step.bindings = rt else: if buildProof: step.bindings = headBindings validRules.append(rule) if buildProof: ns.steps.append(step) if isGround: yield True, ns else: memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(rt), ns)) yield rt, ns except RuleFailure: # Clean up failed antecedents if buildProof: if ns in step.antecedents: step.antecedents.remove(ns) if not validRules: # No rules matching, query factGraph for answers successful = False if buildProof: factStep = InferenceStep(ns, source='some RDF graph') ns.steps.append(factStep) if not isGround: subquery, rt = EDBQuery([queryLiteral], factGraph, [v for v in GetArgs(queryLiteral, secondOrder=True) if isinstance(v, Variable)], bindings).evaluate(debug) if buildProof: factStep.groundQuery = subquery for ans in rt: successful = True if buildProof: factStep.bindings.update(ans) memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(ans), ns)) yield ans, ns if not successful and queryPred not in derivedPreds: # Open query didn't return any results and the predicate # is ostensibly marked as derived predicate, so we have # failed memoizeMemory.setdefault( queryLiteral, set()).add((False, ns)) yield False, ns else: # All the relevant derivations have been explored and the result # is a ground query we can directly execute against the facts if buildProof: factStep.bindings.update(bindings) subquery, rt = EDBQuery([queryLiteral], factGraph, bindings).evaluate(debug) if buildProof: factStep.groundQuery = subquery memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(rt), ns)) yield rt, ns
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 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
def SipStrategy(query, sipCollection, factGraph, derivedPreds, bindings={}, processedRules=None, network=None, debug=False, buildProof=False, memoizeMemory=None, proofLevel=1): """ Accordingly, we define a sip-strategy for computing the answers to a query expressed using a set of Datalog rules, and a set of sips, one for each adornment of a rule head, as follows... Each evaluation uses memoization (via Python decorators) but also relies on well-formed rewrites for using semi-naive bottom up method over large SPARQL data. """ memoizeMemory = memoizeMemory and memoizeMemory or {} queryLiteral = BuildUnitermFromTuple(query) processedRules = processedRules and processedRules or set() if bindings: #There are bindings. Apply them to the terms in the query queryLiteral.ground(bindings) if debug: print("%sSolving" % ('\t' * proofLevel), queryLiteral, bindings) # Only consider ground triple pattern isomorphism with matching bindings goalRDFStatement = queryLiteral.toRDFTuple() if queryLiteral in memoizeMemory: if debug: print("%sReturning previously calculated results for " % \ ('\t' * proofLevel), queryLiteral) for answers in memoizeMemory[queryLiteral]: yield answers elif AlphaNode(goalRDFStatement).alphaNetworkHash( True, skolemTerms=list(bindings.values())) in \ [AlphaNode(r.toRDFTuple()).alphaNetworkHash(True, skolemTerms=list(bindings.values())) for r in processedRules if AdornLiteral(goalRDFStatement).adornment == \ r.adornment]: if debug: print("%s Goal already processed..." % \ ('\t' * proofLevel)) else: isGround = literalIsGround(queryLiteral) if buildProof: ns = NodeSet(goalRDFStatement, network=network, identifier=BNode()) else: ns = None # adornedProgram = factGraph.adornedProgram queryPred = GetOp(queryLiteral) if sipCollection is None: rules = [] else: #For every rule head matching the query, we invoke the rule, #thus determining an adornment, and selecting a sip to follow rules = sipCollection.headToRule.get(queryPred, set()) if None in sipCollection.headToRule: #If there are second order rules, we add them #since they are a 'wildcard' rules.update(sipCollection.headToRule[None]) #maintained list of rules that haven't been processed before and #match the query validRules = [] #each subquery contains values for the bound arguments that are passed #through the sip arcs entering the node corresponding to that literal. For #each subquery generated, there is a set of answers. answers = [] # variableMapping = {} #Some TBox queries can be 'joined' together into SPARQL queries against #'base' predicates via an RDF dataset #These atomic concept inclusion axioms can be evaluated together #using a disjunctive operator at the body of a horn clause #where each item is a query of the form uniPredicate(?X): #Or( uniPredicate1(?X1), uniPredicate2(?X), uniPredicate3(?X), ..) #In this way massive, conjunctive joins can be 'mediated' #between the stated facts and the top-down solver @parameterizedPredicate([i for i in derivedPreds]) def IsAtomicInclusionAxiomRHS(rule, dPreds): """ This is an atomic inclusion axiom with a variable (or bound) RHS: uniPred(?ENTITY) """ bodyList = list(iterCondition(rule.formula.body)) body = first(bodyList) return GetOp(body) not in dPreds and \ len(bodyList) == 1 and \ body.op == RDF.type atomicInclusionAxioms = list(filter(IsAtomicInclusionAxiomRHS, rules)) if atomicInclusionAxioms and len(atomicInclusionAxioms) > 1: if debug: print("\tCombining atomic inclusion axioms: ") pprint(atomicInclusionAxioms, sys.stderr) if buildProof: factStep = InferenceStep(ns, source='some RDF graph') ns.steps.append(factStep) axioms = [rule.formula.body for rule in atomicInclusionAxioms] #attempt to exaustively apply any available substitutions #and determine if query if fully ground vars = [ v for v in GetArgs(queryLiteral, secondOrder=True) if isinstance(v, Variable) ] openVars, axioms, _bindings = \ normalizeBindingsAndQuery(vars, bindings, axioms) if openVars: # mappings = {} #See if we need to do any variable mappings from the query literals #to the literals in the applicable rules query, rt = EDBQuery(axioms, factGraph, openVars, _bindings).evaluate( debug, symmAtomicInclusion=True) if buildProof: factStep.groundQuery = subquery for ans in rt: if buildProof: factStep.bindings.update(ans) memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(ans), ns)) yield ans, ns else: #All the relevant derivations have been explored and the result #is a ground query we can directly execute against the facts if buildProof: factStep.bindings.update(bindings) query, rt = EDBQuery(axioms, factGraph, _bindings).evaluate( debug, symmAtomicInclusion=True) if buildProof: factStep.groundQuery = subquery memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(rt), ns)) yield rt, ns rules = filter(lambda i: not IsAtomicInclusionAxiomRHS(i), rules) for rule in rules: #An exception is the special predicate ph; it is treated as a base #predicate and the tuples in it are those supplied for qb by unification. headBindings = getBindingsFromLiteral(goalRDFStatement, rule.formula.head) # comboBindings = dict([(k, v) for k, v in itertools.chain( # bindings.items(), # headBindings.items())]) varMap = rule.formula.head.getVarMapping(queryLiteral) if headBindings and\ [term for term in rule.formula.head.getDistinguishedVariables(True) if varMap.get(term, term) not in headBindings]: continue # subQueryAnswers = [] # dontStop = True # projectedBindings = comboBindings.copy() if debug: print("%sProcessing rule" % \ ('\t' * proofLevel), rule.formula) if debug and sipCollection: print("Sideways Information Passing (sip) graph for %s: " % queryLiteral) print(sipCollection.serialize(format='n3')) for sip in SIPRepresentation(sipCollection): print(sip) try: # Invoke the rule if buildProof: step = InferenceStep(ns, rule.formula) else: step = None for rt, step in\ invokeRule([headBindings], iter(iterCondition(rule.formula.body)), rule.sip, (proofLevel + 1, memoizeMemory, sipCollection, factGraph, derivedPreds, processedRules.union([ AdornLiteral(query)])), step=step, debug=debug): if rt: if isinstance(rt, dict): #We received a mapping and must rewrite it via #correlation between the variables in the rule head #and the variables in the original query (after applying #bindings) varMap = rule.formula.head.getVarMapping( queryLiteral) if varMap: rt = MakeImmutableDict( refactorMapping(varMap, rt)) if buildProof: step.bindings = rt else: if buildProof: step.bindings = headBindings validRules.append(rule) if buildProof: ns.steps.append(step) if isGround: yield True, ns else: memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(rt), ns)) yield rt, ns except RuleFailure: # Clean up failed antecedents if buildProof: if ns in step.antecedents: step.antecedents.remove(ns) if not validRules: #No rules matching, query factGraph for answers successful = False if buildProof: factStep = InferenceStep(ns, source='some RDF graph') ns.steps.append(factStep) if not isGround: subquery, rt = EDBQuery([queryLiteral], factGraph, [ v for v in GetArgs(queryLiteral, secondOrder=True) if isinstance(v, Variable) ], bindings).evaluate(debug) if buildProof: factStep.groundQuery = subquery for ans in rt: successful = True if buildProof: factStep.bindings.update(ans) memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(ans), ns)) yield ans, ns if not successful and queryPred not in derivedPreds: #Open query didn't return any results and the predicate #is ostensibly marked as derived predicate, so we have failed memoizeMemory.setdefault(queryLiteral, set()).add( (False, ns)) yield False, ns else: #All the relevant derivations have been explored and the result #is a ground query we can directly execute against the facts if buildProof: factStep.bindings.update(bindings) subquery, rt = EDBQuery([queryLiteral], factGraph, bindings).evaluate(debug) if buildProof: factStep.groundQuery = subquery memoizeMemory.setdefault(queryLiteral, set()).add( (prepMemiozedAns(rt), ns)) yield rt, ns
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 \ _expr.name == 'BGP': # 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(sip) pprint(list(self.edb.adornedProgram)) elif self.DEBUG: print("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 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
class BackwardFixpointProcedure(object): """ Uses RETE-UL as a production rule system implementation of a meta-interpreter of an adorned RIF Core ruleset that builds solves conjunctive (BGPs) SPARQL queries. Facts are only generated in a bottom up evaluation of the interpreter if a query has been issued for that fact or if an appropriate sub-query has been generated. Sub-queries for rule bodies (conditions) are generated if a sub-query for the corresponding rule head already exists. Sub-queries for conjuncts are generated from sub-queries of conjunctions they appear in (queries are collected). """ def __init__( self, factGraph, network, derivedPredicates, goal, sipCollection=[], hybridPredicates=None, debug=False, pushDownMDBQ=True, specialBNodeHandling=None, ): self.specialBNodeHandling = specialBNodeHandling self.debug = debug self.metaRule2Network = {} self.pushDownMDBQ = pushDownMDBQ self.pushDownQueries = {} self.maxEDBFront2End = {} self.queryPredicates = set() self.sipCollection = sipCollection self.goal = BuildUnitermFromTuple(goal) self.factGraph = factGraph self.rules = list(factGraph.adornedProgram) self.discardedRules = set() self.ruleLabels = {} self.bfpLookup = {} self.actionHash = {} self.namespaces = {u"bfp": BFP_NS, u"rule": BFP_RULE} self.metaInterpNetwork = network self.derivedPredicates = set(derivedPredicates) if isinstance(derivedPredicates, list) else derivedPredicates self.hybridPredicates = hybridPredicates if hybridPredicates else [] self.edbQueries = set() self.goalSolutions = set() def answers(self, debug=False, solutionCallback=NoopCallbackFn): """ Takes a conjunctive query, a sip collection and initiates the meta-interpreter for a given goal (at a time), propagating evaluate procedures explicitely if no bindings are given from the query to trigger subsequent subqueries via EDB predicates @TODO: Add a PRD externally defined action to the production of rules that produce answers for the query predicate. The action is a user specified callback that can be used to signal InferredGoal and halt RETE/UL evaluation prematurely otherwise, it is left to reach a stable state and the answers collected along the way are added and returned """ # solutions = [] # queryOp = GetOp(self.goal) if self.goal.isGround(): # Mark ground goal so, production rule engine # halts when goal is inferred self.metaInterpNetwork.goal = self.goal.toRDFTuple() adornment = ["f" if isinstance(v, Variable) else "b" for v in GetArgs(self.goal, secondOrder=True)] adornment = reduce(lambda x, y: x + y, adornment) adornedQuery = AdornedUniTerm(self.goal, adornment) bfpTopQuery = self.makeDerivedQueryPredicate(adornedQuery) if debug: print("Asserting initial BFP query ", bfpTopQuery) assert bfpTopQuery.isGround() # Add BFP query atom to working memory, triggering procedure try: self.metaInterpNetwork.feedFactsToAdd( generateTokenSet([bfpTopQuery.toRDFTuple()], debugTriples=[bfpTopQuery.toRDFTuple()] if debug else []) ) except InferredGoal: if debug: print("Reached ground goal. Terminated BFP.") return True else: if self.goal.isGround(): # Ground goal, but didn't trigger it, response must be negative return False def specializeConjuncts(self, rule, idx, evalVars): """ Extends the (vanilla) meta-interpreter for magic set and alexander rewriting sip strategies with capabilities for collapsing chains of extensional predicate queries (frames whose attributes are in EDB and externally-defined predicates) into a single SPARQL query """ # _len = len(rule.formula.body) body = list(iterCondition(rule.formula.body)) skipMDBQCount = 0 for bodyIdx, bodyLiteral in enumerate(body): conjunct = [] # V_{j} = V_{j-1} UNION vars(Literal(..)) where j <> 0 evalVars[(idx + 1, bodyIdx + 1)] = ( list(GetVariables(bodyLiteral, secondOrder=True)) + evalVars[(idx + 1, bodyIdx)] ) if skipMDBQCount > 0: skipMDBQCount -= 1 continue # remainingBodyList = body[bodyIdx+1:] if bodyIdx+1<_len else [] conjunct = EDBQueryFromBodyIterator( self.factGraph, rule.formula.body.formulae[bodyIdx:], self.derivedPredicates, self.hybridPredicates ) lazyBaseConjunct = self.pushDownMDBQ and conjunct pattern = HashablePatternList([(BFP_RULE[str(idx + 1)], BFP_NS.evaluate, Literal(bodyIdx))]) pattern2 = HashablePatternList( [None, (BFP_RULE[str(idx + 1)], BFP_NS.evaluate, Literal(bodyIdx)), bodyLiteral.toRDFTuple()] ) aNodeDk = self.metaInterpNetwork.nodes[pattern] # Rule d^k # query_Literal(x0, ..., xj) :- evaluate(ruleNo, j, X) # query invokation tNode = first(aNodeDk.descendentBetaNodes) assert len(aNodeDk.descendentBetaNodes) == 1 newEvalMemory = SetupEvaluationBetaNode(tNode, rule, self.metaInterpNetwork) isBase = bodyLiteral.adornment is None if isinstance(bodyLiteral, AdornedUniTerm) else True if isinstance(bodyLiteral, N3Builtin): if aNodeDk in self.metaInterpNetwork.alphaNodes: self.metaInterpNetwork.alphaNodes.remove(aNodeDk) # evalTerm = (BFP_RULE[str(idx+1)], BFP_NS.evaluate, Literal(bodyIdx)) del aNodeDk executeAction = EvaluateExecution((idx + 1, bodyIdx), self, []) builtInNode = self.metaRule2Network[self.bfpLookup[("c", idx + 1, bodyIdx + 1)]] assert isinstance(builtInNode.rightNode, BuiltInAlphaNode) builtInNode.executeActions[bodyLiteral.toRDFTuple()] = (True, executeAction) # We bypass d^k, so when evaluate(ruleNo, j, X) is inferred # it is added to left memory of pNode associated with c^k self.evalHash.setdefault((idx + 1, bodyIdx), []).append(builtInNode.memories[LEFT_MEMORY]) self.actionHash.setdefault((idx + 1, bodyIdx + 1), set()).add(builtInNode) elif conjunct and (isBase or lazyBaseConjunct): singleConj = EDBQuery([copy.deepcopy(item) for item in conjunct], self.factGraph) matchingTriple = first(tNode.consequent) assert len(tNode.consequent) == 1 newAction = QueryExecution( self, bodyLiteral, conjoinedTokenMem=self.maxEDBFront2End[(idx + 1, bodyIdx + 1)] if lazyBaseConjunct else None, edbConj=conjunct if lazyBaseConjunct else singleConj, ) self.evalHash.setdefault((idx + 1, bodyIdx), []).append(newEvalMemory) # If the body predicate is a 2nd order predicate, we don't infer the # second order query predicate (since it will trigger a query into # the EDB and thus there is no need to trigger subsequent rules) tNode.executeActions[matchingTriple] = (True, newAction) else: self.evalHash.setdefault((idx + 1, bodyIdx), []).append(newEvalMemory) if IsHybridPredicate(bodyLiteral, self.hybridPredicates) or ( (GetOp(bodyLiteral) in self.derivedPredicates) and not (isBase and len(conjunct) > 1) ): # if pattern2 not in self.metaInterpNetwork.nodes: import pdb;pdb.set_trace() assert pattern2 in self.metaInterpNetwork.nodes termNodeCk = self.metaInterpNetwork.nodes[pattern2] # Rule c^k # evaluate(ruleNo, j+1, X) :- evaluate(ruleNo, j, X), bodyLiteral self.actionHash.setdefault((idx + 1, bodyIdx + 1), set()).add(termNodeCk) assert isinstance(termNodeCk.rightNode, AlphaNode) termNodeCk.leftVariables = set(evalVars[(idx + 1, bodyIdx)]) termNodeCk.rightVariables = set(GetVariables(bodyLiteral, secondOrder=True)) termNodeCk.commonVariables = termNodeCk.rightVariables.intersection(termNodeCk.leftVariables) if lazyBaseConjunct and len(conjunct) > 1: endIdx = self.maxEDBFront2End[(idx + 1, bodyIdx + 1)][-1] skipMDBQCount = endIdx - bodyIdx - 1 def checkNetworkWellformedness(self): for key, rule in list(self.bfpLookup.items()): if len(key) == 2: ruleType, ruleIdx = key bodyIdx = None else: ruleType, ruleIdx, bodyIdx = key termNode = self.metaRule2Network[rule] headTuple = rule.formula.head.toRDFTuple() # p(..) :- q_1(..), q_2(..), ..., q_n(..) if GetOp(rule.formula.head) == BFP_NS.evaluate: # evaluate(.., ..) :- override, executeFn = termNode.executeActions.get(headTuple, (None, None)) assert override and isinstance(executeFn, EvaluateExecution), termNode assert executeFn.ruleNo == ruleIdx assert executeFn.bodyIdx == headTuple[-1] assert bodyIdx is None or executeFn.bodyIdx == int(bodyIdx), bodyIdx if isinstance(rule.formula.body, And): # c^{ruleIdx}_{bodyIdx} # evaluate(.., j+1) :- evaluate(.., j), q_{j+1}(..) # @@ force check builtins or derived predicate c rules if isinstance(termNode.leftNode, AlphaNode): # alphaNode = termNode.leftNode betaNode = termNode.rightNode assert isinstance(termNode.memories[RIGHT_MEMORY], EvaluateConjunctiveQueryMemory), termNode assert isinstance(betaNode, BetaNode) elif not termNode.fedByBuiltin: # alphaNode = termNode.rightNode betaNode = termNode.leftNode assert ( isinstance(termNode.memories[LEFT_MEMORY], EvaluateConjunctiveQueryMemory) or self.evalHash[(ruleIdx, bodyIdx - 1)][0].successor != termNode ), termNode assert isinstance(betaNode, BetaNode) else: # b^{ruleIdx} # evaluate(.., j+1) :- query-p(..) assert termNode.aPassThru elif isinstance(rule.formula.body, And): # a^{ruleIdx} # p(..) :- query-p(..), evaluate(.., n) assert isinstance(termNode.memories[RIGHT_MEMORY], EvaluateConjunctiveQueryMemory) else: # d^{ruleIdx}_{bodyIdx} # query-q_{j+1}(..) :- evaluate(.., j) queryLiteral = list(iterCondition(self.rules[ruleIdx - 1].formula.body))[bodyIdx - 1] if isinstance(queryLiteral, N3Builtin): headTuple = queryLiteral.toRDFTuple() executeKind = EvaluateExecution else: executeKind = QueryExecution if GetOp(queryLiteral) not in self.derivedPredicates: override, executeFn = termNode.executeActions.get(headTuple, (None, None)) assert override and isinstance(executeFn, executeKind), "%s %s %s" % ( termNode.consequent, termNode.executeActions, termNode, ) if not isinstance(queryLiteral, N3Builtin): assert executeFn.queryLiteral == queryLiteral # self.bfp.evalHash[self.conjoinedTokenMem] assert executeFn.conjoinedTokenMem[0] == int(ruleIdx), "%s %s %s" % (termNode, executeFn, key) def createTopDownReteNetwork(self, debug=False): """ Uses the specialized BFP meta-interpretation rules to build a RETE-UL decision network that is modified to support the propagation of bindings from the evaluate predicates into a supplimental magic set sip strategy and the generation of subqueries. The end result is a bottom-up simulation of SLD resolution with complete, sound, and safe memoization in the face of recursion """ for rule in set(self.specializeAdornedRuleset(debug)): self.metaRule2Network[rule] = self.metaInterpNetwork.buildNetworkFromClause(rule) if debug: sortedBFPRules = [ str("%s : %s") % (key, self.bfpLookup[key]) for key in sorted(self.bfpLookup, key=lambda items: str(items[1]) + items[0]) ] for _ruleStr in sortedBFPRules: print(_ruleStr) self.evalHash = {} self.actionHash = {} evalVars = {} self.productions = {} for idx, rule in enumerate(self.rules): if rule in self.discardedRules: continue # label = BFP_RULE[str(idx+1)] conjunctLength = len(list(iterCondition(rule.formula.body))) # Rule a^k # p(x0, ..., xn) :- And(query_p(x0, ..., xn) evaluate(ruleNo, n, X)) currentPattern = HashablePatternList([(BFP_RULE[str(idx + 1)], BFP_NS.evaluate, Literal(conjunctLength))]) assert rule.declare # Find alpha node associated with evaluate condition node = self.metaInterpNetwork.nodes[currentPattern] # evaluate(k, n, X) is a condition in only 1 bfp rule assert len(node.descendentBetaNodes) == 1 bNode = first(node.descendentBetaNodes) assert bNode.leftNode.aPassThru assert len(bNode.consequent) == 1 newEvalMemory = SetupEvaluationBetaNode(bNode, rule, self.metaInterpNetwork) self.evalHash.setdefault((idx + 1, conjunctLength), []).append(newEvalMemory) if GetOp(rule.formula.head) == GetOp(self.goal): # This rule matches a goal, add a solution collecting action goalSolutionAction = GoalSolutionAction(self, rule.formula.head.getVarMapping(self.goal)) bNode.executeActions[rule.formula.head.toRDFTuple()] = (False, goalSolutionAction) self.productions.setdefault(GetOp(rule.formula.head), []).append((idx, bNode)) # Rule b^k # evaluate(ruleNo, 0, X) :- query_p(x0, ..., xn) _rule = self.bfpLookup[("b", idx + 1)] # alpha node associated with query predicate for head of original rule _bodyAlphaNode = self.metaInterpNetwork.nodes[HashablePatternList([_rule.formula.body.toRDFTuple()])] assert len(_bodyAlphaNode.descendentBetaNodes) == 1 tNode = first(_bodyAlphaNode.descendentBetaNodes) self.actionHash.setdefault((idx + 1, 0), set()).add(tNode) # V_{0} = vars(query_p(..)) headQueryPred = list(iterCondition(_rule.formula.body))[0] try: evalVars[(idx + 1, 0)] = list(headQueryPred.terms) except IndexError: raise self.discardedRules.add(rule) continue self.specializeConjuncts(rule, idx, evalVars) for (ruleNo, bodyIdx), tNodes in list(self.actionHash.items()): # Attach evaluate action to p-node that propagates # token to beta memory associated with evaluate(ruleNo, bodyIdx) executeAction = EvaluateExecution((ruleNo, bodyIdx), self, tNodes) evaluationStmt = (BFP_RULE[str(ruleNo)], BFP_NS.evaluate, Literal(bodyIdx)) for tNode in tNodes: tNode.executeActions[evaluationStmt] = (True, executeAction) # executeAction = EvaluateExecution(evalHash, (idx+1, bodyIdx+1), self, termNodeCk) # assert len(termNodeCk.consequent)==1 # termNodeCk.executeAction = (None, executeAction) # Fix join variables for BetaNodes involving evaluate predicates for idx, rule in enumerate(self.rules): if rule in self.discardedRules: continue # Rule a^k # p(x0, ..., xn) :- And(query_p(x0, ..., xn) evaluate(ruleNo, n, X)) # Join vars = vars(query_p) AND V_{n} headQueryPred = self.bfpLookup[("b", idx + 1)].formula.body ruleBodyLen = len(list(iterCondition(rule.formula.body))) termNode = first(self.evalHash[idx + 1, ruleBodyLen]).successor termNode.commonVariables = list( set(evalVars[(idx + 1, ruleBodyLen)]).intersection(GetVariables(headQueryPred, secondOrder=True)) ) skipMDBQCount = 0 for bodyIdx, bodyLiteral in enumerate(iterCondition(rule.formula.body)): if skipMDBQCount > 0: skipMDBQCount -= 1 continue if (idx + 1, bodyIdx + 1) in self.actionHash: # Rule c^k # evaluate(ruleNo, j+1, X) :- And(evaluate(ruleNo, j, X) Literal(x0, ..., xj)) # Join vars = vars(Literal) AND V_{j} termNode2 = self.actionHash[(idx + 1, bodyIdx + 1)] assert len(termNode2) == 1 termNode2 = first(termNode2) termNode2.commonVariables = list( set(evalVars[(idx + 1, bodyIdx)]).intersection(GetVariables(bodyLiteral, secondOrder=True)) ) if (idx + 1, bodyIdx + 1) in self.maxEDBFront2End: endIdx = self.maxEDBFront2End[(idx + 1, bodyIdx + 1)][-1] skipMDBQCount = endIdx - bodyIdx - 1 def makeDerivedQueryPredicate(self, predicate): if isinstance(predicate, AdornedUniTerm): newAdornedPred = BFPQueryTerm(predicate, predicate.adornment) elif isinstance(predicate, N3Builtin): newAdornedPred = BFPQueryTerm(predicate, builtin=predicate) else: newAdornedPred = BFPQueryTerm(predicate, None) if isinstance(newAdornedPred, Uniterm): if isinstance(GetOp(newAdornedPred), Variable): newAdornedPred.setOperator(HIGHER_ORDER_QUERY) newAdornedPred.finalize() self.queryPredicates.add(newAdornedPred) return newAdornedPred def specializeAdornedRuleset(self, debug=False): """ Specialization is applied to the BFP meta-interpreter with respect to the rules of the object program. For each rule of the meta-interpreter that includes a premise referring to a rule of the object program, one specialized version is created for each rule of the object program. """ rules = set() for idx, rule in enumerate(self.rules): label = BFP_RULE[str(idx + 1)] ruleBodyLen = len(list(iterCondition(rule.formula.body))) # if rule.isSecondOrder(): # if debug: # print("Skipping second order rule (%s): %s" % (idx+1, rule)) # continue if debug: print("\t%s. %s" % (idx + 1, rule)) for _sip in SIPRepresentation(rule.sip): print("\t\t", _sip) newRule1 = self.rule1(rule, label, ruleBodyLen) self.bfpLookup[("a", idx + 1)] = newRule1 rules.add(newRule1) newRule2 = self.rule2(rule, label, ruleBodyLen) self.bfpLookup[("b", idx + 1)] = newRule2 rules.add(newRule2) # indicate no skipping is ongoing skipMDBQCount = -1 mDBConjFront = None # _len = len(rule.formula.body) for bodyIdx, bodyLiteral in enumerate(iterCondition(rule.formula.body)): bodyPredSymbol = GetOp(bodyLiteral) if skipMDBQCount > 0: skipMDBQCount -= 1 continue elif skipMDBQCount == 0: # finished skipping maximal db conjuncts, mark end of skipped # conjuncts and indicate that no skipping is ongoing self.maxEDBFront2End[mDBConjFront] = (idx + 1, bodyIdx) mDBConjFront = None skipMDBQCount = -1 evaluateTerm = Uniterm(BFP_NS.evaluate, [label, Literal(bodyIdx + 1)], newNss=self.namespaces) priorEvaluateTerm = Uniterm(BFP_NS.evaluate, [label, Literal(bodyIdx)], newNss=self.namespaces) conj = EDBQueryFromBodyIterator( self.factGraph, rule.formula.body.formulae[bodyIdx:], self.derivedPredicates, self.hybridPredicates ) if self.pushDownMDBQ and conj: # There is a maximal db conjunction, indicate skipping of rules involving # conjuncts mDBConjFront = (idx + 1, bodyIdx + 1) if len(conj) > 1: skipMDBQCount = len(conj) - 1 self.pushDownQueries[mDBConjFront] = EDBQuery( [copy.deepcopy(item) for item in conj], self.factGraph ) else: self.maxEDBFront2End[mDBConjFront] = (idx + 1, bodyIdx + 1) if debug and skipMDBQCount > 0: print("maximal db query: ", self.pushDownQueries[mDBConjFront]) print("skipping %s literals, starting from the %s" % (bodyIdx + 1, skipMDBQCount)) if len(conj) + bodyIdx == len(rule.formula.body): # maximal db conjunction takes up rest of body # tokens should go into (k, n) - where n is the body length self.maxEDBFront2End[mDBConjFront] = (idx + 1, len(rule.formula.body)) if ( not self.pushDownMDBQ or ( (bodyPredSymbol in FILTERS and len(conj) == 1) or ( bodyPredSymbol in self.derivedPredicates or IsHybridPredicate(bodyLiteral, self.hybridPredicates) ) # and # bodyPredSymbol not in self.hybridPredicates) or ( # bodyPredSymbol not in FILTERS and bodyIdx+1 == _len) ) ) and skipMDBQCount in (1, -1): # Either not pushing down or: # 1. It is a lone filter # 2. It is a derived predicate (need continuation BFP rule) # evaluate(ruleNo, j+1, X) :- evaluate(ruleNo, j, X) bodyLiteral(..) newRule = self.makeAdornedRule(And([priorEvaluateTerm, bodyLiteral]), evaluateTerm) self.bfpLookup[("c", idx + 1, bodyIdx + 1)] = newRule rules.add(newRule) elif bodyPredSymbol in FILTERS and len(conj) > 2: raise NotImplementedError(repr(rule)) if bodyPredSymbol not in FILTERS: # query_Literal(x0, ..., xj) :- evaluate(ruleNo, j, X) # OpenQuery(query_Literal) newRule = self.makeAdornedRule(priorEvaluateTerm, self.makeDerivedQueryPredicate(bodyLiteral)) self.bfpLookup[("d", idx + 1, bodyIdx + 1)] = newRule rules.add(newRule) return rules def makeAdornedRule(self, body, head): allVars = set() # first we identify body variables # bodyVars = set(reduce(lambda x, y:x+y, # [ list(extractVariables(i, existential=False)) # for i in iterCondition(body) ])) # #then we identify head variables # headVars = set(reduce(lambda x, y:x+y, # [ list(extractVariables(i, existential=False)) # for i in iterCondition(head) ])) return AdornedRule(Clause(body, head), declare=allVars) def rule1(self, rule, label, bodyLen): """ 'Facts are only generated in a bottom up evaluation of the interpreter if a query has been issued for that fact or if an appropriate sub-query has been generated by the metainterpreter itself.' a^{k} p(x0, ..., xn) :- And(query_p(x0, ..., xn) evaluate(ruleNo, n, X)) OpenQuery(query_p) If there are no bindings posed with the query, then OpenQuery(query_p) is used instead of query_p(x0, ..., xn), indicating that there are no bindings but we wish to evaluate this derived predicate. However, despite the fact that it has no bindings, we want to continue to (openly) solve predicates in a depth-first fashion until we hit an EDB query. """ evaluateTerm = Uniterm(BFP_NS.evaluate, [label, Literal(bodyLen)], newNss=self.namespaces) return self.makeAdornedRule( And([self.makeDerivedQueryPredicate(rule.formula.head), evaluateTerm]), rule.formula.head ) def rule2(self, rule, label, bodyLen): """ When a query is matched, collect answers (begin to evaluate) b^{k} evaluate(ruleNo, 0, X) :- query_p(x0, ..., xn) OpenQuery(query_p) If there are no bindings posed with the query, then OpenQuery(query_p) is used instead of query_p(x0, ..., xn), indicating that there are no bindings but we wish to evaluate this derived predicate. However, despite the fact that it has no bindings, we want to continue to (openly) solve predicates in a depth-first fashion until we hit an EDB query. """ evaluateTerm = Uniterm(BFP_NS.evaluate, [label, Literal(0)], newNss=self.namespaces) return self.makeAdornedRule(self.makeDerivedQueryPredicate(rule.formula.head), evaluateTerm)