Accessing inferred facts in individuals

classic Classic list List threaded Threaded
21 messages Options
12
Oli
Reply | Threaded
Open this post in threaded view
|

Accessing inferred facts in individuals

Oli
Hello,

I'm currently using owlready2 to communicate between Python and OWL, and it is a great API! Thanks a lot :)

I have a question regarding accessing inferred facts: how can I access inferred facts in individuals?

For example:

        - Entities: Component, Material, Method

        - Individuals: Component1, Metal, Drilling

        - Object Properties: hasMaterial, hasProductionMethod

        - Rule: Component(?c) ^ hasMaterial(?c, Metal) -> hasProductionMethod(?c, Drilling)

I defined that Component1 hasMaterial Metal. Then in Protégé I use the Hermit reasoner and it infers that Component1 hasProductionMethod Drilling.

However, when I do this in owlready (with sync_reasoner) I cannot access this information. Is there a way to do this?

Many thanks,
Oli
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Jiba
Administrator
Hello,

There is still no rule support in Olwready, sorry :-(

As far as I know, rules can be used be reasoner for checking consistency, but in Protégé I do not see the inferred property values (where/how do you obtained them ?).

Best regards,
Jean-Baptiste Lamy
MCF HDR, Laboratoire LIMICS, Université Paris 13
Oli
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Oli
Hi Jean-Baptiste,

Thanks for the fast reply :)

After defining the rule in SWRL Tab, I start the reasoner and in the Property assertions of the individual Component1 I get a object property assertion hasProductionMethod Drilling. This assertion, however, is not saved in the ontology after the reasoner is stopped. But I thought that maybe I could access this information from Python while the reasoner was running, with something like this:

        import owlready2 as owl

        onto_path = "my/path/to/onto.owl"
        onto = owl.get_ontology("file://" + onto_path).load()

        with onto:
                owl.sync_reasoner()
       
                print(onto["Component1"].hasProductionMethod)
       
Is this possible? If not, could I change something in the sync_reasoner function to get a result? I don't need this value in the ontology I just need to extract it to Python.

Thanks again!

Cheers,
Oli
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Jiba
Administrator
Hello,

> Is this possible? If not, could I change something in the sync_reasoner
> function to get a result? I don't need this value in the ontology I just
> need to extract it to Python.

The problem is that Hermit does not show those inferrences on the command line. So you need to modify Hermit in order to get them on command line, and then to modify Owlready to apply the inferrences. I already did a similar modification for individual classification, so it is possible, but not easy :-(

Best regards,
Jean-Baptiste Lamy
MCF HDR, Laboratoire LIMICS, Université Paris 13
Oli
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Oli
Hi Jean-Baptiste,

Thanks for the comment and sorry for the late response!

I managed to access the inferred facts using the java based SWRLapi. I've created a java program that I can run using the command line (similarly to what sync_reasoner does). It is not a really elegant solution but I get the results that I wanted.

Cheers,
Oli
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

martingrant
Hi Oli,

I wonder if you could share the program you created? I'm looking for a similar solution.

Thanks
Oli
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Oli
Hi!

Sure :) Here is my InferenceEngine class:

from pathlib import Path
import subprocess
from global_settings import INFERENCE_PATH, GLOBAL_LOGGER

