def SetupRuleStore(n3Stream=None, additionalBuiltins=None, makeNetwork=False): """ Sets up a N3RuleStore, a Graph (that uses it as a store, and ) """ ruleStore = N3RuleStore(additionalBuiltins=additionalBuiltins) nsMgr = NamespaceManager(Graph(ruleStore)) ruleGraph = Graph(ruleStore, namespace_manager=nsMgr) if n3Stream: ruleGraph.parse(n3Stream, format='n3') if makeNetwork: from Network import ReteNetwork closureDeltaGraph = Graph() network = ReteNetwork(ruleStore, inferredTarget=closureDeltaGraph) return ruleStore, ruleGraph, network return ruleStore, ruleGraph
def testExpand(self): EX = Namespace("http://example.com/") namespace_manager = NamespaceManager(Graph()) namespace_manager.bind('ex', EX, override=False) self.testGraph.namespace_manager = namespace_manager man = Class(EX.Man) boy = Class(EX.Boy) woman = Class(EX.Woman) girl = Class(EX.Girl) male = Class(EX.Male) female = Class(EX.Female) human = Class(EX.Human) animal = Class(EX.Animal) cat = Class(EX.Cat) dog = Class(EX.Dog) animal = Class(EX.Animal) animal = cat | dog | human human += man human += boy human += woman human += girl male += man male += boy female += woman female += girl testClass = human & ~female self.assertEquals(repr(testClass), '( ex:Human and ( not ex:Female ) )') newtestClass = ComplementExpansion(testClass, debug=True) self.assertTrue( repr(newtestClass) in ['( ex:Boy or ex:Man )', '( ex:Man or ex:Boy )'], repr(newtestClass)) testClass2 = animal & ~(male | female) self.assertEquals( repr(testClass2), '( ( ex:Cat or ex:Dog or ex:Human ) and ( not ( ex:Male or ex:Female ) ) )' ) newtestClass2 = ComplementExpansion(testClass2, debug=True) testClass2Repr = repr(newtestClass2) self.assertTrue( testClass2Repr in ['( ex:Cat or ex:Dog )', '( ex:Dog or ex:Cat )'], testClass2Repr)
def closureGraph(self,sourceGraph,readOnly=True,store=None): if readOnly: if store is None and not sourceGraph: store = Graph().store store = store is None and sourceGraph.store or store roGraph=ReadOnlyGraphAggregate([sourceGraph,self.inferredFacts], store=store) roGraph.namespace_manager = NamespaceManager(roGraph) for srcGraph in [sourceGraph,self.inferredFacts]: for prefix,uri in srcGraph.namespaces(): roGraph.namespace_manager.bind(prefix,uri) return roGraph else: cg=ConjunctiveGraph() cg+=sourceGraph cg+=self.inferredFacts return cg
def renderNetwork(network,nsMap = {}): """ Takes an instance of a compiled ReteNetwork and a namespace mapping (for constructing QNames for rule pattern terms) and returns a BGL Digraph instance representing the Rete network #(from which GraphViz diagrams can be generated) """ from FuXi.Rete import BuiltInAlphaNode from BetaNode import LEFT_MEMORY, RIGHT_MEMORY, LEFT_UNLINKING dot=Dot(graph_type='digraph') namespace_manager = NamespaceManager(Graph()) for prefix,uri in nsMap.items(): namespace_manager.bind(prefix, uri, override=False) visitedNodes = {} edges = [] idx = 0 for node in network.nodes.values(): if not node in visitedNodes: idx += 1 visitedNodes[node] = generateBGLNode(dot,node,namespace_manager,str(idx)) dot.add_node(visitedNodes[node]) nodeIdxs = {} for node in network.nodes.values(): for mem in node.descendentMemory: if not mem: continue bNode = mem.successor for bNode in node.descendentBetaNodes: for idx,otherNode in enumerate([bNode.leftNode,bNode.rightNode]): if node == otherNode and (node,otherNode) not in edges: for i in [node,bNode]: if i not in visitedNodes: idx += 1 nodeIdxs[i] = idx visitedNodes[i] = generateBGLNode(dot,i,namespace_manager,str(idx)) dot.add_node(visitedNodes[i]) edge = Edge(visitedNodes[node], visitedNodes[bNode], label=idx==0 and 'left' or 'right') dot.add_edge(edge) edges.append((node,bNode)) return dot
def canonicalTerm(self, term): if isinstance(term, URIRef): if self.prolog is not None: namespace_manager = NamespaceManager(Graph()) for prefix, uri in self.prolog.prefixBindings.items(): namespace_manager.bind(prefix, uri, override=False) try: prefix, uri, localName = namespace_manager.compute_qname( term) except: return term if prefix not in self.prolog.prefixBindings: return term else: return u':'.join([prefix, localName]) else: return term elif isinstance(term, Literal): return term.n3() elif isinstance(term, BNode): return term.n3() else: assert isinstance(term, Variable) return term.n3()
def defineProperties(): #namespaces definition aeroOntology = Namespace('http://purl.obolibrary.org/obo/aero.owl') skosNS = Namespace('http://www.w3.org/2004/02/skos/core#') umlsNS = Namespace('http://bioportal.bioontology.org/ontologies/umls/') aeroNS = Namespace('http://purl.obolibrary.org/obo/') OntologyNS = Namespace('http://purl.org/vaers/') medraNS = Namespace('http://purl.bioontology.org/ontology/MDR/') namespace_manager = NamespaceManager(Graph()) namespace_manager.bind('obo', aeroNS, override=False) namespace_manager.bind('owl', OWL_NS, override=False) namespace_manager.bind('aero', aeroOntology, override=False) namespace_manager.bind('skos-core',skosNS, override=False) namespace_manager.bind('umls', umlsNS, override=False) #create the main graph g = Graph() g.namespace_manager = namespace_manager #this tells you that all objects will be created in the g graph -> no need to pass an extra parameter to each Individual.factoryGraph = g return g
def renderProof(self, proof, nsMap={}): """ Takes an instance of a compiled ProofTree and a namespace mapping (for constructing QNames for rule pattern terms) and returns a BGL Digraph instance representing the Proof Tree """ try: import boost.graph as bgl bglGraph = bgl.Digraph() except: try: from pydot import Node, Edge, Dot dot = Dot(graph_type='digraph') except: raise NotImplementedError("No graph libraries") namespace_manager = NamespaceManager(Graph()) vertexMaps = {} edgeMaps = {} # for prefix,uri in nsMap.items(): # namespace_manager.bind(prefix, uri, override=False) visitedNodes = {} edges = [] idx = 0 #register the step nodes for nodeset in self.goals.values(): if not nodeset in visitedNodes: idx += 1 visitedNodes[nodeset] = nodeset.generateGraphNode( str(idx), nodeset is proof) #register the justification steps for justification in nodeset.steps: if not justification in visitedNodes: idx += 1 visitedNodes[ justification] = justification.generateGraphNode( str(idx)) for ant in justification.antecedents: if ant not in visitedNodes: idx += 1 visitedNodes[ant] = ant.generateGraphNode(str(idx)) for node in visitedNodes.values(): dot.add_node(node) for nodeset in self.goals.values(): for justification in nodeset.steps: edge = Edge(visitedNodes[nodeset], visitedNodes[justification], label="is the consequence of", color='red') dot.add_edge(edge) for ant in justification.antecedents: if justification.source: edge = Edge(visitedNodes[ant.steps[0]], visitedNodes[nodeset], label="has antecedent", color='blue') dot.add_edge(edge) else: #not isinstance(justification,InferenceStep) or not justification.source:#(visitedNodes[nodeset],visitedNodes[justification]) not in edges: edge = Edge(visitedNodes[justification], visitedNodes[ant], label="has antecedent", color='blue') #edge.label="has antecedents" dot.add_edge(edge) #edges.append((visitedNodes[nodeset],visitedNodes[justification])) return dot #bglGraph
def __init__(self,nsDict=None): self.nsDict = nsDict and nsDict or {} self.nsMgr = NamespaceManager(Graph()) self.nsMgr.bind('owl','http://www.w3.org/2002/07/owl#') self.nsMgr.bind('math','http://www.w3.org/2000/10/swap/math#')
def main(): from optparse import OptionParser parser = OptionParser() parser.add_option( '--stdin', type="choice", choices=['xml', 'trix', 'n3', 'nt', 'rdfa'], help='Parse RDF from STDIN (useful for piping) with given format') parser.add_option('-x', '--xml', action='append', help='Append to the list of RDF/XML documents to parse') parser.add_option('-t', '--trix', action='append', help='Append to the list of TriX documents to parse') parser.add_option('-n', '--n3', action='append', help='Append to the list of N3 documents to parse') parser.add_option('--nt', action='append', help='Append to the list of NT documents to parse') parser.add_option('-a', '--rdfa', action='append', help='Append to the list of RDFa documents to parse') parser.add_option( '-o', '--output', type="choice", choices=['n3', 'xml', 'pretty-xml', 'TriX', 'turtle', 'nt'], help='Format of the final serialized RDF graph') parser.add_option( '-m', '--ns', action='append', help='Register a namespace binding (QName prefix to a base URI)') parser.add_option( '-r', '--rules', action='append', help='Append to the list of fact files to use to perform reasoning') parser.add_option( '-i', '--inferred', help='URI to use for the graph containing any inferred triples') parser.set_defaults(xml=[], trix=[], n3=[], nt=[], rdfa=[], ns=[], output='n3') (options, args) = parser.parse_args() store = plugin.get(RDFLIB_STORE, Store)() store.open(RDFLIB_CONNECTION) namespace_manager = NamespaceManager(Graph()) for prefixDef in options.ns: prefix, uri = prefixDef.split('=') namespace_manager.bind(prefix, uri, override=False) factGraph = ConjunctiveGraph(store) for graphRef in options.xml: factGraph.parse(graphRef, publicID=Uri.OsPathToUri(graphRef), format='xml') for graphRef in options.trix: factGraph.parse(graphRef, publicID=Uri.OsPathToUri(graphRef), format='trix') for graphRef in options.n3: factGraph.parse(graphRef, publicID=Uri.OsPathToUri(graphRef), format='n3') for graphRef in options.nt: factGraph.parse(graphRef, publicID=Uri.OsPathToUri(graphRef), format='nt') for graphRef in options.rdfa: factGraph.parse(graphRef, publicID=Uri.OsPathToUri(graphRef), format='rdfa') if options.stdin: factGraph.parse(sys.stdin, format=options.stdin) if options.inferred and len(options.rules) > 0: inferredURI = URIRef(options.inferred) ruleStore = N3RuleStore() ruleGraph = Graph(ruleStore) for ruleFile in options.rules: ruleGraph.parse(ruleFile, format='n3') tokenSet = generateTokenSet(factGraph) deltaGraph = Graph(store=factGraph.store, identifier=inferredURI) network = ReteNetwork(ruleStore, inferredTarget=deltaGraph) network.feedFactsToAdd(tokenSet) print factGraph.serialize(destination=None, format=options.output, base=None) store.rollback()
def _get_namespace_manager(self): if self.__namespace_manager is None: self.__namespace_manager = NamespaceManager(self) return self.__namespace_manager
def __init__(self,ruleStore,name = None, initialWorkingMemory = None, inferredTarget = None, nsMap = {}, graphVizOutFile=None, dontFinalize=False, goal=None, rulePrioritizer=None, alphaNodePrioritizer=None): self.leanCheck = {} self.goal = goal self.nsMap = nsMap self.name = name and name or BNode() self.nodes = {} self.alphaPatternHash = {} self.ruleSet = set() for alphaPattern in xcombine(('1','0'),('1','0'),('1','0')): self.alphaPatternHash[tuple(alphaPattern)] = {} if inferredTarget is None: self.inferredFacts = Graph() namespace_manager = NamespaceManager(self.inferredFacts) for k,v in nsMap.items(): namespace_manager.bind(k, v) self.inferredFacts.namespace_manager = namespace_manager else: self.inferredFacts = inferredTarget self.workingMemory = initialWorkingMemory and initialWorkingMemory or set() self.proofTracers = {} self.terminalNodes = set() self.instanciations = {} start = time.time() self.ruleStore=ruleStore self.justifications = {} self.dischargedBindings = {} if not dontFinalize: self.ruleStore._finalize() self.filteredFacts = Graph() self.rulePrioritizer = rulePrioritizer self.alphaNodePrioritizer = alphaNodePrioritizer #'Universal truths' for a rule set are rules where the LHS is empty. # Rather than automatically adding them to the working set, alpha nodes are 'notified' # of them, so they can be checked for while performing inter element tests. self.universalTruths = [] from FuXi.Horn.HornRules import Ruleset self.rules=set() self.negRules = set() for rule in Ruleset(n3Rules=self.ruleStore.rules,nsMapping=self.nsMap): import warnings warnings.warn( "Rules in a network should be built *after* construction via "+ " self.buildNetworkClause(HornFromN3(n3graph)) for instance", DeprecationWarning,2) self.buildNetworkFromClause(rule) self.alphaNodes = [node for node in self.nodes.values() if isinstance(node,AlphaNode)] self.alphaBuiltInNodes = [node for node in self.nodes.values() if isinstance(node,BuiltInAlphaNode)] self._setupDefaultRules() if initialWorkingMemory: start = time.time() self.feedFactsToAdd(initialWorkingMemory) print >>sys.stderr,"Time to calculate closure on working memory: %s m seconds"%((time.time() - start) * 1000) if graphVizOutFile: print >>sys.stderr,"Writing out RETE network to ", graphVizOutFile renderNetwork(self,nsMap=nsMap).write(graphVizOutFile)
def main(): from optparse import OptionParser op = OptionParser( 'usage: %prog [options] factFile1 factFile2 ... factFileN') op.add_option('--why', default=None, help='Specifies the goals to solve for') op.add_option( '--closure', action='store_true', default=False, help='Whether or not to serialize the inferred triples' + ' along with the original triples. Otherwise ' + '(the default behavior), serialize only the inferred triples') op.add_option( '--naive', action='store_true', default=False, help='Naively perform forward chaining over rules and facts using the ' + 'RETE network') op.add_option( '--imports', action='store_true', default=False, help='Whether or not to follow owl:imports in the fact graph') op.add_option( '--output', default='n3', metavar='RDF_FORMAT', choices=[ 'xml', 'TriX', 'n3', 'pml', 'proof-graph', 'nt', 'rif', 'rif-xml', 'conflict', 'man-owl' ], help= "Serialize the inferred triples and/or original RDF triples to STDOUT " + "using the specified RDF syntax ('xml','pretty-xml','nt','turtle', " + "or 'n3') or to print a summary of the conflict set (from the RETE " + "network) if the value of this option is 'conflict'. If the the " + " value is 'rif' or 'rif-xml', Then the rules used for inference " + "will be serialized as RIF. If the value is 'pml' and --why is used, " + " then the PML RDF statements are serialized. If output is " + "'proof-graph then a graphviz .dot file of the proof graph is printed. " + "Finally if the value is 'man-owl', then the RDF facts are assumed " + "to be OWL/RDF and serialized via Manchester OWL syntax. The default is %default" ) op.add_option( '--class', dest='classes', action='append', default=[], metavar='QNAME', help='Used with --output=man-owl to determine which ' + 'classes within the entire OWL/RDF are targetted for serialization' + '. Can be used more than once') op.add_option( '--hybrid', action='store_true', default=False, help='Used to determine whether or not to ' + 'peek into the fact graph to identify predicates that are both ' + 'derived and base. This is expensive for large fact graphs' + 'and is explicitely not used against SPARQL endpoints') op.add_option( '--property', action='append', dest='properties', default=[], metavar='QNAME', help='Used with --output=man-owl or --extract to determine which ' + 'properties are serialized / extracted. Can be used more than once') op.add_option( '--normalize', action='store_true', default=False, help= "Used with --output=man-owl to attempt to determine if the ontology is 'normalized' [Rector, A. 2003]" + "The default is %default") op.add_option( '--ddlGraph', default=False, help= "The location of a N3 Data Description document describing the IDB predicates" ) op.add_option( '--input-format', default='xml', dest='inputFormat', metavar='RDF_FORMAT', choices=['xml', 'trix', 'n3', 'nt', 'rdfa'], help= "The format of the RDF document(s) which serve as the initial facts " + " for the RETE network. One of 'xml','n3','trix', 'nt', " + "or 'rdfa'. The default is %default") op.add_option( '--safety', default='none', metavar='RULE_SAFETY', choices=['loose', 'strict', 'none'], help="Determines how to handle RIF Core safety. A value of 'loose' " + " means that unsafe rules will be ignored. A value of 'strict' " + " will cause a syntax exception upon any unsafe rule. A value of " + "'none' (the default) does nothing") op.add_option( '--pDSemantics', action='store_true', default=False, help= 'Used with --dlp to add pD semantics ruleset for semantics not covered ' + 'by DLP but can be expressed in definite Datalog Logic Programming' + ' The default is %default') op.add_option( '--stdin', action='store_true', default=False, help= 'Parse STDIN as an RDF graph to contribute to the initial facts. The default is %default ' ) op.add_option( '--ns', action='append', default=[], metavar="PREFIX=URI", help='Register a namespace binding (QName prefix to a base URI). This ' + 'can be used more than once') op.add_option( '--rules', default=[], action='append', metavar='PATH_OR_URI', help='The Notation 3 documents to use as rulesets for the RETE network' + '. Can be specified more than once') op.add_option('-d', '--debug', action='store_true', default=False, help='Include debugging output') op.add_option( '--strictness', default='defaultBase', metavar='DDL_STRICTNESS', choices=['loose', 'defaultBase', 'defaultDerived', 'harsh'], help= 'Used with --why to specify whether to: *not* check if predicates are ' + ' both derived and base (loose), if they are, mark as derived (defaultDerived) ' + 'or as base (defaultBase) predicates, else raise an exception (harsh)') op.add_option( '--firstAnswer', default=False, action='store_true', help= 'Used with --why to determine whether to fetch all answers or just ' + 'the first') op.add_option( '--edb', default=[], action='append', metavar='EXTENSIONAL_DB_PREDICATE_QNAME', help= 'Used with --why/--strictness=defaultDerived to specify which clashing ' + 'predicate will be designated as a base predicate') op.add_option( '--idb', default=[], action='append', metavar='INTENSIONAL_DB_PREDICATE_QNAME', help= 'Used with --why/--strictness=defaultBase to specify which clashing ' + 'predicate will be designated as a derived predicate') op.add_option( '--hybridPredicate', default=[], action='append', metavar='PREDICATE_QNAME', help= 'Used with --why to explicitely specify a hybrid predicate (in both ' + ' IDB and EDB) ') op.add_option( '--noMagic', default=[], action='append', metavar='DB_PREDICATE_QNAME', help='Used with --why to specify that the predicate shouldnt have its ' + 'magic sets calculated') op.add_option( '--filter', action='append', default=[], metavar='PATH_OR_URI', help= 'The Notation 3 documents to use as a filter (entailments do not particpate in network)' ) op.add_option( '--ruleFacts', action='store_true', default=False, help="Determines whether or not to attempt to parse initial facts from " + "the rule graph. The default is %default") op.add_option( '--builtins', default=False, metavar='PATH_TO_PYTHON_MODULE', help="The path to a python module with function definitions (and a " + "dicitonary called ADDITIONAL_FILTERS) to use for builtins implementations" ) op.add_option( '--dlp', action='store_true', default=False, help= 'Use Description Logic Programming (DLP) to extract rules from OWL/RDF. The default is %default' ) op.add_option( '--sparqlEndpoint', action='store_true', default=False, help= 'Indicates that the sole argument is the URI of a SPARQL endpoint to query' ) op.add_option( '--ontology', action='append', default=[], metavar='PATH_OR_URI', help= 'The path to an OWL RDF/XML graph to use DLP to extract rules from ' + '(other wise, fact graph(s) are used) ') op.add_option( '--ruleFormat', default='n3', dest='ruleFormat', metavar='RULE_FORMAT', choices=['n3', 'rif'], help= "The format of the rules to parse ('n3', 'rif'). The default is %default" ) op.add_option( '--ontologyFormat', default='xml', dest='ontologyFormat', metavar='RDF_FORMAT', choices=['xml', 'trix', 'n3', 'nt', 'rdfa'], help= "The format of the OWL RDF/XML graph specified via --ontology. The default is %default" ) op.add_option( '--builtinTemplates', default=None, metavar='N3_DOC_PATH_OR_URI', help= 'The path to an N3 document associating SPARQL FILTER templates to ' + 'rule builtins') op.add_option( '--normalForm', action='store_true', default=False, help='Whether or not to reduce DL axioms & LP rules to a normal form') (options, facts) = op.parse_args() nsBinds = {'iw': 'http://inferenceweb.stanford.edu/2004/07/iw.owl#'} for nsBind in options.ns: pref, nsUri = nsBind.split('=') nsBinds[pref] = nsUri namespace_manager = NamespaceManager(Graph()) if options.sparqlEndpoint: factGraph = Graph(plugin.get('SPARQL', Store)(facts[0])) options.hybrid = False else: factGraph = Graph() ruleSet = Ruleset() for fileN in options.rules: if options.ruleFacts and not options.sparqlEndpoint: factGraph.parse(fileN, format='n3') print >> sys.stderr, "Parsing RDF facts from ", fileN if options.builtins: import imp userFuncs = imp.load_source('builtins', options.builtins) rs = HornFromN3(fileN, additionalBuiltins=userFuncs.ADDITIONAL_FILTERS) nsBinds.update(rs.nsMapping) elif options.ruleFormat == 'rif': try: from FuXi.Horn.RIFCore import RIFCoreParser rif_parser = RIFCoreParser(location=fileN, debug=options.debug, nsBindings=nsBinds) rs, facts = rif_parser.getRuleset() except ImportError, e: raise Exception( "Missing 3rd party libraries for RIF processing: %s" % e) else: rs = HornFromN3(fileN) nsBinds.update(rs.nsMapping) ruleSet.formulae.extend(rs)
if options.imports: for owlImport in factGraph.objects(predicate=OWL_NS.imports): factGraph.parse(owlImport) print >> sys.stderr, "Parsed Semantic Web Graph.. ", owlImport if not options.sparqlEndpoint and facts: for pref, uri in factGraph.namespaces(): nsBinds[pref] = uri if options.stdin: assert not options.sparqlEndpoint, "Cannot use --stdin with --sparqlEndpoint" factGraph.parse(sys.stdin, format=options.inputFormat) #Normalize namespace mappings #prune redundant, rdflib-allocated namespace prefix mappings newNsMgr = NamespaceManager(factGraph) from FuXi.Rete.Util import CollapseDictionary for k, v in CollapseDictionary( dict([(k, v) for k, v in factGraph.namespaces()])).items(): newNsMgr.bind(k, v) factGraph.namespace_manager = newNsMgr if options.normalForm: NormalFormReduction(factGraph) if not options.sparqlEndpoint and options.naive: workingMemory = generateTokenSet(factGraph) if options.builtins: import imp userFuncs = imp.load_source('builtins', options.builtins) rule_store, rule_graph, network = SetupRuleStore(