<jupyter_start><jupyter_text>CWPK \26: Introduction to Knowledge Graph Reasoners=======================================Two Standards Come Pre-packaged with Owlready2--------------------------We introduce [OWL](https://en.wikipedia.org/wiki/Web_Ontology_Language) (knowledge graph) [reasoners](https://en.wikipedia.org/wiki/Semantic_reasoner) in this installment of the [*Cooking with Python and KBpedia*](https://www.mkbergman.com/cooking-with-python-and-kbpedia/) series. A reasoner has two purposes. First, based on deductive reasoning, a reasoner can infer new class and property assignments that are logically entailed by the assertions in an ontology (that is, from its [axioms](https://en.wikipedia.org/wiki/Axiom)) but not otherwise explicitly stated. Once inferred, these additional assignments can be written to an inferred version of the ontology for faster lookups and analysis. Second, reasoners can evaluate the stated axioms to determine if the ontology is [consistent](https://en.wikipedia.org/wiki/Consistency) or [satisfiable](https://en.wikipedia.org/wiki/Satisfiability). This second purpose is a key step when building or modifying a knowledge graph to ensure that illogical assertions are not introduced into the system. Reasoners thus often have explanation routines that point out where the inconsistencies or problems occur, thus helping the analyst to fix the errors before committing to productive use. In later installments we will focus especially on these coherency tests when we discuss the build procedures for KBpedia.Consistency is when none of the assertions (axioms) in the knowledge graph contradicts another one. If there is a contradiction the graph is termed to be *inconsistent*. Satisfiability individually evaluates the classes in the graph and checks to see if they can have instances without contradicting other asserted axioms. Unsatisfiability indicates there is a conflicting or missing assignment that needs to be corrected. It is a particularly useful check when there are disjoint assertions made between classes, one of the design pillars of KBpedia. [Owlready2](http://www.lesfleursdunormal.fr/static/informatique/owlready/index_en.html) is distributed with two OWL reasoners:- [HermiT](http://www.hermit-reasoner.com/), developed by the department of Computer Science of the University of Oxford, and- [Pellet](https://github.com/stardog-union/pellet), a reasoner developed specifically to support the OWL language.Both HermiT and Pellet are written in Java, so require access to a JVM on your system. If you have difficulty running these systems it is likely because you: 1) do not have a recent version of Java installed on your system; or 2) do not have a proper PATH statement in your environmental variables to find the Java executable. If you encounter such problems, please consult third-party sources to get Java properly configured for your system before continuing with this installment.  Test OntologyTo make sure that your system is configured properly, go ahead and shift+enter or Run this cell that enters a small example ontology from the [owlready2 documentation](https://owlready2.readthedocs.io/en/latest/reasoning.html):<jupyter_code>from owlready2 import *

onto = get_ontology("http://test.org/onto.owl")

with onto:
    class Drug(Thing):
        def take(self): print("I took a drug")

    class ActivePrinciple(Thing):
        pass

    class has_for_active_principle(Drug >> ActivePrinciple):
        python_name = "active_principles"

    class Placebo(Drug):
        equivalent_to = [Drug & Not(has_for_active_principle.some(ActivePrinciple))]
        def take(self): print("I took a placebo")

    class SingleActivePrincipleDrug(Drug):
        equivalent_to = [Drug & has_for_active_principle.exactly(1, ActivePrinciple)]
        def take(self): print("I took a drug with a single active principle")

    class DrugAssociation(Drug):
        equivalent_to = [Drug & has_for_active_principle.min(2, ActivePrinciple)]
        def take(self): print("I took a drug with %s active principles" % len(self.active_principles))

acetaminophen   = ActivePrinciple("acetaminophen")
amoxicillin     = ActivePrinciple("amoxicillin")
clavulanic_acid = ActivePrinciple("clavulanic_acid")

AllDifferent([acetaminophen, amoxicillin, clavulanic_acid])

drug1 = Drug(active_principles = [acetaminophen])
drug2 = Drug(active_principles = [amoxicillin, clavulanic_acid])
drug3 = Drug(active_principles = [])

close_world(Drug)<jupyter_output><empty_output><jupyter_text>Then, run the HermiT reasoner with the single command:<jupyter_code>sync_reasoner()<jupyter_output>* Owlready2 * Running HermiT...
    java -Xmx2000M -cp C:\1-PythonProjects\Python\lib\site-packages\owlready2\hermit;C:\1-PythonProjects\Python\lib\site-packages\owlready2\hermit\HermiT.jar org.semanticweb.HermiT.cli.CommandLine -c -O -D -I file:///C:/Users/mike/AppData/Local/Temp/tmpbnxf7755
* Owlready2 * HermiT took 0.4851553440093994 seconds
* Owlready * Reparenting onto.drug2: {onto.Drug} => {onto.DrugAssociation}
* Owlready * Reparenting onto.drug1: {onto.Drug} => {onto.SingleActivePrincipleDrug}
* Owlready * Reparenting onto.drug3: {onto.Drug} => {onto.Placebo}
* Owlready * (NB: only changes on entities loaded in Python are shown, other changes are done but not listed)<jupyter_text>The feedback you get to screen should indicate that you are 'Reparenting' the three drugs from one class (Drug) to their appropriate sublasses. By the way, you could also place this argument in the command to turn off the debug reports to screen: $ sync_reasoner(debug = 0).You can also confirm this move for drug2:<jupyter_code>print("drug2 new Classes:", drug2.__class__)<jupyter_output>drug2 new Classes: onto.DrugAssociation<jupyter_text>And, then, in the next three cells, confirm how you took those three drugs:<jupyter_code>drug1.take()
drug2.take()
drug3.take()<jupyter_output>I took a placebo<jupyter_text>And, last, in the next two cells discover if any inconsistent classes remain (they do not), which is equivalent to a class being assigned to the Nothing class in OWL:<jupyter_code>list(default_world.inconsistent_classes())
if Nothing in Drug.equivalent_to:
       print("Drug is inconsistent!")<jupyter_output><empty_output><jupyter_text>General Load MethodOK, so now we see the HermiT reasoner is configured properly and working, we are now ready to test our KBpedia knowledge graph. Go ahead and select Kernel &rarr; Restart & Clear Output from the main menu to begin the next activities from a clean slate.Then execute what has become our standard load procedure:Which environment? The specific load routine you should choose below depends on whether you are using the online MyBinder service (the 'raw' version) or local files. The example below is based on using local files (though replace with your own local directory specification). If loading from MyBinder, replace with the lines that are commented () out.<jupyter_code>main = 'C:/1-PythonProjects/kbpedia/sandbox/kbpedia_reference_concepts.owl'
# main = 'https://raw.githubusercontent.com/Cognonto/CWPK/master/sandbox/builds/ontologies/kbpedia_reference_concepts.owl'
skos_file = 'http://www.w3.org/2004/02/skos/core' 
kko_file = 'C:/1-PythonProjects/kbpedia/sandbox/kko.owl'
# kko_file = 'https://raw.githubusercontent.com/Cognonto/CWPK/master/sandbox/builds/ontologies/kko.owl'

from owlready2 import *
world = World()
kb = world.get_ontology(main).load()
rc = kb.get_namespace('http://kbpedia.org/kko/rc/')

skos = world.get_ontology(skos_file).load()
kb.imported_ontologies.append(skos)

kko = world.get_ontology(kko_file).load()
kb.imported_ontologies.append(kko)<jupyter_output><empty_output><jupyter_text>HermiT ReasonerWe again invoke the HermiT reasoner:<jupyter_code>sync_reasoner()<jupyter_output>* Owlready2 * Running HermiT...
    java -Xmx2000M -cp C:\1-PythonProjects\Python\lib\site-packages\owlready2\hermit;C:\1-PythonProjects\Python\lib\site-packages\owlready2\hermit\HermiT.jar org.semanticweb.HermiT.cli.CommandLine -c -O -D -I file:///C:/Users/mike/AppData/Local/Temp/tmpxglvdub2
* Owlready2 * HermiT took 0.42046189308166504 seconds
* Owlready * (NB: only changes on entities loaded in Python are shown, other changes are done but not listed)<jupyter_text>There is also an argument to infer_property_values = True:<jupyter_code>sync_reasoner(infer_property_values = True)<jupyter_output>* Owlready2 * Running HermiT...
    java -Xmx2000M -cp C:\1-PythonProjects\Python\lib\site-packages\owlready2\hermit;C:\1-PythonProjects\Python\lib\site-packages\owlready2\hermit\HermiT.jar org.semanticweb.HermiT.cli.CommandLine -c -O -D -I file:///C:/Users/mike/AppData/Local/Temp/tmpxkc92ws4 -Y
* Owlready2 * HermiT took 0.416165828704834 seconds
* Owlready * (NB: only changes on entities loaded in Python are shown, other changes are done but not listed)<jupyter_text>We see that the ontology is consistent, which we can confirm with this additional command:<jupyter_code>list(world.inconsistent_classes())<jupyter_output><empty_output><jupyter_text>Pellet ReasonerThe second of our reasoners, Pellet, operates under a similar set of arguments. We invoke Pellet through the modified reasoner command:.<jupyter_code>sync_reasoner_pellet()<jupyter_output>* Owlready2 * Running Pellet...
    java -Xmx2000M -cp C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\antlr-3.2.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\antlr-runtime-3.2.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\aterm-java-1.6.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\commons-codec-1.6.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\httpclient-4.2.3.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\httpcore-4.2.2.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\jcl-over-slf4j-1.6.4.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\jena-arq-2.10.0.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\jena-core-2.10.0.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\jena-iri-0.9.5.jar;C:\1-PythonProjects\Python\lib\site-packages\owlready2\pellet\jena-tdb-0.10.0.jar;C:\1-PythonProjects\Python\lib\site-packa[...]<jupyter_text>Pellet, too, is configured to run in a debug mode. If you wish, you may turn it off with $ sync_reasoner(debug = 0).Like HermiT we can also infer_property_values. But, different than HermiT, we may also infer_data_property_values = True using Pellet:<jupyter_code>sync_reasoner_pellet(infer_property_values = True, infer_data_property_values = True)
list(world.inconsistent_classes())<jupyter_output><empty_output><jupyter_text>SWRLAs long as we are introducing these capabilities, we should also mention that Owlready2 also supports the use of [SWRL](https://en.wikipedia.org/wiki/Semantic_Web_Rule_Language) (the Semantic Web Rule Language) "if . . . then" type statements. To the best of my knowledge, Owlready2 supports all of the standard SWRL constructs. It is also possible to mix Python and OWL code together, but that, too, is a topic we will not be addressing further in this CWPK series.  Save and ExitWhen we are finished with our tests, we can File &rarr; Save and Checkpoint, Rename our output file, or specify it at the command line:<jupyter_code>kb.save(file = 'files/kbpedia_reference_concepts-pellet.owl', format = 'rdfxml')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09893561333100681, 'fraction_numerical': 0.016402024079567267, 'mean_word_length': 5.40391061452514, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 48, 'https://': 11, 'lorem ipsum': 0, 'www.': 4, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '468263', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 3782, 'n_tokens_neox': 3497, 'n_words': 1054, 'path': 'cwpk-26-intro-kg-reasoners.ipynb', 'repo_name': 'Cognonto/CWPK', 'size': '11462'}