class InferenceEngine(object):
    """
    InferenceEngine class

    :param input_file: path to the txt file
    :type input_file: str, Path
    :param ontology_list: list with paths to the owl files to be written in :attr:`file_path`
    :type ontology_list: list
    :param inference_path: path to the directory where the reasoner.jar is located
    :type inference_path: Path
    """

    def __init__(self, input_file, ontology_list, inference_path=INFERENCE_PATH):
        self.input_file = input_file
        self.ontology_list = ontology_list
        self.inference_path = inference_path

    def write_reasoner_input_file(self):
        """
        Given a list with paths to owl files (ontology_list) and a txt file (file_path), this method writes the owl
        file paths to the txt file. The resulting txt file is the input for the :func:`run_rule_engine`.

        :return: written input_file
        """

        if isinstance(self.input_file, Path):
            self.input_file = str(self.input_file)

        with open(self.input_file, 'w') as f:
            for ontology_path in self.ontology_list:
                f.write(ontology_path + '\n')

    def run_rule_engine(self):
        """
        Function that runs the rule engine (using Drools). It uses self.input_file, which is the path to txt file, which
        contains a list with the path of the ontology that uses the rule engine and the dependencies of that ontology
        (imported ontologies). It does not return anything but it updates the inferred facts to the input ontology.

        :Note:

            The order in which the ontologies paths are written into the txt file matters. The dependencies should be
            always above the main ontology, in order to avoid import errors. For example, imagine that the rule engine
            is going to be applied to the ontology onto, which depends on the ontology onto. Then, the input_file.txt
            will look like this:

                global/path/to/onto1.owl
                global/path/to/onto.owl

            This is achieved using the method :func:`write_reasoner_input_file`

        """

        if isinstance(self.inference_path, str):
            self.inference_path = Path(self.inference_path)
            GLOBAL_LOGGER.info('The input inference_path ({}) should be of type Path and it has been converted.'.format(
                self.inference_path))

        jar_path = self.inference_path / "reasoner.jar"
        self.write_reasoner_input_file()
        command = ["java", "-jar", str(jar_path), str(self.input_file)]
        subprocess.check_output(command)


For it to work, you will need the reasoner.jar file that I've created. Do you know how can I attach a file?

It is not the prettiest solution, but it is something :P

Cheers,
Oli
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

martingrant
Hi Oli,

Great thanks! I'm using the nabble site to browse this forum and in the reply page there is a "More" button with a drop down that lets you upload files. Otherwise perhaps you could upload to Dropbox or Google Drive or something similar and share the link so I can get your jar file?

Thanks!
Oli
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Oli
Hi :)

I realized that I have to register to be able to add files, but it doesn't seem to upload. I have uploaded the jar file to WeTransfer (https://we.tl/t-6TXF0ABLjf). Hope it works!

Let me know if it doesn't work (the download or the code).

Good luck!
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

martingrant
Hi Oli,

The download works, thanks so much! Can you give a quick overview of how your code works?

What are "input_file" and "ontology_list"?

I have an ontology file with some SWRL rules defined and it also contains some individuals, I want to run a reasoner to apply the rules to the individuals.

Thanks
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

martingrant
In reply to this post by Oli
Hi Oli,

Actually no problem I managed to figure it out and got it working! This is great it is exactly what I needed and should let me get further with my project. Thanks a lot for the time spent developing your code.

I wonder if you would be able to share the source? And if you are able to give permission to use the code in my research project if you don't mind?

Thanks :)
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

liam
In reply to this post by Oli
You could also force a reclassification step by creating a new class that matches the condition of having the property. Then HermiT will report it in the output. It's not the cleanest solution, but it doesn't require any extra libraries and a little extra work in the ontology.
Oli
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Oli
In reply to this post by martingrant
Heyhey,

Happy to hear it works :)

Here you have the java code (finally managed to upload a file!):

InferenceEngine.java

It was the first time I used java so I hope it is not too messy. But since you have it now, you can expand it or make it nicer :)

Of course you can use it! I'm happy to hear that it is useful for someone else!

Cheers,
Oli


Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

wzimmer
In reply to this post by Jiba
Hi Jean-Baptiste,

when will owelready2 support the access of inferred facts (properties) of individuals?

Best regards,
Walter Zimmer


Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

wzimmer
In reply to this post by liam
Hi Liam,

Thank you for providing another solution to this problem. Could you please elaborate a bit more on this?

I am also working on implementing a solution to access inferred facts (properties) in python.
The way I am doing it is the following. I modified the HermiT jar (CommandLine.java, Reasoner,java and HierarchyDumperFSS.java) to also print the inferred properties. Then I call the the reasoner from Python:

reasoner.py

command = "java -Xmx2000M -cp /usr/local/lib/python3.6/dist-packages/owlready2/hermit:/usr/local/lib/python3.6/dist-packages/owlready2/hermit/HermiT_modified.jar org.semanticweb.HermiT.cli.CommandLine -c -O -D -o pizza_onto_inference.owl pizza.owl"

The next step is to parse the inferred results within reasoner.py.

I have created three individuals (pizza1, pizza2, meatTopping1) and assigned the property has_topping(meatTopping1) to pizza1. For pizza2 I set the SameIndividualAs(pizza1) property. After running the HermiT reasoner I can see that pizza2 has also the property has_topping(meatTopping1).

Has someone written already a parser to parse inferred properties and can share the file?

Thanks,
Walter

Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Jiba
Administrator
Hi Walter,

Modifying the Python parser is the easy part of the job (at least for me). If you send me the modified version of HermiT (that prints the inferred properties), I should be able to write the parser quickly.

Best regards,
Jiba
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

wzimmer
Hi Jiba,

Thank you for your answer. I started already to write the parser, but still need to rewrite two methods. You can see my changes in the reasoner.py (annotated with 'CHANGED BY W. ZIMMER').

Here is a link to the modified HermiT version 1.3.8 and the modified owlready2 (version 0.13) python lib.

https://we.tl/t-7R0Yv7OuNA

I have modified CommandLine.java to do inference on all types (incl. properties):
hermit.precomputeInferences(InferenceType.CLASS_HIERARCHY, InferenceType.OBJECT_PROPERTY_HIERARCHY, InferenceType.DATA_PROPERTY_HIERARCHY,InferenceType.CLASS_ASSERTIONS,InferenceType.OBJECT_PROPERTY_ASSERTIONS,InferenceType.SAME_INDIVIDUAL,InferenceType.DISJOINT_CLASSES,InferenceType.DATA_PROPERTY_ASSERTIONS,InferenceType.DIFFERENT_INDIVIDUALS);

In Reasoner.java I have added the method to print also the properties:
printer.printInferredProperties(m_instanceManager.getCurrentRoleHierarchy());

I perform the inference with the following command which writes the inferred properties into a file (pizza_onto_inference.owl):

java -Xmx2000M -cp /usr/local/lib/python3.6/dist-packages/owlready2/hermit:/usr/local/lib/python3.6/dist-packages/owlready2/hermit/HermiT_modified.jar org.semanticweb.HermiT.cli.CommandLine -c -O -D -o pizza_onto_inference.owl pizza_onto.owl

Here is the content of pizza_onto_inference.owl:
SubClassOf( <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#TomatoTopping> <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#Topping> )
SubClassOf( <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#CheeseTopping> <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#Topping> )
SubClassOf( <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#MeatTopping> <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#Topping> )
SubClassOf( <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#FishTopping> <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#Topping> )


owl:bottomObjectProperty (known instances:  | possible instances: )
<http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#has_topping
(known instances:
   (<http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#pizza1>,
   <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#meatTopping1>)
   (<http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#pizza2>,
   <http://www.lesfleursdunormal.fr/static/_downloads/pizza_onto.owl#meatTopping1>)
   | possible instances:
)
owl:topObjectProperty (known instances:  | possible instances: )



I need to parse the bottom part and assign the property has_topping to the pizza2 individual.

Here you can find the modifiedd pizza_onto.owl file. I have created the individuals pizza1, pizza2 and meatTopping1 and assigned the property has_topping to pizza1 and the attribute pizza1.sameAs(pizza2).

pizza_onto.owl

Best regards,
Walter
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Jiba
Administrator
Hi Walter,

I integrated this in the development version on Bitbucket. It works well for inferring Object property values (but not yet for data properties) !

Best regards,
Jiba
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Jiba
Administrator
Hi again,

I forget to mention that inferring property values is disabled by default. You need to activate it with the infer_property_values parameter as follows:

sync_reasoner(infer_property_values = True)

Jiba
Reply | Threaded
Open this post in threaded view
|

Re: Accessing inferred facts in individuals

Ashutosh
Test.owl

Hi Jiba,
I have uploaded an owl file,in which I have created a Person class.
hasfather and isfatherof are two object properties which are inverse of each other. (I am using release 0.14)

Following are the relationships defined in the owl file.
a) A isfatherof B
b)B hasfather A
c)C hasfather B.


On running reasoner,it should infer 'B isfatherof C',but i am not getting the inferred value.
code which I used after loading the ontology is:
        with onto:
        sync_reasoner(infer_property_values = True,keep_tmp_file = 1)
12